--[[-------------------------------------------------------------------- Ovale Spell Priority Copyright (C) 2012 Sidoine Copyright (C) 2012, 2013 Johnny C. Lam This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License in the LICENSE file accompanying this program. --]]-------------------------------------------------------------------- --[[ 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 <unit>target IDs receive events. No "mouseover" unit IDs receive events. --]] local _, Ovale = ... local OvaleGUID = Ovale:NewModule("OvaleGUID", "AceEvent-3.0") Ovale.OvaleGUID = OvaleGUID --<private-static-properties> local ipairs = ipairs local tinsert = table.insert local API_GetNumGroupMembers = GetNumGroupMembers local API_UnitGUID = UnitGUID local API_UnitName = UnitName local OVALE_GUID_DEBUG = "guid" --[[ Unit IDs for which UNIT_AURA events are known to fire. 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 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 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 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 PET_UNIT["party" .. i] = "partypet" .. i end for i = 1, 40 do PET_UNIT["raid" .. i] = "raidpet" .. i end end --</private-static-properties> --<public-static-properties> --[[ 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 --</public-static-properties> --<public-static-methods> function OvaleGUID:OnEnable() 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", "UpdateAllUnits") self:RegisterEvent("PLAYER_TARGET_CHANGED") self:RegisterEvent("UNIT_PET") self:RegisterEvent("UNIT_TARGET") self:RegisterEvent("UPDATE_MOUSEOVER_UNIT") end 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") self:UnregisterEvent("UNIT_PET") self:UnregisterEvent("UNIT_TARGET") self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT") end 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:GROUP_ROSTER_UPDATE(event) self:UpdateAllUnits() self:SendMessage("Ovale_GroupChanged") end function OvaleGUID:INSTANCE_ENCOUNTER_ENGAGE_UNIT(event) for i= 1, 4 do self:UpdateUnitWithTarget("boss" .. i) end end function OvaleGUID:PLAYER_FOCUS_CHANGED(event) self:UpdateUnitWithTarget("focus") end function OvaleGUID:PLAYER_TARGET_CHANGED(event, cause) self:UNIT_TARGET(event, "player") end function OvaleGUID:UNIT_PET(event, unitId) local pet = PET_UNIT[unitiD] or (unitId .. "pet") self:UpdateUnitWithTarget(pet) self:SendMessage("Ovale_GroupChanged") end function OvaleGUID:UNIT_TARGET(event, unitId) local target = (unitId == "player") and "target" or (unitId .. "target") self:UpdateUnit(target) end function OvaleGUID:UPDATE_MOUSEOVER_UNIT(event) self:UpdateUnitWithTarget("mouseover") end function OvaleGUID:UpdateAllUnits() for _, unitId in pairs(UNIT_AURA_UNITS) do self:UpdateUnitWithTarget(unitId) end end function OvaleGUID:UpdateUnitWithTarget(unitId) self:UpdateUnit(unitId) self:UpdateUnit(unitId .. "target") end 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 end 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: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:GetGUIDForName(name) return self.nameToGUID[name] end function OvaleGUID:GetUnitIdForName(name) return self:GetUnitId(self:GetGUIDForName(name)) end --</public-static-methods>