Thread Tools Display Modes
04-22-17, 10:00 PM   #1
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Any possible/alternative ways to access SV at the top of the file?

Hi all,

So, the reason that I am trying to access SV at the top of each files is to decide whether the files should be fully loaded or not based on its SV.
(To be honest, I am using AceDB-3.0, but with or without using it doesn't really change the fact.)

The similar approach has been discussed here by Galaxy119 and OP, Seyan777.

Here's some example:

SVTest.toc
Code:
## Interface: 70200
## Title: SVTest
## SavedVariables: SVTestDB

core.lua

moduleA.lua
moduleB.lua
core.lua
Lua Code:
  1. local SVTest = LibStub("AceAddon-3.0"):NewAddon("SVTest");
  2. _G.SVTest = SVTest;
  3.  
  4. local defaults = {
  5.     global = {
  6.         moduleA = true,
  7.         moduleB = true,
  8.     },
  9. }
  10.  
  11. function SvTest:OnInitialize()
  12.     self.db = LibStub("AceDB-3.0"):New("SVTestDB", defaults, true);
  13. end

moduleA.lua
Lua Code:
  1. if not SVTest.db.global.moduleA then
  2.     return;
  3. end
  4.  
  5. local ModuleA = SVTest:NewModule("ModuleA");
  6.  
  7. -- So on...

I'm aware of that the first line of moduleA.lua will cause an error as SVs are, sadly, not loaded yet since "ADDON_LOADED" event is fired after all addon codes are loaded.

Would there be any work around, alternative solution, or any smarter(?) ways to achieve this?

TL;DR - methods to enable/disable module based on SVs

Thank you.

Last edited by Layback_ : 04-22-17 at 10:13 PM.
  Reply With Quote
04-23-17, 03:46 AM   #2
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Well, you will always need to wait for ADDON_LOADED. What I've seen addons do before is wrap the whole module in a function, and then just wait until ADDON_LOADED before calling it. (or not) If you don't need the module to be loadable on demand you can also destroy the function to free up that memory.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-23-17, 05:08 AM   #3
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Lombra View Post
Well, you will always need to wait for ADDON_LOADED. What I've seen addons do before is wrap the whole module in a function, and then just wait until ADDON_LOADED before calling it. (or not) If you don't need the module to be loadable on demand you can also destroy the function to free up that memory.
Yeah, I thought about that approach, but I didn't really like the way it works.

Hm... maybe I should re-design overall structure

Last edited by Layback_ : 04-23-17 at 05:17 AM.
  Reply With Quote
04-23-17, 07:47 AM   #4
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
The only other way I can think of is having the modules as separate addons.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-23-17, 06:21 PM   #5
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Lombra View Post
The only other way I can think of is having the modules as separate addons.
Like the OP of this thread suggests?
  Reply With Quote
04-23-17, 07:17 PM   #6
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Yep.

tooshort
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-23-17, 10:12 PM   #7
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Lombra View Post
Yep.

tooshort
If you were to make such addon, which method would you prefer to use?

1. Putting if statement at the top of each lua files

2. creating separate addon for each modules

3. none of the above, but different approach
  Reply With Quote
04-23-17, 11:01 PM   #8
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,877
Define what you are trying to do.

If you are creating an overarching environment you intend to pretty much stay intact with just various options then putting everything under a single folder would seem sensible.

If you intend to create a bunch of independent modules that can be used alone or as part of a UI with maybe some changing of SavedVariable settings then seperate folders/addons would seem sensible here.

A combination of these two approaches may also be viable, depending on what are are trying to achieve.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 04-23-17 at 11:08 PM.
  Reply With Quote
04-24-17, 02:02 AM   #9
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Fizzlemizz View Post
Define what you are trying to do.

If you are creating an overarching environment you intend to pretty much stay intact with just various options then putting everything under a single folder would seem sensible.

If you intend to create a bunch of independent modules that can be used alone or as part of a UI with maybe some changing of SavedVariable settings then seperate folders/addons would seem sensible here.

A combination of these two approaches may also be viable, depending on what are are trying to achieve.
I guess it would be a combination of both.

For some UI features like Unitframe and Actionbar, they could go into a Single addon folder as they are core features of game play while some other modules like "AddonSkin" or "CurrencyTracker" could go into separate addon folders.

BUT, if possible I am also willing to enable/disable those core features like Unitframe and Actionbar, then switch back to blizzard default UIs, and that would be the main reason of why I started this thread !

Last edited by Layback_ : 04-24-17 at 02:14 AM.
  Reply With Quote
04-24-17, 04:24 AM   #10
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Originally Posted by Layback_ View Post
If you were to make such addon, which method would you prefer to use?

1. Putting if statement at the top of each lua files

2. creating separate addon for each modules

3. none of the above, but different approach
Well, depends on the nature of the addon and the modules, I think.

As I said in the other thread, as a user I generally prefer the least amount of folders possible, though you may not be concerned with that. Obviously, sometimes it makes sense to have "folder modules".

I would probably consider the size and significance of each module. The larger the module, the more appropriate to do it as a folder. If the module is very small relative to the addon though, I would reconsider whether I really need to disable it. Just hiding it might suffice.

I don't know what your addon is, but if actionbars and unit frames is something that can be disabled, at that point why not just disable the whole addon?
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-24-17, 06:50 AM   #11
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Lombra View Post
I don't know what your addon is, but if actionbars and unit frames is something that can be disabled, at that point why not just disable the whole addon?
Basically the addon will contain those core features like unitframe, actionbar, minimap and so on where unitframe would be a re-creation with oUF, actionbar with LibActionButton while the rest of them (such as minimap and container frame) are pretty much just re-skinning.
(Not sure of what I should actually call this kind of addon UI suite, maybe?)

It's like Is: UI by lightspark.

So, each of those features will be modularized and easily enabled/disabled (toggled) via interface options.

Last edited by Layback_ : 04-24-17 at 06:55 AM.
  Reply With Quote
04-24-17, 07:26 AM   #12
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
There is always putting the module init in a function loaded at ADDON_LOADED and have these functions called and removed after first use.

Quick dirty example:
Lua Code:
  1. --Core
  2. local addonName, addonTable = ...
  3. addonTable.CreateModule = {}
  4. addonTable.Module = {}
  5.  
  6. local frame = CreateFrame('frame')
  7.  
  8. frame:SetScript('OnEvent', function(self, ...)
  9.     addonTable:LoadModules()
  10. end
  11. function addonTable:LoadModules()
  12.     for x, v in pairs(addonTable.CreateModule) do
  13.         v()
  14.     end
  15.     --addonTable.CreateModule = nil -- or just delete the dang module creation
  16. end
  17. frame:RegisterEvent('ADDON_LOADED')

Lua Code:
  1. --ModuleA
  2. local addonName, addonTable = ...
  3. function addonTable.Module.ModuleA:Load()
  4.     -- saved variables should be loaded since this is called in the core after ADDON_LOADED
  5.     if SVTest.db.global.moduleA then
  6.         local ModuleA
  7.         --load/create the module/frame/objects/stuff
  8.         for x, v in pairs(addonTable.CreateModule) do
  9.             v(ModuleA)
  10.         end
  11.         --feel free to do more
  12.  
  13.         addonTable.Module = ModuleA
  14.     end
  15.     --then delete it
  16.      addonTable.CreateModule.ModuleA = nil
  17. end

Lua Code:
  1. --ModuleA.another  it's in another file
  2. local addonName, addonTable = ...
  3. -- it should only reach this point if it's enabled
  4. function addonTable.CreateModule.ModuleA.another:Load(ModuleA)
  5.     -- load/create the module/frame/objects/stuff
  6. end
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison

Last edited by jeruku : 04-25-17 at 01:24 PM. Reason: #notamorningperson
  Reply With Quote
04-25-17, 12:43 AM   #13
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by jeruku View Post
There is always putting the module init in a function loaded at ADDON_LOADED and have these functions called and removed after first use.
So, in my case, where I use Ace3, it would be:

Core.lua
Lua Code:
  1. local _G = _G;
  2.  
  3. -- Declare addon ------------------------------------------------------------------
  4. local Core = LibStub("AceAddon-3.0"):NewAddon("MyUI_Core", "AceEvent-3.0");
  5. _G.MyUI_Core = Core;
  6.  
  7. -- Defaults db --------------------------------------------------------------------
  8. local defaults = {
  9.     global = {
  10.         modules = {
  11.             Unitframe = true,
  12.             Actionbar = true,
  13.         },
  14.     },
  15. }
  16.  
  17. -- AddOn initialization method ----------------------------------------------------
  18. -- According to Ace3, :OnInitialize() is called after all addons are loaded -------
  19. -- Replaces ADDON_LOADED event from jeruku's example ------------------------------
  20. function Core:OnInitialize()
  21.     self.db = LibStub("AceDB-3.0"):New("MyUIDB", defaults, true);
  22.  
  23.     for k, v in pairs(self.db.global.modules) do
  24.         if not v then
  25.             local module = self:GetModule(k);
  26.  
  27.             module:Disable();
  28.             module = nil;
  29.         end
  30.     end
  31. end

Unitframe.lua
Lua Code:
  1. -- Declare module -----------------------------------------------------------------
  2. local Unitframe = MyUI_Core:NewModule("Unitframe");
  3.  
  4. -- Module codes continued...

But, doesn't this mean it would, at least, go through the lua files once no matter whether the module is enabled/disabled?

Last edited by Layback_ : 04-25-17 at 01:10 AM.
  Reply With Quote
04-25-17, 06:56 AM   #14
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Something like that(?). I do not use Ace so I am trying to wrap my head around it and explain my method.

Basically you wrap your entire module creation code inside a function in a Lua file, this function can be called after saved variables are loaded, thus you can check the saved variable if it is enabled, if it is not you do not call the module creation function, and therefore the function(module) never gets called and goes to garbage collection.

If you want a horribly disgusting abomination of an example you can check out JamPlates Accessories.

I'd like to point out, I'm doing this after waking.
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison

Last edited by jeruku : 04-25-17 at 06:57 AM. Reason: present tense...
  Reply With Quote
04-25-17, 07:35 AM   #15
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by jeruku View Post
Something like that(?). I do not use Ace so I am trying to wrap my head around it and explain my method.

Basically you wrap your entire module creation code inside a function in a Lua file, this function can be called after saved variables are loaded, thus you can check the saved variable if it is enabled, if it is not you do not call the module creation function, and therefore the function(module) never gets called and goes to garbage collection.

If you want a horribly disgusting abomination of an example you can check out JamPlates Accessories.

I'd like to point out, I'm doing this after waking.
So that's same as Lombra's method here.

mmmmmmmmmmmmmmm...

But what if one module is created with several lua files?

Currently, my unitframe module is a combination of unitframe.lua (which I declare module with Ace3), api.lua, config.lua, core.lua, group.lua, player.lua and some element lua files.

Last edited by Layback_ : 04-25-17 at 07:39 AM.
  Reply With Quote
04-25-17, 01:08 PM   #16
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Yes.

And now I feel the fool. Suppose this should be clarified but there are two ways of going about it this way.

One makes it toggled, though for certain features toggles can be dangerous; such as unitframes.
The other involves a reload after enabling/disabling; safer for uniframes and actionbars.

In both options a function for creating a module/feature is used to declare/create the base feature, this function is called after ADDON_LOADED which allows the saved variables to be used. Other Lua files can be used using the shared addonTable(the scoped vararg passed to each Lua file) or globals, though not recommended, where their main function is called in that modules main/core creation function. This then creates that module in a chain reaction when/if the main/core function is called.
Now here is where they differ; in a toggle the function(s) would not be deleted but reserved to toggle on/off without reload, in the second option the function(s) are deleted after use either by nil or written off for garbage collection(a local function not used before EOF, end of file, is deleted) requiring a reload if the module is enabled/disabled.

Hope this helps.

I have updated my previous post to actually show what I am describing in the second option. Apologies for not converting it to Ace.
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison

Last edited by jeruku : 04-25-17 at 01:28 PM. Reason: Edits all around
  Reply With Quote
04-25-17, 04:45 PM   #17
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Layback, you mentioned you use Ace3 to create a core addon and its modules. After poking around with this, I got it to work with SmartRes2 and SmartRes2_Chat.

What I noticed about your example and test code is that you are putting your core addon into the global namespace, which is not necessary, or even desireable. Instead, pull a local reference in the first line of your module code.

Also, AceLocale-3.0 localization tables are extendable (not extensible, you cannot add or modify AceLocale's code). Again, have a look at what I did in both the core and module.

In hindsight, it was remarkably easy, although a lack of good examples was a challenge. But now there is an example

Hopefully this helps, and if you have questions, please ask!
  Reply With Quote
04-25-17, 07:01 PM   #18
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by jeruku View Post
Yes.

And now I feel the fool. Suppose this should be clarified but there are two ways of going about it this way.

One makes it toggled, though for certain features toggles can be dangerous; such as unitframes.
The other involves a reload after enabling/disabling; safer for uniframes and actionbars.

In both options a function for creating a module/feature is used to declare/create the base feature, this function is called after ADDON_LOADED which allows the saved variables to be used. Other Lua files can be used using the shared addonTable(the scoped vararg passed to each Lua file) or globals, though not recommended, where their main function is called in that modules main/core creation function. This then creates that module in a chain reaction when/if the main/core function is called.
Now here is where they differ; in a toggle the function(s) would not be deleted but reserved to toggle on/off without reload, in the second option the function(s) are deleted after use either by nil or written off for garbage collection(a local function not used before EOF, end of file, is deleted) requiring a reload if the module is enabled/disabled.

Hope this helps.

I have updated my previous post to actually show what I am describing in the second option. Apologies for not converting it to Ace.
I really, really and really appreciate your detailed explanations, and you do not need to apologize for not converting it to Ace. It's not your responsibility to do so, but mine

As for unitframe and actionbar, modules that would go into same (core) folder, I would follow your second option as the memory management is definitely a part of my consideration.

Thanks again!
  Reply With Quote
04-25-17, 07:31 PM   #19
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by myrroddin View Post
Layback, you mentioned you use Ace3 to create a core addon and its modules. After poking around with this, I got it to work with SmartRes2 and SmartRes2_Chat.

What I noticed about your example and test code is that you are putting your core addon into the global namespace, which is not necessary, or even desireable. Instead, pull a local reference in the first line of your module code.

Also, AceLocale-3.0 localization tables are extendable (not extensible, you cannot add or modify AceLocale's code). Again, have a look at what I did in both the core and module.

In hindsight, it was remarkably easy, although a lack of good examples was a challenge. But now there is an example

Hopefully this helps, and if you have questions, please ask!
Yeap, I definitely got a question

On SmartRes2, you enable/disable addon and its modules via options panel (with GetModuleEnabled & SetModuleEnabled functions), but doesn't reload ui which means you keeping its functions (since there is not frame). But, what if there were bunch of frames and local functions & tables?

Wouldn't that be a waste of memory?

Here's my working example (prototype) that draws extra power bar on player's screen.


ExtraPower.lua
Lua Code:
  1. -- Declare addon ------------------------------------------------------------------
  2. local ExtraPower = LibStub("AceAddon-3.0"):NewAddon("ExtraPower");
  3.  
  4. -- Defaults db --------------------------------------------------------------------
  5. local defaults = {
  6.     global = {
  7.         power = {
  8.             width = 250,
  9.             height = 15,
  10.             point = {"CENTER", UIParent, "CENTER", 0, -150},
  11.         },
  12.  
  13.         classicon = {
  14.  
  15.         },
  16.     }
  17. }
  18.  
  19. -- AddOn OnInitialize method ------------------------------------------------------
  20. function ExtraPower:OnInitialize()
  21.     self.db = LibStub("AceDB-3.0"):New("ExtraPowerDB", defaults, true);
  22. end

Power.lua
Lua Code:
  1. -- Get addon ----------------------------------------------------------------------
  2. local ExtraPower = LibStub("AceAddon-3.0"):GetAddon("ExtraPower");
  3.  
  4. -- Declare module -----------------------------------------------------------------
  5. local Power = ExtraPower:NewModule("Power");
  6.  
  7. -- Declare & define variables -----------------------------------------------------
  8. local db;
  9.  
  10. local LSM = LibStub("LibSharedMedia-3.0");
  11. local font = LSM:Fetch("font", "MeatEdition");
  12. local statusbar = LSM:Fetch("statusbar", "fer28");
  13.  
  14. local InitBarAndText, UpdateBarAndText;
  15.  
  16. -- Create frame -------------------------------------------------------------------
  17. -- This is here for its event functions -------------------------------------------
  18. do
  19.     local bar = CreateFrame("StatusBar", Power:GetName() .. "Bar", UIParent);
  20.     bar:RegisterEvent("PLAYER_ENTERING_WORLD");
  21.     bar:RegisterUnitEvent("UNIT_POWER_FREQUENT", "player", "vehicle");
  22.  
  23.     Power.bar = bar;
  24. end
  25.  
  26. function InitBarAndText()
  27.     local bar = Power.bar;
  28.  
  29.     bar:SetMinMaxValues(0, 100);
  30.     bar:SetStatusBarTexture(statusbar);
  31.     bar:SetSize(db.power.width, db.power.height);
  32.     bar:SetPoint(unpack(db.power.point));
  33.     bar:SetTemplate(true);
  34.     bar:SetBackground();
  35.  
  36.     bar.playerClass = nil;
  37.  
  38.     local text = bar:CreateFontString("$parentText", "OVERLAY");
  39.     text:SetFont(font, 12, "OUTLINE");
  40.     text:SetAllPoints();
  41.  
  42.     bar.text = text;
  43. end
  44.  
  45. function UpdateBarAndText()
  46.     local bar = Power.bar;
  47.  
  48.     local _, playerClass = UnitClass("player");
  49.  
  50.     local unitPower, unitPowerMax = UnitPower("player"), UnitPowerMax("player");
  51.     local unitPowerPerc = unitPower / unitPowerMax * 100;
  52.  
  53.     if not bar.playerClass or bar.playerClass ~= playerClass then
  54.         local color = RAID_CLASS_COLORS[playerClass];
  55.  
  56.         bar:SetStatusBarColor(color.r, color.g, color.b);
  57.        
  58.         bar.background:SetVertexColor(color.r * 0.25, color.g * 0.25, color.b * 0.25);
  59.  
  60.         bar.text:SetTextColor(color.r, color.g, color.b);
  61.  
  62.         bar.playerClass = playerClass;
  63.     end
  64.  
  65.     bar:SetValue(unitPowerPerc);
  66.  
  67.     bar.text:SetFormattedText("%d (%d%%)", unitPower, unitPowerPerc);
  68. end
  69.  
  70. function Power:OnInitialize()
  71.     db = ExtraPower.db.global;
  72.  
  73.     InitBarAndText();
  74. end
  75.  
  76. function Power.bar:OnEvent(event, ...)
  77.     if event == "PLAYER_ENTERING_WORLD" then
  78.         self:PLAYER_ENTERING_WORLD();
  79.     elseif event == "UNIT_POWER_FREQUENT" then
  80.         self:UNIT_POWER_FREQUENT(...);
  81.     end
  82. end
  83.  
  84. function Power.bar:PLAYER_ENTERING_WORLD()
  85.     UpdateBarAndText();
  86.  
  87.     self:UnregisterEvent("PLAYER_ENTERING_WORLD");
  88. end
  89.  
  90. function Power.bar:UNIT_POWER_FREQUENT(...)
  91.     UpdateBarAndText();
  92. end
  93.  
  94. Power.bar:SetScript("OnEvent", Power.bar.OnEvent);

Last edited by Layback_ : 04-25-17 at 08:31 PM.
  Reply With Quote
04-25-17, 09:25 PM   #20
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
https://www.tutorialspoint.com/lua/l...collection.htm

Set it to nil, and the garbage collector will automatically pick it up when it runs its next cycle.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Any possible/alternative ways to access SV at the top of the file?


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