unreal-save-load

Unreal 5.8 Save and Load

Build durable versioned Unreal persistence

---
name: unreal-save-load
description: Design, implement, version, migrate, optimize, and debug persistent game state in Unreal Engine 5.8. Use for USaveGame, ULocalPlayerSaveGame, UGameplayStatics save/load APIs, slots, platform users, profiles, checkpoints, autosaves, world and actor state, stable identifiers, serialization, FArchive custom versions, schema migration, asynchronous persistence, corruption and recovery, cloud conflicts, multiplayer save authority, GameUserSettings, missing or incompatible saves, save hitches, or packaged save behavior.
---

# Unreal 5.8 Save and Load

## Define the persistence contract first

Read [`references/system-selector.md`](references/system-selector.md).

1. List state that must survive a checkpoint, map travel, application restart, device change, patch,
   account change, and multiplayer session separately.
2. Assign each datum an authority, stable ID, owner file/slot, lifetime, default, validation rule, and
   migration policy.
3. Separate immutable definitions from mutable saved state. Persist definition IDs, not asset objects.
4. Capture a consistent snapshot, write through a serialized per-user operation queue, and acknowledge
   success/failure visibly.
5. Load into data first; validate type/header/version, migrate, resolve definitions, travel/construct the
   world, then apply state in a deterministic phase.
6. Preserve a last-known-good path and never overwrite a readable older/newer save after a failed load.
7. Test real previous-version files, corruption, missing content, low storage, interrupted operations,
   multiple users, and packaged target builds.

Route neighboring work deliberately:

- definition assets, Primary Asset IDs, tables, and redirects -> `unreal-data-assets-tables`;
- subsystem/Actor interface architecture -> `unreal-blueprint-architecture`;
- save-related loading/memory hitches -> `unreal-memory-streaming` and `unreal-insights-profiling`;
- release artifact, patch, platform packaging, and crash collection -> `unreal-packaging-deployment`;
- replicated runtime authority -> `unreal-replication`.

Load only what applies:

- [`references/schema-stable-identifiers.md`](references/schema-stable-identifiers.md)
- [`references/save-load-sequence-async.md`](references/save-load-sequence-async.md)
- [`references/world-state-actors.md`](references/world-state-actors.md)
- [`references/checkpoints-autosaves.md`](references/checkpoints-autosaves.md)
- [`references/versioning-migrations.md`](references/versioning-migrations.md)
- [`references/slots-users-platforms-cloud.md`](references/slots-users-platforms-cloud.md)
- [`references/corruption-failure-recovery.md`](references/corruption-failure-recovery.md)
- [`references/multiplayer-authority-security.md`](references/multiplayer-authority-security.md)
- [`references/performance-testing-debugging.md`](references/performance-testing-debugging.md)
- [`references/use-case-recipes.md`](references/use-case-recipes.md)

## Required answer format

Return:

1. **Persistence matrix** by datum, authority, lifetime, owner, stable ID, and slot.
2. **Save schema/header** with current version, defaults, validation, and size budget.
3. **Snapshot and write sequence**, concurrency policy, callbacks, UI, and failure behavior.
4. **Load, migration, definition resolution, world travel, and apply sequence**.
5. **Actor/world identity**, spawn/destroy state, missing-content behavior, and authority boundary.
6. **Backup/recovery/cloud conflict policy** without unsupported atomicity claims.
7. **Previous-version, corruption, interruption, platform-user, multiplayer, and packaged tests**.

## Hard rules

- Do not serialize live Actor/UObject pointers as durable identity. Persist stable domain IDs, Primary
  Asset IDs, tags, names, GUIDs, and value records with explicit resolution behavior.
- Do not save immutable definition data into every slot. Save the definition ID plus minimal mutable state.
- `AsyncSaveGameToSlot` still serializes on the game thread; it moves the platform write to a worker.
  Keep snapshot/schema cost bounded and measure hitches.
- Serialize save/load operations per platform user/slot. UE warns that some platforms may not support
  simultaneous save and load; completion order must not decide data authority.
- Treat callbacks as stale-capable. Bind weak ownership/request generations and verify slot/user/request.
- Never mutate the live world incrementally from unvalidated bytes. Validate and migrate a data snapshot
  before applying it.
- Never overwrite an unknown newer-version, corrupt, or failed-to-migrate save automatically.
- Do not rely on application shutdown as the only persistence point.
- Local save data is untrusted for competitive authority, paid entitlement, or server economy.
- `SaveGameToSlot` documents that it writes all non-transient properties and does not check the
  `SaveGame` property flag. Do not repeat the common claim that the flag filters this built-in call.
- Verify path, quota, user identity, slot enumeration, cloud behavior, suspend/resume, and atomicity with
  the target platform's current save API; desktop `.sav` behavior is not a universal contract.

See [`references/sources.md`](references/sources.md) for the UE 5.8 primary-source trail.

## Define the persistence contract first

Read [`references/system-selector.md`](/unreal/unreal-save-load/system-selector/).

1. List state that must survive a checkpoint, map travel, application restart, device change, patch,
   account change, and multiplayer session separately.
2. Assign each datum an authority, stable ID, owner file/slot, lifetime, default, validation rule, and
   migration policy.
3. Separate immutable definitions from mutable saved state. Persist definition IDs, not asset objects.
4. Capture a consistent snapshot, write through a serialized per-user operation queue, and acknowledge
   success/failure visibly.
5. Load into data first; validate type/header/version, migrate, resolve definitions, travel/construct the
   world, then apply state in a deterministic phase.
6. Preserve a last-known-good path and never overwrite a readable older/newer save after a failed load.
7. Test real previous-version files, corruption, missing content, low storage, interrupted operations,
   multiple users, and packaged target builds.

Route neighboring work deliberately:

- definition assets, Primary Asset IDs, tables, and redirects -> `unreal-data-assets-tables`;
- subsystem/Actor interface architecture -> `unreal-blueprint-architecture`;
- save-related loading/memory hitches -> `unreal-memory-streaming` and `unreal-insights-profiling`;
- release artifact, patch, platform packaging, and crash collection -> `unreal-packaging-deployment`;
- replicated runtime authority -> `unreal-replication`.

Load only what applies:

- [`references/schema-stable-identifiers.md`](/unreal/unreal-save-load/schema-stable-identifiers/)
- [`references/save-load-sequence-async.md`](/unreal/unreal-save-load/save-load-sequence-async/)
- [`references/world-state-actors.md`](/unreal/unreal-save-load/world-state-actors/)
- [`references/checkpoints-autosaves.md`](/unreal/unreal-save-load/checkpoints-autosaves/)
- [`references/versioning-migrations.md`](/unreal/unreal-save-load/versioning-migrations/)
- [`references/slots-users-platforms-cloud.md`](/unreal/unreal-save-load/slots-users-platforms-cloud/)
- [`references/corruption-failure-recovery.md`](/unreal/unreal-save-load/corruption-failure-recovery/)
- [`references/multiplayer-authority-security.md`](/unreal/unreal-save-load/multiplayer-authority-security/)
- [`references/performance-testing-debugging.md`](/unreal/unreal-save-load/performance-testing-debugging/)
- [`references/use-case-recipes.md`](/unreal/unreal-save-load/use-case-recipes/)

## Required answer format

Return:

1. **Persistence matrix** by datum, authority, lifetime, owner, stable ID, and slot.
2. **Save schema/header** with current version, defaults, validation, and size budget.
3. **Snapshot and write sequence**, concurrency policy, callbacks, UI, and failure behavior.
4. **Load, migration, definition resolution, world travel, and apply sequence**.
5. **Actor/world identity**, spawn/destroy state, missing-content behavior, and authority boundary.
6. **Backup/recovery/cloud conflict policy** without unsupported atomicity claims.
7. **Previous-version, corruption, interruption, platform-user, multiplayer, and packaged tests**.

## Hard rules

- Do not serialize live Actor/UObject pointers as durable identity. Persist stable domain IDs, Primary
  Asset IDs, tags, names, GUIDs, and value records with explicit resolution behavior.
- Do not save immutable definition data into every slot. Save the definition ID plus minimal mutable state.
- `AsyncSaveGameToSlot` still serializes on the game thread; it moves the platform write to a worker.
  Keep snapshot/schema cost bounded and measure hitches.
- Serialize save/load operations per platform user/slot. UE warns that some platforms may not support
  simultaneous save and load; completion order must not decide data authority.
- Treat callbacks as stale-capable. Bind weak ownership/request generations and verify slot/user/request.
- Never mutate the live world incrementally from unvalidated bytes. Validate and migrate a data snapshot
  before applying it.
- Never overwrite an unknown newer-version, corrupt, or failed-to-migrate save automatically.
- Do not rely on application shutdown as the only persistence point.
- Local save data is untrusted for competitive authority, paid entitlement, or server economy.
- `SaveGameToSlot` documents that it writes all non-transient properties and does not check the
  `SaveGame` property flag. Do not repeat the common claim that the flag filters this built-in call.
- Verify path, quota, user identity, slot enumeration, cloud behavior, suspend/resume, and atomicity with
  the target platform's current save API; desktop `.sav` behavior is not a universal contract.

See [`references/sources.md`](/unreal/unreal-save-load/sources/) for the UE 5.8 primary-source trail.

unreal 5.8 save and load design, implement, version, migrate, optimize, and debug persistent game state in unreal engine 5.8. use for usavegame, ulocalplayersavegame, ugameplaystatics save/load apis, slots, platform users, profiles, checkpoints, autosaves, world and actor state, stable identifiers, serialization, farchive custom versions, schema migration, asynchronous persistence, corruption and recovery, cloud conflicts, multiplayer save authority, gameusersettings, missing or incompatible saves, save hitches, or packaged save behavior. checkpoints and autosaves checkpoints and autosaves checkpoint contract define whether a checkpoint restores exact simulation, strategic progress, or a curated restart state. exact physics/ai/projectile snapshots are expensive and often unstable; prefer authoritative semantic state plus deterministic reset rules when the design allows it. trigger only after an atomic gameplay milestone: encounter settled, inventory transaction committed, streaming destination ready, and no incompatible transition in progress. freeze or snapshot through the coordinator so systems agree on one logical time. autosave queue - debounce bursts and coalesce redundant requests; - never run two writes whose completion order could regress the slot; - preserve the newest dirty generation until a successful write includes it; - show a saving indicator and prevent unsafe quit/slot deletion while required; - rate-limit storage writes and platform ui; - retry only classified transient failures with a bounded policy; - keep manual and autosave histories distinct when overwriting would surprise the player. save before risky transitions and periodically at safe moments. shutdown/suspend callbacks may provide little or no time; they are a last chance, not the primary design. for roguelike/anti-save-scum constraints, enforce design rules through commit points and authoritative state. do not corrupt reliability or hide failed writes to manufacture permanence. corruption, failure, and recovery corruption, failure, and recovery classify results instead of collapsing them into “no save”: - absent slot/new user; - unsupported/newer version; - corrupt/truncated/wrong class; - migration or validation failure; - missing content/definition; - permission, quota, storage, account, native ui, or platform failure; - canceled/stale request. recovery policy 1. never apply partial or unvalidated state. 2. preserve the original bytes/slot when policy and privacy permit. 3. try a known-good backup/history only after validating its identity/version. 4. surface which progress may be lost and require confirmation before reset/delete. 5. record non-sensitive result code, schema/build, stage, size, duration, and recovery outcome. do not claim savegametoslot is atomic across every platform. if robust replacement is required, use the target platform's documented transaction/container behavior or implement a validated generation scheme with multiple slots: write candidate generation, confirm success/readability, then advance a small index or choose the highest valid generation. test power loss at each boundary on real hardware. checksums detect accidental corruption; they do not make client data trustworthy. encryption without secure key ownership does not create server authority. multiplayer authority and security multiplayer authority and security the server owns shared world state, competitive progression, match results, inventories/economy, and entitlements. a client savegame may cache presentation or offline progress but must not become trusted input merely because it was produced by ue serialization. dedicated/listen server persistence 1. snapshot authoritative server state at a transaction/checkpoint boundary. 2. identify players by authenticated account/domain id, not controller index or connection object. 3. quiesce or version concurrent mutations so the snapshot is internally consistent. 4. persist to the server/backend with idempotency/version checks. 5. acknowledge only after durable success; retry without duplicating rewards/items. 6. on load, validate/migrate before spawning the world and accepting players. for host migration or listen-server saves, define which state can transfer and how a new authority proves freshness. do not trust the host's local file for paid/competitive state without backend verification. keep local accessibility, graphics, controls, and cosmetic preferences per local player/device as appropriate. avoid sending private local settings to the server unless gameplay requires and consent permits it. never log full save payloads, auth tokens, personal identifiers, or encryption keys. treat imported/cloud saves as hostile input: cap sizes/counts, validate enums/ids/ranges, and reject impossible relationships. performance, testing, and debugging performance, testing, and debugging measure stages bookmark and time separately: - snapshot gathering and lock/quiesce time; - savegame object construction and validation; - game-thread serialization; - worker/platform write and callback latency; - read latency; - game-thread object creation/deserialization; - migration, asset resolution, world travel, actor apply, and post-load rebuilds; - payload bytes and record counts by subsystem. async persistence prevents the device io from blocking the game thread, but ue 5.8 still serializes/ creates savegame objects on the game thread. use unreal insights and packaged target builds to enforce a snapshot/serialization hitch budget. test matrix - first boot, new profile, overwrite, manual/autosave rotation, delete; - every supported released schema and a multi-version skip upgrade; - newer/unknown, wrong class, truncated, bit-corrupt, zero-byte, oversized, duplicate-id saves; - removed/renamed definition, missing optional content, changed map/actor class; - disk/quota full, read-only, permission/native ui denial, unplug/suspend/kill at each boundary; - rapid requests, save during load, travel, death, logout, and stale callbacks; - multiple local/platform users, account switch, split screen, offline/cloud conflict; - dedicated/listen server authority, disconnect/reconnect, idempotent backend retry; - development/test/shipping packaged builds and every target platform. never ship migration code without immutable real-world fixtures and expected post-migration assertions. keep a diagnostic command/ui to report slot metadata and result codes without exposing payload secrets. save/load sequence and async behavior save/load sequence and async behavior save 1. coalesce a request and capture reason, user, slot, generation, and checkpoint id. 2. on the game thread, ask owned systems for a consistent value snapshot in a declared order. 3. validate required ids/ranges and create/populate the savegame object. 4. call asyncsavegametoslot; keep ui/state pending until its completion callback. 5. verify callback generation, slot, user, and success. update last-good metadata only on confirmed success. ue 5.8 performs asyncsavegametoslot serialization on the game thread, platform write on a worker, and completion on the game thread. large object graphs can still hitch during serialization. delegate payload is copied to a worker thread, so copied payload must be thread-safe by value. load 1. select user/slot and queue behind conflicting persistence operations. 2. call asyncloadgamefromslot; handle null/failure as a distinct result, not “new game” silently. 3. on callback, verify request identity and cast/type/header/version. 4. migrate a data object; validate it without mutating live gameplay. 5. resolve required definition ids/assets asynchronously and decide missing-content policy. 6. travel/load the target world if needed. 7. when registered systems/actors are ready, apply global -> world -> spawned -> placed actor -> player state in a documented order; then emit one load-complete event. ue 5.8 performs the platform read on a worker, then object creation/deserialization and callback on the game thread. keep migration/apply work bounded or split it behind a loading transition. synchronous apis are acceptable only for proven-small data at a blocking menu/boot boundary. schema and stable identifiers schema and stable identifiers split definition from state text definition: primary asset id / row id / tag -> display, class, tuning, soft assets save record: stable instance id -> definition id + minimal mutable values runtime: resolved definition + validated mutable record + transient caches use value structs/arrays/maps in the savegame object. avoid world pointers, components, delegates, latent actions, timers, ui objects, replicated caches, and derived presentation data. header fields include at least: - format magic/product namespace when using a custom envelope; - save schema version and optional subsystem versions; - build/content compatibility identifier; - slot/profile id and platform-user binding policy; - creation/update time for display only, not authority; - map/checkpoint identity and playtime if needed; - payload validation/checksum metadata when your format provides it. identity - placed persistent actor: authored stable guid/domain id stored with the actor; - runtime-spawned actor: generated persistent instance id plus definition id and spawn record; - item/quest/ability: stable domain/primary asset id, never display text or array index; - map: soft world/primary asset identity or governed map id; - destroyed/consumed placed actor: tombstone/state record keyed by stable actor id. validate uniqueness in editor/ci. duplication workflows must generate or deliberately preserve ids based on semantic identity; accidental duplicate guids make load order decide state. slots, users, platforms, and cloud slots, users, platforms, and cloud slot taxonomy use explicit namespaces, for example: - global machine/user settings; - account/profile unlocks; - manual playthrough slots; - autosave/checkpoint ring; - optional per-world/server cache. store display metadata in a small header/index that can be read without loading the entire world payload when the platform permits. rebuild a cacheable index from authoritative slots when it is missing. userindex identifies the platform user but is ignored on some platforms. ulocalplayersavegame binds a savegame to a local player and supplies load/create, version, pre/post-save, and async helper lifecycle. use it for per-local-player state; keep machine-wide settings separate. the lower-level isavegamesystem exposes platform capabilities including multiple-user support, native ui, async operations, and save-name enumeration. enumeration is not possible on every platform. query capability rather than assuming desktop behavior. cloud/backend the online services user file interface is beta in ue 5.8. if used, treat local and remote copies as two versioned replicas with account identity, revision/generation, timestamp, and conflict policy. time alone is not enough when clocks differ. offer keep-local/keep-cloud/manual resolution when merging is unsafe. never upload before validating the account, schema, payload, and entitlement. test offline creation, reconnect, concurrent devices, sign-out, account switching, deletion, quota, and interrupted transfer. ue 5.8 primary sources ue 5.8 primary sources - saving and loading your game - ugameplaystatics::asyncsavegametoslot - ugameplaystatics::asyncloadgamefromslot - save game to slot - async save game to slot - async load game from slot - does save game exist - delete game in slot - ulocalplayersavegame - isavegamesystem - usavegame - ugameusersettings - enhanced input user settings: save settings - versioning assets and packages - farchive::usingcustomversion - fcustomversion - online services user file interface — beta pages were checked against ue 5.8 documentation on 2026-07-19. reconfirm threading, platform-user/save capabilities, slot enumeration, online services maturity, cloud behavior, quotas, and certification requirements after an engine or platform update. system selector system selector | state | prefer | |---|---| | playthrough/profile/world progress | custom usavegame schema and coordinator | | per-local-player data with lifecycle/version helpers | ulocalplayersavegame | | resolution/window/scalability | ugameusersettings | | enhanced input key profiles | enhanced input user settings or integrated custom serialization | | immutable item/quest/ability definitions | data asset/table/registry; save stable id only | | map-travel-only runtime state | gameinstance/subsystem/player state, not necessarily disk | | server-owned persistent world/account | authoritative backend/database; client save is cache/ui only | | interoperable/external data format | explicit custom format plus validation/versioning | choose one coordinator, commonly a gameinstance subsystem, to own slot/user policy, snapshot requests, operation serialization, migration registry, callbacks, and telemetry. individual actors contribute records; they do not independently race writes to the same slot. use-case recipes use-case recipes small single-player checkpoint use one profile savegame plus a short autosave ring. persist checkpoint id, player semantic state, inventory records by stable definition/instance id, quest state, and placed-actor tombstones. on load, migrate, travel to the checkpoint map, resolve definitions, apply world records, then player state. multiple campaigns plus global unlocks separate global profile/unlocks from each campaign slot. a campaign save references the owning profile id and its own schema/checkpoint. deleting a campaign must not delete account settings/unlocks accidentally. per-player settings use ugameusersettings for resolution/window/scalability. use ulocalplayersavegame or the owning feature's user-settings api for per-player controls/accessibility/custom preferences. bind to platform user, handle split screen/account switch, and do not put world progress in machine graphics config. open-world actors assign authored stable ids to placed savable actors. store a sparse map of changed state/tombstones plus records for persistent runtime-spawned actors. keep records independent of world partition residency; apply when the owning actor registers or after its cell loads. server-owned progression persist authenticated account/domain records through a server/backend transaction. keep the local file to settings/cache/offline mode. use idempotency keys and compare-and-set/version checks so retries cannot duplicate or roll back rewards. versioning and migrations versioning and migrations use a monotonic save schema version independent of marketing/build version. add subsystem/record versions when they can migrate independently. migration pipeline text read version n validate minimum header n -> n+1 pure data transform validate invariants repeat to current resolve current definitions write upgraded copy only after full success and player/platform policy migration functions must be deterministic, idempotent at their declared boundary, and unable to mutate the live world. preserve fixtures for every supported released version. never maintain only “current-1” if players may skip multiple releases. use safe defaults for added fields. for removed/renamed ids, maintain explicit old-to-new maps, gameplay tag/primary asset redirects where applicable, and domain migrations. asset redirectors do not migrate arbitrary saved strings or external keys. for custom uobject serialization, register a guid with fcustomversionregistration, call farchive::usingcustomversion, and branch on customver. do not change an existing serialized layout without advancing its version. keep custom archive logic narrow and test both save and load. if the file version is newer than the running game, reject it read-only with an actionable message. do not downgrade or overwrite it. world and actor state world and actor state use an interface/component/registry to gather and apply records; do not enumerate every actor and dump arbitrary properties. for each savable actor record: text persistentinstanceid definitionorclassid when runtime-spawned owningmaporpartitionid transform only if design permits movement small explicit gameplay state struct record schema/version when independently migrated apply order 1. load/map travel and wait for the intended world readiness boundary. 2. apply global progression and subsystem registries. 3. spawn saved runtime actors not already present. 4. match placed actors by stable id; apply state or tombstone. 5. resolve cross-record references by stable id after all participants exist. 6. apply player pawn/inventory/checkpoint state and re-enable input/gameplay. do not use actor label, array order, transient object name, pointer, or world partition runtime cell as durable identity. a streamed-out actor is not destroyed progress; retain its record independently of current cell residency. define behavior for removed definitions/maps, duplicate ids, actor class replacement, invalid transforms, blocked spawn points, and a record whose owning content is not installed. quarantine/skipping with a clear player-facing status is safer than an unchecked spawn or null dereference.

Checkpoints and autosaves

# Checkpoints and autosaves

## Checkpoint contract

Define whether a checkpoint restores exact simulation, strategic progress, or a curated restart state.
Exact physics/AI/projectile snapshots are expensive and often unstable; prefer authoritative semantic
state plus deterministic reset rules when the design allows it.

Trigger only after an atomic gameplay milestone: encounter settled, inventory transaction committed,
streaming destination ready, and no incompatible transition in progress. Freeze or snapshot through the
coordinator so systems agree on one logical time.

## Autosave queue

- debounce bursts and coalesce redundant requests;
- never run two writes whose completion order could regress the slot;
- preserve the newest dirty generation until a successful write includes it;
- show a saving indicator and prevent unsafe quit/slot deletion while required;
- rate-limit storage writes and platform UI;
- retry only classified transient failures with a bounded policy;
- keep manual and autosave histories distinct when overwriting would surprise the player.

Save before risky transitions and periodically at safe moments. Shutdown/suspend callbacks may provide
little or no time; they are a last chance, not the primary design.

For roguelike/anti-save-scum constraints, enforce design rules through commit points and authoritative
state. Do not corrupt reliability or hide failed writes to manufacture permanence.

Corruption, failure, and recovery

# Corruption, failure, and recovery

Classify results instead of collapsing them into “no save”:

- absent slot/new user;
- unsupported/newer version;
- corrupt/truncated/wrong class;
- migration or validation failure;
- missing content/definition;
- permission, quota, storage, account, native UI, or platform failure;
- canceled/stale request.

## Recovery policy

1. Never apply partial or unvalidated state.
2. Preserve the original bytes/slot when policy and privacy permit.
3. Try a known-good backup/history only after validating its identity/version.
4. Surface which progress may be lost and require confirmation before reset/delete.
5. Record non-sensitive result code, schema/build, stage, size, duration, and recovery outcome.

Do not claim `SaveGameToSlot` is atomic across every platform. If robust replacement is required, use the
target platform's documented transaction/container behavior or implement a validated generation scheme
with multiple slots: write candidate generation, confirm success/readability, then advance a small index
or choose the highest valid generation. Test power loss at each boundary on real hardware.

Checksums detect accidental corruption; they do not make client data trustworthy. Encryption without
secure key ownership does not create server authority.

Multiplayer authority and security

# Multiplayer authority and security

The server owns shared world state, competitive progression, match results, inventories/economy, and
entitlements. A client SaveGame may cache presentation or offline progress but must not become trusted
input merely because it was produced by UE serialization.

## Dedicated/listen server persistence

1. Snapshot authoritative server state at a transaction/checkpoint boundary.
2. Identify players by authenticated account/domain ID, not controller index or connection object.
3. Quiesce or version concurrent mutations so the snapshot is internally consistent.
4. Persist to the server/backend with idempotency/version checks.
5. Acknowledge only after durable success; retry without duplicating rewards/items.
6. On load, validate/migrate before spawning the world and accepting players.

For host migration or listen-server saves, define which state can transfer and how a new authority proves
freshness. Do not trust the host's local file for paid/competitive state without backend verification.

Keep local accessibility, graphics, controls, and cosmetic preferences per local player/device as
appropriate. Avoid sending private local settings to the server unless gameplay requires and consent
permits it.

Never log full save payloads, auth tokens, personal identifiers, or encryption keys. Treat imported/cloud
saves as hostile input: cap sizes/counts, validate enums/IDs/ranges, and reject impossible relationships.

Performance, testing, and debugging

# Performance, testing, and debugging

## Measure stages

Bookmark and time separately:

- snapshot gathering and lock/quiesce time;
- SaveGame object construction and validation;
- game-thread serialization;
- worker/platform write and callback latency;
- read latency;
- game-thread object creation/deserialization;
- migration, asset resolution, world travel, actor apply, and post-load rebuilds;
- payload bytes and record counts by subsystem.

Async persistence prevents the device IO from blocking the game thread, but UE 5.8 still serializes/
creates SaveGame objects on the game thread. Use Unreal Insights and packaged target builds to enforce a
snapshot/serialization hitch budget.

## Test matrix

- first boot, new profile, overwrite, manual/autosave rotation, delete;
- every supported released schema and a multi-version skip upgrade;
- newer/unknown, wrong class, truncated, bit-corrupt, zero-byte, oversized, duplicate-ID saves;
- removed/renamed definition, missing optional content, changed map/actor class;
- disk/quota full, read-only, permission/native UI denial, unplug/suspend/kill at each boundary;
- rapid requests, save during load, travel, death, logout, and stale callbacks;
- multiple local/platform users, account switch, split screen, offline/cloud conflict;
- dedicated/listen server authority, disconnect/reconnect, idempotent backend retry;
- Development/Test/Shipping packaged builds and every target platform.

Never ship migration code without immutable real-world fixtures and expected post-migration assertions.
Keep a diagnostic command/UI to report slot metadata and result codes without exposing payload secrets.

Save/load sequence and async behavior

# Save/load sequence and async behavior

## Save

1. Coalesce a request and capture reason, user, slot, generation, and checkpoint ID.
2. On the game thread, ask owned systems for a consistent value snapshot in a declared order.
3. Validate required IDs/ranges and create/populate the SaveGame object.
4. Call `AsyncSaveGameToSlot`; keep UI/state pending until its completion callback.
5. Verify callback generation, slot, user, and success. Update last-good metadata only on confirmed success.

UE 5.8 performs `AsyncSaveGameToSlot` serialization on the game thread, platform write on a worker, and
completion on the game thread. Large object graphs can still hitch during serialization. Delegate payload
is copied to a worker thread, so copied payload must be thread-safe by value.

## Load

1. Select user/slot and queue behind conflicting persistence operations.
2. Call `AsyncLoadGameFromSlot`; handle null/failure as a distinct result, not “new game” silently.
3. On callback, verify request identity and cast/type/header/version.
4. Migrate a data object; validate it without mutating live gameplay.
5. Resolve required definition IDs/assets asynchronously and decide missing-content policy.
6. Travel/load the target world if needed.
7. When registered systems/actors are ready, apply global -> world -> spawned -> placed actor -> player
   state in a documented order; then emit one load-complete event.

UE 5.8 performs the platform read on a worker, then object creation/deserialization and callback on the
game thread. Keep migration/apply work bounded or split it behind a loading transition.

Synchronous APIs are acceptable only for proven-small data at a blocking menu/boot boundary.

Schema and stable identifiers

# Schema and stable identifiers

## Split definition from state

```text
Definition: Primary Asset ID / row ID / tag -> display, class, tuning, soft assets
Save record: stable instance ID -> definition ID + minimal mutable values
Runtime: resolved definition + validated mutable record + transient caches
```

Use value structs/arrays/maps in the SaveGame object. Avoid world pointers, components, delegates, latent
actions, timers, UI objects, replicated caches, and derived presentation data.

## Header fields

Include at least:

- format magic/product namespace when using a custom envelope;
- save schema version and optional subsystem versions;
- build/content compatibility identifier;
- slot/profile ID and platform-user binding policy;
- creation/update time for display only, not authority;
- map/checkpoint identity and playtime if needed;
- payload validation/checksum metadata when your format provides it.

## Identity

- placed persistent actor: authored stable GUID/domain ID stored with the actor;
- runtime-spawned actor: generated persistent instance ID plus definition ID and spawn record;
- item/quest/ability: stable domain/Primary Asset ID, never display text or array index;
- map: soft world/Primary Asset identity or governed map ID;
- destroyed/consumed placed actor: tombstone/state record keyed by stable actor ID.

Validate uniqueness in editor/CI. Duplication workflows must generate or deliberately preserve IDs based
on semantic identity; accidental duplicate GUIDs make load order decide state.

Slots, users, platforms, and cloud

# Slots, users, platforms, and cloud

## Slot taxonomy

Use explicit namespaces, for example:

- global machine/user settings;
- account/profile unlocks;
- manual playthrough slots;
- autosave/checkpoint ring;
- optional per-world/server cache.

Store display metadata in a small header/index that can be read without loading the entire world payload
when the platform permits. Rebuild a cacheable index from authoritative slots when it is missing.

`UserIndex` identifies the platform user but is ignored on some platforms. `ULocalPlayerSaveGame` binds a
SaveGame to a Local Player and supplies load/create, version, pre/post-save, and async helper lifecycle.
Use it for per-local-player state; keep machine-wide settings separate.

The lower-level `ISaveGameSystem` exposes platform capabilities including multiple-user support, native
UI, async operations, and save-name enumeration. Enumeration is not possible on every platform. Query
capability rather than assuming desktop behavior.

## Cloud/backend

The Online Services User File Interface is **Beta** in UE 5.8. If used, treat local and remote copies as
two versioned replicas with account identity, revision/generation, timestamp, and conflict policy. Time
alone is not enough when clocks differ.

Offer keep-local/keep-cloud/manual resolution when merging is unsafe. Never upload before validating the
account, schema, payload, and entitlement. Test offline creation, reconnect, concurrent devices, sign-out,
account switching, deletion, quota, and interrupted transfer.

UE 5.8 primary sources

# UE 5.8 primary sources

- [Saving and Loading Your Game](https://dev.epicgames.com/documentation/en-us/unreal-engine/saving-and-loading-your-game-in-unreal-engine)
- [`UGameplayStatics::AsyncSaveGameToSlot`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UGameplayStatics/AsyncSaveGameToSlot)
- [`UGameplayStatics::AsyncLoadGameFromSlot`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UGameplayStatics/AsyncLoadGameFromSlot)
- [Save Game to Slot](https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/SaveGame/SaveGametoSlot)
- [Async Save Game to Slot](https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/SaveGame/AsyncSaveGametoSlot)
- [Async Load Game from Slot](https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/SaveGame/AsyncLoadGamefromSlot)
- [Does Save Game Exist](https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/SaveGame/DoesSaveGameExist)
- [Delete Game in Slot](https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/SaveGame/DeleteGameinSlot)
- [`ULocalPlayerSaveGame`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/ULocalPlayerSaveGame)
- [`ISaveGameSystem`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/ISaveGameSystem)
- [`USaveGame`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/USaveGame)
- [`UGameUserSettings`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UGameUserSettings)
- [Enhanced Input User Settings: Save Settings](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Plugins/EnhancedInput/UEnhancedInputUserSettings/SaveSettings)
- [Versioning Assets and Packages](https://dev.epicgames.com/documentation/en-us/unreal-engine/versioning-of-assets-and-packages-in-unreal-engine)
- [`FArchive::UsingCustomVersion`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/FArchive/UsingCustomVersion)
- [`FCustomVersion`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/FCustomVersion)
- [Online Services User File Interface — Beta](https://dev.epicgames.com/documentation/en-us/unreal-engine/user-file-interface-in-unreal-engine)

Pages were checked against UE 5.8 documentation on 2026-07-19. Reconfirm threading, platform-user/save
capabilities, slot enumeration, Online Services maturity, cloud behavior, quotas, and certification
requirements after an engine or platform update.

System selector

# System selector

| State | Prefer |
|---|---|
| playthrough/profile/world progress | custom `USaveGame` schema and coordinator |
| per-local-player data with lifecycle/version helpers | `ULocalPlayerSaveGame` |
| resolution/window/scalability | `UGameUserSettings` |
| Enhanced Input key profiles | Enhanced Input User Settings or integrated custom serialization |
| immutable item/quest/ability definitions | Data Asset/Table/Registry; save stable ID only |
| map-travel-only runtime state | GameInstance/subsystem/player state, not necessarily disk |
| server-owned persistent world/account | authoritative backend/database; client save is cache/UI only |
| interoperable/external data format | explicit custom format plus validation/versioning |

Choose one coordinator, commonly a GameInstance Subsystem, to own slot/user policy, snapshot requests,
operation serialization, migration registry, callbacks, and telemetry. Individual actors contribute
records; they do not independently race writes to the same slot.

Use-case recipes

# Use-case recipes

## Small single-player checkpoint

Use one profile SaveGame plus a short autosave ring. Persist checkpoint ID, player semantic state,
inventory records by stable definition/instance ID, quest state, and placed-actor tombstones. On load,
migrate, travel to the checkpoint map, resolve definitions, apply world records, then player state.

## Multiple campaigns plus global unlocks

Separate global profile/unlocks from each campaign slot. A campaign save references the owning profile ID
and its own schema/checkpoint. Deleting a campaign must not delete account settings/unlocks accidentally.

## Per-player settings

Use `UGameUserSettings` for resolution/window/scalability. Use `ULocalPlayerSaveGame` or the owning
feature's user-settings API for per-player controls/accessibility/custom preferences. Bind to platform
user, handle split screen/account switch, and do not put world progress in machine graphics config.

## Open-world actors

Assign authored stable IDs to placed savable actors. Store a sparse map of changed state/tombstones plus
records for persistent runtime-spawned actors. Keep records independent of World Partition residency;
apply when the owning actor registers or after its cell loads.

## Server-owned progression

Persist authenticated account/domain records through a server/backend transaction. Keep the local file
to settings/cache/offline mode. Use idempotency keys and compare-and-set/version checks so retries cannot
duplicate or roll back rewards.

Versioning and migrations

# Versioning and migrations

Use a monotonic save schema version independent of marketing/build version. Add subsystem/record versions
when they can migrate independently.

## Migration pipeline

```text
read version N
validate minimum header
N -> N+1 pure data transform
validate invariants
repeat to Current
resolve current definitions
write upgraded copy only after full success and player/platform policy
```

Migration functions must be deterministic, idempotent at their declared boundary, and unable to mutate
the live world. Preserve fixtures for every supported released version. Never maintain only “current-1”
if players may skip multiple releases.

Use safe defaults for added fields. For removed/renamed IDs, maintain explicit old-to-new maps, Gameplay
Tag/Primary Asset redirects where applicable, and domain migrations. Asset redirectors do not migrate
arbitrary saved strings or external keys.

For custom UObject serialization, register a GUID with `FCustomVersionRegistration`, call
`FArchive::UsingCustomVersion`, and branch on `CustomVer`. Do not change an existing serialized layout
without advancing its version. Keep custom archive logic narrow and test both save and load.

If the file version is newer than the running game, reject it read-only with an actionable message. Do
not downgrade or overwrite it.

World and actor state

# World and actor state

Use an interface/component/registry to gather and apply records; do not enumerate every actor and dump
arbitrary properties.

For each savable actor record:

```text
PersistentInstanceId
DefinitionOrClassId when runtime-spawned
OwningMapOrPartitionId
Transform only if design permits movement
small explicit gameplay state struct
record schema/version when independently migrated
```

## Apply order

1. Load/map travel and wait for the intended world readiness boundary.
2. Apply global progression and subsystem registries.
3. Spawn saved runtime actors not already present.
4. Match placed actors by stable ID; apply state or tombstone.
5. Resolve cross-record references by stable ID after all participants exist.
6. Apply player pawn/inventory/checkpoint state and re-enable input/gameplay.

Do not use Actor label, array order, transient object name, pointer, or World Partition runtime cell as
durable identity. A streamed-out actor is not destroyed progress; retain its record independently of
current cell residency.

Define behavior for removed definitions/maps, duplicate IDs, actor class replacement, invalid transforms,
blocked spawn points, and a record whose owning content is not installed. Quarantine/skipping with a
clear player-facing status is safer than an unchecked spawn or null dereference.


unreal-splines

Unreal 5.8 Splines

Build spline paths, meshes, and movement in UE 5.8

---
name: unreal-splines
description: Design, implement, tune, and debug spline-driven systems in Unreal Engine 5.8. Use for Blueprint or C++ paths, Spline Components, Spline Mesh Components, roads, rails, pipes, cables, fences, patrol routes, camera rails, distance-based motion, repeated placement, Landscape Splines, or PCG spline tools.
---

# Unreal 5.8 Splines

## Ownership boundary

This skill owns path math, spline queries, spline-mesh deformation, distance travel, and rigid
placement along a path. Route terrain deformation/paint to
[`unreal-landscape`](../unreal-landscape/SKILL.md), procedural population to
[`unreal-pcg`](../unreal-pcg/SKILL.md), and streamed-cell/Data Layer/HLOD ownership to
[`unreal-world-partition`](../unreal-world-partition/SKILL.md).

## Select the system

Read [`references/use-cases.md`](references/use-cases.md) before implementation.

- Use `USplineComponent` for path data, transforms, distance queries, and movement.
- Use one `USplineMeshComponent` per segment to deform a mesh between two endpoints.
- Use Landscape Splines when the path must deform or paint Landscape terrain.
- Use PCG spline tools when the spline is an authoring input for procedural placement.
- Use ISM/HISM placement instead of spline meshes when repeated objects must remain rigid.

Do not substitute one system for another merely because each contains “Spline” in its
name.

## Execute

1. Classify the job: query path, move actor, deform continuous mesh, place rigid
   instances, edit Landscape, or drive PCG.
2. Declare coordinate space for every query. Prefer World for actor placement and
   Local when feeding start/end data into a Spline Mesh Component owned by the same
   actor.
3. Use **distance along spline** for constant-speed travel and uniform spacing. Do not
   assume spline point index or input key is proportional to physical distance.
4. Put editor-generated geometry in the Construction Script. Put runtime mutation in
   explicit runtime functions. Make both paths idempotent.
5. Batch point edits, then update the spline once. Avoid rebuilding components every
   tick.
6. Validate start, midpoint, end, tightest bend, closed-loop seam, reverse travel,
   collision, and cooked build behavior.

Read [`references/action-patterns.md`](references/action-patterns.md) for exact patterns.
Read [`references/troubleshooting.md`](references/troubleshooting.md) when output twists,
stretches, bunches, duplicates, or moves at inconsistent speed.

## Required answer format

Return:

1. **System choice** and why.
2. **Actor/component layout**.
3. **Ordered Blueprint nodes or C++ calls**, including coordinate spaces.
4. **Variables to expose**, with units and safe bounds where known.
5. **Runtime/editor boundary**.
6. **Failure checks**.
7. **Verification procedure**.

Prefer node and property names used by UE 5.8. Mark experimental PCG features as
experimental. Do not invent editor paths, node names, defaults, or performance claims.

## Hard rules

- Treat a Spline Component as a path, not rendered geometry.
- Treat a Spline Mesh Component as a two-point deformation, not a multi-point path.
- Derive repeated counts and spacing from `Get Spline Length`.
- Scale motion by delta time.
- Preserve an explicit mesh forward axis and up-vector convention.
- Clean up previously generated components before regenerating them.
- Keep spline mutation authoritative in networked gameplay; replicate state or results,
  not divergent per-client construction.
- Profile dense spline meshes and collision. Prefer instancing for large rigid repeats.

See [`references/sources.md`](references/sources.md) for the UE 5.8 source trail.

## Ownership boundary

This skill owns path math, spline queries, spline-mesh deformation, distance travel, and rigid
placement along a path. Route terrain deformation/paint to
[`unreal-landscape`](/unreal/unreal-landscape/), procedural population to
[`unreal-pcg`](/unreal/unreal-pcg/), and streamed-cell/Data Layer/HLOD ownership to
[`unreal-world-partition`](/unreal/unreal-world-partition/).

## Select the system

Read [`references/use-cases.md`](/unreal/unreal-splines/use-cases/) before implementation.

- Use `USplineComponent` for path data, transforms, distance queries, and movement.
- Use one `USplineMeshComponent` per segment to deform a mesh between two endpoints.
- Use Landscape Splines when the path must deform or paint Landscape terrain.
- Use PCG spline tools when the spline is an authoring input for procedural placement.
- Use ISM/HISM placement instead of spline meshes when repeated objects must remain rigid.

Do not substitute one system for another merely because each contains “Spline” in its
name.

## Execute

1. Classify the job: query path, move actor, deform continuous mesh, place rigid
   instances, edit Landscape, or drive PCG.
2. Declare coordinate space for every query. Prefer World for actor placement and
   Local when feeding start/end data into a Spline Mesh Component owned by the same
   actor.
3. Use **distance along spline** for constant-speed travel and uniform spacing. Do not
   assume spline point index or input key is proportional to physical distance.
4. Put editor-generated geometry in the Construction Script. Put runtime mutation in
   explicit runtime functions. Make both paths idempotent.
5. Batch point edits, then update the spline once. Avoid rebuilding components every
   tick.
6. Validate start, midpoint, end, tightest bend, closed-loop seam, reverse travel,
   collision, and cooked build behavior.

Read [`references/action-patterns.md`](/unreal/unreal-splines/action-patterns/) for exact patterns.
Read [`references/troubleshooting.md`](/unreal/unreal-splines/troubleshooting/) when output twists,
stretches, bunches, duplicates, or moves at inconsistent speed.

## Required answer format

Return:

1. **System choice** and why.
2. **Actor/component layout**.
3. **Ordered Blueprint nodes or C++ calls**, including coordinate spaces.
4. **Variables to expose**, with units and safe bounds where known.
5. **Runtime/editor boundary**.
6. **Failure checks**.
7. **Verification procedure**.

Prefer node and property names used by UE 5.8. Mark experimental PCG features as
experimental. Do not invent editor paths, node names, defaults, or performance claims.

## Hard rules

- Treat a Spline Component as a path, not rendered geometry.
- Treat a Spline Mesh Component as a two-point deformation, not a multi-point path.
- Derive repeated counts and spacing from `Get Spline Length`.
- Scale motion by delta time.
- Preserve an explicit mesh forward axis and up-vector convention.
- Clean up previously generated components before regenerating them.
- Keep spline mutation authoritative in networked gameplay; replicate state or results,
  not divergent per-client construction.
- Profile dense spline meshes and collision. Prefer instancing for large rigid repeats.

See [`references/sources.md`](/unreal/unreal-splines/sources/) for the UE 5.8 source trail.

unreal 5.8 splines design, implement, tune, and debug spline-driven systems in unreal engine 5.8. use for blueprint or c++ paths, spline components, spline mesh components, roads, rails, pipes, cables, fences, patrol routes, camera rails, distance-based motion, repeated placement, landscape splines, or pcg spline tools. action patterns action patterns constant-speed actor movement variables: - distancecm — float - speedcmpersec — float - direction — 1.0 or -1.0 - loop — bool - orienttospline — bool per update: 1. length = spline -> get spline length. 2. distancecm += speedcmpersec direction deltaseconds. 3. loop: wrap into [0, length); non-loop: clamp into [0, length]. 4. get transform at distance along spline in world space. 5. if orientation is disabled, use only returned location. 6. apply with set actor transform or move the intended component. 7. define end behavior explicitly: stop, loop, reverse, fire event, or dwell. do not drive constant speed with get location at spline input key plus a linearly increasing key. parametric distance is not guaranteed to be uniform. closest progress to an actor 1. read actor world location. 2. use get distance along spline at location with world coordinate space. 3. use the returned distance for progress, ordering, or a subsequent transform query. 4. if the spline crosses itself, retain previous progress and constrain how far the result may jump between updates. rigid objects at uniform intervals 1. get spline length. 2. choose either: - fixed maximum spacing: count = ceil(length / maxspacing); - approximately target spacing with even end fit: count = round(length / targetspacing). 3. compute actualspacing = length / max(1, count). 4. iterate 0..count when both endpoints need objects; otherwise 0..count-1. 5. query transform at index actualspacing. 6. add an ism/hism instance for repeated meshes; spawn actors only when each instance needs independent behavior. 7. apply lateral offset in the sampled transform's right-vector direction. continuous deformed mesh for each consecutive pair of spline points: 1. create or reuse one spline mesh component. 2. query start/end locations and tangents in the spline owner's local space. 3. assign the static mesh and forward axis. 4. call set start and end with start position/tangent and end position/tangent. 5. apply start/end scale or roll only if required by the design. 6. register the component when created at runtime. 7. store generated components in an array. destroy/clear them before regeneration. for a closed loop, include the last-to-first segment. editable blueprint generator recommended layout: - actor root - spline component - exposed mesh/material/spacing/width/collision variables - generatedcomponents array - rebuild function used by construction script and explicit runtime updates rebuild: 1. destroy or clear previously generated components/instances. 2. validate spline point count and assets. 3. generate deterministically from current spline data. 4. do not modify the designer's control points unless that is the tool's explicit job. landscape road 1. enter landscape manage mode and select spline. 2. create/join/split control points and segments. 3. add a dedicated spline edit layer before expecting heightmap deformation. 4. set segment mesh, width, side falloff, layer name, and raise/lower behavior. 5. snap points to landscape where appropriate. 6. inspect intersections, steep grades, tangents, and material paint transitions. pcg spline authoring in ue 5.8 - enable and enter pcg editor mode. - use draw spline for roads, fences, and line placement. - use draw spline surface for closed fields or bounded scattering. - use graph refresh-rate controls when interactive generation is expensive. - use apply spline to component when pcg must update an existing spline component. - mark the workflow experimental in production documentation and provide a fallback. ue 5.8 primary sources ue 5.8 primary sources - epic games, blueprint spline components overview - epic games, usplinecomponent api - epic games, usplinemeshcomponent api - epic games, landscape splines - epic games, construction script - epic games, pcg editor mode - epic games, ue 5.8 release notes — pcg - epic games, get distance along spline at location version target: unreal engine 5.8. recheck api names and experimental status before using this skill with a later engine version. troubleshooting troubleshooting | symptom | likely cause | action | |---|---|---| | actor speeds up and slows down | sampling by input key or normalized parameter | advance and sample by distance along spline | | objects bunch on curves | sampling control-point intervals rather than arc length | use spline length and distance queries | | mesh is sideways | wrong source-mesh length axis / forward axis | identify source mesh longitudinal axis and match it | | mesh twists or flips | inconsistent up vector, roll, or extreme tangent change | set a stable up-vector convention; inspect point roll and tangents; add points at controlled bends | | visible kink at segment boundary | tangents or segment scale do not match | use spline-provided tangents at both ends; keep adjacent scale/roll continuous | | severe stretching | segment is too long for source mesh or tangent magnitude is extreme | increase segment count or author a longer/denser source mesh | | last fence gap is wrong | fixed spacing without fitting total length | recompute actual spacing from rounded interval count | | generated objects duplicate when editing | construction script is appending without cleanup | destroy/clear generated components or instances before rebuilding | | editor becomes slow while dragging points | heavy construction script, collision rebuild, or too many components | debounce/bake generation; disable unneeded collision; use ism/hism or pcg | | runtime mutation does not update queries | spline changed without final update | batch mutations and call the spline update once | | collision does not match deformation | collision disabled, stale, or expensive dynamic update | confirm collision settings; rebuild only after geometry changes; test cooked behavior | | closed-loop seam pops | missing last-to-first segment or discontinuous roll/tangent | generate closing segment and align seam properties | | camera looks unstable | tangent rotation is not the desired framing | separate position rail from look target; smooth look rotation independently | | patrol agent hits obstacles | spline is not obstacle-aware navigation | sample spline goals and move via navmesh/path following | | network clients disagree | each client mutates path independently | make spline/path state authoritative and replicate deterministic inputs or results | verification checklist - draw/debug the spline and inspect point order. - print spline length and sampled distance. - test distance 0, length / 2, and length. - test shortest and tightest segments. - test reverse and loop boundaries. - test editor reconstruction after moving, duplicating, and undoing the actor. - test collision in standalone and packaged builds. - profile component count, collision, construction script time, and runtime updates. system selector and use cases system selector and use cases choose by output | desired output | use | avoid | |---|---|---| | invisible path, rail, route, or transform field | spline component | spline mesh unless geometry must bend | | bent road strip, pipe, cable, hose, curb, or continuous fence rail | spline component + one spline mesh component per segment | one spline mesh for the whole path | | rigid posts, lamps, trees, signs, or modular props | spline component + ism/hism or spawned actors | deforming the props with spline mesh | | road/path that raises, lowers, or paints landscape | landscape splines on a dedicated spline edit layer | blueprint spline as a terrain-deformation substitute | | procedural content on a line | pcg draw spline / spline data | construction script spawning thousands of actors | | procedural content inside a closed shape | pcg draw spline surface | treating an open path as an area | | camera motion | spline component for position; optional second spline/target for aim | deriving look rotation from tangent when the camera must frame a subject | | ai patrol | spline component as route data plus explicit direction/dwell state | using spline motion as navigation around dynamic obstacles | use-case decisions roads and paths - use landscape splines when terrain conformity and terrain painting are primary. - use spline mesh components when road geometry is authored as deformable modular segments independent of landscape. - keep road width, shoulder width, falloff, material, mesh, collision, and segment length exposed as data. - for pcg-authored roads in ue 5.8, treat pcg editor mode as experimental. the 5.8 apply spline to component node can write pcg spline data to an existing component. cables, pipes, and hoses - use short-enough source meshes that bend without obvious shearing. - ensure source mesh length axis matches the spline mesh forward axis. - use tangent magnitude to control curvature; do not use point position alone. - disable collision unless gameplay needs it. test dynamic collision cost separately. fences - deform only continuous rails or walls. - place posts as rigid instances by distance. - compute the final interval from spline length so the last gap is not visibly short: count = max(1, round(length / targetspacing)), then actualspacing = length / count. camera rails - store travel as distance, not normalized time, if speed is specified in cm/s. - use a timeline/curve to remap time to distance for authored acceleration. - use spline tangent for forward-facing travel; use find look at rotation toward a target for subject framing. - apply camera easing separately from spline geometry. patrol paths - track distance, direction (+1 or -1), speedcmpersec, and dwell state. - closed loop: wrap distance by spline length. - ping-pong: clamp at ends, reverse direction, then apply dwell. - use navmesh pathing between sampled spline goals if agents must avoid obstacles. placement along a spline - uniform physical spacing: sample by distance. - one object per control point: sample by point index. - orientation: use transform/rotation at distance; optionally preserve world up for props that must remain vertical. - random variation: seed it; separate along-path distance jitter from lateral offset. construction versus runtime | need | location | |---|---| | designer drags points and sees generated geometry immediately | construction script | | path is fixed after level load | construction script or baked editor tool | | path changes during play | runtime function called only when data changes | | object travels along fixed path | tick, timeline, or movement task; do not rebuild spline | | thousands of procedural placements | pcg or instancing; avoid individual actor construction |

Action patterns

# Action patterns

## Constant-speed actor movement

Variables:

- `DistanceCm` — float
- `SpeedCmPerSec` — float
- `Direction` — `1.0` or `-1.0`
- `Loop` — bool
- `OrientToSpline` — bool

Per update:

1. `Length = Spline -> Get Spline Length`.
2. `DistanceCm += SpeedCmPerSec * Direction * DeltaSeconds`.
3. Loop: wrap into `[0, Length)`; non-loop: clamp into `[0, Length]`.
4. `Get Transform at Distance Along Spline` in World space.
5. If orientation is disabled, use only returned location.
6. Apply with `Set Actor Transform` or move the intended component.
7. Define end behavior explicitly: stop, loop, reverse, fire event, or dwell.

Do not drive constant speed with `Get Location at Spline Input Key` plus a linearly
increasing key. Parametric distance is not guaranteed to be uniform.

## Closest progress to an actor

1. Read actor world location.
2. Use `Get Distance Along Spline at Location` with World coordinate space.
3. Use the returned distance for progress, ordering, or a subsequent transform query.
4. If the spline crosses itself, retain previous progress and constrain how far the
   result may jump between updates.

## Rigid objects at uniform intervals

1. Get spline length.
2. Choose either:
   - fixed maximum spacing: `count = ceil(length / maxSpacing)`;
   - approximately target spacing with even end fit: `count = round(length / targetSpacing)`.
3. Compute `actualSpacing = length / max(1, count)`.
4. Iterate `0..count` when both endpoints need objects; otherwise `0..count-1`.
5. Query transform at `index * actualSpacing`.
6. Add an ISM/HISM instance for repeated meshes; spawn actors only when each instance
   needs independent behavior.
7. Apply lateral offset in the sampled transform's right-vector direction.

## Continuous deformed mesh

For each consecutive pair of spline points:

1. Create or reuse one Spline Mesh Component.
2. Query start/end locations and tangents in the spline owner's Local space.
3. Assign the static mesh and `Forward Axis`.
4. Call `Set Start and End` with start position/tangent and end position/tangent.
5. Apply start/end scale or roll only if required by the design.
6. Register the component when created at runtime.
7. Store generated components in an array. Destroy/clear them before regeneration.

For a closed loop, include the last-to-first segment.

## Editable Blueprint generator

Recommended layout:

- Actor root
- Spline Component
- Exposed mesh/material/spacing/width/collision variables
- `GeneratedComponents` array
- `Rebuild` function used by Construction Script and explicit runtime updates

`Rebuild`:

1. Destroy or clear previously generated components/instances.
2. Validate spline point count and assets.
3. Generate deterministically from current spline data.
4. Do not modify the designer's control points unless that is the tool's explicit job.

## Landscape road

1. Enter Landscape Manage mode and select Spline.
2. Create/join/split control points and segments.
3. Add a dedicated Spline Edit Layer before expecting heightmap deformation.
4. Set segment mesh, width, side falloff, layer name, and raise/lower behavior.
5. Snap points to Landscape where appropriate.
6. Inspect intersections, steep grades, tangents, and material paint transitions.

## PCG spline authoring in UE 5.8

- Enable and enter PCG Editor Mode.
- Use Draw Spline for roads, fences, and line placement.
- Use Draw Spline Surface for closed fields or bounded scattering.
- Use graph refresh-rate controls when interactive generation is expensive.
- Use `Apply Spline to Component` when PCG must update an existing Spline Component.
- Mark the workflow experimental in production documentation and provide a fallback.

UE 5.8 primary sources

# UE 5.8 primary sources

- Epic Games, [Blueprint Spline Components Overview](https://dev.epicgames.com/documentation/en-us/unreal-engine/blueprint-spline-components-overview-in-unreal-engine)
- Epic Games, [`USplineComponent` API](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/USplineComponent)
- Epic Games, [`USplineMeshComponent` API](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/USplineMeshComponent)
- Epic Games, [Landscape Splines](https://dev.epicgames.com/documentation/en-us/unreal-engine/landscape-splines-in-unreal-engine)
- Epic Games, [Construction Script](https://dev.epicgames.com/documentation/en-us/unreal-engine/construction-script-in-unreal-engine)
- Epic Games, [PCG Editor Mode](https://dev.epicgames.com/documentation/en-us/unreal-engine/pcg-editor-mode-in-unreal-engine)
- Epic Games, [UE 5.8 Release Notes — PCG](https://dev.epicgames.com/documentation/unreal-engine/unreal-engine-5-8-release-notes?lang=en-US)
- Epic Games, [`Get Distance Along Spline at Location`](https://dev.epicgames.com/documentation/unreal-engine/BlueprintAPI/Spline/GetDistanceAlongSplineatLocation)

Version target: Unreal Engine 5.8. Recheck API names and experimental status before
using this skill with a later engine version.

Troubleshooting

# Troubleshooting

| Symptom | Likely cause | Action |
|---|---|---|
| Actor speeds up and slows down | Sampling by input key or normalized parameter | Advance and sample by distance along spline |
| Objects bunch on curves | Sampling control-point intervals rather than arc length | Use spline length and distance queries |
| Mesh is sideways | Wrong source-mesh length axis / `Forward Axis` | Identify source mesh longitudinal axis and match it |
| Mesh twists or flips | Inconsistent up vector, roll, or extreme tangent change | Set a stable up-vector convention; inspect point roll and tangents; add points at controlled bends |
| Visible kink at segment boundary | Tangents or segment scale do not match | Use spline-provided tangents at both ends; keep adjacent scale/roll continuous |
| Severe stretching | Segment is too long for source mesh or tangent magnitude is extreme | Increase segment count or author a longer/denser source mesh |
| Last fence gap is wrong | Fixed spacing without fitting total length | Recompute actual spacing from rounded interval count |
| Generated objects duplicate when editing | Construction Script is appending without cleanup | Destroy/clear generated components or instances before rebuilding |
| Editor becomes slow while dragging points | Heavy Construction Script, collision rebuild, or too many components | Debounce/bake generation; disable unneeded collision; use ISM/HISM or PCG |
| Runtime mutation does not update queries | Spline changed without final update | Batch mutations and call the spline update once |
| Collision does not match deformation | Collision disabled, stale, or expensive dynamic update | Confirm collision settings; rebuild only after geometry changes; test cooked behavior |
| Closed-loop seam pops | Missing last-to-first segment or discontinuous roll/tangent | Generate closing segment and align seam properties |
| Camera looks unstable | Tangent rotation is not the desired framing | Separate position rail from look target; smooth look rotation independently |
| Patrol agent hits obstacles | Spline is not obstacle-aware navigation | Sample spline goals and move via NavMesh/path following |
| Network clients disagree | Each client mutates path independently | Make spline/path state authoritative and replicate deterministic inputs or results |

## Verification checklist

- Draw/debug the spline and inspect point order.
- Print spline length and sampled distance.
- Test distance `0`, `length / 2`, and `length`.
- Test shortest and tightest segments.
- Test reverse and loop boundaries.
- Test editor reconstruction after moving, duplicating, and undoing the actor.
- Test collision in standalone and packaged builds.
- Profile component count, collision, Construction Script time, and runtime updates.

System selector and use cases

# System selector and use cases

## Choose by output

| Desired output | Use | Avoid |
|---|---|---|
| Invisible path, rail, route, or transform field | Spline Component | Spline Mesh unless geometry must bend |
| Bent road strip, pipe, cable, hose, curb, or continuous fence rail | Spline Component + one Spline Mesh Component per segment | One Spline Mesh for the whole path |
| Rigid posts, lamps, trees, signs, or modular props | Spline Component + ISM/HISM or spawned actors | Deforming the props with Spline Mesh |
| Road/path that raises, lowers, or paints Landscape | Landscape Splines on a dedicated Spline Edit Layer | Blueprint spline as a terrain-deformation substitute |
| Procedural content on a line | PCG Draw Spline / spline data | Construction Script spawning thousands of actors |
| Procedural content inside a closed shape | PCG Draw Spline Surface | Treating an open path as an area |
| Camera motion | Spline Component for position; optional second spline/target for aim | Deriving look rotation from tangent when the camera must frame a subject |
| AI patrol | Spline Component as route data plus explicit direction/dwell state | Using spline motion as navigation around dynamic obstacles |

## Use-case decisions

### Roads and paths

- Use Landscape Splines when terrain conformity and terrain painting are primary.
- Use Spline Mesh Components when road geometry is authored as deformable modular
  segments independent of Landscape.
- Keep road width, shoulder width, falloff, material, mesh, collision, and segment
  length exposed as data.
- For PCG-authored roads in UE 5.8, treat PCG Editor Mode as experimental. The 5.8
  `Apply Spline to Component` node can write PCG spline data to an existing component.

### Cables, pipes, and hoses

- Use short-enough source meshes that bend without obvious shearing.
- Ensure source mesh length axis matches the Spline Mesh `Forward Axis`.
- Use tangent magnitude to control curvature; do not use point position alone.
- Disable collision unless gameplay needs it. Test dynamic collision cost separately.

### Fences

- Deform only continuous rails or walls.
- Place posts as rigid instances by distance.
- Compute the final interval from spline length so the last gap is not visibly short:
  `count = max(1, round(length / targetSpacing))`, then
  `actualSpacing = length / count`.

### Camera rails

- Store travel as distance, not normalized time, if speed is specified in cm/s.
- Use a Timeline/curve to remap time to distance for authored acceleration.
- Use spline tangent for forward-facing travel; use `Find Look At Rotation` toward a
  target for subject framing.
- Apply camera easing separately from spline geometry.

### Patrol paths

- Track `Distance`, `Direction` (`+1` or `-1`), `SpeedCmPerSec`, and dwell state.
- Closed loop: wrap distance by spline length.
- Ping-pong: clamp at ends, reverse direction, then apply dwell.
- Use NavMesh pathing between sampled spline goals if agents must avoid obstacles.

### Placement along a spline

- Uniform physical spacing: sample by distance.
- One object per control point: sample by point index.
- Orientation: use transform/rotation at distance; optionally preserve world up for
  props that must remain vertical.
- Random variation: seed it; separate along-path distance jitter from lateral offset.

## Construction versus runtime

| Need | Location |
|---|---|
| Designer drags points and sees generated geometry immediately | Construction Script |
| Path is fixed after level load | Construction Script or baked editor tool |
| Path changes during play | Runtime function called only when data changes |
| Object travels along fixed path | Tick, Timeline, or movement task; do not rebuild spline |
| Thousands of procedural placements | PCG or instancing; avoid individual actor construction |