PersistenceWML
NOTE: This feature is currently under active development for Summer of Code. Information contained in this page is not guaranteed to be accurate, may concern planned future developments, and may change significantly without warning.
Purpose
Persistent Variables are used to record information that can be accessed across savegames and session instances.
For instance, assume that completing a campaign on hard mode should unlock a special item in subsequent playthroughs of this campaign. With a persistent variable, that can be recorded, and made available to the campaign on later plays.
This can also be used to allow two or more related campaigns to communicate with each other about what has happened in each, allowing the player's choices in one campaign to influence the state of another.
Overview
Persistent Variables work like normal Variables, with a few differences.
WARNING: in multiplayer, do not use persistent variables in prestart, start, and other non-synchronized events. |
- During multiplayer, Persistent Variables can not be used in events that occur before side 1 turn 1, and will force a quit if they occur there.
- Persistent Variables may be assigned, retrieved, or cleared, but not directly queried.
- Persistent Variables may only be assigned from an existing variable, not directly from a constant
- In addition to a name, each Persistent Variable must have a namespace
- In multiplayer campaigns, each Persistent Variable also requires a side
WML Syntax
The following WML Tags are provided.
[set_global_variable] namespace=my_addon from_local=foo to_global=my_variable_name side=1 [/set_global_variable]
Assigns a persistent variable with the contents of a standard variable
[get_global_variable] namespace=my_addon from_global=my_variable_name to_local=foo side=1 [/get_global_variable]
Retrieves the contents of a persistent variable and stores them in a standard variable. and
[clear_global_variable] namespace=my_addon global=my_variable_name side=1 [/clear_global_variable]
Clears a persistent variable entirely.
Attribute information
namespace
This atribute specifies the name of the namespace that the persistent variable resides in.
- In this attribute, the character "." means "child of",
- A namespace equal to "foo.bar" will access a "bar" namespace inside "foo", creating it if it doesn't already exist, and store the peristent variable inside "bar".
- If this attribute begins with "." it will access a child namespace of the default namespace.
- A namespace equal to ".bar" with the default namespace of "foo" will access a "bar" namespace inside the "foo" namespace.
- In this attribute, the character "^" means "parent of", must follow a namespace and may only be directly followed by a "." or another "^". And is provided so that content creators can easily use macros to eliminate data repitition for the most frequently used namespaces.
- a namespace equal to "{def}^" with the def macro "foo" will access the "foo" namespace.
- a namespace equal to "{def}^" with the def macro "foo.bar" will access the "foo" namespace.
- a namespace equal to "{def}^" with the def macro "foo.bar.test" will access the "bar" namespace. inside the "foo" namespace.
- a namespace equal to "{def}^^" with the def macro "foo.bar.test" will access the "foo" namespace.
- a namespace equal to "{def}^.rod" with the def macro of "foo.bar" will access the "rod" namespace within the "foo" namespace.
- a namespace equal to "{def}^^.rod" with the def macro "foo.bar.test" will access the "rod" namespace within the "foo" namespace.
- a namespace equal to "{def}^.quiz" with the def macro "foo.bar.test" will access the "quiz" namespace within the "rod" namespace within the "foo" namespace.
- a namespace beginning with "^" is invalid and will generate a WML error, because it is impossible to determine the parent of nothing.
*global
These attributes (from_global, to_global, and global) specify the name of the persistent variable to be worked with. The name of the persistent variable must be a valid variable name, as defined in VariablesWML
*local
These attributes (from_local, to_local) specify the name of the standard variable to be worked with.
side
This attribute specifies which player client's persistence data should read from or written to in multiplayer. This attribute is not used in single player, and may be omitted in single-player only scenarios. If this attribute is equal to "global", the currently active player's data will be read in [get_global_variable] operations, and all player's data will be written to in [set_global_variable] and [clear_global_variable] operations.
About Namespaces
Namespaces exist in order to prevent variable collisions from occuring when two or more unrelated campaigns use the same name for some of their persistent variables. A namespace is simply a name that identifies one set of variables. A namespace may contain only alphabetic characters, digits, and underscores.
Internal Separation
Just as variables can contain other variables, namespaces may contain other namespaces. The syntax for this works just like container variables: to refer to a namespace "bar" contained within a namespace "foo", use namespace="foo.bar"
Uniqueness
Because situations may arise where persistent variables from campaigns that are not installed concurrently have to coexist, a namespace should be unique per-context. This means that two unrelated campaigns with the same name should use different namespaces, but two or more related campaigns with different names may use the same namespace.
The following guidelines are provided in order to facilitate this:
Single Standalone Campaign
For a single campaign which is not intended to interact with other campaigns, the format "(author_handle)_(campaign_name)" is suggested for namespaces. As an example, if an author going by "upthorn" in the community were to create a campaign named "foo", the suggested namespace would be "upthorn_foo".
In cases where the author wishes to remain anonymous, or there are many contributing authors (more than say, two or three), the alternate format "(campaign_name)_(month)(year)" is suggested. Using the above example, assuming that upthorn began work on the campaign on the day this wiki page was created, the resulting namespace would be "foo_may2010"
Multiple Related Campaigns
For multiple related campaigns, there are a few different suggested namespace options depending on order of development and the intended level of interaction.
Developed or Conceived Concurrently
If a campaign is intended from the beginning to be part of a larger world of related campaigns, it is recommended that a namespace be created for the overall world, using the format "(author_handle)_(world_name)" for a named author, or "(world_name)_(month)(year)" for an unnamed author. As an example, if an author going by "upthorn" were to begin development on a "hypothetical" world the day this page was created, this would result in a namespace of either "upthorn_hypothetical" or "hypothetical_may2010"
If a campaign in this world is intended to have a high level of interaction, it is recommended that the campaign simply uses the world's namespace as default, and stores any information that it needs to be kept separate in a child namespace of the format "(campaign_name)". Building on the above example, if upthorn made a "foo" campaign in the "hypothetical" world, with high level of intended interactivity with the world, it would use "upthorn_hypothetical" as its default namespace, perhaps occasionally storing information in "upthorn_hypothetical.foo".
If a campaign in this world is intended to have a medium level of interaction, it is recommended that the campaign creates a child namespace of the format "(campaign_name)" in the world's overall namespace, and uses it as default, accessing the parent namespace when it needs to get information from the overall world. Continuing with the above examples, if upthorn made a "bar" campaign in the "hypothetical" world, with mid level of intended interactivity with the world, it would use "upthorn_hypothetical.bar" as its default namespace, and somewhat frequently access information in "upthorn_hypothetical", by using the namespace "^" or explicitly naming "upthorn_hypothetical".
If a campaign in this world is intended to have a low level of interaction, it is recommended that the campaign uses an entirely separate namespace, of the format "(world_namespace)_(campaign)" as its default, and accesses the overall world's namespace when it needs to communicate with the world. Continuing with the above examples, if upthorn made a "fnord" campaign in the "hypothetical" world, with a low level of intended interactivity with the world, it would use "upthorn_hypothetical_fnord" as its default namespace, and occasionally access information in "upthorn_hypothetical", by explicitly naming "upthorn_hypothetical".
Developed Sequentially
In cases where the first campaign is intended as a standalone, but some time after its release the same author, or other authors decide to make other campaigns in the same overall continuity, the first campaign's namespace cannot be changed.
If campaigns are intended to have a high level of interaction, it is recommended that the later campaign uses the namespace of the prior campaign, and makes a child namespace for itself 'if' it needs to save any of its variables separately. As an example, if an author going by "upthorn" developed a campaign "foo" and later developed a related campaign "bar", the "bar" campaign would use "upthorn_foo" as its default namespace, and perhaps occasionally store information in "upthorn_foo.bar"
If campaigns are intended to have a medium level of interaction, it is recommended that the later campaign makes its default namespace a child inside the namespace of the prior campaign that it is most heavily realted to, and accesses the parent namespace when it needs to work with variables from the prior campaign(s). Working from the above example, upthorn's "bar" campaign would use "upthorn_foo.bar" as its default namespace, and somewhat frequently access the "foo" campaign's information in "upthorn_foo", either by setting the namespace attribute to "upthorn_foo" explicitly, or by using "^" to get "upthorn_foo.bar"'s parent.
If campaigns are intended to have a low level of interaction, it is recommended that the later campaign(s) has its own separate namespace using the "Single Standalone Campaign" guideline format, and explicitly name the prior campaign(s)'s namespace(s) for the few times it needs to access them. Working from the above examples, upthorn's "bar" campaign would use "upthorn_bar" as its default namespace, and occasionally access the "foo" campaign's information in "upthorn_foo", by explicitly naming "upthorn_foo" as the namespace.