import { Model } from '@hatiolab/things-scene' import type Carrier from './carrier' import type MCSCarrierHolder from './mcs-carrier-holder' const DYING_TIMEOUT = 1000 export default class CarrierManager { private carriers: Map = new Map() private dyingTimers: Map> = new Map() private root: any constructor(root: any) { this.root = root } get(carrierName: string): Carrier | undefined { return this.carriers.get(carrierName) } update(holder: MCSCarrierHolder, after: Record, before: Record): void { const afterName = after?.CARRIERNAME const beforeName = before?.CARRIERNAME // 이전에는 캐리어가 있었는데 새 데이터에는 없다 → dying 후보 if (beforeName && (beforeName !== afterName || !afterName)) { const carrier = this.carriers.get(beforeName) if (carrier && carrier.parent === holder) { this.scheduleDying(beforeName) } return } if (!afterName) { return } // dying 상태면 구출 const wasDying = this.dyingTimers.has(afterName) this.cancelDying(afterName) const { width, height } = holder.state let carrier = this.carriers.get(afterName) if (!carrier) { // 새로 생성 carrier = Model.compile( { id: afterName, type: 'Carrier', left: 0, top: 0, width, height, showText: holder.getState('showCarrierText') || false }, this.root.app ) as unknown as Carrier this.carriers.set(afterName, carrier) carrier.data = after holder.addComponent(carrier, { silent: true }) } else if (carrier.parent !== holder && (!beforeName && afterName)) { // CARRIERNAME이 새로 나타남 (이전엔 없었음) → 다른 holder로 이동 ;(holder as any).reparent(carrier, { animated: true, duration: 2000, ease: 'inout' }) } if (carrier.parent === holder) { carrier.data = after } } private scheduleDying(carrierName: string): void { this.cancelDying(carrierName) const timer = setTimeout(() => { this.dyingTimers.delete(carrierName) const carrier = this.carriers.get(carrierName) if (carrier) { this.carriers.delete(carrierName) if (!carrier.disposed) { carrier.removeSelf(true) } } }, DYING_TIMEOUT) this.dyingTimers.set(carrierName, timer) } private cancelDying(carrierName: string): void { const timer = this.dyingTimers.get(carrierName) if (timer) { clearTimeout(timer) this.dyingTimers.delete(carrierName) } } onCarrierDisposed(carrierName: string): void { this.cancelDying(carrierName) this.carriers.delete(carrierName) } dispose(): void { for (const timer of this.dyingTimers.values()) { clearTimeout(timer) } this.dyingTimers.clear() for (const carrier of this.carriers.values()) { if (!carrier.disposed) { carrier.removeSelf(true) } } this.carriers.clear() } }