@rpgjs/client 5.0.0-alpha.23 → 5.0.0-alpha.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/RpgClientEngine.d.ts +35 -115
  2. package/dist/components/gui/mobile/index.d.ts +1 -1
  3. package/dist/index10.js +1 -1
  4. package/dist/index11.js +2 -2
  5. package/dist/index12.js +2 -2
  6. package/dist/index14.js +1 -2
  7. package/dist/index14.js.map +1 -1
  8. package/dist/index15.js +4 -4
  9. package/dist/index16.js.map +1 -1
  10. package/dist/index17.js.map +1 -1
  11. package/dist/index2.js +85 -159
  12. package/dist/index2.js.map +1 -1
  13. package/dist/index20.js.map +1 -1
  14. package/dist/index22.js +1 -1
  15. package/dist/index25.js +2 -2
  16. package/dist/index25.js.map +1 -1
  17. package/dist/index26.js +2 -3
  18. package/dist/index26.js.map +1 -1
  19. package/dist/index28.js +2 -2
  20. package/dist/index28.js.map +1 -1
  21. package/dist/index3.js +1 -1
  22. package/dist/index31.js +2622 -42
  23. package/dist/index31.js.map +1 -1
  24. package/dist/index32.js +88 -2607
  25. package/dist/index32.js.map +1 -1
  26. package/dist/index33.js +64 -107
  27. package/dist/index33.js.map +1 -1
  28. package/dist/index34.js +12 -62
  29. package/dist/index34.js.map +1 -1
  30. package/dist/index35.js +24 -18
  31. package/dist/index35.js.map +1 -1
  32. package/dist/index36.js +87 -19
  33. package/dist/index36.js.map +1 -1
  34. package/dist/index37.js +20 -74
  35. package/dist/index37.js.map +1 -1
  36. package/dist/index38.js +18 -35
  37. package/dist/index38.js.map +1 -1
  38. package/dist/index39.js +137 -20
  39. package/dist/index39.js.map +1 -1
  40. package/dist/index4.js +1 -1
  41. package/dist/index40.js +9 -133
  42. package/dist/index40.js.map +1 -1
  43. package/dist/index41.js +3 -41
  44. package/dist/index41.js.map +1 -1
  45. package/dist/index42.js +536 -1
  46. package/dist/index42.js.map +1 -1
  47. package/dist/index43.js +30 -183
  48. package/dist/index43.js.map +1 -1
  49. package/dist/index44.js +9 -501
  50. package/dist/index44.js.map +1 -1
  51. package/dist/index45.js +6 -334
  52. package/dist/index45.js.map +1 -1
  53. package/dist/index46.js +325 -30
  54. package/dist/index46.js.map +1 -1
  55. package/dist/index47.js +3680 -67
  56. package/dist/index47.js.map +1 -1
  57. package/dist/index48.js +75 -10
  58. package/dist/index48.js.map +1 -1
  59. package/dist/index49.js +186 -6
  60. package/dist/index49.js.map +1 -1
  61. package/dist/index50.js +499 -3685
  62. package/dist/index50.js.map +1 -1
  63. package/dist/index53.js +1 -1
  64. package/dist/index8.js +6 -1
  65. package/dist/index8.js.map +1 -1
  66. package/dist/index9.js +1 -2
  67. package/dist/index9.js.map +1 -1
  68. package/package.json +9 -9
  69. package/src/Gui/Gui.ts +0 -1
  70. package/src/RpgClientEngine.ts +106 -176
  71. package/src/components/character.ce +2 -3
  72. package/src/components/gui/mobile/index.ts +1 -1
  73. package/src/components/gui/mobile/mobile.ce +73 -88
  74. package/src/components/prebuilt/light-halo.ce +2 -71
  75. package/src/components/scenes/canvas.ce +0 -10
  76. package/src/components/scenes/event-layer.ce +1 -0
  77. package/src/module.ts +6 -1
  78. package/dist/Game/TransitionManager.d.ts +0 -56
  79. package/src/Game/TransitionManager.ts +0 -75
package/dist/index53.js CHANGED
@@ -1,4 +1,4 @@
1
- import * as external from './index49.js';
1
+ import * as external from './index45.js';
2
2
 
3
3
 
4
4
 
package/dist/index8.js CHANGED
@@ -106,8 +106,13 @@ function provideClientModules(modules) {
106
106
  const transitions = [...module.transitions];
107
107
  module.transitions = {
108
108
  load: (engine) => {
109
+ const guiService = inject(engine.context, RpgGui);
109
110
  transitions.forEach((transition) => {
110
- engine.addTransition(transition);
111
+ guiService.add({
112
+ name: transition.id,
113
+ component: transition.component,
114
+ data: transition.props || {}
115
+ });
111
116
  });
112
117
  }
113
118
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index8.js","sources":["../src/module.ts"],"sourcesContent":["import { findModules, provideModules } from \"@rpgjs/common\";\nimport { FactoryProvider } from \"@signe/di\";\nimport { RpgClientEngine } from \"./RpgClientEngine\";\nimport { RpgClient } from \"./RpgClient\";\nimport { inject } from \"@signe/di\";\nimport { RpgGui } from \"./Gui/Gui\";\nimport { getSoundMetadata } from \"./Sound\";\n\n/**\n * Type for client modules that can be either:\n * - An object implementing RpgClient interface\n * - A class decorated with @RpgModule decorator\n */\nexport type RpgClientModule = RpgClient | (new () => any);\n\n/**\n * Provides client modules configuration to Dependency Injection\n * \n * This function accepts an array of client modules that can be either:\n * - Objects implementing the RpgClient interface\n * - Classes decorated with the @RpgModule decorator (which will be instantiated)\n * \n * @param modules - Array of client modules (objects or classes)\n * @returns FactoryProvider configuration for DI\n * @example\n * ```ts\n * // Using an object\n * provideClientModules([\n * {\n * engine: {\n * onConnected(engine) {\n * console.log('Client connected')\n * }\n * }\n * }\n * ])\n * \n * // Using a decorated class\n * @RpgModule<RpgClient>({\n * engine: {\n * onStart(engine) {\n * console.log('Client started')\n * }\n * }\n * })\n * class MyClientModule {}\n * \n * provideClientModules([MyClientModule])\n * ```\n */\nexport function provideClientModules(modules: RpgClientModule[]): FactoryProvider {\n return provideModules(modules, \"client\", (modules, context) => {\n const mainModuleClient = findModules(context, 'Client')\n modules = [...mainModuleClient, ...modules]\n modules = modules.map((module) => {\n // If module is a class (constructor function), instantiate it\n // The RpgModule decorator adds properties to the prototype, which will be accessible via the instance\n if (typeof module === 'function') {\n const instance = new module() as any;\n // Copy all enumerable properties (including from prototype) to a plain object\n const moduleObj: any = {};\n for (const key in instance) {\n moduleObj[key] = instance[key];\n }\n module = moduleObj;\n }\n if ('client' in module) {\n module = module.client as any;\n }\n if (module.spritesheets) {\n const spritesheets = [...module.spritesheets];\n module.spritesheets = {\n load: (engine: RpgClientEngine) => {\n spritesheets.forEach((spritesheet) => {\n engine.addSpriteSheet(spritesheet);\n });\n },\n };\n }\n if (module.spritesheetResolver) {\n const resolver = module.spritesheetResolver;\n module.spritesheetResolver = {\n load: (engine: RpgClientEngine) => {\n engine.setSpritesheetResolver(resolver);\n },\n };\n }\n if (module.sounds) {\n const sounds = [...module.sounds];\n module.sounds = {\n load: (engine: RpgClientEngine) => {\n sounds.forEach((sound) => {\n // Check if it's a class decorated with @Sound\n if (typeof sound === 'function' || (sound && sound.constructor && sound.constructor !== Object)) {\n const metadata = getSoundMetadata(sound);\n if (metadata) {\n // Handle single sound\n if (metadata.id && metadata.sound) {\n engine.addSound({\n id: metadata.id,\n src: metadata.sound,\n loop: metadata.loop,\n volume: metadata.volume,\n });\n }\n // Handle multiple sounds\n if (metadata.sounds) {\n Object.entries(metadata.sounds).forEach(([soundId, soundSrc]) => {\n engine.addSound({\n id: soundId,\n src: soundSrc,\n loop: metadata.loop,\n volume: metadata.volume,\n });\n });\n }\n } else {\n // Not a decorated class, treat as regular sound object\n engine.addSound(sound);\n }\n } else {\n // Regular sound object\n engine.addSound(sound);\n }\n });\n },\n };\n }\n if (module.soundResolver) {\n const resolver = module.soundResolver;\n module.soundResolver = {\n load: (engine: RpgClientEngine) => {\n engine.setSoundResolver(resolver);\n },\n };\n }\n if (module.gui) {\n const gui = [...module.gui];\n module.gui = {\n load: (engine: RpgClientEngine) => {\n const guiService = inject(engine.context, RpgGui) as RpgGui;\n gui.forEach((gui) => {\n guiService.add(gui);\n });\n },\n };\n }\n if (module.componentAnimations) {\n const componentAnimations = [...module.componentAnimations];\n module.componentAnimations = {\n load: (engine: RpgClientEngine) => {\n componentAnimations.forEach((componentAnimation) => {\n engine.addComponentAnimation(componentAnimation);\n });\n },\n };\n }\n if (module.transitions) {\n const transitions = [...module.transitions];\n module.transitions = {\n load: (engine: RpgClientEngine) => {\n transitions.forEach((transition) => {\n engine.addTransition(transition);\n });\n },\n };\n }\n if (module.particles) {\n const particles = [...module.particles];\n module.particles = {\n load: (engine: RpgClientEngine) => {\n particles.forEach((particle) => {\n engine.addParticle(particle);\n });\n },\n };\n }\n if (module.sprite) {\n const sprite = {...module.sprite};\n module.sprite = {\n ...sprite,\n load: (engine: RpgClientEngine) => {\n if (sprite.componentsBehind) {\n sprite.componentsBehind.forEach((component) => {\n engine.addSpriteComponentBehind(component);\n });\n }\n if (sprite.componentsInFront) {\n sprite.componentsInFront.forEach((component) => {\n engine.addSpriteComponentInFront(component);\n });\n }\n },\n };\n }\n return module;\n });\n return modules\n });\n}\n\nexport const GlobalConfigToken = \"GlobalConfigToken\";\n\nexport function provideGlobalConfig(config: any) {\n return {\n provide: GlobalConfigToken,\n useValue: config ?? {},\n };\n}\n\nexport function provideClientGlobalConfig(config: any = {}) {\n if (!config.keyboardControls) {\n config.keyboardControls = {\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n action: 'space'\n }\n }\n return provideGlobalConfig(config)\n}\n\n"],"names":["modules","gui"],"mappings":"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"}
1
+ {"version":3,"file":"index8.js","sources":["../src/module.ts"],"sourcesContent":["import { findModules, provideModules } from \"@rpgjs/common\";\nimport { FactoryProvider } from \"@signe/di\";\nimport { RpgClientEngine } from \"./RpgClientEngine\";\nimport { RpgClient } from \"./RpgClient\";\nimport { inject } from \"@signe/di\";\nimport { RpgGui } from \"./Gui/Gui\";\nimport { getSoundMetadata } from \"./Sound\";\n\n/**\n * Type for client modules that can be either:\n * - An object implementing RpgClient interface\n * - A class decorated with @RpgModule decorator\n */\nexport type RpgClientModule = RpgClient | (new () => any);\n\n/**\n * Provides client modules configuration to Dependency Injection\n * \n * This function accepts an array of client modules that can be either:\n * - Objects implementing the RpgClient interface\n * - Classes decorated with the @RpgModule decorator (which will be instantiated)\n * \n * @param modules - Array of client modules (objects or classes)\n * @returns FactoryProvider configuration for DI\n * @example\n * ```ts\n * // Using an object\n * provideClientModules([\n * {\n * engine: {\n * onConnected(engine) {\n * console.log('Client connected')\n * }\n * }\n * }\n * ])\n * \n * // Using a decorated class\n * @RpgModule<RpgClient>({\n * engine: {\n * onStart(engine) {\n * console.log('Client started')\n * }\n * }\n * })\n * class MyClientModule {}\n * \n * provideClientModules([MyClientModule])\n * ```\n */\nexport function provideClientModules(modules: RpgClientModule[]): FactoryProvider {\n return provideModules(modules, \"client\", (modules, context) => {\n const mainModuleClient = findModules(context, 'Client')\n modules = [...mainModuleClient, ...modules]\n modules = modules.map((module) => {\n // If module is a class (constructor function), instantiate it\n // The RpgModule decorator adds properties to the prototype, which will be accessible via the instance\n if (typeof module === 'function') {\n const instance = new module() as any;\n // Copy all enumerable properties (including from prototype) to a plain object\n const moduleObj: any = {};\n for (const key in instance) {\n moduleObj[key] = instance[key];\n }\n module = moduleObj;\n }\n if ('client' in module) {\n module = module.client as any;\n }\n if (module.spritesheets) {\n const spritesheets = [...module.spritesheets];\n module.spritesheets = {\n load: (engine: RpgClientEngine) => {\n spritesheets.forEach((spritesheet) => {\n engine.addSpriteSheet(spritesheet);\n });\n },\n };\n }\n if (module.spritesheetResolver) {\n const resolver = module.spritesheetResolver;\n module.spritesheetResolver = {\n load: (engine: RpgClientEngine) => {\n engine.setSpritesheetResolver(resolver);\n },\n };\n }\n if (module.sounds) {\n const sounds = [...module.sounds];\n module.sounds = {\n load: (engine: RpgClientEngine) => {\n sounds.forEach((sound) => {\n // Check if it's a class decorated with @Sound\n if (typeof sound === 'function' || (sound && sound.constructor && sound.constructor !== Object)) {\n const metadata = getSoundMetadata(sound);\n if (metadata) {\n // Handle single sound\n if (metadata.id && metadata.sound) {\n engine.addSound({\n id: metadata.id,\n src: metadata.sound,\n loop: metadata.loop,\n volume: metadata.volume,\n });\n }\n // Handle multiple sounds\n if (metadata.sounds) {\n Object.entries(metadata.sounds).forEach(([soundId, soundSrc]) => {\n engine.addSound({\n id: soundId,\n src: soundSrc,\n loop: metadata.loop,\n volume: metadata.volume,\n });\n });\n }\n } else {\n // Not a decorated class, treat as regular sound object\n engine.addSound(sound);\n }\n } else {\n // Regular sound object\n engine.addSound(sound);\n }\n });\n },\n };\n }\n if (module.soundResolver) {\n const resolver = module.soundResolver;\n module.soundResolver = {\n load: (engine: RpgClientEngine) => {\n engine.setSoundResolver(resolver);\n },\n };\n }\n if (module.gui) {\n const gui = [...module.gui];\n module.gui = {\n load: (engine: RpgClientEngine) => {\n const guiService = inject(engine.context, RpgGui) as RpgGui;\n gui.forEach((gui) => {\n guiService.add(gui);\n });\n },\n };\n }\n if (module.componentAnimations) {\n const componentAnimations = [...module.componentAnimations];\n module.componentAnimations = {\n load: (engine: RpgClientEngine) => {\n componentAnimations.forEach((componentAnimation) => {\n engine.addComponentAnimation(componentAnimation);\n });\n },\n };\n }\n if (module.transitions) {\n const transitions = [...module.transitions];\n module.transitions = {\n load: (engine: RpgClientEngine) => {\n const guiService = inject(engine.context, RpgGui) as RpgGui;\n transitions.forEach((transition) => {\n guiService.add({\n name: transition.id,\n component: transition.component,\n data: transition.props || {}\n });\n });\n },\n };\n }\n if (module.particles) {\n const particles = [...module.particles];\n module.particles = {\n load: (engine: RpgClientEngine) => {\n particles.forEach((particle) => {\n engine.addParticle(particle);\n });\n },\n };\n }\n if (module.sprite) {\n const sprite = {...module.sprite};\n module.sprite = {\n ...sprite,\n load: (engine: RpgClientEngine) => {\n if (sprite.componentsBehind) {\n sprite.componentsBehind.forEach((component) => {\n engine.addSpriteComponentBehind(component);\n });\n }\n if (sprite.componentsInFront) {\n sprite.componentsInFront.forEach((component) => {\n engine.addSpriteComponentInFront(component);\n });\n }\n },\n };\n }\n return module;\n });\n return modules\n });\n}\n\nexport const GlobalConfigToken = \"GlobalConfigToken\";\n\nexport function provideGlobalConfig(config: any) {\n return {\n provide: GlobalConfigToken,\n useValue: config ?? {},\n };\n}\n\nexport function provideClientGlobalConfig(config: any = {}) {\n if (!config.keyboardControls) {\n config.keyboardControls = {\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n action: 'space'\n }\n }\n return provideGlobalConfig(config)\n}\n\n"],"names":["modules","gui"],"mappings":"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"}
package/dist/index9.js CHANGED
@@ -9,8 +9,8 @@ import './index19.js';
9
9
  import './index28.js';
10
10
  import './index29.js';
11
11
  import 'pixi.js';
12
+ import './index31.js';
12
13
  import './index32.js';
13
- import './index33.js';
14
14
  import '@canvasengine/presets';
15
15
 
16
16
  const throwError = (id) => {
@@ -246,7 +246,6 @@ class RpgGui {
246
246
  } else {
247
247
  guiInstance.data.set(data);
248
248
  guiInstance.display.set(true);
249
- console.log(guiInstance.dependencies);
250
249
  }
251
250
  }
252
251
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index9.js","sources":["../src/Gui/Gui.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { signal, Signal, WritableSignal } from \"canvasengine\";\nimport { AbstractWebsocket, WebSocketToken } from \"../services/AbstractSocket\";\nimport { DialogboxComponent } from \"../components/gui\";\nimport { combineLatest, Subscription } from \"rxjs\";\n\ninterface GuiOptions {\n name?: string;\n id?: string;\n component: any;\n display?: boolean;\n data?: any;\n /**\n * Auto display the GUI when added to the system\n * @default false\n */\n autoDisplay?: boolean;\n /**\n * Function that returns an array of Signal dependencies\n * The GUI will only display when all dependencies are resolved (!= undefined)\n * @returns Array of Signal dependencies\n */\n dependencies?: () => Signal[];\n /**\n * Attach the GUI to sprites instead of displaying globally\n * When true, the GUI will be rendered in character.ce for each sprite\n * @default false\n */\n attachToSprite?: boolean;\n}\n\ninterface GuiInstance {\n name: string;\n component: any;\n display: WritableSignal<boolean>;\n data: WritableSignal<any>;\n autoDisplay: boolean;\n dependencies?: () => Signal[];\n subscription?: Subscription;\n attachToSprite?: boolean;\n}\n\nconst throwError = (id: string) => {\n throw `The GUI named ${id} is non-existent. Please add the component in the gui property of the decorator @RpgClient`;\n};\n\nexport class RpgGui {\n private webSocket: AbstractWebsocket;\n gui = signal<Record<string, GuiInstance>>({});\n extraGuis: GuiInstance[] = [];\n private vueGuiInstance: any = null; // Reference to VueGui instance\n /**\n * Signal tracking which player IDs should display attached GUIs\n * Key: player ID, Value: boolean (true = show, false = hide)\n */\n attachedGuiDisplayState = signal<Record<string, boolean>>({});\n\n constructor(private context: Context) {\n this.webSocket = inject(context, WebSocketToken);\n this.add({\n name: \"rpg-dialog\",\n component: DialogboxComponent,\n });\n }\n\n async _initialize() {\n this.webSocket.on(\"gui.open\", (data: { guiId: string; data: any }) => {\n this.display(data.guiId, data.data);\n });\n\n this.webSocket.on(\"gui.exit\", (guiId: string) => {\n this.hide(guiId);\n });\n\n /**\n * Listen for tooltip display state changes from server\n * This is triggered by showAttachedGui/hideAttachedGui on the server\n */\n this.webSocket.on(\"gui.tooltip\", (data: { players: string[]; display: boolean }) => {\n const currentState = { ...this.attachedGuiDisplayState() };\n data.players.forEach((playerId) => {\n currentState[playerId] = data.display;\n });\n this.attachedGuiDisplayState.set(currentState);\n });\n }\n\n /**\n * Set the VueGui instance reference for Vue component management\n * This is called by VueGui when it's initialized\n * \n * @param vueGuiInstance - The VueGui instance\n */\n _setVueGuiInstance(vueGuiInstance: any) {\n this.vueGuiInstance = vueGuiInstance;\n }\n\n /**\n * Notify VueGui about GUI state changes\n * This synchronizes the Vue component display state\n * \n * @param guiId - The GUI component ID\n * @param display - Display state\n * @param data - Component data\n */\n private _notifyVueGui(guiId: string, display: boolean, data: any = {}) {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Find the GUI in extraGuis\n const extraGui = this.extraGuis.find(gui => gui.name === guiId);\n if (extraGui) {\n // Update the Vue component's display state and data\n this.vueGuiInstance.vm.gui[guiId] = {\n name: guiId,\n display,\n data,\n attachToSprite: extraGui.attachToSprite || false\n };\n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n }\n\n /**\n * Initialize Vue components in the VueGui instance\n * This should be called after VueGui is mounted\n */\n _initializeVueComponents() {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Initialize all extraGuis in the Vue instance\n this.extraGuis.forEach(gui => {\n this.vueGuiInstance.vm.gui[gui.name] = {\n name: gui.name,\n display: gui.display(),\n data: gui.data(),\n attachToSprite: gui.attachToSprite || false\n };\n });\n \n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n\n guiInteraction(guiId: string, name: string, data: any) {\n this.webSocket.emit(\"gui.interaction\", {\n guiId,\n name,\n data,\n });\n }\n\n guiClose(guiId: string, data?: any) {\n this.webSocket.emit(\"gui.exit\", {\n guiId,\n data,\n });\n }\n\n /**\n * Add a GUI component to the system\n * \n * By default, only CanvasEngine components (.ce files) are accepted.\n * Vue components should be handled by the @rpgjs/vue package.\n * \n * @param gui - GUI configuration options\n * @param gui.name - Name or ID of the GUI component\n * @param gui.id - Alternative ID if name is not provided\n * @param gui.component - The component to render (must be a CanvasEngine component)\n * @param gui.display - Initial display state (default: false)\n * @param gui.data - Initial data for the component\n * @param gui.autoDisplay - Auto display when added (default: false)\n * @param gui.dependencies - Function returning Signal dependencies\n * @param gui.attachToSprite - Attach GUI to sprites instead of global display (default: false)\n * \n * @example\n * ```ts\n * gui.add({\n * name: 'inventory',\n * component: InventoryComponent, // Must be a .ce component\n * autoDisplay: true,\n * dependencies: () => [playerSignal, inventorySignal]\n * });\n * \n * // Attach to sprites\n * gui.add({\n * name: 'tooltip',\n * component: TooltipComponent,\n * attachToSprite: true\n * });\n * ```\n */\n add(gui: GuiOptions) {\n const guiId = gui.name || gui.id;\n if (!guiId) {\n throw new Error(\"GUI must have a name or id\");\n }\n const guiInstance: GuiInstance = {\n name: guiId,\n component: gui.component,\n display: signal(gui.display || false),\n data: signal(gui.data || {}),\n autoDisplay: gui.autoDisplay || false,\n dependencies: gui.dependencies ? gui.dependencies() : [],\n attachToSprite: gui.attachToSprite || false,\n };\n\n // Accept both CanvasEngine components (.ce) and Vue components\n // Vue components will be handled by VueGui if available\n if (typeof gui.component !== 'function') {\n guiInstance.component = gui;\n this.extraGuis.push(guiInstance);\n \n // Auto display Vue components if enabled\n if (guiInstance.autoDisplay) {\n this._notifyVueGui(guiId, true, gui.data || {});\n }\n return;\n }\n\n this.gui()[guiId] = guiInstance;\n\n // Auto display if enabled and it's a CanvasEngine component\n if (guiInstance.autoDisplay && typeof gui.component === 'function') {\n this.display(guiId);\n }\n }\n\n /**\n * Get all attached GUI components (attachToSprite: true)\n * \n * Returns all GUI instances that are configured to be attached to sprites.\n * These GUIs should be rendered in character.ce instead of canvas.ce.\n * \n * @returns Array of GUI instances with attachToSprite: true\n * \n * @example\n * ```ts\n * const attachedGuis = gui.getAttachedGuis();\n * // Use in character.ce to render tooltips\n * ```\n */\n getAttachedGuis(): GuiInstance[] {\n const allGuis = this.getAll();\n return Object.values(allGuis).filter(gui => gui.attachToSprite === true);\n }\n\n /**\n * Check if a player should display attached GUIs\n * \n * @param playerId - The player ID to check\n * @returns true if attached GUIs should be displayed for this player\n */\n shouldDisplayAttachedGui(playerId: string): boolean {\n return this.attachedGuiDisplayState()[playerId] === true;\n }\n\n get(id: string): GuiInstance | undefined {\n // Check CanvasEngine GUIs first\n const canvasGui = this.gui()[id];\n if (canvasGui) {\n return canvasGui;\n }\n \n // Check Vue GUIs in extraGuis\n return this.extraGuis.find(gui => gui.name === id);\n }\n\n exists(id: string): boolean {\n return !!this.get(id);\n }\n\n getAll(): Record<string, GuiInstance> {\n const allGuis = { ...this.gui() };\n \n // Add extraGuis to the result\n this.extraGuis.forEach(gui => {\n allGuis[gui.name] = gui;\n });\n \n return allGuis;\n }\n\n /**\n * Display a GUI component\n * \n * Displays the GUI immediately if no dependencies are configured,\n * or waits for all dependencies to be resolved if dependencies are present.\n * Automatically manages subscriptions to prevent memory leaks.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * @param data - Data to pass to the component\n * @param dependencies - Optional runtime dependencies (overrides config dependencies)\n * \n * @example\n * ```ts\n * // Display immediately\n * gui.display('inventory', { items: [] });\n * \n * // Display with runtime dependencies\n * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);\n * ```\n */\n display(id: string, data = {}, dependencies: Signal[] = []) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Check if it's a Vue component (in extraGuis)\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n \n if (isVueComponent) {\n // Handle Vue component display\n this._handleVueComponentDisplay(id, data, dependencies, guiInstance);\n } else {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n console.log(guiInstance.dependencies)\n }\n }\n\n /**\n * Handle Vue component display logic\n * \n * @param id - GUI component ID\n * @param data - Component data\n * @param dependencies - Runtime dependencies\n * @param guiInstance - GUI instance\n */\n private _handleVueComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {\n // Unsubscribe from previous subscription if exists\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n // Use runtime dependencies or config dependencies\n const deps = dependencies.length > 0 \n ? dependencies \n : (guiInstance.dependencies ? guiInstance.dependencies() : []);\n\n if (deps.length > 0) {\n // Subscribe to dependencies\n guiInstance.subscription = combineLatest(\n deps.map(dependency => dependency.observable)\n ).subscribe((values) => {\n if (values.every(value => value !== undefined)) {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n });\n return;\n }\n\n // No dependencies, display immediately\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n\n /**\n * Handle CanvasEngine component display logic\n * \n * @param id - GUI component ID\n * @param data - Component data\n * @param dependencies - Runtime dependencies\n * @param guiInstance - GUI instance\n */\n private _handleCanvasComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {\n \n }\n\n /**\n * Hide a GUI component\n * \n * Hides the GUI and cleans up any active subscriptions.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * \n * @example\n * ```ts\n * gui.hide('inventory');\n * ```\n */\n hide(id: string) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Unsubscribe if there's an active subscription\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n guiInstance.display.set(false);\n \n // Check if it's a Vue component and notify VueGui\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n if (isVueComponent) {\n this._notifyVueGui(id, false);\n }\n }\n}\n"],"names":["DialogboxComponent"],"mappings":"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"}
1
+ {"version":3,"file":"index9.js","sources":["../src/Gui/Gui.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { signal, Signal, WritableSignal } from \"canvasengine\";\nimport { AbstractWebsocket, WebSocketToken } from \"../services/AbstractSocket\";\nimport { DialogboxComponent } from \"../components/gui\";\nimport { combineLatest, Subscription } from \"rxjs\";\n\ninterface GuiOptions {\n name?: string;\n id?: string;\n component: any;\n display?: boolean;\n data?: any;\n /**\n * Auto display the GUI when added to the system\n * @default false\n */\n autoDisplay?: boolean;\n /**\n * Function that returns an array of Signal dependencies\n * The GUI will only display when all dependencies are resolved (!= undefined)\n * @returns Array of Signal dependencies\n */\n dependencies?: () => Signal[];\n /**\n * Attach the GUI to sprites instead of displaying globally\n * When true, the GUI will be rendered in character.ce for each sprite\n * @default false\n */\n attachToSprite?: boolean;\n}\n\ninterface GuiInstance {\n name: string;\n component: any;\n display: WritableSignal<boolean>;\n data: WritableSignal<any>;\n autoDisplay: boolean;\n dependencies?: () => Signal[];\n subscription?: Subscription;\n attachToSprite?: boolean;\n}\n\nconst throwError = (id: string) => {\n throw `The GUI named ${id} is non-existent. Please add the component in the gui property of the decorator @RpgClient`;\n};\n\nexport class RpgGui {\n private webSocket: AbstractWebsocket;\n gui = signal<Record<string, GuiInstance>>({});\n extraGuis: GuiInstance[] = [];\n private vueGuiInstance: any = null; // Reference to VueGui instance\n /**\n * Signal tracking which player IDs should display attached GUIs\n * Key: player ID, Value: boolean (true = show, false = hide)\n */\n attachedGuiDisplayState = signal<Record<string, boolean>>({});\n\n constructor(private context: Context) {\n this.webSocket = inject(context, WebSocketToken);\n this.add({\n name: \"rpg-dialog\",\n component: DialogboxComponent,\n });\n }\n\n async _initialize() {\n this.webSocket.on(\"gui.open\", (data: { guiId: string; data: any }) => {\n this.display(data.guiId, data.data);\n });\n\n this.webSocket.on(\"gui.exit\", (guiId: string) => {\n this.hide(guiId);\n });\n\n /**\n * Listen for tooltip display state changes from server\n * This is triggered by showAttachedGui/hideAttachedGui on the server\n */\n this.webSocket.on(\"gui.tooltip\", (data: { players: string[]; display: boolean }) => {\n const currentState = { ...this.attachedGuiDisplayState() };\n data.players.forEach((playerId) => {\n currentState[playerId] = data.display;\n });\n this.attachedGuiDisplayState.set(currentState);\n });\n }\n\n /**\n * Set the VueGui instance reference for Vue component management\n * This is called by VueGui when it's initialized\n * \n * @param vueGuiInstance - The VueGui instance\n */\n _setVueGuiInstance(vueGuiInstance: any) {\n this.vueGuiInstance = vueGuiInstance;\n }\n\n /**\n * Notify VueGui about GUI state changes\n * This synchronizes the Vue component display state\n * \n * @param guiId - The GUI component ID\n * @param display - Display state\n * @param data - Component data\n */\n private _notifyVueGui(guiId: string, display: boolean, data: any = {}) {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Find the GUI in extraGuis\n const extraGui = this.extraGuis.find(gui => gui.name === guiId);\n if (extraGui) {\n // Update the Vue component's display state and data\n this.vueGuiInstance.vm.gui[guiId] = {\n name: guiId,\n display,\n data,\n attachToSprite: extraGui.attachToSprite || false\n };\n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n }\n\n /**\n * Initialize Vue components in the VueGui instance\n * This should be called after VueGui is mounted\n */\n _initializeVueComponents() {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Initialize all extraGuis in the Vue instance\n this.extraGuis.forEach(gui => {\n this.vueGuiInstance.vm.gui[gui.name] = {\n name: gui.name,\n display: gui.display(),\n data: gui.data(),\n attachToSprite: gui.attachToSprite || false\n };\n });\n \n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n\n guiInteraction(guiId: string, name: string, data: any) {\n this.webSocket.emit(\"gui.interaction\", {\n guiId,\n name,\n data,\n });\n }\n\n guiClose(guiId: string, data?: any) {\n this.webSocket.emit(\"gui.exit\", {\n guiId,\n data,\n });\n }\n\n /**\n * Add a GUI component to the system\n * \n * By default, only CanvasEngine components (.ce files) are accepted.\n * Vue components should be handled by the @rpgjs/vue package.\n * \n * @param gui - GUI configuration options\n * @param gui.name - Name or ID of the GUI component\n * @param gui.id - Alternative ID if name is not provided\n * @param gui.component - The component to render (must be a CanvasEngine component)\n * @param gui.display - Initial display state (default: false)\n * @param gui.data - Initial data for the component\n * @param gui.autoDisplay - Auto display when added (default: false)\n * @param gui.dependencies - Function returning Signal dependencies\n * @param gui.attachToSprite - Attach GUI to sprites instead of global display (default: false)\n * \n * @example\n * ```ts\n * gui.add({\n * name: 'inventory',\n * component: InventoryComponent, // Must be a .ce component\n * autoDisplay: true,\n * dependencies: () => [playerSignal, inventorySignal]\n * });\n * \n * // Attach to sprites\n * gui.add({\n * name: 'tooltip',\n * component: TooltipComponent,\n * attachToSprite: true\n * });\n * ```\n */\n add(gui: GuiOptions) {\n const guiId = gui.name || gui.id;\n if (!guiId) {\n throw new Error(\"GUI must have a name or id\");\n }\n const guiInstance: GuiInstance = {\n name: guiId,\n component: gui.component,\n display: signal(gui.display || false),\n data: signal(gui.data || {}),\n autoDisplay: gui.autoDisplay || false,\n dependencies: gui.dependencies ? gui.dependencies() : [],\n attachToSprite: gui.attachToSprite || false,\n };\n\n // Accept both CanvasEngine components (.ce) and Vue components\n // Vue components will be handled by VueGui if available\n if (typeof gui.component !== 'function') {\n guiInstance.component = gui;\n this.extraGuis.push(guiInstance);\n \n // Auto display Vue components if enabled\n if (guiInstance.autoDisplay) {\n this._notifyVueGui(guiId, true, gui.data || {});\n }\n return;\n }\n\n this.gui()[guiId] = guiInstance;\n\n // Auto display if enabled and it's a CanvasEngine component\n if (guiInstance.autoDisplay && typeof gui.component === 'function') {\n this.display(guiId);\n }\n }\n\n /**\n * Get all attached GUI components (attachToSprite: true)\n * \n * Returns all GUI instances that are configured to be attached to sprites.\n * These GUIs should be rendered in character.ce instead of canvas.ce.\n * \n * @returns Array of GUI instances with attachToSprite: true\n * \n * @example\n * ```ts\n * const attachedGuis = gui.getAttachedGuis();\n * // Use in character.ce to render tooltips\n * ```\n */\n getAttachedGuis(): GuiInstance[] {\n const allGuis = this.getAll();\n return Object.values(allGuis).filter(gui => gui.attachToSprite === true);\n }\n\n /**\n * Check if a player should display attached GUIs\n * \n * @param playerId - The player ID to check\n * @returns true if attached GUIs should be displayed for this player\n */\n shouldDisplayAttachedGui(playerId: string): boolean {\n return this.attachedGuiDisplayState()[playerId] === true;\n }\n\n get(id: string): GuiInstance | undefined {\n // Check CanvasEngine GUIs first\n const canvasGui = this.gui()[id];\n if (canvasGui) {\n return canvasGui;\n }\n \n // Check Vue GUIs in extraGuis\n return this.extraGuis.find(gui => gui.name === id);\n }\n\n exists(id: string): boolean {\n return !!this.get(id);\n }\n\n getAll(): Record<string, GuiInstance> {\n const allGuis = { ...this.gui() };\n \n // Add extraGuis to the result\n this.extraGuis.forEach(gui => {\n allGuis[gui.name] = gui;\n });\n \n return allGuis;\n }\n\n /**\n * Display a GUI component\n * \n * Displays the GUI immediately if no dependencies are configured,\n * or waits for all dependencies to be resolved if dependencies are present.\n * Automatically manages subscriptions to prevent memory leaks.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * @param data - Data to pass to the component\n * @param dependencies - Optional runtime dependencies (overrides config dependencies)\n * \n * @example\n * ```ts\n * // Display immediately\n * gui.display('inventory', { items: [] });\n * \n * // Display with runtime dependencies\n * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);\n * ```\n */\n display(id: string, data = {}, dependencies: Signal[] = []) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Check if it's a Vue component (in extraGuis)\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n \n if (isVueComponent) {\n // Handle Vue component display\n this._handleVueComponentDisplay(id, data, dependencies, guiInstance);\n } else {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n }\n }\n\n /**\n * Handle Vue component display logic\n * \n * @param id - GUI component ID\n * @param data - Component data\n * @param dependencies - Runtime dependencies\n * @param guiInstance - GUI instance\n */\n private _handleVueComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {\n // Unsubscribe from previous subscription if exists\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n // Use runtime dependencies or config dependencies\n const deps = dependencies.length > 0 \n ? dependencies \n : (guiInstance.dependencies ? guiInstance.dependencies() : []);\n\n if (deps.length > 0) {\n // Subscribe to dependencies\n guiInstance.subscription = combineLatest(\n deps.map(dependency => dependency.observable)\n ).subscribe((values) => {\n if (values.every(value => value !== undefined)) {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n });\n return;\n }\n\n // No dependencies, display immediately\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n\n /**\n * Handle CanvasEngine component display logic\n * \n * @param id - GUI component ID\n * @param data - Component data\n * @param dependencies - Runtime dependencies\n * @param guiInstance - GUI instance\n */\n private _handleCanvasComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {\n \n }\n\n /**\n * Hide a GUI component\n * \n * Hides the GUI and cleans up any active subscriptions.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * \n * @example\n * ```ts\n * gui.hide('inventory');\n * ```\n */\n hide(id: string) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Unsubscribe if there's an active subscription\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n guiInstance.display.set(false);\n \n // Check if it's a Vue component and notify VueGui\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n if (isVueComponent) {\n this._notifyVueGui(id, false);\n }\n }\n}\n"],"names":["DialogboxComponent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpgjs/client",
3
- "version": "5.0.0-alpha.23",
3
+ "version": "5.0.0-alpha.24",
4
4
  "description": "RPGJS is a framework for creating RPG/MMORPG games",
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -22,18 +22,18 @@
22
22
  "pixi.js": "^8.9.2"
23
23
  },
24
24
  "dependencies": {
25
- "@rpgjs/client": "5.0.0-alpha.23",
26
- "@rpgjs/common": "5.0.0-alpha.23",
27
- "@rpgjs/server": "5.0.0-alpha.23",
28
- "@signe/di": "^2.5.2",
29
- "@signe/room": "^2.5.2",
30
- "@signe/sync": "^2.5.2",
25
+ "@rpgjs/client": "5.0.0-alpha.24",
26
+ "@rpgjs/common": "5.0.0-alpha.24",
27
+ "@rpgjs/server": "5.0.0-alpha.24",
28
+ "@signe/di": "^2.6.0",
29
+ "@signe/room": "^2.6.0",
30
+ "@signe/sync": "^2.6.0",
31
31
  "pixi-filters": "^6.1.5",
32
32
  "rxjs": "^7.8.2"
33
33
  },
34
34
  "devDependencies": {
35
- "@canvasengine/compiler": "2.0.0-beta.38",
36
- "vite": "^7.2.6",
35
+ "@canvasengine/compiler": "2.0.0-beta.40",
36
+ "vite": "^7.2.7",
37
37
  "vite-plugin-dts": "^4.5.4",
38
38
  "vitest": "^4.0.15"
39
39
  },
package/src/Gui/Gui.ts CHANGED
@@ -318,7 +318,6 @@ export class RpgGui {
318
318
  } else {
319
319
  guiInstance.data.set(data);
320
320
  guiInstance.display.set(true);
321
- console.log(guiInstance.dependencies)
322
321
  }
323
322
  }
324
323
 
@@ -12,8 +12,7 @@ import { load } from "@signe/sync";
12
12
  import { RpgClientMap } from "./Game/Map"
13
13
  import { RpgGui } from "./Gui/Gui";
14
14
  import { AnimationManager } from "./Game/AnimationManager";
15
- import { TransitionManager } from "./Game/TransitionManager";
16
- import { lastValueFrom, Observable } from "rxjs";
15
+ import { lastValueFrom, Observable, combineLatest, BehaviorSubject, filter, switchMap, take } from "rxjs";
17
16
  import { GlobalConfigToken } from "./module";
18
17
  import * as PIXI from "pixi.js";
19
18
  import { PrebuiltComponentAnimations } from "./components/animations";
@@ -37,7 +36,6 @@ export class RpgClientEngine<T = any> {
37
36
  spritesheets: Map<string, any> = new Map();
38
37
  sounds: Map<string, any> = new Map();
39
38
  componentAnimations: any[] = [];
40
- transitions: any[] = [];
41
39
  private spritesheetResolver?: (id: string) => any | Promise<any>;
42
40
  private soundResolver?: (id: string) => any | Promise<any>;
43
41
  particleSettings: {
@@ -55,6 +53,8 @@ export class RpgClientEngine<T = any> {
55
53
  /** Trigger for map shake animation */
56
54
  mapShakeTrigger = trigger();
57
55
 
56
+ controlsReady = signal(undefined);
57
+
58
58
  private predictionEnabled = false;
59
59
  private prediction?: PredictionController<Direction>;
60
60
  private readonly SERVER_CORRECTION_THRESHOLD = 30;
@@ -65,6 +65,12 @@ export class RpgClientEngine<T = any> {
65
65
  private pingInterval: any = null;
66
66
  private readonly PING_INTERVAL_MS = 5000; // Send ping every 5 seconds
67
67
  private lastInputTime = 0;
68
+ // Track map loading state for onAfterLoading hook using RxJS
69
+ private mapLoadCompleted$ = new BehaviorSubject<boolean>(false);
70
+ private playerIdReceived$ = new BehaviorSubject<boolean>(false);
71
+ private playersReceived$ = new BehaviorSubject<boolean>(false);
72
+ private eventsReceived$ = new BehaviorSubject<boolean>(false);
73
+ private onAfterLoadingSubscription?: any;
68
74
 
69
75
  constructor(public context) {
70
76
  this.webSocket = inject(WebSocketToken);
@@ -134,6 +140,7 @@ export class RpgClientEngine<T = any> {
134
140
  ...currentValues,
135
141
  values: new Map([['__default__', controlInstance]])
136
142
  }
143
+ this.controlsReady.set(true);
137
144
  }
138
145
 
139
146
  async start() {
@@ -163,7 +170,6 @@ export class RpgClientEngine<T = any> {
163
170
  this.hooks.callHooks("client-gui-load", this).subscribe();
164
171
  this.hooks.callHooks("client-particles-load", this).subscribe();
165
172
  this.hooks.callHooks("client-componentAnimations-load", this).subscribe();
166
- this.hooks.callHooks("client-transitions-load", this).subscribe();
167
173
  this.hooks.callHooks("client-sprite-load", this).subscribe();
168
174
 
169
175
  await lastValueFrom(this.hooks.callHooks("client-engine-onStart", this));
@@ -192,12 +198,27 @@ export class RpgClientEngine<T = any> {
192
198
 
193
199
  private initListeners() {
194
200
  this.webSocket.on("sync", (data) => {
195
- if (data.pId) this.playerIdSignal.set(data.pId)
201
+ if (data.pId) {
202
+ this.playerIdSignal.set(data.pId);
203
+ // Signal that player ID was received
204
+ this.playerIdReceived$.next(true);
205
+ }
196
206
 
197
207
  // Apply client-side prediction filtering and server reconciliation
198
208
  this.hooks.callHooks("client-sceneMap-onChanges", this.sceneMap, { partial: data }).subscribe();
199
209
 
200
210
  load(this.sceneMap, data, true);
211
+
212
+ // Check if players and events are present in sync data
213
+ const players = data.players || this.sceneMap.players();
214
+ if (players && Object.keys(players).length > 0) {
215
+ this.playersReceived$.next(true);
216
+ }
217
+
218
+ const events = data.events || this.sceneMap.events();
219
+ if (events !== undefined) {
220
+ this.eventsReceived$.next(true);
221
+ }
201
222
  });
202
223
 
203
224
  // Handle pong responses for RTT measurement
@@ -269,7 +290,7 @@ export class RpgClientEngine<T = any> {
269
290
 
270
291
  this.webSocket.on("shakeMap", (data) => {
271
292
  const { intensity, duration, frequency, direction } = data || {};
272
- this.mapShakeTrigger.start({
293
+ (this.mapShakeTrigger as any).start({
273
294
  intensity,
274
295
  duration,
275
296
  frequency,
@@ -366,11 +387,25 @@ export class RpgClientEngine<T = any> {
366
387
  }
367
388
 
368
389
  private async loadScene(mapId: string) {
369
- this.hooks.callHooks("client-sceneMap-onBeforeLoading", this.sceneMap).subscribe();
390
+ await lastValueFrom(this.hooks.callHooks("client-sceneMap-onBeforeLoading", this.sceneMap));
370
391
 
371
392
  // Clear client prediction states when changing maps
372
393
  this.clearClientPredictionStates();
373
394
 
395
+ // Reset all conditions for new map loading
396
+ this.mapLoadCompleted$.next(false);
397
+ this.playerIdReceived$.next(false);
398
+ this.playersReceived$.next(false);
399
+ this.eventsReceived$.next(false);
400
+
401
+ // Unsubscribe previous subscription if exists
402
+ if (this.onAfterLoadingSubscription) {
403
+ this.onAfterLoadingSubscription.unsubscribe();
404
+ }
405
+
406
+ // Setup RxJS observable to wait for all conditions
407
+ this.setupOnAfterLoadingObserver();
408
+
374
409
  this.webSocket.updateProperties({ room: mapId })
375
410
  await this.webSocket.reconnect(() => {
376
411
  this.initListeners()
@@ -378,7 +413,25 @@ export class RpgClientEngine<T = any> {
378
413
  })
379
414
  const res = await this.loadMapService.load(mapId)
380
415
  this.sceneMap.data.set(res)
381
- this.hooks.callHooks("client-sceneMap-onAfterLoading", this.sceneMap).subscribe();
416
+
417
+ // Check if playerId is already present
418
+ if (this.playerIdSignal()) {
419
+ this.playerIdReceived$.next(true);
420
+ }
421
+
422
+ // Check if players and events are already present in sceneMap
423
+ const players = this.sceneMap.players();
424
+ if (players && Object.keys(players).length > 0) {
425
+ this.playersReceived$.next(true);
426
+ }
427
+
428
+ const events = this.sceneMap.events();
429
+ if (events !== undefined) {
430
+ this.eventsReceived$.next(true);
431
+ }
432
+
433
+ // Signal that map loading is completed (this should be last to ensure other checks are done)
434
+ this.mapLoadCompleted$.next(true);
382
435
  this.sceneMap.loadPhysic()
383
436
  }
384
437
 
@@ -937,158 +990,13 @@ export class RpgClientEngine<T = any> {
937
990
  return componentAnimation.instance
938
991
  }
939
992
 
940
- /**
941
- * Add a transition to the engine
942
- *
943
- * Transitions are screen effects that can be displayed during scene changes,
944
- * map loading, or any other moment where a visual transition is needed.
945
- * They are displayed on top of the entire canvas and can have custom props
946
- * that can be functions (similar to ComponentAnimation).
947
- *
948
- * @param transition - The transition configuration
949
- * @param transition.id - Unique identifier for the transition
950
- * @param transition.component - The component function to render
951
- * @param transition.props - Optional props to pass to the component (can be a function)
952
- * @returns The added transition configuration
953
- *
954
- * @example
955
- * ```ts
956
- * // Add a fade transition
957
- * engine.addTransition({
958
- * id: 'fade',
959
- * component: FadeComponent
960
- * });
961
- *
962
- * // Add a transition with props
963
- * engine.addTransition({
964
- * id: 'slide',
965
- * component: SlideComponent,
966
- * props: { direction: 'left', duration: 500 }
967
- * });
968
- *
969
- * // Add a transition with function props
970
- * engine.addTransition({
971
- * id: 'custom',
972
- * component: CustomTransition,
973
- * props: (engine) => ({ width: engine.width(), height: engine.height() })
974
- * });
975
- * ```
976
- */
977
- addTransition(transition: {
978
- component: any,
979
- id: string,
980
- props?: any | ((engine: RpgClientEngine) => any)
981
- }) {
982
- const instance = new TransitionManager()
983
- this.transitions.push({
984
- id: transition.id,
985
- component: transition.component,
986
- props: transition.props,
987
- instance: instance,
988
- current: instance.current
989
- })
990
- return transition;
991
- }
992
-
993
- /**
994
- * Remove a transition from the engine
995
- *
996
- * Removes a transition by its ID. This will not affect any currently
997
- * running transitions, only prevent new ones from being started.
998
- *
999
- * @param id - The unique identifier of the transition to remove
1000
- * @returns true if the transition was found and removed, false otherwise
1001
- *
1002
- * @example
1003
- * ```ts
1004
- * // Remove a transition
1005
- * engine.removeTransition('fade');
1006
- * ```
1007
- */
1008
- removeTransition(id: string): boolean {
1009
- const index = this.transitions.findIndex((transition) => transition.id === id);
1010
- if (index !== -1) {
1011
- this.transitions.splice(index, 1);
1012
- return true;
1013
- }
1014
- return false;
1015
- }
1016
-
1017
- /**
1018
- * Modify an existing transition
1019
- *
1020
- * Updates the component or props of an existing transition. This will
1021
- * not affect any currently running transitions, only future ones.
1022
- *
1023
- * @param id - The unique identifier of the transition to modify
1024
- * @param updates - The updates to apply (component and/or props)
1025
- * @returns true if the transition was found and modified, false otherwise
1026
- *
1027
- * @example
1028
- * ```ts
1029
- * // Update transition props
1030
- * engine.modifyTransition('fade', {
1031
- * props: { duration: 2000, color: 'white' }
1032
- * });
1033
- *
1034
- * // Update transition component
1035
- * engine.modifyTransition('fade', {
1036
- * component: NewFadeComponent
1037
- * });
1038
- * ```
1039
- */
1040
- modifyTransition(id: string, updates: {
1041
- component?: any,
1042
- props?: any | ((engine: RpgClientEngine) => any)
1043
- }): boolean {
1044
- const transition = this.transitions.find((transition) => transition.id === id);
1045
- if (!transition) {
1046
- return false;
1047
- }
1048
- if (updates.component !== undefined) {
1049
- transition.component = updates.component;
1050
- }
1051
- if (updates.props !== undefined) {
1052
- transition.props = updates.props;
1053
- }
1054
- return true;
1055
- }
1056
-
1057
- /**
1058
- * Get a transition by its ID
1059
- *
1060
- * Retrieves the TransitionManager instance for a specific transition,
1061
- * which can be used to start the transition.
1062
- *
1063
- * @param id - The unique identifier of the transition
1064
- * @returns The TransitionManager instance for the transition
1065
- * @throws Error if the transition is not found
1066
- *
1067
- * @example
1068
- * ```ts
1069
- * // Get a transition and start it
1070
- * const fadeTransition = engine.getTransition('fade');
1071
- * fadeTransition.start({ duration: 1000 });
1072
- * ```
1073
- */
1074
- getTransition(id: string): TransitionManager {
1075
- const transition = this.transitions.find((transition) => transition.id === id)
1076
- if (!transition) {
1077
- throw new Error(`Transition with id ${id} not found`)
1078
- }
1079
- return transition.instance
1080
- }
1081
-
1082
993
  /**
1083
994
  * Start a transition
1084
995
  *
1085
- * Convenience method to start a transition by its ID. This combines
1086
- * getTransition and start into a single call. The transition will
1087
- * automatically receive an onFinish callback to remove itself when done.
996
+ * Convenience method to display a transition by its ID using the GUI system.
1088
997
  *
1089
998
  * @param id - The unique identifier of the transition to start
1090
- * @param props - Additional props to pass to the transition component
1091
- * @returns The created transition object
999
+ * @param props - Props to pass to the transition component
1092
1000
  *
1093
1001
  * @example
1094
1002
  * ```ts
@@ -1103,28 +1011,10 @@ export class RpgClientEngine<T = any> {
1103
1011
  * ```
1104
1012
  */
1105
1013
  startTransition(id: string, props: any = {}) {
1106
- const transition = this.transitions.find((t) => t.id === id);
1107
- if (!transition) {
1108
- throw new Error(`Transition with id ${id} not found`);
1109
- }
1110
-
1111
- // Get base props (can be a function or object)
1112
- let baseProps = {};
1113
- if (transition.props) {
1114
- if (typeof transition.props === 'function') {
1115
- baseProps = transition.props(this);
1116
- } else {
1117
- baseProps = transition.props;
1118
- }
1014
+ if (!this.guiService.exists(id)) {
1015
+ throw new Error(`Transition with id ${id} not found. Make sure to add it using engine.addTransition() or in your module's transitions property.`);
1119
1016
  }
1120
-
1121
- // Merge base props with provided props (provided props take precedence)
1122
- const finalProps = {
1123
- ...baseProps,
1124
- ...props,
1125
- };
1126
-
1127
- return transition.instance.start(finalProps);
1017
+ this.guiService.display(id, props);
1128
1018
  }
1129
1019
 
1130
1020
  async processInput({ input }: { input: Direction }) {
@@ -1230,6 +1120,46 @@ export class RpgClientEngine<T = any> {
1230
1120
  return this.sceneMap.getCurrentPlayer()
1231
1121
  }
1232
1122
 
1123
+ /**
1124
+ * Setup RxJS observer to wait for all conditions before calling onAfterLoading hook
1125
+ *
1126
+ * This method uses RxJS `combineLatest` to wait for all conditions to be met,
1127
+ * regardless of the order in which they arrive:
1128
+ * 1. The map loading is completed (loadMapService.load is finished)
1129
+ * 2. We received a player ID (pId)
1130
+ * 3. Players array has at least one element
1131
+ * 4. Events property is present in the sync data
1132
+ *
1133
+ * Once all conditions are met, it uses `switchMap` to call the onAfterLoading hook once.
1134
+ *
1135
+ * ## Design
1136
+ *
1137
+ * Uses BehaviorSubjects to track each condition state, allowing events to arrive
1138
+ * in any order. The `combineLatest` operator waits until all observables emit `true`,
1139
+ * then `take(1)` ensures the hook is called only once, and `switchMap` handles
1140
+ * the hook execution.
1141
+ *
1142
+ * @example
1143
+ * ```ts
1144
+ * // Called automatically in loadScene to setup the observer
1145
+ * this.setupOnAfterLoadingObserver();
1146
+ * ```
1147
+ */
1148
+ private setupOnAfterLoadingObserver(): void {
1149
+ this.onAfterLoadingSubscription = combineLatest([
1150
+ this.mapLoadCompleted$.pipe(filter(completed => completed === true)),
1151
+ this.playerIdReceived$.pipe(filter(received => received === true)),
1152
+ this.playersReceived$.pipe(filter(received => received === true)),
1153
+ this.eventsReceived$.pipe(filter(received => received === true))
1154
+ ]).pipe(
1155
+ take(1), // Only execute once when all conditions are met
1156
+ switchMap(() => {
1157
+ // Call the hook and return the observable
1158
+ return this.hooks.callHooks("client-sceneMap-onAfterLoading", this.sceneMap);
1159
+ })
1160
+ ).subscribe();
1161
+ }
1162
+
1233
1163
  /**
1234
1164
  * Clear client prediction states for cleanup
1235
1165
  *
@@ -13,15 +13,14 @@
13
13
  tint
14
14
  hitbox
15
15
  flash={flashConfig}
16
-
17
- />
16
+ />
18
17
  }
19
18
  </Container>
20
19
  @for (compConfig of normalizedComponentsInFront) {
21
20
  <Container dependencies={@compConfig.@dependencies}>
22
21
  <compConfig.component object ...compConfig.props />
23
22
  </Container>
24
- }
23
+ }
25
24
  @for (attachedGui of attachedGuis) {
26
25
  @if (shouldDisplayAttachedGui) {
27
26
  <Container>
@@ -16,7 +16,7 @@ export const withMobile = () => (
16
16
  autoDisplay: true,
17
17
  dependencies: () => {
18
18
  const engine = inject(RpgClientEngine);
19
- return [signal(isMobile() ||undefined), engine.scene.currentPlayer]
19
+ return [signal(isMobile() ||undefined), engine.controlsReady]
20
20
  }
21
21
  }
22
22
  ]