WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   General Authoring Discussion (https://www.wowinterface.com/forums/forumdisplay.php?f=20)
-   -   Toggling modules with proxy table (https://www.wowinterface.com/forums/showthread.php?t=56045)

Layback_ 02-14-18 10:59 PM

Toggling modules with proxy table
 
So, as a part of my small project I'm working on a functionality to toggle modules depending on player's current specialization and here's a brief draft of what I've done so far:

Lua Code:
  1. local specList = {}; -- Proxy
  2. local _specList = {};
  3.  
  4. local f = CreateFrame("Frame");
  5. f:RegisterEvent("PLAYER_LOGIN");
  6. f:SetScript("OnEvent", function(self, event, ...)
  7.     if event == "PLAYER_LOGIN" then
  8.         local currentSpecIndex = GetSpecialization();
  9.  
  10.         for index = 1, GetNumSpecializations() do
  11.             local id = GetSpecializationInfo(index);
  12.  
  13.             _specList[id] = {};
  14.  
  15.             specList[id] = setmetatable({
  16.                 __parent = specList, -- to access parent table
  17.                 _specList = _specList,
  18.             },
  19.             {
  20.                 __index = function(t, k)
  21.                     local specList = t.__parent;
  22.                     local _specList = t._specList;
  23.  
  24.                     for sK, sV in pairs(specList) do
  25.                         if t == sV then
  26.                             for _sK, _sV in pairs(_specList) do
  27.                                 if sK == _sK then
  28.                                     return _sV[k];
  29.                                 end
  30.                             end
  31.                         end
  32.                     end
  33.                 end,
  34.                 __newindex = function(t, k, v)
  35.                     if k == "enabled" and v then
  36.                         local specList = t.__parent;
  37.                         local _specList = t._specList;
  38.  
  39.                         for sK, sV in pairs(specList) do
  40.                             if t == sV then
  41.                                 for _sK, _sV in pairs(_specList) do
  42.                                     _sV.enabled = sK == _sK;
  43.                                 end
  44.  
  45.                                 break;
  46.                             end
  47.                         end
  48.                     end
  49.                 end,
  50.             });
  51.         end
  52.  
  53.         local id = GetSpecializationInfo(currentSpecIndex);
  54.         specList[id].enabled = true;
  55.  
  56.         self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
  57.  
  58.         self:UnregisterEvent("PLAYER_LOGIN");
  59.     elseif event == "ACTIVE_TALENT_GROUP_CHANGED" then
  60.         local id = GetSpecializationInfo(GetSpecialization());
  61.         specList[id].enabled = true;
  62.     end
  63. end);

It's working perfectly well as I expected, BUT all those nasty for loops & if statements look so messy and I'm pretty sure I would forget what the hxxk I've done here in the close future.
(I'll be changing the variable names and leave comments, tho...)

It would be grateful if someone could come up with better ideas.

Thank you!

Ammako 02-14-18 11:36 PM

Couldn't tell for your actual question (and also I don't know what your addon is meant to actually do), but I do notice something right away:

On spec change, you enable the list (module?) for that spec, but don't disable the others (unless there's some dark magic at work in your code that I can't work out.) So if you changed specs multiple times, you'd just end up having everything enabled, rather than toggling according to spec changes.

Might be worth seeing if that's not causing issues, and if it's not, then it can probably be left as-is. I just thought I'd mention it.

Phanx 02-14-18 11:42 PM

I already don't know what the heck you've done there. :p

I'd do something like this very light and totally untested system that uses AceDB and replicates the basic features of AceAddon and AceEvent, plus some specialized logic to automatically toggle modules on and off based on spec:

Lua Code:
  1. -- create addon object:
  2. local MyAddon = CreateFrame("Frame", "MyAddon")
  3.  
  4. -- create table to use as a module registry:
  5. MyAddon.modules = {}
  6.  
  7. -- set up AceEvent-style event handling:
  8. local function eventHandler(self, event, ...) return self[event](self, ...) end
  9. MyAddon:SetScript("OnEvent", eventHandler)
  10. MyAddon:RegisterEvent("PLAYER_LOGIN")
  11.  
  12. -- add module creation:
  13. function MyAddon:NewModule(name, defaults)
  14.     -- make each module its own object with its own event handling:
  15.     local module = CreateFrame("Frame")
  16.     module:SetScript("OnEvent", eventHandler)
  17.  
  18.     if defaults then
  19.         if self.db then
  20.             -- for modules registered after login:
  21.             module.db = self.db:RegisterNamespace(name, defaults)
  22.         else
  23.             -- for modules registered before/during login,
  24.             -- the core db doesn't exist yet, so hold onto it:
  25.             self.pending = self.pending or {}
  26.             self.pending[name] = defaults
  27.         end
  28.     end
  29.  
  30.     -- add it to the registry:
  31.     self.modules[name] = module
  32.  
  33.     -- and pass back a reference to the object:
  34.     return module
  35. end
  36.  
  37. function MyAddon:GetModule(name)
  38.     return self.modules[name]
  39. end
  40.  
  41. -- basically OnInitialize:
  42. function MyAddon:PLAYER_LOGIN()
  43.     -- register the core addon db here:
  44.     local defaults = {
  45.         profile = {
  46.             cats = true,
  47.             dogs = false,
  48.         }
  49.     }
  50.     self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
  51.  
  52.     -- deal with modules registered before/during login:
  53.     if self.pending then
  54.         for name, defaults in pairs(self.pending) do
  55.             local module = self.modules[name]
  56.             module.db = self.db:RegisterNamespace(name, defaults)
  57.         end
  58.         self.pending = nil
  59.     end
  60.  
  61.     -- register your main logic event:
  62.     self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
  63.     self:ACTIVE_TALENT_GROUP_CHANGED()
  64. end
  65.  
  66. -- handle your main logic event:
  67. function MyAddon:ACTIVE_TALENT_GROUP_CHANGED()
  68.     local id = GetSpecializationInfo(GetSpecialization())
  69.     -- go through all the registered modules:
  70.     for name, module in pairs(self.modules) do
  71.         -- and enable or disable them according to whether they match the current spec:
  72.         if module.specID == id then
  73.             module.enabled = true
  74.             module:Enable()
  75.         else
  76.             module:Disable()
  77.             module.enabled = false
  78.         end
  79.     end
  80. end

And then in each module:
Lua Code:
  1. -- create a new module with some default profile settings:
  2. local DruidCatModule = MyAddon:NewModule("DruidCat", {
  3.     profile = {
  4.         fluffy = true,
  5.     }
  6. })
  7.  
  8. -- give it a specID so the core can figure out when to toggle it:
  9. DruidCatModule.specID = 12345 -- note: not the real spell ID!
  10.  
  11. -- and an Enable method the core can call to turn it on:
  12. function DruidCatModule:Enable()
  13.     -- register for events, create frames if they don't exist yet, show frames
  14.  
  15.     -- self.db gives you the module's specific db
  16.  
  17.     -- register an event just like you would in the core or with AceEvent:
  18.     self:RegisterEvent("EXAMPLE_EVENT")
  19. end
  20.  
  21. -- and a Disable method the core can call to turn it off:
  22. function DruidCatModule:Disable()
  23.     -- unregister events, hide frames
  24.  
  25.     self:UnregisterEvent("EXAMPLE_EVENT")
  26. end
  27.  
  28. -- and handle an event like so:
  29. function DruidCatModule:EXAMPLE_EVENT(fakeArg)
  30.     print("This will never happen.")
  31. end

Layback_ 02-14-18 11:57 PM

Quote:

Originally Posted by Ammako (Post 326918)
Couldn't tell for your actual question (and also I don't know what your addon is meant to actually do), but I do notice something right away:

On spec change, you enable the list (module?) for that spec, but don't disable the others (unless there's some dark magic at work in your code that I can't work out.) So if you changed specs multiple times, you'd just end up having everything enabled, rather than toggling according to spec changes.

Might be worth seeing if that's not causing issues, and if it's not, then it can probably be left as-is. I just thought I'd mention it.

Sorry for lack of explanation :rolleyes:

So, it's like how a group of radio buttons would behave.

Let's say I'm a druid and there are 4 different specs. Switching myself to feral from boomy would enable module for feral, but disable all other specs' module (guardian, resto and boomy). This is what I've been working :p

Phanx 02-15-18 12:07 AM

I see you've already replied to the thread, so be aware I've edited the code in my last post several times in the meantime.

Layback_ 02-15-18 12:12 AM

Quote:

Originally Posted by Phanx (Post 326919)
I already don't know what the heck you've done there. :p

To be honest, I really dunno why I posted this LOL...

I surely needed some advice, but was totally aware of that this is just a garbage :p

I'm so embarrassed now :o

Layback_ 02-15-18 12:13 AM

Quote:

Originally Posted by Phanx (Post 326921)
I see you've already replied to the thread, so be aware I've edited the code in my last post several times in the meantime.

Yeap

Thanks for your solution!! :banana:


All times are GMT -6. The time now is 06:51 AM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2020 MMOUI