Movement Authority
Movement is server-authoritative. The client sends small, sequenced move inputs over the negotiated realtime transport, and the game server queues, reorders, drains, validates, simulates, and acknowledges them on zone ticks.
The client never commits final position. It proposes tile deltas, and the server returns ServerMovementCorrection packets that carry the acknowledged input sequence and the authoritative player snapshot.
Input Shape
MoveInput is the shared decoded shape:
sequence: monotonic client input sequence.dxanddy: tile-step deltas clamped and validated to-1..=1.
Single inputs can arrive on the reliable stream as ClientMoveInput. Datagram movement can arrive as one input or as MoveInputBatch { first_sequence, steps }. Batches are capped by MAX_MOVE_INPUT_STEPS_PER_BATCH and are applied atomically: if any step is rejected, the session movement window is restored to its pre-batch state.
Transport Contract
Movement input transport is negotiated through the realtime runtime profile:
- Datagram-capable sessions use datagram movement as the primary path and stream movement as fallback.
- Sessions without compatible datagrams use stream-only movement.
- Datagram movement uses the
MoveInputclient datagram contract and is bounded by the generated datagram byte limit. - Stream movement uses the
ClientMoveInputstream packet contract. - Both paths recover through
ServerMovementCorrection, which acknowledges the latest accepted sequence.
Ingress validates that the selected transport is allowed by the session runtime profile before accepting an input. Transport violations are rejected as malformed input for that transport, not silently downgraded.
Datagram degradation is tracked per session. When stream fallback inputs are accepted after datagram trouble, the server records fallback transport decisions and can send a move_input_datagram_degraded advisory. When primary datagram movement resumes, it records recovery and can send move_input_datagram_recovered.
Sequence Window
Each active session owns a MoveInputWindow with:
- a pending queue for contiguous inputs ready for simulation;
- a future-input map for out-of-order inputs inside the reorder window;
last_received_move_sequence;last_acknowledged_move_sequence.
The expected first sequence is 1. After that, expected sequence advances from the last received sequence, or from the last acknowledged sequence when no newer input has been received.
Accepted inputs are classified as:
Queued: the input is contiguous and ready for the authority tick;BufferedFuture: the input is in the future window and waits for missing sequences.
Rejected inputs are classified as:
StaleSequence: sequence is older than the expected sequence;QueueFull: pending plus future input count reached the session limit;FutureWindowExceeded: input is beyond the reorder window;DuplicateFutureSequence: future input with that sequence already exists.
When a contiguous input is queued, buffered future inputs drain into the pending queue as long as they remain contiguous and capacity is available.
Authority Tick
Zone simulation runs on the game-server zone tick. The default zone tick interval is 100 ms. During each zone tick, the server applies authoritative movement after scene combat AI and before dirty location persistence.
For each session, movement authority drains up to movement_authority_max_inputs_per_tick pending inputs. The default comes from the shared protocol cadence, and the game-server config can override it with AETHER_GAME_MOVEMENT_AUTHORITY_MAX_INPUTS_PER_TICK. The effective value is clamped to at least 1.
Each tick report records:
- pending input count before and after simulation;
- future input count before and after simulation;
- drained input sequences;
- optional correction packet data.
The server acknowledges every drained input. If the move is blocked, the acknowledged sequence still advances, but the authoritative tile remains unchanged.
Walkability
Movement checks the zone's cached RuntimeTileWalkabilityProjection through ZoneMovementWalkabilityProjection. The projection combines scene bounds and runtime blocking data, with optional occupied-tile checks.
For each drained input, the server computes a candidate tile from the current authoritative tile plus dx and dy:
- If the candidate tile is in bounds and walkable, the player tile changes, motion/facing presentation is retargeted, and the session location is marked dirty.
- If the candidate tile is blocked or out of bounds, the player stays on the current tile, presentation snaps back to the authoritative tile, and the correction still acknowledges the input.
This keeps client prediction bounded: stale predicted positions are corrected by the next movement correction rather than by accepting client coordinates.
Transfer State
Movement is frozen during zone or instance transfer. When a pending transfer token is set, buffered movement inputs are cleared so old datagrams cannot replay across an instance boundary. Authority ticks skip movement while the transfer is pending.
Transfer relocation helpers also clear pending inputs and reset motion presentation. Zone-transfer sync clears AOI visibility state as well, because the next zone needs a fresh replication baseline.
For the larger handoff flow, see Session Handoff And Transfer.
Correction Packets
AuthoritativeMoveCorrection contains:
- the authoritative replicated player snapshot;
acknowledged_sequence, the latest input sequence consumed by authority.
Zone simulation queues movement corrections on both the reliable stream and the server movement-correction datagram path. The delivery metadata treats corrections as recoverable and duplicate-safe. A correction packet is also the acknowledgement rule for client movement input, so clients should retain unacknowledged inputs until the acknowledged sequence advances.
Forced sync helpers use the same correction shape when the server must snap a player to the current authoritative position, such as after transfer activation or relocation.
Metrics And Diagnostics
Movement ingress records decisions by transport, outcome, and reason. Common labels include:
datagram:accepted:queued;datagram:accepted:buffered_future;stream:rejected:future_window_exceeded;stream:ignored:session_transfer_pending.
Transport failover records decisions such as accepted stream fallback and primary datagram recovery.
Authority tick metrics record per-zone backlog before and after the tick, drained input decisions, remaining backlog, and movement-correction decisions. Rejection logs include movement-window diagnostics such as last received sequence, last acknowledged sequence, pending count, future count, and drained sequences.
Tuning
Primary production tuning:
AETHER_GAME_MOVEMENT_AUTHORITY_MAX_INPUTS_PER_TICK: overrides how many pending movement inputs a session can drain per zone tick. The value is clamped to at least1.
Other movement limits are compatibility-significant runtime-profile or registry values rather than direct game-server environment variables:
- max pending inputs per session;
- movement reorder window;
- stream fallback delay;
- datagram degraded streak threshold;
- client movement datagram byte budget;
- batch step count.
Change those through the shared protocol/runtime profile path so client, server, validation, and generated descriptors stay aligned.
Operational Checks
When investigating movement incidents:
- Check whether the session was in transfer state. Transfer-pending movement is intentionally ignored.
- Compare rejected ingress labels with sequence-window diagnostics.
- Confirm the negotiated runtime profile allows the transport being used.
- Inspect authority backlog metrics for a zone-level drain bottleneck.
- Verify walkability projection changes if corrections acknowledge input but do not move the player.
- Check correction delivery and acknowledged sequence progression before assuming client prediction is wrong.