@hiddentao/clockwork-engine
Version:
A TypeScript/PIXI.js game engine for deterministic, replayable games with built-in rendering
113 lines (112 loc) • 3.38 kB
JavaScript
export class GameRecorder {
constructor() {
this.recording = null;
this.isRecording = false;
this.eventManager = null;
this.deltaTicks = [];
this.totalTicks = 0;
}
/**
* Start recording a game session
* Begins recording from the current event manager
*/
startRecording(eventManager, gameConfig, descriptionOrMetadata, additionalMetadata) {
let metadata = {
createdAt: Date.now(),
version: "1.0.0",
};
if (typeof descriptionOrMetadata === "string") {
// Backward compatible: description string
if (descriptionOrMetadata) {
metadata.description = descriptionOrMetadata;
}
// Merge additional metadata if provided
if (additionalMetadata) {
metadata = { ...metadata, ...additionalMetadata };
}
}
else if (descriptionOrMetadata) {
// New usage: metadata object
metadata = {
...metadata,
...descriptionOrMetadata,
// Ensure createdAt is always set
createdAt: descriptionOrMetadata.createdAt || Date.now(),
};
}
this.recording = {
gameConfig,
events: [],
deltaTicks: [],
totalTicks: 0,
metadata,
};
this.deltaTicks = [];
this.totalTicks = 0;
this.eventManager = eventManager;
this.eventManager.setRecorder(this);
this.isRecording = true;
}
/**
* Record any game event
* Only records if currently recording
*/
recordEvent(event) {
if (this.isRecording && this.recording) {
this.recording.events.push({ ...event });
}
}
/**
* Record tick update with deltaTicks and totalTicks
* Only records if currently recording
*/
recordFrameUpdate(deltaTicks, totalTicks) {
if (this.isRecording && this.recording) {
this.deltaTicks.push(deltaTicks);
this.totalTicks = totalTicks;
}
}
/**
* Stop recording
* Recording data remains available via getCurrentRecording()
*/
stopRecording() {
if (!this.isRecording || !this.recording) {
return;
}
// Copy tick data to the recording
this.recording.deltaTicks = [...this.deltaTicks];
this.recording.totalTicks = this.totalTicks;
if (this.eventManager) {
this.eventManager.setRecorder(undefined);
this.eventManager = null;
}
this.isRecording = false;
}
/**
* Check if currently recording
*/
isCurrentlyRecording() {
return this.isRecording;
}
/**
* Get the current recording (without stopping it)
* Useful for inspecting recording state
*/
getCurrentRecording() {
return this.recording ? { ...this.recording } : null;
}
/**
* Reset the recorder, clearing any existing recording
*/
reset() {
this.recording = null;
this.isRecording = false;
this.deltaTicks = [];
this.totalTicks = 0;
if (this.eventManager) {
this.eventManager.setRecorder(undefined);
this.eventManager = null;
}
}
}