Thread Tools Display Modes
03-15-18, 09:01 AM   #1
Ethly
A Fallenroot Satyr
Join Date: Mar 2018
Posts: 23
Accessing fontstring from secure snippet

Hello. I'm trying to implement simple raid frames. Here's what I've come up with so far:

XML:
XML Code:
  1. <Ui xmlns="http://www.blizzard.com/wow/ui/">
  2.   <Frame name="MyFrames_UnitTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
  3.     <Size x="36" y="36"/>
  4.     <Layers>
  5.       <Layer level="OVERLAY">
  6.         <Texture>
  7.           <Color r="0" g="0" b="0"/>
  8.         </Texture>
  9.         <FontString parentKey="name" inherits="GameFontHighlight" text="Name"/>
  10.       </Layer>
  11.     </Layers>
  12.     <Attributes>
  13.       <Attribute name="type1" type="string" value="target"/>
  14.     </Attributes>
  15.   </Frame>
  16.  
  17.   <Frame name="MyFrames_SecureGroupTemplateHeader" parent="UIParent" inherits="SecureGroupHeaderTemplate">
  18.     <Anchors>
  19.       <Anchor point="TOP"/>
  20.     </Anchors>
  21.     <Attributes>
  22.       <Attribute name="showParty" type="boolean" value="true"/>
  23.       <Attribute name="showRaid" type="boolean" value="true"/>
  24.       <Attribute name="showPlayer" type="boolean" value="true"/>
  25.       <Attribute name="showSolo" type="boolean" value="true"/>
  26.       <Attribute name="maxColumns" type="number" value="8"/>
  27.       <Attribute name="unitsPerColumn" type="number" value="5"/>
  28.       <Attribute name="columnAnchorPoint" type="string" value="TOP"/>
  29.       <Attribute name="point" type="string" value="LEFT"/>
  30.       <Attribute name="template" type="string" value="MyFrames_UnitTemplate"/>
  31.       <Attribute name="templateType" type="string" value="Button"/>
  32.       <Attribute name="columnSpacing" type="number" value="1"/>
  33.     </Attributes>
  34.   </Frame>
  35. </Ui>
LUA:
Lua Code:
  1. MyFrames_SecureGroupTemplateHeader:SetAttribute("initialConfigFunction", [=[
  2.   print("icf", self:GetName())
  3.   self:SetAttribute("refreshUnitChange", [[
  4.     print("ruc", self:GetName(), self:GetAttribute("unit"))
  5.     --self.name:SetText(UnitName(self:GetAttribute("unit")))
  6.   ]])
  7. ]=])
  8.  
  9. MyFrames_SecureGroupTemplateHeader:Show()

It works with static label, but I'm struggling to set name dynamically. I've commented line that does not work. As far as I understood, self refers to frame handle and this frame handle does not have "name" key (which I expected to be set from XML parentKey attribute). I tried to use self:GetFrameRef("name"), but it returns null. I guess I have to register it earlier, but I can't figure out how do I do that. UnitName is not available either, so I'm further confused atm. I guess, I'm doing something seriously wrong. If possible, I prefer to keep XML for UI layouts instead of coding it all with Lua. Also, if possible, it should work in combat (so people entering/leaving raid won't brake frames, that's why I'm using SecureGroupHeaderTemplate).

Last edited by Ethly : 03-15-18 at 10:12 AM.
  Reply With Quote
03-15-18, 10:32 AM   #2
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Fontstrings and textures are not secure; you update them through unrestricted code to reflect the current state of the secure frame.

You can think of the visible parts of your unit frame as something separate that sits on top of the secure, clickable portion underneath. Decoration.
  Reply With Quote
03-15-18, 03:49 PM   #3
Ethly
A Fallenroot Satyr
Join Date: Mar 2018
Posts: 23
It seems that the proper way to update unit information is OnAttributeChanged handler. Something like
Lua Code:
  1. function MyFrames_UnitTemplate_OnAttributeChanged(self, attributeName)
  2.   if attributeName == "unit" then
  3.     self.name:SetText(UnitName(self:GetAttribute("unit")))
  4.   end
  5. end
seems to work for me (I didn't test it in combat yet). I guess I overcomplicated with those secure snippets, there's no use for them at all for my purposes.
  Reply With Quote
03-24-18, 12:39 AM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Ethly View Post
It seems that the proper way to update unit information is OnAttributeChanged handler.
That will only update the frame once, when the unit is first set (e.g. to "target"). If you click on another unit to change your target, the unit attribute doesn't change (it's still "target") so you'd still be showing the name of the previous target. For raid frames, this means that as group members change, your frames won't appear to update.

The proper way is to register for specific events that indicate specific information changes, and update only the relevant portions of your frame when they fire. For example, update the name string when UNIT_NAME_UPDATE fires; the level string when UNIT_LEVEL fires; the health bar when UNIT_HEALTH, UNIT_HEALTH_FREQUENT, or UNIT_MAXHEALTH fire; etc. See the unit events list on Wowpedia for a list of relevant events. Also, use RegisterUnitEvent(event, unit) instead of RegisterEvent(event) so that your frame only receives events for the unit it's displaying.

For some frames, you'd also want to update everything when certain events fire -- for example, for a target frame, you'd need to listen for PLAYER_TARGET_CHANGED to know when you selected a different target, since e.g. UNIT_NAME_UPDATE doesn't fire in that case (the unit's name didn't change when you targeted it!).

Finally, "*target" units (targettarget, focustarget, raid12pettarget, etc.) don't fire unit events at all, so you just have to update everything in an OnUpdate handler. You can look at how oUF handles these events for an example.
__________________
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-24-18, 01:04 AM   #5
Ethly
A Fallenroot Satyr
Join Date: Mar 2018
Posts: 23
Thanks. Currently I'm making specifically raid frames (or party frames if I'm in party) based on SecureGroupHeaderTemplate and they seem to work with OnAttributeChanged way. If someone joins, each unit frame updates with new unit, if someone leaves, last frame updates with null unit, etc. At least from my limited testing with some people joining and leaving. Here's my snippet:
Lua Code:
  1. function MyFrames_UnitTemplate_OnAttributeChanged(self, attributeName)
  2.   if attributeName == "unit" then
  3.     local unit = self:GetAttribute("unit");
  4.     if unit == nil then
  5.       self:UnregisterAllEvents();
  6.     else
  7.       self.name:SetText(UnitName(unit));
  8.       updateBarTextures(self, unit);
  9.       self:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", unit);
  10.       self:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", unit);
  11.       self:RegisterUnitEvent("UNIT_HEAL_PREDICTION", unit);
  12.       self:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", unit);
  13.       self:RegisterUnitEvent("UNIT_MAXHEALTH", unit);
  14.     end
  15.   end
  16. end

PS UNIT_HEALTH_FREQUENT is so weird. Combat log events arriving 200-300 ms earlier than UNIT_HEALTH_FREQUENT so parsing combat log would make unit frames a bit more responsive, but it's quite a headache, why WoW implemented this way I just don't understand, it's not even about throttling, a single npc swinging me every few seconds still shows the same lag between combat log event and UNIT_HEALTH_FREQUENT event. And with heals this problem is not present, I'm receiving UNIT_HEALTH_FREQUENT exactly at the same time as heal combat log event.

Last edited by Ethly : 03-24-18 at 01:08 AM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Accessing fontstring from secure snippet

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