Skip to main content

Saving & Loading Instance State

A practical guide to saving and loading the state of instanced interaction proxies across game sessions.

Overview

The plugin persists instance states in memory during gameplay -- this survives World Partition streaming and PCG regeneration within the same session. However, all state is lost when the game exits. This guide shows how to save states to disk and restore them on load.

What Gets Persisted Automatically

  • State tag + step index per instance (stored in UERPInstanceSwapSubsystem)
  • Identified by FERPInstanceKey (actor path + quantized position)
  • Survives WP stream in/out and PCG regen within the same session
  • Lost on game exit -- you must save to disk yourself

How to Save States

Use your game's SaveGame system. On save, iterate the instance keys you have tracked and read their state from the subsystem.

Blueprint pattern:

Event: On Save Game
-> Get ERPInstanceSwapSubsystem
-> For each tracked instance key:
-> GetInstanceState(Key) -> StateTag
-> GetInstanceStateIndex(Key) -> StepIndex
-> Store in your SaveGame struct: {Key, StateTag, StepIndex}
-> Save to slot

Only save keys that are not in their default state (step 0). This keeps your save files small.

How to Load States

On load, restore each saved entry into the subsystem. When the player later approaches those instances, the proxies will spawn at the correct state.

Blueprint pattern:

Event: On Load Game
-> Get ERPInstanceSwapSubsystem
-> For each saved entry:
-> SetInstanceState(Key, StateTag, StepIndex)
-> (Timestamps reset to now -- timers restart from this point)

Any Duration-based auto-transitions will restart from the moment of load, not from the original interaction time.

Tracking Instance Keys

The subsystem does not broadcast which keys exist globally. You need to track which instances have been modified.

Listen to the OnInstanceActorStateChanged event on UERPInstancedInteractionComponent and maintain a set of modified keys.

Blueprint pattern:

// In your PlayerController or GameInstance:

Variable: ModifiedInstanceKeys (Set of FERPInstanceKey)

Event: OnInstanceActorStateChanged (Actor, StateTag, StepIndex, InstanceKey)
-> Branch: StepIndex > 0
True: -> Add InstanceKey to ModifiedInstanceKeys
False: -> Remove InstanceKey from ModifiedInstanceKeys

// On save: iterate ModifiedInstanceKeys
// On load: restore from SaveGame, then clear the set and rebuild from saved data

This approach only saves keys the player has actually interacted with.

Approach 2: Extend the Subsystem

For full control, create a Blueprint or C++ subclass of UERPInstanceSwapSubsystem that exposes a method to return all persisted states. This is useful if multiple systems modify instance states and you want a single source of truth.

World Partition Considerations

  • Instance keys use the ISMC owner's actor path, which is stable per WP cell
  • If you reorganize WP cells (move actors between cells), keys will break -- this is rare in production
  • PCG: works as long as seeds are stable and positions do not shift between sessions
  • Large worlds: consider calling PurgeStaleStates(MaxAgeSeconds) periodically to remove old states that no longer have active proxies

Example: Saving Harvested Trees

A complete flow for a tree-harvesting system:

During gameplay:

  1. Player approaches trees -- proxies spawn at default state (step 0, full tree)
  2. Player harvests a tree -- state advances to step 1 (stump)
  3. OnInstanceActorStateChanged fires -- you add the key to your tracked set

On save:

For each key in ModifiedInstanceKeys:
-> GetInstanceState(Key) -> "ERP.Instance.Harvested"
-> GetInstanceStateIndex(Key) -> 1
-> Write to SaveGame: {Key, "ERP.Instance.Harvested", 1}

On quit and relaunch:

Load SaveGame
-> For each saved entry:
-> SetInstanceState(Key, "ERP.Instance.Harvested", 1)

Player approaches the same trees: proxies spawn at step 1 (stump mesh) instead of step 0 (full tree). The player sees the world exactly as they left it.


Next Steps

Learn how instances work in Instanced Interaction Guide.

Check the subsystem API in API Reference.