ESOUI

ESOUI (https://www.esoui.com/forums/index.php)
-   General Authoring Discussion (https://www.esoui.com/forums/forumdisplay.php?f=174)
-   -   Libraries & Saved Variables (https://www.esoui.com/forums/showthread.php?t=4153)

circonian 12/19/14 12:57 AM

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.

votan 12/19/14 02:26 AM

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).

Garkin 12/19/14 05:58 AM

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.

circonian 12/19/14 04:46 PM

Quote:

Originally Posted by votan (Post 17929)
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

circonian 12/19/14 05:10 PM

Quote:

Originally Posted by Garkin (Post 17930)
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?

circonian 12/19/14 05:13 PM

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

Sasky 12/19/14 05:45 PM

Quote:

Originally Posted by circonian (Post 17941)
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.

merlight 12/19/14 05:45 PM

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.

circonian 12/19/14 09:35 PM

Quote:

Originally Posted by merlight (Post 17944)
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?

votan 12/20/14 03:17 AM

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.

sirinsidiator 12/20/14 07:26 AM

Quote:

Originally Posted by circonian (Post 17941)
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.

Garkin 12/20/14 07:52 AM

Quote:

Originally Posted by sirinsidiator (Post 17949)
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


votan 12/20/14 09:10 AM

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.

Garkin 12/20/14 09:57 AM

Quote:

Originally Posted by votan (Post 17951)
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.

votan 12/20/14 10:36 AM

Quote:

Originally Posted by Garkin (Post 17952)
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".

merlight 12/20/14 10:46 AM

@circonioan: I meant not included, sry; edited post

Quote:

Originally Posted by votan (Post 17951)
If I compare Garkin and sirinsidiator, the difference is, that Garkin uses only one ## SavedVariables.

Both methods seem to work, AlphaTools uses two lines.

Quote:

Originally Posted by sirinsidiator (Post 17949)
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.

Garkin 12/20/14 11:00 AM

Quote:

Originally Posted by merlight (Post 17954)
@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.

sirinsidiator 12/20/14 11:20 AM

Quote:

Originally Posted by Garkin (Post 17950)
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.

Quote:

Originally Posted by merlight (Post 17954)
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 :D

merlight 12/20/14 12:03 PM

Quote:

Originally Posted by Garkin (Post 17955)
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.

circonian 12/20/14 07:09 PM

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.


All times are GMT -6. The time now is 09:45 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2014 - 2022 MMOUI