changeset 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 bb19899c65a7
files core.lua gui.lua
diffstat 2 files changed, 65 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/core.lua	Fri May 11 03:56:21 2012 +0000
+++ b/core.lua	Sat May 12 07:17:55 2012 +0000
@@ -53,6 +53,7 @@
 - itemlink      full clickable link
 - itexture      icon path (e.g., Interface\Icons\INV_Misc_Rune_01)
 - quality       ITEM_QUALITY_* number
+- unique        an almost-certainly-unique string, content meaningless
 - disposition   offspec/gvault/shard; missing otherwise; can be set from
                 the extratext field
 - count         e.g., "x3"; missing otherwise; can be set/removed from
@@ -109,7 +110,7 @@
 
 ------ Constants
 local option_defaults = {
-	['datarev'] = 19,    -- cheating, this isn't actually an option
+	['datarev'] = 20,    -- cheating, this isn't actually an option
 	['popup_on_join'] = true,
 	['register_slashloot'] = true,
 	['scroll_to_bottom'] = true,
@@ -161,7 +162,7 @@
 -- Play cute games with namespaces here just to save typing.  WTB Lua 5.2 PST.
 do local _G = _G setfenv (1, addon)
 
-	commrev			= '16'
+	commrev			= '17'
 	revision		= _G.GetAddOnMetadata(nametag,"Version") or "?"  -- "x.yy.z", etc
 	ident			= "OuroLoot2"
 	identTg			= "OuroLoot2Tg"
@@ -563,8 +564,11 @@
 	local r = self:load_assert (GetRealmName(), "how the freak does GetRealmName() fail?")
 	self.history_all[r] = self:_prep_new_history_category (self.history_all[r], r)
 	self.history = self.history_all[r]
+
+	local histformat = self.history_all.HISTFORMAT
+	self.history_all.HISTFORMAT = nil   -- don't keep this in live data
 	if (not InCombatLockdown()) and OuroLootSV_hist and 
-	   (OuroLootSV_hist.HISTFORMAT == nil)  -- restored data but it's older
+	   (histformat == nil or histformat < 3) -- restored data but it's older
 	then
 		-- Big honkin' loop
 		for rname,realm in pairs(self.history_all) do
@@ -573,11 +577,13 @@
 					if loot.count == "" then
 						loot.count = nil
 					end
+					if not loot.unique then
+						loot.unique = loot.id .. ' ' .. loot.when
+					end
 				end
 			end
 		end
 	end
-	self.history_all.HISTFORMAT = nil   -- don't keep this in live data
 	--OuroLootSV_hist = nil
 
 	-- Handle changes to the stored data format in stages from oldest to newest.
@@ -627,6 +633,14 @@
 			-- the exact same data in the exact same way.  At least they're
 			-- not actually running the same loop twice... probably... sigh.
 
+		bumpers[19] = function()
+			for i,e in ipairs(OuroLootSV) do
+				if e.kind == 'loot' and e.history_unique then
+					e.unique, e.history_unique = e.history_unique, nil
+				end
+			end
+		end
+
 		--[===[
 		local real = bumpers
 		bumpers = newproxy(true)
@@ -862,7 +876,7 @@
 	end end
 	if worth_saving then
 		OuroLootSV_hist = self.history_all
-		OuroLootSV_hist.HISTFORMAT = 2
+		OuroLootSV_hist.HISTFORMAT = 3
 	else
 		OuroLootSV_hist = nil
 	end
@@ -1050,10 +1064,10 @@
 	end
 	addon.recent_loot = create_new_cache ('loot', comm_cleanup_ttl+3, prefer_local_loots)
 
-	local GetItemInfo, GetItemIcon = GetItemInfo, GetItemIcon
+	local GetItemInfo, GetItemIcon, random = GetItemInfo, GetItemIcon, math.random
 
-	-- 'from' and onwards only present if this is triggered by a broadcast
-	function addon:_do_loot (local_override, recipient, itemid, count, from, extratext)
+	-- 'from' only present if this is triggered by a broadcast
+	function addon:_do_loot (local_override, recipient, unique, itemid, count, from, extratext)
 		local itexture = GetItemIcon(itemid)
 		local iname, ilink, iquality = GetItemInfo(itemid)
 		local i
@@ -1062,16 +1076,18 @@
 			iname, ilink, iquality, itexture = 
 				UNKNOWN..': '..itemid, 'item:6948', ITEM_QUALITY_COMMON, [[ICONS\INV_Misc_QuestionMark]]
 		end
-		self.dprint('loot',">>_do_loot, R:", recipient, "I:", itemid, "C:", count, "frm:", from, "ex:", extratext, "q:", iquality)
+		self.dprint('loot',">>_do_loot, R:", recipient, "U:", unique, "I:",
+			itemid, "C:", count, "frm:", from, "ex:", extratext, "q:", iquality)
 
 		itemid = tonumber(ilink:match("item:(%d+)") or 0)
+		unique = tostring(unique or random(8675309))  -- also, xkcd.com/1047
 		-- This is only a 'while' to make jumping out of it easy and still do cleanup below.
 		while local_override or ((iquality >= self.threshold) and not opts.itemfilter[itemid]) do
 			if (self.rebroadcast and (not from)) and not local_override then
-				self:vbroadcast('loot', recipient, itemid, count)
+				self:vbroadcast('loot', recipient, unique, itemid, count)
 			end
 			if (not self.enabled) and (not local_override) then break end
-			local signature = recipient .. iname .. (count or "")
+			local signature = unique .. recipient .. iname .. (count or "")
 			if from and self.recent_loot:test(signature) then
 				self.dprint('cache', "remote loot <",signature,"> already in cache, skipping")
 			else
@@ -1086,6 +1102,7 @@
 					id			= itemid,
 					itemlink	= ilink,
 					itexture	= itexture,
+					unique		= unique,
 					count		= (count and count ~= "") and count or nil,
 					bcast_from	= from,
 					extratext	= extratext,
@@ -1165,17 +1182,20 @@
 				person = my_name    -- UNIT_YOU / You
 			end
 
-			--local id = tonumber((select(2, strsplit(":", itemstring))))
-			local id = tonumber(itemstring:match('|Hitem:(%d+):'))
+			--local id = tonumber(itemstring:match('|Hitem:(%d+):'))
+			local id,unique,_
+			_,id,_,_,_,_,_,_,unique = strsplit (":", itemstring)
+			if unique == 0 then unique = nil end
 
-			return self:_do_loot (false, person, id, count)
+			return self:_do_loot (false, person, unique, id, count)
 
 		elseif event == "broadcast" then
 			return self:_do_loot(false, ...)
 
 		elseif event == "manual" then
 			local r,i,n = ...
-			return self:_do_loot(true, r,i,nil,nil,n)
+			return self:_do_loot(true, r, --[[unique=]]nil, i,
+				--[[count=]]nil, --[[from=]]nil, n)
 		end
 	end
 end
@@ -2057,7 +2077,10 @@
 			count = e.count,
 		}
 		tinsert (h, 1, n)
-		e.history_unique = n.id .. ' ' .. n.when
+		if (not e.unique) or (#e.unique==0) then
+			e.unique = n.id .. ' ' .. n.when
+		end
+		n.unique = e.unique
 	end
 
 	-- Create new history table based on current loot.
@@ -2109,7 +2132,7 @@
 		end
 
 		local player = loot.person
-		local tag = loot.history_unique
+		local tag = loot.unique
 		local errtxt
 		local player_i, player_h, hist_i
 
@@ -2118,8 +2141,7 @@
 		else
 			player_i,player_h = self:get_loot_history(player)
 			for i,h in ipairs(player_h) do
-				local unique = h.id .. ' ' .. h.when
-				if unique == tag then
+				if h.unique == tag then
 					hist_i = i
 					break
 				end
@@ -2200,7 +2222,7 @@
 			-- remove history entry
 			if hist_i then
 				local hist_h = tremove (name_h, hist_i)
-				deleted_cache[e.history_unique] = hist_h
+				deleted_cache[e.unique] = hist_h
 				self.hist_clean = nil
 			elseif (olddisp == 'shard' or olddisp == 'gvault') then
 				-- Sharding a vault item, or giving the auto-sharder something to bank,
@@ -2221,9 +2243,9 @@
 			-- cache of stuff we've already deleted; if it's not there then just do
 			-- the same steps as _addHistoryEntry.
 			local entry
-			if e.history_unique and deleted_cache[e.history_unique] then
-				entry = deleted_cache[e.history_unique]
-				deleted_cache[e.history_unique] = nil
+			if e.unique and deleted_cache[e.unique] then
+				entry = deleted_cache[e.unique]
+				deleted_cache[e.unique] = nil
 			end
 			local when = g_today and self:format_timestamp (g_today, e) or tostring(e.stamp)
 			entry = entry or {
@@ -2232,7 +2254,10 @@
 				count = e.count,
 			}
 			tinsert (name_h, 1, entry)
-			e.history_unique = e.history_unique or (entry.id .. ' ' .. entry.when)
+			if (not e.unique) or (#e.unique==0) then
+				e.unique = entry.id .. ' ' .. entry.when
+			end
+			entry.unique = e.unique 
 			self.hist_clean = nil
 			return
 		end
@@ -2256,7 +2281,7 @@
 			local msg = {t,...}
 			-- tconcat requires strings, but T is known to be one already
 			for i = 2, #msg do
-				msg[i] = tostring(msg[i]) or ""
+				msg[i] = tostring(msg[i] or "")
 			end
 			return tconcat (msg, '\a')
 		end
@@ -2306,13 +2331,20 @@
 		addon:_check_revision (revlarge)
 	end
 
-	OCR_funcs.loot = function (sender, _, recip, item, count, extratext)
-		addon.dprint('comm', "DOTloot, sender", sender, "recip", recip, "item", item, "count", count)
+	OCR_funcs['16loot'] = function (sender, _, recip, item, count, extratext)
+		addon.dprint('comm', "DOTloot/16, sender", sender, "recip", recip, "item", item, "count", count)
 		if not addon.enabled then return end
 		adduser (sender, nil, true)
-		addon:CHAT_MSG_LOOT ("broadcast", recip, item, count, sender, extratext)
+		addon:CHAT_MSG_LOOT ("broadcast", recip, --[[unique=]]"", item, count, sender, extratext)
 	end
-	OCR_funcs['16loot'] = OCR_funcs.loot
+	OCR_funcs.loot = OCR_funcs['16loot']   -- old unversioned stuff goes to 16
+	OCR_funcs['17loot'] = function (sender, _, recip, unique, item, count, extratext)
+		addon.dprint('comm', "DOTloot, sender", sender, "recip", recip,
+			"unique", unique, "item", item, "count", count)
+		if not addon.enabled then return end
+		adduser (sender, nil, true)
+		addon:CHAT_MSG_LOOT ("broadcast", recip, unique, item, count, sender, extratext)
+	end
 
 	OCR_funcs.boss = function (sender, _, reason, bossname, instancetag)
 		addon.dprint('comm', "DOTboss, sender", sender, "reason", reason,
@@ -2328,6 +2360,7 @@
 		adduser (sender, nil, true)
 		addon:on_boss_broadcast (reason, bossname, instancetag, maxsize)
 	end
+	OCR_funcs['17boss'] = OCR_funcs['16boss']
 
 	OCR_funcs.bcast_req = function (sender)
 		if addon.debug.comm or ((not g_wafer_thin) and (not addon.rebroadcast))
--- a/gui.lua	Fri May 11 03:56:21 2012 +0000
+++ b/gui.lua	Sat May 12 07:17:55 2012 +0000
@@ -464,7 +464,7 @@
 
 -- Done at startup, and whenever we've changed the population of tabs.
 function addon:gui_init (loot_pointer)
-	g_loot = loot_pointer
+	g_loot = assert(loot_pointer, "something went wrong at startup")
 	g_generated = nil
 	tabgroup_tabs = {}
 	window_title = "Ouro Loot " .. self.revision
@@ -579,7 +579,7 @@
 	["Rebroadcast this loot entry"] = function(rowi)
 		local e = g_loot[rowi]
 		-- This only works because GetItemInfo accepts multiple argument formats
-		addon:vbroadcast('loot', e.person, e.itemlink, e.count, e.cols[3].value)
+		addon:vbroadcast('loot', e.person, e.unique, e.itemlink, e.count, e.cols[3].value)
 		addon:Print("Rebroadcast entry", rowi, e.itemlink)
 	end,
 
@@ -594,7 +594,7 @@
 				addon:vbroadcast('boss', e.reason, e.bossname, e.instance)
 			elseif e.kind == 'loot' then
 				-- This only works because GetItemInfo accepts multiple argument formats
-				addon:vbroadcast('loot', e.person, e.itemlink, e.count, e.cols[3].value)
+				addon:vbroadcast('loot', e.person, e.unique, e.itemlink, e.count, e.cols[3].value)
 			end
 			addon:Print("Rebroadcast entry", rowi, e.itemlink or e.bossname or UNKNOWN)
 			rowi = rowi + 1