This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
AgrarianGameArchive/Docs/PersistenceDesignDocument.md
T
2026-05-17 17:08:05 -07:00

12 KiB

Agrarian Persistence Design Document

Purpose

This document defines Agrarian's persistence direction for the MVP foundation. It separates what the game saves, what remains external metadata, how save data should be versioned, and what must be deferred until later persistence systems are needed.

The design goal is to preserve meaningful player and world progress without locking the project into brittle prototype data.

Persistence Principles

Save Meaningful State

Persist things that change gameplay or player progress:

  • player identity;
  • survival stats;
  • inventory;
  • placed structures;
  • world time and weather state;
  • resource depletion where needed;
  • active tile/package version.

Do not persist static terrain files, generated caches, editor-only assets, or pure presentation state.

Version Everything That Can Outlive A Build

Save data is a compatibility contract. Every persistent record should carry enough version/context to migrate or safely reject it later.

Minimum version fields:

  • save format version;
  • game build/version;
  • active map/tile ID;
  • active tile package version;
  • record type version where needed.

External Metadata Stays External

Tile registry and terrain package metadata should remain external authoritative metadata. Save data should reference tile IDs/package versions, not copy entire tile registries into saves.

Server Owns Writes

Only the server writes authoritative persistence records. Clients display replicated state and may request actions, but they do not write authoritative save state directly.

MVP Persistence Scope

The MVP persistence scope is intentionally narrow:

  • player identity;
  • player survival snapshot;
  • player inventory snapshot;
  • placed campfire/shelter/basic build pieces;
  • resource depletion state where needed for shared gameplay;
  • world time;
  • weather state/seed/source metadata;
  • active Ground Zero tile ID;
  • active Ground Zero tile package version.

Containers should be included once they become part of the playable loop. If containers are not in the first playable loop yet, they remain a near-term implementation item rather than a blocker for this design document.

Player Identity

MVP player identity can be simple.

Acceptable early identity options:

  • local platform/user identifier;
  • deterministic test profile ID;
  • server-assigned temporary player ID;
  • future account ID once account services exist.

Persistence should avoid using player display names as primary keys. Display names can change.

Minimum player record:

PlayerId
DisplayName
LastKnownTileId
LastKnownTransform
SurvivalSnapshot
CareHistorySnapshot
InventorySnapshot
UpdatedAt
RecordVersion

Survival Snapshot

Persist the survival state needed to resume a player:

  • health;
  • stamina;
  • hunger;
  • thirst;
  • body temperature;
  • injury severity;
  • sickness severity;
  • exhaustion;
  • alive/dead state if death persistence is active.

Survival rates and tuning values should not be duplicated into the save unless there is a specific compatibility reason. They belong in code/config/data assets.

MVP implementation note: UAgrarianPersistenceSubsystem::SaveCurrentWorld captures live Agrarian player characters into FAgrarianSavedPlayer, including transform, survival snapshot, care history snapshot, and inventory stacks. RestorePlayers reapplies those records to matching live characters before or alongside world actor restore.

The same save path captures authoritative world weather state from AAgrarianGameState: world hour, collapsed weather enum, mapped provider inputs, and FAgrarianWeatherDebugSnapshot. The debug snapshot includes weather source, provider timestamp, tile ID, tile center coordinate, provider weather code, and the final applied in-game weather state so weather-related save/load issues can be inspected per tile.

LoadCurrentWorld is the unified MVP load entry point. It restores world weather/time state first, then restores matching player records and persistent world actors. Admin load commands should call this combined path so weather, players, and structures are rehydrated from the same save slot instead of partially restoring only actors or players.

Care History Snapshot

Reserve a long-term care history snapshot beside the immediate survival snapshot. The MVP records neutral normalized fields only; later lifecycle and aging systems will decide how aggressively those histories affect health, stamina, strength, endurance, disease resistance, injury risk, recovery, visual aging, and old-age decline.

Reserved care history fields:

  • nutrition quality;
  • illness burden;
  • injury burden;
  • sleep quality;
  • shelter quality;
  • stress burden;
  • workload burden;
  • treatment quality.

Inventory Snapshot

Persist inventory as item definition IDs and stack counts.

Do persist:

  • item ID;
  • stack count;
  • durability/condition when added;
  • container/location ID when containers exist.

Do not persist full item definition data. Item definitions belong in Data Assets and are loaded by ID.

World State

MVP world state should include:

  • world/gameplay time;
  • weather state;
  • weather seed or source timestamp when available;
  • active tile ID;
  • active tile package version;
  • save timestamp;
  • save format version.

World time uses the MVP calendar target:

4 real hours = 1 in-game day

Day/night presentation can later use real-region solar metadata, but the save should persist the gameplay calendar state and enough tile context to recreate presentation.

Structure And Placement State

Placed gameplay structures should persist when they are part of the survival loop.

Minimum placed object record:

ObjectId
ObjectTypeId
TileId
Transform
OwnerPlayerId
HealthOrCondition
CustomState
CreatedAt
UpdatedAt
RecordVersion

For MVP, this includes:

  • campfire;
  • primitive shelter;
  • basic build pieces once available.

Future structure persistence should support decay, ownership, permissions, settlement membership, repair state, and destruction history.

Resource Depletion State

Not every resource needs persistent depletion in the MVP.

Persist depletion when:

  • multiple players can observe the changed state;
  • the depleted state affects survival;
  • immediate respawn would undermine the loop;
  • the actor is intentionally part of a shared world memory test.

Avoid persisting every foliage or minor gatherable actor until performance and world-density rules are clear.

Minimum resource state:

ResourceId
ResourceTypeId
TileId
RemainingAmount
DepletedAt
RespawnAt
RecordVersion

Tile Metadata In Save Data

Save data should reference external tile metadata, not duplicate it.

Persist in save:

  • active tile ID;
  • active tile package version;
  • tile registry schema version;
  • tile package checksum or manifest hash if needed for validation.

Keep external:

  • full tile registry;
  • terrain metadata;
  • heightmap metadata;
  • landform analysis;
  • water/shoreline analysis;
  • neighbor edge verification;
  • tile package files.

Reason:

  • terrain packages may improve over time;
  • tile registry can grow independently;
  • save files should stay small and migrate safely;
  • player/world state should not corrupt when tile metadata updates.

Containers

Containers are a near-term persistence item once storage gameplay exists.

Minimum container record:

ContainerId
ContainerTypeId
TileId
Transform
OwnerPlayerId
InventorySnapshot
LockOrPermissionState
RecordVersion

Until containers are implemented, inventory can remain player-carried and placed structure state can remain separate.

Save Timing

MVP save timing should include:

  • manual admin save command;
  • load on server start;
  • periodic server-side save interval once server state is changing regularly;
  • explicit save before planned server shutdown.

Recommended initial interval:

every 5 minutes during active play

The interval should be tunable. It should not block gameplay on slow disk I/O.

Load On Server Start

Server startup should:

  1. Load save metadata.
  2. Validate save format version.
  3. Validate active tile ID and package version.
  4. Load world state.
  5. Load placed structures/resource state.
  6. Load known player records.
  7. Spawn or restore runtime actors.
  8. Log skipped or migrated records.

If save validation fails, the server should fail clearly or start a new world only when explicitly configured to do so.

Migration Strategy

Persistence must assume data formats will change.

Rules:

  • never silently reinterpret old records as new formats;
  • add migration functions when changing saved record shape;
  • keep unknown fields harmless where possible;
  • log migrations;
  • reject unsupported future save versions;
  • back up saves before destructive migrations.

MVP can use simple file saves, but the data shape should still include versions so future database migration is possible.

Storage Backend

MVP storage can be file-based while the system is small.

Acceptable MVP options:

  • Unreal USaveGame records;
  • JSON records for inspectability;
  • hybrid approach where gameplay uses USaveGame and tile metadata remains JSON/external.

Long-term candidates:

  • SQLite for local/server structured state;
  • PostgreSQL for persistent multiplayer services;
  • object storage/CDN for tile packages;
  • append-only event logs for economy/governance where auditability matters.

Do not choose the long-term database before the MVP proves the shape of the state that needs to persist.

Backup And Recovery

Persistence is not a backup by itself.

MVP operations should keep:

  • repository backup;
  • VM backup;
  • save data backup;
  • tile package backup;
  • tile registry backup.

Before changing save formats, take a manual backup of current save data.

Security

Persistent data should never store secrets.

Do not store:

  • passwords;
  • API tokens;
  • private keys;
  • admin reset tokens;
  • mail credentials;
  • DigitalOcean tokens.

Player records should store stable IDs and gameplay state, not sensitive account credentials.

Testing Gates

Minimum persistence smoke test:

  1. Start server.
  2. Join as a player.
  3. Change survival/inventory state.
  4. Place a campfire or primitive shelter.
  5. Deplete one resource node if resource persistence is enabled.
  6. Save manually.
  7. Stop server.
  8. Start server.
  9. Confirm player/world state restored as expected.

Minimum migration test:

  1. Load a previous save format fixture.
  2. Run migration or compatibility load.
  3. Confirm unsupported data is rejected or logged clearly.
  4. Confirm supported data survives.

Minimum tile validation test:

  1. Save active Ground Zero tile ID/package version.
  2. Restart server.
  3. Confirm the server validates the active package version.
  4. Confirm clients can still download the required package from the tile endpoint.

Current Roadmap Decisions

This document defines:

  • MVP persistence scope;
  • save data vs external tile registry boundary;
  • player identity save direction;
  • player stats save direction;
  • player inventory save direction;
  • resource depletion persistence rule;
  • world time save direction;
  • weather seed/state save direction;
  • container persistence direction;
  • server-side save interval direction;
  • load-on-server-start direction;
  • initial tile registry persistence direction.

Implementation work remains tracked separately in the roadmap.

The MVP resource-node implementation stores depletion as existing map/tile actor state. Each AAgrarianResourceNode may define a stable PersistenceNodeId; otherwise the actor name is used as a fallback. Save files capture RemainingHarvests for resource nodes present in the loaded world and restore only matching existing nodes. This deliberately avoids spawning resource nodes from saves, keeping tile-authored resources owned by tile content while letting persistence remember depletion for active tiles.

Open Questions

  • Should the first playable MVP use USaveGame, JSON, or a hybrid save backend?
  • What is the first stable SaveFormatVersion value?
  • Should disconnected players remain in world physically or be removed?
  • How much inventory should death/respawn preserve?
  • When do saves move from file-based records to database-backed records?
  • How should family/generation records attach to player identity later?