Quantcast Libraries & Saved Variables - ESOUI
Thread Tools Display Modes
12/19/14, 12:57 AM   #1
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 648
Libraries & Saved Variables

I have a couple of addons that work with tracking needed traits & recipes. I was "hoping" to find a way for them to share that information (and with other addons) so they don't all have to do the same work.
I thought about writing a library, which works, but I can not get saved variables to work with it. I figured libraries probably weren't really supposed to be saving things, but was hoping to find a way around it. I managed to get it to save the information, by doing:
Lua Code:
  1. local MAJOR, MINOR = "LibNeed4Research-1.0", 3
  2. local ln4r, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
  3. if not ln4r then return end
  4.  
  5. local function OnAddOnLoaded(_event, _sAddonName)
  6.     if _sAddonName == "ZO_Ingame" then
  7.         ln4r:Initialize()
  8.     end
  9.     ln4r.asv = ZO_SavedVars:NewAccountWide("LibNeed4ResearchVars", 1, nil, varDefaults)
  10.     ACV = ln4r.asv
  11.  
  12.     EVENT_MANAGER:UnregisterForEvent("LibNeed4Research", EVENT_ADD_ON_LOADED)
  13. end
  14. EVENT_MANAGER:RegisterForEvent("LibNeed4Research", EVENT_ADD_ON_LOADED, OnAddOnLoaded)
It creates a saved variable file & writes to it, but it seems like it won't reload it. It seems like it is reinitializing the varDefaults variables every time. I'm guessing its just not possible?
I tried to look at the zo_savedvars.lua to figure out how it is loaded to see what is wrong, but I didn't quite understand it all.

So before I give up on it and scrap the whole thing I figured I'de give it a shot and ask.
Is this possible to do somehow without installing it as a stand alone addon? I just don't know if people would want to bother with installing some separate addon that does nothing but track data.
  Reply With Quote
12/19/14, 02:26 AM   #2
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 498
Edit: I just looked a bit closer to your code:
Maybe you are calling ZO_SavedVars:NewAccountWide a bit too early. What if the addon is not "ZO_Ingame"? You do not exit. Instead you unregister as soon as the first event is called.

If it still wont work, I think this will work using the library as a stand-alone addon having its own manifest file, only.
Because you have to register the variable to be saved and reloaded. And this seems to be a "security feature".
As soon as using the "embedded style", it is "just" some code.

One way, which may works is to use a global variable, which is referenced by the save-variable of all addons. While loading it must be part of the library to copy the data from any addon to that global variable. (Using a timestamp to get the most recent data). Really a copy, not changing the reference to another variable.
Redundant on disk, I know.

Something like:
Lua Code:
  1. addon_savevar.trackData = ln4r:GetSavedVariable(addon_savevar.trackData)
addon_savevar.trackData can be nil the first time.
addon_savevar.trackData contains a timestamp managed by the library.
ln4r:GetSavedVariable takes over the data or not, depending on the timestamp, and always returns the shared variable (=lua table).
__________________
@votan73 (EU - megaserver)

Last edited by votan : 12/19/14 at 04:22 AM.
  Reply With Quote
12/19/14, 05:58 AM   #3
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 853
SavedVariables are available when EVENT_ADD_ON_LOADED is triggered for your addon, not sooner. If you try to use saved variables when the ZO_Ingame is loaded, your variables are not ready yet and will be overwritten when initialized.

Loading order of addons is always:
1 - ZO_IngameLocalization
2 - ZO_Libraries
3 - ZO_Common
4 - ZO_Ingame
5 - from here starts your addons in (probably) random order


As votan said - if you want to have saved variables, you must specify global reference in addon manifest. If you have addon manifest, EVENT_ADD_ON_LOADED will be triggered for your library, so you can use it.
__________________
@Garkin (retired from ESO)
My addons: SkyShards, LoreBooks, Dustman, Map Coordinates, No, thank you!, ... (full list)
  Reply With Quote
12/19/14, 04:46 PM   #4
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 648
Originally Posted by votan View Post
Edit: I just looked a bit closer to your code:
Maybe you are calling ZO_SavedVars:NewAccountWide a bit too early. What if the addon is not "ZO_Ingame"? You do not exit. Instead you unregister as soon as the first event is called.
Doh, yeah of course, that is why its all getting overwritten. I had changed code around so many times. I was originally grabbing the saved vars in the ln4r:Initialize(). I was just moving things around trying to figure out a way to make it work and didn't even notice that. Thanks
  Reply With Quote
12/19/14, 05:10 PM   #5
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 648
Originally Posted by Garkin View Post
SavedVariables are available when EVENT_ADD_ON_LOADED is triggered for your addon, not sooner. If you try to use saved variables when the ZO_Ingame is loaded, your variables are not ready yet and will be overwritten when initialized.

Loading order of addons is always:
1 - ZO_IngameLocalization
2 - ZO_Libraries
3 - ZO_Common
4 - ZO_Ingame
5 - from here starts your addons in (probably) random order


As votan said - if you want to have saved variables, you must specify global reference in addon manifest. If you have addon manifest, EVENT_ADD_ON_LOADED will be triggered for your library, so you can use it.
Awesome, thanks again for the help!

Well it could use a little more testing but so far it seems like I managed to get it to work using the library with two different addons.
I managed to get it to work by doing this specifying two SavedVariables & the path to the library in each addon.
Lua Code:
  1. ## Title: Click4Info
  2. ## APIVersion: 100010
  3. ## OptionalDependsOn: LibAddonMenu-2.0
  4. ## SavedVariables: Click4InfoSavedVars
  5. ## SavedVariables: Need4ResearchVars
  6. ## Version: 1.5
  7. ## Author: Circonian
  8. ## Description: Circonians Click4Info Version 1.5
  9.  
  10. libs\LibStub\LibStub.lua
  11. libs\LibNeed4Research\LibNeed4Research.lua

and then having the library load when the addon that contains it is loaded (I had to manually put the addons name in there though):
Lua Code:
  1. -- This is code from the library file, not the addon
  2. local function OnAddOnLoaded(_event, _sAddonName)
  3.         -- had to manually change this to the owning addon
  4.     if _sAddonName == Click4Info.name then
  5.         ln4r:Initialize()
  6.     end
  7. end
  8. function ln4r:Initialize()
  9.     ln4r.AccountSavedVariables = ZO_SavedVars:NewAccountWide("LibNeed4ResearchVars", 1, nil, varDefaults)
  10.     ASV = ln4r.AccountSavedVariables
  11.     UpdateTables()
  12.     EVENT_MANAGER:UnregisterForEvent("LibNeed4Research", EVENT_ADD_ON_LOADED)
  13. end

It reads & writes the saved variables to each of the addons saved variable files and that will work just fine for me & my addons. But I was wondering if there is any way to grab the addon name that is loading the library?
Some way to be able to set the addon name dynamically in the libraries OnAddOnLoaded :
Lua Code:
  1. -- This is the one in my library file.
  2. local function OnAddOnLoaded(_event, _sAddonName)
  3.     if _sAddonName == <to set this to the owning addons name> then
  4.         ln4r:Initialize()
  5.     end
  6. end
So that addon developers don't have to modify the library file to put their addon name in there?
  Reply With Quote
12/19/14, 05:13 PM   #6
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 648
I guess at the very least if there is no way to grab the addon name for the addon that is loading the library I could have them manually call an initialize function for the library (Instead of using EVENT_ADD_ON_LOADED) and just use a flag to make sure the initialize code only gets run once.
Lua Code:
  1. local bHasBeenInitialized = false
  2.  
  3. function LibNeed4ResearchInitialize()
  4.     if bHasBeenInitialized then return end
  5.     bHasBeenInitialized = true
  6.    
  7.     ln4r.AccountSavedVariables = ZO_SavedVars:NewAccountWide("Need4ResearchVars", 1, nil, varDefaults)
  8.     ASV = ln4r.AccountSavedVariables
  9.     UpdateTables()
  10.     EVENT_MANAGER:UnregisterForEvent("LibNeed4Research", EVENT_ADD_ON_LOADED)
  11. end

Last edited by circonian : 12/19/14 at 05:15 PM.
  Reply With Quote
12/19/14, 05:45 PM   #7
Sasky
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 241
Originally Posted by circonian View Post
It reads & writes the saved variables to each of the addons saved variable files and that will work just fine for me & my addons. But I was wondering if there is any way to grab the addon name that is loading the library?
Some way to be able to set the addon name dynamically in the libraries OnAddOnLoaded ... So that addon developers don't have to modify the library file to put their addon name in there?

1) Use EVENT_PLAYER_ACTIVATED instead. The drawback is you can't actually use the data before then. For research data, that might not be an issue.

1b) If users do need some sort of activate-level code on it, you could register callbacks to be fired when the SavedVariables is available. You could either write your own callback manager or use a ZO_CallbackObject (either your own or even EVENT_MANAGER).

2) The manual initialization function would work. Either set it as an explicit .init() or require users to only instantiate your library during the init function or later.

3) If Minion ever handles dependencies, you could just create it stand-alone. I know it was mentioned awhile back as a feature they were looking at doing, but who knows the timeline for that.

Last edited by Sasky : 12/19/14 at 05:47 PM.
  Reply With Quote
12/19/14, 05:45 PM   #8
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 679
You'll be better off having the library not optional and not included in each addon using it, but a stand-alone lib-addon with its own saved vars.

edit: sorry, I meant not included That's what happens when I re-word a sentence 3 times before posting.

Last edited by merlight : 12/20/14 at 10:37 AM.
  Reply With Quote
12/19/14, 09:35 PM   #9
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 648
Originally Posted by merlight View Post
You'll be better off having the library not optional and included in each addon using it, but a stand-alone lib-addon with its own saved vars.
You said stand-alone and included in each addon using it, what do you mean? Do you mean they would just zip both addon folders together in a single zip & upload it as their addon?
  Reply With Quote
12/20/14, 03:17 AM   #10
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 498
Hi alltogether,

as far as I understood we need a registered/whitelisted variable name and an addon it belongs to, right?
Why not using a build-in variable? I would suggest to write a generic framework (Maybe as part of LibStub?)

This is working Proof of Concept code:
Lua Code:
  1. local varDefaults = { Test = "1234" }
  2. local asv
  3.  
  4. SLASH_COMMANDS["/test1"] = function() asv.Test = GetTimeStamp() end
  5. SLASH_COMMANDS["/test2"] = function() d(asv.Test) end
  6.  
  7. local function OnAddOnLoaded(event, addonName)
  8.   if addonName == "ZO_Ingame" then
  9.     EVENT_MANAGER:UnregisterForEvent("CommonAddonLibrary", EVENT_ADD_ON_LOADED)
  10.     asv = ZO_SavedVars:NewAccountWide("ZO_Ingame_SavedVariables", 1, "CommonAddonLibrary", varDefaults)
  11.   end
  12. end
  13.  
  14. EVENT_MANAGER:RegisterForEvent("CommonAddonLibrary", EVENT_ADD_ON_LOADED, OnAddOnLoaded)

Edit: The root section (here CommonAddonLibrary) should have a very unique name, handled by the framework only. Addon authors using the framework can register sub-sections, only. To avoid conflict with names used by ZO.
__________________
@votan73 (EU - megaserver)

Last edited by votan : 12/20/14 at 07:48 AM.
  Reply With Quote
12/20/14, 07:26 AM   #11
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,290
Originally Posted by circonian View Post
I managed to get it to work by doing this specifying two SavedVariables & the path to the library in each addon.
Lua Code:
  1. ## Title: Click4Info
  2. ## APIVersion: 100010
  3. ## OptionalDependsOn: LibAddonMenu-2.0
  4. ## SavedVariables: Click4InfoSavedVars
  5. ## SavedVariables: Need4ResearchVars
I tried to use two saved variables in one addon before, but it randomly failed to save them on ui reloads.
__________________
Like what I do? Support me on Patreon!
>siri.exe MyAddon
Does your addon work? [y/n] n
There is a typo in there.
  Reply With Quote
12/20/14, 07:52 AM   #12
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 853
Originally Posted by sirinsidiator View Post
I tried to use two saved variables in one addon before, but it randomly failed to save them on ui reloads.
I'm using two saved variables in LoreBooks since v0.3 (22.4.2014) and I had not a single issue with that.


Code:
## Title: |cEFEBBELoreBooks|r 1.4.5
## Description: This addon displays map pins for Shalidor's Library books.
## Version: 1.4.5
## Author: |cEFEBBEGarkin|r
## APIVersion: 100010
## SavedVariables: LBooks_SavedVariables LBooksData_SavedVariables
## OptionalDependsOn: LibAddonMenu-2.0 LibMapPins-1.0 CustomCompassPins
__________________
@Garkin (retired from ESO)
My addons: SkyShards, LoreBooks, Dustman, Map Coordinates, No, thank you!, ... (full list)
  Reply With Quote
12/20/14, 09:10 AM   #13
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 498
If I compare Garkin and sirinsidiator, the difference is, that Garkin uses only one ## SavedVariables.
If more than one saved variable can be specified, sharing data should be possible, by simply using a shared variable name.

tja.
__________________
@votan73 (EU - megaserver)
  Reply With Quote
12/20/14, 09:57 AM   #14
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 853
Originally Posted by votan View Post
If I compare Garkin and sirinsidiator, the difference is, that Garkin uses only one ## SavedVariables.
If more than one saved variable can be specified, sharing data should be possible, by simply using a shared variable name.

tja.
This is how it does default UI. It has just one global name for saved variables defined in manifest:

from Ingame.txt:
Code:
; Ingame Script Files
## DependsOn: ZO_IngameLocalization ZO_Common

## SavedVariables: ZO_Ingame_SavedVariables
And then each part of the UI uses the same variable with different namespace:
Lua Code:
  1. --Provisioner.lua:
  2. self.savedVars = ZO_SavedVars:New("ZO_Ingame_SavedVariables", 1, "Provisioner", defaults)
  3.  
  4. --SmithingCreation.lua:
  5. self.savedVars = ZO_SavedVars:New("ZO_Ingame_SavedVariables", 2, "SmithingCreation", defaults)
  6.  
  7. --WorldMap.lua:
  8. g_savedVars = ZO_SavedVars:New("ZO_Ingame_SavedVariables", 4, "WorldMap", defaults)
  9.  
  10. --etc.

All you need is some data sharing addon (because of manifest) where you define global variable name for saved variables. But as you said, it is possible to use "ZO_Ingame_SavedVariables" instead which will be always available as default UI is loaded first. You should just use unique namespace for the data.
__________________
@Garkin (retired from ESO)
My addons: SkyShards, LoreBooks, Dustman, Map Coordinates, No, thank you!, ... (full list)
  Reply With Quote
12/20/14, 10:36 AM   #15
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 498
Originally Posted by Garkin View Post
All you need is some data sharing addon (because of manifest) where you define global variable name for saved variables. But as you said, it is possible to use "ZO_Ingame_SavedVariables" instead which will be always available as default UI is loaded first. You should just use unique namespace for the data.
Thanks Garkin, that you can agree
The unique namespace is the reason why I think this should be handled by a framework/library.

I just tested: Using a shared saved variable name in different addon manifests results in what I mentioned first: The content is redundant saved for each addon. Which could be problematic if one addon has been disabled for a while.

@circonian: The answer is: You can use data sharing addon (which is what you want to avoid) or a unique namespace in "ZO_Ingame_SavedVariables".
__________________
@votan73 (EU - megaserver)
  Reply With Quote
12/20/14, 10:46 AM   #16
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 679
@circonioan: I meant not included, sry; edited post

Originally Posted by votan View Post
If I compare Garkin and sirinsidiator, the difference is, that Garkin uses only one ## SavedVariables.
Both methods seem to work, AlphaTools uses two lines.

Originally Posted by sirinsidiator View Post
I tried to use two saved variables in one addon before, but it randomly failed to save them on ui reloads.
I've encountered a nasty bug with using two saved variables. If any of them is not present in the saved file already and you don't create it upon load, the file will subsequently be saved corrupted - with the variable you did create appended to it instead of replaced. That way my AddonProfiles.lua grew over 2.5MB, having over 300 copies of the variable, while its usual size is ~10k.
  Reply With Quote
12/20/14, 11:00 AM   #17
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 853
Originally Posted by merlight View Post
@circonioan: I meant not included, sry; edited post



Both methods seem to work, AlphaTools uses two lines.



I've encountered a nasty bug with using two saved variables. If any of them is not present in the saved file already and you don't create it upon load, the file will subsequently be saved corrupted - with the variable you did create appended to it instead of replaced. That way my AddonProfiles.lua grew over 2.5MB, having over 300 copies of the variable, while its usual size is ~10k.
I'm not sure if it is a bug. If you separate variable names by comma, it will behave as you have descrbed. But all items in addon manifest has to be space separated, there shouldn't be any other character.
__________________
@Garkin (retired from ESO)
My addons: SkyShards, LoreBooks, Dustman, Map Coordinates, No, thank you!, ... (full list)
  Reply With Quote
12/20/14, 11:20 AM   #18
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,290
Originally Posted by Garkin View Post
I'm using two saved variables in LoreBooks since v0.3 (22.4.2014) and I had not a single issue with that.
Maybe the problem occurred because I don't use the ZO_SavedVars class. I have tested different structures to the table over a month, but never found out what caused it to not save the state.
Sometimes it worked for days and sometimes it deleted everything on every second ui reload.

Originally Posted by merlight View Post
I've encountered a nasty bug with using two saved variables. If any of them is not present in the saved file already and you don't create it upon load, the file will subsequently be saved corrupted - with the variable you did create appended to it instead of replaced. That way my AddonProfiles.lua grew over 2.5MB, having over 300 copies of the variable, while its usual size is ~10k.
Also they don't seem to protect against recursions. had the client fill my harddisk with 7.5GB of the same table once
__________________
Like what I do? Support me on Patreon!
>siri.exe MyAddon
Does your addon work? [y/n] n
There is a typo in there.
  Reply With Quote
12/20/14, 12:03 PM   #19
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 679
Originally Posted by Garkin View Post
I'm not sure if it is a bug. If you separate variable names by comma, it will behave as you have descrbed. But all items in addon manifest has to be space separated, there shouldn't be any other character.
Having the same variable repeated over and over in the saved file looks like a bug to me. It's easily replicable - simply prepend an arbitrary variable name to your manifest (like this ## SavedVariables: NonexistentNonsense MyRealSavedVariable), don't create the first variable in the addon, and you'll see your saved file grow.
  Reply With Quote
12/20/14, 07:09 PM   #20
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 648
I don't think what I wanted is possible. I know some of you were already saying that. I'm mainly posting this for anyone else interested who reads this post.

I ran into another problem. Although I can get the library to work with multiple addons reading & writing the saved variables to each addons saved variable file doing the above. I realized that if a user installed a NEW addon that had the library included AND that addon got loaded first, it would have no saved variables yet for that saved variable table and thus wipe out all saved variables when it is loaded.

So I guess stand alone with its own saved variables would be the only way.

Thanks again everyone for all of your advice.
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » Libraries & Saved Variables

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