From e717465e0eb64581613b1625431d8ada475f2a21 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Mon, 9 Dec 2013 02:14:10 +0000 Subject: [PATCH] Re-write of OvaleGUID. - Cleaner mappings between GUID <--> Unit ID <--> Unit name. - Create "unit ID" priority so that the "best" unit ID is returned for a given GUID. - Update mappings more aggressively to fix ticket 326. git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1243 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- OvaleAura.lua | 4 +- OvaleGUID.lua | 317 ++++++++++++++++++++++++++++++++------------------------- 2 files changed, 182 insertions(+), 139 deletions(-) diff --git a/OvaleAura.lua b/OvaleAura.lua index c8ccc43..517844a 100644 --- a/OvaleAura.lua +++ b/OvaleAura.lua @@ -277,7 +277,7 @@ function OvaleAura:COMBAT_LOG_EVENT_UNFILTERED(event, ...) if CLEU_AURA_EVENTS[event] then local unitId = OvaleGUID:GetUnitId(destGUID) - if unitId and not OvaleGUID.UNIT_AURA_UNITS[unitId] then + if unitId and not OvaleGUID.UNIT_AURA_UNIT[unitId] then Ovale:DebugPrintf(OVALE_AURA_DEBUG, "%s: %s", event, unitId) self:ScanAurasOnGUID(destGUID) end @@ -335,7 +335,7 @@ end function OvaleAura:ScanAllUnitAuras() -- Update auras on all visible units. - for unitId in pairs(OvaleGUID.UNIT_AURA_UNITS) do + for unitId in pairs(OvaleGUID.UNIT_AURA_UNIT) do self:ScanAuras(unitId) end end diff --git a/OvaleGUID.lua b/OvaleGUID.lua index 0396bd0..f32bd5c 100644 --- a/OvaleGUID.lua +++ b/OvaleGUID.lua @@ -8,66 +8,116 @@ file accompanying this program. --]]-------------------------------------------------------------------- --- This addon translates a GUID to a target name --- Usage: OvaleGUID:GetUnitId(guid) +--[[ + This addon manages mappings between GUID <--> unit ID <--> unit name. + + A GUID can have multiple unit IDs. + A unit ID can only have one GUID. + A unit ID may not exist. + + All primary unit IDs receive events. + No target IDs receive events. + No "mouseover" unit IDs receive events. +--]] local _, Ovale = ... -local OvaleGUID = Ovale:NewModule("OvaleGUID", "AceEvent-3.0", "AceConsole-3.0") +local OvaleGUID = Ovale:NewModule("OvaleGUID", "AceEvent-3.0") Ovale.OvaleGUID = OvaleGUID -- -local strfind = string.find -local strsub = string.sub +local ipairs = ipairs +local tinsert = table.insert local API_GetNumGroupMembers = GetNumGroupMembers -local API_UnitExists = UnitExists local API_UnitGUID = UnitGUID local API_UnitName = UnitName local OVALE_GUID_DEBUG = "guid" --- --- -OvaleGUID.unitId = {} -OvaleGUID.guid = {} -OvaleGUID.nameToGUID = {} -OvaleGUID.nameToUnit = {} +--[[ + Unit IDs for which UNIT_AURA events are known to fire. --- Units for which UNIT_AURA is known to fire. --- These are unit IDs that correspond to unit frames in the default WoW UI. -OvaleGUID.UNIT_AURA_UNITS = {} + UNIT_AURA_UNITS is an ordered list of unit ID priority. + UNIT_AURA_UNIT is a table that holds the reverse mapping of UNIT_AURA_UNITS. +--]] +local UNIT_AURA_UNITS = {} do - local self = OvaleGUID - self.UNIT_AURA_UNITS["focus"] = true - self.UNIT_AURA_UNITS["pet"] = true - self.UNIT_AURA_UNITS["player"] = true - self.UNIT_AURA_UNITS["target"] = true - + tinsert(UNIT_AURA_UNITS, "player") + tinsert(UNIT_AURA_UNITS, "pet") + tinsert(UNIT_AURA_UNITS, "vehicle") + tinsert(UNIT_AURA_UNITS, "npc") + tinsert(UNIT_AURA_UNITS, "target") + tinsert(UNIT_AURA_UNITS, "focus") for i = 1, 5 do - self.UNIT_AURA_UNITS["arena" .. i] = true - self.UNIT_AURA_UNITS["arenapet" .. i] = true + tinsert(UNIT_AURA_UNITS, "arena" .. i) + tinsert(UNIT_AURA_UNITS, "arenapet" .. i) + end + for i = 1, 40 do + tinsert(UNIT_AURA_UNITS, "raid" .. i) + tinsert(UNIT_AURA_UNITS, "raidpet" .. i) end for i = 1, 4 do - self.UNIT_AURA_UNITS["boss" .. i] = true + tinsert(UNIT_AURA_UNITS, "party" .. i) + tinsert(UNIT_AURA_UNITS, "partypet" .. i) + end + for i = 1, 4 do + tinsert(UNIT_AURA_UNITS, "boss" .. i) + end +end + +local UNIT_AURA_UNIT = {} +do + for i, unitId in ipairs(UNIT_AURA_UNITS) do + UNIT_AURA_UNIT[unitId] = i + end +end + +-- PET_UNIT[unitId] = pet's unit ID +local PET_UNIT = {} +do + PET_UNIT["player"] = "pet" + for i = 1, 5 do + PET_UNIT["arena" .. i] = "arenapet" .. i end for i = 1, 4 do - self.UNIT_AURA_UNITS["party" .. i] = true - self.UNIT_AURA_UNITS["partypet" .. i] = true + PET_UNIT["party" .. i] = "partypet" .. i end for i = 1, 40 do - self.UNIT_AURA_UNITS["raid" .. i] = true - self.UNIT_AURA_UNITS["raidpet" .. i] = true + PET_UNIT["raid" .. i] = "raidpet" .. i end end +-- + +-- +--[[ + Unit ID --> GUID mapping. + unit ID can only have one GUID. + self.unitIdToGUID[unitId] = GUID +--]] +OvaleGUID.unitIdToGUID = {} + +--[[ + GUID --> unit ID mapping. + A GUID can have multiple unit IDs. + self.GUIDtoUnitId[guid] = { unitId = true if it exists and points to guid; nil otherwise } +--]] +OvaleGUID.GUIDtoUnitId = {} + +--[[ +--]] +OvaleGUID.nameToGUID = {} + +-- Export UNIT_AURA_UNIT table of units that receive UNIT_AURA events. +OvaleGUID.UNIT_AURA_UNIT = UNIT_AURA_UNIT -- -- function OvaleGUID:OnEnable() - self:Update("player") self:RegisterEvent("ARENA_OPPONENT_UPDATE") self:RegisterEvent("GROUP_ROSTER_UPDATE") self:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT") + self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateAllUnits") self:RegisterEvent("PLAYER_FOCUS_CHANGED") - self:RegisterEvent("PLAYER_LOGIN") + self:RegisterEvent("PLAYER_LOGIN", "UpdateAllUnits") self:RegisterEvent("PLAYER_TARGET_CHANGED") self:RegisterEvent("UNIT_PET") self:RegisterEvent("UNIT_TARGET") @@ -78,6 +128,7 @@ function OvaleGUID:OnDisable() self:UnregisterEvent("ARENA_OPPONENT_UPDATE") self:UnregisterEvent("GROUP_ROSTER_UPDATE") self:UnregisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT") + self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("PLAYER_FOCUS_CHANGED") self:UnregisterEvent("PLAYER_LOGIN") self:UnregisterEvent("PLAYER_TARGET_CHANGED") @@ -86,144 +137,136 @@ function OvaleGUID:OnDisable() self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT") end -function OvaleGUID:Update(unitId) - local guid = API_UnitGUID(unitId) - local previousGuid = self.guid[unitId] - if previousGuid ~= guid then - if previousGuid and self.unitId[previousGuid] then - self.unitId[previousGuid][unitId] = nil - if not next(self.unitId[previousGuid]) then - self.unitId[previousGuid] = nil - end - end - self.guid[unitId] = guid - if guid then - if not self.unitId[guid] then - self.unitId[guid] = {} - end - Ovale:DebugPrintf(OVALE_GUID_DEBUG, "GUID %s is %s", guid, unitId) - self.unitId[guid][unitId] = true - end - end - local name = API_UnitName(unitId) - if name and (not self.nameToGUID[name] or unitId == "target" - or self.nameToUnit[name] == "mouseover") then - self.nameToGUID[name] = guid - self.nameToUnit[name] = unitId +function OvaleGUID:ARENA_OPPONENT_UPDATE(event, unitId, eventType) + for i = 1, 5 do + local unit = "arena" .. i + self:UpdateUnitWithTarget(unit) + local pet = PET_UNIT[unit] or (unit .. "pet") + self:UpdateUnitWithTarget(pet) end end -function OvaleGUID:GetGUID(unitId) - if not unitId then return nil end - local guid = self.guid[unitId] - if not guid or strfind(unitId, "mouseover") == 1 then - self.guid[unitId] = API_UnitGUID(unitId) - guid = self.guid[unitId] - end - return guid +function OvaleGUID:GROUP_ROSTER_UPDATE(event) + self:UpdateAllUnits() + self:SendMessage("Ovale_GroupChanged") end -function OvaleGUID:GetGUIDForName(name) - return self.nameToGUID[name] +function OvaleGUID:INSTANCE_ENCOUNTER_ENGAGE_UNIT(event) + for i= 1, 4 do + self:UpdateUnitWithTarget("boss" .. i) + end end --- Return a unit Id associated with guid. --- Prefer to return a unit Id for which the WoW servers fire UNIT_AURA events. -function OvaleGUID:GetUnitId(guid) - local unitIdFound = nil - local unitIdTable = self.unitId[guid] - if unitIdTable then - for unitId in pairs(unitIdTable) do - if self.UNIT_AURA_UNITS[unitId] then - return unitId - elseif not unitIdFound then - if strfind(unitId, "mouseover") == 1 then - if API_UnitExists(unitId) then - unitIdFound = unitId - else - unitIdTable[unitId] = nil - self.guid[unitId] = nil - end - else - unitIdFound = unitId - end - end - end - end - return unitIdFound +function OvaleGUID:PLAYER_FOCUS_CHANGED(event) + self:UpdateUnitWithTarget("focus") end -function OvaleGUID:GetUnitIdForName(name) - local unitId = self.nameToUnit[name] - if strfind(unitId, "mouseover") == 1 then - if API_UnitExists("mouseover") then - return unitId - else - self.nameToUnit[name] = nil - return nil - end - end - return unitId +function OvaleGUID:PLAYER_TARGET_CHANGED(event, cause) + self:UNIT_TARGET(event, "player") end -function OvaleGUID:UpdateWithTarget(unitId) - self:Update(unitId) - self:Update(unitId.."target") +function OvaleGUID:UNIT_PET(event, unitId) + local pet = PET_UNIT[unitiD] or (unitId .. "pet") + self:UpdateUnitWithTarget(pet) + self:SendMessage("Ovale_GroupChanged") end -function OvaleGUID:PLAYER_LOGIN(event) - self:Update("player") +function OvaleGUID:UNIT_TARGET(event, unitId) + local target = (unitId == "player") and "target" or (unitId .. "target") + self:UpdateUnit(target) end -function OvaleGUID:PLAYER_TARGET_CHANGED(event) - self:UNIT_TARGET(event, "player") +function OvaleGUID:UPDATE_MOUSEOVER_UNIT(event) + self:UpdateUnitWithTarget("mouseover") end -function OvaleGUID:UNIT_TARGET(event, unitId) - self:Update(unitId .. "target") - if unitId == "player" then - self:Update("target") +function OvaleGUID:UpdateAllUnits() + for _, unitId in pairs(UNIT_AURA_UNITS) do + self:UpdateUnitWithTarget(unitId) end end -function OvaleGUID:GROUP_ROSTER_UPDATE(event) - for i=1, API_GetNumGroupMembers() do - self:UpdateWithTarget("raid"..i) - self:UpdateWithTarget("raidpet"..i) - end - self:SendMessage("Ovale_GroupChanged") +function OvaleGUID:UpdateUnitWithTarget(unitId) + self:UpdateUnit(unitId) + self:UpdateUnit(unitId .. "target") end -function OvaleGUID:UNIT_PET(event, unitId) - if strfind(unitId, "party") == 0 then - local petId = "partypet" .. strsub(unitId, 6) - self:UpdateWithTarget(petId) - elseif strfind(unitId, "raid") == 0 then - local petId = "raidpet" .. strsub(unitId, 5) - self:UpdateWithTarget(petId) - elseif unitId == "player" then - self:UpdateWithTarget("pet") +function OvaleGUID:UpdateUnit(unitId) + local guid = API_UnitGUID(unitId) + if guid then + local previousGUID = self.unitIdToGUID[unitId] + if previousGUID ~= guid then + -- Remove previous mappings for this unit ID. + if previousGUID and self.GUIDtoUnitId[previousGUID] then + self.GUIDtoUnitId[previousGUID][unitId] = nil + if not next(self.GUIDtoUnitId[previousGUID]) then + self.GUIDtoUnitId[previousGUID] = nil + end + end + -- Create new mappings this unit ID to the GUID. + self.unitIdToGUID[unitId] = guid + self.GUIDtoUnitId[guid] = self.GUIDtoUnitId[guid] or {} + self.GUIDtoUnitId[guid][unitId] = true + + Ovale:DebugPrintf(OVALE_GUID_DEBUG, "GUID %s is %s", guid, unitId) + + if unitId == "target" or self.unitIdToGUID.target ~= guid then + local name = API_UnitName(unitId) + self.nameToGUID[name] = self.nameToGUID[name] or guid + end + end + else + -- This unit ID doesn't point to a valid GUID. + self.unitIdToGUID[unitId] = nil + if self.GUIDtoUnitId[guid] then + self.GUIDtoUnitId[guid][unitId] = nil + if not next(self.GUIDtoUnitId[guid]) then + self.GUIDtoUnitId[guid] = nil + end + end end - self:SendMessage("Ovale_GroupChanged") end -function OvaleGUID:ARENA_OPPONENT_UPDATE(event) - for i=1, 5 do - self:UpdateWithTarget("arena"..i) +function OvaleGUID:GetGUID(unitId) + if unitId then + -- If the unit ID doesn't receive events, then refresh it now. + if not UNIT_AURA_UNIT[unitId] then + self:UpdateUnit(unitId) + end + return self.unitIdToGUID[unitId] end + return nil end -function OvaleGUID:PLAYER_FOCUS_CHANGED(event) - self:UpdateWithTarget("focus") +function OvaleGUID:GetUnitId(guid) + if self.GUIDtoUnitId[guid] then + -- Find the unit ID with the best (lowest) priority. + local bestUnitId, bestPriority + for unitId in pairs(self.GUIDtoUnitId[guid]) do + local priority = UNIT_AURA_UNIT[unitId] + if priority then + if not bestPriority or priority < bestPriority then + bestUnitId, bestPriority = unitId, priority + end + else + -- This isn't a unit ID that receives events, so refresh it to make + -- sure it still points to this GUID. + self:UpdateUnit(unitId) + if not bestPriority and self.unitIdToGUID[unitId] == guid then + bestUnitId = unitId + end + end + end + return bestUnitId + end + return nil end -function OvaleGUID:UPDATE_MOUSEOVER_UNIT(event) - self:UpdateWithTarget("mouseover") +function OvaleGUID:GetGUIDForName(name) + return self.nameToGUID[name] end -function OvaleGUID:INSTANCE_ENCOUNTER_ENGAGE_UNIT(event) - for i=1, 4 do - self:UpdateWithTarget("boss"..i) - end +function OvaleGUID:GetUnitIdForName(name) + return self:GetUnitId(self:GetGUIDForName(name)) end -- -- 1.7.9.5