@rpgjs/client 5.0.0-beta.1 → 5.0.0-beta.11

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 (245) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +19 -0
  3. package/dist/Game/AnimationManager.d.ts +1 -1
  4. package/dist/Game/AnimationManager.js +18 -9
  5. package/dist/Game/AnimationManager.js.map +1 -1
  6. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  7. package/dist/Game/Event.js.map +1 -1
  8. package/dist/Game/Map.d.ts +9 -1
  9. package/dist/Game/Map.js +63 -5
  10. package/dist/Game/Map.js.map +1 -1
  11. package/dist/Game/Object.d.ts +47 -15
  12. package/dist/Game/Object.js +82 -38
  13. package/dist/Game/Object.js.map +1 -1
  14. package/dist/Game/Player.js.map +1 -1
  15. package/dist/Game/ProjectileManager.d.ts +89 -0
  16. package/dist/Game/ProjectileManager.js +179 -0
  17. package/dist/Game/ProjectileManager.js.map +1 -0
  18. package/dist/Game/ProjectileManager.spec.d.ts +1 -0
  19. package/dist/Gui/Gui.d.ts +17 -4
  20. package/dist/Gui/Gui.js +78 -48
  21. package/dist/Gui/Gui.js.map +1 -1
  22. package/dist/Gui/Gui.spec.d.ts +1 -0
  23. package/dist/Gui/NotificationManager.js.map +1 -1
  24. package/dist/Resource.js +1 -1
  25. package/dist/Resource.js.map +1 -1
  26. package/dist/RpgClient.d.ts +110 -15
  27. package/dist/RpgClientEngine.d.ts +86 -10
  28. package/dist/RpgClientEngine.js +306 -49
  29. package/dist/RpgClientEngine.js.map +1 -1
  30. package/dist/Sound.js.map +1 -1
  31. package/dist/_virtual/{_@oxc-project_runtime@0.122.0 → _@oxc-project_runtime@0.130.0}/helpers/decorate.js +1 -1
  32. package/dist/_virtual/{_@oxc-project_runtime@0.122.0 → _@oxc-project_runtime@0.130.0}/helpers/decorateMetadata.js +1 -1
  33. package/dist/components/animations/animation.ce.js +4 -5
  34. package/dist/components/animations/animation.ce.js.map +1 -1
  35. package/dist/components/animations/hit.ce.js +19 -25
  36. package/dist/components/animations/hit.ce.js.map +1 -1
  37. package/dist/components/animations/index.js +4 -4
  38. package/dist/components/animations/index.js.map +1 -1
  39. package/dist/components/character.ce.js +422 -240
  40. package/dist/components/character.ce.js.map +1 -1
  41. package/dist/components/dynamics/bar.ce.js +97 -0
  42. package/dist/components/dynamics/bar.ce.js.map +1 -0
  43. package/dist/components/dynamics/image.ce.js +24 -0
  44. package/dist/components/dynamics/image.ce.js.map +1 -0
  45. package/dist/components/dynamics/parse-value.d.ts +3 -0
  46. package/dist/components/dynamics/parse-value.js +54 -35
  47. package/dist/components/dynamics/parse-value.js.map +1 -1
  48. package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
  49. package/dist/components/dynamics/shape-utils.d.ts +16 -0
  50. package/dist/components/dynamics/shape-utils.js +73 -0
  51. package/dist/components/dynamics/shape-utils.js.map +1 -0
  52. package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
  53. package/dist/components/dynamics/shape.ce.js +84 -0
  54. package/dist/components/dynamics/shape.ce.js.map +1 -0
  55. package/dist/components/dynamics/text.ce.js +34 -56
  56. package/dist/components/dynamics/text.ce.js.map +1 -1
  57. package/dist/components/gui/box.ce.js +6 -8
  58. package/dist/components/gui/box.ce.js.map +1 -1
  59. package/dist/components/gui/dialogbox/index.ce.js +56 -62
  60. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  61. package/dist/components/gui/gameover.ce.js +42 -65
  62. package/dist/components/gui/gameover.ce.js.map +1 -1
  63. package/dist/components/gui/hud/hud.ce.js +21 -30
  64. package/dist/components/gui/hud/hud.ce.js.map +1 -1
  65. package/dist/components/gui/menu/equip-menu.ce.js +112 -165
  66. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -1
  67. package/dist/components/gui/menu/exit-menu.ce.js +8 -6
  68. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -1
  69. package/dist/components/gui/menu/items-menu.ce.js +52 -69
  70. package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
  71. package/dist/components/gui/menu/main-menu.ce.js +75 -92
  72. package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
  73. package/dist/components/gui/menu/options-menu.ce.js +5 -4
  74. package/dist/components/gui/menu/options-menu.ce.js.map +1 -1
  75. package/dist/components/gui/menu/skills-menu.ce.js +12 -17
  76. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -1
  77. package/dist/components/gui/mobile/index.js +2 -2
  78. package/dist/components/gui/mobile/index.js.map +1 -1
  79. package/dist/components/gui/mobile/mobile.ce.js +5 -4
  80. package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
  81. package/dist/components/gui/notification/notification.ce.js +22 -24
  82. package/dist/components/gui/notification/notification.ce.js.map +1 -1
  83. package/dist/components/gui/save-load.ce.js +72 -249
  84. package/dist/components/gui/save-load.ce.js.map +1 -1
  85. package/dist/components/gui/shop/shop.ce.js +90 -127
  86. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  87. package/dist/components/gui/title-screen.ce.js +45 -70
  88. package/dist/components/gui/title-screen.ce.js.map +1 -1
  89. package/dist/components/index.d.ts +2 -1
  90. package/dist/components/index.js +1 -0
  91. package/dist/components/player-components-utils.d.ts +67 -0
  92. package/dist/components/player-components-utils.js +162 -0
  93. package/dist/components/player-components-utils.js.map +1 -0
  94. package/dist/components/player-components-utils.spec.d.ts +1 -0
  95. package/dist/components/player-components.ce.js +189 -0
  96. package/dist/components/player-components.ce.js.map +1 -0
  97. package/dist/components/prebuilt/hp-bar.ce.js +42 -44
  98. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
  99. package/dist/components/prebuilt/light-halo.ce.js +36 -59
  100. package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
  101. package/dist/components/scenes/canvas.ce.js +165 -21
  102. package/dist/components/scenes/canvas.ce.js.map +1 -1
  103. package/dist/components/scenes/draw-map.ce.js +25 -32
  104. package/dist/components/scenes/draw-map.ce.js.map +1 -1
  105. package/dist/components/scenes/event-layer.ce.js +9 -8
  106. package/dist/components/scenes/event-layer.ce.js.map +1 -1
  107. package/dist/core/inject.js +1 -1
  108. package/dist/core/inject.js.map +1 -1
  109. package/dist/core/setup.js +1 -1
  110. package/dist/core/setup.js.map +1 -1
  111. package/dist/decorators/spritesheet.d.ts +1 -0
  112. package/dist/decorators/spritesheet.js +11 -0
  113. package/dist/decorators/spritesheet.js.map +1 -0
  114. package/dist/index.d.ts +4 -0
  115. package/dist/index.js +26 -21
  116. package/dist/module.js +15 -1
  117. package/dist/module.js.map +1 -1
  118. package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@3.0.1}/node_modules/@signe/di/dist/index.js +7 -117
  119. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js.map +1 -0
  120. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js +239 -0
  121. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js.map +1 -0
  122. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  123. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
  124. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js +696 -0
  125. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js.map +1 -0
  126. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js +44 -0
  127. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  128. package/dist/node_modules/.pnpm/{@signe_sync@2.9.0 → @signe_sync@3.0.1}/node_modules/@signe/sync/dist/index.js +57 -141
  129. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js.map +1 -0
  130. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -1
  131. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -1
  132. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js +27 -27
  133. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -1
  134. package/dist/presets/animation.js.map +1 -1
  135. package/dist/presets/faceset.js.map +1 -1
  136. package/dist/presets/icon.js.map +1 -1
  137. package/dist/presets/index.js.map +1 -1
  138. package/dist/presets/lpc.js.map +1 -1
  139. package/dist/presets/rmspritesheet.js.map +1 -1
  140. package/dist/services/AbstractSocket.js.map +1 -1
  141. package/dist/services/actionInput.d.ts +12 -0
  142. package/dist/services/actionInput.js +27 -0
  143. package/dist/services/actionInput.js.map +1 -0
  144. package/dist/services/actionInput.spec.d.ts +1 -0
  145. package/dist/services/keyboardControls.js.map +1 -1
  146. package/dist/services/loadMap.d.ts +6 -0
  147. package/dist/services/loadMap.js +1 -1
  148. package/dist/services/loadMap.js.map +1 -1
  149. package/dist/services/mmorpg-connection.d.ts +5 -0
  150. package/dist/services/mmorpg-connection.js +50 -0
  151. package/dist/services/mmorpg-connection.js.map +1 -0
  152. package/dist/services/mmorpg-connection.spec.d.ts +1 -0
  153. package/dist/services/mmorpg.d.ts +10 -4
  154. package/dist/services/mmorpg.js +56 -33
  155. package/dist/services/mmorpg.js.map +1 -1
  156. package/dist/services/pointerContext.d.ts +11 -0
  157. package/dist/services/pointerContext.js +48 -0
  158. package/dist/services/pointerContext.js.map +1 -0
  159. package/dist/services/pointerContext.spec.d.ts +1 -0
  160. package/dist/services/save.js.map +1 -1
  161. package/dist/services/save.spec.d.ts +1 -0
  162. package/dist/services/standalone-message.d.ts +1 -0
  163. package/dist/services/standalone-message.js +9 -0
  164. package/dist/services/standalone-message.js.map +1 -0
  165. package/dist/services/standalone.js +4 -3
  166. package/dist/services/standalone.js.map +1 -1
  167. package/dist/services/standalone.spec.d.ts +1 -0
  168. package/dist/utils/getEntityProp.js +4 -3
  169. package/dist/utils/getEntityProp.js.map +1 -1
  170. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  171. package/dist/utils/readPropValue.d.ts +2 -0
  172. package/dist/utils/readPropValue.js +13 -0
  173. package/dist/utils/readPropValue.js.map +1 -0
  174. package/package.json +13 -14
  175. package/src/Game/AnimationManager.spec.ts +30 -0
  176. package/src/Game/AnimationManager.ts +22 -10
  177. package/src/Game/Map.ts +91 -2
  178. package/src/Game/Object.ts +148 -69
  179. package/src/Game/ProjectileManager.spec.ts +338 -0
  180. package/src/Game/ProjectileManager.ts +324 -0
  181. package/src/Gui/Gui.spec.ts +273 -0
  182. package/src/Gui/Gui.ts +105 -50
  183. package/src/Resource.ts +1 -2
  184. package/src/RpgClient.ts +125 -17
  185. package/src/RpgClientEngine.ts +457 -87
  186. package/src/components/character.ce +441 -32
  187. package/src/components/dynamics/bar.ce +88 -0
  188. package/src/components/dynamics/image.ce +21 -0
  189. package/src/components/dynamics/parse-value.spec.ts +83 -0
  190. package/src/components/dynamics/parse-value.ts +111 -37
  191. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  192. package/src/components/dynamics/shape-utils.ts +61 -0
  193. package/src/components/dynamics/shape.ce +90 -0
  194. package/src/components/dynamics/text.ce +35 -149
  195. package/src/components/gui/dialogbox/index.ce +18 -8
  196. package/src/components/gui/gameover.ce +2 -1
  197. package/src/components/gui/menu/equip-menu.ce +2 -1
  198. package/src/components/gui/menu/exit-menu.ce +2 -1
  199. package/src/components/gui/menu/items-menu.ce +3 -2
  200. package/src/components/gui/menu/main-menu.ce +2 -1
  201. package/src/components/gui/save-load.ce +2 -1
  202. package/src/components/gui/shop/shop.ce +3 -2
  203. package/src/components/gui/title-screen.ce +2 -1
  204. package/src/components/index.ts +2 -1
  205. package/src/components/player-components-utils.spec.ts +109 -0
  206. package/src/components/player-components-utils.ts +205 -0
  207. package/src/components/player-components.ce +222 -0
  208. package/src/components/prebuilt/hp-bar.ce +4 -3
  209. package/src/components/prebuilt/light-halo.ce +2 -2
  210. package/src/components/scenes/canvas.ce +175 -8
  211. package/src/components/scenes/draw-map.ce +18 -17
  212. package/src/components/scenes/event-layer.ce +1 -2
  213. package/src/core/setup.ts +2 -2
  214. package/src/decorators/spritesheet.ts +8 -0
  215. package/src/index.ts +4 -0
  216. package/src/module.ts +18 -1
  217. package/src/services/actionInput.spec.ts +101 -0
  218. package/src/services/actionInput.ts +53 -0
  219. package/src/services/loadMap.ts +2 -0
  220. package/src/services/mmorpg-connection.spec.ts +99 -0
  221. package/src/services/mmorpg-connection.ts +69 -0
  222. package/src/services/mmorpg.ts +68 -36
  223. package/src/services/pointerContext.spec.ts +36 -0
  224. package/src/services/pointerContext.ts +84 -0
  225. package/src/services/save.spec.ts +127 -0
  226. package/src/services/standalone-message.ts +7 -0
  227. package/src/services/standalone.spec.ts +34 -0
  228. package/src/services/standalone.ts +3 -2
  229. package/src/utils/getEntityProp.spec.ts +96 -0
  230. package/src/utils/getEntityProp.ts +4 -3
  231. package/src/utils/readPropValue.ts +16 -0
  232. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +0 -1
  233. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js +0 -457
  234. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js.map +0 -1
  235. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +0 -463
  236. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
  237. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +0 -2191
  238. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +0 -1
  239. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +0 -10
  240. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +0 -1
  241. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +0 -91
  242. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
  243. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +0 -1
  244. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +0 -14
  245. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +0 -1
package/src/Gui/Gui.ts CHANGED
@@ -3,12 +3,12 @@ import { signal, Signal, WritableSignal } from "canvasengine";
3
3
  import { AbstractWebsocket, WebSocketToken } from "../services/AbstractSocket";
4
4
  import { DialogboxComponent, ShopComponent, SaveLoadComponent, MainMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent } from "../components/gui";
5
5
  import { combineLatest, Subscription } from "rxjs";
6
- import { delay, PrebuiltGui } from "@rpgjs/common";
6
+ import { PrebuiltGui } from "@rpgjs/common";
7
7
 
8
8
  interface GuiOptions {
9
9
  name?: string;
10
10
  id?: string;
11
- component: any;
11
+ component?: any;
12
12
  display?: boolean;
13
13
  data?: any;
14
14
  /**
@@ -28,19 +28,36 @@ interface GuiOptions {
28
28
  * @default false
29
29
  */
30
30
  attachToSprite?: boolean;
31
+ /**
32
+ * Vue v4 compatibility flag. Prefer attachToSprite in v5 projects.
33
+ */
34
+ rpgAttachToSprite?: boolean;
31
35
  }
32
36
 
33
- interface GuiInstance {
37
+ export interface GuiInstance {
34
38
  name: string;
35
39
  component: any;
36
40
  display: WritableSignal<boolean>;
37
41
  data: WritableSignal<any>;
38
42
  autoDisplay: boolean;
39
- dependencies?: () => Signal[];
43
+ dependencies?: Signal[];
40
44
  subscription?: Subscription;
41
45
  attachToSprite?: boolean;
42
46
  }
43
47
 
48
+ type GuiState = {
49
+ name: string;
50
+ component: any;
51
+ display: boolean;
52
+ data: any;
53
+ attachToSprite: boolean;
54
+ };
55
+
56
+ type VueGuiBridge = {
57
+ updateGuiState?: (state: GuiState) => void;
58
+ initializeGuiStates?: (states: GuiState[]) => void;
59
+ };
60
+
44
61
  interface GuiAction {
45
62
  guiId: string;
46
63
  name: string;
@@ -117,7 +134,7 @@ export class RpgGui {
117
134
  private webSocket: AbstractWebsocket;
118
135
  gui = signal<Record<string, GuiInstance>>({});
119
136
  extraGuis: GuiInstance[] = [];
120
- private vueGuiInstance: any = null; // Reference to VueGui instance
137
+ private vueGuiInstance: VueGuiBridge | null = null;
121
138
  private optimisticReducers = new Map<string, OptimisticReducer[]>();
122
139
  private pendingActions = new Map<string, GuiAction[]>();
123
140
  /**
@@ -196,6 +213,7 @@ export class RpgGui {
196
213
  */
197
214
  _setVueGuiInstance(vueGuiInstance: any) {
198
215
  this.vueGuiInstance = vueGuiInstance;
216
+ this._initializeVueComponents();
199
217
  }
200
218
 
201
219
  /**
@@ -207,21 +225,9 @@ export class RpgGui {
207
225
  * @param data - Component data
208
226
  */
209
227
  private _notifyVueGui(guiId: string, display: boolean, data: any = {}) {
210
- if (this.vueGuiInstance && this.vueGuiInstance.vm) {
211
- // Find the GUI in extraGuis
212
- const extraGui = this.extraGuis.find(gui => gui.name === guiId);
213
- if (extraGui) {
214
- // Update the Vue component's display state and data
215
- this.vueGuiInstance.vm.gui[guiId] = {
216
- name: guiId,
217
- display,
218
- data,
219
- attachToSprite: extraGui.attachToSprite || false
220
- };
221
- // Trigger Vue reactivity
222
- this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);
223
- }
224
- }
228
+ const extraGui = this.extraGuis.find(gui => gui.name === guiId);
229
+ if (!extraGui) return;
230
+ this.vueGuiInstance?.updateGuiState?.(this.toGuiState(extraGui, display, data));
225
231
  }
226
232
 
227
233
  /**
@@ -229,20 +235,9 @@ export class RpgGui {
229
235
  * This should be called after VueGui is mounted
230
236
  */
231
237
  _initializeVueComponents() {
232
- if (this.vueGuiInstance && this.vueGuiInstance.vm) {
233
- // Initialize all extraGuis in the Vue instance
234
- this.extraGuis.forEach(gui => {
235
- this.vueGuiInstance.vm.gui[gui.name] = {
236
- name: gui.name,
237
- display: gui.display(),
238
- data: gui.data(),
239
- attachToSprite: gui.attachToSprite || false
240
- };
241
- });
242
-
243
- // Trigger Vue reactivity
244
- this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);
245
- }
238
+ this.vueGuiInstance?.initializeGuiStates?.(
239
+ this.extraGuis.map(gui => this.toGuiState(gui))
240
+ );
246
241
  }
247
242
 
248
243
  guiInteraction(guiId: string, name: string, data: any) {
@@ -301,35 +296,46 @@ export class RpgGui {
301
296
  * });
302
297
  * ```
303
298
  */
304
- add(gui: GuiOptions) {
305
- const guiId = gui.name || gui.id;
299
+ add(gui: GuiOptions | any) {
300
+ const component = this.resolveComponent(gui);
301
+ const guiId = this.resolveGuiId(gui, component);
306
302
  if (!guiId) {
307
303
  throw new Error("GUI must have a name or id");
308
304
  }
305
+ const attachToSprite = this.resolveAttachToSprite(gui, component);
309
306
  const guiInstance: GuiInstance = {
310
307
  name: guiId,
311
- component: gui.component,
312
- display: signal(gui.display || false),
313
- data: signal(gui.data || {}),
308
+ component,
309
+ display: signal<boolean>(gui.display || false),
310
+ data: signal<any>(gui.data || {}),
314
311
  autoDisplay: gui.autoDisplay || false,
315
312
  dependencies: gui.dependencies ? gui.dependencies() : [],
316
- attachToSprite: gui.attachToSprite || false,
313
+ attachToSprite,
317
314
  };
318
315
 
319
- // Accept both CanvasEngine components (.ce) and Vue components
320
- // Vue components will be handled by VueGui if available
321
- if (typeof gui.component !== 'function') {
322
- guiInstance.component = gui;
323
- this.extraGuis.push(guiInstance);
316
+ if (this.isVueComponentInstance(guiInstance)) {
317
+ this.removeCanvasGui(guiId);
318
+ const existingIndex = this.extraGuis.findIndex(existing => existing.name === guiId);
319
+ if (existingIndex >= 0) {
320
+ this.extraGuis[existingIndex].subscription?.unsubscribe();
321
+ this.extraGuis[existingIndex] = guiInstance;
322
+ } else {
323
+ this.extraGuis.push(guiInstance);
324
+ }
325
+
326
+ this._initializeVueComponents();
324
327
 
325
- // Auto display Vue components if enabled
326
328
  if (guiInstance.autoDisplay) {
327
- this._notifyVueGui(guiId, true, gui.data || {});
329
+ this.display(guiId, gui.data);
330
+ } else {
331
+ this._notifyVueGui(guiId, guiInstance.display(), guiInstance.data());
328
332
  }
329
333
  return;
330
334
  }
331
335
 
336
+ this.removeVueGui(guiId);
332
337
  this.gui()[guiId] = guiInstance;
338
+ this._initializeVueComponents();
333
339
 
334
340
  // Auto display if enabled and it's a CanvasEngine component
335
341
  if (guiInstance.autoDisplay && typeof gui.component === 'function') {
@@ -357,8 +363,15 @@ export class RpgGui {
357
363
  * ```
358
364
  */
359
365
  getAttachedGuis(): GuiInstance[] {
360
- const allGuis = this.getAll();
361
- return Object.values(allGuis).filter(gui => gui.attachToSprite === true);
366
+ return Object.values(this.gui()).filter(gui => gui.attachToSprite === true);
367
+ }
368
+
369
+ getVueGuis(): GuiInstance[] {
370
+ return [...this.extraGuis];
371
+ }
372
+
373
+ getAttachedVueGuis(): GuiInstance[] {
374
+ return this.extraGuis.filter(gui => gui.attachToSprite === true);
362
375
  }
363
376
 
364
377
  /**
@@ -461,7 +474,7 @@ export class RpgGui {
461
474
  // Use runtime dependencies or config dependencies
462
475
  const deps = dependencies.length > 0
463
476
  ? dependencies
464
- : (guiInstance.dependencies ? guiInstance.dependencies() : []);
477
+ : (guiInstance.dependencies ?? []);
465
478
 
466
479
  if (deps.length > 0) {
467
480
  // Subscribe to dependencies
@@ -522,6 +535,48 @@ export class RpgGui {
522
535
  return this.extraGuis.some(gui => gui.name === id);
523
536
  }
524
537
 
538
+ private isVueComponentInstance(gui: GuiInstance) {
539
+ return typeof gui.component !== "function";
540
+ }
541
+
542
+ private removeCanvasGui(guiId: string) {
543
+ const current = this.gui();
544
+ if (!(guiId in current)) return;
545
+ const next = { ...current };
546
+ delete next[guiId];
547
+ this.gui.set(next);
548
+ }
549
+
550
+ private removeVueGui(guiId: string) {
551
+ const removed = this.extraGuis.filter(existing => existing.name === guiId);
552
+ removed.forEach(gui => gui.subscription?.unsubscribe());
553
+ if (removed.length > 0) {
554
+ this.extraGuis = this.extraGuis.filter(existing => existing.name !== guiId);
555
+ }
556
+ }
557
+
558
+ private resolveComponent(gui: GuiOptions | any) {
559
+ return gui?.component ?? gui;
560
+ }
561
+
562
+ private resolveGuiId(gui: GuiOptions | any, component: any) {
563
+ return gui?.name || gui?.id || component?.name || component?.__name;
564
+ }
565
+
566
+ private resolveAttachToSprite(gui: GuiOptions | any, component: any) {
567
+ return !!(gui?.attachToSprite || gui?.rpgAttachToSprite || component?.attachToSprite || component?.rpgAttachToSprite);
568
+ }
569
+
570
+ private toGuiState(gui: GuiInstance, display = gui.display(), data = gui.data()): GuiState {
571
+ return {
572
+ name: gui.name,
573
+ component: gui.component,
574
+ display,
575
+ data,
576
+ attachToSprite: gui.attachToSprite || false,
577
+ };
578
+ }
579
+
525
580
  private clearPendingActions(guiId: string) {
526
581
  this.pendingActions.delete(guiId);
527
582
  }
package/src/Resource.ts CHANGED
@@ -64,7 +64,7 @@ export class RpgResource {
64
64
  // Extract image path from spritesheet
65
65
  const imageLink = spritesheet?.image || spritesheet?.imageSource || undefined;
66
66
  if (imageLink) {
67
- RpgResource._spritesheets.set(id, imageLink);
67
+ RpgResource._spritesheets.set(String(id), imageLink);
68
68
  }
69
69
  });
70
70
 
@@ -147,4 +147,3 @@ export class RpgResource {
147
147
  return RpgResource._sounds;
148
148
  }
149
149
  }
150
-
package/src/RpgClient.ts CHANGED
@@ -2,11 +2,33 @@ import { ComponentFunction, Signal } from 'canvasengine'
2
2
  import { RpgClientEngine } from './RpgClientEngine'
3
3
  import { Loader, Container } from 'pixi.js'
4
4
  import { RpgClientObject } from './Game/Object'
5
- import { type MapPhysicsEntityContext, type MapPhysicsInitContext } from '@rpgjs/common'
5
+ import { type MapPhysicsEntityContext, type MapPhysicsInitContext, type RpgActionName } from '@rpgjs/common'
6
+ import type {
7
+ ClientProjectileSpawn,
8
+ RenderedProjectileProps,
9
+ } from './Game/ProjectileManager'
6
10
 
7
11
  type RpgClass<T = any> = new (...args: any[]) => T
8
12
  type RpgComponent = RpgClientObject
9
13
  type SceneMap = Container
14
+ export type SpriteComponentConfig = ComponentFunction | {
15
+ component: ComponentFunction
16
+ props?: Record<string, any> | ((object: RpgClientObject) => Record<string, any>)
17
+ data?: Record<string, any> | ((object: RpgClientObject) => Record<string, any>)
18
+ dependencies?: (object: RpgClientObject) => any[]
19
+ }
20
+
21
+ export interface RpgSpriteBeforeRemoveContext {
22
+ reason?: string
23
+ data?: any
24
+ transition?: {
25
+ animation?: string
26
+ graphic?: string | string[]
27
+ duration?: number
28
+ effect?: string
29
+ }
30
+ timeoutMs?: number
31
+ }
10
32
 
11
33
  export interface RpgClientEngineHooks {
12
34
  /**
@@ -28,13 +50,14 @@ export interface RpgClientEngineHooks {
28
50
  /**
29
51
  * Recover keys from the pressed keyboard
30
52
  *
31
- * @prop { (engine: RpgClientEngine, obj: { input: string, playerId: number }) => any } [onInput]
53
+ * @prop { (engine: RpgClientEngine, obj: { input: string | number, action?: string | number, data?: any, playerId: number }) => any } [onInput]
32
54
  * @memberof RpgEngineHooks
33
55
  */
34
- onInput?: (engine: RpgClientEngine, obj: { input: string, playerId: number }) => any
56
+ onInput?: (engine: RpgClientEngine, obj: { input: RpgActionName, action?: RpgActionName, data?: any, playerId: number }) => any
35
57
 
36
58
  /**
37
- * Called when the user is connected to the server
59
+ * Called when the user is connected to the server. In MMORPG mode, this
60
+ * runs after the server sends the RPGJS connection acceptance packet.
38
61
  *
39
62
  * @prop { (engine: RpgClientEngine, socket: any) => any } [onConnected]
40
63
  * @memberof RpgEngineHooks
@@ -50,7 +73,8 @@ export interface RpgClientEngineHooks {
50
73
  onDisconnect?: (engine: RpgClientEngine, reason: any, socket: any) => any
51
74
 
52
75
  /**
53
- * Called when there was a connection error
76
+ * Called when there was a connection error. In MMORPG mode, this also runs
77
+ * when server-side auth refuses the connection.
54
78
  *
55
79
  * @prop { (engine: RpgClientEngine, err: any, socket: any) => any } [onConnectError]
56
80
  * @memberof RpgEngineHooks
@@ -81,7 +105,7 @@ export interface RpgSpriteHooks {
81
105
  * }
82
106
  * ```
83
107
  */
84
- componentsBehind?: ComponentFunction[]
108
+ componentsBehind?: SpriteComponentConfig[]
85
109
 
86
110
  /**
87
111
  * Array of components to render in front of the sprite
@@ -96,7 +120,28 @@ export interface RpgSpriteHooks {
96
120
  * }
97
121
  * ```
98
122
  */
99
- componentsInFront?: ComponentFunction[]
123
+ componentsInFront?: SpriteComponentConfig[]
124
+
125
+ /**
126
+ * Reusable sprite components addressable by server-side component definitions.
127
+ *
128
+ * The server sends only the component id and serializable props. The client
129
+ * registry maps that id to the CanvasEngine component that renders it.
130
+ *
131
+ * @prop {Record<string, ComponentFunction>} [components]
132
+ * @memberof RpgSpriteHooks
133
+ * @example
134
+ * ```ts
135
+ * import GuildBadge from './components/guild-badge.ce'
136
+ *
137
+ * const sprite: RpgSpriteHooks = {
138
+ * components: {
139
+ * guildBadge: GuildBadge
140
+ * }
141
+ * }
142
+ * ```
143
+ */
144
+ components?: Record<string, ComponentFunction>
100
145
 
101
146
  /**
102
147
  * As soon as the sprite is initialized
@@ -114,6 +159,21 @@ export interface RpgSpriteHooks {
114
159
  */
115
160
  onDestroy?: (sprite: RpgComponent) => any
116
161
 
162
+ /**
163
+ * Called when a sprite removal is requested, before it disappears from the scene.
164
+ *
165
+ * Return a promise to keep the sprite visible while an animation, effect, or
166
+ * sound transition is running. The server still owns gameplay removal and
167
+ * uses the timeout carried by the remove request as a safety limit.
168
+ *
169
+ * @prop { (sprite: RpgSprite, context: RpgSpriteBeforeRemoveContext) => any } [onBeforeRemove]
170
+ * @memberof RpgSpriteHooks
171
+ */
172
+ onBeforeRemove?: (
173
+ sprite: RpgComponent,
174
+ context: RpgSpriteBeforeRemoveContext
175
+ ) => any
176
+
117
177
  /**
118
178
  * As soon as a data is changed on the server side (the name for example), you are able to know the new data but also the old data.
119
179
  *
@@ -191,6 +251,14 @@ export interface RpgSceneHooks<Scene> {
191
251
  }
192
252
 
193
253
  export interface RpgSceneMapHooks extends RpgSceneHooks<SceneMap> {
254
+ /**
255
+ * Root CanvasEngine component used to render the RPG scene map.
256
+ *
257
+ * Use the exported `SceneMap` component inside your custom component to
258
+ * keep the default map rendering and compose additional scene children.
259
+ */
260
+ component?: ComponentFunction
261
+
194
262
  /**
195
263
  * The map and resources are being loaded
196
264
  *
@@ -235,6 +303,28 @@ export interface RpgSceneMapHooks extends RpgSceneHooks<SceneMap> {
235
303
  onPhysicsReset?: (scene: SceneMap) => any
236
304
  }
237
305
 
306
+ export interface RpgProjectileHooks {
307
+ /**
308
+ * CanvasEngine components used to render server-authoritative projectiles.
309
+ */
310
+ components?: Record<string, ComponentFunction>
311
+
312
+ /**
313
+ * Called when a projectile spawn batch is received from the server.
314
+ */
315
+ onSpawn?: (projectile: ClientProjectileSpawn) => any
316
+
317
+ /**
318
+ * Called when the server confirms a projectile impact.
319
+ */
320
+ onImpact?: (projectile: RenderedProjectileProps | null) => any
321
+
322
+ /**
323
+ * Called when the server destroys a projectile.
324
+ */
325
+ onDestroy?: (projectile: RenderedProjectileProps | null) => any
326
+ }
327
+
238
328
  export interface RpgClient {
239
329
  /**
240
330
  * Add hooks to the player or engine. All modules can listen to the hook
@@ -485,6 +575,13 @@ export interface RpgClient {
485
575
  * ```
486
576
  */
487
577
  attachToSprite?: boolean
578
+ /**
579
+ * Vue v4 compatibility alias for `attachToSprite`.
580
+ *
581
+ * Prefer `attachToSprite` in v5 projects. This is read by `@rpgjs/vue`
582
+ * for Vue GUI components migrated from the v4 GUI API.
583
+ */
584
+ rpgAttachToSprite?: boolean
488
585
  } | any)[],
489
586
 
490
587
  /**
@@ -563,33 +660,36 @@ export interface RpgClient {
563
660
  * */
564
661
  sprite?: RpgSpriteHooks
565
662
 
566
- /**
567
- * Reference the scenes of the game. Here you can put your own class that inherits RpgSceneMap
663
+ /**
664
+ * Reference the scenes of the game.
568
665
  *
569
666
  * ```ts
570
667
  * import { RpgSceneMapHooks, RpgClient, defineModule } from '@rpgjs/client'
668
+ * import MyScene from './my-scene.ce'
571
669
  *
572
670
  * export const sceneMap: RpgSceneMapHooks = {
573
- *
671
+ * component: MyScene
574
672
  * }
575
673
  *
576
674
  * defineModule<RpgClient>({
577
- * scenes: {
578
- * // If you put the RpgSceneMap scene, Thhe key is called mandatory `map`
579
- * map: sceneMap
580
- * }
675
+ * sceneMap
581
676
  * })
582
677
  * ```
583
678
  *
584
- * @prop { [sceneName: string]: RpgSceneMapHooks } [scenes]
679
+ * @prop {RpgSceneMapHooks} [sceneMap]
585
680
  * @memberof RpgClient
586
681
  * */
682
+ sceneMap?: RpgSceneMapHooks
683
+
684
+ /**
685
+ * Legacy scene map hook container.
686
+ *
687
+ * Prefer `sceneMap` for new code.
688
+ */
587
689
  scenes?: {
588
690
  map: RpgSceneMapHooks
589
691
  }
590
692
 
591
- sceneMap?: RpgSceneMapHooks
592
-
593
693
  /**
594
694
  * Array containing the list of component animations
595
695
  * Each element defines a temporary component to display for animations like hits, effects, etc.
@@ -620,4 +720,12 @@ export interface RpgClient {
620
720
  id: string,
621
721
  component: ComponentFunction
622
722
  }[]
723
+
724
+ /**
725
+ * Client-side projectile rendering configuration.
726
+ *
727
+ * Register a CanvasEngine component per projectile type. The server sends
728
+ * compact spawn/impact/destroy events and the client predicts x/y locally.
729
+ */
730
+ projectiles?: RpgProjectileHooks
623
731
  }