faster game state
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { makeAutoObservable, reaction, toJS } from "mobx";
|
||||
import { autorun, makeAutoObservable, toJS } from "mobx";
|
||||
import type { WorldState } from "./worldState";
|
||||
import type { Game, Pos3, RuntimeGameScene, ScriptContext, ScriptCoroutineContext } from "../types";
|
||||
import type { Game, GameObjectInstance, Pos3, RuntimeGameScene, ScriptContext, ScriptCoroutineContext } from "../types";
|
||||
import type { CameraProps } from "@react-three/fiber";
|
||||
import type { ScriptGameEventBus } from "../scripts/eventBus";
|
||||
import { GameFactory } from "../model/gameFactory";
|
||||
@@ -18,12 +18,31 @@ export class GameState {
|
||||
private coroutines = new ScriptCoroutines();
|
||||
private eventBus: ScriptGameEventBus;
|
||||
|
||||
private _buildGameObjects() {
|
||||
return Object.fromEntries(
|
||||
Object.entries(this.scene.objects).map(([id, obj]) => [id, {
|
||||
id: obj.id,
|
||||
typeId: obj.typeId,
|
||||
physics: obj.physics,
|
||||
gravityScale: obj.gravityScale,
|
||||
position: toJS(obj.position),
|
||||
rotation: toJS(obj.rotation),
|
||||
scale: toJS(obj.scale),
|
||||
version: obj.version,
|
||||
linearVelocity: toJS(obj.linearVelocity),
|
||||
angularVelocity: toJS(obj.angularVelocity),
|
||||
} satisfies GameObjectInstance])
|
||||
) as unknown as RuntimeGameScene['objects'];
|
||||
}
|
||||
|
||||
private startAutoSave() {
|
||||
return reaction(
|
||||
() => (this.asGame),
|
||||
(data) => this.saveData(data),
|
||||
{ delay: 5000 }
|
||||
);
|
||||
return autorun(() => {
|
||||
GameFactory.save({
|
||||
paused: this.isPaused,
|
||||
time: this.time,
|
||||
scene: { playerObjectId: this.scene.playerObjectId, objects: this._buildGameObjects() },
|
||||
});
|
||||
}, { delay: 5000 });
|
||||
}
|
||||
|
||||
// @ts-expect-error -- for future use
|
||||
@@ -46,12 +65,16 @@ export class GameState {
|
||||
this.isFirstTick = true;
|
||||
this.scene = game.scene;
|
||||
|
||||
this._stopAutoSave = this.startAutoSave();
|
||||
makeAutoObservable(this);
|
||||
this._stopAutoSave = this.startAutoSave();
|
||||
|
||||
this.eventBus = GameFactory.evalGameScripts(rawWorld, this.scene, this.coroutines);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._stopAutoSave();
|
||||
}
|
||||
|
||||
public emitEvent(event: string, context: Omit<ScriptContext, 'world' | 'scene' | keyof ScriptCoroutineContext> = {}) {
|
||||
this.eventBus.emit(
|
||||
event,
|
||||
@@ -63,14 +86,6 @@ export class GameState {
|
||||
);
|
||||
}
|
||||
|
||||
public get asGame(): Game {
|
||||
return {
|
||||
paused: toJS(this.isPaused),
|
||||
time: toJS(this.time),
|
||||
scene: toJS(this.scene),
|
||||
};
|
||||
}
|
||||
|
||||
public setGame(value: Game) {
|
||||
this.isPaused = value.paused;
|
||||
this.time = value.time;
|
||||
@@ -101,16 +116,13 @@ export class GameState {
|
||||
// });
|
||||
// }
|
||||
|
||||
private saveData(data: Game): void {
|
||||
console.log('Saving game...');
|
||||
const stack = new Error('Saving game...').stack!.split('\n').slice(1);
|
||||
const { ...debug } = toJS(data);
|
||||
console.dir({ stack, debug });
|
||||
GameFactory.save(data);
|
||||
}
|
||||
|
||||
public save(): void {
|
||||
this.saveData(this.asGame);
|
||||
console.log('Saving game...');
|
||||
GameFactory.save({
|
||||
paused: this.isPaused,
|
||||
time: this.time,
|
||||
scene: { playerObjectId: this.scene.playerObjectId, objects: this._buildGameObjects() },
|
||||
});
|
||||
}
|
||||
|
||||
public resume(): void {
|
||||
@@ -138,4 +150,4 @@ export class GameState {
|
||||
this.emitEvent('gameStart');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ export class RootState {
|
||||
return;
|
||||
|
||||
this.game.pause();
|
||||
this.game.dispose();
|
||||
this.game = undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { makeAutoObservable, reaction, toJS } from "mobx";
|
||||
import { autorun, makeAutoObservable, toJS } from "mobx";
|
||||
import { WorldFactory } from "../model/worldFactory";
|
||||
import { type ObjectInstance, type ObjectType, type World, type VoxelType, type RuntimeWorld } from "../types";
|
||||
import { state } from "./rootState";
|
||||
@@ -10,8 +10,32 @@ import { populateRuntimeWorld } from "../utils/runtime";
|
||||
export class WorldState {
|
||||
public data: RuntimeWorld = WorldFactory.create();
|
||||
|
||||
private _buildSave(): World {
|
||||
const d = this.data;
|
||||
return {
|
||||
objectTypes: toJS(d.objectTypes),
|
||||
voxelTypes: toJS(d.voxelTypes),
|
||||
editorCamera: toJS(d.editorCamera),
|
||||
gameRules: toJS(d.gameRules),
|
||||
initialScene: {
|
||||
playerObjectId: d.initialScene.playerObjectId,
|
||||
objects: Object.fromEntries(
|
||||
Object.entries(d.initialScene.objects).map(([id, obj]) => [id, {
|
||||
id: obj.id,
|
||||
typeId: obj.typeId,
|
||||
physics: obj.physics,
|
||||
gravityScale: obj.gravityScale,
|
||||
position: toJS(obj.position),
|
||||
rotation: toJS(obj.rotation),
|
||||
scale: toJS(obj.scale),
|
||||
} satisfies ObjectInstance])
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private startAutoSave() {
|
||||
return reaction(() => toJS(this.data), (data) => this.saveData(data), { delay: 500 });
|
||||
return autorun(() => WorldFactory.save(this._buildSave()), { delay: 500 });
|
||||
}
|
||||
|
||||
private withoutAutoSave(fn: () => void) {
|
||||
@@ -103,16 +127,8 @@ export class WorldState {
|
||||
state.worldEditor.resetSelection();
|
||||
}
|
||||
|
||||
private saveData(data: World): void {
|
||||
console.log('Saving world...');
|
||||
const stack = new Error('Saving world...').stack!.split('\n').slice(1);
|
||||
const { voxelTypes: _vts, initialScene: _is, ...debug } = toJS(data);
|
||||
console.dir({ stack, debug });
|
||||
WorldFactory.save(toJS(this.data));
|
||||
}
|
||||
|
||||
public save(): void {
|
||||
this.saveData(this.data);
|
||||
WorldFactory.save(this._buildSave());
|
||||
}
|
||||
|
||||
public getObjectTypeById(id: string): ObjectType | undefined {
|
||||
|
||||
Reference in New Issue
Block a user