TradeSkillMaster/Core/Service/Crafting/Sync.lua

228 lines
8.3 KiB
Lua
Raw Permalink Normal View History

2020-11-13 14:13:12 -05:00
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local CraftingSync = TSM.Crafting:NewPackage("Sync")
local L = TSM.Include("Locale").GetTable()
local Delay = TSM.Include("Util.Delay")
local TempTable = TSM.Include("Util.TempTable")
local String = TSM.Include("Util.String")
local Log = TSM.Include("Util.Log")
local Theme = TSM.Include("Util.Theme")
local Sync = TSM.Include("Service.Sync")
local private = {
hashesTemp = {},
spellsTemp = {},
spellsProfessionLookupTemp = {},
spellInfoTemp = {
spellIds = {},
mats = {},
itemStrings = {},
names = {},
numResults = {},
hasCDs = {},
},
accountLookup = {},
accountStatus = {},
}
local RETRY_DELAY = 5
local PROFESSION_HASH_FIELDS = { "spellId", "itemString" }
-- ============================================================================
-- Module Functions
-- ============================================================================
function CraftingSync.OnInitialize()
Sync.RegisterConnectionChangedCallback(private.ConnectionChangedHandler)
Sync.RegisterRPC("CRAFTING_GET_HASHES", private.RPCGetHashes)
Sync.RegisterRPC("CRAFTING_GET_SPELLS", private.RPCGetSpells)
Sync.RegisterRPC("CRAFTING_GET_SPELL_INFO", private.RPCGetSpellInfo)
end
function CraftingSync.GetStatus(account)
local status = private.accountStatus[account]
if not status then
return Theme.GetFeedbackColor("RED"):ColorText(L["Not Connected"])
elseif status == "UPDATING" or status == "RETRY" then
return Theme.GetFeedbackColor("YELLOW"):ColorText(L["Updating"])
elseif status == "SYNCED" then
return Theme.GetFeedbackColor("GREEN"):ColorText(L["Up to date"])
else
error("Invalid status: "..tostring(status))
end
end
-- ============================================================================
-- RPC Functions and Result Handlers
-- ============================================================================
function private.RPCGetHashes()
wipe(private.hashesTemp)
local player = UnitName("player")
private.GetPlayerProfessionHashes(player, private.hashesTemp)
return player, private.hashesTemp
end
function private.RPCGetHashesResultHandler(player, data)
if not player or not private.accountLookup[player] then
-- request timed out, so try again
Log.Warn("Getting hashes timed out")
if private.accountLookup[player] then
private.accountStatus[private.accountLookup[player]] = "RETRY"
Delay.AfterTime(RETRY_DELAY, private.RetryGetHashesRPC)
end
return
end
local currentInfo = TempTable.Acquire()
private.GetPlayerProfessionHashes(player, currentInfo)
local requestProfessions = TempTable.Acquire()
for profession, hash in pairs(data) do
if hash == currentInfo[profession] then
Log.Info("%s data for %s already up to date", profession, player)
else
Log.Info("Need updated %s data from %s (%s, %s)", profession, player, hash, tostring(currentInfo[hash]))
requestProfessions[profession] = true
end
end
TempTable.Release(currentInfo)
if next(requestProfessions) then
private.accountStatus[private.accountLookup[player]] = "UPDATING"
Sync.CallRPC("CRAFTING_GET_SPELLS", player, private.RPCGetSpellsResultHandler, requestProfessions)
else
private.accountStatus[private.accountLookup[player]] = "SYNCED"
end
TempTable.Release(requestProfessions)
end
function private.RPCGetSpells(professions)
wipe(private.spellsProfessionLookupTemp)
wipe(private.spellsTemp)
local player = UnitName("player")
local query = TSM.Crafting.CreateRawCraftsQuery()
:Select("spellId", "profession")
:Custom(private.QueryProfessionFilter, professions)
:Custom(private.QueryPlayerFilter, player)
:OrderBy("spellId", true)
for _, spellId, profession in query:Iterator() do
private.spellsProfessionLookupTemp[spellId] = profession
tinsert(private.spellsTemp, spellId)
end
query:Release()
return player, private.spellsProfessionLookupTemp, private.spellsTemp
end
function private.RPCGetSpellsResultHandler(player, professionLookup, spells)
if not player or not private.accountLookup[player] then
-- request timed out, so try again from the start
Log.Warn("Getting spells timed out")
if private.accountLookup[player] then
private.accountStatus[private.accountLookup[player]] = "RETRY"
Delay.AfterTime(RETRY_DELAY, private.RetryGetHashesRPC)
end
return
end
for i = #spells, 1, -1 do
local spellId = spells[i]
if TSM.Crafting.HasSpellId(spellId) then
-- already have this spell so just make sure this player is added
TSM.Crafting.AddPlayer(spellId, player)
tremove(spells, i)
end
end
if #spells == 0 then
Log.Info("Spells up to date for %s", player)
private.accountStatus[private.accountLookup[player]] = "SYNCED"
else
Log.Info("Requesting %d spells from %s", #spells, player)
Sync.CallRPC("CRAFTING_GET_SPELL_INFO", player, private.RPCGetSpellInfoResultHandler, professionLookup, spells)
end
end
function private.RPCGetSpellInfo(professionLookup, spells)
for _, tbl in pairs(private.spellInfoTemp) do
wipe(tbl)
end
for i, spellId in ipairs(spells) do
private.spellInfoTemp.spellIds[i] = spellId
private.spellInfoTemp.mats[i] = TSM.db.factionrealm.internalData.crafts[spellId].mats
private.spellInfoTemp.itemStrings[i] = TSM.db.factionrealm.internalData.crafts[spellId].itemString
private.spellInfoTemp.names[i] = TSM.db.factionrealm.internalData.crafts[spellId].name
private.spellInfoTemp.numResults[i] = TSM.db.factionrealm.internalData.crafts[spellId].numResult
private.spellInfoTemp.hasCDs[i] = TSM.db.factionrealm.internalData.crafts[spellId].hasCD
end
Log.Info("Sent %d spells", #private.spellInfoTemp.spellIds)
return UnitName("player"), professionLookup, private.spellInfoTemp
end
function private.RPCGetSpellInfoResultHandler(player, professionLookup, spellInfo)
if not player or not professionLookup or not spellInfo or not private.accountLookup[player] then
-- request timed out, so try again from the start
Log.Warn("Getting spell info timed out")
if private.accountLookup[player] then
private.accountStatus[private.accountLookup[player]] = "RETRY"
Delay.AfterTime(RETRY_DELAY, private.RetryGetHashesRPC)
end
return
end
for i, spellId in ipairs(spellInfo.spellIds) do
TSM.Crafting.CreateOrUpdate(spellId, spellInfo.itemStrings[i], professionLookup[spellId], spellInfo.names[i], spellInfo.numResults[i], player, spellInfo.hasCDs[i] and true or false)
for itemString in pairs(spellInfo.mats[i]) do
TSM.db.factionrealm.internalData.mats[itemString] = TSM.db.factionrealm.internalData.mats[itemString] or {}
end
TSM.Crafting.SetMats(spellId, spellInfo.mats[i])
end
Log.Info("Added %d spells from %s", #spellInfo.spellIds, player)
private.accountStatus[private.accountLookup[player]] = "SYNCED"
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.ConnectionChangedHandler(account, player, connected)
if connected then
private.accountLookup[player] = account
private.accountStatus[account] = "UPDATING"
-- issue a request for profession info
Sync.CallRPC("CRAFTING_GET_HASHES", player, private.RPCGetHashesResultHandler)
else
private.accountLookup[player] = nil
private.accountStatus[account] = nil
end
end
function private.RetryGetHashesRPC()
for player, account in pairs(private.accountLookup) do
if private.accountStatus[account] == "RETRY" then
Sync.CallRPC("CRAFTING_GET_HASHES", player, private.RPCGetHashesResultHandler)
end
end
end
function private.QueryProfessionFilter(row, professions)
return professions[row:GetField("profession")]
end
function private.QueryPlayerFilter(row, player)
return String.SeparatedContains(row:GetField("players"), ",", player)
end
function private.GetPlayerProfessionHashes(player, resultTbl)
local query = TSM.Crafting.CreateRawCraftsQuery()
:Custom(private.QueryPlayerFilter, player)
:OrderBy("spellId", true)
query:GroupedHash(PROFESSION_HASH_FIELDS, "profession", resultTbl)
query:Release()
end