state-sync
Game state synchronization, snapshot systems, and conflict resolution for consistent multiplayer experience
When & Why to Use This Skill
This Claude skill provides comprehensive logic and architectural patterns for game state synchronization, ensuring a seamless and consistent multiplayer experience. It offers advanced implementations for snapshot interpolation, delta compression, and conflict resolution, supporting various synchronization models like lockstep and interest management to optimize network performance and reduce latency.
Use Cases
- Implementing smooth entity interpolation to eliminate jitter and 'teleporting' in high-latency network environments.
- Reducing server-to-client bandwidth consumption by applying delta compression to only transmit changed game state data.
- Architecting large-scale multiplayer environments using interest management to filter updates based on player proximity and visibility.
- Debugging and resolving complex 'rubber-banding' issues through robust state reconciliation and client-side prediction logic.
| name | state-sync |
|---|---|
| description | Game state synchronization, snapshot systems, and conflict resolution for consistent multiplayer experience |
| sasmp_version | "1.3.0" |
| version | "2.0.0" |
| bonded_agent | 04-state-sync-expert |
| bond_type | PRIMARY_BOND |
| type | counter |
| enum | [snapshot, delta, lockstep, interest_management] |
| min | 50 |
| max | 200 |
| default | 100 |
| max_attempts | 3 |
| backoff | exponential |
| initial_delay_ms | 50 |
| level | debug |
| fields | [entity_count, delta_size, checksum] |
| - name | sync_desync_detected |
State Synchronization
Ensure consistent game state across all connected players.
Snapshot Interpolation
class SnapshotBuffer {
constructor(size = 3, delay = 100) {
this.buffer = [];
this.size = size;
this.delay = delay;
}
add(snapshot) {
this.buffer.push({
time: snapshot.serverTime,
entities: new Map(snapshot.entities)
});
while (this.buffer.length > this.size) {
this.buffer.shift();
}
}
interpolate(renderTime) {
const targetTime = renderTime - this.delay;
const [before, after] = this.findBrackets(targetTime);
if (!before || !after) return this.extrapolate();
const t = (targetTime - before.time) / (after.time - before.time);
return this.lerp(before, after, t);
}
lerp(before, after, t) {
const result = new Map();
for (const [id, a] of before.entities) {
const b = after.entities.get(id);
if (b) {
result.set(id, {
x: a.x + (b.x - a.x) * t,
y: a.y + (b.y - a.y) * t,
z: a.z + (b.z - a.z) * t
});
}
}
return result;
}
}
Delta Compression
class DeltaCompressor {
createDelta(baseline, current) {
const delta = { created: [], updated: [], deleted: [] };
for (const [id, entity] of current) {
const prev = baseline.get(id);
if (!prev) {
delta.created.push({ id, ...entity });
} else if (this.changed(prev, entity)) {
delta.updated.push({ id, ...this.diff(prev, entity) });
}
}
for (const [id] of baseline) {
if (!current.has(id)) delta.deleted.push(id);
}
return delta;
}
changed(a, b) {
return a.x !== b.x || a.y !== b.y || a.z !== b.z;
}
diff(prev, curr) {
const d = {};
if (prev.x !== curr.x) d.x = curr.x;
if (prev.y !== curr.y) d.y = curr.y;
if (prev.z !== curr.z) d.z = curr.z;
return d;
}
}
Sync Model Comparison
| Model | Latency | Bandwidth | Best For |
|---|---|---|---|
| Snapshot | Medium | High | Simple games |
| Delta | Medium | Low | Most games |
| Lockstep | High | Low | RTS, Fighting |
| Interest Mgmt | Low | Low | MMO |
Troubleshooting
Common Failure Modes
| Error | Root Cause | Solution |
|---|---|---|
| Teleporting | Empty buffer | Increase buffer size |
| Desync | Non-determinism | Add checksums |
| Rubber-banding | Bad reconciliation | Fix prediction |
| Invisible entities | AoI bug | Check interest radius |
Debug Checklist
// Check buffer state
console.log(`Buffer: ${buffer.length}/${buffer.size}`);
console.log(`Time span: ${buffer.getTimeSpan()}ms`);
// Verify checksums
const cs1 = computeChecksum(clientState);
const cs2 = computeChecksum(serverState);
console.log(`Match: ${cs1 === cs2}`);
Unit Test Template
describe('DeltaCompressor', () => {
test('detects changes', () => {
const compressor = new DeltaCompressor();
const baseline = new Map([['e1', { x: 0, y: 0 }]]);
const current = new Map([['e1', { x: 1, y: 0 }]]);
const delta = compressor.createDelta(baseline, current);
expect(delta.updated).toHaveLength(1);
expect(delta.updated[0].x).toBe(1);
});
});
Resources
assets/- Sync templatesreferences/- Best practices