Thread Tools Display Modes
12-17-17, 06:35 AM   #1
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Class specific addon?

Hi all,

Just a quick question here.
Would it be possible to create a class specific addon?
I mean of course you can set addons to load from addon control panel for each character, but I want to create something that only loads for specific class.

Currently, I've stated the following lines of code at the top of each Lua files for one of my addon.

Lua Code:
  1. if select(2, UnitClass("player")) ~= "ROGUE" then
  2.     return;
  3. end

Those lines are written on every localization, core, etc and it honestly doesn't mean that the addon "WON'T BE LOADED". The addon would still be loaded, but only skips rest of the code if the class doesn't match.

Would there be any possible solution to this?

Thank you!

Last edited by Layback_ : 12-17-17 at 06:38 AM.
  Reply With Quote
12-17-17, 08:38 AM   #2
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Something like this?

http://wowprogramming.com/docs/api/DisableAddOn
Lua Code:
  1. if select(2, UnitClass("player")) ~= "ROGUE" then
  2.     DisableAddOn(AddonName, CharacterName)
  3.     -- ReloadUI()
  4.     return;
  5. end
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison
  Reply With Quote
12-17-17, 10:10 AM   #3
Ammako
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 256
You can't prevent an addon from loading from within its own code.

jeruku's solution may somewhat work, but it ultimately uses the built-in addon enable/disable feature anyway, and you'd need the user to click to confirm reload ui at login anyway so it wouldn't even be done silently (unless you had the addon stay loaded on first use and then unloaded ever after, but I don't think that's what you want.)

If your addon is only ever intented to work for one class, then your solution is the best you can get short of just marking it disabled for non-rogue characters on character select.
If you had multiple different features in your addon for different classes, what you could do is have a main addon core, with child addons that are class specific and load on demand only when logging into a character of that class.
  Reply With Quote
12-17-17, 01:13 PM   #4
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Combine the 2 solutions. The addon will not run for classes other than Rogue, and will be disabled for those characters after the first log in.
__________________
"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
12-17-17, 05:19 PM   #5
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Thanks to jeruku, Ammako and Seerah.

About jeruku's solution, like Ammako said, the process requires a '/reloadui' and won't be done silently. At first, I also thought of this, but abandoned it due to such reason.

I would probably have a go with what Seerah said or Ammako's second solution!

Last edited by Layback_ : 12-19-17 at 12:49 AM.
  Reply With Quote
12-17-17, 09:00 PM   #6
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Just to be clear...

Lua Code:
  1. local _, class = UnitClass("player")
  2. if class ~= "ROGUE" then
  3.      DisableAddon("YourAddonName")   --you don't need to specify a character here, unless you want to disable for a different character than the one you're on ;)
  4.      return
  5. end
__________________
"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
12-19-17, 01:01 AM   #7
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Seerah View Post
Just to be clear...

Lua Code:
  1. local _, class = UnitClass("player")
  2. if class ~= "ROGUE" then
  3.      DisableAddon("YourAddonName")   --you don't need to specify a character here, unless you want to disable for a different character than the one you're on ;)
  4.      return
  5. end
So, am I doing the right thing?

.TOC
Code:
## Title: Title
## Notes: Note
## Extra Tags: Extra Tag Values
## OptionalDeps: LibStub, CallbackHandler-1.0, Ace3, LibSharedMedia-3.0

Loader.lua

lib\load.xml
media\load.xml
locale\load.xml

Core.lua
Loader.lua
Lua Code:
  1. if select(2, UnitClass("player")) ~= "ROGUE" then
  2.      DisableAddon("YourAddonName");
  3.  
  4.      return;
  5. end

Core.lua
Lua Code:
  1. -- Passed class test :)
  2. code
  3. code
  4. code

I Like the idea, but as Ammako stated, wouldn't this require ReloadUI() to take effect?

I'm currently away from my main PC and can't test this

Last edited by Layback_ : 12-19-17 at 01:04 AM.
  Reply With Quote
12-19-17, 08:57 AM   #8
Ammako
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 256
DisableAddon takes effect right away. Sorta.

The addon will still be loaded the first time, but since you make the code return it won't really run (does return "exit" the addon completely when used outside of a function like this?)

Then if the user logs out and back in, or reloads the UI, the addon will not be loaded, 'cause it was disabled.

So pretty much, it loads the first time but won't run, and on subsequent logins it wont load anymore.

If you preferred, you could still prompt the user to reload ui, or use a popup that asks if they want to reload to disable the addon (this would only show once on first login, of course.)
  Reply With Quote
12-19-17, 11:46 AM   #9
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Sorry about the confusion with ReloadUI. I had thought Petship used ReloadUI but I was wrong. (Answered your question shortly after a reformat of Windows.)

My overall solution is to load everything after all variables are loaded. Doing so means none of it is relevant and only six lines of code are ever loaded or used. If you need an example of how I do it you can take a look at Petship.

Otherwise Ammako's solution will work as well.
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison
  Reply With Quote
12-19-17, 12:41 PM   #10
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
You just need one Lua file. For a real simple, basic example, look at my Forfend.
__________________
"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
12-19-17, 07:38 PM   #11
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Again, many thanks to Ammako, jeruku and Seerah.

I just tested the solution but, hmmmm... ultimately, it still does not fulfill my need.
I mean it's definitely a valid solution.

The reason that I made another Lua file called Loader.lua is because I thought doing so would also prevent those libraries and media files being loaded, but no luck lel...

Like Ammako said, they are not being loaded since the next login or at least with ReloadUI() (after addon being fully disabled).

Perhaps it is impossible to actualize what I want.

Last edited by Layback_ : 12-19-17 at 07:43 PM.
  Reply With Quote
12-19-17, 09:07 PM   #12
Ammako
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 256
It's not something the addon api really supports, no. There is AddonLoader, if that still works, but when your goal is to prevent your addon from being loaded, achieving that by instead loading a different addon probably isn't ideal (and requiring users to download a separate addon is even less practical than just having them disable it )

Just in case this solution can interest you, not sure if this is the best way to do it (I'm not sure if it could potentially introduce taint in rare cases? idk)

lua Code:
  1. StaticPopupDialogs["YOURADDONCONFIRMRELOAD"] = {
  2.     text = "YourAddonName is meant for a different class and has been disabled. Would you like to /reload for it to take effect?",
  3.     button1 = YES,
  4.     button2 = NO,
  5.     OnAccept = function()
  6.         ReloadUI()
  7.     end,
  8.     timeout = 0,
  9.     whileDead = true,
  10.     hideOnEscape = true,
  11.     preferredIndex = STATICPOPUP_NUMDIALOGS,
  12. }
  13.  
  14. local _, class = UnitClass("player")
  15. if class ~= "ROGUE" then
  16.     DisableAddon("YourAddonName")
  17.     StaticPopup_Show("YOURADDONCONFIRMRELOAD")
  18.     return
  19. end

Not tested, but in theory this should prevent your class-specific stuff from running, and it'll give a popup prompt for the user to /reload so they don't have to manually type /reload (or log out/back in) themselves. They also have the option to just say No if they don't care, and the popup won't ever bother them again unless they re-enabled the addon anyway.


Edit: Actually, if you want to think out of the box. You can probably have a separate addon bundled with your actual addon, whose only job is to load the addon itself if the character being played is a rogue.
If that works for addons that are bundled with external libraries, at least.

Something like this:

MyAddonLoader.toc
Code:
## Interface: 70300
## Title: MyAddonLoader
## Notes: Loads the addon if the character is a rogue

MyAddonLoader.lua
MyAddonLoader.lua
lua Code:
  1. local _, class = UnitClass("player")
  2. if class == "ROGUE" then
  3.     LoadAddon(MyAddon)
  4. end

MyAddon.toc
Code:
## Interface: 70300
## Title: MyAddon
## Notes: The actual addon
## LoadOnDemand: 1
## RequiredDeps: MyAddonLoader <-- Maybe not actually required, but w/e

MyAddon.lua
MyAddon.lua
lua Code:
  1. -- Passed class test :)
  2. code
  3. code
  4. code

See if that works, or if that causes issues. All that would be in MyAddonLoader is the .toc and the basic class check test in the .lua, the libraries and everything would be in MyAddon and should only be loaded if the character being played is a rogue?
If that doesn't work, then I guess prompting the user to /reload or having them deal with the addon being loaded once during first login would be the only real solution.

You may want to put the code from MyAddonLoader.lua inside an event handler which fires at PLAYER_LOGIN too (or whenever you are certain that UnitClass can be accessed), in case that could fail and return nil otherwise. But if everything works then you probably don't need to.

Also it looks like you may also have to add the included library dependencies to MyAddon.toc, but I'm not sure which ones you are using or which ones you need (and tbh I've never toyed with that), so you'll have to keep in mind to add that yourself.

Last edited by Ammako : 12-19-17 at 09:30 PM.
  Reply With Quote
12-20-17, 12:52 AM   #13
Nimhfree
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 267
The technique using a LoadOnDemand addon should work. The only issue is you need to package more than one addon together and make sure users understand the role of the LoadOnDemand addon(s) included. You do not need to to disable the LoadOnDemand addon, but be aware that the user could attempt to manually load it, so you should put a check for your class in the start of that addon as well.
  Reply With Quote
12-20-17, 02:22 AM   #14
Ammako
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 256
I don't think LoadOnDemand addons work that way.



Many addons already do this, and an user can't really just decide to go manually load the addon. Unless you get an user who starts typing /script LoadAddon(MyAddon) in chat, at which point honestly it's no-one's problem but their own.

Users don't really need to understand anything, anyway. They just drag and drop the folders to their AddOn folder (or let their Twitch client do it for them, at least.)

And now that I look at it, other addons with bundled libs work fine with LoadOnDemand (InFlight has those), so it should work fine here too.

Last edited by Ammako : 02-18-18 at 07:22 PM.
  Reply With Quote
12-20-17, 05:48 AM   #15
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
@Ammako

Originally Posted by Ammako View Post
Edit: Actually, if you want to think out of the box. You can probably have a separate addon bundled with your actual addon, whose only job is to load the addon itself if the character being played is a rogue.
If that works for addons that are bundled with external libraries, at least.

Something like this:

See if that works, or if that causes issues. All that would be in MyAddonLoader is the .toc and the basic class check test in the .lua, the libraries and everything would be in MyAddon and should only be loaded if the character being played is a rogue?
If that doesn't work, then I guess prompting the user to /reload or having them deal with the addon being loaded once during first login would be the only real solution.
Actually, this was the second solution that I thought after reading jeruku, Seerah and your replies

This definitely worked as I expected, but the reason that I abandoned this, at first, was because I felt it was contradictory to waste a resource by creating another addon to reduce the resource waste of the main addon.

BUT, I did miss a point that I had libraries and media embedded into my addon and thus, creating a separate addon like that would still be much better than those unnecessary libraries and media being loaded

Originally Posted by Ammako View Post
Also it looks like you may also have to add the included library dependencies to MyAddon.toc, but I'm not sure which ones you are using or which ones you need (and tbh I've never toyed with that), so you'll have to keep in mind to add that yourself.
Yeap, I've already stated those OptionalDeps to my TOC

Last edited by Layback_ : 12-20-17 at 06:02 AM.
  Reply With Quote
12-20-17, 11:02 AM   #16
Ammako
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 256
Having an idle five lines of code loaded that only runs once won't really break it for most users, regardless.
  Reply With Quote
12-20-17, 01:39 PM   #17
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
The way the client works is this:

1. Looks at the .toc file to find which files will be used
2. Compiles these Lua/XML files into memory ("loads" them so that the code can be run)
3. Executes (runs) the code in the files, based on load order defined in the .toc

There is no way to skip step 2. But if returning at the start of the file because the player class doesn't match, then the below code does not run (execute) - all that's being used is static memory, the addon doesn't actually do anything. Eventually, iirc, it all gets flushed by the garbage collector because it's not being used. When the addon is disabled, it will not load (compile) at all on the next session - because it's now disabled for that character.

Edit: this is the best way to handle class-specific addons

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

This is how libraries (that use LibStub) work:

1. Addon1 loads libraries A, B, and C.
2. Addon2 then loads libraries A, C, and D.
3. LibStub compares the versions of libraries A and C (the duplicates).
--- if the version of the libraries is more recent in Addon2, it allows the code in these libraries to run, and to be what is shared by the two addons
--- it then tosses its references to the code in the older versions of the libraries - the old code is not used/shared by the addons, and it is eventually flushed by the garbage collector
--- if the version of the libraries is more recent in Addon1, the opposite happens

This is very much like your exit out based on class comparison.
__________________
"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
12-21-17, 06:20 PM   #18
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Hi Seerah,

Originally Posted by Seerah View Post
The way the client works is this:

1. Looks at the .toc file to find which files will be used
2. Compiles these Lua/XML files into memory ("loads" them so that the code can be run)
3. Executes (runs) the code in the files, based on load order defined in the .toc

There is no way to skip step 2. But if returning at the start of the file because the player class doesn't match, then the below code does not run (execute) - all that's being used is static memory, the addon doesn't actually do anything. Eventually, iirc, it all gets flushed by the garbage collector because it's not being used. When the addon is disabled, it will not load (compile) at all on the next session - because it's now disabled for that character.

Edit: this is the best way to handle class-specific addons
So, even if the addon is set to LoadOnDemand, it still compiles and stays idle after step 2?

Originally Posted by Seerah View Post
This is how libraries (that use LibStub) work:

1. Addon1 loads libraries A, B, and C.
2. Addon2 then loads libraries A, C, and D.
3. LibStub compares the versions of libraries A and C (the duplicates).
--- if the version of the libraries is more recent in Addon2, it allows the code in these libraries to run, and to be what is shared by the two addons
--- it then tosses its references to the code in the older versions of the libraries - the old code is not used/shared by the addons, and it is eventually flushed by the garbage collector
--- if the version of the libraries is more recent in Addon1, the opposite happens

This is very much like your exit out based on class comparison.
Yeah, I was aware of how libraries with LibStub work
  Reply With Quote
12-21-17, 07:14 PM   #19
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Late to the party... Why not use AddonLoader? It is here on Wowinterface as well.

Set it up as per its documentation, with its load on tags? Now you don't have to muck around with Lua and trying to figure out how to only load on one class.
  Reply With Quote
12-21-17, 07:59 PM   #20
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Originally Posted by Layback_ View Post
Hi Seerah,
So, even if the addon is set to LoadOnDemand, it still compiles and stays idle after step 2?
No, because it sees in the TOC file in step 1 that the addon is LoD. When it is called with LoadAddOn("AddonName"), then it moves on to step 2 and loads it into memory, then runs it (step 3).

/edit: TOC files are only read when the game client is started up. This is why you need to exit the game completely when editing/changing a TOC file. The TOC file is also where the client gets the addon name from to display in the addon menu at the character select screen.
__________________
"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


Last edited by Seerah : 12-21-17 at 08:01 PM.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Class specific addon?

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