View Single Post
08/03/16, 08:35 AM   #1
Ayantir
 
Ayantir's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 1,019
SavedVariables, ZO_SavedVars, AccountWide, per character and name changes

Hello,

A little tutorial and things to known on savedvars.



First, what is savedvars ?

A savedVariable is a Lua variable which is dumped into a text file.
A savedVariable MUST be a table.
Elements in the table can be number, string, boolean, or table.
Functions cannot be dumped, nil values are stripped.



Why using savedvariables ?

As long as we cannot save almost nothing on TESO DB on the server, the settings or other data which should persists must be stored somewhere, so here are the SavedVars.



Where are they ?

There are in Elder Scrolls Online\{environnement}\SavedVariables.
Basically, it's Documents\Elder Scrolls Online\live(eu)\SavedVariables
More info is on the Wiki : http://wiki.esoui.com/UserFolder



Which file and what name ?

The file have the name of your Addon metafile
If your metafile is Something.txt, the Savedvariable file wille be Something.lua



How can I enable a variable to be saved ?

You can add this to the metafile
Code:
## SavedVariables: var1 var2 var3 var4 var5


I want my settings have a default value, be set by character, or accunt wide

ZOS give us an object to play more easily with saved vars.
Please note this is totally optionnal.

If in your code you do
Lua Code:
  1. var1 = "foo"
without anything else than the line in metafile, the data will be saved as is.

But if you need some help to manage your SV, you should use the ZO_SavedVars object.



How ?

1) your defaults array. it will contain the defaults values. If an user don't have SV, the whole content will be sent as "template". If you just added one subvariable, the new one will be pushed in and the existing ones won't be changed.

Lua Code:
  1. local defaults = {
  2.     something = true,
  3.     somethingElse = false,
  4. }

A first try will be :

Lua Code:
  1. local db
  2. local ADDON_NAME = "DummyAddon"
  3.  
  4. -- Initialises the settings and menu
  5. local function onAddonLoaded(_, addonName)
  6.  
  7.     --Protect
  8.     if addonName == ADDON_NAME then
  9.        
  10.         --Default values for the SavedVariables
  11.         local defaults = {
  12.             keepAmount      = 0,
  13.             fillUpAmount    = 0,
  14.         }
  15.  
  16.         -- Fetch the saved variables
  17.         db = ZO_SavedVars:NewAccountWide("THE_NAME_OF_THE_VAR_IN_METAFILE", SV_VERSION_NAME, nil, defaults)
  18.  
  19.                  -- some code

This code will "link" the local db variable to the Savedvariable THE_NAME_OF_THE_VAR_IN_METAFILE.
If a value doesn't exist in THE_NAME_OF_THE_VAR_IN_METAFILE, the constructor will fetch it from the defaults variable.

please note if db and default should remain "local", THE_NAME_OF_THE_VAR_IN_METAFILE is leaked to _G (you can inspect it).

changing db will change THE_NAME_OF_THE_VAR_IN_METAFILE.



Methods
  1. ZO_SavedVars:NewAccountWide will save the data in an account wide array. It don't support account name changes.
    The key is GetDisplayName()

    ex, the Roomba addon :

    Lua Code:
    1. ROOMBA_OPTS =
    2. {
    3.     ["Default"] =
    4.     {
    5.         ["@Ayantir"] =
    6.         {
    7.             ["$AccountWide"] =
    8.             {
    9.                 ["RoombaPosition"] = 3,
    10.                 ["RoombaAtBank"] = true,
    11.                 ["RoombaAtGBank"] = true,
    12.                 ["version"] = 1,
    13.                 ["RoombaInBag"] = true,
    14.             },
    15.         },
    16.     },
    17. }

  2. ZO_SavedVars:New will save the data in an character wide array. It don't support name changes.
    The key is GetUnitName("player")
  3. ZO_SavedVars:NewCharacterNameSettings will save the data in an character wide array. It support name changes.
    The key is GetUnitName("player") This key will change after a character rename.

    ex, the RollingStones addon :

    Lua Code:
    1. ROLLINGSTONES =
    2. {
    3.     ["Default"] =
    4.     {
    5.         ["@Ayantir"] =
    6.         {
    7.             ["Ayantir"] =
    8.             {
    9.                 ["version"] = 1.2000000000,
    10.                 ["keepAmount"] = 0,
    11.                 ["fillUpAmount"] = 0,
    12.             },
    13.         },
    14.     },
    15. }
  4. ZO_SavedVars:NewCharacterIdSettings will save the data in an character wide array. It support name changes.
    The key is GetCurrentCharacterId()

    Lua Code:
    1. ROLLINGSTONES =
    2. {
    3.     ["Default"] =
    4.     {
    5.         ["@Ayantir"] =
    6.         {
    7.             ["8798292046256355"] =
    8.             {
    9.                 ["$LastCharacterName"] = "Ayantir",
    10.                 ["version"] = 1.2000000000,
    11.                 ["keepAmount"] = 0,
    12.                 ["fillUpAmount"] = 0,
    13.             },
    14.         },
    15.     },
    16. }



SavedVars versioning

the 2nd parameter, version is a key (string or number) to push the defaults array even if an old value existed before. It erase old data.

Avoid if possible changing version. You should only change version when there is an absolute need. (addon rewrited entirely, api bump).

This action lead to reset all user config.

Ex :

Before :

Lua Code:
  1. savedVarsVersion    = 1.2,
  2.         local defaults = {
  3.             keepAmount      = 0,
  4.             fillUpAmount    = 0,
  5.         }
  6.  
  7. ROLLINGSTONES =
  8. {
  9.     ["Default"] =
  10.     {
  11.         ["@Ayantir"] =
  12.         {
  13.             ["8798292046256355"] =
  14.             {
  15.                 ["$LastCharacterName"] = "Ayantir",
  16.                 ["keepAmount"] = 0,
  17.                 ["fillUpAmount"] = 0,
  18.                 ["version"] = 1.2000000000,
  19.             },
  20.         },
  21.     },
  22. }


After :

Lua Code:
  1. savedVarsVersion    = 1.3,
  2.         --Default values for the SavedVariables
  3.         local defaults = {
  4.             keepAmount      = 10,
  5.         }
  6.  
  7. ROLLINGSTONES =
  8. {
  9.     ["Default"] =
  10.     {
  11.         ["@Ayantir"] =
  12.         {
  13.             ["8798292046256355"] =
  14.             {
  15.                 ["$LastCharacterName"] = "Ayantir",
  16.                 ["keepAmount"] = 10,
  17.                 ["version"] = 1.3000000000,
  18.             },
  19.         },
  20.     },
  21. }


Limitations

32bits client has the inherent limitations of the 32Bits allocation memory.
  • Max file = 4GB (consider that a HUGE SV is 1MB+)
  • Max values stored = Avoid more than 10k entries per level. Avoid files of more than 30MB. If you addon dump more than this, data can be corrupted.

Both 32 & 64 bits :

Max length of string variable : 1000 characters. if your string variable is more than 1000 bytes, it won't be saved


When is the file written ?

The fle is written when the UI Reloads.

Lua ReloadUI()
Lua SetCVar() -- ONLY if it trigger a reload UI (a loading screen).
Lua LogOut()
Lua Quit()
Windows Alt+F4
Clicking on the red X of the ESO window
When Game kicks you on the loading screen



Killing Process -> DATA NOT SAVED
CRASH -> DATA NOT SAVED




Bugs

Having multiple Vars set in a same metafile is dangerous.

If you want to have multiple SV please never do assignment between the variables (no var1 = var2 or any subkey of any variables)

With

Code:
## SavedVariables: var1 var2
if you do :

Lua Code:
  1. var1 = {key1 = "something", key2 = "something else"}
  2. var2 = "foo"
  3. var1.key2 = var2

var2 will be nil in SV. (var1.key2 steal the value).

If you want to do this, consider a table which embed both tables.



Recursivity, 4GB file and crashs

As in a lot of languages, Lua accept recursive calls, but if you try to save a var which contain a recursive call, it will crash your game.

For this, you must :
  • kill the recursivity before saving the var
  • or build a symetric var without recursivity <- Consider THIS as the best solution

If you play with ZOS datalists, you may consider the dataEntry recursive call. here are 2 screenshots of var which shouldn't be saved in SV.




Last edited by Ayantir : 12/10/16 at 08:42 PM.
  Reply With Quote