John@72
|
1 local bsk=bsk
|
John@72
|
2 local _G=_G
|
John@72
|
3 local table=table
|
John@72
|
4 local pairs=pairs
|
John@72
|
5 local setmetatable=setmetatable
|
John@72
|
6 local ipairs=ipairs
|
John@72
|
7 local unpack=unpack
|
John@72
|
8 local string=string
|
John@72
|
9 local sformat=string.format
|
John@72
|
10 local tostring=tostring
|
John@72
|
11 local type=type
|
John@72
|
12 local getn=getn
|
John@72
|
13
|
John@72
|
14 local commlib = LibStub("AceComm-3.0") or _G.error("Couldn't load up AceComm")
|
John@72
|
15 local s = LibStub("AceSerializer-3.0") or _G.error("Couldn't load up AceSerializer")
|
John@72
|
16
|
John@72
|
17 setfenv(1,bsk)
|
John@72
|
18
|
John@72
|
19 local function BuildPacket(handler,message)
|
John@72
|
20 local p = {handler,message}
|
John@72
|
21 local str = s:Serialize({handler,message})
|
John@72
|
22 print("sending",str)
|
John@72
|
23 return p,str
|
John@72
|
24 end
|
John@72
|
25
|
John@72
|
26 local function SendMessage(str)
|
John@72
|
27 --commlib:SendCommMessage("BSKADDON",str,"GUILD")
|
John@86
|
28 commlib:SendCommMessage("BSKADDON"..commversion,str,"RAID")
|
John@72
|
29 end
|
John@72
|
30
|
John@72
|
31 local function Send(handler,message)
|
John@72
|
32 local p,str = BuildPacket(handler,message)
|
John@72
|
33 SendMessage(str)
|
John@72
|
34 end
|
John@72
|
35
|
John@72
|
36 -- todo: ActivateList and AddReserve -> state
|
John@72
|
37 Comm =
|
John@72
|
38 {
|
John@72
|
39 ["SS"] = function(self,packet,sender,isloop)
|
John@72
|
40 print("isloop",isloop)
|
John@72
|
41 if not isloop then DispatchState(packet) end
|
John@72
|
42 end,
|
John@72
|
43 ["SendStateChange"] = function(self,...)
|
John@72
|
44 local p,str = BuildPacket("SS",{...})
|
John@72
|
45 DispatchState(p[2])
|
John@72
|
46 SendMessage(str)
|
John@72
|
47 end,
|
John@72
|
48 ["AR"] = function(self,packet,sender,isloop)
|
John@72
|
49 if isloop then return end
|
John@72
|
50 PersonList:AddReserve(packet)
|
John@72
|
51 changeListener:DataEvent()
|
John@72
|
52 end,
|
John@72
|
53 ["AddReserve"] = function(self,packet)
|
John@72
|
54 if changeListener then
|
John@72
|
55 changeListener:DataEvent(change)
|
John@72
|
56 end
|
John@72
|
57 Send("AR",packet)
|
John@72
|
58 end,
|
John@72
|
59 ["SendChange"] = function(self,change)
|
John@72
|
60 if changeListener then
|
John@72
|
61 changeListener:DataEvent(change)
|
John@72
|
62 end
|
John@72
|
63 Send("CC",change)
|
John@72
|
64 end,
|
John@72
|
65 ["CC"] = function(self,change,sender,isloop)
|
John@72
|
66 if isloop then return end
|
John@91
|
67 table.insert(db.profile.changes,change)
|
John@72
|
68 ProcessChange(change)
|
John@72
|
69 changeListener:DataEvent()
|
John@72
|
70 end,
|
John@72
|
71 ["Push"] = function(self)
|
John@91
|
72 Send("PU",{db.profile.lists,db.profile.persons,db.profile.changes,db.profile.time})
|
John@72
|
73 end,
|
John@72
|
74 ["PU"] = function(self,packet,sender,isloop)
|
John@72
|
75 if isloop then return end
|
John@91
|
76 db.profile.lists,db.profile.persons,db.profile.changes,db.profile.time = unpack(packet)
|
John@72
|
77 CreateWorkingStateFromChanges(db.profile.changes)
|
John@72
|
78 if changeListener then
|
John@72
|
79 changeListener:DataEvent()
|
John@72
|
80 end
|
John@72
|
81 end,
|
John@91
|
82
|
John@91
|
83 ["TS"] = function(self,packet,sender,isloop)
|
John@91
|
84 if isloop then return end
|
John@91
|
85 if masterLooterIsMe and admin then
|
John@91
|
86 -- only non-admins will send this message, send them the present
|
John@91
|
87 -- working state
|
John@92
|
88
|
John@92
|
89 local t = packet
|
John@92
|
90 local remoteBase = table.remove(t,1)
|
John@92
|
91
|
John@92
|
92 -- if their base is older than ours, this is easy - send them our
|
John@92
|
93 -- base and all the changes
|
John@92
|
94 -- if their base is equal to ours, then diff their changes vs ours
|
John@92
|
95 -- and send them the remainder - it's ok if they have changes we
|
John@92
|
96 -- don't
|
John@92
|
97 -- if their base is newer, then we have a problem - it means another
|
John@92
|
98 -- admin rebased and we aren't aware of that. but the other admin
|
John@92
|
99 -- wouldn't have done that if they didn't believe all the admins
|
John@92
|
100 -- were synced up to the release point. So do we trust that and use
|
John@92
|
101 -- this as a rebase opportunity? print an error? just reply that we
|
John@92
|
102 -- don't have anything new to share with them? only send them
|
John@92
|
103 --
|
John@92
|
104
|
John@92
|
105 if remoteBase == db.profile.time then
|
John@92
|
106 local j = 1 -- index in foreign list
|
John@92
|
107 local n = getn(t)
|
John@92
|
108 local o = {}
|
John@92
|
109 for i,v in pairs(db.profile.changes) do -- for each timestamp in our list
|
John@92
|
110 if t and t[j] < v.time then
|
John@92
|
111 table.insert(o,v)
|
John@92
|
112 end
|
John@92
|
113 while j<n and t[j] <= v.time do j = j+1 end -- advance the foreign pointer past our current entry
|
John@92
|
114 end -- j>=n ? add because the remote hit end of road. lt? add because it's a missing stamp
|
John@92
|
115 print("Received request at timebase",remoteBase,"and returning:")
|
John@92
|
116 PrintTable(o)
|
John@93
|
117 if getn(o) > 0 then
|
John@93
|
118 Send("CU",o) -- todo: send privately to the requster
|
John@93
|
119 end
|
John@92
|
120 else
|
John@93
|
121 print("Received request at differing timebase",remoteBase,db.profile.time," ... pushing")
|
John@93
|
122 self:Push() -- todo: send privately to requester
|
John@92
|
123 end
|
John@91
|
124 end
|
John@91
|
125 end,
|
John@91
|
126
|
John@91
|
127 ["CU"] = function(self,packet,sender,isloop) -- blindly trust an admin loot master
|
John@91
|
128 if isloop then return end
|
John@93
|
129
|
John@93
|
130 local c = packet
|
John@93
|
131 local old = db.profile.changes
|
John@93
|
132
|
John@93
|
133 local new = {}
|
John@93
|
134
|
John@93
|
135 local op = 1
|
John@93
|
136 local cp = 1
|
John@93
|
137
|
John@93
|
138 local no = getn(old)
|
John@93
|
139 local nc = getn(c)
|
John@93
|
140
|
John@93
|
141 if no == 0 then
|
John@93
|
142 db.profile.changes = c
|
John@93
|
143 else
|
John@94
|
144 while op <= no or cp <= nc do -- lists are pre-sorted. insertion merge them
|
John@94
|
145 if cp > nc then -- inelegant
|
John@94
|
146 table.insert(new,old[op])
|
John@94
|
147 op = op + 1
|
John@94
|
148 elseif op > no then
|
John@94
|
149 table.insert(new,c[cp])
|
John@94
|
150 cp = cp + 1
|
John@94
|
151 elseif c[cp].time < old[op].time then
|
John@94
|
152 table.insert(new,c[cp])
|
John@94
|
153 cp = cp + 1
|
John@94
|
154 elseif c[cp].time > old[op].time then
|
John@94
|
155 table.insert(new,old[op])
|
John@94
|
156 op = op + 1
|
John@94
|
157 else
|
John@93
|
158 error("Bad update received from ",sender)
|
John@93
|
159 end
|
John@93
|
160 end
|
John@94
|
161 print("Updating changes - ",getn(new), "entries")
|
John@93
|
162 db.profile.changes = new
|
John@93
|
163 end
|
John@93
|
164
|
John@91
|
165 CreateWorkingStateFromChanges(db.profile.changes)
|
John@91
|
166 if changeListener then
|
John@91
|
167 changeListener:DataEvent()
|
John@91
|
168 end
|
John@91
|
169 end,
|
John@91
|
170
|
John@91
|
171 ["RequestCatchup"] = function(self)
|
John@91
|
172 if not admin then
|
John@92
|
173 --local string = _g.tostring(timestamp)
|
John@92
|
174 --for i,v in pairs(db.profile.changes) do -- append all change timestamps
|
John@92
|
175 -- string = string .. "|" .. _g.tostring(v.time)
|
John@92
|
176 --end
|
John@92
|
177 local t = {db.profile.time}
|
John@92
|
178 for i,v in pairs(db.profile.changes) do -- append all change timestamps
|
John@92
|
179 table.insert(t,v.time)
|
John@92
|
180 end
|
John@92
|
181 Send("TS", t) -- todo: send privately to loot master
|
John@91
|
182 else
|
John@91
|
183 -- todo: admins talking to one another
|
John@91
|
184 end
|
John@91
|
185
|
John@91
|
186 end,
|
John@72
|
187 }
|
John@72
|
188
|
John@72
|
189 local function OnCommReceived(prefix, message, distribution, sender)
|
John@72
|
190 print("Received on", distribution)
|
John@72
|
191 local success,packet = s:Deserialize(message)
|
John@72
|
192 local isloop = _G.UnitName("player") == sender
|
John@72
|
193
|
John@72
|
194 print("received",message)
|
John@72
|
195
|
John@72
|
196 Comm[packet[1]](Comm,packet[2],sender,isloop)
|
John@72
|
197 end
|
John@72
|
198
|
John@86
|
199 alertlist = {}
|
John@86
|
200 local function OnOlderCommReceived(prefix, message, distribution, sender)
|
John@86
|
201 if not alertlist[sender] then
|
John@86
|
202 printf("Received communication from %s, who is using an older version of the addon; ignoring",sender)
|
John@86
|
203 alertlist[sender]=true
|
John@86
|
204 end
|
John@86
|
205 end
|
John@86
|
206
|
John@86
|
207 local function OnNewerCommReceived(prefix, message, distribution, sender)
|
John@86
|
208 if not alertlist[sender] then
|
John@86
|
209 printf("Received communication from %s, who is using a newer version of the addon; ignoring",sender)
|
John@86
|
210 alertlist[sender]=true
|
John@86
|
211 end
|
John@86
|
212 end
|
John@86
|
213
|
John@72
|
214 function InitializeComm()
|
John@86
|
215 for i = 0,commversion-1 do
|
John@86
|
216 commlib:RegisterComm("BSKADDON"..i,OnOlderCommReceived)
|
John@86
|
217 end
|
John@86
|
218 commlib:RegisterComm("BSKADDON"..commversion,OnCommReceived)
|
John@86
|
219 for i = commversion+1,commversion+5 do -- some sensible number
|
John@86
|
220 commlib:RegisterComm("BSKADDON"..i,OnNewerCommReceived)
|
John@86
|
221 end
|
John@72
|
222 end
|
John@72
|
223
|
John@72
|
224 function DeinitializeComm()
|
John@72
|
225
|
John@72
|
226 end
|