Network sync: claim (distributed authority)
Shares authority between players by claim: each client simulates the objects it has claimed, such as its avatar or a car it drives, while the server only arbitrates and everything else is shown interpolated.
Network sync: claim (distributed authority) (net.claim) #
What it is for #
Shares authority between players by claim: each client simulates the objects it has claimed, such as its avatar or a car it drives, while the server only arbitrates and everything else is shown interpolated.
It needs net.transport, game.engine; installing it brings them in.
Turn it on #
Install the kit in a project, then change a setting (the values shown are its defaults):
gripforge_gamekit_install { project_id: "gkp_…", id: "net.claim" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "net.claim",
config: { "snapshotHz": 20, "publishHz": 20 } }
First example #
<!-- test: kits/net_claim/tests/net_claim.rs::connecting_publishes_the_player_as_a_locked_avatar_once --> This is the body of the passing test connecting_publishes_the_player_as_a_locked_avatar_once; the helper functions it calls are defined at the top of the same test file.
#[test]
fn connecting_publishes_the_player_as_a_locked_avatar_once() {
let mut s = online(json!({}));
player(&mut s, 1.0, 2.0);
answer(&mut s, "c:create", json!(40));
connect(&mut s, 3);
let sent = commands(&mut s);
let creates: Vec<&Json> = sent.iter().filter(|c| c["c"] == "create").collect();
assert_eq!(creates.len(), 1);
assert_eq!(creates[0]["state"]["p"], json!([1, 0, 2]));
assert_eq!(creates[0]["state"]["d"], json!({ "kind": "avatar" }));
assert_eq!(creates[0]["lock"], true);
assert_eq!(call(&mut s, KIT, "netIdOf", json!(["e1"])), json!(40));
assert_eq!(call(&mut s, KIT, "entityOf", json!([40])), json!("e1"));
step(&mut s, 2);
assert!(
commands(&mut s).iter().all(|c| c["c"] != "create"),
"never created twice"
);
}
Settings and defaults #
Descriptions come from the kit manifest and stay in English.
| Setting | Type | Default | Range or values | Meaning |
|---|---|---|---|---|
snapshotHz | integer | 20 | 1–120 | Server → clients state rate (Hz). |
publishHz | integer | 20 | 1–120 | Owner → server state rate (Hz). |
leaseMs | integer | 750 | 100–60000 | An owner silent this long loses its objects (they revert to the server). |
stickyMs | integer | 250 | 0–10000 | Minimum hold before another peer may take an object (anti ping-pong). |
maxHoldMs | integer | 0 | 0–3600000 | Cap on one hold (0 = none). |
stealPolicy | string | "priority" | never, priority, always | Owned object claimed by another peer: never (first wins), priority (strictly higher priority wins), always (latest wins). |
maxClaimsPerPeer | integer | 64 | 1–4096 | Objects one peer may hold at once. |
maxObjectsPerPeer | integer | 256 | 0–65536 | Objects one peer may create. |
maxObjects | integer | 4096 | 1–1000000 | Cap on all replicated objects: clients cannot create beyond it. |
keyframeEvery | integer | 20 | 1–1000 | Every Nth snapshot carries every object (heals lost deltas). |
maxSpeed | number | 300 | 0–10000 | Plausibility: max speed of a published object in m/s (0 = off). |
worldLimit | number | 2000 | 1–1000000 | Positions beyond ±worldLimit m are rejected. |
maxAngularSpeed | number | 1000 | 0–1000000 | Published angular velocities beyond this (rad/s, per axis) are rejected. |
antiCheat | boolean | true | Plausibility check of published moves (maxSpeed × plausibilitySlack + plausibilityMarginM over the elapsed time); false = trust… | |
plausibilitySlack | number | 1.5 | 1–10 | Anti-cheat: tolerance factor on maxSpeed (jitter, bursts). |
plausibilityMarginM | number | 0.5 | 0–100 | Anti-cheat: distance always allowed on top (m). |
plausibilityMinDtMs | integer | 50 | 1–1000 | Anti-cheat: the elapsed time counts as at least this (two publishes arriving together). |
onOwnerLeave | string | "revert" | revert, destroy | Objects created by a peer that leaves: kept (server-owned) or destroyed. |
interpolationMs | integer | 100 | 0–1000 | Remote objects are drawn this far in the past. |
interpolationBuffer | integer | 32 | 2–256 | Remote samples kept per object. |
extrapolateMs | integer | 250 | 0–1000 | Extrapolate at most this long past the newest remote sample. |
reclaimMs | integer | 500 | 50–10000 | A pending claim is sent again after this long without an answer. |
handoverMinMs | integer | 200 | 0–5000 | Blend from the local simulation to the new owner: at least… |
handoverMaxMs | integer | 2000 | 0–10000 | …at most (the blend lasts about one RTT). |
snapDistance | number | 4 | 0.01–1000 | Errors above this (m) snap instead of blending. |
optimistic | boolean | true | Drive a claimed object at once, before the grant arrives. | |
sleepKeyframeMs | 0 | Owner: a sleeping body is still published this often, so its lease never expires (0 = auto: min(1000, leaseMs / 3)); must stay… | ||
pushExtrapolateMs | integer | 100 | 0–1000 | physics: the server predicts a pushed body at most this far ahead. |
maxStepsPerUpdate | integer | 16 | 1–256 | physics: server steps per host frame at most (the backlog of a stalled host is dropped). |
clientMaxStepsPerUpdate | integer | 8 | 1–256 | physics: client steps per host frame at most. |
maxClientBodySize | number | 50 | 0.01–1000 | physics shared: largest extent / radius (m) of a body a client creates. |
maxClientBodyMass | number | 10000 | 0–1000000 | physics shared: largest mass (kg) of a body a client creates. |
autoClaimRadius | number | 0 | 0–1000 | Web runtime: claim objects tagged net_claimable within this distance of the player (0 = only explicit claims); released beyond… |
physics | string | "none" | none, native, shared | Bodies: none; native = the engine physics simulates (owner / dedicated server), the core replicates states, sleep and… |
avatar | boolean | true | Web runtime: publish the local player entity as this client's avatar object. |
Services, events, variables #
- Service
net.sync: The project replication model (one per project: the net.* sync kits conflict with each other). - Service
net.claim: claim(entity, priority) / release(entity) / isOwner(entity) / create(state); ownership events. - Events emitted:
net.owner(entity,netId,owner,mine) — Ownership of a replicated object changed.net.denied(entity,netId,why) — A claim was refused (owned, sticky, quota, locked, unknown).
- Variables:
net.status(string) — Network statusnet.rtt(number) — Ping (ms)net.peers(number) — Players online
Hooks and modding #
This kit declares no hook and no collection to mod.
Engines #
Declared targets: web, godot, unity, unreal. gripforge kit api net.claim lists the exact settings and services of your version.
Versions #
Kit version 1.2.0.