Mercurial > wow > breuesk
changeset 105:c6c748a5823b tip
Collaborative list trimming 80% functional
Updates for the zone-in problem
author | John@Yosemite-PC |
---|---|
date | Sun, 06 May 2012 08:33:34 -0400 |
parents | 9aa2dcbbdc87 |
children | |
files | Admin.lua Comm.lua Lists.lua |
diffstat | 3 files changed, 131 insertions(+), 51 deletions(-) [+] |
line wrap: on
line diff
--- a/Admin.lua Sun May 06 08:30:15 2012 -0400 +++ b/Admin.lua Sun May 06 08:33:34 2012 -0400 @@ -15,8 +15,13 @@ adminList = {} +local lastZoneTime = 0 +local function ZoneChanged() + lastZoneTime = _G.time() +end local function GuildRosterUpdate() local guildInfoText = _G.GetGuildInfoText() + if lastZoneTime+5 > _G.time() then return end -- silly workaround - GGIT() returns "" when you zone in local newAdminList = {} for line in guildInfoText:gmatch("[^\r\n]+") do local l,r = line:match("(.*):(.*)") -- could use wow strsplit had I known about it before writing this @@ -67,60 +72,94 @@ function RemoteAdminUpdateReceived(sender,remoteAdminStatusTable) if not admin then return end - local rs = remoteAdminStatusTable - local events = {} -- record all timestamps seen in this update + local rs,base,changes = unpack(remoteAdminStatusTable) for i,_ in pairs(adminList) do -- update each admin's entry in your own DB - -- grab the db copy and the incoming copy for that admin - if not db.profile.adminStatus then db.profile.adminStatus = {} end - local dbs = db.profile.adminStatus[i] or {base=0, changes={}} - local ics = rs[i] or {base=0, changes={}} + if i ~= me then + -- grab the db copy and the incoming copy for that admin + if not db.profile.adminStatus then db.profile.adminStatus = {} end + local dbs = db.profile.adminStatus[i] or {base=0, changes={}} + local ics = rs[i] or {base=0, changes={}} - -- figure out which is better and keep that one - -- winning criteria: - -- * broadcast was actually from that person (ie best - -- verification possible) - -- * newer base - -- * same base, more entries - -- * todo: see if date last observed is a better option + -- figure out which is better and keep that one + -- winning criteria: + -- * broadcast was actually from that person (ie best + -- verification possible) + -- * newer base + -- * same base, more entries + -- * todo: see if date last observed is a better option - if i==sender then - db.profile.adminStatus[i] = ics - elseif ics.base > dbs.base or (ics.base==dbs.base and getn(ics.changes) > getn(dbs.changes)) then - db.profile.adminStatus[i] = ics + if i==sender then + db.profile.adminStatus[i] = ics + elseif ics.base > dbs.base or (ics.base==dbs.base and getn(ics.changes) > getn(dbs.changes)) then + db.profile.adminStatus[i] = ics + end end end - local rss = rs[sender] + if changes and getn(changes)>0 then + IntegrateChangeDiff(base,changes) + end - -- now figure out what I'm missing - and ask for it! + -- trim if the replies said it's safe - -- construct a hash table of all entries that the sender has / should have - local entries = {} - for i,v in pairs(rs) do - if v.changes then - for j,k in pairs(v.changes) do - entries[k.time] = true + local trimPoint = db.profile.time + -- come up with a tentative starting point (max base) + for i,v in pairs(db.profile.adminStatus) do + if v.base > trimPoint then trimPoint = v.base end + end + + local pointer = {} + -- fast forward pointers *past* the trimPoint in each list + for p,l in pairs(db.profile.adminStatus) do + pointer[p] = 1 + for i,v in ipairs(l.changes) do + if v <= trimPoint then + pointer[p] = i+1 -- "past" the trim point - might point to nil + else + break end end end - -- now go back and scrub my own keys from that list + print("pointers") + PrintTable(pointer) + for i,v in ipairs(db.profile.changes) do - entries[v.time] = nil + if v.time > trimPoint then -- advance to the trim point estimate before doing anything + -- into uncharted territory, let's see how far we can push it + local continue = true + for p,t in pairs(pointer) do + local dbpapct = db.profile.adminStatus[p].changes[t] + if dbpapct and dbpapct==v.time then + pointer[p] = pointer[p]+1 + else + continue=false + break + end + trimPoint = v.time + end + if not continue then break end + end end - -- what's left is what I need to ask for - local request = {} - for i,v in pairs(entries) do - if v then table.insert(request,i) end + print("pointers") + PrintTable(pointer) + if trimPoint > db.profile.time then + + -- protect trimming back to beginning of previous month so we're not + -- trimming like madmen + local ct = _G.date("*t",_G.time()) + ct.month = ct.month-1 + if ct.month < 1 then ct.month = 12 end + ct.day = 1 + ct.hour = 1 + ct.minute = 0 + ct.sec = 0 + local ts = _G.time(ct) + print("I think I can trim to",trimPoint,ts) + TrimLists(ts) + else + print("no bother trimming",trimPoint) end - table.sort(request) - Comm:RequestSpecificChanges(request,sender) - - for - -- specifically leaving this broken. note to self. - -- this still isn't good enough. it doesn't communicate an admin's - -- present working state. like if they had put in new changes since - -- loading up. or learned of some changes to fill in an old gap end function InitializeAdmin() @@ -153,6 +192,9 @@ end event:RegisterEvent("GUILD_ROSTER_UPDATE",GuildRosterUpdate) + event:RegisterEvent("ZONE_CHANGED_NEW_AREA",ZoneChanged) + event:RegisterEvent("ZONE_CHANGED_INDOORS",ZoneChanged) + event:RegisterEvent("ZONE_CHANGED",ZoneChanged) _G.GuildRoster() -- will eventually force the event to fire if me == "Breuemama" then -- debugging only
--- a/Comm.lua Sun May 06 08:30:15 2012 -0400 +++ b/Comm.lua Sun May 06 08:33:34 2012 -0400 @@ -111,7 +111,7 @@ local success, o = CreateChangeDiff(remoteBase,t) if success and getn(o) > 0 then - Send("CU",o) + Send("CU",{remoteBase,o}) end if not success then -- push print("Received request at differing timebase",remoteBase,db.profile.time," ... pushing") @@ -122,7 +122,10 @@ ["CU"] = function(self,packet,sender,isloop) -- blindly trust an admin loot master if isloop then return end - IntegrateChangeDiff(packet) + local base,changes = unpack(packet) + if base and base > 0 and changes and getn(changes) > 0 then + IntegrateChangeDiff(base,changes) + end end, ["RequestCatchup"] = function(self,from) -- todo: integrate from @@ -153,14 +156,16 @@ print("SA") if isloop then return end if admin then - SendAdmin("SR",onloadAdminStatus) -- SR ... prevent infinite loop please + -- todo: only send back a diff. this is barbaric. + SendAdmin("SR",{onloadAdminStatus,db.profile.time,db.profile.changes}) -- SR ... prevent infinite loop please RemoteAdminUpdateReceived(sender,packet) end end, ["SendAdminStatusTable"] = function(self) if admin then - SendAdmin("SA",onloadAdminStatus) -- only send onload status, since that's the only data you're guaranteed to have safely safed + SendAdmin("SA",{onloadAdminStatus,db.profile.time}) -- only send onload status, since that's the only data you're guaranteed to have safely saved + -- todo: see whether the above comment is correct, or the code end end, }
--- a/Lists.lua Sun May 06 08:30:15 2012 -0400 +++ b/Lists.lua Sun May 06 08:33:34 2012 -0400 @@ -8,7 +8,6 @@ -- TODO: switch all action functions to use identifiers rather than names --- TODO: collaborative list trimming -- TODO: collapse slists into delimited strings for space (premature optimization?) -- TODO: organize working state data a little more carefully - hard to keep -- track of all the arrays that are floating out there @@ -850,19 +849,31 @@ end end - -- apply first half + print("before -",#before) + --return + + --apply first half CreateWorkingStateFromChanges(before) -- save this state permanently; trim the changes permanently LootLists:SaveToDB(db) PersonList:SaveToDB(db) while db.profile.changes ~= nil and db.profile.changes[1] ~= nil and db.profile.changes[1].time <= time do - table.remove(db.profile.changes,1) + table.remove(db.profile.changes,1) end + print("reapplying ",_G.getn(db.profile.changes)) db.profile.time = lastTime -- using the trimmed list and the new bases, recreate the working state - CreateWorkingStateFromChanges(db.profile.changes) + --CreateWorkingStateFromChanges(db.profile.changes) + + for i,v in ipairs(db.profile.changes) do + ProcessChange(v) + end + + if changelistener then + changelistener:dataevent() + end end @@ -943,7 +954,7 @@ end end -function IntegrateChangeDiff(remoteChanges) -- todo: check against remoteBase before committing to insanity +function IntegrateChangeDiff(remoteBase,remoteChanges) local c = remoteChanges local old = db.profile.changes @@ -953,9 +964,20 @@ local cp = 1 local no = getn(old) + + local worthRefresh = false -- only worth refreshing if we take changes from c + + -- if remotebase is older, don't integrate anything prior to db.profile.time. if they're newer, it's ok to merge in their changes + if remoteBase < db.profile.time then + while c[1] and c[1].time < db.profile.time do + table.remove(c,1) + end + end + local nc = getn(c) - if no == 0 then + if no == 0 and nc > 0 then + worthRefresh = true db.profile.changes = c else while op <= no or cp <= nc do -- lists are pre-sorted. insertion merge them @@ -963,9 +985,17 @@ table.insert(new,old[op]) op = op + 1 elseif op > no then + worthRefresh=true table.insert(new,c[cp]) cp = cp + 1 + elseif c[cp].time == old[op].time then + -- todo: even though they're the same timestamp, still compare + -- contents for sanity + table.insert(new,old[cp]) + cp = cp + 1 + op = op + 1 elseif c[cp].time < old[op].time then + worthRefresh=true table.insert(new,c[cp]) cp = cp + 1 elseif c[cp].time > old[op].time then @@ -979,8 +1009,10 @@ db.profile.changes = new end - CreateWorkingStateFromChanges(db.profile.changes) - if changeListener then - changeListener:DataEvent() + if worthRefresh then + CreateWorkingStateFromChanges(db.profile.changes) + if changelistener then + changelistener:dataevent() + end end end