import { autorun, makeAutoObservable, toJS } from "mobx"; import { WorldFactory } from "../model/worldFactory"; import { type ObjectInstance, type ObjectType, type World, type VoxelType } 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: World = WorldFactory.create(); private _buildSave(): World { const d = this.data; return toJS(d); } private startAutoSave() { return autorun(() => this.save(), { 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.resetSelection(); } 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: [14, 17, -25], look: [-2.5, 0.31, 3], }, initialScene: { objects: { terrain: { id: 'terrain', typeId: 'terrain', physics: false, // pinned gravityScale: 0, // pinned position: [0, -1, 0], rotation: [0, 0, 0], scale: [1, 1, 1], visible: true, linearVelocity: [0, 0, 0], angularVelocity: [0, 0, 0], }, ...objectMap, }, playerObjectId: 'obj1', }, gameRules: { gravity: true, }, }); console.log(objects); state.worldEditor.resetSelection(); } public load() { console.log('Loading world...'); this.withoutAutoSave(() => { this.data = WorldFactory.load() ?? WorldFactory.create(); }); state.worldEditor.resetSelection(); } public save(): void { console.log('Saving world...'); WorldFactory.save(this._buildSave()); } public getObjectTypeById(id: string): ObjectType | undefined { return this.data.objectTypes[id]; } public getVoxelTypeById(id: string): VoxelType | undefined { return this.data.voxelTypes[id]; } }