Skip to content

feat: WorldResyncAsync, to ask for a fresh baseline after frames go missing - #50

Merged
Taure merged 1 commit into
mainfrom
feat/world-tick-gap-detection
Aug 17, 2026
Merged

Taure merged 1 commit into
mainfrom
feat/world-tick-gap-detection

Conversation

@Taure

@Taure Taure commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

asobi v0.89.0 stamps zone, frame_seq and kf on the world.tick payload.
This SDK hands OnWorldTick the raw payload string and parses none of it, so all
three already reach the game untouched - nothing was needed to expose them, and
this SDK is better off than the typed ones for that reason.

What was missing is the repair. Adds WorldResyncAsync(zoneX, zoneY), which asks
the server to re-send one zone's complete baseline. One zone rather than the
interest ring, which is nine zones at the default view radius, and the caller
already knows which zone gapped because the sequence is per zone.

No gap DETECTOR here, and that is a decision rather than an omission. asobi-godot
got one, but its dispatcher already holds a parsed Dictionary; this one holds a
string, and the only scanner available is JsonScan.ExtractField, which takes the
first match in the whole document. An entity inside updates carrying a field
named zone, frame_seq or kf would be read instead of the envelope's own,
silently and with no way for the caller to notice. Adding a real JSON reader to
support a detector costs far more than the detector is worth, and the game
already parses the frame to use updates at all, so it is better placed to read
the sequence than the SDK is. The XML doc on WorldResyncAsync explains all of
that, plus the two things a caller must get right: key entities on zone, and
adopt a kf frame even when its frame_seq is LOWER, because a zone restart
resets the sequence while the zone's identity does not.

The payload construction lives in WsFrame rather than AsobiRealtime, and that
placement is the point. Tests/AsobiCore.NET compiles WsFrame.cs but NOT
AsobiRealtime.cs, which references UnityEngine and cannot build outside the
editor - so anything written there is invisible to CI. Putting the frame-building
in WsFrame, beside WorldInputPayload where it belongs by symmetry, makes the part
that can actually be wrong testable. What remains untested is a single delegating
call.

Formatted with the invariant culture, and tested for it: a long carries no
decimal separator, but a culture that groups digits would splice a separator into
the array and produce a frame the server rejects as malformed - a bug that only
appears on someone else's machine.

Tests: three cases covering an ordinary coordinate pair, zero and negative
coordinates (zone [0,0] is a real zone and coordinates run negative either side
of the origin), and de-DE culture invariance. Suite 132/132.

…issing

asobi v0.89.0 stamps `zone`, `frame_seq` and `kf` on the world.tick payload.
This SDK hands OnWorldTick the raw payload string and parses none of it, so all
three already reach the game untouched - nothing was needed to expose them, and
this SDK is better off than the typed ones for that reason.

What was missing is the repair. Adds WorldResyncAsync(zoneX, zoneY), which asks
the server to re-send one zone's complete baseline. One zone rather than the
interest ring, which is nine zones at the default view radius, and the caller
already knows which zone gapped because the sequence is per zone.

No gap DETECTOR here, and that is a decision rather than an omission. asobi-godot
got one, but its dispatcher already holds a parsed Dictionary; this one holds a
string, and the only scanner available is JsonScan.ExtractField, which takes the
first match in the whole document. An entity inside `updates` carrying a field
named `zone`, `frame_seq` or `kf` would be read instead of the envelope's own,
silently and with no way for the caller to notice. Adding a real JSON reader to
support a detector costs far more than the detector is worth, and the game
already parses the frame to use `updates` at all, so it is better placed to read
the sequence than the SDK is. The XML doc on WorldResyncAsync explains all of
that, plus the two things a caller must get right: key entities on `zone`, and
adopt a `kf` frame even when its frame_seq is LOWER, because a zone restart
resets the sequence while the zone's identity does not.

The payload construction lives in WsFrame rather than AsobiRealtime, and that
placement is the point. Tests/AsobiCore.NET compiles WsFrame.cs but NOT
AsobiRealtime.cs, which references UnityEngine and cannot build outside the
editor - so anything written there is invisible to CI. Putting the frame-building
in WsFrame, beside WorldInputPayload where it belongs by symmetry, makes the part
that can actually be wrong testable. What remains untested is a single delegating
call.

Formatted with the invariant culture, and tested for it: a long carries no
decimal separator, but a culture that groups digits would splice a separator into
the array and produce a frame the server rejects as malformed - a bug that only
appears on someone else's machine.

Tests: three cases covering an ordinary coordinate pair, zero and negative
coordinates (zone [0,0] is a real zone and coordinates run negative either side
of the origin), and de-DE culture invariance. Suite 132/132.
@Taure
Taure merged commit ad66f36 into main Aug 17, 2026
3 checks passed
@Taure
Taure deleted the feat/world-tick-gap-detection branch August 17, 2026 19:48
@Taure
Taure restored the feat/world-tick-gap-detection branch August 17, 2026 23:17
@Taure
Taure deleted the feat/world-tick-gap-detection branch August 17, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant