John@98: local bsk=bsk John@98: local _G=_G John@98: local table=table John@98: local pairs=pairs John@98: local setmetatable=setmetatable John@98: local ipairs=ipairs John@98: local string=string John@98: local sformat=string.format John@98: local strsplit=strsplit John@98: local tostring=tostring John@98: local type=type John@98: local unpack=unpack John@98: local getn=getn John@98: setfenv(1,bsk) John@98: John@98: adminList = {} John@98: John@105: local lastZoneTime = 0 John@105: local function ZoneChanged() John@105: lastZoneTime = _G.time() John@105: end John@98: local function GuildRosterUpdate() John@98: local guildInfoText = _G.GetGuildInfoText() John@105: if lastZoneTime+5 > _G.time() then return end -- silly workaround - GGIT() returns "" when you zone in John@98: local newAdminList = {} John@98: for line in guildInfoText:gmatch("[^\r\n]+") do John@98: local l,r = line:match("(.*):(.*)") -- could use wow strsplit had I known about it before writing this John@98: l = string.trim(l or "") John@98: r = string.trim(r or "") John@99: if l == "BSKADMIN" then -- found a juicy line. may contain multiple, comma or space delimited John@98: local admins = {strsplit(", ",r)} John@98: for _,a in pairs(admins) do John@98: a = string.trim(a or "") John@98: if a ~= "" then John@98: newAdminList[a] = true John@98: end John@98: end John@98: end John@98: end John@98: John@103: if me == "Breuemama" then -- todo: strictly debugging ... John@103: newAdminList[me] = true John@103: newAdminList["Breue"] = true John@103: end John@103: John@98: if _G.next(adminList) ~= nil then -- had old admins. don't want to spam on initial load John@98: -- diff new vs old John@98: for a in pairs(adminList) do John@98: if not newAdminList[a] then John@98: print("Admin removed:", a) John@98: end John@98: end John@98: for a in pairs(newAdminList) do John@98: if not adminList[a] then John@98: print("Admin added:",a) John@98: end John@98: end John@98: end John@98: adminList = newAdminList John@99: John@103: if adminList[me] then -- I'm an admin! John@99: admin = true John@99: bsk.db.profile.admin = true John@99: RegisterAdminChannels() John@99: else John@99: admin = false John@99: bsk.db.profile.admin = false John@99: UnregisterAdminChannels() John@99: end John@99: end John@99: John@99: function RemoteAdminUpdateReceived(sender,remoteAdminStatusTable) John@99: if not admin then return end John@99: John@105: local rs,base,changes = unpack(remoteAdminStatusTable) John@99: for i,_ in pairs(adminList) do -- update each admin's entry in your own DB John@99: John@105: if i ~= me then John@105: -- grab the db copy and the incoming copy for that admin John@105: if not db.profile.adminStatus then db.profile.adminStatus = {} end John@105: local dbs = db.profile.adminStatus[i] or {base=0, changes={}} John@105: local ics = rs[i] or {base=0, changes={}} John@99: John@105: -- figure out which is better and keep that one John@105: -- winning criteria: John@105: -- * broadcast was actually from that person (ie best John@105: -- verification possible) John@105: -- * newer base John@105: -- * same base, more entries John@105: -- * todo: see if date last observed is a better option John@99: John@105: if i==sender then John@105: db.profile.adminStatus[i] = ics John@105: elseif ics.base > dbs.base or (ics.base==dbs.base and getn(ics.changes) > getn(dbs.changes)) then John@105: db.profile.adminStatus[i] = ics John@105: end John@99: end John@99: end John@103: John@105: if changes and getn(changes)>0 then John@105: IntegrateChangeDiff(base,changes) John@105: end John@103: John@105: -- trim if the replies said it's safe John@103: John@105: local trimPoint = db.profile.time John@105: -- come up with a tentative starting point (max base) John@105: for i,v in pairs(db.profile.adminStatus) do John@105: if v.base > trimPoint then trimPoint = v.base end John@105: end John@105: John@105: local pointer = {} John@105: -- fast forward pointers *past* the trimPoint in each list John@105: for p,l in pairs(db.profile.adminStatus) do John@105: pointer[p] = 1 John@105: for i,v in ipairs(l.changes) do John@105: if v <= trimPoint then John@105: pointer[p] = i+1 -- "past" the trim point - might point to nil John@105: else John@105: break John@103: end John@103: end John@103: end John@105: print("pointers") John@105: PrintTable(pointer) John@105: John@103: for i,v in ipairs(db.profile.changes) do John@105: if v.time > trimPoint then -- advance to the trim point estimate before doing anything John@105: -- into uncharted territory, let's see how far we can push it John@105: local continue = true John@105: for p,t in pairs(pointer) do John@105: local dbpapct = db.profile.adminStatus[p].changes[t] John@105: if dbpapct and dbpapct==v.time then John@105: pointer[p] = pointer[p]+1 John@105: else John@105: continue=false John@105: break John@105: end John@105: trimPoint = v.time John@105: end John@105: if not continue then break end John@105: end John@103: end John@105: print("pointers") John@105: PrintTable(pointer) John@105: if trimPoint > db.profile.time then John@105: John@105: -- protect trimming back to beginning of previous month so we're not John@105: -- trimming like madmen John@105: local ct = _G.date("*t",_G.time()) John@105: ct.month = ct.month-1 John@105: if ct.month < 1 then ct.month = 12 end John@105: ct.day = 1 John@105: ct.hour = 1 John@105: ct.minute = 0 John@105: ct.sec = 0 John@105: local ts = _G.time(ct) John@105: print("I think I can trim to",trimPoint,ts) John@105: TrimLists(ts) John@105: else John@105: print("no bother trimming",trimPoint) John@103: end John@98: end John@98: John@98: function InitializeAdmin() John@98: if not event then John@98: _G.error("BSK: Improper order of initialization") John@98: end John@103: me = _G.UnitName("player") John@99: John@99: if admin then -- if at last login I was an admin ... John@99: John@99: -- note that we're not transmitting anything here. we'll do that once we John@99: -- know for certain we're an admin John@99: John@99: -- cache the onload status in case it changes in memory later John@99: onloadAdminStatus = {} John@99: tcopy(onloadAdminStatus,db.profile.adminStatus) John@99: John@99: -- update our own entry - safe because comms shouldn't have happened yet John@99: if not onloadAdminStatus then onloadAdminStatus = {} end John@99: if not onloadAdminStatus[me] then onloadAdminStatus[me] = {} end John@99: onloadAdminStatus[me].base = db.profile.time or 0 John@99: onloadAdminStatus[me].changes= {} John@99: for _,v in ipairs(db.profile.changes) do John@99: table.insert(onloadAdminStatus[me].changes,v.time) -- only timestamps John@99: end John@99: John@99: else -- otherwise store a blank slate John@99: onloadAdminStatus = {} John@99: db.profile.adminStatus = nil John@99: end John@99: John@98: event:RegisterEvent("GUILD_ROSTER_UPDATE",GuildRosterUpdate) John@105: event:RegisterEvent("ZONE_CHANGED_NEW_AREA",ZoneChanged) John@105: event:RegisterEvent("ZONE_CHANGED_INDOORS",ZoneChanged) John@105: event:RegisterEvent("ZONE_CHANGED",ZoneChanged) John@98: _G.GuildRoster() -- will eventually force the event to fire John@103: John@103: if me == "Breuemama" then -- debugging only John@103: GuildRosterUpdate() John@103: end John@98: end John@98: John@98: