How could this be written neater?
Hi all,
I've tried to make an aura tracker addon and..... it is working fine, but the code looks really disgusting. Lua Code:
I am pretty happy with the rest of parts, but :UNIT_AURA() function is... meh....... Even if I've left some comments there, pretty sure I would forget what I have done there with all those for loops. Could I ask some helps?! Thank you. |
For me it seems like AuraTrack:UNIT_AURA(...) can be split into two functions.
|
(1) You're doing checkups on tables that may not exist. If you don't intend to add tables for every class and spec, anyone else using your addon that is not a destruction warlock will get errors.
(2) What's the point in your holder frame and not just using the AuraTrack frame you already created to show your auras? (3) You don't need to upvalue the global environment just to grab a few functions. This process is quick and painless and only happens once on login anyway. (4) Unless there's a specific reason why you're using a set max of 6 auras, you can use a frame factory / frame pool to spawn your trackers instead of creating them on load. I'll show you an example of how this works with the native implementation already in the UI. Lua Code:
|
Quote:
|
Hi MunkDev,
Your example is awesome :banana:!!!! Quote:
If possible, I am planning to create an interface options panel to add the id for each class and spec. Quote:
The actual project uses Ace3.0 and AuraTrack in that case is actually an addon of Ace3.0 (not frame). I totally forgot to clarify regarding that :( Quote:
Quote:
In the future, if I want to limit the max frame to 6, I guess I could just put if statement at the top of :UNIT_AURA() function, am I right? Code:
function AuraTrack:UNIT_AURA(...) I have skimmed through the APIs and there are new terms (and functions) in your example that I am not familiar with.
So, you are inheriting ObjectPoolMixin's functions to AuraTracker via Mixin which are OnLoad, ReleaseAll and Acquire, right? Learning new stuff is always exciting :banana: *EDIT: Guess I found a reference here *EDIT2: Are there any other good Mixin that is good to know with? |
Mixin literally stands for "mix in", as in mixing in stuff from another table into your own table. It's a good way to preserve memory, because it utilises the same basic functions that are useful in many different cases. It's essentially an implementation of inheritance and object-oriented programming, albeit less bloated.
There's also a function called CreateFramePool, which returns a table that can be used to recycle objects that are displayed dynamically. A typical case for that is when you don't know how many objects you need. The downside is that it expects an XML template for the type of frame you want to create a pool for. In the example I posted, I used a simpler solution, which is to only use the downscaled ObjectPoolMixin. This is the basis of a frame pool, but you supply the functions to create and reset your objects yourself. This is useful for when you're creating your objects in pure Lua. Generally, you probably shouldn't go looking for mixins unless you have a distinct need for them. If you do insist, however, you can use this script to list all existing mixins in your chat: Lua Code:
|
Quote:
Thank you so much for your detailed explanation! I really appreciate your help :banana: |
Quote:
Quote:
For example Lua Code:
then follow suit Lua Code:
Is this bad practice? If so I'd love more info on this. Everyone has their ways. So telling him he doesn't need to do this is right or wrong here or are you teaching him what you have learned. Lua Code:
|
The only reason why I do local _G = getfenv(0) is my paranoia o_O
I've seen addons that do some weird manipulations w/ environments, so _G may end up being something else, and a check like _G == getfenv(0) will return false. IMHO, if you have no paranoia and don't call global functions from inside OnUpdate and prob OnEvent funcs, only if you register for REALLY spammy events, e.g., CLEU, personally, I consider UNIT_POWER_FREQUENT spammy too, there's no point in creating upvalues for pretty much anything. Another reason might be to please one's Lua linter :D |
Quote:
Also never thought of the whole _G = getfenv(0) deal. Incoming paranoia? :confused: |
Quote:
But in most cases upvalues and/or accessing globals via _G are a personal preference or even a style, people like weird things o_O |
Quote:
The performance gain is negligible at best. The only recurring functions that are used in loops in response to a frequent event are the two functions I listed at the top. If you're doing a ton of lookups very frequently, it might be wise to upvalue functions or entire tables in that case. Personally, I don't upvalue the global environment because it produces uglier code. |
There were those old threads about _G upvaluing if that helps
|
Quote:
Quote:
People need to understand what kind of gains we are talking about here. Some results were presented in one of the threads Ketho linked. I'd like to provide some more. I tested the following cases using debugprofilestop(), which is very precise. Over a hundred thousand iterations, calling UnitAura without any upvalues takes around 52 milliseconds. Code:
for i = 1, 1e5 do Code:
local UnitAura = UnitAura As for assigning values, we're upping the iteration count to one million for increased accuracy. Upvaluing without using _G takes 15.5 ms. Code:
for i = 1, 1e6 do Code:
for i = 1, 1e6 do Code:
local _G = _G Code:
for i = 1, 1e6 do Do with this info as you will. Here is the exact test suite I'm using. Feel free to try to produce your own results. Code:
local t = debugprofilestop |
Quote:
I agree w/ you and I also said that there's almost no need to create any upvalues in 99.99% of cases. Basically, my comment was "do as I say, not as I do" :D P.S. I prob should start fighting _G-paranoia though.... |
Fair enough. :)
|
Quote:
|
Quote:
My answer was to move the check function to a local and then make a global dummy function that returns the check function. The worst part was the integration into a timer loop I use to check the global dummy every five seconds and reinitialize it if it's nil, while trying to out the addon deleting it with ADDON_LOADED. I recently removed that part of the timer loop actually, but I still hide the main check function locally, while the global dummy is just an API thing I keep. Paranoia aside, I still learned that I shouldn't have important functions outside my addon's scope. |
Quote:
Quote:
I once wasted a lot of time doing so... |
Quote:
|
To prevent such annoyance, I wrote a complete a new debug module which only checks for annoyance of my own API:
Pretty much like c# try / catch <3 Everything else is third-party-addon stuff (you are dismissed, foolish addon) |
Sorry for interrupting ;)
I got a further question to MunkDev. So, I was trying to apply same method to target's debuff and here I got some issue. Lua Code:
Those auraIDs are all "Unstable Affliction (UA)" of Affliction Warlock. 233490 / 233496 / 233497 / 233498 / 233499 The problem is since I am passing a spellName as an argument of UnitDebuff() function, casting UA once will generate five buttons at the same time as they all have same names, but different id :confused: To track a specific UA debuff, I guess I should pass an index of an aura as an argument rather than a name, but looping through all debuffs sounds inefficient to me. |
Do it the other way around, cycle through all target debuffs that are applied by you and match their IDs against UAs' IDs o_O
IIRC, unit can have up to 40(?) debuffs, might be wrong here... -- edit #1 I should get some coffee... Quote:
|
Quote:
I was considering something like... Lua Code:
But... (1) What if my spell doesn't get included within those 40 debuffs? (2) Would there be a variable that stores number of unit's (not only target's, but for others' as well) buff/debuff? I mean something like BUFF_ACTUAL_DISPLAY/DEBUFF_ACTUAL_DISPLAY for player. (3) I tried to refer aura element of oUF, but.............. meh... guess it's too complex for me :( |
Drycoded, haven't tested anything...
Lua Code:
Quote:
Quote:
|
Hi again,
(1) I guess the example slightly is limited (focused I mean) to Unstable Affliction (UA). Of course, I know that example is just an example and I should modify bits to make it generic, but, hm...... I don't know :confused: (2) What if the a nth debuff on "target" is not "player's" while (n+1)th debuff is? |
Quote:
Quote:
Lua Code:
W/ "PLAYER" as a filter you'll be getting ONLY debuffs that were applied by the player. It's a separate pre-filtered list of auras, there's no gaps, its indices aren't related to anything. For example, this code: Lua Code:
will return this on my paladin: Lua Code:
whereas actual buff list look like this: Lua Code:
Lua Code:
|
Quote:
I thought giving a filter "PLAYER" lets the UnitAura to internally check if the caster was "player" or not. Didn't realize that it would ignore all others from the scratch. This makes more sense now +_+!! It also cleared up the first point, so please ignore that :banana: |
|
Quote:
Definitely didn't pay attention to word "Query" :p |
All times are GMT -6. The time now is 04:32 AM. |
vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI