mirror of
https://github.com/brues-code/pfUI.git
synced 2026-11-05 18:18:57 +00:00
Read nameplate units directly instead of scanning by name
This commit is contained in:
+42
-101
@@ -2,37 +2,26 @@
|
|||||||
setfenv(1, pfUI:GetEnvironment())
|
setfenv(1, pfUI:GetEnvironment())
|
||||||
|
|
||||||
--[[ libunitscan ]]--
|
--[[ libunitscan ]]--
|
||||||
-- A pfUI library that detects and saves all kind of unit related informations.
|
-- A pfUI library that remembers the class, level and guild of every player it
|
||||||
-- Such as level, class, elite-state and playertype. Each query causes the library
|
-- sees: in the friends, guild, raid and party rosters, in /who results, and as
|
||||||
-- to automatically scan for the target if not already existing. Player-data is
|
-- target, mouseover or nameplate. The data is persisted within pfUI_playerDB,
|
||||||
-- persisted within the pfUI_playerDB where the mob data is a throw-away table.
|
-- for the places that only have a player's name, such as chat links and
|
||||||
-- The automatic target scanner is only working for vanilla due to client limitations
|
-- offline friends. Anything with a unit reads the unit itself instead.
|
||||||
-- on further expansions.
|
|
||||||
--
|
--
|
||||||
-- External functions:
|
-- External functions:
|
||||||
-- GetUnitInfo(name, active, isPlayer)
|
-- GetUnitInfo(name)
|
||||||
-- Returns information of the given unitname. Returns nil if no match is found.
|
-- Returns information of the given player name. Returns nil if the player
|
||||||
-- When nothing is found and the active flag is set, the autoscanner will
|
-- was never seen.
|
||||||
-- 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
|
-- class[String] - The class of the player
|
||||||
-- level[Number] - The level of the unit
|
-- level[Number] - The level of the player
|
||||||
-- elite[String] - The elite state of the unit (See UnitClassification())
|
-- guild[String] - The guild name of the player
|
||||||
-- 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
|
-- return instantly when another libunitscan is already active
|
||||||
if pfUI.api.libunitscan then return end
|
if pfUI.api.libunitscan then return end
|
||||||
|
|
||||||
local units = { players = {}, mobs = {} }
|
local players = {}
|
||||||
local queue = { }
|
|
||||||
|
|
||||||
-- Feed (guid, name, classToken) into ClassicAPI's persistent name
|
-- Feed (guid, name, classToken) into ClassicAPI's persistent name
|
||||||
-- cache when the unit's GUID is resolvable. Roster-style packets
|
-- 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))
|
C_PlayerCache.RememberPlayer(guid, name, class, UnitRace(unit), UnitSex(unit))
|
||||||
end
|
end
|
||||||
|
|
||||||
function GetUnitInfo(name, active, isPlayer)
|
function GetUnitInfo(name)
|
||||||
if isPlayer ~= false and units["players"][name] then
|
local ret = players[name]
|
||||||
local ret = units["players"][name]
|
if ret then
|
||||||
return ret.class, ret.level, ret.elite, true, ret.guild
|
return ret.class, ret.level, 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
|
||||||
end
|
end
|
||||||
|
|
||||||
local function AddData(db, name, class, level, elite, guild)
|
local function AddData(name, class, level, guild)
|
||||||
if not name or not db then return end
|
if not name then return end
|
||||||
units[db] = units[db] or {}
|
players[name] = players[name] or {}
|
||||||
units[db][name] = units[db][name] or {}
|
players[name].class = class or players[name].class
|
||||||
units[db][name].class = class or units[db][name].class
|
players[name].level = level or players[name].level
|
||||||
units[db][name].level = level or units[db][name].level
|
players[name].guild = guild or players[name].guild
|
||||||
units[db][name].elite = elite or units[db][name].elite
|
|
||||||
units[db][name].guild = guild or units[db][name].guild
|
|
||||||
queue[name] = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local libunitscan = CreateFrame("Frame", "pfUnitScan", UIParent)
|
local libunitscan = CreateFrame("Frame", "pfUnitScan", UIParent)
|
||||||
@@ -85,14 +65,14 @@ libunitscan:SetScript("OnEvent", function()
|
|||||||
if event == "PLAYER_ENTERING_WORLD" then
|
if event == "PLAYER_ENTERING_WORLD" then
|
||||||
|
|
||||||
-- load pfUI_playerDB
|
-- load pfUI_playerDB
|
||||||
units.players = pfUI_playerDB
|
players = pfUI_playerDB
|
||||||
|
|
||||||
-- update own character details
|
-- update own character details
|
||||||
local name = UnitName("player")
|
local name = UnitName("player")
|
||||||
local class = UnitClassBase("player")
|
local class = UnitClassBase("player")
|
||||||
local level = UnitLevel("player")
|
local level = UnitLevel("player")
|
||||||
local guild = GetGuildInfo("player")
|
local guild = GetGuildInfo("player")
|
||||||
AddData("players", name, class, level, nil, guild)
|
AddData(name, class, level, guild)
|
||||||
RememberByUnit("player", name, class)
|
RememberByUnit("player", name, class)
|
||||||
|
|
||||||
elseif event == "FRIENDLIST_UPDATE" then
|
elseif event == "FRIENDLIST_UPDATE" then
|
||||||
@@ -100,38 +80,38 @@ libunitscan:SetScript("OnEvent", function()
|
|||||||
local info = C_FriendList.GetFriendInfoByIndex(i)
|
local info = C_FriendList.GetFriendInfoByIndex(i)
|
||||||
if info then
|
if info then
|
||||||
local level = info.level > 0 and info.level or nil
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "GUILD_ROSTER_UPDATE" then
|
elseif event == "GUILD_ROSTER_UPDATE" then
|
||||||
local name, class, level, _, guild
|
local guild = GetGuildInfo("player")
|
||||||
|
local name, class, level, _
|
||||||
for i = 1, GetNumGuildMembers() do
|
for i = 1, GetNumGuildMembers() do
|
||||||
name, _, _, level, class = GetGuildRosterInfo(i)
|
name, _, _, level, class = GetGuildRosterInfo(i)
|
||||||
guild = GetGuildInfo("player")
|
|
||||||
class = L["class"][class] or nil
|
class = L["class"][class] or nil
|
||||||
AddData("players", name, class, level, nil, guild)
|
AddData(name, class, level, guild)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "RAID_ROSTER_UPDATE" then
|
elseif event == "RAID_ROSTER_UPDATE" then
|
||||||
local name, class, SubGroup, level, unit, _
|
local name, class, level, unit, _
|
||||||
for i = 1, GetNumRaidMembers() do
|
for i = 1, GetNumRaidMembers() do
|
||||||
unit = "raid" .. i
|
unit = "raid" .. i
|
||||||
name, _, SubGroup, level, class = GetRaidRosterInfo(i)
|
name, _, _, level, class = GetRaidRosterInfo(i)
|
||||||
class = L["class"][class] or nil
|
class = L["class"][class] or nil
|
||||||
AddData("players", name, class, level)
|
AddData(name, class, level)
|
||||||
RememberByUnit(unit, name, class)
|
RememberByUnit(unit, name, class)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "PARTY_MEMBERS_CHANGED" then
|
elseif event == "PARTY_MEMBERS_CHANGED" then
|
||||||
local name, class, level, unit, _, guild
|
local name, class, level, unit, guild
|
||||||
for i = 1, GetNumPartyMembers() do
|
for i = 1, GetNumPartyMembers() do
|
||||||
unit = "party" .. i
|
unit = "party" .. i
|
||||||
class = UnitClassBase(unit)
|
class = UnitClassBase(unit)
|
||||||
name = UnitName(unit)
|
name = UnitName(unit)
|
||||||
level = UnitLevel(unit)
|
level = UnitLevel(unit)
|
||||||
guild = GetGuildInfo(unit)
|
guild = GetGuildInfo(unit)
|
||||||
AddData("players", name, class, level, nil, guild)
|
AddData(name, class, level, guild)
|
||||||
RememberByUnit(unit, name, class)
|
RememberByUnit(unit, name, class)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -139,7 +119,7 @@ libunitscan:SetScript("OnEvent", function()
|
|||||||
for i = 1, C_FriendList.GetNumWhoResults() do
|
for i = 1, C_FriendList.GetNumWhoResults() do
|
||||||
local info = C_FriendList.GetWhoInfo(i)
|
local info = C_FriendList.GetWhoInfo(i)
|
||||||
if info then
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -147,55 +127,16 @@ libunitscan:SetScript("OnEvent", function()
|
|||||||
local scan = event == "PLAYER_TARGET_CHANGED" and "target"
|
local scan = event == "PLAYER_TARGET_CHANGED" and "target"
|
||||||
or event == "NAME_PLATE_UNIT_ADDED" and arg1
|
or event == "NAME_PLATE_UNIT_ADDED" and arg1
|
||||||
or "mouseover"
|
or "mouseover"
|
||||||
local name, class, level, elite, guild, _
|
if UnitIsPlayer(scan) then
|
||||||
if UnitExists(scan) then
|
local name = UnitName(scan)
|
||||||
if UnitIsPlayer(scan) then
|
local class = UnitClassBase(scan)
|
||||||
class = UnitClassBase(scan)
|
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
|
||||||
level = UnitLevel(scan)
|
local level = UnitLevel(scan)
|
||||||
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
|
level = level > 0 and level or nil
|
||||||
level = level > 0 and level or nil
|
AddData(name, class, level, GetGuildInfo(scan))
|
||||||
name = UnitName(scan)
|
RememberByUnit(scan, name, class)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
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
|
pfUI.api.libunitscan = libunitscan
|
||||||
|
|||||||
+4
-1
@@ -59,7 +59,10 @@ pfUI:RegisterModule("afkcam", function ()
|
|||||||
if not this:IsVisible() then return end
|
if not this:IsVisible() then return end
|
||||||
local info = _G.ChatTypeInfo[string.gsub(event,"CHAT_MSG_","")]
|
local info = _G.ChatTypeInfo[string.gsub(event,"CHAT_MSG_","")]
|
||||||
if not info then return end
|
if not info then return end
|
||||||
local class = GetUnitInfo(arg2 or "")
|
-- the engine name-queries a chat sender before the event fires, so the
|
||||||
|
-- sender's GUID (arg12) always resolves
|
||||||
|
local _, class
|
||||||
|
if arg12 and arg12 ~= "" then _, class = GetPlayerInfoByGUID(arg12) end
|
||||||
local author, msg
|
local author, msg
|
||||||
if class and class ~= UNKNOWN then
|
if class and class ~= UNKNOWN then
|
||||||
local class_color = PFUI_CLASS_COLORS[class]:GenerateHexColorMarkup()
|
local class_color = PFUI_CLASS_COLORS[class]:GenerateHexColorMarkup()
|
||||||
|
|||||||
+17
-36
@@ -1040,9 +1040,7 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
|||||||
local level = plate.original.level:IsShown() and plate.original.level:GetObjectType() == "FontString" and tonumber(plate.original.level:GetText()) or "??"
|
local level = plate.original.level:IsShown() and plate.original.level:GetObjectType() == "FontString" and tonumber(plate.original.level:GetText()) or "??"
|
||||||
|
|
||||||
-- reset per-unit cache when the plate is reassigned. Gate on GUID *and*
|
-- reset per-unit cache when the plate is reassigned. Gate on GUID *and*
|
||||||
-- name — name alone misses pool reuse between same-named units (e.g. plate
|
-- name — name alone misses pool reuse between same-named units.
|
||||||
-- held a player "Ironforge Guard" and is now reassigned to the NPC by the
|
|
||||||
-- same name), which would leak a stale "PLAYER" hint into GetUnitInfo.
|
|
||||||
-- Wipe the whole cache table: the PERF gates below ("only update X when
|
-- Wipe the whole cache table: the PERF gates below ("only update X when
|
||||||
-- X changed") would otherwise skip bar/color/text updates when the new
|
-- X changed") would otherwise skip bar/color/text updates when the new
|
||||||
-- unit happens to share a cached value with the previous occupant
|
-- unit happens to share a cached value with the previous occupant
|
||||||
@@ -1065,27 +1063,26 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
|||||||
if event == "PLAYER_TARGET_CHANGED" then unitstr = nil end
|
if event == "PLAYER_TARGET_CHANGED" then unitstr = nil end
|
||||||
|
|
||||||
-- remove unitstr when it doesn't resolve to this plate's unit (stale istarget,
|
-- remove unitstr when it doesn't resolve to this plate's unit (stale istarget,
|
||||||
-- stale mouseover guid or a despawned unit). Must run before the cache fills
|
-- stale mouseover guid or a despawned unit)
|
||||||
-- below -- an unrelated unitstr would poison cache.player/minion with the
|
|
||||||
-- *other* unit's answer, and the nil-gate would then never recompute it.
|
|
||||||
if unitstr and UnitName(unitstr) ~= name then unitstr = nil end
|
if unitstr and UnitName(unitstr) ~= name then unitstr = nil end
|
||||||
|
|
||||||
-- resolve player vs npc from plate's own unit so libunitscan can't return
|
-- the plate's own unit token says who it is; a player too high to show a
|
||||||
-- a player record for an NPC sharing the same name (e.g. Chromie). Stored
|
-- level keeps the one the player database last saw
|
||||||
-- as true/false/nil so it doubles as the GetUnitInfo hint.
|
local unit = plate.unit
|
||||||
if plate.cache.player == nil and unitstr then
|
local player, class, elite, guild, ulevel
|
||||||
plate.cache.player = UnitIsPlayer(unitstr) and true or false
|
if unit then
|
||||||
|
player = UnitIsPlayer(unit)
|
||||||
|
class = player and UnitClassBase(unit)
|
||||||
|
elite = UnitClassification(unit)
|
||||||
|
guild = player and GetGuildInfo(unit) or UnitSubName(unit)
|
||||||
|
ulevel = UnitLevel(unit)
|
||||||
|
if player and ulevel <= 0 then
|
||||||
|
local _
|
||||||
|
_, ulevel = GetUnitInfo(name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if plate.cache.minion == nil and unitstr then
|
|
||||||
plate.cache.minion = UnitIsMinion(unitstr) and true or false
|
|
||||||
end
|
|
||||||
local class, ulevel, elite, player, guild
|
|
||||||
if not plate.cache.minion then
|
|
||||||
class, ulevel, elite, player, guild = GetUnitInfo(name, true, plate.cache.player)
|
|
||||||
end
|
|
||||||
if plate.cache.player ~= nil then player = plate.cache.player or nil end
|
|
||||||
|
|
||||||
-- Use database level ONLY if current level is ?? (fixes ?? after reload, but doesn't override visible levels)
|
-- Use the unit's level ONLY if current level is ?? (fixes ?? after reload, but doesn't override visible levels)
|
||||||
local levelFromDB = false
|
local levelFromDB = false
|
||||||
if level == "??" and ulevel and ulevel > 0 then
|
if level == "??" and ulevel and ulevel > 0 then
|
||||||
level = ulevel
|
level = ulevel
|
||||||
@@ -1095,13 +1092,9 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
|||||||
local unittype = GetUnitType(plate)
|
local unittype = GetUnitType(plate)
|
||||||
local font_size = C.nameplates.use_unitfonts == "1" and C.global.font_unit_size or C.global.font_size
|
local font_size = C.nameplates.use_unitfonts == "1" and C.global.font_unit_size or C.global.font_size
|
||||||
|
|
||||||
-- ignore players with npc names if plate level is lower than player level
|
|
||||||
if ulevel and ulevel > (level == "??" and -1 or level) then player = nil end
|
|
||||||
|
|
||||||
if player and unittype == "ENEMY_NPC" then unittype = "ENEMY_PLAYER" end
|
if player and unittype == "ENEMY_NPC" then unittype = "ENEMY_PLAYER" end
|
||||||
if player and unittype == "FRIENDLY_NPC" then unittype = "FRIENDLY_PLAYER" end
|
if player and unittype == "FRIENDLY_NPC" then unittype = "FRIENDLY_PLAYER" end
|
||||||
elite = plate.original.levelicon:IsShown() and not player and "boss" or elite
|
elite = plate.original.levelicon:IsShown() and not player and "boss" or elite
|
||||||
if not class and not plate.cache.minion then plate.wait_for_scan = true end
|
|
||||||
|
|
||||||
-- skip data updates on invisible frames
|
-- skip data updates on invisible frames
|
||||||
if not visible then return end
|
if not visible then return end
|
||||||
@@ -1219,7 +1212,6 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
|||||||
|
|
||||||
if cfg.showhp then
|
if cfg.showhp then
|
||||||
local rhp, rhpmax, estimated
|
local rhp, rhpmax, estimated
|
||||||
local unit = plate.unit
|
|
||||||
if unit then
|
if unit then
|
||||||
local npHp = UnitHealth(unit)
|
local npHp = UnitHealth(unit)
|
||||||
local npMaxHp = UnitHealthMax(unit)
|
local npMaxHp = UnitHealthMax(unit)
|
||||||
@@ -1491,7 +1483,6 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
|||||||
|
|
||||||
local update
|
local update
|
||||||
local original = nameplate.original
|
local original = nameplate.original
|
||||||
local name = original.name:GetText()
|
|
||||||
local mouseover = nameplate.cachedGuid and nameplate.cachedGuid == frameState.mouseoverGuid or nil
|
local mouseover = nameplate.cachedGuid and nameplate.cachedGuid == frameState.mouseoverGuid or nil
|
||||||
|
|
||||||
-- trigger queued event update
|
-- trigger queued event update
|
||||||
@@ -1575,16 +1566,6 @@ nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focu
|
|||||||
update = true
|
update = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- trigger update when unit was found. Pass the cached player hint so the
|
|
||||||
-- retry probes the same table OnDataChanged will read on the next pass —
|
|
||||||
-- otherwise an NPC sharing a name with a known player flips wait_for_scan
|
|
||||||
-- off here, then OnDataChanged re-sets it, every frame until the mob scan
|
|
||||||
-- lands.
|
|
||||||
if nameplate.wait_for_scan and not nameplate.cache.minion and GetUnitInfo(name, true, nameplate.cache.player) then
|
|
||||||
nameplate.wait_for_scan = nil
|
|
||||||
update = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- trigger update when name color changed (includes combat state check).
|
-- trigger update when name color changed (includes combat state check).
|
||||||
-- Skipped once OnDataChanged owns the name colour (class-coloured friendly
|
-- Skipped once OnDataChanged owns the name colour (class-coloured friendly
|
||||||
-- players), so the two writers cannot overwrite each other.
|
-- players), so the two writers cannot overwrite each other.
|
||||||
|
|||||||
Reference in New Issue
Block a user