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.", |