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 { 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 { CameraProps } from "@react-three/fiber";
|
||||||
import type { ScriptGameEventBus } from "../scripts/eventBus";
|
import type { ScriptGameEventBus } from "../scripts/eventBus";
|
||||||
import { GameFactory } from "../model/gameFactory";
|
import { GameFactory } from "../model/gameFactory";
|
||||||
@@ -18,12 +18,31 @@ export class GameState {
|
|||||||
private coroutines = new ScriptCoroutines();
|
private coroutines = new ScriptCoroutines();
|
||||||
private eventBus: ScriptGameEventBus;
|
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() {
|
private startAutoSave() {
|
||||||
return reaction(
|
return autorun(() => {
|
||||||
() => (this.asGame),
|
GameFactory.save({
|
||||||
(data) => this.saveData(data),
|
paused: this.isPaused,
|
||||||
{ delay: 5000 }
|
time: this.time,
|
||||||
);
|
scene: { playerObjectId: this.scene.playerObjectId, objects: this._buildGameObjects() },
|
||||||
|
});
|
||||||
|
}, { delay: 5000 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error -- for future use
|
// @ts-expect-error -- for future use
|
||||||
@@ -46,12 +65,16 @@ export class GameState {
|
|||||||
this.isFirstTick = true;
|
this.isFirstTick = true;
|
||||||
this.scene = game.scene;
|
this.scene = game.scene;
|
||||||
|
|
||||||
this._stopAutoSave = this.startAutoSave();
|
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
|
this._stopAutoSave = this.startAutoSave();
|
||||||
|
|
||||||
this.eventBus = GameFactory.evalGameScripts(rawWorld, this.scene, this.coroutines);
|
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> = {}) {
|
public emitEvent(event: string, context: Omit<ScriptContext, 'world' | 'scene' | keyof ScriptCoroutineContext> = {}) {
|
||||||
this.eventBus.emit(
|
this.eventBus.emit(
|
||||||
event,
|
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) {
|
public setGame(value: Game) {
|
||||||
this.isPaused = value.paused;
|
this.isPaused = value.paused;
|
||||||
this.time = value.time;
|
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 {
|
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 {
|
public resume(): void {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export class RootState {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this.game.pause();
|
this.game.pause();
|
||||||
|
this.game.dispose();
|
||||||
this.game = undefined;
|
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 { WorldFactory } from "../model/worldFactory";
|
||||||
import { type ObjectInstance, type ObjectType, type World, type VoxelType, type RuntimeWorld } from "../types";
|
import { type ObjectInstance, type ObjectType, type World, type VoxelType, type RuntimeWorld } from "../types";
|
||||||
import { state } from "./rootState";
|
import { state } from "./rootState";
|
||||||
@@ -10,8 +10,32 @@ import { populateRuntimeWorld } from "../utils/runtime";
|
|||||||
export class WorldState {
|
export class WorldState {
|
||||||
public data: RuntimeWorld = WorldFactory.create();
|
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() {
|
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) {
|
private withoutAutoSave(fn: () => void) {
|
||||||
@@ -103,16 +127,8 @@ export class WorldState {
|
|||||||
state.worldEditor.resetSelection();
|
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 {
|
public save(): void {
|
||||||
this.saveData(this.data);
|
WorldFactory.save(this._buildSave());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getObjectTypeById(id: string): ObjectType | undefined {
|
public getObjectTypeById(id: string): ObjectType | undefined {
|
||||||
|
|||||||
Reference in New Issue
Block a user