(10 Kb)
Updated: 10/07/18 11:28 PM
File Info
Murkmire (4.2)
Wolfhunter (4.1)
Updated:10/07/18 11:28 PM
Created:10/03/18 10:28 PM
Monthly downloads:186
Total downloads:190
Version: 3.0
by: silvereyes [More]
A library to manage and migrate to addon settings that support scopes per server, per account and per character, and to allow toggling between scopes on-the-fly.

Should I Use LibSavedVars?

If you answer "yes" to all the below, then LibSavedVars is definitely for you.
  • I am an addon developer
  • I want to add the ability to toggle between server-wide and character-specific saved variables at runtime, without reloading
  • I want to store different settings per megaserver (NA, EU)
  • I want my character-specific settings to survive character name changes.
  • I want to do this all in a standardized way without inventing my own custom logic

How Easy Is LibSavedVars to Use?

LibSavedVars is just as easy to use as ZO_SavedVars, just with some additional functionality.

It will be easiest to implement for the following kinds of addons:
  • Addons that don't yet have any saved vars
  • Addons that only have a single saved var table for player settings
  • Addons that have a single saved var for character settings and a single saved var for account-wide settings, and the state for which one is active for a player is stored within the character settings table.

If your addon falls into one of those two categories, migrating to LibSavedVars should only take a few lines of code beyond including the library.

What LibSavedVars Is NOT For
  • Server-Agnostic Saved Vars

    If you don't need to separate out data between NA and EU because the data you are tracking doesn't change (e.g. furniture lists, item links, coordinate positions, etc), then LibSavedVars isn't going to really provide you with much advantage over the normal "Default" account wide ZO_SavedVars functionality.

  • Addons with complex custom logic for managing saved variable scope between servers

    You are certainly free to rework your addon to use LibSavedVars instead, but it's most likely not going to do everything your custom implementation does.

  • Addons with a saved var for character settings and one for account settings, but the state for which one is active is stored within the account settings table.

    I'll probably add a function in the future to enable account-wide settings on all characters with a simple function call, but it will always retain the ability to disable account-wide settings for an individual character while having them enabled for others.

    LibSavedVars is designed with the idea that account-wide settings represent a player's global default preferences, and character-specific settings act as overrides to those defaults.

    Forcing a player to choose between whether they want global defaults -OR- per-character customization runs counter to the purpose of LibSavedVars.

Planned Features
  • Adding a function and a LibAddonMenu-2.0 button to enable account-wide settings on all characters
  • A standardized data versioning/upgrade system that does not completely clear data when moving to a new settings format
  • Utilities and LibAddonMenu-2.0 controls for copying settings between characters, accounts and servers.

  • Include the unzipped LibSavedVars and LibStub anywhere inside your addon's folder.
  • Add a DependsOn: clause to your addon manifest with LibSavedVars in the list

  • Create two new SavedVariables entries in your addon manifest txt file, one for character settings (e.g. MyAddon_Character), and one for account settings (e.g. MyAddon_Account). If you have any existing SavedVariables entry (e.g. MyAddon_Data) leave it in place.

    ## Title: My Cool Addon
    ## Author: |c99CCEFsilvereyes|r
    ## Description: Example of LibSavedVars usage.
    ## Version: 1.2.0
    ## APIVersion: 100024 100025
    ## DependsOn: LibStub LibSavedVars LibAddonMenu-2.0
    ## SavedVariables: MyAddon_Account
    ## SavedVariables: MyAddon_Character
    ## SavedVariables: MyAddon_Data
  • At the top of your addon's lua code file, load LibSavedVars as a local variable using LibStub:
    Lua Code:
    1. MyAddon = {
    2.     name = "MyAddon",
    3.     defaults = {
    4.         ["setting1"] = "default value"
    5.     }
    6. }
    7. local addon = MyAddon
    8. local LibSavedVars = LibStub("LibSavedVars")
  • Inside an event handler for EVENT_ADD_ON_LOADED in your addon lua code, call local data = LibSavedVars:New() and then save it to a variable your addon methods will have access to. If you had an existing legacy saved var variable before, you should save the new data object to the same variable name, and everything should just work.

    Lua Code:
    1. --[[ Runs once upon login or /reloadui for every addon that is loaded ]]--
    2. local function OnAddonLoaded(event, name)
    4.     -- Only run when this addon is loaded
    5.     if name ~= addon.name then return end
    6.     EVENT_MANAGER:UnregisterForEvent(addon.name, EVENT_ADD_ON_LOADED)
    8.     --[[
    10.      Create ZO_SavedVar instances for account-wide and/or character-specific
    11.      saved vars, per-server, and returns a new data object (See Data.lua) that
    12.      can be used just like a normal ZO_SavedVars object, but can toggle between
    13.      account-wide and character-specific settings on-the-fly.
    15.      The data object can also be used for migrating old ZO_SavedVar instances to
    16.      the server-specific structure using the data:Migrate() method.  
    17.      See below for migration instructions.
    19.      accountSavedVarsName:          Name of the account-wide saved var to create,
    20.                                     or nil. If nil, then characterSavedVarsName
    21.                                     should not be nil.
    23.                                     Should match a name specified with
    24.                                     ## SavedVariables in your manifest.
    26.      characterSavedVarsName:        Name of the character-specific saved var to
    27.                                     create, or nil. If nil, then
    28.                                     accountSavedVarsName should not be nil.
    30.                                     Should match a name specified with
    31.                                     ## SavedVariables in your manifest.
    33.      defaults:                      (optional) Table containing default values
    34.                                     for your saved vars.
    36.      defaultAccountSavedVarsActive: True if account-wide saved vars should be
    37.                                     enabled by default the first time settings
    38.                                     are loaded for a character; false if
    39.                                     character-specific settings should be enabled
    40.                                     by default.
    42.                                     If you plan to use the data:Migrate()
    43.                                     feature, you should pass in true only if your
    44.                                     legacy saved vars were created with
    45.                                     ZO_SavedVars:NewAccountWide().
    46.                                     If your legacy saved vars were created with
    47.                                     ZO_SavedVars:New() or
    48.                                     ZO_SavedVars:NewCharacterIdSettings(), then
    49.                                     you should pass in false.
    50.     ]]--
    51.     local data = LibSavedVars:New(
    52.         addon.name .. "_Account",   -- accountSavedVarsName
    53.         addon.name .. "_Character", -- characterSavedVarsName
    54.         addon.defaults,             -- defaults
    55.         false                       -- defaultAccountSavedVarsActive
    56.     )
    58.     -- use instead of New() for only account-wide vars
    59.     -- LibSavedVars:NewAccountWide(addon.name .. "_Account", addon.defaults)
    61.     -- use instead of New() for only character-specific vars
    62.     -- LibSavedVars:NewCharacterIdSettings(
    63.     --     addon.name .. "_Character", addon.defaults)
    65.     -- We will access saved vars using addon.settings within our methods.  
    66.     -- Replace "addon.settings" with whatever variable you want, as long as it's
    67.     -- scoped to your addon only.
    68.     addon.settings = data
    69. end
    71. -- Wire up addon loaded event
    72. EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_ADD_ON_LOADED, OnAddonLoaded)

Migrating Existing Saved Vars

If you have existing old saved vars data (e.g. MyAddon_Data in the manifest above), LibSavedVars will enable you to move it to the new server-specific SavedVars (e.g. MyAddon_Character and/or MyAddon_Account) with minimal effort using the data:Migrate() method.
  • Call ZO_SavedVar inside your addon loaded event handler, just like before, to create your legacy saved var table.
  • For best performance, it's recommended to remove the "defaults" parameter to ZO_SavedVar. If you don't, ZO_SavedVar will repopulate the table with default junk data every time the addon loaded event fires.
  • Call the data:Migrate() method on your LibSavedVars data object, passing in your legacy saved var as a parameter.
  • If you want to run any transformations on your legacy saved vars immediately before data is migrated for the first time, you can pass in a callback function and any parameters as arguments.
  • After the data is copied, the old saved var table will be emptied (leaving the default "version" value).

Lua Code:
  1. function addon:OnBeforeSavedVarsMigrate(legacySavedVars, param1, param2)
  2.     -- Manipulate the legacySavedVars table here
  3. end
  5. --[[ Runs once upon login or /reloadui for every addon that is loaded ]]--
  6. local function OnAddonLoaded(event, name)
  8.     -- Only run when this addon is loaded
  9.     if name ~= addon.name then return end
  10.     EVENT_MANAGER:UnregisterForEvent(addon.name, EVENT_ADD_ON_LOADED)
  12.     -- Create LibSavedVars data
  13.     local data = LibSavedVars:New(
  14.         addon.name .. "_Account",   -- accountSavedVarsName
  15.         addon.name .. "_Character", -- characterSavedVarsName
  16.         addon.defaults,             -- defaults
  17.         false                       -- defaultAccountSavedVarsActive
  18.     )
  20.     --[[
  21.      Move saved var values from an old legacy saved vars instance into
  22.      appropriate character-specific or account-wide saved vars in this instance.
  24.      Once migrated, the old legacy saved vars are cleared, and a new var called
  25.      libSavedVarsMigrated is set to true. Successived calls to this method will
  26.      not migrate again if legacySavedVars.libSavedVarsMigrated is true.
  28.      If data.dataSource.defaultAccountSavedVarsActive is true, then the values
  29.      are copied to account-wide saved vars for both  NA and EU if on live, or
  30.      just PTS if on PTS, and then cleared.
  32.      If data.dataSource.defaultAccountSavedVarsActive is NOT true, then the
  33.      values are copied to character-specific settings on only the current server,
  34.      and then cleared for the currently logged in user.
  36.      legacySavedVars: The ZO_SavedVars instance to migrate to the new savedvars
  37.                       structure in this instance.
  39.      beforeCallback:  (optional) If specified, raised right before data is
  40.                                  copied, so that any transformations can be run
  41.                                  on the old saved vars table before its values
  42.                                  are moved.
  44.                                  Valid signatures include
  45.                                  function(addon, legacySavedVars, ...), if addon
  46.                                  is not nil, or function(legacySavedVars, ...)
  47.                                  if addon is nil.
  49.      addon:           (optional) If not nil, will be passed as the first
  50.                                  parameter to beforeCallback. Helpful when using
  51.                                  callbacks defined on your addon itself, so you
  52.                                  can access "self".
  54.      ...:             (optional) Any additional parameters passed will be sent
  55.                                  along to beforeCallback(), after the
  56.                                  legacySavedVars parameter.
  57.     ]]--
  58.     local p1 = true
  59.     local p2 = false
  60.     local legacySavedVars = ZO_SavedVars:New(addon.name .. "_Data", 1)
  61.     data:Migrate(legacySavedVars, addon.OnBeforeSavedVarsMigrate, addon, p1, p2)
  62. end
  64. -- Wire up addon loaded event
  65. EVENT_MANAGER:RegisterForEvent(addon.name, EVENT_ADD_ON_LOADED, OnAddonLoaded)

Saved Variable Reading and Writing

The following examples assume your saved vars data object is accessable via addon.settings...

Reading a saved var value:
Lua Code:
  1. local setting1 = addon.settings.setting1
  2. -- OR --
  3. local setting1 = addon.settings["setting1"]

Writing a saved var value:
Lua Code:
  1. addon.settings.setting1 = value
  2. -- OR ---
  3. addon.settings["setting1"] = value

Saved Variable Looping

The following examples assume your saved vars data object is accessable via addon.settings...

Looping with pairs:

Note: an additional key called __dataSource is included as the last key with pairs() and next() iterations. This allows you to access the internal dataSource property in Zgoo, but it is something to keep in mind when looping.
Lua Code:
  1. for key, value in pairs(addon.settings) do
  2.     if key ~= "__dataSource" then
  3.         -- do something
  4.         d("key: "..tostring(key)..", value: "..tostring(value))
  5.     end
  6. end

If you don't want to worry about __dataSource, you can loop the raw saved vars table directly:
Lua Code:
  1. local savedVars = addon.settings:GetActiveSavedVars()
  2. local rawSavedVars = LibSavedVars:GetRawDataTable(savedVars)
  3. for key, value in pairs(rawSavedVars) do
  4.     -- do something
  5.     d("key: "..tostring(key)..", value: "..tostring(value))
  6. end

Looping with next:

Lua Code:
  1. local key, value = next(addon.settings, nil)
  2. while key ~= "__dataSource" then
  3.     -- do something
  4.     d("key: "..tostring(key)..", value: "..tostring(value))
  5.     key, value = next(addon.settings, key)
  6. end

Looping with ipairs:

Lua Code:
  1. for index, value in ipairs(addon.settings) do
  2.     -- do something
  3.     d("index: "..tostring(index)..", value: "..tostring(value))
  4. end

Looping with a counter variable:

Note the use of addon.settings:GetLength() instead of #addon.settings. The # operator is not supported, because it cannot be overloaded on tables in Lua 5.1, which is what ESO uses.
Lua Code:
  1. for index, 1, addon.settings:GetLength() do
  2.     -- do something
  3.     d("index: "..tostring(index)..", value: "..tostring(value))
  4. end

LibAddonMenu-2 Integration
LibSavedVars has a helper method to create the "Account-wide Settings" checkbox in your LibAddonMenu-2 panel, localized for English, French, German, Japanese and Russian.

The following example assumes your saved vars data object is accessable via addon.settings...

Lua Code:
  1. -- Setup options panel
  2.     local LAM2 = LibStub("LibAddonMenu-2.0")
  4.     local panelData = {
  5.         type = "panel",
  6.         name = addon.title,
  7.         displayName = addon.title,
  8.         author = addon.author,
  9.         version = addon.version,
  10.         slashCommand = "/myaddon",
  11.         registerForRefresh = true,
  12.         registerForDefaults = true,
  13.     }
  14.     LAM2:RegisterAddonPanel(addon.name .. "Options", panelData)
  16.     local optionsTable = {
  18.         -- Account-wide settings
  19.         addon.settings:GetLibAddonMenuAccountCheckbox(),
  21.         -- other LAM2 setting options....
  23.     }
  25.     LAM2:RegisterOptionControls(addon.name .. "Options", optionsTable)
Version 3.0

- New methods New(), NewAccountWide() and NewCharacterIdSettings() return a data object that can be used as a 1:1 replacement for ZO_SavedVars instances
- New helper method GetRawDataTable() returns the underlying data table for a ZO_SavedVars instance, since ZO_SavedVars:New() just returns an interface, not the data itself.
- Added usage documentation / comments to all public methods in code.

- Data class features:
* data["key"] and data.key operator support
* data["key"] = value and data.key = value operator support
* next(), pairs() and ipairs() support for iterating saved vars
* GetAccountSavedVarsActive() and SetAccountSavedVarsActive(value) methods for toggling the active scope between account and character-specific settings
* Migrate(legacySavedVars, beforeCallback, addon, ...) method to call directly and control when migration is executed.
* GetActiveSavedVars() method to return a reference to the active ZO_SavedVars instance for the currently logged-in character
* GetLength() returns the # length of the data for the active ZO_SavedVars instance for the currently logged-in character
* GetLibAddonMenuAccountCheckbox() replaces the old library-wide method that took an "addon" parameter.

* Get() Use data["key"] or data.key of the new data class instead.
* Set(value) Use data["key"] = value or data.key = value of the new data class instead.
* Init() Legacy var migration moved to data class. Use data:Migrate() of the new data class and New(), NewAccountWide() and NewCharacterIdSettings() instead.
* GetLibAddonMenuSetting(addon) Use data:GetLibAddonMenuSetting() of the new data class instead.

Version 2
- Fix bug where account wide settings overwrite character settings when toggling in LAM2

Version 1
- Initial release
Optional Files (0)

Archived Files (2)
File Name
10/04/18 10:27 AM
10/03/18 10:28 PM

There have been no comments posted to this file.
Be the first to add one.

Category Jump: