WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   General Authoring Discussion (https://www.wowinterface.com/forums/forumdisplay.php?f=20)
-   -   Class icons on nameplates (https://www.wowinterface.com/forums/showthread.php?t=56583)

Mitur 08-21-18 07:55 AM

Class icons on nameplates
 
Hi guys, first timer here!
Did some search on these forums and discovered a lot of useful information, you are really helpful bunch of people!
Trying to figure out the nameplate magics.
For practice I'm attempting to show class icons over the friendly nameplates.
After the initial loading things work well, but after I move my camera and nameplates get dynamically reassigned, icons tend to appear over wrong classes.
To narrow things down I've tried to restrict the icons to WARRIOR class only.
And it obviously didn't work as planned :)
https://imgur.com/G3UPLIx

Lua Code:
  1. local events = {
  2.     ["npu_added"] = "NAME_PLATE_UNIT_ADDED",
  3.     ["npu_removed"] = "NAME_PLATE_UNIT_REMOVED",
  4.     -- ["bg"] = "PLAYER_ENTERING_BATTLEGROUND",
  5.     -- ["gru"] = "GROUP_ROSTER_UPDATE",
  6.     -- ["ptc"] = "PLAYER_TARGET_CHANGED",
  7.     ["load"] = "ADDON_LOADED"
  8. }
  9. local icons = {
  10.     ["DEMONHUNTER"] = 236415,
  11.     ["DRUID"] = 625999,
  12.     ["HUNTER"] = 626000,
  13.     ["MAGE"] = 626001,
  14.     ["MONK"] = 626002,
  15.     ["PALADIN"] = 626003,
  16.     ["PRIEST"] = 626004,
  17.     ["ROGUE"] = 626005,
  18.     ["SHAMAN"] = 626006,
  19.     ["WARLOCK"] = 626007,
  20.     ["WARRIOR"] = 626008,
  21.     ["DEATHKNIGHT"] = 135771
  22. }
  23.  
  24. --[[ Potentially useful checks
  25.     UnitIsFriend(unit, otherUnit) comparing relationships between units
  26.     UnitIsPlayer(unit)
  27.     UnitInPArty(unit)
  28. ]]
  29.  
  30. local guidSet = {}
  31. local idSet = {}
  32.  
  33. local sdb = CreateFrame("Frame")
  34. local _G = _G
  35. local GetNamePlateForUnit = _G.C_NamePlate.GetNamePlateForUnit --get nameplate from global UI variable _G
  36.  
  37. local function addIcon(parentFrame, icon)
  38.     local iconFrame, iconTexture
  39.     iconFrame = CreateFrame("Frame", nil, parentFrame)
  40.     iconFrame:SetFrameStrata("BACKGROUND")
  41.     iconFrame:SetWidth(32)
  42.     iconFrame:SetHeight(32)
  43.  
  44.     iconTexture = iconFrame:CreateTexture(nil, "BACKGROUND")
  45.     iconTexture:SetTexture(icons[icon])
  46.     iconTexture:SetAllPoints(iconFrame)
  47.  
  48.     iconFrame.texture = iconTexture
  49.     iconFrame:SetPoint("TOPLEFT", 10, 10)
  50.     iconFrame:Show()
  51. end
  52.  
  53. local function removeIcon(parentFrame)
  54.     parentFrame:Hide()
  55. end
  56.  
  57. local function nameplateHandler(self, event, unit)
  58.     local namePlate = GetNamePlateForUnit(unit)
  59.     local unit_frame = namePlate.UnitFrame
  60.     local unitGUID = UnitGUID(unit)
  61.     local separator = ", "
  62.     local className, classId, raceName, raceId, gender, name, realm = GetPlayerInfoByGUID(unitGUID)
  63.     if event == events["npu_added"] then
  64.         if classId == "WARRIOR" and not idSet:contains(unit) then
  65.             print(name .. separator .. classId .. separator .. unit .. " added!")
  66.             idSet[unit] = name
  67.             addIcon(namePlate, classId)
  68.         end
  69.     elseif event == events["npu_removed"] and idSet:contains(unit) then
  70.         print("Was saved as " .. idSet[id])
  71.         print("Was removed as " .. name)
  72.         idSet:remove(unit)
  73.         removeIcon(namePlate)
  74.     end
  75. end
  76.  
  77. local function showFriendlyNameplates(self, event)
  78.     if event == events["load"] then
  79.         SetCVar("nameplateShowAll", 1)
  80.         SetCVar("nameplateShowFriends", 1)
  81.     end
  82. end
  83.  
  84. -- Utility functions
  85.  
  86. function guidSet:contains(key)
  87.     return self[key] ~= nil
  88. end
  89.  
  90. function idSet:contains(key)
  91.     return self[key] ~= nil
  92. end
  93.  
  94. function idSet:remove(key)
  95.     idSet[key] = nil
  96. end
  97.  
  98. -- Registering for a table of events
  99.  
  100. for k, v in pairs(events) do
  101.     sdb:RegisterEvent(v)
  102. end
  103. sdb:SetScript("OnEvent", nameplateHandler)
  104. -- sdb:SetScript("OnEvent", showFriendlyNameplates)

I feel that the removeIcon function is faulty as I don't know how to get to the frame I've created on top of the nameplate.
Maybe I have to gather all the frames I create in a table?
Or perhaps all the stuff I do is just plain wrong and there is a simpler way to accomplish this task that I don't see as a beginner.
Thank you very much for taking your time to read this and for any hints and advice!

Vrul 08-21-18 09:38 AM

I see a few things that I think are wrong but I'm not sure since you reference things not in the posted code. Post ALL of your code.

Ammako 08-21-18 09:59 AM

You're running :Hide() on the nameplate itself, why?
The nameplate already disappears when unit is removed, that part is redundant, and you're not actually hiding the iconframe. Meaning, once the nameplate gets reassigned to a different unit, it is still anchored to it and will still appear, even if the character is of the wrong class.

[I wrote a thing here that I realized would not work, edited out]

Also, not related to the functionality of your code, but you are creating a new frame every time a nameplate appears. You should only create one per nameplate. Efficiency reasons.

Mitur 08-21-18 10:30 AM

Quote:

Originally Posted by Vrul (Post 329744)
I see a few things that I think are wrong but I'm not sure since you reference things not in the posted code. Post ALL of your code.

I only omitted things like table creation (icons table for example), and obvious stuff like event registration etc. Main logic is contained within the code I posted.

Quote:

Originally Posted by Ammako (Post 329745)
You're running :Hide() on the nameplate itself, why?
The nameplate already disappears when unit is removed, that part is redundant, and you're not actually hiding the iconframe. Meaning, once the nameplate gets reassigned to a different unit, it is still anchored to it and will still appear, even if the character is of the wrong class.

[I wrote a thing here that I realized would not work, edited out]

Also, not related to the functionality of your code, but you are creating a new frame every time a nameplate appears. You should only create one per nameplate. Efficiency reasons.

Thanks for explaining the Hide() part, I just don't know how to get the reference to the Frame that I created to hide it properly.
And you're right about the efficiency part for sure.
I should somehow check if the nameplate already contains my Frame. If only I knew how to manage the nameplates properly :p

Vrul 08-21-18 10:47 AM

Quote:

Originally Posted by Mitur (Post 329746)
I only omitted things like table creation (icons table for example), and obvious stuff like event registration etc. Main logic is contained within the code I posted.

Not really.
Code:

    if event == events["npu_added"] and not idSet:contains(unit) then
Without knowing what is going on in idSet:contains(unit) I have no idea if that logic branch is correct. I believe that part to be unnecessary but I have no way to be sure. I also don't know if you have the correct events in your table (or why you abstract them that way instead of just putting the event name there).

Code:

    elseif event == events["npu_removed"] and idSet:contains(id) then
        idSet:remove(id)

Same issues as above and also what does idSet:remove(id) do? What does "id" even reference and where is it set? Is it supposed to be "unit" instead or is there something going on in the code not posted.

In short post ALL of your code if you want help.

Ammako 08-21-18 11:15 AM

Quote:

Originally Posted by Mitur (Post 329746)
I only omitted things like table creation (icons table for example), and obvious stuff like event registration etc. Main logic is contained within the code I posted.

You should still post your whole code, rule of thumb. You may know what seems important or not, but to the people reading, we don't know what else is there so there's no way for anyone to know.

Quote:

Originally Posted by Mitur (Post 329746)
Thanks for explaining the Hide() part, I just don't know how to get the reference to the Frame that I created to hide it properly.
And you're right about the efficiency part for sure.
I should somehow check if the nameplate already contains my Frame. If only I knew how to manage the nameplates properly :p

iconFrame is local to your addIcon function, you'll have a hard time accessing it from anywhere else.

You could declare iconFrame inside nameplateHandler, and pass it as an argument to addIcon and removeIcon. Ideally, you'd probably do this differently as a whole, but see if that works to begin with.

The way nameplates work, there is a finite amount of nameplates, and they are recycled as units appear and disappear. Nameplates aren't unique to the unit.If NamePlate1 gets assigned to a Warrior player character, and that character either dies or moves out of sight, NamePlate1 will get re-assigned to a different unit later on. If you modify that nameplate, the modifications will still be in place when it reappears later with a different unit assigned to it. So that has to be kept in mind.

Also, I could be wrong about the multiple frames per nameplate thing, but from my understanding, iconFrame being local to addIcon function, a new instance of it is created every time the function gets called, and references to it are lost once the function exits. Anyone feel free to let me know if that's wrong :p

Mitur 08-22-18 02:42 AM

Thank you guys for pointing out my mistakes, I appreciate it very much!
I've updated my original post with the full code.
@Vrul - sorry for the "id" variable, it got mixed up when I decided to rename the argument to "unit" for better readability and missed some occurrences.

Vrul 08-22-18 07:17 AM

Code:

local addonName = ...

local iconKey = addonName .. "Icon"

local GetNamePlateForUnit = C_NamePlate.GetNamePlateForUnit

local iconTexture = {
    ["DEATHKNIGHT"] = 135771,
    ["DEMONHUNTER"] = 236415,
    ["DRUID"] = 625999,
    ["HUNTER"] = 626000,
    ["MAGE"] = 626001,
    ["MONK"] = 626002,
    ["PALADIN"] = 626003,
    ["PRIEST"] = 626004,
    ["ROGUE"] = 626005,
    ["SHAMAN"] = 626006,
    ["WARLOCK"] = 626007,
    ["WARRIOR"] = 626008
}

local frame = CreateFrame("Frame")
 
frame:SetScript("OnEvent", function(self, event, unit)
    local namePlate = GetNamePlateForUnit(unit)
    if event == "NAME_PLATE_UNIT_ADDED" and UnitIsFriend("player", unit) then
        local _, class = UnitClass(unit)
        if iconTexture[class] then
            local icon = namePlate[iconKey]
            if not icon then
                icon = namePlate:CreateTexture(nil, "OVERLAY")
                icon:SetPoint('TOPLEFT', 10, 10)
                icon:SetSize(32, 32)
                namePlate[iconKey] = icon
            end
            icon:SetTexture(iconTexture[class])
            icon:Show()
            return
        end
    end
    if namePlate[iconKey] then
        namePlate[iconKey]:Hide()
    end
end)

frame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
frame:RegisterEvent("NAME_PLATE_UNIT_REMOVED")


Mitur 08-22-18 07:30 AM

Quote:

Originally Posted by Vrul (Post 329760)
Lua Code:
  1. -- awesome clean code

Man...
Can't thank you enough for providing me with this crisp, minimalistic example.
Tested it already and it works just fine.
And I've learned a lot, thank you! :)


All times are GMT -6. The time now is 05:49 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI