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 templates
references/ - Best practices