mirror of
https://github.com/brues-code/pfUI.git
synced 2026-09-22 07:36:56 +00:00
6c64143b60
GetUnitInfo() probed the players table first, so an NPC sharing a name with a known player (e.g. Chromie) inherited the player's class, level, and guild. Adds an isPlayer hint to GetUnitInfo and resolves each plate's actual unit type from its cached GUID via UnitIsPlayer before the lookup. The plate's cache.player gates further work.
201 lines
7.3 KiB
Lua
201 lines
7.3 KiB
Lua
-- load pfUI environment
|
|
setfenv(1, pfUI:GetEnvironment())
|
|
|
|
--[[ libunitscan ]]--
|
|
-- A pfUI library that detects and saves all kind of unit related informations.
|
|
-- Such as level, class, elite-state and playertype. Each query causes the library
|
|
-- to automatically scan for the target if not already existing. Player-data is
|
|
-- persisted within the pfUI_playerDB where the mob data is a throw-away table.
|
|
-- The automatic target scanner is only working for vanilla due to client limitations
|
|
-- on further expansions.
|
|
--
|
|
-- External functions:
|
|
-- GetUnitInfo(name, active, isPlayer)
|
|
-- Returns information of the given unitname. Returns nil if no match is found.
|
|
-- When nothing is found and the active flag is set, the autoscanner will
|
|
-- automatically pick it up and try to fill the missing entry by targetting the unit.
|
|
-- Pass isPlayer=true/false to restrict the lookup to the players or mobs table
|
|
-- (avoids name-collision false positives, e.g. a player and an NPC named Chromie).
|
|
--
|
|
-- class[String] - The class of the unit
|
|
-- level[Number] - The level of the unit
|
|
-- elite[String] - The elite state of the unit (See UnitClassification())
|
|
-- player[Boolean] - Returns true if unit is a player
|
|
-- guild[String] - Returns guild name of unit is a player
|
|
--
|
|
-- Internal functions:
|
|
-- libunitscan:AddData(db, name, class, level, elite)
|
|
-- Adds unit data to a given db. Where db should be either "players" or "mobs"
|
|
--
|
|
|
|
-- return instantly when another libunitscan is already active
|
|
if pfUI.api.libunitscan then return end
|
|
|
|
local units = { players = {}, mobs = {} }
|
|
local queue = { }
|
|
|
|
-- Feed (guid, name, classToken) into ClassicAPI's persistent name
|
|
-- cache when the unit's GUID is resolvable. Roster-style packets
|
|
-- (party / raid / inspect on glance) carry class inline, so the
|
|
-- engine often doesn't issue a separate name query and the DLL's
|
|
-- NameCache hook never fires for them — this is where we close that gap.
|
|
local function RememberByUnit(unit, name, class)
|
|
if not (name and class) then return end
|
|
local guid = UnitGUID(unit)
|
|
if not guid then return end
|
|
C_PlayerCache.RememberPlayer(guid, name, class, UnitRace(unit), UnitSex(unit))
|
|
end
|
|
|
|
function GetUnitInfo(name, active, isPlayer)
|
|
if isPlayer ~= false and units["players"][name] then
|
|
local ret = units["players"][name]
|
|
return ret.class, ret.level, ret.elite, true, ret.guild
|
|
elseif isPlayer ~= true and units["mobs"][name] then
|
|
local ret = units["mobs"][name]
|
|
return ret.class, ret.level, ret.elite, nil, ret.guild
|
|
elseif active then
|
|
queue[name] = true
|
|
libunitscan:Show()
|
|
end
|
|
end
|
|
|
|
local function AddData(db, name, class, level, elite, guild)
|
|
if not name or not db then return end
|
|
units[db] = units[db] or {}
|
|
units[db][name] = units[db][name] or {}
|
|
units[db][name].class = class or units[db][name].class
|
|
units[db][name].level = level or units[db][name].level
|
|
units[db][name].elite = elite or units[db][name].elite
|
|
units[db][name].guild = guild or units[db][name].guild
|
|
queue[name] = nil
|
|
end
|
|
|
|
local libunitscan = CreateFrame("Frame", "pfUnitScan", UIParent)
|
|
libunitscan:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
libunitscan:RegisterEvent("FRIENDLIST_UPDATE")
|
|
libunitscan:RegisterEvent("GUILD_ROSTER_UPDATE")
|
|
libunitscan:RegisterEvent("RAID_ROSTER_UPDATE")
|
|
libunitscan:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
|
libunitscan:RegisterEvent("PLAYER_TARGET_CHANGED")
|
|
libunitscan:RegisterEvent("WHO_LIST_UPDATE")
|
|
libunitscan:RegisterEvent("CHAT_MSG_SYSTEM")
|
|
libunitscan:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
|
|
libunitscan:RegisterEvent("NAME_PLATE_UNIT_ADDED")
|
|
libunitscan:SetScript("OnEvent", function()
|
|
if event == "PLAYER_ENTERING_WORLD" then
|
|
|
|
-- load pfUI_playerDB
|
|
units.players = pfUI_playerDB
|
|
|
|
-- update own character details
|
|
local name = UnitName("player")
|
|
local _, class = UnitClass("player")
|
|
local level = UnitLevel("player")
|
|
local guild = GetGuildInfo("player")
|
|
AddData("players", name, class, level, nil, guild)
|
|
RememberByUnit("player", name, class)
|
|
|
|
elseif event == "FRIENDLIST_UPDATE" then
|
|
local name, class, level
|
|
for i = 1, GetNumFriends() do
|
|
name, level, class = GetFriendInfo(i)
|
|
class = L["class"][class] or nil
|
|
-- friendlist updates due to friend going off-line return level 0, let's not overwrite good older values
|
|
level = level > 0 and level or nil
|
|
AddData("players", name, class, level)
|
|
end
|
|
|
|
elseif event == "GUILD_ROSTER_UPDATE" then
|
|
local name, class, level, _, guild
|
|
for i = 1, GetNumGuildMembers() do
|
|
name, _, _, level, class = GetGuildRosterInfo(i)
|
|
guild = GetGuildInfo("player")
|
|
class = L["class"][class] or nil
|
|
AddData("players", name, class, level, nil, guild)
|
|
end
|
|
|
|
elseif event == "RAID_ROSTER_UPDATE" then
|
|
local name, class, SubGroup, level, unit, _
|
|
for i = 1, GetNumRaidMembers() do
|
|
unit = "raid" .. i
|
|
name, _, SubGroup, level, class = GetRaidRosterInfo(i)
|
|
class = L["class"][class] or nil
|
|
AddData("players", name, class, level)
|
|
RememberByUnit(unit, name, class)
|
|
end
|
|
|
|
elseif event == "PARTY_MEMBERS_CHANGED" then
|
|
local name, class, level, unit, _, guild
|
|
for i = 1, GetNumPartyMembers() do
|
|
unit = "party" .. i
|
|
_, class = UnitClass(unit)
|
|
name = UnitName(unit)
|
|
level = UnitLevel(unit)
|
|
guild = GetGuildInfo(unit)
|
|
AddData("players", name, class, level, nil, guild)
|
|
RememberByUnit(unit, name, class)
|
|
end
|
|
|
|
elseif event == "WHO_LIST_UPDATE" or event == "CHAT_MSG_SYSTEM" then
|
|
local name, class, level, guild, _
|
|
for i = 1, GetNumWhoResults() do
|
|
name, guild, level, _, class, _ = GetWhoInfo(i)
|
|
class = L["class"][class] or nil
|
|
AddData("players", name, class, level, nil, guild)
|
|
end
|
|
|
|
elseif event == "UPDATE_MOUSEOVER_UNIT" or event == "PLAYER_TARGET_CHANGED" or event == "NAME_PLATE_UNIT_ADDED" then
|
|
local scan = event == "PLAYER_TARGET_CHANGED" and "target"
|
|
or event == "NAME_PLATE_UNIT_ADDED" and arg1
|
|
or "mouseover"
|
|
local name, class, level, elite, guild, _
|
|
if UnitIsPlayer(scan) then
|
|
_, class = UnitClass(scan)
|
|
level = UnitLevel(scan)
|
|
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
|
|
level = level > 0 and level or nil
|
|
name = UnitName(scan)
|
|
guild = GetGuildInfo(scan)
|
|
AddData("players", name, class, level, nil, guild)
|
|
RememberByUnit(scan, name, class)
|
|
else
|
|
_, class = UnitClass(scan)
|
|
elite = UnitClassification(scan)
|
|
level = UnitLevel(scan)
|
|
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
|
|
level = level > 0 and level or nil
|
|
name = UnitName(scan)
|
|
guild = UnitSubName(scan)
|
|
AddData("mobs", name, class, level, elite, guild)
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- setup sound function switches
|
|
local SoundOn = PlaySound
|
|
local SoundOff = function() return end
|
|
|
|
libunitscan:SetScript("OnUpdate", function()
|
|
-- don't scan when another unit is in target
|
|
if UnitExists("target") or UnitName("target") then return end
|
|
|
|
local name = next(queue)
|
|
if name then
|
|
-- disable sound
|
|
_G.PlaySound = SoundOff
|
|
|
|
-- try to target the unknown unit
|
|
TargetByName(name, true)
|
|
ClearTarget()
|
|
|
|
-- enable sound again
|
|
_G.PlaySound = SoundOn
|
|
|
|
queue[name] = nil
|
|
end
|
|
|
|
this:Hide()
|
|
end)
|
|
|
|
pfUI.api.libunitscan = libunitscan
|