Thread Tools Display Modes
04-30-17, 06:49 AM   #1
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
(AceDB-3.0) I don't get where my codes are going wrong.

Hi all,

Sorry for keep asking a Ace3.0 related questions here. Take all and put together in one lump, Wowinterface is actually the most activated community to discuss this (even if it is a specific library related question).

SO,

I am currently trying to re-write one of my addon that tracks various data of player such as currency, money, class, etc and here's what I've got so far.

ToonTracker.toc
Code:
## Interface: 70200
## Title: ToonTracker
## Author: Layback
## SavedVariables: ToonTrackerDB

ToonTracker.lua

currency.lua
ToonTracker.lua
Lua Code:
  1. -- Declare addon ------------------------------------------------------------------
  2. local ToonTracker = LibStub("AceAddon-3.0"):NewAddon("ToonTracker");
  3.  
  4. -- Declare & define variables -----------------------------------------------------
  5. local db;
  6.  
  7. -- Defaults db --------------------------------------------------------------------
  8. local defaults = {
  9.     global = {
  10.         modules = {
  11.             ["*"] = true,
  12.         },
  13.  
  14.         experience = {
  15.             pos = {"CENTER", "UIParent", "CENTER", 0, 0},
  16.         },
  17.     },
  18.  
  19.     realm = {
  20.         ["*"] = { -- character's name
  21.             currency = {},
  22.         },
  23.     },
  24. }
  25.  
  26. function ToonTracker:OnInitialize()
  27.     self.db = LibStub("AceDB-3.0"):New("ToonTrackerDB", defaults, true);
  28.  
  29.     db = self.db;
  30.  
  31.     local name = UnitName("player");
  32.     local _, englishClass = UnitClass("player");
  33.  
  34.     db.realm[name].class = englishClass;
  35. end

currency.lua
Lua Code:
  1. -- Get addon ----------------------------------------------------------------------
  2. local ToonTracker = LibStub("AceAddon-3.0"):GetAddon("ToonTracker");
  3.  
  4. -- Declare module -----------------------------------------------------------------
  5. local Currency = ToonTracker:NewModule("Currency");
  6.  
  7. -- Declare & define variables -----------------------------------------------------
  8. local db;
  9.  
  10. local name = UnitName("player");
  11.  
  12. local CURRENCY_ID = {
  13.     824,    -- Warlords of Draenor garrison resource
  14.     1220,   -- Legion order resource
  15.     1342,   -- Legionfall War Supplies
  16.     1226,   -- Nethershard
  17. }
  18.  
  19. function Currency:OnInitialize()
  20.     db = ToonTracker.db.realm;
  21.  
  22.     -- Gold
  23.     db[name].money = GetMoney();
  24.  
  25.     -- Currency
  26.     for i = 1, #CURRENCY_ID do
  27.         local currencyName, currencyAmount = GetCurrencyInfo(CURRENCY_ID[i]);
  28.  
  29.         db[name].currency[CURRENCY_ID[i]] = currencyAmount;
  30.     end
  31. end

And here's the output when I first log-in to the toon.


class is well set, but neither money nor currency table are correctly filled with the actual values.
(strangely currency table is properly formed with currencyIDs lol......)

In order to fix this, I'll have to forcibly reload an ui, which is stupid


Could I get some advice, please?

Thank you!



----------------------------------------------------------------------------------------------------------------

EDIT

Would that be because both :OnInitialize() functions are called simultaneously, which I don't think they are.

If they ran at a time, accessing db in Currency:OnInitialize() should return nil, shouldn't it?

Last edited by Layback_ : 04-30-17 at 07:13 AM.
  Reply With Quote
04-30-17, 02:12 PM   #2
VincentSDSH
Non-Canadian Luzer!
 
VincentSDSH's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2006
Posts: 350
Have you tried using :OnEnable()? I built my currency tracker during LK beta so my memory is a bit fuzzy but there are a fair number of things the client doesn't have right off the bat.
__________________
AddonsExecutive Assistant User Configurable To-Do ListLegible Mail Choose the Font for Your Mail
  Reply With Quote
04-30-17, 08:04 PM   #3
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by VincentSDSH View Post
Have you tried using :OnEnable()? I built my currency tracker during LK beta so my memory is a bit fuzzy but there are a fair number of things the client doesn't have right off the bat.
Hi Vincent,

you mean :OnEnable() for module, not addon, right?

I'll have a go and let you know !
  Reply With Quote
04-30-17, 08:35 PM   #4
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by VincentSDSH View Post
Have you tried using :OnEnable()? I built my currency tracker during LK beta so my memory is a bit fuzzy but there are a fair number of things the client doesn't have right off the bat.
It worked

The only change was

Currency.lua
Lua Code:
  1. -- Get addon ----------------------------------------------------------------------
  2. local ToonTracker = LibStub("AceAddon-3.0"):GetAddon("ToonTracker");
  3.  
  4. -- Declare module -----------------------------------------------------------------
  5. local Currency = ToonTracker:NewModule("Currency");
  6.  
  7. -- Declare & define variables -----------------------------------------------------
  8. local db;
  9.  
  10. local name = UnitName("player");
  11.  
  12. local CURRENCY_ID = {
  13.     824,    -- Warlords of Draenor garrison resource
  14.     1220,   -- Legion order resource
  15.     1342,   -- Legionfall War Supplies
  16.     1226,   -- Nethershard
  17. }
  18.  
  19. function Currency:OnInitialize()
  20.     db = ToonTracker.db.realm;
  21. end
  22.  
  23. function Currency:OnEnable()
  24.     -- Gold
  25.     db[name].money = GetMoney();
  26.  
  27.     -- Currency
  28.     for i = 1, #CURRENCY_ID do
  29.         local currencyName, currencyAmount = GetCurrencyInfo(CURRENCY_ID[i]);
  30.  
  31.         db[name].currency[CURRENCY_ID[i]] = currencyAmount;
  32.     end
  33. end

What would be cauinsg this, lol...?
  Reply With Quote
04-30-17, 08:40 PM   #5
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
OnInitialize() only fires once per addon or module, meaning it fires once for the addon, and once for each and every loaded module. Even if you /reloadui it still won't fire again. It would be the equivalent of registering for ADDON_LOADED (for saved variables) and PLAYER_ENTERING_WORLD (for miscellaneous other start up code) and then unregistering both events. OnInitialize() just makes that process a bit cleaner.

OnEnable() is somewhat like PEW, keeping in mind that it is never unregistered. Each time you /reloadui, OnEnable() fires.

If you are not getting the correct currency information, that probably means the game cannot provide that information ... yet.

With Ace3, you register events and library callbacks in OnEnable(). And handling events is always through a function, then register for PLAYER_MONEY in currency.lua's OnEnable(), and immediately call that function from OnEnable().

In your PLAYER_MONEY handler function, have a line that reads:
Lua Code:
  1. db.realm[name].money = GetMoney() -- or whatever you actually need
  Reply With Quote
04-30-17, 10:10 PM   #6
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by myrroddin View Post
OnInitialize() only fires once per addon or module, meaning it fires once for the addon, and once for each and every loaded module. Even if you /reloadui it still won't fire again. It would be the equivalent of registering for ADDON_LOADED (for saved variables) and PLAYER_ENTERING_WORLD (for miscellaneous other start up code) and then unregistering both events. OnInitialize() just makes that process a bit cleaner.

OnEnable() is somewhat like PEW, keeping in mind that it is never unregistered. Each time you /reloadui, OnEnable() fires.

If you are not getting the correct currency information, that probably means the game cannot provide that information ... yet.

With Ace3, you register events and library callbacks in OnEnable(). And handling events is always through a function, then register for PLAYER_MONEY in currency.lua's OnEnable(), and immediately call that function from OnEnable().

In your PLAYER_MONEY handler function, have a line that reads:
Lua Code:
  1. db.realm[name].money = GetMoney() -- or whatever you actually need
Hi myrroddin,

So, does the following look better?!

Lua Code:
  1. -- Get addon ----------------------------------------------------------------------
  2. local ToonTracker = LibStub("AceAddon-3.0"):GetAddon("ToonTracker");
  3.  
  4. -- Declare module -----------------------------------------------------------------
  5. local Currency = ToonTracker:NewModule("Currency", "AceEvent-3.0");
  6.  
  7. -- Declare & define variables -----------------------------------------------------
  8. local db;
  9.  
  10. local name = UnitName("player");
  11.  
  12. local CURRENCY_ID = {
  13.     824,    -- Warlords of Draenor garrison resource
  14.     1220,   -- Legion order resource
  15.     1342,   -- Legionfall War Supplies
  16.     1226,   -- Nethershard
  17. }
  18.  
  19. function Currency:OnInitialize()
  20.     db = ToonTracker.db.realm;
  21. end
  22.  
  23. function Currency:OnEnable()
  24.     self:RegisterEvent("PLAYER_MONEY");
  25.     self:RegisterEvent("CURRENCY_DISPLAY_UPDATE");
  26. end
  27.  
  28. function Currency:OnDisable()
  29.     self:UnregisterEvent("PLAYER_MONEY");
  30.     self:UnregisterEvent("CURRENCY_DISPLAY_UPDATE");
  31. end
  32.  
  33. function Currency:PLAYER_MONEY()
  34.     db.realm[name].money = GetMoney();
  35. end
  36.  
  37. function Currency:CURRENCY_DISPLAY_UPDATE()
  38.     for i = 1, #CURRENCY_ID do
  39.         local currencyName, currencyAmount = GetCurrencyInfo(CURRENCY_ID[i]);
  40.  
  41.         db.realm[name].currency[CURRENCY_ID[i]] = currencyAmount;
  42.     end
  43. end


+ Another question

AceEvent-3.0 has two ways of registering handler function to an event.

First is like my code above, while the second one is passing as a argument on event registration.

e.g:
Lua Code:
  1. local function PEW()
  2.     -- Code...
  3. end
  4.  
  5. self:RegisterEvent("PLAYER_ENTERING_WORLD", PEW);

Do they have any big difference?

Last edited by Layback_ : 04-30-17 at 10:24 PM.
  Reply With Quote
05-01-17, 12:36 AM   #7
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Looking better. Here's a couple of notes:
Lua Code:
  1. function Currency:OnEnable()
  2.     self:RegisterEvent("PLAYER_MONEY");
  3.     self:RegisterEvent("CURRENCY_DISPLAY_UPDATE");
  4.     -- call your functions so you get some data right away
  5.     self:PLAYER_MONEY()
  6.     self:CURRENCY_DISPLAY_UPDATE()
  7. end
I am not sure your example question will work with AceEvent-3.0; I read the API and it might work, but I am not convinced. Try it for yourself. I will elaborate what the docs actually mean, as far as I can tell.
Lua Code:
  1. self:RegisterEvent("SOME_EVENT", "SomeCallback", arg)
  2. -- "SOME_EVENT" is obviously a WoW event, wrapped in quotes
  3. -- "SomeCallback" (could be "Some_Callback" but never "Some Callback" because that is not how functions are named) is a psuedonym for your event handler.
  4.  
  5. -- basic version
  6. self:RegisterEvent("PLAYER_REGEN_DISABLED") -- in OnEnable()
  7.  
  8. function currency:PLAYER_REGEN_DISABLED()
  9.     -- do something
  10. end
  11.  
  12. -- callback version
  13. self:RegisterEvent("PLAYER_REGEN_DISABLED", "CombatStarted") -- in OnEnable()
  14.  
  15. function currency:CombatStarted()
  16.     -- do something
  17. end
And arg could be anything you pass into your handler function. It could be a string, number, Boolean, etc. As per the AceEvent-3.0 API, you can only pass arg to the callback version of the event handler.

The callback method is convenient if there were, say, a few very similar events (ie: their args are virtually the same) and you wanted to handle all the events in the same function to make things easier on you when coding.

For example, let's say there are three events. Since all events pass the event name as the first arg, I will list the args as expected. However, AceEvent knows this, and you do not need to account for this when registering.
  • SOME_ANIMAL(event, "dog")
  • CUTE_ANIMAL(event, "cat")
  • RIDEABLE_ANIMAL(event, "camel")
Now, you want to register all the events as normal, except that you will pass a callback because you want one function handler for all three events.

Lua Code:
  1. -- register events in OnEnable()
  2. self:RegisterEvent("SOME_ANIMAL", "MyAnimal")
  3. self:RegisterEvent("CUTE_ANIMAL", "MyAnimal")
  4. self:RegisterEvent("RIDEABLE_ANIMAL", "MyAnimal")
  5.  
  6. -- in main chunk, handle the events
  7. function MyAddon:MyAnimal(event, arg)
  8.     local WhatIsMyAnimal = arg
  9.     if WhatIsMyAnimal == "dog" then
  10.         print("woof")
  11.     elseif WhatIsMyAnimal == "cat" then
  12.         print("meow")
  13.     else
  14.         print("Gnomes cannot see over a camel's humps!")
  15.     end
  16. end
  Reply With Quote
05-01-17, 06:42 AM   #8
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Hi again myrroddin,

Thank you so much for such a detailed explanations!

I really appreciate it !!
  Reply With Quote
05-01-17, 07:52 AM   #9
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
You are most welcome. Another tip: if you register a few events via the callback method, I did mention that they have to have similar args. That said, the args can be sequentially similar.

Let's say your three events return the following, besides the necessary event name itself:
  1. unit
  2. unit, target
  3. unit, target, target of target
Lua Code:
  1. function myaddon:SOME_FUNCTION(event, ...)
  2.     local me, you, your_target = ...
  3. end
You could process all three of these events in the same function handler, because the args are sequential. However, the following list will mess you up. You could account for the changes using if/then and = replacement (see SmartRes2's handling of LibResInfo's resurrection and mass resurrection callbacks as examples), but it can get messy.
  1. unit
  2. target, unit
  3. target of target, target, unit
Obviously, these args are not sequential, and the above code will not work.
  Reply With Quote
05-01-17, 08:12 AM   #10
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Yet another tip, you can use UnregisterAllEvents() in OnDisable() rather than listing each one individually. Of course, if there were events you do not want unregistered when putting the addon into standby mode, you'd either have to register them again in OnDisable() or list all your events individually.

UnregisterAllEvents() takes no arguments, and it is slower, as AceEvent has to loop through all registered events to unregister them. However, unless you are registering dozens of events and unregistering them rapidly, nobody will ever know you have done this. Modern computers are just way too fast!

Conversely, there is also RegisterAllEvents() which does exactly that: registers all events in the entire game. Unless you are a madman, don't do that!

RegisterEvent, RegisterAllEvents, UnregisterEvent, and UnregisterAllEvents are all native to WoW. AceEvent only really offers passing the additional argument as something new. Also, AceEvent does not support RegisterUnitEvent, but UnregisterAllEvents will unregister those hooks.

In other words, if you ever need to use RegisterUnitEvent, then do not use AceEvent. Do not load it via your toc, do not embed it in your AceAddon addon table creation line, just do not use AceEvent.

Last edited by myrroddin : 05-01-17 at 08:19 AM. Reason: further thoughts
  Reply With Quote
05-01-17, 04:48 PM   #11
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Hi myrroddin,

Thank you for extra tips!

1. What if I was to use a handler to figure out which event is called and pass the arguments like the following?

Lua Code:
  1. function Currency:EventHandler(event, ...)
  2.     if event == "PLAYER_MONEY" then
  3.         functionA();
  4.     elseif event == "CURRENCY_DISPLAY_UPDATE" then
  5.         functionB();
  6.     elseif event == "CHAT_MSG_CURRENCY" then
  7.         functionC(...);
  8.     elseif event == "GUILD_ROSTER_UPDATE" then
  9.         functionD(...);
  10.     end
  11. end

"PLAYER_MONEY" and "CURRENCY_DISPLAY_UPDATE" doesn't have an argument, but "CHAT_MSG_CURRENCY" and "GUILD_ROSTER_UPDATE" have some arguments which differ from each other.

In that case, should I still consider making separate handler for those events?

2. To be honest, I still haven't decided whether I should keep using an AceEvent-3.0 or not
  Reply With Quote
05-01-17, 05:16 PM   #12
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
The main reason for separating event handling code is for your own readability. Long if-chains can be difficult to read, and separating the event can make the code neat.

I wouldn't recommend using AceEvent. It's not bad, it just doesn't do anything that you can't accomlish yourself with a couple of lines of code. (unless maybe if you want to use internal addon callbacks)

Code:
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", function(self, event, ...)
	Currency[event](Currency, ...)
end)
This will look for a method on your Currency object with the same name as the triggered event. If you want a custom method name you'll just do this:
Code:
function Currency:EVENTX()
end

Currency.OnEventX = Currency.EVENTX
__________________
Grab your sword and fight the Horde!
  Reply With Quote
05-01-17, 06:26 PM   #13
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
What Lombra said. There are two main reasons to use AceEvent-3.0:
  • Hooking two or more events to the same function (function, handler, and callback all basically mean the same thing)
  • Passing an additional argument to the function that the events do not pass
There are also two main reasons to not use AceEvent-3.0:
  • As Lombra showed, unless you need the above functionality, it brings nothing but overhead
  • It does not support RegisterUnitEvent, and can conflict if not processed correctly
If you are on the fence about whether or not to use AceEvent, then I suggest not to use it.
  Reply With Quote
05-02-17, 07:15 PM   #14
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Many thanks to Lombra and myrroddin.

Yeah, guess I should not use AceEvent-3.0 until I see the necessity

Gotta change all my codes haha
  Reply With Quote
05-02-17, 07:45 PM   #15
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Oh, and this might be the very last question.

It's not related to Ace3, but is kinda close to the topic of this thread(?).

How do you guys think of functions being created within a function like the following?

Lua Code:
  1. -- Get addon ----------------------------------------------------------------------
  2. local Core = LibStub("AceAddon-3.0"):GetAddon("Core");
  3. local ExtraPower = LibStub("AceAddon-3.0"):GetAddon("ExtraPower");
  4.  
  5. -- Declare module -----------------------------------------------------------------
  6. local Power = ExtraPower:NewModule("Power");
  7.  
  8. local ADDITIONAL_BAR_NAME = ADDITIONAL_BAR_NAME;
  9. local ADDITIONAL_BAR_INDEX = ADDITIONAL_BAR_INDEX;
  10.  
  11. -- Declare & define variables -----------------------------------------------------
  12. local db;
  13.  
  14. local LSM = LibStub("LibSharedMedia-3.0");
  15. local font = LSM:Fetch("font", "MeatEdition");
  16. local statusbar = LSM:Fetch("statusbar", "fer28");
  17.  
  18. local InitObjects;
  19.  
  20. function Power:OnInitialize()
  21.     db = ExtraPower.db.global;
  22.  
  23.     self:SetEnabledState(db.modules[self:GetName()]);
  24. end
  25.  
  26. function Power:OnEnable()
  27.     InitObjects();
  28. end
  29.  
  30. function Power:OnDisable()
  31.    
  32. end
  33.  
  34. function InitObjects()
  35.     local bar = CreateFrame("StatusBar", ExtraPower:GetName() .. "Bar", UIParent);
  36.     bar:RegisterEvent("PLAYER_ENTERING_WORLD");
  37.     bar:RegisterUnitEvent("UNIT_POWER_FREQUENT", "player", "vehicle");
  38.     bar:RegisterUnitEvent("UNIT_DISPLAYPOWER", "player");
  39.     bar:SetMinMaxValues(0, 100);
  40.     bar:SetStatusBarTexture(statusbar);
  41.     bar:SetSize(db.power.bar.width, db.power.bar.height);
  42.     bar:SetPoint(unpack(db.power.bar.point));
  43.     bar:SetTemplate(true);
  44.     bar:SetBackground();
  45.  
  46.     function bar:OnEvent(event, ...)
  47.         if event == "PLAYER_ENTERING_WORLD" then
  48.             self:PLAYER_ENTERING_WORLD();
  49.         elseif event == "UNIT_POWER_FREQUENT" then
  50.             self:UNIT_POWER_FREQUENT(...);
  51.         elseif event == "UNIT_DISPLAYPOWER" then
  52.             self:UNIT_DISPLAYPOWER();
  53.         end
  54.     end
  55.  
  56.     function bar:PLAYER_ENTERING_WORLD()
  57.         -- ...
  58.     end
  59.  
  60.     function bar:UNIT_POWER_FREQUENT(...)
  61.         -- ...
  62.     end
  63.  
  64.     function bar:UNIT_DISPLAYPOWER()
  65.         -- ...
  66.     end
  67.  
  68.     bar:SetScript("OnEvent", bar.OnEvent);
  69.  
  70.     bar.playerClass = nil;
  71.  
  72.     Power.bar = bar;
  73.  
  74.     local text = bar:CreateFontString("$parentText", "OVERLAY");
  75.     text:SetFont(font, 12, "OUTLINE");
  76.     text:SetAllPoints();
  77.  
  78.     bar.text = text;
  79. end

The reason that I have done this is to prevent those 'bar' related event functions being created when the frame (bar) doesn't even exist, yet, and I would like to avoid wasting a memory by creating those functions in local which will never be used when module is disabled.

However, I have seen a post saying that this kind of structure has performance issue as it takes more time than it does with creating a local functions.
  Reply With Quote
05-03-17, 02:23 AM   #16
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
That looks confusing to me.

You can blend Ace3 and vanilla WoW code easily enough.
Lua Code:
  1. function Currency:OnInitialize()
  2.     Currency.eventFrame = CreateFrame("Frame") -- OnInit only fires once, so creating frames and setting their parameters here would be a good idea    
  3. end
  4.  
  5. function Currency:OnEnable()
  6.     -- mimic AceEvent without the callback or extra arg
  7.     -- basic functionality, but it works
  8.     -- you also gain RegisterUnitEvent yay!!
  9.     Currency.eventFrame:SetScript("OnEvent", function(self, event, ...)
  10.         Currency[event](Currency, ...) -- notice the change on this line?
  11.     end)
  12.  
  13.     Currency.eventFrame:RegisterEvent("SOME_EVENT")
  14.     Currency.eventFrame:RegisterEvent("ANOTHER_EVENT")
  15.     Currency.eventFrame:RegisterUnitEvent("PLAYER_EVENT", "player", "target")
  16. end
  17.  
  18. function Currency:OnDisable()
  19.     Currency.eventFrame:UnregisterAllEvents()
  20. end
  21.  
  22. function Currency:SOME_EVENT()
  23.     -- do something
  24. end
  25.  
  26. -- etc
  27. -- etc
Here are some issues I have with your InitObjects()
  • It is not a local function, but should be
  • You have some things in there that should be done only once, like creating frames, which is presumably good, yet there are other things that ought to be handled multiple times like registering events
  • Nothing wrong with having your event handlers inside that function, but it doesn't look easy to debug in a year or two

Last edited by myrroddin : 05-03-17 at 02:25 AM.
  Reply With Quote
05-03-17, 04:25 AM   #17
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Just edited codes based on your advice!

Lua Code:
  1. -- Get addon ----------------------------------------------------------------------
  2. local Core = LibStub("AceAddon-3.0"):GetAddon("Core");
  3. local ExtraPower = LibStub("AceAddon-3.0"):GetAddon("ExtraPower");
  4.  
  5. -- Declare module -----------------------------------------------------------------
  6. local Power = ExtraPower:NewModule("Power");
  7.  
  8. -- Upvalue variable ---------------------------------------------------------------
  9. local ADDITIONAL_BAR_NAME = ADDITIONAL_BAR_NAME;
  10. local ADDITIONAL_BAR_INDEX = ADDITIONAL_BAR_INDEX;
  11.  
  12. -- Declare & define variables -----------------------------------------------------
  13. local db;
  14.  
  15. local LSM = LibStub("LibSharedMedia-3.0");
  16. local font = LSM:Fetch("font", "MeatEdition");
  17. local statusbar = LSM:Fetch("statusbar", "fer28");
  18.  
  19. local InitObjects, UpdateBarAndText;
  20.  
  21. function Power:OnInitialize()
  22.     db = ExtraPower.db.global;
  23.  
  24.     if db.modules[self:GetName()] then
  25.         InitObjects();
  26.     end
  27.  
  28.     self:SetEnabledState(db.modules[self:GetName()]);
  29. end
  30.  
  31. function Power:OnEnable()
  32.     local bar = Power.bar;
  33.  
  34.     bar:RegisterEvent("PLAYER_ENTERING_WORLD");
  35.     bar:RegisterUnitEvent("UNIT_POWER_FREQUENT", "player", "vehicle");
  36.     bar:RegisterUnitEvent("UNIT_DISPLAYPOWER", "player");
  37.  
  38.     bar:SetScript("OnEvent", function(self, event, ...)
  39.         Power[event](Power, self, ...);
  40.     end);
  41. end
  42.  
  43. function Power:OnDisable()
  44.     local bar = Power.bar;
  45.  
  46.     bar:UnregisterAllEvents();
  47. end
  48.  
  49. function Power:PLAYER_ENTERING_WORLD()
  50.     UpdateBarAndText();
  51.  
  52.     self:UnregisterEvent("PLAYER_ENTERING_WORLD");
  53. end
  54.  
  55. function Power:UNIT_POWER_FREQUENT()
  56.     UpdateBarAndText();
  57. end
  58.  
  59. function Power:UNIT_DISPLAYPOWER()
  60.     UpdateBarAndText();
  61. end
  62.  
  63. function InitObjects()
  64.     local bar = CreateFrame("StatusBar", ExtraPower:GetName() .. "Bar", UIParent);
  65.     bar:SetMinMaxValues(0, 100);
  66.     bar:SetStatusBarTexture(statusbar);
  67.     bar:SetSize(db.power.bar.width, db.power.bar.height);
  68.     bar:SetPoint(unpack(db.power.bar.point));
  69.     bar:SetTemplate(true);
  70.     bar:SetBackground();
  71.  
  72.     local text = bar:CreateFontString("$parentText", "OVERLAY");
  73.     text:SetFont(font, 12, "OUTLINE");
  74.     text:SetAllPoints();
  75.  
  76.     Power.bar = bar;
  77.  
  78.     bar.playerClass = nil;
  79.     bar.text = text;
  80. end

1. Transferred RegisterEvent(...) functions to :OnEnable() function from InitObjects() function.

2. Added UnregisterAllEvents(...) function on :OnDisable() function.

3. Transferred InitObjects() function (which creates frames and other objects) call to :OnInitialize() function from :OnEnable() function.

4. On L#39, I've added self (bar) as an argument for just in case if I need them (which would be redundant as Power.bar is same anyways ).

If I missed something, please let me know!!

+ About InitObject() function, I have been told that once it is declared as local at the top of .lua file, it functions as local, thus I didn't put local at L#63.
  Reply With Quote
05-04-17, 07:12 AM   #18
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Here's one more question!!

How would you manage a module with more than one lua files?

For example, my Unitframe (which I made with oUF) is made up of five different lua files called:
  • api.lua: Holds 24 local functions to create a unitframe
  • core.lua: Responsible for style registration and actual unitframe spawning
  • group.lua & unit.lua: Nothing really special
  • unitframe.lua: Being a core part of module (Those AceAddon-3.0 functions, :OnInitialize(), :OnEnable() & :OnDisable() functions are called here)

If the module is disabled, those 24 local functions and function calls on core.lua becomes useless, but occupies memory.

What would be the best practice for this case?
  Reply With Quote
05-04-17, 01:08 PM   #19
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
You would load those lua files in your toc as usual. When the module is disabled, you are correct, their functionality also gets disabled, and Lua will garbage collect as usual.

Without more information, that is the best answer I can provide right now.
  Reply With Quote
05-04-17, 03:59 PM   #20
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Hm... I'm still confused.

You mean that those local functions will also get collected by garbage collection?

Here I've attached my addon.

If you don't mind, could you please have a look at them when you have a spare time?
(OnInitialize(), OnEnable() & OnDisable() functions for Unitframe module are not properly used, yet...)

Thank you!!
Attached Files
File Type: zip MyUI_Core.zip (2.48 MB, 131 views)

Last edited by Layback_ : 05-04-17 at 06:40 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » (AceDB-3.0) I don't get where my codes are going wrong.

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