Files
citygen/client/entities.ts
T

34 lines
1.7 KiB
TypeScript

import type { Agent, Delta, Snapshot } from './generated/city_pb';
interface Sample { previous: Agent; current: Agent; fromTick: number; toTick: number }
/** Keep only subscribed entities. Time is aligned to the latest server tick. */
export class EntityState {
private entities = new Map<number, Sample>();
private tick = 0;
private received = 0;
snapshot(snapshot: Snapshot, now = performance.now()) {
this.entities.clear(); this.tick = Number(snapshot.tick); this.received = now;
for (const a of snapshot.entities) this.entities.set(a.id, { previous: a, current: a, fromTick: this.tick, toTick: this.tick });
}
delta(delta: Delta, now = performance.now()) {
const tick = Number(delta.tick);
if (tick < this.tick) return;
this.tick = tick; this.received = now;
for (const id of delta.despawned) this.entities.delete(id);
for (const a of delta.spawned) this.entities.set(a.id, { previous: a, current: a, fromTick: tick, toTick: tick });
for (const a of delta.changed) {
const old = this.entities.get(a.id);
if (old) this.entities.set(a.id, { previous: old.current, current: a, fromTick: old.toTick, toTick: tick });
}
}
positions(now = performance.now()): { id: number; x: number; y: number }[] {
const renderTick = this.tick + (now - this.received - 200) / 100;
return [...this.entities].map(([id, s]) => {
const t = s.toTick === s.fromTick ? 1 : Math.max(0, Math.min(1, (renderTick - s.fromTick) / (s.toTick - s.fromTick)));
return { id, x: (s.previous.x + (s.current.x - s.previous.x) * t) / 100, y: (s.previous.y + (s.current.y - s.previous.y) * t) / 100 };
});
}
clear() { this.entities.clear(); }
get size() { return this.entities.size; }
}