34 lines
1.7 KiB
TypeScript
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; }
|
|
}
|