import { Hook } from "/Scripts/types/hook" import { Scene } from "/Scripts/types/scene" /** * The scope that the hook is firing from */ export enum HookScope { CORE, SCRIPT, SCENE_CLIENT, SCENE_SERVER, } /** * A hook that is tracked by the manager */ interface TrackedHook extends Hook { /** * The scope that this hook was defined at */ scope: HookScope, /** * The scene that added the hook */ scene?: TrackedScene, } /** * A scene being tracked by the manager */ interface TrackedScene { /** * The id assigned to the scene */ sceneId: number, /** * The scene itself */ scene: Scene, } /** * Manages hooks for the engine */ export class HookManager { /** * The list of all hooks currently tracked by this manager */ hooks: Array = [] /** * A map of a scene to all hooks related to the scene */ sceneHookMap: Record> = { } /** * A map of engine signal to the list of hooks that should be called when that signal fires */ signalHookMap: Record> = { } /** * The list of all scenes tracked by the manager */ trackedScenes: Array<{ sceneId: number, scene: Scene }> = [] /** * A scene */ sceneIdIncrementer: number = 0 /** * Registers all hooks in a scene to the hook manager * @param scene The scene */ registerScene(scene: Scene, isServerScene: boolean){ const shouldRegister: boolean = !this.containsScene(scene) if(shouldRegister){ //add to the list of tracked scenes const trackedScene: TrackedScene = { sceneId: this.sceneIdIncrementer++, scene: scene, } this.trackedScenes.push(trackedScene) //load all hooks from the scene scene.hooks.forEach((hook: Hook) => { this.registerHook(trackedScene,hook,isServerScene) }) } } /** * Deregisters all hooks in a scene from the hook manager * @param scene The scene */ deregisterScene(scene: Scene){ throw new Error("Unsupported Operation!") } /** * Checks if the manager is tracking a given scene * @param scene The scene * @returns true if it is being tracked already, false otherwise */ containsScene(scene: Scene): boolean { this.trackedScenes.forEach(trackedScene => { if(trackedScene.scene === scene){ return true } }) return false } /** * Registers a hook * @param scene The scene introducing the hook * @param hook The hook */ registerHook(scene: TrackedScene, hook: Hook, isServerScene: boolean){ const trackedHook: TrackedHook = { ...hook, scope: isServerScene ? HookScope.SCENE_SERVER : HookScope.SCENE_CLIENT, scene: scene, } //add to flat array this.hooks.push(trackedHook) //add to signal array const hookSignal: string = hook.signal const signalArray: Array = this.signalHookMap?.[hookSignal] ? this.signalHookMap?.[hookSignal] : [] signalArray.push(trackedHook) this.signalHookMap[hookSignal] = signalArray //add to scene array const sceneArray: Array = this.sceneHookMap?.[scene.sceneId] ? this.sceneHookMap?.[scene.sceneId] : [] sceneArray.push(trackedHook) this.sceneHookMap[scene.sceneId] = sceneArray } /** * Deregisters a hook * @param scene The scene which introduced the hook * @param hook The hook */ deregisterHook(scene: Scene, hook: Hook){ throw new Error("Supported operation!") } /** * Fires a signal * @param signal The signal * @param value The value associated with the signal */ fireSignal(signal: string, value: any){ const hooks: Array = this.signalHookMap[signal] hooks.forEach(trackedHook => { trackedHook.callback(value) }) } }