// BLOG

Restoring a Player on Another Moon

Restoring a Player on Another Moon

Saving a player at planetary scale is not the same as saving a transform.

By 13–14 May, Ashes of the Unbound had dedicated-server persistence and a hierarchy of celestial coordinate frames. Joining those systems exposed every piece of context a simple position vector had been hiding: which body owns the location, which local origin was active, which frame contains the movement state and when the server is allowed to release the player back to normal play.

Server-owned restore data

The server remains authoritative, but restoration data is player-specific. The server resolves the durable identity, loads the correct state and sends the owning client only the payload needed to establish its view.

That owner-only boundary avoids broadcasting private or irrelevant restoration state to every connection. It also keeps the live client from selecting which durable record it wants to become. Identity resolution happens first; restore follows.

The payload includes more than an Unreal transform because an Unreal transform only makes sense inside the current local world.

Saving the body, sector and frame

A planetary location needs its owning celestial body and body-fixed context. A local character transform needs the origin against which it was expressed. If those identifiers are omitted, loading code must infer them from a large coordinate or from whichever body happens to be nearby.

Inference may work in a test level with one moon. It is not a persistence format.

The durable representation therefore carries enough context to reconstruct the local presentation after the server has identified the correct body and sector. The client can establish its origin, convert the durable state into that view, then place the character precisely.

Converting pending movement state

One of the restore defects demonstrated why every vector needs a frame.

The character could be placed correctly while a movement correction remained expressed in the source coordinate basis. Applying that correction after the destination frame was active sent motion in the wrong direction.

The fix was not another positional offset. It was an explicit coordinate-frame conversion for the correction itself. Velocities, impulses and accumulated corrections are not secondary details; they are directional state and must cross the same boundaries as placement.

This is a classic large-world failure because the screenshot at rest can look perfect. The bug appears on the first movement update.

Locking restore state

Rebuilding the correct client view is a sequence. During that sequence, ordinary movement, replication reactions or origin updates can race the restore and partially undo it.

Restore locks make the transition explicit. The client enters a controlled restoration state, establishes the required celestial context, applies placement and dependent movement state, validates completion and only then returns to ordinary play.

A lock is not a delay. It is a statement that normal operations are temporarily invalid while a state transition is incomplete.

World subsystems also have to respect runtime context. They are instantiated in multiple kinds of worlds, so server-only restoration cannot run merely because a subsystem exists. Net mode and world type decide which part of the path is active.

Testing first and second connection

The test path captured both the initial and subsequent connection states:

EvidenceRunner capture from the first dedicated-server connection.

EvidenceRunner capture from the second dedicated-server connection.

These frames were part of a larger diagnostic run, not proof that every restoration issue was closed. They establish the tested scene states and preserve the visible output around the connection sequence.

The remaining first-connection SkyLight issue

The same connection testing exposed a SkyLight problem in which first and later connections could capture different lighting states. That investigation continued beyond the restore work and remained open in the documented record through 18 May.

The latest pass demonstrated a one-run causal intervention: changing SkyAtmosphere admission state altered the captured cubemap content, and one control became worse. That supports a causal relationship. It does not yet establish the root cause, and it is not a production fix.

I am preserving that result in the Notebook rather than giving it a victory-lap article. The development record is more useful if “we learned which state influences the capture” remains distinct from “we fixed first connection lighting.”

What a complete restore requires

By 14 May, dedicated restoration had become an ordered server/client transition with stable identity, owner-only payloads, celestial context, explicit frame conversion and restore locks. That is a much more demanding definition than “the save struct deserialized.”

It is also what the game needs. Travelling between worlds only feels continuous if the machinery beneath it can preserve who the player is, where they belong and how every dependent system should interpret the first frame after they return.