Technical Design

Network Architecture

RISK This is the highest-cost, highest-risk area of the project. Persistent, server-authoritative, raidable PvPvE for ~40–60 players is genuinely hard. Treat the networking + persistence backbone as a Phase-1 first-class deliverable, not something to retrofit.

Status: draftOwner: UnassignedUpdated: 2026-10-01

Production schedule — 2026-09-13: PIPE-ROADMAP now defines 32 focused phases (P00–P31). Phase 0/1/2/3 references retained in this document are legacy scope bands, not the new phase numbers. The owner confirmed limited-area core-loop proof before full-map expansion; see the roadmap for dependencies, audited status and remaining work.

Production context

Deprecated source referenceGDD/04-Multiplayer/01-Network-Architecture.md
Decision markers4 confirmed · 1 recommendations · 0 TBD
Browser document roleThis standalone HTML file is authoritative; edit this file directly through the project workflow.

Verified implementation evidence

  • Source/Lambeer/Persistence/SaveSubsystem.*
  • Source/Lambeer/Persistence/LambeerWorldPersistenceSubsystem.*
  • Source/Lambeer/Core/LambeerLocalPlayer.*
  • Source/Lambeer/Core/LambeerPlayerState.*

Relationships

Document contract coverage

Use these required Technical Design areas during review. The HTML content below is authoritative; items not stated explicitly remain unresolved.

  • ReviewProblem & Scope
  • ReviewCurrent vs Proposed
  • ReviewArchitecture
  • ReviewData Model
  • ReviewInterfaces & Events
  • ReviewReplication / Persistence
  • ReviewPerformance & Failure Handling
  • ReviewImplementation Plan
  • ReviewVerification Strategy
  • ReviewTechnical Decisions / TBDs

Authoritative project content

[RISK] This is the highest-cost, highest-risk area of the project. Persistent, server-authoritative, raidable PvPvE for ~40–60 players is genuinely hard. Treat the networking + persistence backbone as a Phase-1 first-class deliverable, not something to retrofit.

Model — [CONFIRMED]

  • Dedicated-server authoritative. The server owns all gameplay truth: damage, inventory, stats, building, loot, AI. Clients are never trusted.
  • No listen-server / P2P for live play (a listen-server mode may be used purely for local testing).
  • ~40–60 players per server instance, plus AI hordes.
  • Linux dedicated server build target (MetaHuman plugins are already configured for Win64 + Linux).

Core principles

  1. Server authority everywhere. Clients send requests (RPCs/input); the server validates and applies. This is the foundation of anti-cheat for a full-loot/raid game.
  2. Client prediction for feel. Movement and firing feedback are predicted client-side and reconciled with the server.
  3. Replication discipline. With ~40–60 players + AI + bases, naïve replication will not scale. Use relevancy, dormancy, update-frequency tuning, and consider the Replication Graph for relevancy management. [RECOMMENDATION], validate need by profiling.
  4. Lag compensation for hitscan combat (server rewind) so shooting feels fair. [RISK] non-trivial; budget for it.

Replication hotspots (plan for these)

System Challenge Mitigation direction
Building (hundreds of pieces/base) Too many actors to replicate ISM/HISM visuals + lightweight per-piece records; dormancy; distance relevancy
AI hordes Server CPU + replication AI LOD, active caps, relevancy despawn; evaluate Mass if needed
Inventories Bandwidth + privacy Replicate owner-only; server validates all changes
Combat hits Fairness + cheating Server-authoritative + lag comp; never trust client damage
Bosses + PvP in one area Replication spike Relevancy + effects budget

Persistence backbone — [RISK], design [CONFIRMED]

Persistent world means the server must save and restore world/player state across restarts:

  • Player data: inventory, equipment, survival stats, unlocked recipes, permanent boss buffs, position/respawn point, clan/squad membership.
  • World/base data: placed building pieces (transform, tier, HP, ownership), container contents, deployables, vehicles, territory anchors.
  • Loot/world state: container respawn timers, dropped death-bags (with despawn timers).

Confirmed storage model

  • Dedicated-server durable store: one SQLite database per server world stores world state, player records, inventories, buildings, vehicles, and containers.
  • Live state: authoritative gameplay state remains in dedicated-server RAM while the server is running.
  • Write path: dirty records are saved asynchronously and periodically so gameplay does not block on disk I/O. Critical transitions such as logout and graceful shutdown request a final flush.
  • Client storage: UE SaveGame is restricted to local settings such as graphics options and keybinds; it never stores authoritative gameplay state.
  • Evolution: SQLite schema and records are versioned and migrated. Gameplay code accesses storage through the save subsystem rather than issuing database operations directly.

Manual-house ISM state — 2026-10-05

Implemented additive fields in the existing schema-1 BuildingSites payload: bManualHousePiece distinguishes the source kind; Health defaults to -1 for pristine/legacy catalog-derived HP. Manual records use HouseInstanceId, AuthoredFinishKey containing the local piece GUID in digits format, and SiteId derived from house + local piece IDs. bAuthoredDefault/bCompleted identify source pieces; bRemoved is a durable tombstone. Existing resource, appearance, transform, optional owner Squad and explicit support fields retain their meanings.

Source definitions remain on the saved level Actor. Capture stores only partial HP/removal deltas for manual sources, including changes to currently unloaded sources; native player sites retain full records. Restore reconciles both source-before-record and record-before-source order. An ISM index shift never changes save identity. Replicated house deltas rebuild client visuals. Codec rejects forged identities and invalid HP. Authored finish deltas now preserve HP and may have an existing owner Squad; an empty owner denies refund demolition while allowing damage. No schema version or new storage service was invented.

TH/EN authoring and owner acceptance checklist. Non-PIE automation covers identity, instance hits, support/snap, damage, tombstones, SQLite reload and independent houses. Owner Dedicated Server/two-client rejoin, streaming and packaged cook remain unverified.

ManualHouse Ceiling revision, 2026-10-11: central-record migration applies only to bManualHousePiece legacy Ceiling Finish records. Structural Ceiling retains SiteId/HouseInstanceId, upper-face transform datum, health/removal and contributed units; old cosmetic support links are cleared. Map-authored migration uses the same stable local IDs. Existing PCG/player records and schema-1 remain unchanged. Canonical scope, selected variants and verification.

ManualHouse Ceiling edges — 2026-10-12: clipped floor triangles/hulls are derived from current manual-house records, Wall junction footprints and central removal flags. Capture/restore retains the existing identities/poses and schema; transient procedural buffers are rebuilt on Editor load and after central changes/replication. PCG/player legacy remains unchanged. Owning edge and validation contract.

Building-piece persistence and replication — [CONFIRMED DESIGN 2026-09-29]

FEAT-BUILDING covers player-built structures and ordinary authored houses with piece-level damage. POI and progression-locked structure remains protected under WORLD-C09. The 2026-09-29 P16 slice adds optional Squads and BuildingSites arrays to the existing schema-1 world-state payload. Each site stores stable site/Squad IDs, catalog piece, tier, transform, contributed units and completion state; codec automation passes. Authoritative multiplayer restart/rejoin remains unverified in owner PIE. Manual-house and native authored-finish HP/damage are now implemented as described below; PCG structural conversion remains later work.

  • Each authored placement has a stable HouseInstanceID; each piece in its reusable definition has a stable PieceID. Their pair identifies the saved world-house piece. Player-placed pieces also require a stable system-owned identity. Actor display names, Level Instance asset identity alone, World Partition load order and ISM/HISM instance indices are not durable keys.
  • The server owns damage, current health, material, destruction, repair, upgrade and ownership. Clients request actions; the server validates them and replicates the resulting state. Promotion between ISM/HISM and an interactive Actor must preserve the same logical record and must not duplicate damage or restore a destroyed visual.
  • Untouched authored pieces can derive their default state from the house definition. Persist modified authored-piece state so a damaged or destroyed piece remains changed after restart or streaming; persist every placed player piece and applicable placement/ownership state. Exact record layout and schema migration are implementation decisions, not approved by the guide's sample struct.
  • Capture and restore use ULambeerWorldPersistenceSubsystem and USaveSubsystem with the existing per-world SQLite transaction, dirty-flush and failure rules. There is no separate authoritative BuildingSaveSubsystem or gameplay SaveGame path. Adding these durable records must extend Lambeer.Persistence automation for independent house instances, partial HP, destruction, player-built ownership, stream unload/reload and restart/rejoin.
  • [OWNER CONFIRMED 2026-09-29] The server rejects placement unless the requesting player is a current member of a valid Squad; it does not create a Squad on placement. A valid placement outside canonical POI/no-build volumes first commits an unfinished hologram construction site; material contributions and completion happen later. The server owns its stable identity, Squad identity, contributed-material state and transition to the completed piece. Persist unfinished sites and contributions through the same world-record path. Replicate hologram visibility only to current members of that Squad; non-members do not see it and cannot contribute or remove it. A current member does not need to hold a Hammer to contribute or remove an unfinished site. The server atomically consumes contributed inventory, immediately completes the piece at its full bill, or cancels an unsupported site and returns every contributed unit as world pickups at the site. The collision-free hologram provides no support to other pieces. A member leaving the Squad loses site access while the Squad retains it. An empty Squad retains the same identity and sites after its final member leaves; no current member can see or act on them. The pre-placement local preview is not a durable world record. Canonical building rule.

[OWNER CONFIRMED 2026-10-04] Modular appearance selection extends the existing optional schema-1 building-site record with stable VariantId. Placement RPCs carry a permitted resource and variant; server validation resolves through piece/shared appearance Data Assets. Central world capture/restore retains selections, unfinished contributions and authored finish deltas. Missing legacy IDs use a default; removed variants diagnose and recover to the default. Legacy roof Brick/Concrete records migrate to Tile/Metal while retaining identity, ownership, pose and contributed units; gable infills keep wall resources. PCG authoring choices remain saved level properties. Canonical shared appearance contract and validation.

P07 player/world contract — [CONFIRMED 2026-09-14]

Owner resolved the P07 load, recovery and first durable-record rules below. Runtime uses one SQLite file per world through USaveSubsystem; the in-memory backend remains only while no world is open. Later P15 added crafting queues and the 2026-09-29 P16 slice added Squad and building-site arrays to the optional schema-1 world payload. Vehicle records remain later work. Owner-reported pass 2026-09-14 on Dedicated Server + two Preview clients closed the original ROAD-P07; the new building fields have non-PIE codec coverage but no owner restart/rejoin result yet.

[OWNER CONFIRMED 2026-09-30] A Squad requires a server-unique case-insensitive display name of at most 16 characters on creation; logo upload is optional, PNG only, at most 5 MB and 256 × 256 pixels, and requires no review. Only the current Leader may rename or upload. FLambeerSquadRecord now stores name, Leader, Officers, base64 PNG and the latest 100 activity entries in the existing optional schema-1 world payload; no schema version was invented. ULambeerWorldPersistenceSubsystem captures and restores that record through USaveSubsystem. Upload and download use bounded reliable chunks. Legacy records assign their first member Leader and prompt for a name. Native build and persistence codec coverage pass; owner restart/rejoin and upload delivery in PIE remain unverified. Squad identity contract.

[OWNER CONFIRMED 2026-10-01] Squad invitations begin at an aimed player through IA_Interact and the shared Command Ring. The server validates interaction reach/obstruction and the existing role/membership/persistence gates. A reliable owner-client RPC carries the inviter and Squad display names immediately to a CommonUI Yes/No modal; presentation does not wait for invitation property replication. Yes/No still invoke the existing authority-owned membership/decline flow. Joined membership and activity use the current dirty world-save path; pending invitations are transient and no save schema fields change. Canonical invitation flow and owner-only multiplayer/restart checklist.

[OWNER CONFIRMED 2026-10-02] Independent Floor/Ceiling/Exterior Wall Finish and standalone frame/leaf construction sites use the existing BuildingSites record and replicated construction actor. The additive optional SupportSiteId retains a finish’s completed slab/wall or a leaf’s completed door frame through capture/restore; no schema-version change or separate save service is introduced. Unfinished cancellation refunds all contributed units; completed demolition refunds half rounded down. Supporting slab/wall/frame demolition removes its attached finishes/leaf and refunds the whole group atomically before destruction. Standalone door definitions use the same Squad, contribution, completion, tier, transform and support fields; old combined door-wall IDs remain valid on restore. Standalone door decisions and owner checks. Codec coverage includes linked floor/ceiling records, legacy payloads lacking the field and malformed self-support rejection. Authored PCG finish deltas additionally use optional HouseInstanceId, AuthoredFinishKey, bAuthoredDefault and bRemoved fields. Exterior wall and gable cells use ExteriorWallFinish face-plane keys and preserve their rotation through the same codec. Originals have deterministic house/face/room/cell IDs and no Squad owner; an original tombstone is accepted only for a completed finish with its matching stable ID. Player replacements retain valid Squad IDs and independent SiteIds. Untouched originals are derived, not serialized. The registry captures unloaded replacements and tombstones, reapplying deltas whether the source registers before or after restoration. Source unload produces no refund. This additive schema-1 extension uses the same central world-state codec/SQLite path. Lambeer.Persistence.AuthoredFinishDeltas and AuthoredFinishLifecycle exercise independent house identities, malformed-record rejection, stream unload, SQLite close/reopen and both reconciliation orders without BeginPlay; owner multiplayer/restart acceptance remains pending. Canonical scope and owner-only restart/rejoin checks.

Single Player topology

[CONFIRMED 2026-09-14] TBD-HUD-UI-003: shipping Single Player uses embedded authority as NM_Standalone in the same process. This preserves the confirmed SP world-pause rule. Multiplayer live play remains dedicated-server authoritative. Listen-server stays local-test only. A later local dedicated process is optional hardening, not the P07 topology. Frontend save-list UI stays session-agnostic.

Write cadence and crash safety

  • Dirty records flush asynchronously every 30 seconds of world-up time. This is the approved P07 interval, not a later tuning pass.
  • Single Player Pause exposes a manual required-player Save. Exit to Main Menu measures real elapsed time from the latest durable snapshot (the loaded snapshot is the initial baseline); when that age is more than 30 seconds, a successful required-player flush is mandatory before travel. A failed required flush cancels the exit.
  • Logout, graceful shutdown, death-bag spawn, death itself, authored pickup collection, and runtime world-drop spawn request a final flush.
  • Use SQLite. Persist only committed transactions. A crash mid-write must not yield a half-applied player or world record. The P07 contract asked for WAL; UE 5.8 SQLiteCore is compiled with SQLITE_OMIT_WAL, so runtime uses BEGIN IMMEDIATE / COMMIT plus the engine rollback journal instead of write-ahead logging.
  • Full backup/restore operations remain later ops work; WAL plus explicit failure states are the P07 recovery surface.

[PAUSE SAVE/EXIT IMPLEMENTED 2026-09-15; OWNER PIE PENDING] The 30-second exit threshold uses monotonic real elapsed time, so time spent in a paused Standalone world is still counted. Manual Save and a required pre-exit Save both use the existing required-player capture, transaction and read-back verification path. The loaded durable state establishes the initial time baseline; every successful snapshot refreshes it. Threshold boundary automation, the closed-Editor native build, Persistence 8/8, HUD 24/24, Frontend 4/4 and WBP_PauseMenu compile/save/readback pass. The existing GameplayCueNotifyPaths fixture warning remains unrelated. Owner PIE must validate the visible buttons, save feedback, under/over-30-second exit behavior and multiplayer absence.

Save failure recovery and background snapshots — 2026-09-23

[IMPLEMENTED; owner runtime acceptance pending] The owner authorized the C++ review fixes. Player reads now distinguish a successful empty query from SQL/read failure and reject a payload whose identity differs from its row key. World state and all drop records must validate before restore is marked complete or authored loot is enabled. A failed world/drop load blocks snapshot writes; unreadable records are preserved. Enumeration requires SQLite Done, not merely a non-row result. Failed COMMIT rolls back; an uncertain rollback closes the connection instead of reusing it.

Threading and ordering: ULambeerWorldPersistenceSubsystem captures copied value records from the authoritative world; USaveSubsystem queues serialization, checksums and SQLite I/O on a worker. FLambeerSQLiteStore contains the shared SQL implementation outside UObject ownership. At most one snapshot runs at a time; additional changes remain pending in the world and are captured after completion. This UE SQLite HAL does not support concurrent connections to one file, so the active connection has exclusive worker access until its future resolves. Store reads, critical writes, rename, close, delete and world switching join the pending future before accessing storage. No worker dereferences gameplay UObjects. Completion clears dirty state only for the submitted revision; later changes remain dirty. Failed background writes retain dirty state for the existing 30-second cadence rather than retrying every frame. Capture time becomes the acknowledged save age, and an in-flight write forces Save and Exit to drain and flush.

Compatibility: schema version, save file locations, gameplay values and the 24-hour remaining world-up despawn contract are unchanged. Existing schema-1 worlds continue through the same codec. Critical operations retain a synchronous acknowledged flush; background autosave and deferred authored-container snapshots use the worker. The local index reads only the 16-byte SQLite header instead of loading the complete database into memory.

Validation: final build and focused automation evidence are recorded in TECH-SOURCE-STRUCTURE. Failure fixtures use separate temporary databases: unavailable player tables, failed drop queries, damaged drop checksums, a deferred foreign-key COMMIT failure, rollback/retry, async copy ownership, bounded submission, newer dirty revisions, critical-save ordering and close/reopen. No owner database is damaged by these fixtures.

Load validation and failure recovery

ConditionRequired behavior
Missing worldContinue is disabled with an explicit reason. Do not create a replacement world automatically.
Corrupt SQLite / failed checksumMark the world Corrupt, refuse entry, and keep the file. Do not silent-repair, auto-delete, or reset characters.
Schema older than the running buildMigrate upward, then allow entry.
Schema newer than the running buildMark Incompatible and refuse entry. Do not downgrade.
World valid, player record corruptRefuse that character with an explicit reason. Do not spawn a replacement identity over the same character/server binding, and do not delete inventory to force a join.
Interrupted before initial appearance commitNo authoritative character exists yet. Do not capture a player row while entry state is RequiresCreation or Error. A legacy/incomplete row with bInitialSpawnChosen=false and an invalid appearance re-enters Character Creation and is replaced only after a valid server-owned commit.

[P08 PROBE FIX 2026-09-15; OWNER-REPORTED PASS 2026-09-16] World-list probing must preserve its input database path independently from the output summary. A caller previously supplied Summary.DatabasePath as the input while the same Summary was reset as output, producing a false Missing result for an intact database. ProbeFile now copies the path before resetting output and the caller passes a separate local value. The reported owner database remained intact and passed schema 1, metadata and SQLite quick_check; post-fix native build and Lambeer.Persistence 6/6 pass with direct alias regression coverage. Owner later reported Save World Select/Continue probing passed.

[P08 REQUIRED-PLAYER FLUSH HARDENING 2026-09-15; OWNER-REPORTED PASS 2026-09-16] Owner PIE showed that a player could commit initial appearance, enter gameplay, move, run Lambeer.SaveFlush, receive ok, and still have no durable player row on the next entry. A player-scoped flush must now capture the supplied Controller's ALambeerPlayerState explicitly, merge that record into the snapshot, commit it, and read it back successfully before reporting success. Initial appearance commit, first starter-town selection, logout and Lambeer.SaveFlush use this required-player path. World-only periodic flushes retain the aggregate path. Pre-commit RequiresCreation/Error states remain deliberately non-durable and cause a required-player flush to fail rather than return a misleading ok. Owner later reported remaining persistence/restart checks passed.

P07 persisted player record

[SPAWN-SELECTION PRESENTATION CORRECTION 2026-10-14; OWNER RETEST PENDING] The owner reported walking in place and no turning in Client 1 on L_Dev_Sandbox, with no town-selection screen visible. Live MCP confirmed Dedicated Server plus two clients: pie-1 failed its saved-position spawn, recovered at the authored PlayerStart and remained in MOVE_None; the other pawn was MOVE_Walking. The shared death/town screen was incorrectly dismissed by a later living-death notification even though entry still required spawn selection. NotifyDeathRecordChanged now preserves/reopens that screen for a living RequiresSpawnSelection character. A stale living-presentation RPC also respects pending entry and actual death. The owning controller re-evaluates entry/death presentation in OnRep_PlayerState to handle state notifications arriving before its PlayerState reference. The holding-pawn lock remains until the owner selects an authored town; the existing town-selection RPC unlocks movement and flushes bInitialSpawnChosen=true through the central persistence path. No schema, saved gameplay fields or rotation contract changes. Closed-Editor LambeerEditor and Lambeer Win64 Development builds pass. The real notification-handler regression covers both entry/death replication orders, late owning PlayerState readiness, stale living RPCs and completed-selection/death dismissal in an isolated non-PIE world. MCP Frontend/HUD/Persistence validation passes 75/75 with no test warnings or errors, including SavedPositionSpawnRecovery and SpawnSelectionPresentationOrder. BP_PlayerCharacter compiles and its scoped Save is clean; the exact project reopened on L_Dev_Sandbox. Live diagnosis and validation / 75-test results. Post-fix owner PIE acceptance remains pending: Play with Dedicated Server plus two clients, choose an authored town in Client 1, verify movement and movement-facing rotation, then stop/rejoin and verify normal saved entry.

Lifecycle correction validation: Closed-Editor LambeerEditor Win64 Development build passed. Frontend 4/4, HUD 24/24 and Persistence 7/7 (including the new early-read/Controller-destruction regression) passed. The fixture's first GAS initialization emitted the existing missing GameplayCueNotifyPaths configuration warning. Owner later reported Continue skips Character Creation and remaining persistence/restart checks passed.

[SPAWN RECOVERY IMPLEMENTED 2026-09-15; OWNER-REPORTED PASS 2026-09-16] The owner reports an underground-looking camera and no character after Continue. Live MCP logs at 15:43:49 and 15:43:58 UTC show successful lookup of pie-0 in the existing Apple world, restoration at (0,0,0), then BP_PlayerCharacter_C spawn failure due to collision. The owner requested implementation after the initial diagnostic-only handoff. RestartPlayer now checks whether saved-position spawning produced a pawn. On failure, the map's normal PlayerStart path supplies a holding pawn, the saved appearance/loadout/survival state is restored, and a living character is locked in starter-town selection without reopening Character Creation. Dead records retain the normal death/bed/town flow and are not resurrected. If fallback also fails, entry becomes Error and returns to Main Menu with an explicit failure; capture cannot overwrite the existing row. No hard-coded recovery coordinates, forced collision bypass, schema bump, or direct owner-database repair is used. Owner later reported remaining spawn-recovery gameplay checks passed.

Recovery persistence and validation: Pending living recovery uses the existing bInitialSpawnChosen=false capture/restore route, so saves and interrupted recovery preserve the town-selection requirement and restored data. The chosen town returns entry to Ready and uses the required-player flush. Valid saved-position spawning remains unchanged. Closed-Editor LambeerEditor Win64 Development build passed; MCP Frontend 4/4, HUD 24/24 and Persistence 8/8 passed (36/36). The existing early-entry fixture emitted the known GameplayCueNotifyPaths warning; the new Lambeer.Persistence.SavedPositionSpawnRecovery passed without warnings/errors. It exercises opposing collision geometry, actual GameMode restart/possession, restored inventory/attributes, interrupted recovery reentry, town selection/write/readback, subsequent normal Continue, dead-record recovery and total spawn-failure preservation in an isolated temporary database without PIE, BeginPlay or world ticking. Owner later reported Continue, town selection, visible controllable character, move/Lambeer.SaveFlush and restart/Continue without another creation/town prompt passed. Previously overwritten data remains unrecoverable from the current row.

[P08 LOAD-ORDER ROOT CAUSE CORRECTED 2026-09-15; OWNER-REPORTED PASS 2026-09-16] The owner reported that required-player flush hardening did not fix Continue. Live logs prove appearance commit, starter-town selection, SaveFlush and readback all succeeded for pie-0, then the next RestartPlayer reported Missing before OnWorldBeginPlay activated persistence. The old TryLoadPlayerRecord returned Missing whenever bPersistenceActive was false without querying the already-open database. Reads now ensure the authoritative store is open independently of periodic capture activation; BeginPlay reuses that store. Storage unavailability returns Unavailable and refuses entry instead of creating a replacement character. This supersedes the earlier missing-player-in-snapshot diagnosis; required-player write/readback checks remain useful but were insufficient. Owner later reported remaining Continue/restart persistence passed.

Exit capture: UE calls APlayerController::Destroyed before AController::Destroyed invokes GameMode Logout; the former destroys or unpossesses the pawn. Capture now runs before the PlayerController superclass teardown. A pawnless PlayerState cannot overwrite a complete record with default zero transform and empty inventory. Existing records already overwritten before this fix are not reconstructed automatically. The non-PIE Lambeer.Persistence.EntryBeforeBeginPlay regression uses an isolated GameInstance/world and temporary SQLite store to verify early reads, genuine missing identity, unavailable service and teardown preservation; no PIE/BeginPlay is started.

  • Identity and FAppearanceState (gender, preset, hair, skin, eye).
  • bInitialSpawnChosen distinguishes a committed appearance awaiting starter-town selection (initial entry or living saved-position spawn recovery) from a returning playable character. It is backward-compatible as true for records written before P08. Appearance is retained during recovery; town choice marks the field and flushes the record.
  • World transform/rotation and last bed (the bed that last started Sleep).
  • bDead, death location, death-bag id, killer name and cause. A dead record restores the spawn-select screen, not a playable locked corpse. Lambeer.Kill on an already-dead character reopens that screen.
  • Inventory, equipment, held hands, nested contents, durability, magazine contents, chamber, attachments, item BloodAmount/WetAmount, and character body/hair blood and wetness.
  • Survival attributes that exist in the session (including Energy/Sleep/Immunity).
  • [IMPLEMENTED 2026-09-22] P12 injury flags bBleeding, bFractured, bInfected, bCold, bHot and InfectionCheckElapsedSeconds. They are optional fields on the existing schema 1 player payload. A record written before this change loads them as clear and elapsed 0. The infection timer does not advance while the world is shut down.
  • Q1–Q0 bindings as references to existing item instances, never cloned stacks.
  • World rain intensity so a wet character does not reload under a clear sky.

Player rows are keyed by a durable login LambeerPlayerKey, not by OnlineSubsystemNull’s per-session RoboPC-* UniqueNetId. Dedicated Server + two PIE Preview clients use pie-{PIEInstance} so the same two windows rejoin the same two characters. A real online UniqueNetId is used when it is durable. Packaged offline identities fall back to a local settings UUID. Server Browser join now appends that same login option to the connect URL. Dedicated and listen persistable worlds advertise a Null/LAN session for development discovery. One-process PIE lists those hosts by listen port because OnlineSubsystemNull’s LAN beacon cannot FindSessions against itself; a PIE client returning to Main Menu must not destroy the hosted GameSession. Steam discovery remains blocked on TBD-HUD-UI-004. Owner reported Null/LAN Server Browser Refresh/Join 2026-09-16.

Do not persist observed chamber/magazine HUD knowledge. Unlocked recipes, boss buffs, clan/squad membership, buildings and vehicles wait for their owning phases. [IMPLEMENTED 2026-09-22] Active crafting queue rows are an optional CraftingQueues array on the schema-1 world-state payload. A payload written before this change loads that array empty. Schema version stays 1. The station-destruction recovery container is world-drop kind StationRecovery, restored as ALambeerStationRecoveryContainer, looted through the existing container transfer, and uses the same 24-hour world-up remaining despawn as death bags and runtime drops. It is not a death bag and does not create a death marker. These rows are not fields on the P07 player record. Canonical rule: TBD-HUD-UI-005. P07 does not persist AI blood or AI wetness; those remain open in their feature documents. [CONFIRMED 2026-09-22] The P14 damage-receiving zombie pawn is not in this save contract. Killing one is not restored as dead after restart.

Authored map containers — P13 extension

[IMPLEMENTED 2026-09-23; NON-PIE VALIDATED] Map-placed AWorldDropContainer children opt in through bPersistAuthoredContainer and a saved AuthoredContainerId derived from their Editor actor GUID. Runtime death bags and station-recovery containers remain on their existing drop path. Optional schema-1 AuthoredContainers world-state records contain the stable ID and complete inventory stacks. Older saves without this field have no visited containers; authored defaults initialize only the first encounter. A saved empty array is an empty container, never a refill request. No loot respawn or new despawn timer is introduced.

ULambeerWorldPersistenceSubsystem caches records across World Partition unload, restores them when an authored container registers, and includes unloaded records in snapshots. Inventory changes request a next-tick flush, after the transfer has completed; container state and player inventory commit together through USaveSubsystem::WriteSnapshot. The usual autosave, logout and graceful-exit paths also capture containers. Invalid/duplicate loaded IDs refuse registration. Failed world-state loads disable authored loot and snapshot writes instead of overwriting the unreadable state. Existing stack sanitization applies to a copy, preserving live inventory. Tactical-device state remains durable under the existing item contract; HUD observation knowledge is not a stack save field. See Kit Proof Town integration. Owner Dedicated Server restart/rejoin and actual streaming acceptance remain pending.

Death bags and runtime world drops

P13 validation — 2026-09-23: closed-Editor LambeerEditor Win64 Development build succeeded. Lambeer.Persistence passed 9/9 (8 clean, 1 with the existing GameplayCueNotifyPaths configuration warning). AuthoredContainers covers fresh-world first registration, older schema-1 payloads, partial depletion, empty state after SQLite reopen, retained unloaded records, late registration, duplicate loaded IDs, nested contents, copied-stack sanitization and fail-closed capture/registration guards. The fixture does not start PIE or BeginPlay. The first run exposed the empty-new-database read case; backend reads now distinguish a successful no-row result from SQL/decoding failure. A subsequent test expectation was corrected to preserve tactical-device state under the pre-existing contract. Final report: outputs/p13-kit-proof-town-20260923/persistence-tests-verified/index.json. Both P13 crate IDs and opt-in flags survived a saved map unload/reload.

  • Death bags, runtime world drops (player drop, throw-to-pickup, drop-trade), and station-recovery containers persist across restart. Restart itself never deletes them.
  • Each uses a 24-hour real-time remaining despawn that counts only while that world is running. Remaining time is saved. Time spent while the world is shut down does not consume the timer; after reopen the leftover duration continues.
  • Authored map-placed pickups remain level actors. They do not receive this 24-hour runtime-drop timer unless they become a runtime drop. After a player collects one, its stable actor id is stored in world state and that instance is not restored on later loads. Container loot-table respawn timers stay later world/loot work.
  • Place collect-once sandbox items as AWorldItemPickup / BP_WorldItemPickup (or a child such as BP_Pickup_Sledgehammer_Test) in the map with a unique actor label and a non-empty Stack. Do not spawn them from BeginPlay every session, and do not use Lambeer.SpawnPickup for fixtures that must stay collected — that cheat creates a runtime drop with the 24-hour timer.

Local world index

  • Each local world is one SQLite database, same persistence semantics as a dedicated server world.
  • Players may create, rename, list and delete worlds. Delete requires one confirmation and removes that world’s database.
  • P07 has no world-count cap.
  • The remembered-world pointer for Continue lives in client settings, not inside a world database. Start Single Player always opens the save list and never overwrites automatically.

Full vehicle records — [CONFIRMED]

Vehicles use full gameplay-state persistence, not a transform-only respawn record. The stable vehicle record and explicitly linked child records preserve identity/class, world placement and original spawn point, cabin lock state, ignition/key requirement, permanent Hotwire state, inserted-key link, overall and component condition, fuel and implemented operational resources, integrated inventory with complete item-instance state, installed parts/upgrades/cosmetics, and lifecycle timestamps/flags. The authoritative field-level contracts live in Vehicles — Full vehicle persistence and FEAT-LOCK-ACCESS.

Lock and access records — [CONFIRMED DESIGN 2026-09-17]

Later P16/P17/P23 records persist each one-time initial lock result, current built-in state, independent installed Lock-item link/owner, exact Vehicle-ID key binding and current item location, original vehicle spawn point, inserted key and permanent Hotwire. Restoring or streaming an existing record never rerolls the 30% world door/window or 90% vehicle initial chance. Squad access is authorized from current server membership rather than copied as a stale durable allow-list. This design is outside the implemented P07 player/pickup record scope and must extend USaveSubsystem / ULambeerWorldPersistenceSubsystem with matching Lambeer.Persistence automation when implemented.

[RISK]: P07 cadence, committed transactions and explicit corrupt/incompatible entry states are implemented. Schema-migration automation shipped with the SQLite backend (Lambeer.Persistence 6/6). Engine SQLite omits WAL, so rollback-journal atomicity is the crash-safety surface until a later ops/SQLite change. Full backup/restore remains later ops work before persistent-world release.

Connectivity & ops (later phases)

  • Matchmaking/server-browser, sessions, and a backend for official servers are Phase-2/3. See 02-Servers-and-Hosting.md.
  • Anti-cheat: Easy Anti-Cheat (EAC) — [CONFIRMED]. Server authority remains the first line of defense; EAC integration and operational hardening are required before launch.

Implementation guidance

Measure server CPU and each client connection with TECH-PERFORMANCE-PROFILING — Dedicated Server + Client1 + Client2. The runbook separates shared-process PIE, isolated captures, replication traffic and persistence stalls; no capacity pass is implied.

  • Build gameplay systems server-authoritative from day one — retrofitting authority is far more expensive than designing for it.
  • Use GameState/PlayerState for replicated shared/per-player state; keep large/private data in owner-only-replicated components.
  • Co-locate persistence with a UGameInstanceSubsystem/UWorldSubsystem save service. See ../05-Technical/04-Source-Code-Structure.md.

Player-facing session contract — [CONFIRMED]

FEAT-HUD-UI requires character, statistics, achievements, persisted position, and respawn state to be scoped per character on each server. Single Player uses the same gameplay and persistence semantics with no other players and may pause. [CONFIRMED 2026-09-14] TBD-HUD-UI-003: SP authority is embedded NM_Standalone; see the P07 persistence contract.