first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
# `entity-sync`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Top-level manager for networked entity state. Tracks every entity by id,
buffers remote-peer history for interpolation, samples local entities at the
configured send rate, and exposes the diagnostic snapshot needed by HUD
overlays. Hot-path methods stay allocation-free except for the result array
returned by `collectLocalUpdates`.
## Features
- Per-entity `StateBuffer` for remote sources, automatic `EntityInterpolator`
binding.
- Per-frame `updateRemoteEntities(serverTime)` walks every remote and writes
the interpolated transform back to the entity record.
- `shouldSend(currentTime)` gates outbound messages against the configured
send rate.
- Records `r3f_net.snapshots_total{outcome}` for every receive, including the
`out_of_order` outcome surfaced from `StateBuffer.push`.
- Zod-validated options; bad input throws `R3F_NET.INVALID_OPTIONS`.
## Usage: Basic Example
```ts
import { EntitySyncManager } from "@suaveplan/r3f-networking";
const sync = new EntitySyncManager({ sendRate: 20 });
sync.registerEntity("e1", "me", true);
sync.registerEntity("e2", "peer", false);
sync.receiveUpdate({
entityId: "e2",
transform: { position: [1, 0, 0], rotation: [0,0,0,1], scale: [1,1,1] },
timestamp: 1000,
seq: 1,
});
sync.updateRemoteEntities(1100);
```
## Usage: Advanced Example
Drive sync from a transport receive callback and a per-frame R3F hook:
```ts
transport.onMessage((peer, env) => {
const msg = decodeUpdate(env.payload);
sync.receiveUpdate(msg);
});
useFrame((state) => {
const t = state.clock.elapsedTime * 1000;
sync.updateRemoteEntities(t);
if (sync.shouldSend(t)) {
for (const m of sync.collectLocalUpdates(t)) transport.broadcast(m);
}
});
```
## API Reference
- `new EntitySyncManager(config?: EntitySyncConfig)`
- `registerEntity(id, ownerId, isLocal, initial?)` / `unregisterEntity(id)`
- `receiveUpdate(message: EntityUpdateMessage)`
- `updateRemoteEntities(serverTime: number)`
- `updateLocalEntity(id, transform)`
- `shouldSend(currentTime): boolean`
- `collectLocalUpdates(timestamp): EntityUpdateMessage[]`
- `getSnapshot(): SyncSnapshot`
- `getEntityCount(): number` / `clear()`
## Implementation Notes
The send-rate gate uses wall-clock time on each frame rather than a setInterval
so missed frames cannot accumulate. Remote `out_of_order` errors are swallowed
and reported through the OTel counter — surfacing them as exceptions would
cascade-kill the consuming r3f frame loop on transient jitter. The
`enablePrediction` flag is consumed by hooks that wire `ClientPredictor`
externally; the manager itself does not predict.