import { makeAutoObservable, runInAction } from "mobx"; import type { WorldState } from "./worldState"; import { type ObjectInstance, type Pos3, type R3, type V3, type RuntimeScene } from "../types"; import { createObjectInstance } from "../utils/object"; import { randomId } from "../utils"; import { state } from "./rootState"; import { populateRuntimeObject } from "../utils/runtime"; export const SelectionEditModeEnum = [ 'translate', 'rotate', 'scale', ] as const; type SelectionEditModeTuple = typeof SelectionEditModeEnum; export type SelectionEditMode = SelectionEditModeTuple[number]; export function nextSelectionEditMode(mode: SelectionEditMode | undefined): SelectionEditMode { if (mode === undefined) return 'translate'; const idx = SelectionEditModeEnum.indexOf(mode); return SelectionEditModeEnum[(idx + 1) % SelectionEditModeEnum.length]; } export class WorldEditorState { private readonly world: WorldState; public selectedObjectId: string | undefined; public selectedObjectMode: SelectionEditMode | undefined; constructor(world: WorldState) { this.world = world; makeAutoObservable(this); } public get isEnabled(): boolean { return !state.isGamePlaying; } public setCamera(value: Pos3): void { this.world.data.editorCamera = value; } public setSelectedObject(id: string, mode: SelectionEditMode): void { this.selectedObjectId = id; this.selectedObjectMode = mode; } public resetSelectedObject(): void { this.selectedObjectId = undefined; this.selectedObjectMode = undefined; } public get scene(): RuntimeScene { return this.world.data.initialScene; } public get camera(): Pos3 { return this.world.data.editorCamera; } public setObjectTransform(id: string, position: V3, rotation: R3, scale: V3): void { const obj = this.scene.objects[id]; if (!obj) return; runInAction(() => { // all in one go obj.position = position; obj.rotation = rotation; obj.scale = scale; }); } public addObjectCloneAtRandomPosition(typeId: string): ObjectInstance { return this.addObjectClone( typeId, { x: Math.random() * 3, y: Math.random() * 3, z: Math.random() * 1 }, ); } public addObjectClone( typeId: string, pos: { x: number; y: number; z: number; }, ): ObjectInstance { const obj = populateRuntimeObject(createObjectInstance(randomId(), typeId), this.world.data); obj.position = [pos.x, pos.y, pos.z]; obj.rotation = [0, 0, 0]; this.scene.objects[obj.id] = obj; return obj; } }