NarraLeaf

Storable

Storable allows you to store data in the game's state. Data stored in Storable will be saved and loaded with current game state.

If you are looking for creating actions to operate data, you can use Persistent abstraction.

Data stored in Storable are separated by namespace. You can use the same key in different namespaces.
For example, you can store the player1's name in the player1 namespace and the player2's name in the player2 namespace.

Namespace game is already defined and can store data, you can add your own by instantiating a new Namespace.

For example, create a new namespace player1 and store the player1's name in it:

type Player1Content = {
    name: string;
};

const storable = game.getLiveGame().getStorable();

// initialize and register a namespace
const player1namespace = Storable.createNamespace<Player1Content>("player1", {
    name: "default name",
});

storable.addNamespace(player1namespace);

// set data from the namespace
const namespace = storable.getNamespace<Player1Content>('player1');
namespace.set('name', 'John Doe');

// get data from the namespace
const name = namespace.get('name');
console.log(name); // John Doe

Static Methods

createNamespace<T extends NameSpaceContent<keyof T>>

Create a new namespace

  • name: string - Human-readable name of the namespace
  • initContent: T - Initial content of the namespace
  • key?: string - The namespace key, default is the name
  • Returns Namespace<T>

Public Properties

events

Public Methods

addNamespace<T extends NameSpaceContent<keyof T>>

  • namespace: Namespace<T>
  • Returns this

getNamespace<T extends NameSpaceContent<keyof T> = any>

  • key: string - The namespace key
  • Returns Namespace<T>

setNamespace<T extends NameSpaceContent<keyof T> = any>

  • key: string - The namespace key
  • namespace: Namespace<T>
  • Returns this

getNamespaces

  • Returns { [key: string]: Namespace<any>; }

hasNamespace

  • key: string
  • Returns boolean

removeNamespace

  • key: string
  • Returns this

keys

  • Returns string[]

values

  • Returns Namespace<any>[]

entries

  • Returns [string, Namespace<any>][]

onChange

Available since 0.19.0.

Listen for a stored value changing.

The listener runs after the new value is readable, and only when the value actually moved — writing a value equal to the one already there reports nothing, and equality is structural, so rebuilding an object with the same contents is also a no-op. Loading a save does not report changes; see onRestore.

Subscriptions outlive the namespaces they watch: newGame() and loading a save both rebuild every namespace from scratch, and a listener registered here survives that. For the whole story, see Watching stored values.

Overload 1 of 3

Every change, in any registered namespace.

storable.onChange(({namespace, key, previous, next}) => {
    console.log(`${namespace}.${key}: ${previous} -> ${next}`);
});
  • listener: (change: StorableChange) => void - See StorableChange
  • Returns EventToken - A token whose cancel() removes the listener

Overload 2 of 3

Changes in one namespace.

storable.onChange("persistent:player", ({key, next}) => {...});
  • namespace: string - The namespace key, e.g. "persistent:player" for new Persistent("player", ...)
  • listener: (change: StorableChange) => void
  • Returns EventToken

Overload 3 of 3

Changes to one key.

const token = storable.onChange("persistent:player", "gold", ({next}) => {
    if (next === 100) achievements.unlock("rich");
});

token.cancel();
  • namespace: string - The namespace key
  • key: string - The key inside that namespace
  • listener: (change: StorableChange) => void
  • Returns EventToken

onRestore

Available since 0.19.0.

Listen for the store being replaced wholesale — loading a save, or rewinding a namespace to a snapshot. Fires once per bulk application, naming the namespaces involved, instead of the changes it implies.

Re-read whatever you derive from the store when this fires.

storable.onRestore(({namespaces}) => {
    if (namespaces.includes("persistent:player")) rereadPlayerView();
});
  • listener: (restore: StorableRestore) => void - See StorableRestore
  • Returns EventToken - A token whose cancel() removes the listener

Watching a value across a save load takes both signals. onChange is deliberately silent during a load, so a listener that must also fire when a loaded save arrives already at the interesting value has to re-check it on onRestore.

On this page