Mercurial > wow > ouroloot
comparison core.lua @ 71:fb330a1fb6e9
Add a unique field to loot (extracted from uniqueID field when possible, randomly generated when not) and include it in broadcasts. Use this as a history identifier for future loot. Will need to tweak using this in signatures (and finally avoid problems looting multiples of an item to a single person).
| author | Farmbuyer of US-Kilrogg <farmbuyer@gmail.com> |
|---|---|
| date | Sat, 12 May 2012 07:17:55 +0000 |
| parents | cdee65c1bd8c |
| children | 32eb24fb2ebf |
comparison
equal
deleted
inserted
replaced
| 70:cdee65c1bd8c | 71:fb330a1fb6e9 |
|---|---|
| 51 - itemname not including square brackets | 51 - itemname not including square brackets |
| 52 - id itemID as number | 52 - id itemID as number |
| 53 - itemlink full clickable link | 53 - itemlink full clickable link |
| 54 - itexture icon path (e.g., Interface\Icons\INV_Misc_Rune_01) | 54 - itexture icon path (e.g., Interface\Icons\INV_Misc_Rune_01) |
| 55 - quality ITEM_QUALITY_* number | 55 - quality ITEM_QUALITY_* number |
| 56 - unique an almost-certainly-unique string, content meaningless | |
| 56 - disposition offspec/gvault/shard; missing otherwise; can be set from | 57 - disposition offspec/gvault/shard; missing otherwise; can be set from |
| 57 the extratext field | 58 the extratext field |
| 58 - count e.g., "x3"; missing otherwise; can be set/removed from | 59 - count e.g., "x3"; missing otherwise; can be set/removed from |
| 59 extratext; triggers only for a stack of items, not "the boss | 60 extratext; triggers only for a stack of items, not "the boss |
| 60 dropped double axes today" | 61 dropped double axes today" |
| 107 OuroLootSV_log = {} | 108 OuroLootSV_log = {} |
| 108 | 109 |
| 109 | 110 |
| 110 ------ Constants | 111 ------ Constants |
| 111 local option_defaults = { | 112 local option_defaults = { |
| 112 ['datarev'] = 19, -- cheating, this isn't actually an option | 113 ['datarev'] = 20, -- cheating, this isn't actually an option |
| 113 ['popup_on_join'] = true, | 114 ['popup_on_join'] = true, |
| 114 ['register_slashloot'] = true, | 115 ['register_slashloot'] = true, |
| 115 ['scroll_to_bottom'] = true, | 116 ['scroll_to_bottom'] = true, |
| 116 ['chatty_on_kill'] = false, | 117 ['chatty_on_kill'] = false, |
| 117 ['no_tracking_wipes'] = false, | 118 ['no_tracking_wipes'] = false, |
| 159 addon.author_debug = flib.author_debug | 160 addon.author_debug = flib.author_debug |
| 160 | 161 |
| 161 -- Play cute games with namespaces here just to save typing. WTB Lua 5.2 PST. | 162 -- Play cute games with namespaces here just to save typing. WTB Lua 5.2 PST. |
| 162 do local _G = _G setfenv (1, addon) | 163 do local _G = _G setfenv (1, addon) |
| 163 | 164 |
| 164 commrev = '16' | 165 commrev = '17' |
| 165 revision = _G.GetAddOnMetadata(nametag,"Version") or "?" -- "x.yy.z", etc | 166 revision = _G.GetAddOnMetadata(nametag,"Version") or "?" -- "x.yy.z", etc |
| 166 ident = "OuroLoot2" | 167 ident = "OuroLoot2" |
| 167 identTg = "OuroLoot2Tg" | 168 identTg = "OuroLoot2Tg" |
| 168 status_text = nil | 169 status_text = nil |
| 169 | 170 |
| 561 | 562 |
| 562 self.history_all = self.history_all or OuroLootSV_hist or {} | 563 self.history_all = self.history_all or OuroLootSV_hist or {} |
| 563 local r = self:load_assert (GetRealmName(), "how the freak does GetRealmName() fail?") | 564 local r = self:load_assert (GetRealmName(), "how the freak does GetRealmName() fail?") |
| 564 self.history_all[r] = self:_prep_new_history_category (self.history_all[r], r) | 565 self.history_all[r] = self:_prep_new_history_category (self.history_all[r], r) |
| 565 self.history = self.history_all[r] | 566 self.history = self.history_all[r] |
| 567 | |
| 568 local histformat = self.history_all.HISTFORMAT | |
| 569 self.history_all.HISTFORMAT = nil -- don't keep this in live data | |
| 566 if (not InCombatLockdown()) and OuroLootSV_hist and | 570 if (not InCombatLockdown()) and OuroLootSV_hist and |
| 567 (OuroLootSV_hist.HISTFORMAT == nil) -- restored data but it's older | 571 (histformat == nil or histformat < 3) -- restored data but it's older |
| 568 then | 572 then |
| 569 -- Big honkin' loop | 573 -- Big honkin' loop |
| 570 for rname,realm in pairs(self.history_all) do | 574 for rname,realm in pairs(self.history_all) do |
| 571 for pk,player in ipairs(realm) do | 575 for pk,player in ipairs(realm) do |
| 572 for lk,loot in ipairs(player) do | 576 for lk,loot in ipairs(player) do |
| 573 if loot.count == "" then | 577 if loot.count == "" then |
| 574 loot.count = nil | 578 loot.count = nil |
| 575 end | 579 end |
| 580 if not loot.unique then | |
| 581 loot.unique = loot.id .. ' ' .. loot.when | |
| 582 end | |
| 576 end | 583 end |
| 577 end | 584 end |
| 578 end | 585 end |
| 579 end | 586 end |
| 580 self.history_all.HISTFORMAT = nil -- don't keep this in live data | |
| 581 --OuroLootSV_hist = nil | 587 --OuroLootSV_hist = nil |
| 582 | 588 |
| 583 -- Handle changes to the stored data format in stages from oldest to newest. | 589 -- Handle changes to the stored data format in stages from oldest to newest. |
| 584 if OuroLootSV then | 590 if OuroLootSV then |
| 585 local dirty = false | 591 local dirty = false |
| 624 | 630 |
| 625 bumpers[18] = bumpers[16] | 631 bumpers[18] = bumpers[16] |
| 626 -- In the not-very-many days between 16 and 19, I managed to break | 632 -- In the not-very-many days between 16 and 19, I managed to break |
| 627 -- the exact same data in the exact same way. At least they're | 633 -- the exact same data in the exact same way. At least they're |
| 628 -- not actually running the same loop twice... probably... sigh. | 634 -- not actually running the same loop twice... probably... sigh. |
| 635 | |
| 636 bumpers[19] = function() | |
| 637 for i,e in ipairs(OuroLootSV) do | |
| 638 if e.kind == 'loot' and e.history_unique then | |
| 639 e.unique, e.history_unique = e.history_unique, nil | |
| 640 end | |
| 641 end | |
| 642 end | |
| 629 | 643 |
| 630 --[===[ | 644 --[===[ |
| 631 local real = bumpers | 645 local real = bumpers |
| 632 bumpers = newproxy(true) | 646 bumpers = newproxy(true) |
| 633 local mt = getmetatable(bumpers) | 647 local mt = getmetatable(bumpers) |
| 860 t.byname = nil | 874 t.byname = nil |
| 861 end | 875 end |
| 862 end end | 876 end end |
| 863 if worth_saving then | 877 if worth_saving then |
| 864 OuroLootSV_hist = self.history_all | 878 OuroLootSV_hist = self.history_all |
| 865 OuroLootSV_hist.HISTFORMAT = 2 | 879 OuroLootSV_hist.HISTFORMAT = 3 |
| 866 else | 880 else |
| 867 OuroLootSV_hist = nil | 881 OuroLootSV_hist = nil |
| 868 end | 882 end |
| 869 OuroLootSV_log = #OuroLootSV_log > 0 and OuroLootSV_log or nil | 883 OuroLootSV_log = #OuroLootSV_log > 0 and OuroLootSV_log or nil |
| 870 end | 884 end |
| 1048 end | 1062 end |
| 1049 wipe(candidates) | 1063 wipe(candidates) |
| 1050 end | 1064 end |
| 1051 addon.recent_loot = create_new_cache ('loot', comm_cleanup_ttl+3, prefer_local_loots) | 1065 addon.recent_loot = create_new_cache ('loot', comm_cleanup_ttl+3, prefer_local_loots) |
| 1052 | 1066 |
| 1053 local GetItemInfo, GetItemIcon = GetItemInfo, GetItemIcon | 1067 local GetItemInfo, GetItemIcon, random = GetItemInfo, GetItemIcon, math.random |
| 1054 | 1068 |
| 1055 -- 'from' and onwards only present if this is triggered by a broadcast | 1069 -- 'from' only present if this is triggered by a broadcast |
| 1056 function addon:_do_loot (local_override, recipient, itemid, count, from, extratext) | 1070 function addon:_do_loot (local_override, recipient, unique, itemid, count, from, extratext) |
| 1057 local itexture = GetItemIcon(itemid) | 1071 local itexture = GetItemIcon(itemid) |
| 1058 local iname, ilink, iquality = GetItemInfo(itemid) | 1072 local iname, ilink, iquality = GetItemInfo(itemid) |
| 1059 local i | 1073 local i |
| 1060 if (not iname) or (not itexture) then | 1074 if (not iname) or (not itexture) then |
| 1061 i = true | 1075 i = true |
| 1062 iname, ilink, iquality, itexture = | 1076 iname, ilink, iquality, itexture = |
| 1063 UNKNOWN..': '..itemid, 'item:6948', ITEM_QUALITY_COMMON, [[ICONS\INV_Misc_QuestionMark]] | 1077 UNKNOWN..': '..itemid, 'item:6948', ITEM_QUALITY_COMMON, [[ICONS\INV_Misc_QuestionMark]] |
| 1064 end | 1078 end |
| 1065 self.dprint('loot',">>_do_loot, R:", recipient, "I:", itemid, "C:", count, "frm:", from, "ex:", extratext, "q:", iquality) | 1079 self.dprint('loot',">>_do_loot, R:", recipient, "U:", unique, "I:", |
| 1080 itemid, "C:", count, "frm:", from, "ex:", extratext, "q:", iquality) | |
| 1066 | 1081 |
| 1067 itemid = tonumber(ilink:match("item:(%d+)") or 0) | 1082 itemid = tonumber(ilink:match("item:(%d+)") or 0) |
| 1083 unique = tostring(unique or random(8675309)) -- also, xkcd.com/1047 | |
| 1068 -- This is only a 'while' to make jumping out of it easy and still do cleanup below. | 1084 -- This is only a 'while' to make jumping out of it easy and still do cleanup below. |
| 1069 while local_override or ((iquality >= self.threshold) and not opts.itemfilter[itemid]) do | 1085 while local_override or ((iquality >= self.threshold) and not opts.itemfilter[itemid]) do |
| 1070 if (self.rebroadcast and (not from)) and not local_override then | 1086 if (self.rebroadcast and (not from)) and not local_override then |
| 1071 self:vbroadcast('loot', recipient, itemid, count) | 1087 self:vbroadcast('loot', recipient, unique, itemid, count) |
| 1072 end | 1088 end |
| 1073 if (not self.enabled) and (not local_override) then break end | 1089 if (not self.enabled) and (not local_override) then break end |
| 1074 local signature = recipient .. iname .. (count or "") | 1090 local signature = unique .. recipient .. iname .. (count or "") |
| 1075 if from and self.recent_loot:test(signature) then | 1091 if from and self.recent_loot:test(signature) then |
| 1076 self.dprint('cache', "remote loot <",signature,"> already in cache, skipping") | 1092 self.dprint('cache', "remote loot <",signature,"> already in cache, skipping") |
| 1077 else | 1093 else |
| 1078 -- There is some redundancy in all this, in the interests of ease-of-coding | 1094 -- There is some redundancy in all this, in the interests of ease-of-coding |
| 1079 i = { | 1095 i = { |
| 1084 quality = iquality, | 1100 quality = iquality, |
| 1085 itemname = iname, | 1101 itemname = iname, |
| 1086 id = itemid, | 1102 id = itemid, |
| 1087 itemlink = ilink, | 1103 itemlink = ilink, |
| 1088 itexture = itexture, | 1104 itexture = itexture, |
| 1105 unique = unique, | |
| 1089 count = (count and count ~= "") and count or nil, | 1106 count = (count and count ~= "") and count or nil, |
| 1090 bcast_from = from, | 1107 bcast_from = from, |
| 1091 extratext = extratext, | 1108 extratext = extratext, |
| 1092 variant = self:is_variant_item(ilink), | 1109 variant = self:is_variant_item(ilink), |
| 1093 } | 1110 } |
| 1163 person = person:match("|c%x%x%x%x%x%x%x%x(%S+)") or person | 1180 person = person:match("|c%x%x%x%x%x%x%x%x(%S+)") or person |
| 1164 else | 1181 else |
| 1165 person = my_name -- UNIT_YOU / You | 1182 person = my_name -- UNIT_YOU / You |
| 1166 end | 1183 end |
| 1167 | 1184 |
| 1168 --local id = tonumber((select(2, strsplit(":", itemstring)))) | 1185 --local id = tonumber(itemstring:match('|Hitem:(%d+):')) |
| 1169 local id = tonumber(itemstring:match('|Hitem:(%d+):')) | 1186 local id,unique,_ |
| 1170 | 1187 _,id,_,_,_,_,_,_,unique = strsplit (":", itemstring) |
| 1171 return self:_do_loot (false, person, id, count) | 1188 if unique == 0 then unique = nil end |
| 1189 | |
| 1190 return self:_do_loot (false, person, unique, id, count) | |
| 1172 | 1191 |
| 1173 elseif event == "broadcast" then | 1192 elseif event == "broadcast" then |
| 1174 return self:_do_loot(false, ...) | 1193 return self:_do_loot(false, ...) |
| 1175 | 1194 |
| 1176 elseif event == "manual" then | 1195 elseif event == "manual" then |
| 1177 local r,i,n = ... | 1196 local r,i,n = ... |
| 1178 return self:_do_loot(true, r,i,nil,nil,n) | 1197 return self:_do_loot(true, r, --[[unique=]]nil, i, |
| 1198 --[[count=]]nil, --[[from=]]nil, n) | |
| 1179 end | 1199 end |
| 1180 end | 1200 end |
| 1181 end | 1201 end |
| 1182 | 1202 |
| 1183 | 1203 |
| 2055 id = e.id, | 2075 id = e.id, |
| 2056 when = self:format_timestamp (g_today, e), | 2076 when = self:format_timestamp (g_today, e), |
| 2057 count = e.count, | 2077 count = e.count, |
| 2058 } | 2078 } |
| 2059 tinsert (h, 1, n) | 2079 tinsert (h, 1, n) |
| 2060 e.history_unique = n.id .. ' ' .. n.when | 2080 if (not e.unique) or (#e.unique==0) then |
| 2081 e.unique = n.id .. ' ' .. n.when | |
| 2082 end | |
| 2083 n.unique = e.unique | |
| 2061 end | 2084 end |
| 2062 | 2085 |
| 2063 -- Create new history table based on current loot. | 2086 -- Create new history table based on current loot. |
| 2064 function addon:rewrite_history (realmname) | 2087 function addon:rewrite_history (realmname) |
| 2065 local r = assert(realmname) | 2088 local r = assert(realmname) |
| 2107 if loot.kind ~= 'loot' then | 2130 if loot.kind ~= 'loot' then |
| 2108 error("trying to "..operation_text.." something that isn't loot") | 2131 error("trying to "..operation_text.." something that isn't loot") |
| 2109 end | 2132 end |
| 2110 | 2133 |
| 2111 local player = loot.person | 2134 local player = loot.person |
| 2112 local tag = loot.history_unique | 2135 local tag = loot.unique |
| 2113 local errtxt | 2136 local errtxt |
| 2114 local player_i, player_h, hist_i | 2137 local player_i, player_h, hist_i |
| 2115 | 2138 |
| 2116 if not tag then | 2139 if not tag then |
| 2117 errtxt = "Entry for %s is missing a history tag!" | 2140 errtxt = "Entry for %s is missing a history tag!" |
| 2118 else | 2141 else |
| 2119 player_i,player_h = self:get_loot_history(player) | 2142 player_i,player_h = self:get_loot_history(player) |
| 2120 for i,h in ipairs(player_h) do | 2143 for i,h in ipairs(player_h) do |
| 2121 local unique = h.id .. ' ' .. h.when | 2144 if h.unique == tag then |
| 2122 if unique == tag then | |
| 2123 hist_i = i | 2145 hist_i = i |
| 2124 break | 2146 break |
| 2125 end | 2147 end |
| 2126 end | 2148 end |
| 2127 if not hist_i then | 2149 if not hist_i then |
| 2198 if (newdisp == 'shard' or newdisp == 'gvault') then | 2220 if (newdisp == 'shard' or newdisp == 'gvault') then |
| 2199 local name_i, name_h, hist_i = self:_history_by_loot_id (e, "mark") | 2221 local name_i, name_h, hist_i = self:_history_by_loot_id (e, "mark") |
| 2200 -- remove history entry | 2222 -- remove history entry |
| 2201 if hist_i then | 2223 if hist_i then |
| 2202 local hist_h = tremove (name_h, hist_i) | 2224 local hist_h = tremove (name_h, hist_i) |
| 2203 deleted_cache[e.history_unique] = hist_h | 2225 deleted_cache[e.unique] = hist_h |
| 2204 self.hist_clean = nil | 2226 self.hist_clean = nil |
| 2205 elseif (olddisp == 'shard' or olddisp == 'gvault') then | 2227 elseif (olddisp == 'shard' or olddisp == 'gvault') then |
| 2206 -- Sharding a vault item, or giving the auto-sharder something to bank, | 2228 -- Sharding a vault item, or giving the auto-sharder something to bank, |
| 2207 -- etc, wouldn't necessarily have had a history entry to begin with. | 2229 -- etc, wouldn't necessarily have had a history entry to begin with. |
| 2208 else | 2230 else |
| 2219 -- Must create a new history entry. Could call '_addHistoryEntry(index)' | 2241 -- Must create a new history entry. Could call '_addHistoryEntry(index)' |
| 2220 -- but that would duplicate a lot of effort. To start with, check the | 2242 -- but that would duplicate a lot of effort. To start with, check the |
| 2221 -- cache of stuff we've already deleted; if it's not there then just do | 2243 -- cache of stuff we've already deleted; if it's not there then just do |
| 2222 -- the same steps as _addHistoryEntry. | 2244 -- the same steps as _addHistoryEntry. |
| 2223 local entry | 2245 local entry |
| 2224 if e.history_unique and deleted_cache[e.history_unique] then | 2246 if e.unique and deleted_cache[e.unique] then |
| 2225 entry = deleted_cache[e.history_unique] | 2247 entry = deleted_cache[e.unique] |
| 2226 deleted_cache[e.history_unique] = nil | 2248 deleted_cache[e.unique] = nil |
| 2227 end | 2249 end |
| 2228 local when = g_today and self:format_timestamp (g_today, e) or tostring(e.stamp) | 2250 local when = g_today and self:format_timestamp (g_today, e) or tostring(e.stamp) |
| 2229 entry = entry or { | 2251 entry = entry or { |
| 2230 id = e.id, | 2252 id = e.id, |
| 2231 when = when, | 2253 when = when, |
| 2232 count = e.count, | 2254 count = e.count, |
| 2233 } | 2255 } |
| 2234 tinsert (name_h, 1, entry) | 2256 tinsert (name_h, 1, entry) |
| 2235 e.history_unique = e.history_unique or (entry.id .. ' ' .. entry.when) | 2257 if (not e.unique) or (#e.unique==0) then |
| 2258 e.unique = entry.id .. ' ' .. entry.when | |
| 2259 end | |
| 2260 entry.unique = e.unique | |
| 2236 self.hist_clean = nil | 2261 self.hist_clean = nil |
| 2237 return | 2262 return |
| 2238 end | 2263 end |
| 2239 end | 2264 end |
| 2240 end | 2265 end |
| 2254 local function assemble(t,...) | 2279 local function assemble(t,...) |
| 2255 if select('#',...) > 0 then | 2280 if select('#',...) > 0 then |
| 2256 local msg = {t,...} | 2281 local msg = {t,...} |
| 2257 -- tconcat requires strings, but T is known to be one already | 2282 -- tconcat requires strings, but T is known to be one already |
| 2258 for i = 2, #msg do | 2283 for i = 2, #msg do |
| 2259 msg[i] = tostring(msg[i]) or "" | 2284 msg[i] = tostring(msg[i] or "") |
| 2260 end | 2285 end |
| 2261 return tconcat (msg, '\a') | 2286 return tconcat (msg, '\a') |
| 2262 end | 2287 end |
| 2263 return t | 2288 return t |
| 2264 end | 2289 end |
| 2304 OCR_funcs.revcheck = function (sender, _, revlarge) | 2329 OCR_funcs.revcheck = function (sender, _, revlarge) |
| 2305 addon.dprint('comm', "revcheck, sender", sender) | 2330 addon.dprint('comm', "revcheck, sender", sender) |
| 2306 addon:_check_revision (revlarge) | 2331 addon:_check_revision (revlarge) |
| 2307 end | 2332 end |
| 2308 | 2333 |
| 2309 OCR_funcs.loot = function (sender, _, recip, item, count, extratext) | 2334 OCR_funcs['16loot'] = function (sender, _, recip, item, count, extratext) |
| 2310 addon.dprint('comm', "DOTloot, sender", sender, "recip", recip, "item", item, "count", count) | 2335 addon.dprint('comm', "DOTloot/16, sender", sender, "recip", recip, "item", item, "count", count) |
| 2311 if not addon.enabled then return end | 2336 if not addon.enabled then return end |
| 2312 adduser (sender, nil, true) | 2337 adduser (sender, nil, true) |
| 2313 addon:CHAT_MSG_LOOT ("broadcast", recip, item, count, sender, extratext) | 2338 addon:CHAT_MSG_LOOT ("broadcast", recip, --[[unique=]]"", item, count, sender, extratext) |
| 2314 end | 2339 end |
| 2315 OCR_funcs['16loot'] = OCR_funcs.loot | 2340 OCR_funcs.loot = OCR_funcs['16loot'] -- old unversioned stuff goes to 16 |
| 2341 OCR_funcs['17loot'] = function (sender, _, recip, unique, item, count, extratext) | |
| 2342 addon.dprint('comm', "DOTloot, sender", sender, "recip", recip, | |
| 2343 "unique", unique, "item", item, "count", count) | |
| 2344 if not addon.enabled then return end | |
| 2345 adduser (sender, nil, true) | |
| 2346 addon:CHAT_MSG_LOOT ("broadcast", recip, unique, item, count, sender, extratext) | |
| 2347 end | |
| 2316 | 2348 |
| 2317 OCR_funcs.boss = function (sender, _, reason, bossname, instancetag) | 2349 OCR_funcs.boss = function (sender, _, reason, bossname, instancetag) |
| 2318 addon.dprint('comm', "DOTboss, sender", sender, "reason", reason, | 2350 addon.dprint('comm', "DOTboss, sender", sender, "reason", reason, |
| 2319 "name", bossname, "it", instancetag) | 2351 "name", bossname, "it", instancetag) |
| 2320 if not addon.enabled then return end | 2352 if not addon.enabled then return end |
| 2326 "name", bossname, "it", instancetag, "size", maxsize) | 2358 "name", bossname, "it", instancetag, "size", maxsize) |
| 2327 if not addon.enabled then return end | 2359 if not addon.enabled then return end |
| 2328 adduser (sender, nil, true) | 2360 adduser (sender, nil, true) |
| 2329 addon:on_boss_broadcast (reason, bossname, instancetag, maxsize) | 2361 addon:on_boss_broadcast (reason, bossname, instancetag, maxsize) |
| 2330 end | 2362 end |
| 2363 OCR_funcs['17boss'] = OCR_funcs['16boss'] | |
| 2331 | 2364 |
| 2332 OCR_funcs.bcast_req = function (sender) | 2365 OCR_funcs.bcast_req = function (sender) |
| 2333 if addon.debug.comm or ((not g_wafer_thin) and (not addon.rebroadcast)) | 2366 if addon.debug.comm or ((not g_wafer_thin) and (not addon.rebroadcast)) |
| 2334 then | 2367 then |
| 2335 addon:Print("%s has requested additional broadcasters! Choose %s to enable rebroadcasting, or %s to remain off and also ignore rebroadcast requests for as long as you're logged in.", | 2368 addon:Print("%s has requested additional broadcasters! Choose %s to enable rebroadcasting, or %s to remain off and also ignore rebroadcast requests for as long as you're logged in.", |
