Thread Tools Display Modes
03-08-14, 03:27 AM   #1
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
Help with a table issue

Ok so, here's my good old nameplates addon

http://pastebin.com/ATJTK2VN

Now here's my threat oUF module

http://pastebin.com/ghNQfx5k

I don't want to use the default nameplates threat coloring instead, i want to use my own. So, i feed the plates in a global table (nameplates lines 307 and 328) and then use that table to color them (threat lines 132 to 141)

The issue i need help with:

Currently, when i enter combat with a group of mobs, all the plates light up showing the threat color of my target instead of their own threat in relation to me.

Does anyone know what i have to change to make it work on a plate per plate basis ? (so that each plate show their own threat) ?
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-08-14, 06:18 AM   #2
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Read http://wowprogramming.com/docs/api/UnitThreatSituation

Add the nameplate unit to test to
Lua Code:
  1. local status = UnitThreatSituation("player")

Or use http://wowprogramming.com/docs/api/U...hreatSituation. I'm not sure. Just read the descriptions.

Last edited by Duugu : 03-08-14 at 06:21 AM.
  Reply With Quote
03-08-14, 06:57 AM   #3
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
That's not the issue at all, actually the threat module works just fine, it's the nameplates. in other words, ALL the nameplates visible on screen show the colors of the nameplate of my target, probably because they're all being fed to the table without any distinction. So, the threat module takes everything in the table and colors it according to my current target when they should be fed one by one, independently.
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-08-14, 07:21 AM   #4
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Well, as far as I understand your code you are iterating over all the nameplates and recolor them here:

Code:
                       for _, plate in pairs(caelUI.plates) do
133.                                local status = UnitThreatSituation("player")
135.                                if (status and status > 0) then
136.                                        local r, g, b = unpack(aggroColors[playerIsTank][status])
137.                                        plate.healthBar.hpGlow:SetBackdropBorderColor(r, g, b)
138.                                else
139.                                        plate.healthBar.hpGlow:SetBackdropBorderColor(0, 0, 0)
140.                                end
141.                        end
The color values are based on
Code:
local status = UnitThreatSituation("player")
if (status and status > 0) then
The if clause has the same result for every single nameplate. Because you're requesting a general aggro value and not the value for the actual namplate unit (I'm not sure what UnitThreatSituation("player") does reaturn. But whatever it is ... it's the same value for ever single step in you loop.)
  Reply With Quote
03-08-14, 08:06 AM   #5
Oppugno
A Fallenroot Satyr
Join Date: Sep 2012
Posts: 22
So two hours later the website is stable enough so I can finally post:

As far as I'm aware it is unfeasible to get accurate threat information for nameplates other than from the supplied threat region on the nameplate(s). This is because the methods for determining threat (UnitThreatSituation, UnitDetailedThreatSituation) require a unitID (for both the threater and threatee). Because nameplates inherently don't have unitIDs linked to them and although it would be possible to match unitIDs to nameplates in a limited scope it's just not feasible as a threat indicator on a large scale.

The practical way to guarantee known threat on nameplates is to use the provided threat region on them.

If you want a simple solution to your answer replace lines 132-141 in Threat with this:
Lua Code:
  1. for _, plate in pairs(caelUI.plates) do
  2.     if plate:Visible() -- This won't be neccessary if the table only contains active nameplates
  3.         if plate.healthBar.oldGlow:IsShown() then
  4.             local r, g, b = plate.healthBar.oldGlow:GetVertexColor()
  5.            
  6.             -- 0 - Unit has less than 100% raw threat (default UI shows no indicator)
  7.             -- 1 - Unit has 100% or higher raw threat but isn't mobUnit's primary target (default UI shows yellow indicator)
  8.             -- 2 - Unit is mobUnit's primary target, and another unit has 100% or higher raw threat (default UI shows orange indicator)
  9.             -- 3 - Unit is mobUnit's primary target, and no other unit has 100% or higher raw threat (default UI shows red indicator)
  10.             -- You can get the colours from GetThreatStatusColor(#)
  11.             local status = (g + b == 0 and 3) or (b == 0 and 2) or 1
  12.            
  13.             plate.healthBar.hpGlow:SetBackdropBorderColor(unpack(aggroColors[playerIsTank][status]))
  14.         else
  15.             plate.healthBar.npGlow:SetBackdropBorderColor(0, 0, 0)
  16.         end
  17.     end
  18. end
However, I'm not certain nameplates update for events as immediately as standard frames (I've seen 0.5s + delays) so your threat update events will probably trigger before the new threat colours show up on the nameplates.

Personally, the way I do it is as you've done previously, with an OnUpdate script. However, I use a single OnUpdate script and a table for tracking currently visible nameplates. It will benefit from less CPU time and less memory usage (compared to giving each nameplate it's own OnUpdate script).

Last edited by Oppugno : 03-08-14 at 08:19 AM. Reason: Clarified some stuff.
  Reply With Quote
03-08-14, 08:15 AM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Duugu View Post
The if clause has the same result for every single nameplate. Because you're requesting a general aggro value and not the value for the actual namplate unit (I'm not sure what UnitThreatSituation("player") does reaturn. But whatever it is ... it's the same value for ever single step in you loop.)
UnitThreatSituation("player") without a second unit will return information based on the unit the player's threat is highest against. If you're on the threat table for 5 mobs, but only have aggro on 1, then it will indicate that you have aggro. To get information about your threat vs. a specific unit, you need to pass a second unit, eg. UnitThreatSituation("player", "target")

However, this only works for units with a current (and known) unit token, so it isn't a suitable solution for nameplates. Use the solution posted by Oppugno instead to get the information from the nameplate's default threat region.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
03-08-14, 10:09 AM   #7
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
Originally Posted by Oppugno View Post
Lua Code:
  1. if plate:Visible() -- This won't be neccessary if the table only contains active nameplates
If i'm not mistaken, once nameplates aren't visible on screen they don't exist anymore, meaning that the same applies to the table, or do you mean i have to clear the table manually ?
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-08-14, 11:14 AM   #8
Oppugno
A Fallenroot Satyr
Join Date: Sep 2012
Posts: 22
Nameplates persist long after they've gone off screen / not visible anymore and are constantly being recycled. Which makes sense or else there would be alot of garbage being generated each time a nameplate went off screen only to come back on screen 2 seconds later because you turned your camera. To test it, try doing a frame stack.
  Reply With Quote
03-08-14, 11:16 AM   #9
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
In that case i'm not sure i understand the comment you've made in the code
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-08-14, 12:09 PM   #10
Oppugno
A Fallenroot Satyr
Join Date: Sep 2012
Posts: 22
(Although I'm pretty sure you understood this part) To clarify, when I wrote 'active' I meant the nameplate is actually visible on the screen at this moment in time.

Say you've fought 50 mobs at once and they all had unique nameplates because they were all on the screen at one time. If you then encounter a pack of 3 mobs, well only 3 of those 50 nameplates are actually active / visible at the moment. So, obviously it would be wasteful running your threat update on the 47 other nameplates because they're not visible at the moment. The way I avoid updating those hidden nameplates is by storing the active / visible nameplates in a table of only them. I do this by Hooking/Setting the OnHide and OnShow scripts for each nameplate to remove or add them to that table of visible nameplates.

Lua Code:
  1. caelUI.activePlates = {}
  2.  
  3. local function NameplateOnShow(self)
  4.     -- This is where we account for the fact that the frame could have been recycled for a new mob.
  5.  
  6.     -- We now know it's on the screen and shown.
  7.     caelUI.activePlates[self] = true
  8. end
  9.  
  10. local function NameplateOnHide(self)
  11.     -- It's not shown anymore, don't care about updating it.
  12.     caelUI.activePlates[self] = nil
  13. end
  14.  
  15. local function NameplateOnIntialise(self)
  16.     -- First time we've seen this nameplate
  17.     self:HookScript('OnShow', NameplateOnShow)
  18.     self:HookScript('OnHide', NameplateOnHide)
  19.  
  20.     NameplateOnShow(self) -- We can't pre-hook the OnShow so we call it directly
  21. end
  22.  
  23. WorldFrame:HookScript('OnUpdate', function(self, elapsed)
  24.     -- Scan for new nameplates, calling NameplateOnInitialise(<nameplate object>) on each new one.
  25. end)

With that we now have a table that contains only nameplates that are actually visible. Which now means we can do:
Lua Code:
  1. for plate in pairs(caelUI.activePlates) do
  2.     if plate.healthBar.oldGlow:IsShown() then
  3.         local r, g, b = plate.healthBar.oldGlow:GetVertexColor()
  4.        
  5.         -- 0 - Unit has less than 100% raw threat (default UI shows no indicator)
  6.         -- 1 - Unit has 100% or higher raw threat but isn't mobUnit's primary target (default UI shows yellow indicator)
  7.         -- 2 - Unit is mobUnit's primary target, and another unit has 100% or higher raw threat (default UI shows orange indicator)
  8.         -- 3 - Unit is mobUnit's primary target, and no other unit has 100% or higher raw threat (default UI shows red indicator)
  9.         -- You can get the colours from GetThreatStatusColor(#)
  10.         local status = (g + b == 0 and 3) or (b == 0 and 2) or 1
  11.        
  12.         plate.healthBar.hpGlow:SetBackdropBorderColor(unpack(aggroColors[playerIsTank][status]))
  13.     else
  14.         plate.healthBar.npGlow:SetBackdropBorderColor(0, 0, 0)
  15.     end
  16. end
  Reply With Quote
03-09-14, 10:33 AM   #11
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
Right, this is what i have now, let me know if i didn't miss anything

http://pastebin.com/vx7HakVc

So far it seems to work great for just about everything exept one minor detail:

For some reason, if i enable lines 37-39 to recolor tapped units, those will just not keep the color i want them to have, so they'll be blinking between whatever color i choose (in this case for testing purpose plain red) and the default grey color and i can't find any reason why those won't work when everything else does.
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-09-14, 05:56 PM   #12
Oppugno
A Fallenroot Satyr
Join Date: Sep 2012
Posts: 22
The tapped colour is set/reset every frame while the nameplate is tapped. That is what is causing your flickering bar colour. I know of three 'solutions':
  1. Set the bar colour every frame. (CPU expensive)
  2. Create your own health bar and display that instead of the provided one.
  3. Ignore threat when the nameplate is tapped. (Any mob that doesn't become a shared tag once you engage it likely isn't relevant to you.)

The only parts of UpdatePlate() that need to be run in an OnUpdate script are lines 63-65 so you have a massive overhead calling that entire function.
  Reply With Quote
03-10-14, 03:54 AM   #13
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
Originally Posted by Oppugno View Post
The only parts of UpdatePlate() that need to be run in an OnUpdate script are lines 63-65 so you have a massive overhead calling that entire function.
This should do it

http://pastebin.com/XSEw2iXN

I had to leave the healthbar stuff in the OnUpdate, if i move it in the OnShow for example the healthbar are fine at first but as soon as they leave the screen then come back, they keep the skin but change to the default size.
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }

Last edited by Caellian : 03-10-14 at 05:15 PM.
  Reply With Quote
03-10-14, 05:16 PM   #14
Oppugno
A Fallenroot Satyr
Join Date: Sep 2012
Posts: 22
Sorry, what I meant was you do need everything else other than lines 63-65 in your OnShow function (UpdatePlate). But you need to make a separate function that is called from your OnUpdate script.
Lua Code:
  1. local UpdateThreat = function(self)
  2.     self.healthBar.r, self.healthBar.g, self.healthBar.b = UpdatePlateColor(self.healthBar, self.healthBar:GetStatusBarColor())
  3.     self.healthBar:SetStatusBarColor(self.healthBar.r, self.healthBar.g, self.healthBar.b)
  4.     self.healthBar.hpBackground:SetVertexColor(self.healthBar.r * 0.33, self.healthBar.g * 0.33, self.healthBar.b * 0.33, 0.75)
  5. end
Lua Code:
  1. local UpdatePlate = function(self)
  2.     -- Leave the stuff before this section
  3.  
  4.     UpdateThreat(self)
  5.     -- Only remove this section (lines 63-65)
  6.     --self.healthBar.r, self.healthBar.g, self.healthBar.b = UpdatePlateColor(self.healthBar, self.healthBar:GetStatusBarColor())
  7.     --self.healthBar:SetStatusBarColor(self.healthBar.r, self.healthBar.g, self.healthBar.b)
  8.     --self.healthBar.hpBackground:SetVertexColor(self.healthBar.r * 0.33, self.healthBar.g * 0.33, self.healthBar.b * 0.33, 0.75)
  9.     --self.healthBar.lastUpdate = 0
  10.    
  11.     -- Leave the stuff after this section
  12. end)
Lua Code:
  1. nameplates:SetScript("OnUpdate", function(self, elapsed)
  2.     temp = WorldFrame:GetNumChildren()
  3.  
  4.     if temp ~= numChildren then
  5.         numChildren = temp
  6.         HookFrames(WorldFrame:GetChildren())
  7.     end
  8.  
  9.     if self.elapsed and self.elapsed > 0.1 then
  10.         for frame in pairs(caelUI.activePlates) do
  11.             UpdateThreat(frame)
  12.         end
  13.  
  14.         self.elapsed = 0
  15.     else
  16.         self.elapsed = (self.elapsed or 0) + elapsed
  17.     end
  18. end)

Or better yet, merge the two components (the threat colouring and the OnUpdate script) and get rid of UpdateThreat entirely. There will be up to a ~0.1s delay after a frame is shown before its threat is updated by your OnUpdate script but it's faster iterating over the table and running the contents of a function than iterating and then calling a function to run its contents.

Lua Code:
  1. nameplates:SetScript("OnUpdate", function(self, elapsed)
  2.     temp = WorldFrame:GetNumChildren()
  3.  
  4.     if temp ~= numChildren then
  5.         numChildren = temp
  6.         HookFrames(WorldFrame:GetChildren())
  7.     end
  8.  
  9.     if self.elapsed and self.elapsed > 0.1 then
  10.         for frame in pairs(caelUI.activePlates) do
  11.             self.healthBar.r, self.healthBar.g, self.healthBar.b = UpdatePlateColor(self.healthBar, self.healthBar:GetStatusBarColor())
  12.             self.healthBar:SetStatusBarColor(self.healthBar.r, self.healthBar.g, self.healthBar.b)
  13.             self.healthBar.hpBackground:SetVertexColor(self.healthBar.r * 0.33, self.healthBar.g * 0.33, self.healthBar.b * 0.33, 0.75)
  14.         end
  15.  
  16.         self.elapsed = 0
  17.     else
  18.         self.elapsed = (self.elapsed or 0) + elapsed
  19.     end
  20. end)

Edit: And that'll teach me to get distracted while writing a response.

Last edited by Oppugno : 03-10-14 at 05:25 PM.
  Reply With Quote
03-10-14, 05:17 PM   #15
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
Ouch, i edited my post above with my most recent changes at the same time you were posting i guess.
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-10-14, 05:34 PM   #16
Oppugno
A Fallenroot Satyr
Join Date: Sep 2012
Posts: 22
As for the resizing frames if you do increase their size keep in mind that the area on which you can click a nameplate will be roughly the same as the original (smaller) area. Also, OnSizeChanged scripts are probably the ideal script for dealing with changing frame sizes, not OnUpdate. This thread might be of some use, where someone had to deal with resizing frames on nameplates.
  Reply With Quote
03-11-14, 06:04 AM   #17
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
Cael, the code in the linked thread is basically a stripped version of your CaelNameplates before you took it off from WoWI. I think the only real difference is the removal of the custom coloring and using a texture for the border instead of a backdrop. I hope it helps
  Reply With Quote
03-11-14, 06:22 PM   #18
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
The UNIT_SPELLCAST* events you have registered are not helpful because they only fire for "real" unit ids but you have them registered to all castbars. So you will spread the results for your target among all nameplates. The same goes for channeling. Also instead of calling UpdateTime from Castbar_OnValueChanged why not set it directly as the script handler? You could significantly reduce the table look-ups in CreatePlate too.
  Reply With Quote
03-13-14, 02:47 AM   #19
Caellian
A Frostmaul Preserver
 
Caellian's Avatar
Join Date: May 2006
Posts: 281
http://pastebin.com/TkyJP6Vb
__________________
if (sizeof(workload) > sizeof(brain_capacity)) { die('System Overload'); }
  Reply With Quote
03-19-14, 02:06 PM   #20
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
In your OnUpdate (lines 303-322 in the pastebin) you should create a local reference to self.healthBar and spare yourself 11 table look-ups. You also have an unnecessary call to GetStatusBarColor() in UpdatePlateColor. Line 46 could just read
Code:
newr, newg, newb = r, g, b
or you could just return from every if statement and even spare the 3 locals for the new color.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Help with a table issue


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