John@72: local bsk=bsk John@72: local _G=_G John@72: local table=table John@72: local pairs=pairs John@72: local setmetatable=setmetatable John@72: local ipairs=ipairs John@72: local unpack=unpack John@72: local string=string John@72: local sformat=string.format John@72: local tostring=tostring John@72: local type=type John@72: local getn=getn John@72: John@72: local commlib = LibStub("AceComm-3.0") or _G.error("Couldn't load up AceComm") John@72: local s = LibStub("AceSerializer-3.0") or _G.error("Couldn't load up AceSerializer") John@72: John@72: setfenv(1,bsk) John@72: John@72: local function BuildPacket(handler,message) John@72: local p = {handler,message} John@72: local str = s:Serialize({handler,message}) John@72: print("sending",str) John@72: return p,str John@72: end John@72: John@72: local function SendMessage(str) John@72: --commlib:SendCommMessage("BSKADDON",str,"GUILD") John@86: commlib:SendCommMessage("BSKADDON"..commversion,str,"RAID") John@72: end John@72: John@72: local function Send(handler,message) John@72: local p,str = BuildPacket(handler,message) John@72: SendMessage(str) John@72: end John@72: John@72: -- todo: ActivateList and AddReserve -> state John@72: Comm = John@72: { John@72: ["SS"] = function(self,packet,sender,isloop) John@72: print("isloop",isloop) John@72: if not isloop then DispatchState(packet) end John@72: end, John@72: ["SendStateChange"] = function(self,...) John@72: local p,str = BuildPacket("SS",{...}) John@72: DispatchState(p[2]) John@72: SendMessage(str) John@72: end, John@72: ["AR"] = function(self,packet,sender,isloop) John@72: if isloop then return end John@72: PersonList:AddReserve(packet) John@72: changeListener:DataEvent() John@72: end, John@72: ["AddReserve"] = function(self,packet) John@72: if changeListener then John@72: changeListener:DataEvent(change) John@72: end John@72: Send("AR",packet) John@72: end, John@72: ["SendChange"] = function(self,change) John@72: if changeListener then John@72: changeListener:DataEvent(change) John@72: end John@72: Send("CC",change) John@72: end, John@72: ["CC"] = function(self,change,sender,isloop) John@72: if isloop then return end John@91: table.insert(db.profile.changes,change) John@72: ProcessChange(change) John@72: changeListener:DataEvent() John@72: end, John@72: ["Push"] = function(self) John@91: Send("PU",{db.profile.lists,db.profile.persons,db.profile.changes,db.profile.time}) John@72: end, John@72: ["PU"] = function(self,packet,sender,isloop) John@72: if isloop then return end John@91: db.profile.lists,db.profile.persons,db.profile.changes,db.profile.time = unpack(packet) John@72: CreateWorkingStateFromChanges(db.profile.changes) John@72: if changeListener then John@72: changeListener:DataEvent() John@72: end John@72: end, John@91: John@91: ["TS"] = function(self,packet,sender,isloop) John@91: if isloop then return end John@91: if masterLooterIsMe and admin then John@91: -- only non-admins will send this message, send them the present John@91: -- working state John@91: -- todo: if they send a timestamp that's somewhere along our John@91: -- timeline, then just catch them up John@92: --local dbPersons = {toons=PersonList.toons,time=PersonList.time} John@92: --Send("CU",{dbPersons,LootLists.l,timestamp}) -- todo: send privately John@92: John@92: local t = packet John@92: local remoteBase = table.remove(t,1) John@92: John@92: -- if their base is older than ours, this is easy - send them our John@92: -- base and all the changes John@92: -- if their base is equal to ours, then diff their changes vs ours John@92: -- and send them the remainder - it's ok if they have changes we John@92: -- don't John@92: -- if their base is newer, then we have a problem - it means another John@92: -- admin rebased and we aren't aware of that. but the other admin John@92: -- wouldn't have done that if they didn't believe all the admins John@92: -- were synced up to the release point. So do we trust that and use John@92: -- this as a rebase opportunity? print an error? just reply that we John@92: -- don't have anything new to share with them? only send them John@92: -- John@92: John@92: if remoteBase == db.profile.time then John@92: local j = 1 -- index in foreign list John@92: local n = getn(t) John@92: local o = {} John@92: for i,v in pairs(db.profile.changes) do -- for each timestamp in our list John@92: if t and t[j] < v.time then John@92: table.insert(o,v) John@92: end John@92: while j=n ? add because the remote hit end of road. lt? add because it's a missing stamp John@92: print("Received request at timebase",remoteBase,"and returning:") John@92: PrintTable(o) John@92: else John@92: print("Received request at differing timebase",remoteBase,db.profile.time) John@92: end John@91: end John@91: end, John@91: John@91: ["CU"] = function(self,packet,sender,isloop) -- blindly trust an admin loot master John@91: if isloop then return end John@91: print("CU") John@91: db.profile.persons,db.profile.lists,db.profile.time = unpack(packet) John@91: db.profile.changes = {} John@91: CreateWorkingStateFromChanges(db.profile.changes) John@91: if changeListener then John@91: changeListener:DataEvent() John@91: end John@91: end, John@91: John@91: ["RequestCatchup"] = function(self) John@91: if not admin then John@92: --local string = _g.tostring(timestamp) John@92: --for i,v in pairs(db.profile.changes) do -- append all change timestamps John@92: -- string = string .. "|" .. _g.tostring(v.time) John@92: --end John@92: local t = {db.profile.time} John@92: for i,v in pairs(db.profile.changes) do -- append all change timestamps John@92: table.insert(t,v.time) John@92: end John@92: Send("TS", t) -- todo: send privately to loot master John@91: else John@91: -- todo: admins talking to one another John@91: end John@91: John@91: end, John@72: } John@72: John@72: local function OnCommReceived(prefix, message, distribution, sender) John@72: print("Received on", distribution) John@72: local success,packet = s:Deserialize(message) John@72: local isloop = _G.UnitName("player") == sender John@72: John@72: print("received",message) John@72: John@72: Comm[packet[1]](Comm,packet[2],sender,isloop) John@72: end John@72: John@86: alertlist = {} John@86: local function OnOlderCommReceived(prefix, message, distribution, sender) John@86: if not alertlist[sender] then John@86: printf("Received communication from %s, who is using an older version of the addon; ignoring",sender) John@86: alertlist[sender]=true John@86: end John@86: end John@86: John@86: local function OnNewerCommReceived(prefix, message, distribution, sender) John@86: if not alertlist[sender] then John@86: printf("Received communication from %s, who is using a newer version of the addon; ignoring",sender) John@86: alertlist[sender]=true John@86: end John@86: end John@86: John@72: function InitializeComm() John@86: for i = 0,commversion-1 do John@86: commlib:RegisterComm("BSKADDON"..i,OnOlderCommReceived) John@86: end John@86: commlib:RegisterComm("BSKADDON"..commversion,OnCommReceived) John@86: for i = commversion+1,commversion+5 do -- some sensible number John@86: commlib:RegisterComm("BSKADDON"..i,OnNewerCommReceived) John@86: end John@72: end John@72: John@72: function DeinitializeComm() John@72: John@72: end