import { CocosStorage } from '../modules/save/CocosStorage'; import { SaveManager } from '../modules/save/SaveManager'; import { StatsSection } from '../modules/save/StatsSection'; /** * The application's services, created once by the loader scene. * * Cocos components are built by the engine, so there is nowhere to inject * dependencies through a constructor; a small explicit locator is the honest * alternative to every component reaching for its own singleton. Everything it * holds is engine-independent apart from the storage adapter, so a test can * build one over `MemoryStorage` and drive the whole thing headlessly. */ export class App { private static _instance: App | null = null; readonly save: SaveManager; readonly stats: StatsSection; private constructor(save: SaveManager, stats: StatsSection) { this.save = save; this.stats = stats; } /** Builds the services and loads saved progress. Called once, from `Bootstrap`. */ static create(): App { if (App._instance) { return App._instance; } const stats = new StatsSection(); const save = new SaveManager(new CocosStorage()); save.register(stats); save.load(); App._instance = new App(save, stats); return App._instance; } static get instance(): App { if (!App._instance) { throw new Error('App.create() has not run — is the loader scene the start scene?'); } return App._instance; } static get exists(): boolean { return App._instance !== null; } /** Records the result of a match and writes it out immediately. */ recordMatch(outcome: 'win' | 'loss' | 'draw'): void { this.stats.recordResult(outcome); this.save.save(); } }