Read nameplate units directly instead of scanning by name

This commit is contained in:
Brues
2026-10-31 15:08:39 -05:00
parent f81ea09d1c
commit e43ddd31fd
3 changed files with 63 additions and 138 deletions
+42 -101
View File
@@ -2,37 +2,26 @@
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.
-- A pfUI library that remembers the class, level and guild of every player it
-- sees: in the friends, guild, raid and party rosters, in /who results, and as
-- target, mouseover or nameplate. The data is persisted within pfUI_playerDB,
-- for the places that only have a player's name, such as chat links and
-- offline friends. Anything with a unit reads the unit itself instead.
--
-- 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).
-- GetUnitInfo(name)
-- Returns information of the given player name. Returns nil if the player
-- was never seen.
--
-- 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"
-- class[String] - The class of the player
-- level[Number] - The level of the player
-- guild[String] - The guild name of the player
--
-- return instantly when another libunitscan is already active
if pfUI.api.libunitscan then return end
local units = { players = {}, mobs = {} }
local queue = { }
local players = {}
-- Feed (guid, name, classToken) into ClassicAPI's persistent name
-- cache when the unit's GUID is resolvable. Roster-style packets
@@ -46,28 +35,19 @@ local function RememberByUnit(unit, name, class)
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()
function GetUnitInfo(name)
local ret = players[name]
if ret then
return ret.class, ret.level, ret.guild
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
local function AddData(name, class, level, guild)
if not name then return end
players[name] = players[name] or {}
players[name].class = class or players[name].class
players[name].level = level or players[name].level
players[name].guild = guild or players[name].guild
end
local libunitscan = CreateFrame("Frame", "pfUnitScan", UIParent)
@@ -85,14 +65,14 @@ libunitscan:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" then
-- load pfUI_playerDB
units.players = pfUI_playerDB
players = pfUI_playerDB
-- update own character details
local name = UnitName("player")
local class = UnitClassBase("player")
local level = UnitLevel("player")
local guild = GetGuildInfo("player")
AddData("players", name, class, level, nil, guild)
AddData(name, class, level, guild)
RememberByUnit("player", name, class)
elseif event == "FRIENDLIST_UPDATE" then
@@ -100,38 +80,38 @@ libunitscan:SetScript("OnEvent", function()
local info = C_FriendList.GetFriendInfoByIndex(i)
if info then
local level = info.level > 0 and info.level or nil
AddData("players", info.name, info.classFilename, level)
AddData(info.name, info.classFilename, level)
end
end
elseif event == "GUILD_ROSTER_UPDATE" then
local name, class, level, _, guild
local guild = GetGuildInfo("player")
local name, class, level, _
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)
AddData(name, class, level, guild)
end
elseif event == "RAID_ROSTER_UPDATE" then
local name, class, SubGroup, level, unit, _
local name, class, level, unit, _
for i = 1, GetNumRaidMembers() do
unit = "raid" .. i
name, _, SubGroup, level, class = GetRaidRosterInfo(i)
name, _, _, level, class = GetRaidRosterInfo(i)
class = L["class"][class] or nil
AddData("players", name, class, level)
AddData(name, class, level)
RememberByUnit(unit, name, class)
end
elseif event == "PARTY_MEMBERS_CHANGED" then
local name, class, level, unit, _, guild
local name, class, level, unit, guild
for i = 1, GetNumPartyMembers() do
unit = "party" .. i
class = UnitClassBase(unit)
name = UnitName(unit)
level = UnitLevel(unit)
guild = GetGuildInfo(unit)
AddData("players", name, class, level, nil, guild)
AddData(name, class, level, guild)
RememberByUnit(unit, name, class)
end
@@ -139,7 +119,7 @@ libunitscan:SetScript("OnEvent", function()
for i = 1, C_FriendList.GetNumWhoResults() do
local info = C_FriendList.GetWhoInfo(i)
if info then
AddData("players", info.fullName, info.filename, info.level, nil, info.fullGuildName)
AddData(info.fullName, info.filename, info.level, info.fullGuildName)
end
end
@@ -147,55 +127,16 @@ libunitscan:SetScript("OnEvent", function()
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 UnitExists(scan) then
if UnitIsPlayer(scan) then
class = UnitClassBase(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 = UnitClassBase(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
if UnitIsPlayer(scan) then
local name = UnitName(scan)
local class = UnitClassBase(scan)
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
local level = UnitLevel(scan)
level = level > 0 and level or nil
AddData(name, class, level, GetGuildInfo(scan))
RememberByUnit(scan, name, class)
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