Wowpedia

We have moved to Warcraft Wiki. Click here for information and the new URL.

READ MORE

Wowpedia
(Replace "Annoyances" section. It is well-defined and completely correct behavior withing event system, partially explained in beginning of article. Replace section with more detailed explanation.)
m (→‎VARIABLES_LOADED event: minor rewording)
Line 103: Line 103:
 
['key2'] = 'value2';
 
['key2'] = 'value2';
 
}
 
}
when your saved variables are loaded, it will overwrite table defined in source by previously saved version that have no 'key2' and therefore, 'key2' won't have default value set.
+
when your saved variables are loaded, saved value of table that have no 'key2' will overwrite table defined in source and, therefore, 'key2' won't have default value set.
   
 
Correct way to initialize default values is to register for VARIABLES_LOADED event, test keys that you want to initialized if they are nil or not and write your default values.
 
Correct way to initialize default values is to register for VARIABLES_LOADED event, test keys that you want to initialized if they are nil or not and write your default values.

Revision as of 11:15, 24 May 2007

SavedVariables.lua

With the exception of a few game-managed properties (slot contents, graphics settings, etc), all custom values which need to be saved between sessions are maintained on the player's computer in a set of .lua files, which are referred to as 'SavedVariables' files. There are three types of SavedVariables files:

  • WTF\Account\ACCOUNTNAME\SavedVariables.lua - "Global" saved settings
  • WTF\Account\ACCOUNTNAME\SavedVariables\AddOnName.lua - Per-account settings for each individual AddOn.
  • WTF\Account\ACCOUNTNAME\RealmName\CharacterName\AddOnName.lua - Per-character settings for each individual AddOn

These files are written whenever the UI engine shuts down (either at game quit, or at the start of a forced UI reload), and then executed when the UI is started and addons are loaded (after logging in or at the end of a forced UI reload).

The SavedVariables.lua files are executed as code (just like your addon code). The time at which they're executed varies slightly by file type -- The AddOn specific SavedVariables files are executed right after the addon they belong to has been loaded, and before the ADDON_LOADED event is fired for the addon. The global SavedVariables.lua file is loaded after all of the initial addons are loaded, before the player is given control, and before the VARIABLES_LOADED event is fired.

When the UI engine shuts down, only those variables which have been marked for saving will be written into the SavedVariables.lua files. A variable can be written to more than one file (though this is generally ill-advised since it can cause settings to be overwritten later on)

Designating variables to save

SavedVariables in AddOn's .toc

The best way is to use the SavedVariables or SavedVariablesPerCharacter keywords in your Addon's .toc file. Thus, an addon with some saved variables would have a .toc like:

## Interface: 1300
## Title: Demo AddOn
## Notes: This is a test to show how to save variables between game sessions
## SavedVariables: Demo_test, Demo_foo
## SavedVariablesPerCharacter: Demo_perchar
Demo.xml

If you have to store lots of pieces data, or data with dynamic keys, wrap it in one or two table variables rather than consuming huge quantities of global namespace.

The ## SavedVariables: heading is used for data you want to be available to your addon no matter which character is playing. ## SavedVariablesPerCharacter: is used for data that you ONLY want to be available to a specific character. There is no way of accessing another character's per-character data, so if you need to access other character's data, then you should use a regular per-addon saved table, and use indexes within that for realm and character.

The RegisterForSave function (Do not use this)

THIS FUNCTION IS NOW RESTRICTED This function is now restricted to Blizzard-signed addons, and addons which depend on it will no longer work.

IMPORTANT: This information is really for reference only, you can not access this functionality from outside Blizzard signed AddOns. Use SavedVariables instead.

LUA code can explicitly request that a variable be saved by calling the RegisterForSave("varName") function with the variable name that should be saved. That variable then becomes flagged for saving at the end of the session. It's important to note that since this is an active process, the variable will only be saved if it is registered during a session, so compilation execution failures that prevent the call from being made will end up without the variable being flagged.

Variables flagged this way go into the global SavedVariables.lua file.

Before the addition of the SavedVariables section in the .toc this was the only way to flag variables for saving, however now use of this function is not recommended unless there's a specific reason for optional saving (and you understand all the risks).

IMPORTANT: "Dynamic variable names" is NEVER a reason to use this function, use a table instead with dynamic keys, i.e.:

 ADDON_SETTINGS = {}
 ADDON_SETTINGS["dynamic" .. something] = value

Using previously saved variables

If your needs are simple, then you just have to mark your variable as saved in the .toc file, and initialize it with a reasonable default value at startup or OnLoad time. If there is a previously saved value, then it will simply overwrite the default one, otherwise the default value will remain. At the end of the play session whatever value it has ended up as will be saved.

If your addon derives configuration from the saved variables, you will likely want to be informed when they've been loaded so the addon can reconfigure itself. In this case create an event handler and register for the "ADDON_LOADED" event, when the arg1 global variable has the name of your addon. Once this is called you can re-check your configuration and set things appropriately.

If your addon is not 'OnDemand' loaded, then you can also just use the "VARIABLES_LOADED" event.

Finally, if you wish to do logic involving both the default and loaded value, you can use a technique as follows:

When the addon sets up the default value, you do:

 Demo_foo = { "bar" }
 local initDemo_foo = Demo_foo;

In your OnLoad handler you add:

 this:RegisterEvent("ADDON_LOADED");

Then, in your OnEvent handler, you have

if ((event == "ADDON_LOADED") and (arg1 == "Demo")) then
  if (initDemo_foo == Demo_foo) then
    -- No change - Must be new user
  else
    -- Changed - Previous user
  end
end

Things that can't be saved

Not all Lua constructs can be saved. For example, inline functions.

function f()
 data = 1
  local function g()
   -- code block
  end
 return { data, g }
end

savedVar = f()  -- will fail to save g

VARIABLES_LOADED event

When working with variables designated for saving, you should not initialized them with table values without paying attention to VARIABLES_LOADED event. Because, as explained in loading sequence above, file with saved variables is processed after code of your addon and because entire table is single value, if you define table with default values like this:

tableName = {
    ['key1'] = 'value1';
}

and later alter the table in source to this:

tableName = {
    ['key1'] = 'value1';
    ['key2'] = 'value2';
}

when your saved variables are loaded, saved value of table that have no 'key2' will overwrite table defined in source and, therefore, 'key2' won't have default value set.

Correct way to initialize default values is to register for VARIABLES_LOADED event, test keys that you want to initialized if they are nil or not and write your default values.

function AddOnName_OnLoad()
    this:RegisterEvent('VARIABLES_LOADED')
end

function AddOnName_OnEvent(event)
    if event == 'VARIABLES_LOADED' then
        if(not tableName.key1) then tableName.key1 = 'value1' end;
        if(not tableName.key2) then tableName.key1 = 'value2' end;
    end
end

Simple values, such as number or strings, still can be initialized without waiting for event if you do not require any additional checks or processing (because you'd be working on your hard-coded values, not on those read from saved file and all you work will be overwritten after that), but for sake of simple maintenance in case your initialization becomes more complex in future, it is advised to use registering for VARIABLES_LOADED event from beginning to save you rewrite or headache of catching elusive bugs later.