Mercurial > wow > ouroloot
comparison core.lua @ 102:fe04f5c4114a
- expiring cache callback arg, handle new entries coming in during the
same loop at the previous ones ALL being removed
TODO: rework other "candidate" caches to use this instead
- raider snapshots use string tokens for 'online' field
- document callback args
- CheckBoxSmallLabel preemptively apply proposed fix for ace3 ticket 304
- now that option toggles are not wedged into tight space, revert to
using standard CheckBox widget instead of small-label variant
(go back if ticket 304 is not fixed for release)
| author | Farmbuyer of US-Kilrogg <farmbuyer@gmail.com> |
|---|---|
| date | Sat, 04 Aug 2012 22:03:05 +0000 |
| parents | f7162a1cadc7 |
| children | dc8a23a47b03 |
comparison
equal
deleted
inserted
replaced
| 101:f7162a1cadc7 | 102:fe04f5c4114a |
|---|---|
| 12 - subgroup 1-8 (NUM_RAID_GROUPS), NRG+1 if something's wrong | 12 - subgroup 1-8 (NUM_RAID_GROUPS), NRG+1 if something's wrong |
| 13 - race English codename ("BloodElf", etc) | 13 - race English codename ("BloodElf", etc) |
| 14 - sex 1 = unknown/error, 2 = male, 3 = female | 14 - sex 1 = unknown/error, 2 = male, 3 = female |
| 15 - level can be 0 if player was offline at the time | 15 - level can be 0 if player was offline at the time |
| 16 - guild guild name, or missing if unguilded | 16 - guild guild name, or missing if unguilded |
| 17 - online 1 = online, 2 = offline, 3 = no longer in raid | 17 - online 'online', 'offline', 'no_longer' [no longer in raid group] |
| 18 [both of these next two fields use time_t values:] | 18 [both of these next two fields use time_t values:] |
| 19 - join time player joined the raid (or first time we've seen them) | 19 - join time player joined the raid (or first time we've seen them) |
| 20 - leave time player left the raid (or time we've left the raid, if | 20 - leave time player left the raid (or time we've left the raid, if |
| 21 'online' is not 3) | 21 'online' is not 'no_longer') |
| 22 | 22 |
| 23 Common g_loot entry indices: | 23 Common g_loot entry indices: |
| 24 - kind time/boss/loot | 24 - kind time/boss/loot |
| 25 - hour 0-23, on the *physical instance server*, not the realm server | 25 - hour 0-23, on the *physical instance server*, not the realm server |
| 26 - minute 0-59, ditto | 26 - minute 0-59, ditto |
| 75 ------ Saved variables | 75 ------ Saved variables |
| 76 ------ Constants | 76 ------ Constants |
| 77 ------ Addon member data | 77 ------ Addon member data |
| 78 ------ Globals | 78 ------ Globals |
| 79 ------ Expiring caches | 79 ------ Expiring caches |
| 80 ------ Ace3 framework stuff | 80 ------ Ace3 framework stuff (callback 'events', search for LCALLBACK) |
| 81 ------ Event handlers | 81 ------ Event handlers |
| 82 ------ Slash command handler | 82 ------ Slash command handler |
| 83 ------ On/off | 83 ------ On/off |
| 84 ------ Behind the scenes routines | 84 ------ Behind the scenes routines |
| 85 ------ Saved texts | 85 ------ Saved texts |
| 99 | 99 |
| 100 ------ Saved variables | 100 ------ Saved variables |
| 101 OuroLootSV = nil -- possible copy of g_loot | 101 OuroLootSV = nil -- possible copy of g_loot |
| 102 OuroLootSV_saved = nil -- table of copies of saved texts, default nil; keys | 102 OuroLootSV_saved = nil -- table of copies of saved texts, default nil; keys |
| 103 -- are numeric indices of tables, subkeys of those | 103 -- are numeric indices of tables, subkeys of those |
| 104 -- are name/forum/attend/date | 104 -- are name/forum/attend/date |
| 105 OuroLootSV_hist = nil | 105 OuroLootSV_hist = nil |
| 106 OuroLootSV_log = {} | 106 OuroLootSV_log = {} |
| 107 | 107 |
| 108 | 108 |
| 109 ------ Constants | 109 ------ Constants |
| 627 cache:add(bar) | 627 cache:add(bar) |
| 628 ....10 seconds pass | 628 ....10 seconds pass |
| 629 cache:test(foo) -- returns false | 629 cache:test(foo) -- returns false |
| 630 cache:test(bar) -- returns true | 630 cache:test(bar) -- returns true |
| 631 ....5 seconds pass | 631 ....5 seconds pass |
| 632 ....bar also gone, cleanup() called | 632 ....bar also gone, cleanup() called: |
| 633 function cleanup (expired_entries) | |
| 634 for i = 1, #expired_entries do -- this table is in strict FIFO order | |
| 635 print(i, expired_entries[i]) | |
| 636 -- 1 foo | |
| 637 -- 2 bar | |
| 638 end | |
| 639 end | |
| 633 ]] | 640 ]] |
| 634 do | 641 do |
| 635 local caches = {} | 642 local caches = {} |
| 636 local cleanup_group = _G.AnimTimerFrame:CreateAnimationGroup() | 643 local cleanup_group = _G.AnimTimerFrame:CreateAnimationGroup() |
| 637 local time = _G.time | 644 local time, next = _G.time, _G.next |
| 645 local new, del = flib.new, flib.del | |
| 638 cleanup_group:SetLooping("REPEAT") | 646 cleanup_group:SetLooping("REPEAT") |
| 639 cleanup_group:SetScript("OnLoop", function(cg) | 647 cleanup_group:SetScript("OnLoop", function(cg) |
| 640 addon.dprint('cache',"OnLoop firing") | 648 addon.dprint('cache',"OnLoop firing") |
| 641 local now = time() | 649 local now = time() |
| 642 local alldone = true | 650 local actives = 0 |
| 651 local expired = new() | |
| 643 -- this is ass-ugly | 652 -- this is ass-ugly |
| 644 for name,c in pairs(caches) do | 653 for name,c in next, caches do |
| 645 local fifo = c.fifo | 654 local fifo = c.fifo |
| 646 local active = #fifo > 0 | 655 local active = #fifo > 0 |
| 656 actives = actives + (active and 1 or 0) | |
| 647 while (#fifo > 0) and (now > fifo[1].t) do | 657 while (#fifo > 0) and (now > fifo[1].t) do |
| 648 addon.dprint('cache', name, "cache removing", fifo[1].t, "<", fifo[1].m, ">") | 658 local datum = tremove(fifo,1) |
| 649 tremove(fifo,1) | 659 addon.dprint('cache', name, "cache removing", datum.t, "<", datum.m, ">") |
| 660 c.hash[datum.m] = nil | |
| 661 tinsert(expired,datum.m) | |
| 662 del(datum) | |
| 650 end | 663 end |
| 651 if active and #fifo == 0 and c.func then | 664 if active and #fifo == 0 and c.func then |
| 652 addon.dprint('cache', name, "empty, firing cleanup") | 665 addon.dprint('cache', name, "empty, firing cleanup") |
| 653 c:func() | 666 c.func(expired) |
| 654 end | 667 end |
| 655 alldone = alldone and (#fifo == 0) | 668 wipe(expired) |
| 656 end | 669 end |
| 657 if alldone then | 670 del(expired) |
| 671 if actives == 0 then | |
| 658 addon.dprint('cache',"OnLoop FINISHING animation group") | 672 addon.dprint('cache',"OnLoop FINISHING animation group") |
| 659 cleanup_group:Finish() | 673 cleanup_group:Finish() |
| 660 _G.collectgarbage() | |
| 661 else | 674 else |
| 662 addon.dprint('cache',"OnLoop done, not yet finished") | 675 addon.dprint('cache',"OnLoop done, not yet finished") |
| 663 end | 676 end |
| 664 end) | 677 end) |
| 665 | 678 |
| 666 local function _add (cache, x) | 679 local function _add (cache, x) |
| 667 local datum = { t=time()+cache.ttl, m=x } | 680 assert(type(x)~='number') |
| 681 local datum = new() | |
| 682 datum.m = x | |
| 683 datum.t = time() + cache.ttl | |
| 668 cache.hash[x] = datum | 684 cache.hash[x] = datum |
| 669 tinsert (cache.fifo, datum) | 685 tinsert (cache.fifo, datum) |
| 670 if not cleanup_group:IsPlaying() then | 686 if not cleanup_group:IsPlaying() then |
| 671 addon.dprint('cache', cache.name, "with entry", datum.t, "<", datum.m, "> STARTING animation group") | 687 addon.dprint('cache', cache.name, "with entry", datum.t, "<", datum.m, "> STARTING animation group") |
| 672 cache.cleanup:SetDuration(1) -- hmmm | |
| 673 cleanup_group:Play() | 688 cleanup_group:Play() |
| 674 end | 689 end |
| 675 end | 690 end |
| 676 local function _test (cache, x) | 691 local function _test (cache, x) |
| 677 -- FIXME This can return false positives, if called after the onloop | |
| 678 -- fifo has been removed but before the GC has removed the weak entry. | |
| 679 -- What to do, what to do... try forcing a GC during alldone. | |
| 680 return cache.hash[x] ~= nil | 692 return cache.hash[x] ~= nil |
| 681 end | 693 end |
| 682 | 694 |
| 683 function create_new_cache (name, ttl, on_alldone) | 695 function create_new_cache (name, ttl, on_alldone) |
| 684 -- setting OnFinished for cleanup fires at the end of each inner loop, | 696 -- setting OnFinished for cleanup fires at the end of each inner loop, |
| 685 -- with no 'requested' argument to distinguish cases. thus, on_alldone. | 697 -- with no 'requested' argument to distinguish cases. thus, on_alldone. |
| 686 -- FWIW, on_alldone is passed this table as its sole argument: | |
| 687 local c = { | 698 local c = { |
| 688 ttl = ttl, | 699 ttl = ttl, |
| 689 name = name, | 700 name = name, |
| 690 add = _add, | 701 add = _add, |
| 691 test = _test, | 702 test = _test, |
| 692 cleanup = cleanup_group:CreateAnimation("Animation"), | 703 cleanup = cleanup_group:CreateAnimation("Animation"), |
| 693 func = on_alldone, | 704 func = on_alldone, |
| 705 -- Testing merging these two (_add's 'x' must not be numeric) | |
| 694 fifo = {}, | 706 fifo = {}, |
| 695 hash = _G.setmetatable({}, {__mode='kv'}), | 707 --hash = {}, |
| 696 } | 708 } |
| 697 c.cleanup:SetOrder(1) | 709 c.hash = c.fifo |
| 710 c.cleanup:SetOrder(1) -- [1,100] range within parent animation | |
| 711 c.cleanup:SetDuration(0.8) -- hmmm | |
| 698 caches[name] = c | 712 caches[name] = c |
| 699 return c | 713 return c |
| 700 end | 714 end |
| 701 end | 715 end |
| 702 | 716 |
| 1050 end | 1064 end |
| 1051 return self:NewModule(modname) | 1065 return self:NewModule(modname) |
| 1052 end | 1066 end |
| 1053 end | 1067 end |
| 1054 | 1068 |
| 1055 -- We don't want to trigger plugins and another addons as soon as something | 1069 --[[ LCALLBACK |
| 1056 -- interesting happens, because a nontrivial amount of work happens "quickly" | 1070 Standard ace3-style callback registration and dispatching. All player names |
| 1057 -- after the interesting event: cleanups/fixups, improvs from network, etc. | 1071 are simple (uncolored) strings. The "uniqueID" always refers to the unique |
| 1058 -- So firing a callback is delayed ever so briefly by human standards. | 1072 tag string stored as 'unique' in loot entries and used as keys in history. |
| 1059 -- | 1073 Item IDs are always of numeric type. |
| 1060 -- Can't *quite* use the expiring caches for this, but that's okay. | 1074 |
| 1075 'Activate', enabled_p, rebroadcast_p, threshold | |
| 1076 The two boolean predicates are self-explanatory. The threshold is an | |
| 1077 ITEM_QUALITY_* constant integer. | |
| 1078 | |
| 1079 'Deactivate' | |
| 1080 After all system events have been unregistered. | |
| 1081 | |
| 1082 'Reset' | |
| 1083 Clicking "Clear Loot", after all data manipulation is finished. | |
| 1084 | |
| 1085 'NewBoss', boss | |
| 1086 Boss event triggered by a local bossmod (DBM, etc) or a remote OL tracker. | |
| 1087 Argument is a g_loot table entry of kind=='boss'. | |
| 1088 | |
| 1089 'NewBossEntry', boss | |
| 1090 New row in primary EOI table of kind=='boss'. Includes all 'NewBoss' | |
| 1091 occasions, plus manual boss additions, testing, etc. Arg same as NewBoss. | |
| 1092 | |
| 1093 'NewLootEntry', loot | |
| 1094 'DelLootEntry', loot | |
| 1095 New or removed row in primary EOI table of kind=='loot'. Argument is a | |
| 1096 g_loot table entry of kind=='loot'. | |
| 1097 | |
| 1098 'NewEOIEntry', entry | |
| 1099 'DelEOIEntry', entry | |
| 1100 New or removed row in primary EOI table, of any kind. Argument is the | |
| 1101 g_loot entry, already inserted into or removed from g_loot. | |
| 1102 | |
| 1103 'NewHistory', player_name, uniqueID | |
| 1104 'DelHistory', player_name, uniqueID | |
| 1105 New or removed entry in player history. Name argument self-explanatory. | |
| 1106 ID is the corresponding loot, already inserted into or removed from the | |
| 1107 history structures. | |
| 1108 | |
| 1109 'Reassign', uniqueID, itemID, loot, from_player_name, to_player_name | |
| 1110 Loot reassigned from one player to another. Loot represented by the | |
| 1111 unique & item IDs, and the g_loot entry of kind=='loot'. The player | |
| 1112 names are self-explanatory. | |
| 1113 | |
| 1114 'MarkAs', uniqueID, itemID, loot, old_disposition, new_disposition | |
| 1115 The "Mark as <x>" action (as if from the item right-click menu, possibly | |
| 1116 from a remote tracker) has finished. ID & loot arguments are as in | |
| 1117 'Reassign'. The old/new dispositions are those of the g_loot index | |
| 1118 "disposition" (described at the top of core.lua), with the added possible | |
| 1119 value of "normal" meaning exactly that. | |
| 1120 ]] | |
| 1061 do | 1121 do |
| 1062 local mtnewindex = function() error("This table is read-only", 3) end | 1122 -- We don't want to trigger plugins or other addons as soon as something |
| 1123 -- interesting happens, because a nontrivial amount of work happens "soon" | |
| 1124 -- after the interesting event: cleanups/fixups, improvs from network, | |
| 1125 -- etc. So firing a callback is delayed ever so briefly by human scales. | |
| 1126 -- | |
| 1127 -- For data safety, we replace any table arguments with read-only proxies | |
| 1128 -- before passing them to the callbacks. The goal is to prevent accidents, | |
| 1129 -- not fraud. | |
| 1130 local unpack, setmetatable = _G.unpack, _G.setmetatable | |
| 1131 local mtnewindex = function() --[[local]]error("This table is read-only", 3) end | |
| 1063 local function make_readonly (t) | 1132 local function make_readonly (t) |
| 1064 return _G.setmetatable({}, { | 1133 return setmetatable({}, { |
| 1065 __newindex = mtnewindex, | 1134 __newindex = mtnewindex, |
| 1066 __index = t, | 1135 __index = t, |
| 1067 __metatable = false, | 1136 __metatable = false, |
| 1137 __tostring = getmetatable(t) and getmetatable(t).__tostring, | |
| 1068 }) | 1138 }) |
| 1069 end | 1139 end |
| 1070 | 1140 |
| 1071 local unpack = _G.unpack | 1141 local queue = create_new_cache ('callbacks', 1.2, function (allcbs) |
| 1072 local function F (t) | 1142 for _,c in ipairs(allcbs) do |
| 1073 addon.callbacks:Fire (unpack(t)) | 1143 addon.callbacks:Fire (unpack(c)) |
| 1074 flib.del(t) | 1144 flib.del(c) |
| 1075 end | 1145 end |
| 1146 end) | |
| 1076 function addon:Fire (...) | 1147 function addon:Fire (...) |
| 1077 self.dprint('callback', ...) | 1148 self.dprint('callback', ...) |
| 1078 local capture = flib.new(...) | 1149 local capture = flib.new(...) |
| 1079 for k,v in ipairs(capture) do if type(v) == 'table' then | 1150 for k,v in ipairs(capture) do if type(v) == 'table' then |
| 1080 capture[k] = make_readonly(v) | 1151 capture[k] = make_readonly(v) |
| 1081 end end | 1152 end end |
| 1082 self:ScheduleTimer (F, 1.2, capture) | 1153 queue:add(capture) |
| 1083 end | 1154 end |
| 1084 end | 1155 end |
| 1085 | 1156 |
| 1086 | 1157 |
| 1087 ------ Event handlers | 1158 ------ Event handlers |
| 1137 local IsInInstance, UnitIsConnected, UnitClass, UnitRace, UnitSex, | 1208 local IsInInstance, UnitIsConnected, UnitClass, UnitRace, UnitSex, |
| 1138 UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo, GetRaidRosterInfo = | 1209 UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo, GetRaidRosterInfo = |
| 1139 IsInInstance, UnitIsConnected, UnitClass, UnitRace, UnitSex, | 1210 IsInInstance, UnitIsConnected, UnitClass, UnitRace, UnitSex, |
| 1140 UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo, GetRaidRosterInfo | 1211 UnitLevel, UnitInRaid, UnitIsVisible, GetGuildInfo, GetRaidRosterInfo |
| 1141 local time, difftime = time, difftime | 1212 local time, difftime = time, difftime |
| 1142 local R_ACTIVE, R_OFFLINE, R_LEFT = 1, 2, 3 | 1213 local R_ACTIVE, R_OFFLINE, R_LEFT = 'online', 'offline', 'no_longer' |
| 1143 | 1214 |
| 1144 local lastevent, now = 0, 0 | 1215 local lastevent, now = 0, 0 |
| 1145 local redo_count = 0 | 1216 local redo_count = 0 |
| 1146 local redo, timer_handle | 1217 local redo, timer_handle |
| 1147 | 1218 |
| 2138 addon:Print("Registered kill for '%s' in %s!", boss.bossname, boss.instance) | 2209 addon:Print("Registered kill for '%s' in %s!", boss.bossname, boss.instance) |
| 2139 end | 2210 end |
| 2140 end | 2211 end |
| 2141 wipe(candidates) | 2212 wipe(candidates) |
| 2142 end | 2213 end |
| 2214 -- Ten seconds is a long time, but occasionally DBM takes for-EVAH to | |
| 2215 -- decide that a fight is over. | |
| 2143 local recent_boss = create_new_cache ('boss', 10, fixup_durations) | 2216 local recent_boss = create_new_cache ('boss', 10, fixup_durations) |
| 2144 | 2217 |
| 2145 -- Similar to _do_loot, but duration+ parms only present when locally generated. | 2218 -- Similar to _do_loot, but duration+ parms only present when locally generated. |
| 2146 local function _do_boss (self, reason, bossname, intag, maxsize, duration) | 2219 local function _do_boss (self, reason, bossname, intag, maxsize, duration) |
| 2147 self.dprint('loot',">>_do_boss, R:", reason, "B:", bossname, | 2220 self.dprint('loot',">>_do_boss, R:", reason, "B:", bossname, |
