import { makeAutoObservable, reaction, 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"; import { DEFAULT_VOXEL_TYPES } from "../model/defaultVoxelTypes"; import { wolf } from "../model/objectPrefabs/wolf"; import { terrainXZ } from "../model/objectPrefabs/terrain"; import { populateRuntimeWorld } from "../utils/runtime"; export class WorldState { public data: RuntimeWorld = WorldFactory.create(); private startAutoSave() { return reaction(() => toJS(this.data), (data) => this.saveData(data), { delay: 500 }); } private withoutAutoSave(fn: () => void) { this._stopAutoSave(); fn(); this._stopAutoSave = this.startAutoSave(); } private _stopAutoSave: () => void = () => { }; constructor() { makeAutoObservable(this); this._stopAutoSave = this.startAutoSave(); } public reset() { console.log('Resetting world...'); this.withoutAutoSave(() => { this.data = WorldFactory.create(); }); state.worldEditor.resetSelectedObject(); } public loadMock() { console.log('Mocking world...'); const objects = Array(3).fill(0) .map((_, idx) => ({ id: `obj${idx}`, typeId: 'wolf', physics: true, gravityScale: 1, position: [idx * 10 - 10, 5, 0], rotation: [0, 0, 0], scale: [1, 1, 1], } as ObjectInstance)); const objectMap = Object.fromEntries( objects.map((obj) => [obj.id, obj]), ) as Record this.data = populateRuntimeWorld({ objectTypes: { wolf: { id: 'wolf', name: 'Wolf', voxels: wolf, }, terrain: { id: 'terrain', name: 'Terrain', voxels: terrainXZ(50, 50), } }, voxelTypes: DEFAULT_VOXEL_TYPES, editorCamera: { position: [-9, 11, 30], look: [-0.52, -0.35, -0.2], }, initialScene: { character: { transform: { position: [0, 5, 20], look: [0, 0, 0], }, }, objects: { terrain: { id: 'terrain', typeId: 'terrain', physics: false, // pinned gravityScale: 0, // pinned position: [0, -1, 0], rotation: [0, 0, 0], scale: [1, 1, 1], }, ...objectMap, }, }, gameRules: { gravity: true, }, }); console.log(objects); state.worldEditor.resetSelectedObject(); } public load() { console.log('Loading world...'); this.withoutAutoSave(() => { this.data = WorldFactory.load() ?? WorldFactory.create(); }); state.worldEditor.resetSelectedObject(); } private saveData(data: World): void { console.log('Saving world...'); const stack = new Error('Saving world...').stack!.split('\n').slice(1); const { objectTypes, voxelTypes, ...debug } = toJS(data); console.dir({ stack, debug }); WorldFactory.save(toJS(this.data)); } public save(): void { this.saveData(this.data); } public getObjectTypeById(id: string): ObjectType | undefined { return this.data.objectTypes[id]; } public getVoxelTypeById(id: string): VoxelType | undefined { return this.data.voxelTypes[id]; } }