Skip to main content

SaveGame

This section documents EDInteractionSystem’s SaveGame pipeline.

It is designed to persist and restore:

  • Removed foliage instances (destroyed/harvested foliage stays removed after reload)
  • Interactable actors (and custom saveable actors), including:
    • current HP
    • interaction blocked/denied state
    • destroyed state
    • any game-specific variables marked with SaveGame

The workflow is multiplayer-ready:

  • Save/Load runs on the server (authority).
  • When a save is applied, state is replicated to clients using normal replication (and the plugin’s already replicated foliage removal state).

Entry point

The entry point is the GameState component:

  • UEDInteractionGameStateComponent

Main server functions:

  • SaveInteractionToSlot(SlotName, UserIndex)
  • LoadInteractionFromSlot(SlotName, UserIndex, bApplyImmediately)
  • ApplyLoadedInteractionSave(SaveGameObject)

What gets saved

1) Removed foliage

The system stores removed foliage instances as:

  • StaticMesh (soft reference)
  • Location (world space)

Saved into:

  • UEDInteractionSaveGame::RemovedFoliageInstances (FEDSavedRemovedFoliageInstance)

On load, removal is re-applied by finding the matching instance by StaticMesh + Location and removing it.

2) Saveable actors (interactable and/or custom)

Actors are saved into:

  • UEDInteractionSaveGame::SavedActors (FEDSavedActorExtendedData)

Each entry includes:

  • SaveKey: stable identifier used to match the actor on load
  • Transform: actor transform (applied on load if the root component is Movable)
  • InteractableState: basic UEDInteractableComponent state (HP, deny/blocked, etc.)
  • SavedObjects: serialized bytes for selected objects (actor and/or components) using ArIsSaveGame = true

SaveKey (stable identifier)

The system needs a stable key to find “the same” actor again when loading.

Priority order:

  1. If the actor implements IEDInteractionSaveable, GetEDSaveKey() is used.
  2. If the actor has UEDInteractableComponent, UEDInteractableComponent::GetEffectiveSaveKey() is used:
    • If SaveKey is set on the component, it is used.
    • Otherwise, the actor name is used.
  3. Final fallback: actor name.

Recommendations:

  • For placed level actors, set SaveKey explicitly to avoid relying on actor names.
  • For dynamically spawned actors, implement IEDInteractionSaveable and generate your own key (for example, a gameplay ID).

Saving custom variables (UPROPERTY(SaveGame))

To save game-specific variables on your actor or component:

  • Mark properties with UPROPERTY(SaveGame)

Objects are serialized using:

  • FObjectAndNameAsStringProxyArchive with Ar.ArIsSaveGame = true

That means only properties tagged as SaveGame are included.

Example (C++):

UPROPERTY(SaveGame, BlueprintReadWrite)
int32 TimesInteracted = 0;

Destroyed state tracking

If a save-relevant interactable actor is destroyed, the system can remember it so that after loading it remains destroyed.

Automatic (interactables)

If an actor has:

  • UEDInteractableComponent with bRelevantForSaveGame = true

then on server destruction it registers:

  • UEDInteractionGameStateComponent::MarkSaveKeyAsDestroyed(GetEffectiveSaveKey())

Manual (your gameplay)

If you destroy objects through custom logic (outside the interaction flow), you can mark them yourself:

  • MarkSaveKeyAsDestroyed(SaveKey)

On load:

  • If the save key is present in DestroyedActorSaveKeys, the actor is destroyed immediately.

API: adding saveable elements

You have three main ways to extend what gets saved.

A) Automatic tag-based saving

If an actor has tag:

  • EDSaveGame

it is considered a save candidate.

Also, UEDInteractableComponent exposes:

  • bRelevantForSaveGame

which automatically adds the EDSaveGame tag to the owning actor during initialization.

B) Explicit registration (server)

To save an actor even without the tag:

  • RegisterSaveableActor(Actor)
  • UnregisterSaveableActor(Actor)

This is useful for dynamically spawned actors or systems managed from GameMode/GameState.

C) Interface control (IEDInteractionSaveable)

Implement IEDInteractionSaveable on your actor to control:

  • GetEDSaveKey() → stable key
  • GetEDSaveObjects(Objects) → list of UObjects to serialize

If you do not implement the interface:

  • The system serializes the actor and all its components by default.

Blueprint usage

  1. Ensure your GameState has UEDInteractionGameStateComponent.
  2. On the server (for example, in GameMode on level start):
    • LoadInteractionFromSlot("EDInteraction", 0, true)
  3. When you want to save (checkpoint / menu / autosave):
    • SaveInteractionToSlot("EDInteraction", 0)

C++ usage

if (AGameStateBase* GS = UGameplayStatics::GetGameState(World))
{
if (UEDInteractionGameStateComponent* Comp = GS->FindComponentByClass<UEDInteractionGameStateComponent>())
{
Comp->LoadInteractionFromSlot(TEXT("EDInteraction"), 0, true);
Comp->SaveInteractionToSlot(TEXT("EDInteraction"), 0);
}
}

Current limitations

  • This system does not spawn missing actors on load; it restores state only for actors that exist in the level (and destroys them if marked as destroyed).
  • If you rely on actor-name keys and you rename the actor, matching will break. Prefer SaveKey or IEDInteractionSaveable.