Thread Tools Display Modes
05-27-11, 10:29 AM   #1
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
How to show castbars for all visible nameplates

I was thinking about how to display castbars and spell icon for all visible nameplates.

Since this is way more tricky than the stuff I normally do I need some help.

Brainstorming so far:

* cache all nameplates in a table
* check on events (COMBAT_LOG_EVENT_UNFILTERED?!?) if a cast starts
* associate the cast with the proper nameplate by comparing the check above with the cached nameplates
* create a castbar and spell icon for unit's that are casting and display the cast
* show the cast and it's icon

I'm kinda stuck here, not sure how to get rid of cached nameplates or if this is even necessary and if anything of what I said above is correct. I tried to take a glimpse look at how TidyPlates does it, but didn't got it so far, since everything is so split up.


Anyway, I want to use the code with my existing nameplate addon(s), if possible. Which more or less re-skin blizzards plates. So a "simple solution" without the use of additional libraries would be preferable.
__________________
Rock: "We're sub-standard DPS. Nerf Paper, Scissors are fine."
Paper: "OMG, WTF, Scissors!"
Scissors: "Rock is OP and Paper are QQers. We need PvP buffs."

"neeh the game wont be remembered as the game who made blizz the most money, it will be remembered as the game who had the most QQ'ers that just couldnt quit the game for some reason..."

  Reply With Quote
05-27-11, 11:02 AM   #2
Crepusculu
A Deviate Faerie Dragon
 
Crepusculu's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 16
I am not sure why you are trying to get "rid of a cache of nameplates". Just merely nullify or wipe out your cache table if you want to do that. The purpose of building a cache is to quickly access them rather than call the global variable table every time you want to modify the nameplate.


I would do the following

- collect a reference to all nameplates and continue checking for nameplates as they are created. Nameplates are stored as children on the WorldFrame and do not fire any events when they are created.
- create a custom cast bar for every frame, leave them hidden
- set up a combatlog parser
- grab the spell information on event, and find the matching nameplate to place the spell information
- modify the nameplate custom cast bar to display the information, and add an updater to move the bar
- hide the castbar / remove the updater when spell interrupts or finishes, or when the nameplate is hidden


The general issue that prevents you from just making castbars on each nameplate is the lack of a unique identifier on nameplates. That is to say that when an unit casts a spell in the combatlog, you have a GUID number provided that is unique to that unit. Nameplates don't show their GUID number, although they provide the unit name. You could parse the combatlog and assume that all unit names are unique and assign castbars to nameplates with matching unit names, but you will find duplicate names such as players matching pet names and multiple caster npcs. There are methods around this, but they are not simple.
  Reply With Quote
05-27-11, 12:43 PM   #3
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
The main purpose is to show castbars for PvP, and names in PvP should be unique. So maybe a filter or a zone check will get around the GUID thingy, since we can't simply check for something like "isPlayer", unless class colored statusbars are checked in blizzards options and we base our "isPlayer" on the color of the healthbar.

As for the cache, I just wanted to make sure obsolete (i.e. dead units) nameplates get deleted from the table (cache), to prevent memory from sky-rocketing. No idea of that's necessary, but that was my reason.

Anyhow, so I need some kind of "EventHandler" that checks for cast start, interrupt, channel, etc., hmkay.

and add an updater to move the bar
You mean to fill and deplete (channel casts) the bar?


Another question would be: How do I do all that without influencing the default castbar behaviour for the selected nameplate (aka your target)? Can I handle non-selected nameplates only?
__________________
Rock: "We're sub-standard DPS. Nerf Paper, Scissors are fine."
Paper: "OMG, WTF, Scissors!"
Scissors: "Rock is OP and Paper are QQers. We need PvP buffs."

"neeh the game wont be remembered as the game who made blizz the most money, it will be remembered as the game who had the most QQ'ers that just couldnt quit the game for some reason..."

  Reply With Quote
05-27-11, 01:52 PM   #4
hankthetank
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2009
Posts: 64
save unitids in a new nameplate member (WorldFrame.NameplateN.uid) on UPDATE_MOUSEOVER_UNIT and UNIT_TARGET:"player": unitguid("mouseover" / "target"). check the visibility of this one hover overlay region as you can't rely on event handlers of nameplate elemnts as is mostly the case. you might need to delay the check a few ms.

reset the value OnShow. you can use this event actually.

make a nameplate scan for the target uid on COMBAT_LOG_EVENT_UNFILTERED

draw your statusbar or reuse / show the original nameplate statusbar accordingly. the latter may cause one of these unforeseeable nameplate override issues but is the best solution imo. when the unit is targeted you can let wow handle the castbar.

of course the whole thing will be somewhat unreliable.

if you are checking for players the whole thing is a lot easier. you can extract the unit type and if it is a player from the guid string (tonumber(guid:sub(5, 5), 16) % 8), if so and you found a nameplate with its hp bar player / class colored and the same label as the caster's name you are pretty safe to assume it's the unit in question. cross realm bg comes into mind maybe, not sure if combatlog events return names as name-server there. i'm not even sure how the names are displayed in the nameplate there. man... i never pvp it seems lol.

Last edited by hankthetank : 05-27-11 at 02:26 PM.
  Reply With Quote
05-27-11, 02:49 PM   #5
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
Originally Posted by hankthetank View Post
if you are checking for players the whole thing is a lot easier. you can extract the unit type and if it is a player from the guid string (tonumber(guid:sub(5, 5), 16) % 8), if so and you found a nameplate with its hp bar player / class colored and the same label as the caster's name you are pretty safe to assume it's the unit in question. cross realm bg comes into mind maybe, not sure if combatlog events return names as name-server there. i'm not even sure how the names are displayed in the nameplate there. man... i never pvp it seems lol.
Do the mouseover and UnitID suggestions work for all nameplates or just the selected one? If for all: Will it be necessary to mouseover all nameplates first? Stupid question(s) probably, but I don't get it, yet.

So the guid string can tell me if it's a player or not, already? Or did you mean by class colored healthbar, too? Seems like I have to read about that code, never needed it before.

It just states the name, no matter if it's cross server or not. I never encountered the same name twice in the same battleground, yet neither - so either this can not happen or it's rare enough to not be an issue.

Anyway, thanks for all the input. Highly appreciated!
__________________
Rock: "We're sub-standard DPS. Nerf Paper, Scissors are fine."
Paper: "OMG, WTF, Scissors!"
Scissors: "Rock is OP and Paper are QQers. We need PvP buffs."

"neeh the game wont be remembered as the game who made blizz the most money, it will be remembered as the game who had the most QQ'ers that just couldnt quit the game for some reason..."

  Reply With Quote
05-27-11, 05:25 PM   #6
hankthetank
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2009
Posts: 64
i'll try to clear things up.

the basic strategy that would work for every unit is to save the unit id of the nameplate whenever it is possible for you to retrieve as this is what you will compare to when you receive an unfiltered combatlog event for a cast.

you will only get the unit id for a nameplate unit on two occasions (feel free to correct me here but i don't see another possibility for this):
  • you mouseover a nameplate, that means you mouseover a unit and can access the unitid "mouseover". listen to the UPDATE_MOUSEOVER_UNIT event to let wow inform you thusly.
  • you target an unit (unitid "target") that is currently represented by nameplate.

now you will need the scan for the nameplate that corresponds the unit you just retrieved if there is any. so you iterate through all nameplates and check them:
  • when you mouseover a unit there is this one overlay region for the matching nameplate that is shown (the one when the healthbar lightens up). here is the signature for nameplate regions:

    lua Code:
    1. aggro, border, hover, name, level, boss, raidTarget, elite = frame:GetRegions()

    the one you are looking for is hover. when you find a nameplate in your scan where this texture IsShown() you know it matches unitid "mouseover".
  • when you target something all nameplates but the one of the unit you're targeting are half transparent. so you make sure that at least one nameplate has a GetAlpha() value < 1 and one has an alpha value of 1. when you target some unit that has no nameplate all nameplates have values < 1. if there is only one nameplate available you will have to rely on a simple name check or discard this information altogether.

now that you hopefully have a guid-nameplate pair you can store this information. the best way to do that is to save it with the nameplate itself, e.g. NameplateN.guid.

when the nameplate is hidden (register OnHide) you will need to flag this information invalid, e.g. NameplateN.guid = -1, because this nameplate, if it is recycled later on, will most definitely represent another unit.

now when you receive an event for a unit cast you can iterate through all nameplates in WorldFrame and check if casterGUID == Nameplate.guid.

this of course means it will only work if you have mouseovered or targeted the unit previously and the moment you walk out of range the information is rendered useless but that's how it works.

the case where you can speed up things and make it more reliable is with player casts as you can assume that there is no name ambiguity. so you extend your code and check, inside the combatlog event, if the unit is a player (see my previous post and http://www.wowpedia.org/GUID#Notes). if that's the case you can bypass that whole guid thing, iterate through all nameplates, check if it's a player nameplate and compare casterName with name:GetText() (see above).

to decide if a nameplate belongs to a player you check the color of the healthbar

lua Code:
  1. healthBar, castBar = frame:GetChildren()

player nameplates are either blue or class-colored whereas npc nameplates are reaction-colored. this is an excerpt from cael's nameplates:

lua Code:
  1. local r, g, b = self.healthBar:GetStatusBarColor()
  2. local newr, newg, newb
  3. if g + b == 0 then
  4.         -- Hostile unit
  5.         newr, newg, newb = 0.69, 0.31, 0.31
  6.         self.healthBar:SetStatusBarColor(0.69, 0.31, 0.31)
  7. elseif r + b == 0 then
  8.         -- Friendly unit
  9.         newr, newg, newb = 0.33, 0.59, 0.33
  10.         self.healthBar:SetStatusBarColor(0.33, 0.59, 0.33)
  11. elseif r + g == 0 then
  12.         -- Friendly player
  13.         newr, newg, newb = 0.31, 0.45, 0.63
  14.         self.healthBar:SetStatusBarColor(0.31, 0.45, 0.63)
  15. elseif 2 - (r + g) < 0.05 and b == 0 then
  16.         -- Neutral unit
  17.         newr, newg, newb = 0.65, 0.63, 0.35
  18.         self.healthBar:SetStatusBarColor(0.65, 0.63, 0.35)
  19. else
  20.         -- Hostile player - class colored.
  21.         newr, newg, newb = r, g, b
  22. end

when the nameplate is player-colored and the name matches you're safe to say it's the same unit.

all that's left to do is handling the statusbar update. you can either attach your custom castbar to the nameplate. do this when you register OnHide() once. or you reuse the existing castbar and take care of manually showing and skinning it. mind that if the caster is also your target wow automatically shows the nameplate castbar and you can skip that part entirely for this case. this also means that it is probably better to reuse the existing castbar for an uniform look.

edit: good lord...... how long this post became.

it also came to my mind that another possibility to associate a guid to a nameplate would be to check the raid icon texture of the nameplate for its offset and maintain a guid<->raidtarget table. see my lich king addon (stun module) to get an idea of how to do this.

Last edited by hankthetank : 05-27-11 at 08:13 PM.
  Reply With Quote
05-27-11, 07:26 PM   #7
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
Thanks a lot. I'll report back.
__________________
Rock: "We're sub-standard DPS. Nerf Paper, Scissors are fine."
Paper: "OMG, WTF, Scissors!"
Scissors: "Rock is OP and Paper are QQers. We need PvP buffs."

"neeh the game wont be remembered as the game who made blizz the most money, it will be remembered as the game who had the most QQ'ers that just couldnt quit the game for some reason..."

  Reply With Quote
05-27-11, 08:49 PM   #8
thebigmunch
A Deviate Faerie Dragon
Join Date: Jul 2007
Posts: 15
Don't know if you knew about Kollectiv's Overhead addon. One of it's main features is the functionality you're looking at. You could check that out for reference. I've also been wanting to add this to my own addon but haven't gotten started on it yet.

Last edited by thebigmunch : 05-27-11 at 09:03 PM.
  Reply With Quote
05-27-11, 11:19 PM   #9
Crissa
A Flamescale Wyrmkin
 
Crissa's Avatar
Join Date: May 2008
Posts: 136
I don't quite understand the end result you're trying for.

Name plates with cast bars? What?

-Crissa
  Reply With Quote
05-28-11, 01:43 AM   #10
Crepusculu
A Deviate Faerie Dragon
 
Crepusculu's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 16
You can actually read the "sourceFlags" parameter in the combatlog to determine if the unit is a player, rather than parsing the GUID

bit.band(sourceFlags, COMBATLOG_OBJECT_CONTROL_PLAYER) > 0



@hankthetank

You can get an accurate GUID assignment by monitoring the nameplate healthbar with the combatlog, which doesn't require targeting / mouseover
  Reply With Quote
05-28-11, 05:28 AM   #11
thebigmunch
A Deviate Faerie Dragon
Join Date: Jul 2007
Posts: 15
Crissa, castbars only show up on your target's nameplate. We are trying to get castbars on ALL nameplates, which is very useful in pvp settings.
  Reply With Quote
05-28-11, 10:16 AM   #12
hankthetank
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2009
Posts: 64
Sourceflag, GUID - comes to the same thing.

Now that you say it, searching by hp could be done.

Code:
Combatlog damage event->
    Get sourceGUID & destGuid ->
        Do a raid/party/etc[N].."target" scan ->
            sGUID == GUID(raid[N]) && dGuid == GUID(raid[N].."target") ->
                Save UnitHealth, UnitHealthMax and UnitName
    Iterate nameplates ->
        Compare hpBar:GetMax, hpBar:GetValue and name:GetText values ->
            Save GUID
The process would be much more economical if you maintain raidN<->targetGUID pairs you update on UNIT_TARGET instead of doing a group target scan every time. But the whole thing won't help you when you are not in some kind of group because you will need this intermediate step with the target scan. I would also record if all nameplates currently have GUID informations as reactions to combatlog events are costly. Also chances are not so bad that if a mage goes into a goup of mobs and AEs the crap out of them the hpbar values are not distinct, especially in the low level range.

Last edited by hankthetank : 05-28-11 at 10:35 AM.
  Reply With Quote
05-29-11, 02:00 AM   #13
Crissa
A Flamescale Wyrmkin
 
Crissa's Avatar
Join Date: May 2008
Posts: 136
It would be very useful everywhere. To not need to have something targeted so I can tell if it's casting? It would be great for offtanks or solo vs groups PvE play.

-Crissa
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » How to show castbars for all visible nameplates

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