Add continuous auto-save to IndexedDB for physics recordings
All checks were successful
Build / build (push) Successful in 1m26s
All checks were successful
Build / build (push) Successful in 1m26s
Modified physics recorder to automatically save all captured data to IndexedDB:
- Auto-saves every 10 seconds in batches (non-blocking)
- Creates unique session ID for each gameplay session
- Buffers snapshots between saves to minimize IndexedDB writes
- Saves any remaining buffered data on disposal
- All data preserved indefinitely in browser storage
Technical implementation:
- Auto-save buffer collects snapshots between 10-second intervals
- performAutoSave() copies buffer and clears immediately (non-blocking)
- Async save happens in background without impacting frame rate
- Session ID format: "session-{timestamp}" for easy identification
- Ring buffer (30s) still available for quick exports
Recording flow:
1. Recording starts when XR pose is set
2. Every frame adds snapshot to ring buffer AND auto-save buffer
3. Every 10 seconds, auto-save buffer is flushed to IndexedDB
4. On disposal, any remaining buffered frames are saved
5. All data accessible via existing storage APIs
Performance: Minimal impact - saves happen async every 10s, not per frame.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e473e3d03e
commit
88d380fa3f
BIN
public/assets/themes/default/audio/ammo.mp3
Normal file
BIN
public/assets/themes/default/audio/ammo.mp3
Normal file
Binary file not shown.
BIN
public/assets/themes/default/audio/danger.mp3
Normal file
BIN
public/assets/themes/default/audio/danger.mp3
Normal file
Binary file not shown.
BIN
public/assets/themes/default/audio/fuel.mp3
Normal file
BIN
public/assets/themes/default/audio/fuel.mp3
Normal file
Binary file not shown.
BIN
public/assets/themes/default/audio/hull.mp3
Normal file
BIN
public/assets/themes/default/audio/hull.mp3
Normal file
Binary file not shown.
BIN
public/assets/themes/default/audio/warning.mp3
Normal file
BIN
public/assets/themes/default/audio/warning.mp3
Normal file
Binary file not shown.
@ -74,6 +74,13 @@ export class PhysicsRecorder {
|
||||
// IndexedDB storage
|
||||
private _storage: PhysicsStorage | null = null;
|
||||
|
||||
// Auto-save to IndexedDB
|
||||
private _autoSaveEnabled: boolean = true;
|
||||
private _autoSaveBuffer: PhysicsSnapshot[] = [];
|
||||
private _autoSaveInterval: number = 10000; // Save every 10 seconds
|
||||
private _lastAutoSaveTime: number = 0;
|
||||
private _currentSessionId: string = "";
|
||||
|
||||
constructor(scene: Scene) {
|
||||
this._scene = scene;
|
||||
|
||||
@ -86,6 +93,7 @@ export class PhysicsRecorder {
|
||||
|
||||
/**
|
||||
* Start the ring buffer recorder (always capturing last 30 seconds)
|
||||
* Also starts auto-save to IndexedDB
|
||||
*/
|
||||
public startRingBuffer(): void {
|
||||
if (this._isEnabled) {
|
||||
@ -95,16 +103,22 @@ export class PhysicsRecorder {
|
||||
|
||||
this._isEnabled = true;
|
||||
this._startTime = performance.now();
|
||||
this._lastAutoSaveTime = performance.now();
|
||||
this._frameNumber = 0;
|
||||
|
||||
// Create unique session ID for this recording
|
||||
this._currentSessionId = `session-${Date.now()}`;
|
||||
|
||||
// Hook into physics update observable
|
||||
this._scene.onAfterPhysicsObservable.add(() => {
|
||||
if (this._isEnabled) {
|
||||
this.captureFrame();
|
||||
this.checkAutoSave();
|
||||
}
|
||||
});
|
||||
|
||||
debugLog("PhysicsRecorder: Ring buffer started (30 second capacity)");
|
||||
debugLog("PhysicsRecorder: Recording started (ring buffer + auto-save to IndexedDB)");
|
||||
debugLog(`PhysicsRecorder: Session ID: ${this._currentSessionId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,6 +251,11 @@ export class PhysicsRecorder {
|
||||
this._longRecording.push(snapshot);
|
||||
}
|
||||
|
||||
// Add to auto-save buffer if enabled
|
||||
if (this._autoSaveEnabled) {
|
||||
this._autoSaveBuffer.push(snapshot);
|
||||
}
|
||||
|
||||
this._frameNumber++;
|
||||
|
||||
// Track performance
|
||||
@ -251,6 +270,61 @@ export class PhysicsRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it's time to auto-save to IndexedDB
|
||||
*/
|
||||
private checkAutoSave(): void {
|
||||
if (!this._autoSaveEnabled || !this._storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = performance.now();
|
||||
const timeSinceLastSave = now - this._lastAutoSaveTime;
|
||||
|
||||
// Save every 10 seconds
|
||||
if (timeSinceLastSave >= this._autoSaveInterval && this._autoSaveBuffer.length > 0) {
|
||||
this.performAutoSave();
|
||||
this._lastAutoSaveTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save buffered snapshots to IndexedDB
|
||||
*/
|
||||
private async performAutoSave(): Promise<void> {
|
||||
if (!this._storage || this._autoSaveBuffer.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy buffer and clear it immediately to avoid blocking next frame
|
||||
const snapshotsToSave = [...this._autoSaveBuffer];
|
||||
this._autoSaveBuffer = [];
|
||||
|
||||
// Create a recording from the buffered snapshots
|
||||
const metadata: RecordingMetadata = {
|
||||
startTime: snapshotsToSave[0].timestamp,
|
||||
endTime: snapshotsToSave[snapshotsToSave.length - 1].timestamp,
|
||||
frameCount: snapshotsToSave.length,
|
||||
recordingDuration: snapshotsToSave[snapshotsToSave.length - 1].timestamp - snapshotsToSave[0].timestamp,
|
||||
physicsUpdateRate: this._physicsUpdateRate
|
||||
};
|
||||
|
||||
const recording: PhysicsRecording = {
|
||||
metadata,
|
||||
snapshots: snapshotsToSave
|
||||
};
|
||||
|
||||
try {
|
||||
// Save to IndexedDB with session ID as name
|
||||
await this._storage.saveRecording(this._currentSessionId, recording);
|
||||
|
||||
const duration = (metadata.recordingDuration / 1000).toFixed(1);
|
||||
debugLog(`PhysicsRecorder: Auto-saved ${snapshotsToSave.length} frames (${duration}s) to IndexedDB`);
|
||||
} catch (error) {
|
||||
debugLog("PhysicsRecorder: Error during auto-save", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export last N seconds from ring buffer
|
||||
*/
|
||||
@ -512,11 +586,18 @@ export class PhysicsRecorder {
|
||||
/**
|
||||
* Dispose of recorder resources
|
||||
*/
|
||||
public dispose(): void {
|
||||
public async dispose(): Promise<void> {
|
||||
// Save any remaining buffered data before disposing
|
||||
if (this._autoSaveBuffer.length > 0) {
|
||||
debugLog(`PhysicsRecorder: Saving ${this._autoSaveBuffer.length} remaining frames before disposal`);
|
||||
await this.performAutoSave();
|
||||
}
|
||||
|
||||
this.stopRingBuffer();
|
||||
this.stopLongRecording();
|
||||
this._ringBuffer = [];
|
||||
this._longRecording = [];
|
||||
this._autoSaveBuffer = [];
|
||||
|
||||
if (this._storage) {
|
||||
this._storage.close();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user