131 lines
4.0 KiB
TypeScript
131 lines
4.0 KiB
TypeScript
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<string, ObjectInstance>
|
|
|
|
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];
|
|
}
|
|
}
|