comparison core.lua @ 100:a57133ee3c9b

- Allow event callbacks using the standard CallbackHandler scheme. Add a debug.callback flag with usual semantics. - Fire an initial set of events. This will take experimentation. - If restoring g_loot, set metatables on previous entries also.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Mon, 30 Jul 2012 19:25:46 +0000
parents 966d06c8d9c9
children f7162a1cadc7
comparison
equal deleted inserted replaced
99:966d06c8d9c9 100:a57133ee3c9b
203 comm = false, 203 comm = false,
204 loot = false, 204 loot = false,
205 flow = false, 205 flow = false,
206 notraid = false, 206 notraid = false,
207 cache = false, 207 cache = false,
208 callback = false,
208 alsolog = false, 209 alsolog = false,
209 } 210 }
210 --@debug@ 211 --@debug@
211 DEBUG_PRINT = true 212 DEBUG_PRINT = true
212 debug.loot = true 213 debug.loot = true
213 debug.comm = true 214 debug.comm = true
215 is_guilded = _G.IsInGuild()
214 --@end-debug@ 216 --@end-debug@
215 217
216 -- This looks ugly, but it factors out the load-time decisions from 218 -- This looks ugly, but it factors out the load-time decisions from
217 -- the run-time ones. Args to [dp]print are concatenated with spaces. 219 -- the run-time ones. Args to [dp]print are concatenated with spaces.
218 if tekdebug then 220 if tekdebug then
386 local pprint, tabledump = addon.pprint, flib.tabledump 388 local pprint, tabledump = addon.pprint, flib.tabledump
387 local CopyTable = _G.CopyTable 389 local CopyTable = _G.CopyTable
388 local GetNumRaidMembers = _G.GetNumGroupMembers or _G.GetNumRaidMembers 390 local GetNumRaidMembers = _G.GetNumGroupMembers or _G.GetNumRaidMembers
389 local IsInRaid = _G.IsInRaid or (function() return GetNumRaidMembers() > 0 end) 391 local IsInRaid = _G.IsInRaid or (function() return GetNumRaidMembers() > 0 end)
390 -- En masse forward decls of symbols defined inside local blocks 392 -- En masse forward decls of symbols defined inside local blocks
391 local _register_bossmod, makedate, create_new_cache, _init, _log 393 local _register_bossmod, makedate, create_new_cache, _init, _log, _do_loot_metas
392 local _history_by_loot_id, _setup_unique_replace, _unavoidable_collision 394 local _history_by_loot_id, _setup_unique_replace, _unavoidable_collision
393 local _notify_about_change, _notify_about_remote 395 local _notify_about_change, _notify_about_remote
394 396
395 -- Try to extract numbers from the .toc "Version" and munge them into an 397 -- Try to extract numbers from the .toc "Version" and munge them into an
396 -- integral form for comparison. The result doesn't need to be meaningful as 398 -- integral form for comparison. The result doesn't need to be meaningful as
609 611
610 -- If unique keys ever change into objects instead of strings, change 612 -- If unique keys ever change into objects instead of strings, change
611 -- this into a weakly-keyed table. 613 -- this into a weakly-keyed table.
612 mt = { __metatable = 'Should be using setmode.' } 614 mt = { __metatable = 'Should be using setmode.' }
613 615
614 g_uniques = setmetatable (m_reset{}, mt) 616 g_uniques = _G.setmetatable (m_reset{}, mt)
615 end 617 end
616 618
617 619
618 ------ Expiring caches 620 ------ Expiring caches
619 --[[ 621 --[[
687 add = _add, 689 add = _add,
688 test = _test, 690 test = _test,
689 cleanup = cleanup_group:CreateAnimation("Animation"), 691 cleanup = cleanup_group:CreateAnimation("Animation"),
690 func = on_alldone, 692 func = on_alldone,
691 fifo = {}, 693 fifo = {},
692 hash = setmetatable({}, {__mode='kv'}), 694 hash = _G.setmetatable({}, {__mode='kv'}),
693 } 695 }
694 c.cleanup:SetOrder(1) 696 c.cleanup:SetOrder(1)
695 caches[name] = c 697 caches[name] = c
696 return c 698 return c
697 end 699 end
713 -- VARIABLES_LOADED has fired by this point; test if we're doing something like 715 -- VARIABLES_LOADED has fired by this point; test if we're doing something like
714 -- relogging during a raid and already have collected loot data 716 -- relogging during a raid and already have collected loot data
715 local OuroLootSV = _G.OuroLootSV 717 local OuroLootSV = _G.OuroLootSV
716 g_restore_p = OuroLootSV ~= nil 718 g_restore_p = OuroLootSV ~= nil
717 self.dprint('flow', "oninit sets restore as", g_restore_p) 719 self.dprint('flow', "oninit sets restore as", g_restore_p)
720
721 -- Primarily for plugins, but can be of use to me also...
722 self.callbacks = _G.LibStub("CallbackHandler-1.0"):New(self)
723 --function self.callbacks:OnUsed (target_aka_self, eventname) end
724 --function self.callbacks:OnUnused (target_aka_self, eventname) end
718 725
719 if _G.OuroLootOptsDB == nil then 726 if _G.OuroLootOptsDB == nil then
720 local vclick = self.format_hypertext ([[click here]], ITEM_QUALITY_UNCOMMON, 'help') 727 local vclick = self.format_hypertext ([[click here]], ITEM_QUALITY_UNCOMMON, 'help')
721 self:ScheduleTimer(function(s) 728 self:ScheduleTimer(function(s)
722 for id in pairs(self.default_itemfilter) do 729 for id in pairs(self.default_itemfilter) do
1042 end 1049 end
1043 return self:NewModule(modname) 1050 return self:NewModule(modname)
1044 end 1051 end
1045 end 1052 end
1046 1053
1054 -- We don't want to trigger plugins and another addons as soon as something
1055 -- interesting happens, because a nontrivial amount of work happens "quickly"
1056 -- after the interesting event: cleanups/fixups, improvs from network, etc.
1057 -- So firing a callback is delayed ever so briefly by human standards.
1058 --
1059 -- Can't *quite* use the expiring caches for this, but that's okay.
1060 do
1061 local unpack = _G.unpack
1062 local function F (t)
1063 addon.callbacks:Fire (unpack(t))
1064 flib.del(t)
1065 end
1066 function addon:Fire (...)
1067 self.dprint('callback', ...)
1068 local capture = flib.new(...)
1069 self:ScheduleTimer (F, 1.2, capture)
1070 end
1071 end
1072
1047 1073
1048 ------ Event handlers 1074 ------ Event handlers
1049 function addon:_clear_SVs() 1075 function addon:_clear_SVs()
1050 g_loot = {} -- not saved, just fooling PLAYER_LOGOUT tests 1076 g_loot = {} -- not saved, just fooling PLAYER_LOGOUT tests
1051 _G.OuroLootSV = nil 1077 _G.OuroLootSV = nil
1126 if r.online ~= R_LEFT and not UnitInRaid(name) then 1152 if r.online ~= R_LEFT and not UnitInRaid(name) then
1127 r.online = R_LEFT 1153 r.online = R_LEFT
1128 r.leave = now 1154 r.leave = now
1129 end 1155 end
1130 end 1156 end
1157
1158 -- XXX somewhere in here, we could fire a useful callback event
1131 1159
1132 if redo then 1160 if redo then
1133 redo_count = redo_count + 1 1161 redo_count = redo_count + 1
1134 end 1162 end
1135 redo = false 1163 redo = false
1605 end 1633 end
1606 self:Print "Baron Steamroller has been slain. Congratulations on your rug." 1634 self:Print "Baron Steamroller has been slain. Congratulations on your rug."
1607 1635
1608 elseif cmd == "debug" then 1636 elseif cmd == "debug" then
1609 if arg then 1637 if arg then
1638 self.is_guilded = _G.IsInGuild()
1610 self.debug[arg] = not self.debug[arg] 1639 self.debug[arg] = not self.debug[arg]
1611 _G.print(arg,self.debug[arg]) 1640 _G.print(arg,self.debug[arg])
1612 if self.debug[arg] then self.DEBUG_PRINT = true end 1641 if self.debug[arg] then self.DEBUG_PRINT = true end
1613 else 1642 else
1614 self.DEBUG_PRINT = not self.DEBUG_PRINT 1643 self.DEBUG_PRINT = not self.DEBUG_PRINT
1703 self.enabled = not opt_bcast_only 1732 self.enabled = not opt_bcast_only
1704 g_seeing_oldsigs = nil 1733 g_seeing_oldsigs = nil
1705 if opt_threshold then 1734 if opt_threshold then
1706 self:SetThreshold (opt_threshold, --[[quiet_p=]]true) 1735 self:SetThreshold (opt_threshold, --[[quiet_p=]]true)
1707 end 1736 end
1737 self:Fire ('Activate', self.enabled, self.rebroadcast, self.threshold)
1708 self:Print("Now %s; threshold currently %s.", 1738 self:Print("Now %s; threshold currently %s.",
1709 self.enabled and "tracking" or "only broadcasting", 1739 self.enabled and "tracking" or "only broadcasting",
1710 self.thresholds[self.threshold]) 1740 self.thresholds[self.threshold])
1711 self:broadcast('revcheck',version_large) 1741 self:broadcast('revcheck',version_large)
1712 end 1742 end
1717 self.enabled = false 1747 self.enabled = false
1718 self.rebroadcast = false 1748 self.rebroadcast = false
1719 self:UnregisterEvent(RAID_ROSTER_UPDATE_EVENT) 1749 self:UnregisterEvent(RAID_ROSTER_UPDATE_EVENT)
1720 self:UnregisterEvent("PLAYER_ENTERING_WORLD") 1750 self:UnregisterEvent("PLAYER_ENTERING_WORLD")
1721 self:UnregisterEvent("CHAT_MSG_LOOT") 1751 self:UnregisterEvent("CHAT_MSG_LOOT")
1752 self:Fire ('Deactivate')
1722 self:Print("Deactivated.") 1753 self:Print("Deactivated.")
1723 end 1754 end
1724 1755
1725 function addon:Clear(verbose_p) 1756 function addon:Clear(verbose_p)
1726 local repopup, st 1757 local repopup, st
1742 else 1773 else
1743 self:Print("Current loot data cleared.") 1774 self:Print("Current loot data cleared.")
1744 end 1775 end
1745 end 1776 end
1746 _init(self,st) 1777 _init(self,st)
1778 self:Fire ('Reset')
1747 if repopup then 1779 if repopup then
1748 addon:BuildMainDisplay() 1780 addon:BuildMainDisplay()
1749 end 1781 end
1750 end 1782 end
1751 1783
1994 self.hist_clean = nil 2026 self.hist_clean = nil
1995 if g_restore_p then 2027 if g_restore_p then
1996 g_loot = _G.OuroLootSV 2028 g_loot = _G.OuroLootSV
1997 self.popped = #g_loot > 0 2029 self.popped = #g_loot > 0
1998 self.dprint('flow', "restoring", #g_loot, "entries") 2030 self.dprint('flow', "restoring", #g_loot, "entries")
2031 _do_loot_metas()
1999 self:ScheduleTimer("Activate", 12, opts.threshold) 2032 self:ScheduleTimer("Activate", 12, opts.threshold)
2000 -- FIXME printed could be too large if entries were deleted, how much do we care? 2033 -- FIXME printed could be too large if entries were deleted, how much do we care?
2001 self.sharder = opts.autoshard 2034 self.sharder = opts.autoshard
2002 else 2035 else
2003 g_loot = {} 2036 g_loot = {}
2078 break 2111 break
2079 end 2112 end
2080 end 2113 end
2081 end 2114 end
2082 bossi = addon._addBossEntry(boss) 2115 bossi = addon._addBossEntry(boss)
2083 -- addon. 2116 addon:Fire ('NewBoss', boss)
2084 bossi = addon._adjustBossOrder (bossi, g_boss_signpost) or bossi 2117 bossi = addon._adjustBossOrder (bossi, g_boss_signpost) or bossi
2085 g_boss_signpost = nil 2118 g_boss_signpost = nil
2086 addon.latest_instance = boss.instance 2119 addon.latest_instance = boss.instance
2087 addon.dprint('loot', "added boss entry", bossi) 2120 addon.dprint('loot', "added boss entry", bossi)
2088 if boss.reason == 'kill' then 2121 if boss.reason == 'kill' then
2228 2261
2229 -- Adding entries to the loot record, and tracking the corresponding timestamp. 2262 -- Adding entries to the loot record, and tracking the corresponding timestamp.
2230 do 2263 do
2231 local rawget, setmetatable = _G.rawget, _G.setmetatable 2264 local rawget, setmetatable = _G.rawget, _G.setmetatable
2232 2265
2233 -- This shouldn't be required. /sadface 2266 --@debug@
2267 local tos = {}
2268 tos.time = function (e)
2269 return e.startday.text
2270 end
2271 tos.boss = function (e)
2272 return e.bossname .. '/' .. e.reason
2273 end
2274 tos.loot = function (e)
2275 return e.itemname .. '/' .. e.person .. '/' .. e.unique .. '/'
2276 .. tostring(e.disposition) .. (e.extratext and ('/'..e.extratext) or '')
2277 end
2278 --@end-debug@
2234 local loot_entry_mt = { 2279 local loot_entry_mt = {
2235 __index = function (e,key) 2280 __index = function (e,key)
2281 -- This shouldn't be required, as the refresh should be picking
2282 -- it up already. Sigh.
2236 if key == 'cols' then 2283 if key == 'cols' then
2237 pprint('mt', e.kind, "key is", key) 2284 pprint('mt', e.kind, "key is", key)
2238 --tabledump(e) -- not actually that useful
2239 addon:_fill_out_eoi_data(1) 2285 addon:_fill_out_eoi_data(1)
2240 end 2286 end
2241 return rawget(e,key) 2287 return rawget(e,key)
2242 end 2288 end,
2289 --@debug@
2290 __tostring = function (e)
2291 local k = e.kind
2292 if k then
2293 return ("<%s/%s>"):format(k, tos[k] and tos[k](e) or "?")
2294 end
2295 return "<unknown loot entry type>"
2296 end,
2297 --@end-debug@
2243 } 2298 }
2299 function _do_loot_metas()
2300 for i,e in ipairs(g_loot) do
2301 setmetatable(e,loot_entry_mt)
2302 end
2303 _do_loot_metas = nil
2304 end
2244 2305
2245 -- Given a loot index, searches backwards for a timestamp. Returns that 2306 -- Given a loot index, searches backwards for a timestamp. Returns that
2246 -- index and the time entry, or nil if it falls off the beginning. Pass an 2307 -- index and the time entry, or nil if it falls off the beginning. Pass an
2247 -- optional second index to search no earlier than that. 2308 -- optional second index to search no earlier than that.
2248 -- May also be able to make good use of this in forum-generation routine. 2309 -- May also be able to make good use of this in forum-generation routine.
2324 e.stamp = time_t --localuptime 2385 e.stamp = time_t --localuptime
2325 if e.kind == 'loot' then 2386 if e.kind == 'loot' then
2326 if (not e.unique) or (#e.unique==0) then 2387 if (not e.unique) or (#e.unique==0) then
2327 e.unique = e.id .. (e.disposition or e.person) .. _G.date("%Y/%m/%d %H:%M",e.stamp) 2388 e.unique = e.id .. (e.disposition or e.person) .. _G.date("%Y/%m/%d %H:%M",e.stamp)
2328 end 2389 end
2390 addon:Fire ('NewLootEntry', e)
2329 end 2391 end
2330 local index = #g_loot + 1 2392 local index = #g_loot + 1
2331 g_loot[index] = e 2393 g_loot[index] = e
2394 addon:Fire ('NewEOIEntry', e)
2332 return index 2395 return index
2333 end 2396 end
2334 2397
2335 -- Safety wrapper only. 2398 -- Safety/convenience wrapper only.
2336 -- XXX Maybe pprint something here.
2337 function addon._addBossEntry (e) 2399 function addon._addBossEntry (e)
2338 local ret = addon._addLootEntry(e) 2400 local ret = addon._addLootEntry(e)
2339 assert(e.kind=='boss') 2401 assert(e.kind=='boss')
2340 local needSize = e.maxsize == nil 2402 local needSize = e.maxsize == nil
2341 local needSnap = e.raidersnap == nil 2403 local needSnap = e.raidersnap == nil
2344 local ss, max, inst = addon:snapshot_raid() 2406 local ss, max, inst = addon:snapshot_raid()
2345 if needSize then e.maxsize = max end 2407 if needSize then e.maxsize = max end
2346 if needSnap then e.raidersnap = ss end 2408 if needSnap then e.raidersnap = ss end
2347 if needInst then e.instance = inst end 2409 if needInst then e.instance = inst end
2348 end 2410 end
2411 addon:Fire ('NewBossEntry', e)
2349 return ret 2412 return ret
2350 end 2413 end
2351 2414
2352 -- Problem: (1) boss kill happens, (2) fast looting happens, (3) boss 2415 -- Problem: (1) boss kill happens, (2) fast looting happens, (3) boss
2353 -- cache cleanup fires. Result: loot shows up before boss kill entry. 2416 -- cache cleanup fires. Result: loot shows up before boss kill entry.
2550 local clicky 2613 local clicky
2551 function addon:horrible_horrible_error (err_msg) 2614 function addon:horrible_horrible_error (err_msg)
2552 if self.display then 2615 if self.display then
2553 local d = self.display 2616 local d = self.display
2554 if d then 2617 if d then
2618 -- Take this down a piece at a time, on the assumption that
2619 -- the main window won't be able to do so.
2555 local gui = d:GetUserData("GUI state") 2620 local gui = d:GetUserData("GUI state")
2556 local eoist = gui.eoiST 2621 local eoist = gui.eoiST
2557 if eoist then eoist:Hide() end 2622 if eoist then eoist:Hide() end
2558 local histst = gui.histST 2623 local histst = gui.histST
2559 if histst then histst:Hide() end 2624 if histst then histst:Hide() end
2885 h.when[U] = when 2950 h.when[U] = when
2886 h.id[U] = e.id 2951 h.id[U] = e.id
2887 h.count[U] = e.count 2952 h.count[U] = e.count
2888 2953
2889 g_uniques[U] = { loot = lootindex, history = e.person } 2954 g_uniques[U] = { loot = lootindex, history = e.person }
2955 self:Fire ('NewHistory', e.person, U)
2890 end 2956 end
2891 2957
2892 -- Create new history table based on current loot. 2958 -- Create new history table based on current loot.
2893 function addon:rewrite_history (realmname) 2959 function addon:rewrite_history (realmname)
2894 local r = assert(realmname) 2960 local r = assert(realmname)
3102 end 3168 end
3103 if self.display then 3169 if self.display then
3104 self.display:GetUserData("GUI state").eoiST:OuroLoot_Refresh(index) 3170 self.display:GetUserData("GUI state").eoiST:OuroLoot_Refresh(index)
3105 self:redisplay() 3171 self:redisplay()
3106 end 3172 end
3173 self:Fire ('Reassign', unique, id, e, from_name, to_name)
3107 return index 3174 return index
3108 end 3175 end
3109 3176
3110 local function expunge (player, index_or_unique) 3177 local function expunge (player, index_or_unique)
3111 local i,u 3178 local i,u
3126 assert(#u>0) 3193 assert(#u>0)
3127 tremove (player.unique, i) 3194 tremove (player.unique, i)
3128 player.when[u], player.id[u], player.count[u] = nil, nil, nil 3195 player.when[u], player.id[u], player.count[u] = nil, nil, nil
3129 g_uniques[u] = nil 3196 g_uniques[u] = nil
3130 addon.hist_clean = nil 3197 addon.hist_clean = nil
3198 addon:Fire ('DelHistory', player.name, u)
3131 return #player.unique 3199 return #player.unique
3132 end 3200 end
3133 3201
3134 -- Mirror of _addHistoryEntry. Arguments are either: 3202 -- Mirror of _addHistoryEntry. Arguments are either:
3135 -- E - loot entry 3203 -- E - loot entry
3305 -- A unique tag has been set by this point. 3373 -- A unique tag has been set by this point.
3306 if how == "local" then 3374 if how == "local" then
3307 unique = assert(e.unique) 3375 unique = assert(e.unique)
3308 self:vbroadcast('mark', unique, id, olddisp, newdisp) 3376 self:vbroadcast('mark', unique, id, olddisp, newdisp)
3309 end 3377 end
3378 self:Fire ('MarkAs', unique, id, e, olddisp or 'normal', newdisp or 'normal')
3310 return index 3379 return index
3311 end 3380 end
3312 end 3381 end
3313 3382
3314 3383
3345 function addon:broadcast(tag,...) 3414 function addon:broadcast(tag,...)
3346 local msg = assemble(tag,...) 3415 local msg = assemble(tag,...)
3347 self.dprint('comm', "<broadcast>:", msg) 3416 self.dprint('comm', "<broadcast>:", msg)
3348 self:SendCommMessage(self.ident, msg, "RAID") 3417 self:SendCommMessage(self.ident, msg, "RAID")
3349 -- this is what lets us debug our own message traffic: 3418 -- this is what lets us debug our own message traffic:
3350 if self.debug.comm then 3419 if self.debug.comm and self.is_guilded then
3351 self:SendCommMessage(self.ident, msg, "GUILD") 3420 self:SendCommMessage(self.ident, msg, "GUILD")
3352 end 3421 end
3353 end 3422 end
3354 -- whispercast(<to>, 'tag', <stuff>) 3423 -- whispercast(<to>, 'tag', <stuff>)
3355 function addon:whispercast(to,...) 3424 function addon:whispercast(to,...)