Mercurial > wow > ouroloot
diff core.lua @ 81:0f6355bcfe68
Initial version of reassign_loot that handles remote broadcasting, tested in sandbox. Catch tab generation errors at a higher level and take apart the window (including STs) rather than propagating Lua errors upwards.
author | Farmbuyer of US-Kilrogg <farmbuyer@gmail.com> |
---|---|
date | Fri, 15 Jun 2012 20:04:05 +0000 |
parents | f01d8d1b8f82 |
children | ae17128ef3f2 |
line wrap: on
line diff
--- a/core.lua Thu Jun 14 04:48:13 2012 +0000 +++ b/core.lua Fri Jun 15 20:04:05 2012 +0000 @@ -143,7 +143,14 @@ .." a download URL for copy-and-pasting. You can %s to ping other raiders" .." for their installed versions (same as '/ouroloot ping' or clicking the" .." 'Ping!' button on the options panel)." -local unique_collision = "|cffff1010%s:|r|nItem '%s' was carrying unique tag <%s>, but that was already in use; tried to generate a new tag and failed!|n|nRemote sender was '%s', previous cache entry was <%s/%s>.|n|nThis may require a live human to figure out; the loot in question has not been stored." +local horrible_error_text = [[|cffff1010]] .. ERROR_CAPS + ..[[:|n|cffffff00Something unrecoverable has happened. The error message]] + ..[[ which was provided follows in white:|r|n|n%s|n|n|cffffff00Ouro Loot]] + ..[[ will not display a window until this situation is corrected. ]] + ..[[ You can try typing|n|cff00ff40/ouroloot fix ?|n]] + ..[[|cffffff00to see what can be done by software alone. You may still]] + ..[[ need to do a "/reload" afterwards, or even restart the game client.]] +local unique_collision = "Item '%s' was carrying unique tag <%s>, but that was already in use; tried to generate a new tag and failed!|n|nRemote sender was '%s', previous cache entry was <%s/%s>.|n|nThis may require a live human to figure out; the loot in question has not been stored." local remote_chatty = "|cff00ff00%s|r changed %d/%s from %s%s|r to %s%s|r" local qualnames = { ['gray'] = 0, ['grey'] = 0, ['poor'] = 0, ['trash'] = 0, @@ -339,8 +346,8 @@ local CopyTable, GetNumRaidMembers = _G.CopyTable, _G.GetNumRaidMembers -- En masse forward decls of symbols defined inside local blocks local _register_bossmod, makedate, create_new_cache, _init, _log -local _history_by_loot_id, _notify_about_remote, _setup_unique_replace -local _unavoidable_collision +local _history_by_loot_id, _setup_unique_replace, _unavoidable_collision +local _notify_about_change, _notify_about_remote -- Try to extract numbers from the .toc "Version" and munge them into an -- integral form for comparison. The result doesn't need to be meaningful as @@ -1382,7 +1389,7 @@ self.dprint('loot', "substituting", unique, "with", replacement) else i = g_uniques[unique] - local err = unique_collision:format (ERROR_CAPS, iname, unique, + local err = unique_collision:format (iname, unique, tostring(from), tostring(i.loot), tostring(i.history)) _unavoidable_collision (err) -- Make sure this is logged one way or another @@ -1625,8 +1632,19 @@ elseif cmd == "ping" then self:DoPing() - elseif cmd == "fixcache" then - self:do_item_cache_fixup() + elseif cmd == "fix" then + if arg == "?" then + self:Print[['/loot fix cache' updates loot that wasn't in the cache]] + self:Print[['/loot fix history' repairs inconsistent data on the History tab]] + self:Print[['/loot fix' changes no stored data, only allows the window to be displayed again (this is built into all fixes above)]] + return + elseif arg == "cache" then + self:do_item_cache_fixup() + elseif arg == "history" then + self:repair_history_integrity() + end + self.NOLOAD = nil + self:Print("Window unlocked, best of luck.") else if self:OpenMainDisplayToTab(cmd) then @@ -1798,7 +1816,15 @@ end end - function _notify_about_remote (sender, index, from_whom, olddisp) + local hexes = _G.setmetatable({}, {__index = function (t, k) + local r = _G.math.floor(255*k.r+0.5) + local g = _G.math.floor(255*k.g+0.5) + local b = _G.math.floor(255*k.b+0.5) + local hex = ("|cff%.2x%.2x%.2x"):format(r,g,b) + t[k] = hex + return hex + end}) + function _notify_about_change (chatframe, source, index, olddisp, from_whom, from_class) local e = g_loot[index] if not e then -- how did this happen? @@ -1806,8 +1832,16 @@ end local from_color, from_text, to_color, to_text if from_whom then - -- FIXME need to return previous name/class from reassign_loot - + from_color = from_class + and addon.class_colors[from_class] + or _G.NORMAL_FONT_COLOR + from_color = hexes[from_color] + from_text = from_whom + to_color = e.person_class + and addon.class_colors[e.person_class] + or _G.NORMAL_FONT_COLOR + to_color = hexes[to_color] + to_text = e.person else if olddisp then from_text = addon.disposition_colors[olddisp].text @@ -1824,11 +1858,15 @@ to_color = addon.disposition_colors[e.disposition or "normal"].hex end - addon.dprint ('loot', "notifying:", sender, index, + addon.dprint ('loot', "notification:", source, index, e.itemlink, from_color, from_text, to_color, to_text) - addon:CFPrint (remote_change_chatframe, remote_chatty, sender, index, + addon:CFPrint (chatframe, remote_chatty, source, index, e.itemlink, from_color, from_text, to_color, to_text) end + + function _notify_about_remote (sender, index, olddisp, from_whom, from_class) + _notify_about_change (remote_change_chatframe, sender, index, olddisp, from_whom, from_class) + end end -- Adds indices to traverse the tables in a nice sorted order. @@ -2505,25 +2543,42 @@ do local clicky - function _unavoidable_collision (err) + function addon:horrible_horrible_error (err_msg) + if self.display then + local d = self.display + if d then + local eoist = d:GetUserData("eoiST") + if eoist then eoist:Hide() end + local histst = d:GetUserData("histST") + if histst then histst:Hide() end + d:Hide() + end + end + self.NOLOAD = err_msg -- This should happen so rarely that it's not worth moving into gui.lua - if not StaticPopupDialogs["OUROL_COLLISION"] then - StaticPopupDialogs["OUROL_COLLISION"] = flib.StaticPopup{ + if not StaticPopupDialogs["OUROL_ARGH"] then + StaticPopupDialogs["OUROL_ARGH"] = flib.StaticPopup{ button1 = OKAY, } clicky = addon.format_hypertext( [[ SYSTEM FAILURE -- RELEASE RINZLER ]], "|cffff0000", - function() StaticPopup_Show "OUROL_COLLISION" end) + function() StaticPopup_Show "OUROL_ARGH" end) end - StaticPopupDialogs["OUROL_COLLISION"].text = err + StaticPopupDialogs["OUROL_ARGH"].text = horrible_error_text:format(err_msg) _G.PlaySoundFile ([[Interface\AddOns\Ouro_Loot\sfrr.ogg]], "Master") addon:Print (" ") addon:Print (" ", clicky) addon:Print (" ") end + + function _unavoidable_collision (err) + addon:horrible_horrible_error (err) + -- we don't actually need to kill the GUI in this case + addon.NOLOAD = nil + end end --function DOTEST() --- local err = unique_collision:format (ERROR_CAPS, +-- local err = unique_collision:format ( -- "Codpiece of the Grimacing Lunatic", -- 'n3183021', 'Farmbuyer', '14', '78') -- _unavoidable_collision (err) @@ -2540,7 +2595,7 @@ end function addon:save_list() - local s = self:check_saved_table(); if not s then return end; + local s = self:check_saved_table(); if not s then return end for i,t in ipairs(s) do self:Print("#%d %s %d entries %s", i, t.date, t.count, t.name) end @@ -2564,7 +2619,7 @@ end function addon:save_restore(num) - local s = self:check_saved_table(); if not s then return end; + local s = self:check_saved_table(); if not s then return end if (not num) or (num > #s) then return self:Print("Saved text number must be 1 - "..#s) end @@ -2579,7 +2634,7 @@ end function addon:save_delete(num) - local s = self:check_saved_table(); if not s then return end; + local s = self:check_saved_table(); if not s then return end if (not num) or (num > #s) then return self:Print("Saved text number must be 1 - "..#s) end @@ -2641,6 +2696,58 @@ p.unique = new_uniques end + function addon:repair_history_integrity() + local rcount, pcount, hcount, errors = 0, 0, 0, 0 + local empties_to_delete = {} + + for rname,realm in pairs(self.history_all) do + for pk,player in ipairs(realm) do + local id, when, unique, count = {}, {}, {}, {} + for i,h in ipairs(player.unique) do + h = tostring(h) + if player.when[h] and player.id[h] then + unique[#unique+1] = h + id[h] = player.id[h] + when[h] = player.when[h] + count[h] = player.count[h] + else + self:Print("Realm %s, player %s, entry %d: tag <%s>, id <%s>, time <%s>, count <%s>", + rname, player.name, i, h, tostring(player.id[h]), + tostring(player.when[h]), tostring(player.count[h])) + errors = errors + 1 + end + hcount = hcount + 1 + end + player.id, player.when, player.unique, player.count = + id, when, unique, count + player.person_class = g_loot.raiders[player.name] + and g_loot.raiders[player.name].class + if #player.unique > 1 then + sort_player(player) + elseif #player.unique == 0 then + tinsert (empties_to_delete, 1, pk) + end + pcount = pcount + 1 + end + if #empties_to_delete > 0 then + for _,pk in ipairs(empties_to_delete) do + local player = tremove (realm, pk) + self:Print("Realm %s, player %s, is empty", rname, player.name) + end + wipe(empties_to_delete) + end + if #realm == 0 then + self.history_all[rname] = nil + self:Print("Realm %s is empty", rname) + end + rcount = rcount + 1 + end + self:_build_history_names() + if errors > 0 then + self:Print("The listed entries have been erased from history.") + end + end + -- Possibly called during login. Cleared when no longer needed. -- Rewrites a PLAYER table from format 3 to format 4. function addon:_uplift_history_format (player) @@ -2884,16 +2991,79 @@ return nil, errtxt end - function addon:reassign_loot (index, to_name) - assert(type(to_name)=='string' and to_name:len()>0) - local e = g_loot[index] + -- Handles reassigning loot between players. Arguments depend on who's + -- calling it: + -- "local", row_index, new_recipient + -- "remote", sender, unique_id, item_id, old_recipient, new_recipient + -- In the local case, must also broadcast a trigger. In the remote case, + -- must figure out the corresponding loot entry (if it exists). In both + -- cases, must update history appropriately. Returns nil if anything odd + -- happens; returns the affected loot index on success. + --function addon:reassign_loot (index, to_name) + function addon:reassign_loot (how, ...) + -- This must all be filled out in all cases: + local e, index, from_name, to_name, unique, id + -- Only set in remote case: + local sender + + if how == "local" then + -- GUI doesn't allow reassignment unless the item is not-shard, + -- so we can assume the presence of a unique tag in this function. + index, to_name = ... + assert(type(to_name)=='string' and to_name:len()>0) + index = assert(tonumber(index)) + e = g_loot[index] + id = e.id + unique = assert(e.unique) + from_name = e.person + + elseif how == "remote" then + sender, unique, id, from_name, to_name = ... + id = tonumber(id) + local cache + local loop = 0 + repeat -- wtb continue statement pst + if loop > 1 then break end + e = nil + cache = cache and g_uniques:SEARCH(unique) or g_uniques[unique] + index = tonumber(cache.loot) + if index then + e = g_loot[index] + else + end + loop = loop + 1 + until e and (e.id == id) + + else + return -- silently ignore future cases from future clients + end + + if self.debug.loot then + local m = ("Reassign index %d (pre-unique %s) with id %d from '%s' to '%s'."): + format(index, unique, id, tostring(from_name), tostring(to_name)) + self.dprint('loot', m) + if sender == my_name then + self.dprint('loot',"(Returning early from debug mode's double self-reassign.)") + return index + end + end + + if not e then + -- say something? + return + end + local from_i, from_h, hist_i = _history_by_loot_id (e, "reassign") - local from_name = e.person local to_i,to_h = self:get_loot_history(to_name) - if not from_i then -- from_h here is the formatted error text - self:Print(from_h .. " Loot will be reassigned, but history will NOT be updated.", e.itemlink) + if not from_i then + if how == "local" then + -- from_h here is the formatted error text + self:Print(from_h .. " Loot will be reassigned, but history will NOT be updated.", e.itemlink) + end else + -- XXX do some sanity checks here? from_name == from_h.name, etc? + local U = tremove (from_h.unique, hist_i) -- The loot master giveth... to_h.unique[#to_h.unique+1] = U @@ -2908,11 +3078,29 @@ -- Blessed be the lookup cache of the loot master. g_uniques[U] = { loot = index, history = to_i } end + local from_person_class = e.person_class or from_h.person_class + or (g_loot.raiders[from_name] and g_loot.raiders[from_name].class) + or select(2,_G.UnitClass(from_name)) e.person = to_name - e.person_class = select(2,_G.UnitClass(to_name)) + e.person_class = to_h.person_class + or (g_loot.raiders[to_name] and g_loot.raiders[to_name].class) + or select(2,_G.UnitClass(to_name)) self.hist_clean = nil - - self:Print("Reassigned entry %d/%s from '%s' to '%s'.", index, e.itemlink, from_name, to_name) + self.loot_clean = nil + + if how == "local" then + --self:Print("Reassigned entry %d/%s from '%s' to '%s'.", index, e.itemlink, from_name, to_name) + _notify_about_change (_G.DEFAULT_CHAT_FRAME, _G.UNIT_YOU, index, + nil, from_name, from_person_class) + self:vbroadcast('reassign', unique, id, from_name, to_name) + elseif opts.chatty_on_remote_changes then + _notify_about_remote (sender, index, nil, from_name, from_person_class) + end + if self.display then + self.display:GetUserData("eoiST"):OuroLoot_Refresh(index) + self:redisplay() + end + return index end -- Similar to _addHistoryEntry. The second arg may be a loot entry @@ -3035,11 +3223,20 @@ elseif how == "remote" then sender, unique, id, olddisp, newdisp = ... - local cache = g_uniques[unique] - if cache.loot then + id = tonumber(id) + local cache + local loop = 0 + repeat -- wtb continue statement pst + if loop > 1 then break end + e = nil + cache = cache and g_uniques:SEARCH(unique) or g_uniques[unique] index = tonumber(cache.loot) - e = g_loot[index] - end + if index then + e = g_loot[index] + else + end + loop = loop + 1 + until e and (e.id == id) else return -- silently ignore future cases from future clients @@ -3064,6 +3261,8 @@ e.bcast_from = nil -- I actually don't remember now why this gets cleared... e.extratext = nil self:history_handle_disposition (index, olddisp) + self.hist_clean = nil + self.loot_clean = nil -- A unique tag has been set by this point. if how == "local" then unique = assert(e.unique) @@ -3155,10 +3354,17 @@ local index = addon:loot_mark_disposition ("remote", sender, unique, item, old, new) --if not addon.enabled then return end -- hmm if index and opts.chatty_on_remote_changes then - _notify_about_remote (sender, index, --[[from_whom=]]nil, old) + _notify_about_remote (sender, index, old) end end + OCR_funcs['17reassign'] = function (sender, _, unique, item, from, to) + addon.dprint('comm', "DOTreassign/17, sender", sender, "unique", unique, + "item", item, "from", from, "to", to) + --[[local index =]] addon:reassign_loot ("remote", sender, unique, item, from, to) + -- Notification handled inside reassign_loot. + end + 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