You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.7 KiB

-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- http://www.curse.com/addons/wow/tradeskill-master --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- This file handled multi-account syncing and communication
-- register this file with Ace libraries
local TSM = select(2, ...)
local Sync = TSM:NewModule("Sync", "AceComm-3.0", "AceEvent-3.0")
TSMAPI.Sync = {}
local private = {callbacks={}, addedFriends={}, invalidPlayers={}}
TSMAPI:RegisterForTracing(private, "TradeSkillMaster.Sync_private")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster") -- loads the localization table
-- Request friend info from the server
ShowFriends()
function Sync:OnEnable()
Sync:RegisterComm("TSMSyncData")
Sync:RegisterEvent("CHAT_MSG_SYSTEM")
local data = {characters={}, accountKey=TSMAPI.Sync:GetAccountKey()}
for name in pairs(TSM.db.realm.characters) do
data.characters[name] = TSMAPI.Sync:GetAccountKey()
end
TSMAPI:CreateTimeDelay("syncSetupDelay", 3, function() TSMAPI.Sync:BroadcastData("TradeSkillMaster", "SETUP", data) end)
end
--Load the libraries
local libS = LibStub:GetLibrary("AceSerializer-3.0")
local libC = LibStub:GetLibrary("LibCompress")
local libCE = libC:GetAddonEncodeTable()
function Sync:OnCommReceived(_, data, _, source)
-- remove realm name from source
source = ("-"):split(source)
-- Decode the compressed data
data = libCE:Decode(data)
-- Decompress the decoded data
local data = libC:Decompress(data)
if not data then return end
-- Deserialize the decompressed data
local success
local tmpData = data
success, data = libS:Deserialize(data)
if not success or not data then return end
-- data is good, do callback
local key = data.__key
local module = data.__module
local account = data.__account
if not key or not module or not private.callbacks[module] then return end
data.__key = nil
data.__module = nil
data.__account = nil
-- make sure we are getting this from a known source
if not TSM.db.realm.syncAccounts[account] and (module ~= "TradeSkillMaster" and not data.isSetup) then return end
private.callbacks[module](key, data, source)
end
function Sync:CHAT_MSG_SYSTEM(_, msg)
if #private.addedFriends == 0 then return end
if msg == ERR_FRIEND_NOT_FOUND then
tremove(private.addedFriends, 1)
else
for i, v in ipairs(private.addedFriends) do
if format(ERR_FRIEND_ADDED_S, v) == msg then
tremove(private.addedFriends, i)
private.invalidPlayers[strlower(v)] = true
end
end
end
end
function TSMAPI.Sync:GetAccountKey()
return TSM.db.realm.accountKey
end
function TSM:RegisterSyncCallback(module, callback)
private.callbacks[module] = callback
end
function private:IsPlayerOnline(target, noAdd)
for i=1, GetNumFriends() do
local name, _, _, _, connected = GetFriendInfo(i)
if name and strlower(name) == strlower(target) then
return connected
end
end
if not noAdd and not private.invalidPlayers[strlower(target)] and GetNumFriends() ~= 50 then
-- add them as a friend
AddFriend(target)
tinsert(private.addedFriends, target)
for i=1, GetNumFriends() do
local name, _, _, _, connected = GetFriendInfo(i)
if name and strlower(name) == strlower(target) then
return connected
end
end
end
end
function TSMAPI.Sync:SendData(module, key, data, target)
local playerOnline = private:IsPlayerOnline(target)
if not playerOnline then return end
data.__module = module
data.__key = key
data.__account = TSMAPI.Sync:GetAccountKey()
-- we will encode using Huffman, LZW, and no compression separately
-- this is to deal with a bug in the compression code
local orig = data
local serialized = libS:Serialize(data)
local encodedData = {}
encodedData[1] = libCE:Encode(libC:CompressHuffman(serialized))
encodedData[2] = libCE:Encode(libC:CompressLZW(serialized))
encodedData[3] = libCE:Encode("\001"..serialized)
-- verify each compresion and pick the shorted valid one
local minIndex = -1
local minLen = math.huge
for i=#encodedData, 1, -1 do
local test = libC:Decompress(libCE:Decode(encodedData[i]))
if test and test == serialized and #encodedData[i] < minLen then
minLen = #encodedData[i]
minIndex = i
end
end
-- sanity check
if not encodedData[minIndex] then error("Could not encode data.") end
-- send off the serialized, compressed, and encoded data
Sync:SendCommMessage("TSMSyncData", encodedData[minIndex], "WHISPER", target)
end
function TSMAPI.Sync:BroadcastData(module, key, data)
for account, players in pairs(TSM.db.realm.syncAccounts) do
if account ~= TSMAPI.Sync:GetAccountKey() then
local sent
for player in pairs(players) do
if private:IsPlayerOnline(player, true) then
TSMAPI.Sync:SendData(module, key, data, player)
sent = true
break
end
end
if not sent then
for player in pairs(players) do
if private:IsPlayerOnline(player) then
TSMAPI.Sync:SendData(module, key, data, player)
sent = true
break
end
end
end
end
end
end
function private:SendSetupData(target, isResponse, isSetup)
local data = {isResponse=isResponse, isSetup=isSetup, characters={}, accountKey=TSMAPI.Sync:GetAccountKey()}
for name in pairs(TSM.db.realm.characters) do
data.characters[name] = true
end
TSMAPI.Sync:SendData("TradeSkillMaster", "SETUP", data, target)
end
function TSM:DoSyncSetup(target)
if target == "" then
private.syncSetupTarget = nil
return
end
private.syncSetupTarget = target
private:SendSetupData(target, nil, true)
end
function TSM:SyncCallback(key, data, source)
if key == "SETUP" then
if (data.isSetup and strlower(source) ~= strlower(private.syncSetupTarget or "")) or (not data.isSetup and not TSM.db.realm.syncAccounts[data.accountKey]) then
return
end
TSMAPI:Verify(data.accountKey ~= TSMAPI.Sync:GetAccountKey(), "It appears that you've manually copied your saved variables between accounts which will cause TSM's automatic sync'ing to not work. You'll need to undo this, and/or delete the TradeSkillMaster, TSM_Crafting, and TSM_ItemTracker saved variables files on both accounts (with WoW closed) in order to fix this.")
TSM.db.realm.syncAccounts[data.accountKey] = data.characters
if data.isSetup then
TSMAPI:CloseFrame()
TSM:Printf(L["Setup account sync'ing with the account which '%s' is on."], source)
end
if data.isResponse then return end -- already responded
private:SendSetupData(source, true, data.isSetup)
end
end