import { defaultTrapRuntime, type SceneTrapsEvent, type SceneTrapsState, type SceneTrapRuntime, } from '../../shared/types'; function emptyState(): SceneTrapsState { return { revision: 1, cacheKey: null, byId: {}, lastActivation: null, }; } function cloneById(byId: Record): Record { const out: Record = {}; for (const [k, v] of Object.entries(byId)) { out[k] = { ...v }; } return out; } export class SceneTrapsStore { private state: SceneTrapsState = emptyState(); /** Кэш runtime по ключу сцены/ноды на время сессии показа. */ private cache = new Map>(); private currentKey: string | null = null; private activationToken = 0; getState(): SceneTrapsState { return { ...this.state, byId: cloneById(this.state.byId), lastActivation: this.state.lastActivation ? { ...this.state.lastActivation } : null, }; } resetSession(): void { this.cache.clear(); this.currentKey = null; this.state = emptyState(); } /** * Переключение сцены: сохраняем runtime в кэш и подгружаем/инициализируем для новых trapIds. */ switchScene(cacheKey: string | null, trapIds: readonly string[]): SceneTrapsState { if (this.currentKey !== null) { this.cache.set(this.currentKey, cloneById(this.state.byId)); } this.currentKey = cacheKey; const cached = cacheKey ? this.cache.get(cacheKey) : undefined; const byId: Record = {}; for (const id of trapIds) { byId[id] = cached?.[id] ? { ...cached[id]! } : defaultTrapRuntime(); } if (cacheKey) { this.cache.set(cacheKey, cloneById(byId)); } this.state = { revision: this.state.revision + 1, cacheKey, byId, lastActivation: null, }; return this.getState(); } dispatch(event: SceneTrapsEvent): SceneTrapsState { switch (event.kind) { case 'syncTrapIds': { const byId: Record = {}; for (const id of event.trapIds) { byId[id] = this.state.byId[id] ? { ...this.state.byId[id]! } : defaultTrapRuntime(); } if (this.currentKey) this.cache.set(this.currentKey, cloneById(byId)); this.state = { ...this.state, revision: this.state.revision + 1, byId, }; return this.getState(); } case 'reveal': { const cur = this.state.byId[event.trapId]; if (!cur) return this.getState(); const byId = cloneById(this.state.byId); byId[event.trapId] = { ...cur, revealed: true }; if (this.currentKey) this.cache.set(this.currentKey, cloneById(byId)); this.state = { ...this.state, revision: this.state.revision + 1, byId, }; return this.getState(); } case 'activate': { const cur = this.state.byId[event.trapId]; if (!cur) return this.getState(); const byId = cloneById(this.state.byId); byId[event.trapId] = { status: 'active', revealed: true }; this.activationToken += 1; if (this.currentKey) this.cache.set(this.currentKey, cloneById(byId)); this.state = { ...this.state, revision: this.state.revision + 1, byId, lastActivation: { trapId: event.trapId, token: this.activationToken }, }; return this.getState(); } case 'disarm': { const cur = this.state.byId[event.trapId]; if (!cur) return this.getState(); const byId = cloneById(this.state.byId); byId[event.trapId] = { status: 'disarmed', revealed: true }; if (this.currentKey) this.cache.set(this.currentKey, cloneById(byId)); this.state = { ...this.state, revision: this.state.revision + 1, byId, }; return this.getState(); } default: { const _x: never = event; void _x; return this.getState(); } } } }