Thread Tools Display Modes
07/30/21, 08:35 AM   #1
rosalith
Join Date: Jun 2021
Posts: 3
Help with first addon!

Hi I wrote a small addon that pretty much works as intended but theres an annoying bug that I can't figure out.

What the addon does is hides the target bar at the top of the screen only for certain creatures. The bug is that when I am looking at one of said creatures (and target bar is hidden correctly) and then look staright at someone else whose targetbar I DO want to see like an enemy or player, then that will be hidden too initially. You have to look away so that the is no target at all first.

Here is my entire code, if I made any daft mistakes pls be gentle I have no idea what I'm doing!

Lua Code:
  1. HideCritterHealthbar = {}
  2.  
  3. HideCritterHealthbar.name = "HideCritterHealthbar"
  4.  
  5. function HideCritterHealthbar.OnAddOnLoaded(event, addonName)
  6.     if addonName == HideCritterHealthbar.name then
  7.         HideCritterHealthbar:Initialize()
  8.     end
  9. end
  10.  
  11. function HideCritterHealthbar:Initialize()
  12.     EVENT_MANAGER:RegisterForEvent(self.name, EVENT_RETICLE_TARGET_CHANGED, self.Main)
  13.     EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_ADD_ON_LOADED)
  14. end
  15.  
  16. -- main function that runs every time target changes
  17. function HideCritterHealthbar.Main(event)
  18.     local rName = GetUnitName("reticleover")
  19.     local rReaction = GetUnitReaction("reticleover")
  20.     local rIsCritter
  21.  
  22.     if (rReaction == 2 or rReaction == 3 or rReaction == 5) then
  23.         if (rName == "Beetle" or
  24.         rName == "Butterfly" or
  25.         rName == "Rat") then
  26. -- ^ I cut down that list so that its neater here, longer in the real code
  27.  
  28.             rIsCritter = true
  29.         else
  30.             rIsCritter = false
  31.         end
  32.     else
  33.         rIsCritter = false
  34.     end
  35.  
  36.     UNIT_FRAMES:SetFrameHiddenForReason("reticleover", "disabled", rIsCritter)
  37.     ZO_UnitFrames_UpdateWindow("reticleover", true)
  38. end
  39.  
  40. EVENT_MANAGER:RegisterForEvent(HideCritterHealthbar.name, EVENT_ADD_ON_LOADED, HideCritterHealthbar.OnAddOnLoaded)
  Reply With Quote
07/30/21, 10:05 AM   #2
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
hi and welcome,

first of all you should unregister the event_add_on_loaded again as your addon was found as it is run for each addon and library once and does not need to do your checks for each of the addons then anymore if yours was already found:
In your case this is no big problem but one should just understand that and unregister events again if not needed anymore -> could/may increase performance and loading screens in total above all addons.
Lua Code:
  1. function HideCritterHealthbar.OnAddOnLoaded(event, addonName)
  2.     if addonName == HideCritterHealthbar.name then
  3.         EVENT_MANAGER:UnregisterForEvent(HideCritterHealthbar.name, EVENT_ADD_ON_LOADED)
  4.         HideCritterHealthbar:Initialize()
  5.     end
  6. end

2nd:
Stick to 1 usage of the notation . or : !

function HideCritterHealthbar.OnAddOnLoaded(event, addonName)
function HideCritterHealthbar:Initialize()

You should not use the : if your addon is not using any kinf of object oriented approach using classes and objects.
As this is imply a function rename it to function HideCritterHealthbar.Initialize and also rename the call to it to use the . and do not use the : if not needed. Some example tutorials still use it and you can do like you want, but in the end it somehow disturbs the eye as one expects HideCritterHealthbar to be an object of ZO_Object or a subclass of something that way (which uses the variable "self" to point to it's own object).

You are using the 2self" pointer inside that line e.g. via self.main to point to the function HideCritterHealthbar.Main
EVENT_MANAGER:RegisterForEvent(self.name, EVENT_RETICLE_TARGET_CHANGED, self.Main)
-> Change that to EVENT_MANAGER:RegisterForEvent(self.name, EVENT_RETICLE_TARGET_CHANGED, HideCritterHealthbar.Main)
Else self could not work properly as you did not define HideCritterHealthbar as subcalss of ZO_Object.
Also change self.name to HideCritterHealthbar.name

In total you should think about the laod order of lua, it will compile from top to bottom so variables defined below a function that tries to use it will be out of scope/nil.
As your variable HideCritterHealthbar isd efined global (means no local up in front -> so it will be available via _G["HideCritterHealthbar"] or simply HideCritterHealthbar) the load order does not matter. But if they would be local you would need to put the event_add_on_loaded at the bottom, initialization above it, main above this and so on so that they would be found properly.

Do not use the hardcoded values here if there exist constants to use:
Code:
if (rReaction == 2 or rReaction == 3 or rReaction == 5) then
The API function GetUnitReaction returns a value of type UnitReactionType whichc an all be found in the API ESOUIDocumentation_Pxx.txt files linked at the Wiki -> API versions.
The UnitReactionTypes can be:
Code:
h5. UnitReactionType
* UNIT_REACTION_COMPANION
* UNIT_REACTION_DEFAULT
* UNIT_REACTION_FRIENDLY
* UNIT_REACTION_HOSTILE
* UNIT_REACTION_NEUTRAL
* UNIT_REACTION_NPC_ALLY
* UNIT_REACTION_PLAYER_ALLY
So better to use those instead of 2 3 and so on! You can inspect teh values of teh constants via an addon like MerTorchbug or Zgoo ingame via chat commands like /tb UNIT_REACTION_DEFAULT or /zgoo UNIT_REACTION_DEFAULT It will output the value into chat then.
Or you can use mer Torchbug's UI so simply type /tb and let it load. Then at the global inspector choose the appropriate tab e.g. constants or functions and use the search at the top.
Here is a list of the constant = value
Code:
UNIT_REACTION_DEFAULT = 0
UNIT_REACTION_FRIENDLY = 3
UNIT_REACTION_HOSTILE = 1
UNIT_REACTION_NEUTRAL = 2
UNIT_REACTION_NPC_ALLY = 5
UNIT_REACTION_PLAYER_ALLY = 4

Currently trying to find the reason for your problem.
Maybe the event is called multiple times if you move the reticle, like first as you leave the critter below the crosshair and then as you move it above the other user/npc etc.

You culd add debug messages via
d("My Text: " .. tostring(variableName))
to see what variable got what value and which event is called how often etc.

Anyway this here would be my improved code for you, hope it helps to learn a bit. Most ist the same you had written in the code, just a bit improved.

Lua Code:
  1. HideCritterHealthbar = {}
  2.  
  3. HideCritterHealthbar.name = "HideCritterHealthbar"
  4. local myAddonName = HideCritterHealthbar.name -- Speed up variable
  5. local retOver = "reticleover" --Speed up variable
  6.  
  7. -- main function that runs every time target changes
  8. function HideCritterHealthbar.Main(event)
  9.     local rName = GetUnitName(retOver)
  10.     local rReaction = GetUnitReaction(retOver)
  11.     local rIsCritter = false --preset the variable wth false to prevent several if ...else...down below
  12.  
  13.     local reactionsToCheck = {
  14.         [UNIT_REACTION_NEUTRAL] = true,
  15.         [UNIT_REACTION_FRIENDLY] = true,
  16.         [UNIT_REACTION_NPC_ALLY] = true,
  17.     }
  18.     local namesToCheck = {
  19.         ["Beetle"] = true,
  20.         ["Butterfly"] = true,
  21.         Rat = true, --only a different notation possible for Strings. Either ["stringName"] or stringName directly
  22.     }
  23.  
  24.     --Easier / more performant way to check multiple values. Check if it is inside a table namesToCheck
  25.     --if tableName[variableName] will check if the variableName in tableName is ~= nil and if it is a boolean value if is == true
  26.     --If the variable is not of type boolean it will just check if it's inside the table via ~= nil
  27.     if reactionsToCheck[rReaction] and namesToCheck[rName] then
  28.         rIsCritter = true
  29.     end
  30.     --The 3 lines above can be written as 1 line as well:
  31.     --rIsCritter = (reactionsToCheck[rReaction] and namesToCheck[rName]) or false
  32.  
  33.     UNIT_FRAMES:SetFrameHiddenForReason(retOver, "disabled", rIsCritter)
  34.     ZO_UnitFrames_UpdateWindow(retOver, true)
  35. end
  36.  
  37. function HideCritterHealthbar.Initialize()
  38.     EVENT_MANAGER:RegisterForEvent(myAddonName, EVENT_RETICLE_TARGET_CHANGED, HideCritterHealthbar.Main)
  39.     EVENT_MANAGER:UnregisterForEvent(myAddonName, EVENT_ADD_ON_LOADED)
  40. end
  41.  
  42. function HideCritterHealthbar.OnAddOnLoaded(event, addonName)
  43.     if addonName == myAddonName then
  44.         EVENT_MANAGER:UnregisterForEvent(myAddonName, EVENT_ADD_ON_LOADED)
  45.         HideCritterHealthbar.Initialize()
  46.     end
  47. end
  48. EVENT_MANAGER:RegisterForEvent(myAddonName, EVENT_ADD_ON_LOADED, HideCritterHealthbar.OnAddOnLoaded)

Last edited by Baertram : 07/30/21 at 10:18 AM.
  Reply With Quote
07/30/21, 02:35 PM   #3
rosalith
Join Date: Jun 2021
Posts: 3
You're a star, thanks for taking the time to look at this! I knew there'd be some 'bad practise' things in there so, I appreciate that

I'm also noticing another bug now, sometimes the target bar appears faded which makes me think its somehow being caught mid-animation (fade in/out animation) and frozen there. I remember seeing somewhere a zos function that refreshed alpha level of unit frames... maybe that could help?
  Reply With Quote
07/31/21, 06:18 AM   #4
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Perhaps the update of the bars is done too often if you just respect each reticle change. You could see if the event fires even if your reticle stays on the same enemy/npc and you just move it, first. If that happens cache the last name of the unit below the reticle and check if it changes. If not do not call your code to update the bars. This should prevent some unneeded updates to the bars, but it's only a guess.

I have not worked with unit frames in the past so I do not know the function you refer to, sorry. Maybe another addon dev can help here.
  Reply With Quote
07/31/21, 07:09 AM   #5
rosalith
Join Date: Jun 2021
Posts: 3
I did check how often the event fires with the debug thing you mentioned, it fires once when you look at a target from nothing, and again if you look back to nothing. Looking from one target to another makes it fire only once, so it's not that often overall. it doesn't fire at all if you keep looking at one target, even if you move around.

I found the zos function it was DoAlphaUpdate but it didn't do anything....honestly tried so many weird things last night and this bug won't go away. Might just have to deal with it!
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Help with first addon!

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off