@hastearcade/snowglobe
Version:
A TypeScript port of CrystalOrb, a high-level Rust game networking library
74 lines • 2.82 kB
JavaScript
import * as Timestamp from './timestamp.js';
export class CommandBuffer {
map;
_timestamp;
constructor(map = new Map(), _timestamp = Timestamp.make()) {
this.map = map;
this._timestamp = _timestamp;
// The original crystalorb implementation used a more effecient datatype
// to insert commands in reverse timestamp order.
// TODO investigate whether map is too slow here
}
timestamp() {
return this._timestamp;
}
filterStaleTimestamps(timestamp, before) {
if (timestamp != null) {
this.map.forEach((value, key) => {
if (Timestamp.cmp(key, timestamp) === (before ? -1 : 1)) {
this.map.delete(key);
}
});
}
}
updateTimestamp(timestamp) {
this._timestamp = timestamp;
const acceptableRange = Timestamp.comparableRangeWithMidpoint(this._timestamp);
this.filterStaleTimestamps(acceptableRange.min, true);
this.filterStaleTimestamps(acceptableRange.max, false);
}
drainAll() {
const sortedCommands = [...this.map.entries()].sort((a, b) => Timestamp.cmp(a[0], b[0]));
this.map.clear();
return sortedCommands.map(tc => tc[1]).flat();
}
drainUpTo(timestamp) {
const sortedCommands = [...this.map.entries()].sort((a, b) => Timestamp.cmp(a[0], b[0]));
const filteredCommands = sortedCommands.filter(tc => Timestamp.cmp(tc[0], timestamp) <= 0);
for (const [timestamp] of filteredCommands) {
this.map.delete(timestamp);
}
return filteredCommands.map(tc => tc[1]).flat();
}
insert(timestampedCommand) {
const incomingTimestamp = Timestamp.get(timestampedCommand);
if (Timestamp.acceptableTimestampRange(this._timestamp, incomingTimestamp)) {
const commandsExist = this.map.get(incomingTimestamp);
if (commandsExist == null) {
this.map.set(incomingTimestamp, [timestampedCommand]);
}
else {
this.map.set(incomingTimestamp, [...commandsExist, timestampedCommand]);
}
}
else {
console.warn("The command's timestamp is outside the acceptable range and will be ignored");
}
}
commandsAt(timestamp) {
return this.map.get(timestamp);
}
length() {
return this.map.size;
}
[Symbol.iterator]() {
return this.map.entries();
}
clone() {
return new CommandBuffer(new Map(Array.from(this.map.entries()).map(([timestamp, commands]) => [
timestamp,
commands.map(command => Timestamp.set(command.clone(), timestamp))
])), Timestamp.make(this._timestamp));
}
}
//# sourceMappingURL=command.js.map