WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Help with an addon i am making. (https://www.wowinterface.com/forums/showthread.php?t=49771)

darrare 08-21-14 07:36 PM

Help with an addon i am making.
 
Im making an addon that tracks combat stats for a hunter such as agility, ap, crit, mastery, haste, etc.

i have it displaying correctly, but my only problem is i have no way for it to update at a reasonable rate.

local function updateFunction()
AgilityLine.text:SetText("Agility = ".. getRangedAgility())
AttackPowerLine.text:SetText("AP = ".. getRangedAttackPower())
CritLine.text:SetText("Crit = ".. getRangedCrit() .."%")
MasteryLine.text:SetText("Mastery = ".. getRangedMastery())
HasteLine.text:SetText("Haste = ".. getHaste() .."%")
end

i have this function that updates it correctly, but i have no idea how to impliment a way to make it only update when it should, and not 60 times a second.

any help would be appreciated

Yafis 08-21-14 07:40 PM

You have update on OnUpdate?

darrare 08-21-14 08:01 PM

Quote:

Originally Posted by Yafis (Post 295784)
You have update on OnUpdate?

not sure i understand, is OnUpdate some sort of built in function?

SDPhantom 08-21-14 08:29 PM

For now, you need to create a frame that'll run the code in its OnUpdate handler.
lua Code:
  1. local lastupdate=0;--   Local storing how long since our last update
  2. local frame=CreateFrame("Frame");-- Our frame
  3.  
  4. frame:SetScript("OnUpdate",function(self,elapsed)
  5.     lastupdate=lastupdate+elapsed;--    Add elapsed to update local
  6.     if lastupdate>1 then--  If it's been a second, update
  7.         AgilityLine.text:SetText("Agility = ".. getRangedAgility());
  8.         AttackPowerLine.text:SetText("AP = ".. getRangedAttackPower());
  9.         CritLine.text:SetText("Crit = ".. getRangedCrit() .."%");
  10.         MasteryLine.text:SetText("Mastery = ".. getRangedMastery());
  11.         HasteLine.text:SetText("Haste = ".. getHaste() .."%");
  12.  
  13.         lastupdate=0;-- Reset to zero
  14.     end
  15. end);



In WoD, we'll be getting a new C_Timer system to handle this.
When this happens, your code would look like this.
lua Code:
  1. C_Timer.NewTicker(1,function()--    Register a function to update every second
  2.     AgilityLine.text:SetText("Agility = ".. getRangedAgility());
  3.     AttackPowerLine.text:SetText("AP = ".. getRangedAttackPower());
  4.     CritLine.text:SetText("Crit = ".. getRangedCrit() .."%");
  5.     MasteryLine.text:SetText("Mastery = ".. getRangedMastery());
  6.     HasteLine.text:SetText("Haste = ".. getHaste() .."%");
  7. end);



Note: To enable Lua syntax highlighting on these forums, surround the code with [highlight=lua] [/highlight].
This is also visible as a Lua button on the right side of the formatting toolbar in the message editor.

Phanx 08-21-14 09:03 PM

I'm pretty sure there are events that fire when these stats changed, so there's no reason to use an OnUpdate script here. Just register for the event(s) that tell you when your stats change, and update when they fire:

Code:

local f = CreateFrame("Frame")
f:RegisterEvent("HEY_YOUR_STATS_CHANGED") -- not the real event name
f:RegisterEvent("SOME_OTHER_EVENT")
f:SetScript("OnEvent", function(self, event, ...)
    -- update the display here
end)

Use the /eventtrace command in-game, do something that changes your stats, and look in the window to see which event fired. I recommend either doing this far away from other players, or leaving /eventtrace open for a minute beforehand and removing all the irrelevant events that are filling the window (hover and click the X).

Resike 08-22-14 02:24 AM

The event you looking for is "UNIT_STATS".

Cybeloras 08-23-14 03:25 PM

You will also need COMBAT_RATING_UPDATE since UNIT_STATS will only cover changes in agility.

MaLarsson 08-24-14 10:14 AM

I feel that it is a good practice to always check which events you want to listen to before beginning with the code.
Wowwiki has a list of all the events: http://www.wowwiki.com/Events_A-Z_(Full_List)
You can try adding something like this to your code:
Lua Code:
  1. local frame, events = CreateFrame("Frame", nil, UIParent), {}
  2.  
  3. function events:UNIT_STATS(unitID)
  4.    if unitID == "player" then
  5.       updateFunction()
  6.    end
  7. end
  8.  
  9. function events:COMBAT_RATING_UPDATE()
  10.    updateFunction()
  11. end
  12.  
  13. for k, v in pairs(events) do
  14.    frame:RegisterEvent(k)
  15. end

Phanx 08-25-14 12:01 AM

That code is incomplete, as you didn't actually tell the frame what to do in response to events. Also:

- There's no need to use separate functions for the two events, as you want to do the same thing in response to both.

- You should use RegisterUnitEvent instead of RegisterEvent with UNIT_STATS so you don't have to manually filter out all other units.

- If your frame isn't a UI object shown the user, there's no need to give it a parent.

- A frame is already a table, so there's no need to create a separate table to hold functions.

Code:

-- updateFunction here

local frame = CreateFrame("Frame")
-- ^ If you already have a frame, you can register events on that instead of creating a new one here.
frame:RegisterEvent("COMBAT_RATING_UPDATE")
frame:RegisterUnitEvent("UNIT_STATS", "player")
frame:SetScript("OnEvent", updateFunction)

(On a side note, I really hope those "AgilityLine" etc. values are not globals. :()

Sharparam 08-25-14 08:39 AM

Quote:

Originally Posted by Phanx (Post 295929)
- A frame is already a table, so there's no need to create a separate table to hold functions.

There can be collisions in key names though, depending on the AddOn, so I prefer having my AddOn specific code in its own table (the private one passed as an argument to each file).

For a small AddOn like this I guess it doesn't really matter though.

Phanx 08-25-14 09:01 AM

Quote:

Originally Posted by Sharparam (Post 295937)
There can be collisions in key names though...

I'm not sure how, since the key names are 100% under your control. It's not like you're forced to give two methods the same name...

Sharparam 08-25-14 09:32 AM

What I mean is you could have something in your table named the same as an existing function or value, which means what was previously defined is overwritten with your stuff. That could lead to bugs or unexpected behaviour. What if you make a SetScript method in your AddOn that is used for something, which then overrides Frame's SetScript method?

Phanx 08-25-14 11:42 AM

Quote:

Originally Posted by Sharparam (Post 295942)
What if you make a SetScript method in your AddOn that is used for something, which then overrides Frame's SetScript method?

But why would you do that? There are literally infinite options for naming your methods. It's not any more difficult to avoid overwriting a frame's default SetScript method than it is to avoid overwriting your own DoThings method or overwriting the global CreateFrame function. This is quite possibly the most contrived excuse for overcomplicating addon code that I've ever heard. :(

Sharparam 08-25-14 12:01 PM

It's still not exactly good practice I'd say to just modify a table from CreateFrame with your own methods, at least for addons larger than a single file. I've never really come across a design pattern like that outside of WoW addon development (granted, most of my experience is with OOP languages where you typically place your code in a namespace/package named after you or a company).

Keeping it separated in that way makes it more clear what code is yours and what code comes from default libraries, and can in some cases also make code more readable for an outside developer, they wouldn't have to check if the method someframe:SomeMethod() that is defined in file1.lua and used in file2.lua comes from the WoW Frame or a custom method in file1.lua.

Torhal 08-25-14 12:18 PM

I'm guessing you've never heard of Monkeypatching. :D

Sharparam 08-25-14 12:30 PM

Well monkeypatching isn't exactly a good thing most of the time is it? :P

Torhal 08-25-14 01:28 PM

If you're a code slob it can be bad, but that's true with any software technique.

Phanx 08-25-14 02:50 PM

Quote:

Originally Posted by Sharparam (Post 295946)
IKeeping it separated in that way makes it more clear what code is yours and what code comes from default libraries, and can in some cases also make code more readable for an outside developer, they wouldn't have to check if the method someframe:SomeMethod() that is defined in file1.lua and used in file2.lua comes from the WoW Frame or a custom method in file1.lua.

But why are you giving your custom methods the same names as default methods in the first place? This is just as bad an idea as naming a table table or naming a local function tostring -- there's just no reason to do it. If you see a SetScript method in a WoW addon, it should always be the SetScript method that comes with the given object type, period, just like if you see a call to a function named tostring it should be the Lua language function. Anything else is just confusing for no reason.

Sharparam 08-25-14 03:12 PM

One reason could be if you make something that you want to behave like a Frame's event/script system. Say you want custom callbacks for some object you have, like:

lua Code:
  1. local object = {callbacks={}}
  2.  
  3. function object:SetScript(typ, func)
  4.   if not self.callbacks[typ] then self.callbacks[typ] = {} end
  5.   table.insert(self.callbacks[typ], func)
  6. end
  7.  
  8. function object:Fire(typ, ...)
  9.   if not self.callbacks[typ] then return end
  10.   for _, f in pairs(self.callbacks[typ]) do f(...) end
  11. end
  12.  
  13. object:SetScript("MyCustomTrigger", function() print("foo bar baz") end)
  14.  
  15. -- Some code that does stuff and triggers the callbacks
  16. object:Fire("MyCustomTrigger")

Yes, there's CallbackHandler lib for this kind of stuff, but sometimes you just want to roll your own when you don't utilize near half the features of an existing library or don't like the particular way they implemented things.

Implementing the above on a Frame wouldn't really work while making sure there aren't any problems with the Frame's own SetScript and related types of events/triggers. Forwards compatibility can also be a concern, why put your addon at risk of being made incompatible with a future patch when it's preventable with little effort? Using different names would work, but why not choose a method that lets you use whatever name you feel fits best.

And if you're just blindly using a Frame to put all your methods in, you could be unknowingly replacing something that the Frame actually uses for whatever purpose if you don't check the documentation before implementing a method.

I like to have the comfort of knowing that whatever I'm putting in my tables, won't directly conflict with anything and lives in its own space. I do sometimes put things in Frames, but mostly for one-off objects. An example being in the options file of one of my addons (code is in MoonScript, but should be relatively readable I hope).

Phanx 08-25-14 05:22 PM

Quote:

Originally Posted by Sharparam (Post 295953)
One reason could be if you make something that you want to behave like a Frame's event/script system.

So... either use the normal Frame event/script system, or name your method something else? Still not seeing how this is leading to using a default API method name for your own custom method is in any way beneficial, regardless of whether you're defining it on a Frame object or a plain table. If I see "object:SetScript" in WoW addon code, the only reasonable assumption to make is that "object" is a frame of some type, and "SetScript" is the standard "SetScript" method that comes with a frame object.

Quote:

Originally Posted by Sharparam (Post 295953)
And if you're just blindly using a Frame to put all your methods in, you could be unknowingly replacing something that the Frame actually uses for whatever purpose if you don't check the documentation before implementing a method.

If you have no idea what methods a Frame object comes with, you should take your hands off the keyboard and go look at some API documentation before proceeding.

Quote:

Originally Posted by Sharparam (Post 295953)
An example being in the options file of one of my addons (code is in MoonScript, but should be relatively readable I hope).

Ugh, MoonScript. Someone (maybe you) posted a link to that recently, and the official examples of Lua code it generates about made me vomit. It's horrible.... but I guess if you're not actually programming in Lua, and you're writing your addons in some Python-like pseudo-code that generates Lua code on par with the HTML generated by MS Front Page circa 1997, that probably explains why you're arguing in favor or something that makes no sense. :(


All times are GMT -6. The time now is 02:06 PM.

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