@rpgjs/client 5.0.0-beta.2 → 5.0.0-beta.20

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 (314) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/dist/Game/AnimationManager.d.ts +2 -1
  3. package/dist/Game/AnimationManager.js +21 -9
  4. package/dist/Game/AnimationManager.js.map +1 -1
  5. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  6. package/dist/Game/ClientVisuals.d.ts +61 -0
  7. package/dist/Game/ClientVisuals.js +96 -0
  8. package/dist/Game/ClientVisuals.js.map +1 -0
  9. package/dist/Game/ClientVisuals.spec.d.ts +1 -0
  10. package/dist/Game/Event.js.map +1 -1
  11. package/dist/Game/EventComponentResolver.d.ts +16 -0
  12. package/dist/Game/EventComponentResolver.js +52 -0
  13. package/dist/Game/EventComponentResolver.js.map +1 -0
  14. package/dist/Game/EventComponentResolver.spec.d.ts +1 -0
  15. package/dist/Game/Map.d.ts +9 -1
  16. package/dist/Game/Map.js +83 -5
  17. package/dist/Game/Map.js.map +1 -1
  18. package/dist/Game/Object.d.ts +49 -15
  19. package/dist/Game/Object.js +101 -42
  20. package/dist/Game/Object.js.map +1 -1
  21. package/dist/Game/Object.spec.d.ts +1 -0
  22. package/dist/Game/Player.js.map +1 -1
  23. package/dist/Game/ProjectileManager.d.ts +98 -0
  24. package/dist/Game/ProjectileManager.js +196 -0
  25. package/dist/Game/ProjectileManager.js.map +1 -0
  26. package/dist/Game/ProjectileManager.spec.d.ts +1 -0
  27. package/dist/Gui/Gui.d.ts +20 -6
  28. package/dist/Gui/Gui.js +96 -54
  29. package/dist/Gui/Gui.js.map +1 -1
  30. package/dist/Gui/Gui.spec.d.ts +1 -0
  31. package/dist/Gui/NotificationManager.js.map +1 -1
  32. package/dist/Resource.js +1 -1
  33. package/dist/Resource.js.map +1 -1
  34. package/dist/RpgClient.d.ts +194 -15
  35. package/dist/RpgClientEngine.d.ts +176 -11
  36. package/dist/RpgClientEngine.js +669 -68
  37. package/dist/RpgClientEngine.js.map +1 -1
  38. package/dist/Sound.js.map +1 -1
  39. package/dist/_virtual/{_@oxc-project_runtime@0.122.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/decorate.js +1 -1
  40. package/dist/_virtual/{_@oxc-project_runtime@0.122.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/decorateMetadata.js +1 -1
  41. package/dist/_virtual/_rolldown/runtime.js +13 -0
  42. package/dist/components/animations/animation.ce.js +6 -5
  43. package/dist/components/animations/animation.ce.js.map +1 -1
  44. package/dist/components/animations/fx.ce.js +60 -0
  45. package/dist/components/animations/fx.ce.js.map +1 -0
  46. package/dist/components/animations/hit.ce.js +24 -28
  47. package/dist/components/animations/hit.ce.js.map +1 -1
  48. package/dist/components/animations/index.d.ts +1 -0
  49. package/dist/components/animations/index.js +6 -4
  50. package/dist/components/animations/index.js.map +1 -1
  51. package/dist/components/character.ce.js +606 -248
  52. package/dist/components/character.ce.js.map +1 -1
  53. package/dist/components/dynamics/bar.ce.js +99 -0
  54. package/dist/components/dynamics/bar.ce.js.map +1 -0
  55. package/dist/components/dynamics/image.ce.js +26 -0
  56. package/dist/components/dynamics/image.ce.js.map +1 -0
  57. package/dist/components/dynamics/parse-value.d.ts +3 -0
  58. package/dist/components/dynamics/parse-value.js +54 -35
  59. package/dist/components/dynamics/parse-value.js.map +1 -1
  60. package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
  61. package/dist/components/dynamics/shape-utils.d.ts +16 -0
  62. package/dist/components/dynamics/shape-utils.js +73 -0
  63. package/dist/components/dynamics/shape-utils.js.map +1 -0
  64. package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
  65. package/dist/components/dynamics/shape.ce.js +86 -0
  66. package/dist/components/dynamics/shape.ce.js.map +1 -0
  67. package/dist/components/dynamics/text.ce.js +36 -56
  68. package/dist/components/dynamics/text.ce.js.map +1 -1
  69. package/dist/components/gui/box.ce.js +9 -9
  70. package/dist/components/gui/box.ce.js.map +1 -1
  71. package/dist/components/gui/dialogbox/index.ce.js +75 -65
  72. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  73. package/dist/components/gui/gameover.ce.js +47 -68
  74. package/dist/components/gui/gameover.ce.js.map +1 -1
  75. package/dist/components/gui/hud/hud.ce.js +23 -31
  76. package/dist/components/gui/hud/hud.ce.js.map +1 -1
  77. package/dist/components/gui/menu/equip-menu.ce.js +121 -172
  78. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -1
  79. package/dist/components/gui/menu/exit-menu.ce.js +15 -10
  80. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -1
  81. package/dist/components/gui/menu/items-menu.ce.js +62 -77
  82. package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
  83. package/dist/components/gui/menu/main-menu.ce.js +89 -104
  84. package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
  85. package/dist/components/gui/menu/options-menu.ce.js +12 -8
  86. package/dist/components/gui/menu/options-menu.ce.js.map +1 -1
  87. package/dist/components/gui/menu/skills-menu.ce.js +17 -19
  88. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -1
  89. package/dist/components/gui/mobile/index.js +2 -2
  90. package/dist/components/gui/mobile/index.js.map +1 -1
  91. package/dist/components/gui/mobile/mobile.ce.js +7 -5
  92. package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
  93. package/dist/components/gui/notification/notification.ce.js +28 -26
  94. package/dist/components/gui/notification/notification.ce.js.map +1 -1
  95. package/dist/components/gui/save-load.ce.js +81 -256
  96. package/dist/components/gui/save-load.ce.js.map +1 -1
  97. package/dist/components/gui/shop/shop.ce.js +107 -142
  98. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  99. package/dist/components/gui/title-screen.ce.js +50 -73
  100. package/dist/components/gui/title-screen.ce.js.map +1 -1
  101. package/dist/components/index.d.ts +2 -1
  102. package/dist/components/index.js +1 -0
  103. package/dist/components/interaction-components.ce.js +22 -0
  104. package/dist/components/interaction-components.ce.js.map +1 -0
  105. package/dist/components/player-components-utils.d.ts +67 -0
  106. package/dist/components/player-components-utils.js +162 -0
  107. package/dist/components/player-components-utils.js.map +1 -0
  108. package/dist/components/player-components-utils.spec.d.ts +1 -0
  109. package/dist/components/player-components.ce.js +191 -0
  110. package/dist/components/player-components.ce.js.map +1 -0
  111. package/dist/components/prebuilt/hp-bar.ce.js +45 -45
  112. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
  113. package/dist/components/prebuilt/light-halo.ce.js +39 -60
  114. package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
  115. package/dist/components/scenes/canvas.ce.js +205 -27
  116. package/dist/components/scenes/canvas.ce.js.map +1 -1
  117. package/dist/components/scenes/draw-map.ce.js +39 -39
  118. package/dist/components/scenes/draw-map.ce.js.map +1 -1
  119. package/dist/components/scenes/event-layer.ce.js +51 -10
  120. package/dist/components/scenes/event-layer.ce.js.map +1 -1
  121. package/dist/core/inject.js +1 -1
  122. package/dist/core/inject.js.map +1 -1
  123. package/dist/core/setup.js +1 -1
  124. package/dist/core/setup.js.map +1 -1
  125. package/dist/decorators/spritesheet.d.ts +1 -0
  126. package/dist/decorators/spritesheet.js +11 -0
  127. package/dist/decorators/spritesheet.js.map +1 -0
  128. package/dist/i18n.d.ts +55 -0
  129. package/dist/i18n.js +60 -0
  130. package/dist/i18n.js.map +1 -0
  131. package/dist/i18n.spec.d.ts +1 -0
  132. package/dist/index.d.ts +7 -0
  133. package/dist/index.js +29 -21
  134. package/dist/module.js +45 -4
  135. package/dist/module.js.map +1 -1
  136. package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@3.1.0}/node_modules/@signe/di/dist/index.js +7 -117
  137. package/dist/node_modules/.pnpm/@signe_di@3.1.0/node_modules/@signe/di/dist/index.js.map +1 -0
  138. package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js +239 -0
  139. package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
  140. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  141. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
  142. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js +698 -0
  143. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js.map +1 -0
  144. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js +43 -0
  145. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  146. package/dist/node_modules/.pnpm/{@signe_sync@2.9.0 → @signe_sync@3.1.0_react@19.2.7}/node_modules/@signe/sync/dist/index.js +57 -141
  147. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/index.js.map +1 -0
  148. package/dist/node_modules/.pnpm/{partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js → partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js} +30 -17
  149. package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js.map +1 -0
  150. package/dist/node_modules/.pnpm/{partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js → partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js} +65 -34
  151. package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js.map +1 -0
  152. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js +13 -0
  153. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js.map +1 -0
  154. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js +106 -0
  155. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js.map +1 -0
  156. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js +13 -0
  157. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js.map +1 -0
  158. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js +121 -0
  159. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js.map +1 -0
  160. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js +10 -0
  161. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js.map +1 -0
  162. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js +110 -0
  163. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js.map +1 -0
  164. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js +99 -0
  165. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js.map +1 -0
  166. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js +82 -0
  167. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js.map +1 -0
  168. package/dist/node_modules/.pnpm/{zod@3.24.2/node_modules/zod/lib/index.js → zod@3.25.76/node_modules/zod/v3/types.js} +74 -611
  169. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js.map +1 -0
  170. package/dist/presets/animation.js.map +1 -1
  171. package/dist/presets/faceset.js.map +1 -1
  172. package/dist/presets/icon.js.map +1 -1
  173. package/dist/presets/index.js.map +1 -1
  174. package/dist/presets/lpc.js.map +1 -1
  175. package/dist/presets/rmspritesheet.js.map +1 -1
  176. package/dist/services/AbstractSocket.d.ts +2 -0
  177. package/dist/services/AbstractSocket.js.map +1 -1
  178. package/dist/services/actionInput.d.ts +14 -0
  179. package/dist/services/actionInput.js +59 -0
  180. package/dist/services/actionInput.js.map +1 -0
  181. package/dist/services/actionInput.spec.d.ts +1 -0
  182. package/dist/services/interactions.d.ts +159 -0
  183. package/dist/services/interactions.js +460 -0
  184. package/dist/services/interactions.js.map +1 -0
  185. package/dist/services/interactions.spec.d.ts +1 -0
  186. package/dist/services/keyboardControls.d.ts +1 -0
  187. package/dist/services/keyboardControls.js +1 -0
  188. package/dist/services/keyboardControls.js.map +1 -1
  189. package/dist/services/loadMap.d.ts +9 -0
  190. package/dist/services/loadMap.js +1 -1
  191. package/dist/services/loadMap.js.map +1 -1
  192. package/dist/services/mmorpg-connection.d.ts +5 -0
  193. package/dist/services/mmorpg-connection.js +50 -0
  194. package/dist/services/mmorpg-connection.js.map +1 -0
  195. package/dist/services/mmorpg-connection.spec.d.ts +1 -0
  196. package/dist/services/mmorpg.d.ts +11 -4
  197. package/dist/services/mmorpg.js +57 -33
  198. package/dist/services/mmorpg.js.map +1 -1
  199. package/dist/services/pointerContext.d.ts +11 -0
  200. package/dist/services/pointerContext.js +48 -0
  201. package/dist/services/pointerContext.js.map +1 -0
  202. package/dist/services/pointerContext.spec.d.ts +1 -0
  203. package/dist/services/save.js.map +1 -1
  204. package/dist/services/save.spec.d.ts +1 -0
  205. package/dist/services/standalone-message.d.ts +1 -0
  206. package/dist/services/standalone-message.js +9 -0
  207. package/dist/services/standalone-message.js.map +1 -0
  208. package/dist/services/standalone.d.ts +4 -1
  209. package/dist/services/standalone.js +36 -16
  210. package/dist/services/standalone.js.map +1 -1
  211. package/dist/services/standalone.spec.d.ts +1 -0
  212. package/dist/utils/getEntityProp.js +4 -3
  213. package/dist/utils/getEntityProp.js.map +1 -1
  214. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  215. package/dist/utils/mapId.d.ts +1 -0
  216. package/dist/utils/mapId.js +6 -0
  217. package/dist/utils/mapId.js.map +1 -0
  218. package/dist/utils/readPropValue.d.ts +2 -0
  219. package/dist/utils/readPropValue.js +13 -0
  220. package/dist/utils/readPropValue.js.map +1 -0
  221. package/package.json +13 -13
  222. package/src/Game/AnimationManager.spec.ts +30 -0
  223. package/src/Game/AnimationManager.ts +26 -10
  224. package/src/Game/ClientVisuals.spec.ts +56 -0
  225. package/src/Game/ClientVisuals.ts +184 -0
  226. package/src/Game/EventComponentResolver.spec.ts +84 -0
  227. package/src/Game/EventComponentResolver.ts +74 -0
  228. package/src/Game/Map.ts +134 -2
  229. package/src/Game/Object.spec.ts +59 -0
  230. package/src/Game/Object.ts +181 -77
  231. package/src/Game/ProjectileManager.spec.ts +449 -0
  232. package/src/Game/ProjectileManager.ts +346 -0
  233. package/src/Gui/Gui.spec.ts +340 -0
  234. package/src/Gui/Gui.ts +129 -57
  235. package/src/Resource.ts +1 -2
  236. package/src/RpgClient.ts +220 -17
  237. package/src/RpgClientEngine.ts +959 -116
  238. package/src/components/animations/fx.ce +101 -0
  239. package/src/components/animations/index.ts +4 -2
  240. package/src/components/character.ce +681 -45
  241. package/src/components/dynamics/bar.ce +88 -0
  242. package/src/components/dynamics/image.ce +21 -0
  243. package/src/components/dynamics/parse-value.spec.ts +83 -0
  244. package/src/components/dynamics/parse-value.ts +111 -37
  245. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  246. package/src/components/dynamics/shape-utils.ts +61 -0
  247. package/src/components/dynamics/shape.ce +90 -0
  248. package/src/components/dynamics/text.ce +35 -149
  249. package/src/components/gui/dialogbox/index.ce +52 -21
  250. package/src/components/gui/gameover.ce +6 -4
  251. package/src/components/gui/menu/equip-menu.ce +11 -9
  252. package/src/components/gui/menu/exit-menu.ce +6 -4
  253. package/src/components/gui/menu/items-menu.ce +11 -9
  254. package/src/components/gui/menu/main-menu.ce +14 -12
  255. package/src/components/gui/menu/options-menu.ce +4 -3
  256. package/src/components/gui/menu/skills-menu.ce +2 -1
  257. package/src/components/gui/notification/notification.ce +7 -1
  258. package/src/components/gui/save-load.ce +13 -11
  259. package/src/components/gui/shop/shop.ce +20 -18
  260. package/src/components/gui/title-screen.ce +6 -4
  261. package/src/components/index.ts +2 -1
  262. package/src/components/interaction-components.ce +23 -0
  263. package/src/components/player-components-utils.spec.ts +109 -0
  264. package/src/components/player-components-utils.ts +205 -0
  265. package/src/components/player-components.ce +222 -0
  266. package/src/components/prebuilt/hp-bar.ce +4 -3
  267. package/src/components/prebuilt/light-halo.ce +2 -2
  268. package/src/components/scenes/canvas.ce +219 -15
  269. package/src/components/scenes/draw-map.ce +34 -22
  270. package/src/components/scenes/event-layer.ce +55 -4
  271. package/src/core/setup.ts +2 -2
  272. package/src/decorators/spritesheet.ts +8 -0
  273. package/src/i18n.spec.ts +39 -0
  274. package/src/i18n.ts +59 -0
  275. package/src/index.ts +7 -0
  276. package/src/module.ts +61 -11
  277. package/src/services/AbstractSocket.ts +3 -0
  278. package/src/services/actionInput.spec.ts +155 -0
  279. package/src/services/actionInput.ts +120 -0
  280. package/src/services/interactions.spec.ts +175 -0
  281. package/src/services/interactions.ts +722 -0
  282. package/src/services/keyboardControls.ts +2 -1
  283. package/src/services/loadMap.ts +5 -1
  284. package/src/services/mmorpg-connection.spec.ts +99 -0
  285. package/src/services/mmorpg-connection.ts +69 -0
  286. package/src/services/mmorpg.ts +70 -36
  287. package/src/services/pointerContext.spec.ts +36 -0
  288. package/src/services/pointerContext.ts +84 -0
  289. package/src/services/save.spec.ts +127 -0
  290. package/src/services/standalone-message.ts +7 -0
  291. package/src/services/standalone.spec.ts +54 -0
  292. package/src/services/standalone.ts +44 -12
  293. package/src/utils/getEntityProp.spec.ts +96 -0
  294. package/src/utils/getEntityProp.ts +4 -3
  295. package/src/utils/mapId.ts +2 -0
  296. package/src/utils/readPropValue.ts +16 -0
  297. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +0 -1
  298. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js +0 -457
  299. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js.map +0 -1
  300. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +0 -463
  301. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
  302. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +0 -2191
  303. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +0 -1
  304. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +0 -10
  305. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +0 -1
  306. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +0 -91
  307. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
  308. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +0 -1
  309. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +0 -14
  310. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +0 -1
  311. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +0 -1
  312. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +0 -1
  313. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +0 -2
  314. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +0 -1
@@ -0,0 +1,196 @@
1
+ import { normalizeRoomMapId } from "../utils/mapId.js";
2
+ import { computed, signal } from "canvasengine";
3
+ //#region src/Game/ProjectileManager.ts
4
+ var ProjectileManager = class {
5
+ constructor(hooks, predictionResolver) {
6
+ this.hooks = hooks;
7
+ this.predictionResolver = predictionResolver;
8
+ this.components = /* @__PURE__ */ new Map();
9
+ this.projectiles = /* @__PURE__ */ new Map();
10
+ this.version = signal(0);
11
+ this.impactDurationMs = 350;
12
+ this.current = computed(() => {
13
+ this.version();
14
+ const now = Date.now();
15
+ const rendered = [];
16
+ for (const projectile of this.projectiles.values()) {
17
+ const props = this.toProps(projectile, now);
18
+ if (!props) continue;
19
+ rendered.push({
20
+ id: projectile.spawn.id,
21
+ type: projectile.spawn.type,
22
+ component: projectile.component,
23
+ props
24
+ });
25
+ }
26
+ return rendered;
27
+ });
28
+ }
29
+ register(type, component) {
30
+ this.components.set(type, component);
31
+ return component;
32
+ }
33
+ get(type) {
34
+ return this.components.get(type);
35
+ }
36
+ setMapId(mapId) {
37
+ const normalizedMapId = normalizeRoomMapId(mapId);
38
+ if (this.mapId === normalizedMapId) return;
39
+ this.mapId = normalizedMapId;
40
+ this.clear();
41
+ }
42
+ getMapId() {
43
+ return this.mapId;
44
+ }
45
+ spawnBatch(projectiles, clock = {}) {
46
+ if (!this.acceptsMap(clock.mapId)) return;
47
+ const now = clock.now ?? Date.now();
48
+ for (const projectile of projectiles) {
49
+ const component = this.components.get(projectile.type);
50
+ if (!component) continue;
51
+ const runtime = {
52
+ spawn: {
53
+ ...projectile,
54
+ delay: projectile.delay ?? 0,
55
+ index: projectile.index ?? 0,
56
+ count: projectile.count ?? 1
57
+ },
58
+ component,
59
+ createdAt: now
60
+ };
61
+ this.setPredictedImpact(runtime);
62
+ this.projectiles.set(projectile.id, runtime);
63
+ this.hooks.callHooks("client-projectiles-onSpawn", runtime.spawn).subscribe();
64
+ }
65
+ this.touch();
66
+ }
67
+ impactBatch(impacts, context = {}) {
68
+ if (!this.acceptsMap(context.mapId)) return;
69
+ const now = Date.now();
70
+ for (const impact of impacts) {
71
+ const projectile = this.projectiles.get(impact.id);
72
+ if (!projectile) continue;
73
+ this.setImpact(projectile, impact, now);
74
+ this.hooks.callHooks("client-projectiles-onImpact", this.toProps(projectile, now)).subscribe();
75
+ }
76
+ this.touch();
77
+ }
78
+ destroyBatch(projectiles, context = {}) {
79
+ if (!this.acceptsMap(context.mapId)) return;
80
+ const now = Date.now();
81
+ for (const destroyed of projectiles) {
82
+ const projectile = this.projectiles.get(destroyed.id);
83
+ if (!projectile) continue;
84
+ if (destroyed.reason === "hit") {
85
+ const current = this.toProps(projectile, now);
86
+ this.setImpact(projectile, {
87
+ id: destroyed.id,
88
+ targetId: destroyed.targetId ?? projectile.impact?.targetId,
89
+ x: destroyed.x ?? projectile.impact?.x ?? current?.x ?? projectile.spawn.origin.x,
90
+ y: destroyed.y ?? projectile.impact?.y ?? current?.y ?? projectile.spawn.origin.y,
91
+ distance: destroyed.distance ?? projectile.impact?.distance ?? current?.distance
92
+ }, now);
93
+ }
94
+ projectile.destroyReason = destroyed.reason;
95
+ projectile.destroyAt = projectile.destroyAt ?? (projectile.impact && projectile.impactStartedAt !== void 0 ? projectile.impactStartedAt + this.impactDurationMs : now);
96
+ this.hooks.callHooks("client-projectiles-onDestroy", this.toProps(projectile, now)).subscribe();
97
+ }
98
+ this.touch();
99
+ }
100
+ clear() {
101
+ this.projectiles.clear();
102
+ this.touch();
103
+ }
104
+ step() {
105
+ const now = Date.now();
106
+ let changed = false;
107
+ for (const [id, projectile] of this.projectiles) if (!this.toProps(projectile, now) && !this.isWaitingForDelay(projectile, now) || projectile.destroyAt !== void 0 && now >= projectile.destroyAt) {
108
+ this.projectiles.delete(id);
109
+ changed = true;
110
+ }
111
+ this.touch(changed || this.projectiles.size > 0);
112
+ }
113
+ toProps(projectile, now) {
114
+ const spawn = projectile.spawn;
115
+ const delayMs = (spawn.delay ?? 0) * 1e3;
116
+ const elapsedMs = now - projectile.createdAt - delayMs;
117
+ if (elapsedMs < 0) return null;
118
+ const elapsed = elapsedMs / 1e3;
119
+ const ttl = Math.max(.001, spawn.ttl);
120
+ const rawDistance = Math.min(spawn.speed * elapsed, spawn.range);
121
+ const predictedImpact = this.getActivePredictedImpact(projectile, now, rawDistance);
122
+ const visualImpact = projectile.visualImpact ?? projectile.impact;
123
+ const distance = visualImpact?.distance ?? predictedImpact?.distance ?? rawDistance;
124
+ const progress = Math.min(1, distance / spawn.range);
125
+ const x = visualImpact?.x ?? predictedImpact?.x ?? spawn.origin.x + spawn.direction.x * distance;
126
+ const y = visualImpact?.y ?? predictedImpact?.y ?? spawn.origin.y + spawn.direction.y * distance;
127
+ const impactElapsedMs = projectile.impactStartedAt !== void 0 ? Math.max(0, now - projectile.impactStartedAt) : void 0;
128
+ return {
129
+ ...spawn,
130
+ x,
131
+ y,
132
+ angle: Math.atan2(spawn.direction.y, spawn.direction.x),
133
+ distance,
134
+ elapsed,
135
+ progress,
136
+ impact: projectile.impact,
137
+ impactElapsed: impactElapsedMs === void 0 ? void 0 : impactElapsedMs / 1e3,
138
+ impactProgress: impactElapsedMs === void 0 ? void 0 : Math.min(1, impactElapsedMs / this.impactDurationMs),
139
+ destroyed: projectile.destroyAt !== void 0,
140
+ ttl
141
+ };
142
+ }
143
+ acceptsMap(mapId) {
144
+ const normalizedMapId = normalizeRoomMapId(mapId);
145
+ return !normalizedMapId || !this.mapId || normalizedMapId === this.mapId;
146
+ }
147
+ isWaitingForDelay(projectile, now) {
148
+ const delayMs = (projectile.spawn.delay ?? 0) * 1e3;
149
+ return now - projectile.createdAt - delayMs < 0;
150
+ }
151
+ setPredictedImpact(projectile) {
152
+ if (projectile.spawn.predictImpact === false) return;
153
+ const impact = this.predictionResolver?.(projectile.spawn);
154
+ if (!impact || !Number.isFinite(impact.x) || !Number.isFinite(impact.y)) return;
155
+ const distance = typeof impact.distance === "number" && Number.isFinite(impact.distance) ? impact.distance : Math.hypot(impact.x - projectile.spawn.origin.x, impact.y - projectile.spawn.origin.y);
156
+ if (!Number.isFinite(distance) || distance < 0 || distance > projectile.spawn.range) return;
157
+ projectile.predictedImpact = {
158
+ ...impact,
159
+ distance
160
+ };
161
+ }
162
+ getActivePredictedImpact(projectile, now, rawDistance) {
163
+ if (!projectile.predictedImpact || projectile.impact) return;
164
+ const distance = projectile.predictedImpact.distance;
165
+ if (distance === void 0 || rawDistance < distance) return;
166
+ return projectile.predictedImpact;
167
+ }
168
+ setImpact(projectile, impact, now) {
169
+ projectile.visualImpact = this.resolveVisualImpact(projectile, impact, now);
170
+ projectile.impact = impact;
171
+ projectile.predictedImpact = void 0;
172
+ projectile.impactStartedAt = projectile.impactStartedAt ?? now;
173
+ const impactDestroyAt = projectile.impactStartedAt + this.impactDurationMs;
174
+ projectile.destroyAt = Math.max(projectile.destroyAt ?? 0, impactDestroyAt);
175
+ }
176
+ resolveVisualImpact(projectile, impact, now) {
177
+ const predicted = projectile.predictedImpact;
178
+ if (!predicted || !this.isSameTarget(predicted, impact)) return impact;
179
+ const distance = predicted.distance;
180
+ if (distance === void 0) return impact;
181
+ const delayMs = (projectile.spawn.delay ?? 0) * 1e3;
182
+ const elapsedMs = now - projectile.createdAt - delayMs;
183
+ if (elapsedMs < 0) return impact;
184
+ return Math.min(projectile.spawn.speed * (elapsedMs / 1e3), projectile.spawn.range) >= distance ? predicted : impact;
185
+ }
186
+ isSameTarget(a, b) {
187
+ return a.targetId !== void 0 && a.targetId === b.targetId;
188
+ }
189
+ touch(force = true) {
190
+ if (force) this.version.update((value) => value + 1);
191
+ }
192
+ };
193
+ //#endregion
194
+ export { ProjectileManager };
195
+
196
+ //# sourceMappingURL=ProjectileManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectileManager.js","names":[],"sources":["../../src/Game/ProjectileManager.ts"],"sourcesContent":["import { computed, signal } from \"canvasengine\";\nimport { Hooks } from \"@rpgjs/common\";\nimport { normalizeRoomMapId } from \"../utils/mapId\";\n\nexport interface ClientProjectileSpawn {\n id: string;\n type: string;\n ownerId?: string;\n origin: { x: number; y: number };\n direction: { x: number; y: number };\n speed: number;\n range: number;\n ttl: number;\n spawnTick: number;\n delay?: number;\n index?: number;\n count?: number;\n params?: Record<string, unknown>;\n collisionMask?: number;\n ignoreOwner?: boolean;\n predictImpact?: boolean;\n}\n\nexport interface ClientProjectileImpact {\n id: string;\n targetId?: string;\n x: number;\n y: number;\n distance?: number;\n}\n\nexport interface ClientProjectileDestroy {\n id: string;\n reason?: string;\n targetId?: string;\n x?: number;\n y?: number;\n distance?: number;\n}\n\nexport interface RenderedProjectileProps extends ClientProjectileSpawn {\n x: number;\n y: number;\n angle: number;\n distance: number;\n elapsed: number;\n progress: number;\n impact?: ClientProjectileImpact;\n impactElapsed?: number;\n impactProgress?: number;\n destroyed?: boolean;\n}\n\nexport interface RenderedProjectile {\n id: string;\n type: string;\n component: any;\n props: RenderedProjectileProps;\n}\n\nexport type ProjectilePredictionResolver = (\n projectile: ClientProjectileSpawn,\n) => ClientProjectileImpact | null | undefined;\n\nexport interface ProjectileSpawnClock {\n now?: number;\n currentServerTick?: number;\n tickDurationMs?: number;\n mapId?: string;\n}\n\ninterface RuntimeProjectile {\n spawn: ClientProjectileSpawn;\n component: any;\n createdAt: number;\n impact?: ClientProjectileImpact;\n visualImpact?: ClientProjectileImpact;\n predictedImpact?: ClientProjectileImpact;\n impactStartedAt?: number;\n destroyAt?: number;\n destroyReason?: string;\n}\n\nexport class ProjectileManager {\n private readonly components = new Map<string, any>();\n private readonly projectiles = new Map<string, RuntimeProjectile>();\n private readonly version = signal(0);\n private readonly impactDurationMs = 350;\n private mapId?: string;\n\n constructor(\n private readonly hooks: Hooks,\n private readonly predictionResolver?: ProjectilePredictionResolver,\n ) {}\n\n current = computed<RenderedProjectile[]>(() => {\n this.version();\n const now = Date.now();\n const rendered: RenderedProjectile[] = [];\n for (const projectile of this.projectiles.values()) {\n const props = this.toProps(projectile, now);\n if (!props) {\n continue;\n }\n rendered.push({\n id: projectile.spawn.id,\n type: projectile.spawn.type,\n component: projectile.component,\n props,\n });\n }\n return rendered;\n });\n\n register(type: string, component: any): any {\n this.components.set(type, component);\n return component;\n }\n\n get(type: string): any {\n return this.components.get(type);\n }\n\n setMapId(mapId: string | undefined): void {\n const normalizedMapId = normalizeRoomMapId(mapId);\n if (this.mapId === normalizedMapId) return;\n this.mapId = normalizedMapId;\n this.clear();\n }\n\n getMapId(): string | undefined {\n return this.mapId;\n }\n\n spawnBatch(projectiles: ClientProjectileSpawn[], clock: ProjectileSpawnClock = {}): void {\n if (!this.acceptsMap(clock.mapId)) return;\n const now = clock.now ?? Date.now();\n for (const projectile of projectiles) {\n const component = this.components.get(projectile.type);\n if (!component) {\n continue;\n }\n const runtime: RuntimeProjectile = {\n spawn: {\n ...projectile,\n delay: projectile.delay ?? 0,\n index: projectile.index ?? 0,\n count: projectile.count ?? 1,\n },\n component,\n createdAt: now,\n };\n this.setPredictedImpact(runtime);\n this.projectiles.set(projectile.id, runtime);\n this.hooks.callHooks(\"client-projectiles-onSpawn\", runtime.spawn).subscribe();\n }\n this.touch();\n }\n\n impactBatch(impacts: ClientProjectileImpact[], context: { mapId?: string } = {}): void {\n if (!this.acceptsMap(context.mapId)) return;\n const now = Date.now();\n for (const impact of impacts) {\n const projectile = this.projectiles.get(impact.id);\n if (!projectile) {\n continue;\n }\n this.setImpact(projectile, impact, now);\n this.hooks.callHooks(\"client-projectiles-onImpact\", this.toProps(projectile, now)).subscribe();\n }\n this.touch();\n }\n\n destroyBatch(projectiles: ClientProjectileDestroy[], context: { mapId?: string } = {}): void {\n if (!this.acceptsMap(context.mapId)) return;\n const now = Date.now();\n for (const destroyed of projectiles) {\n const projectile = this.projectiles.get(destroyed.id);\n if (!projectile) {\n continue;\n }\n if (destroyed.reason === \"hit\") {\n const current = this.toProps(projectile, now);\n this.setImpact(projectile, {\n id: destroyed.id,\n targetId: destroyed.targetId ?? projectile.impact?.targetId,\n x: destroyed.x ?? projectile.impact?.x ?? current?.x ?? projectile.spawn.origin.x,\n y: destroyed.y ?? projectile.impact?.y ?? current?.y ?? projectile.spawn.origin.y,\n distance: destroyed.distance ?? projectile.impact?.distance ?? current?.distance,\n }, now);\n }\n projectile.destroyReason = destroyed.reason;\n projectile.destroyAt = projectile.destroyAt ?? (\n projectile.impact && projectile.impactStartedAt !== undefined\n ? projectile.impactStartedAt + this.impactDurationMs\n : now\n );\n this.hooks.callHooks(\"client-projectiles-onDestroy\", this.toProps(projectile, now)).subscribe();\n }\n this.touch();\n }\n\n clear(): void {\n this.projectiles.clear();\n this.touch();\n }\n\n step(): void {\n const now = Date.now();\n let changed = false;\n for (const [id, projectile] of this.projectiles) {\n const props = this.toProps(projectile, now);\n if (\n (!props && !this.isWaitingForDelay(projectile, now)) ||\n (projectile.destroyAt !== undefined && now >= projectile.destroyAt)\n ) {\n this.projectiles.delete(id);\n changed = true;\n }\n }\n this.touch(changed || this.projectiles.size > 0);\n }\n\n private toProps(projectile: RuntimeProjectile, now: number): RenderedProjectileProps | null {\n const spawn = projectile.spawn;\n const delayMs = (spawn.delay ?? 0) * 1000;\n const elapsedMs = now - projectile.createdAt - delayMs;\n if (elapsedMs < 0) {\n return null;\n }\n const elapsed = elapsedMs / 1000;\n const ttl = Math.max(0.001, spawn.ttl);\n const rawDistance = Math.min(spawn.speed * elapsed, spawn.range);\n const predictedImpact = this.getActivePredictedImpact(projectile, now, rawDistance);\n const visualImpact = projectile.visualImpact ?? projectile.impact;\n const distance = visualImpact?.distance ?? predictedImpact?.distance ?? rawDistance;\n const progress = Math.min(1, distance / spawn.range);\n const x = visualImpact?.x ?? predictedImpact?.x ?? spawn.origin.x + spawn.direction.x * distance;\n const y = visualImpact?.y ?? predictedImpact?.y ?? spawn.origin.y + spawn.direction.y * distance;\n const impactElapsedMs = projectile.impactStartedAt !== undefined\n ? Math.max(0, now - projectile.impactStartedAt)\n : undefined;\n return {\n ...spawn,\n x,\n y,\n angle: Math.atan2(spawn.direction.y, spawn.direction.x),\n distance,\n elapsed,\n progress,\n impact: projectile.impact,\n impactElapsed: impactElapsedMs === undefined ? undefined : impactElapsedMs / 1000,\n impactProgress: impactElapsedMs === undefined\n ? undefined\n : Math.min(1, impactElapsedMs / this.impactDurationMs),\n destroyed: projectile.destroyAt !== undefined,\n ttl,\n };\n }\n\n private acceptsMap(mapId: string | undefined): boolean {\n const normalizedMapId = normalizeRoomMapId(mapId);\n return !normalizedMapId || !this.mapId || normalizedMapId === this.mapId;\n }\n\n private isWaitingForDelay(projectile: RuntimeProjectile, now: number): boolean {\n const delayMs = (projectile.spawn.delay ?? 0) * 1000;\n return now - projectile.createdAt - delayMs < 0;\n }\n\n private setPredictedImpact(projectile: RuntimeProjectile): void {\n if (projectile.spawn.predictImpact === false) {\n return;\n }\n const impact = this.predictionResolver?.(projectile.spawn);\n if (!impact || !Number.isFinite(impact.x) || !Number.isFinite(impact.y)) {\n return;\n }\n const distance = typeof impact.distance === \"number\" && Number.isFinite(impact.distance)\n ? impact.distance\n : Math.hypot(impact.x - projectile.spawn.origin.x, impact.y - projectile.spawn.origin.y);\n if (!Number.isFinite(distance) || distance < 0 || distance > projectile.spawn.range) {\n return;\n }\n projectile.predictedImpact = {\n ...impact,\n distance,\n };\n }\n\n private getActivePredictedImpact(\n projectile: RuntimeProjectile,\n now: number,\n rawDistance: number,\n ): ClientProjectileImpact | undefined {\n if (!projectile.predictedImpact || projectile.impact) {\n return undefined;\n }\n const distance = projectile.predictedImpact.distance;\n if (distance === undefined || rawDistance < distance) {\n return undefined;\n }\n return projectile.predictedImpact;\n }\n\n private setImpact(projectile: RuntimeProjectile, impact: ClientProjectileImpact, now: number): void {\n projectile.visualImpact = this.resolveVisualImpact(projectile, impact, now);\n projectile.impact = impact;\n projectile.predictedImpact = undefined;\n projectile.impactStartedAt = projectile.impactStartedAt ?? now;\n const impactDestroyAt = projectile.impactStartedAt + this.impactDurationMs;\n projectile.destroyAt = Math.max(projectile.destroyAt ?? 0, impactDestroyAt);\n }\n\n private resolveVisualImpact(\n projectile: RuntimeProjectile,\n impact: ClientProjectileImpact,\n now: number,\n ): ClientProjectileImpact {\n const predicted = projectile.predictedImpact;\n if (!predicted || !this.isSameTarget(predicted, impact)) {\n return impact;\n }\n const distance = predicted.distance;\n if (distance === undefined) {\n return impact;\n }\n const delayMs = (projectile.spawn.delay ?? 0) * 1000;\n const elapsedMs = now - projectile.createdAt - delayMs;\n if (elapsedMs < 0) {\n return impact;\n }\n const rawDistance = Math.min(projectile.spawn.speed * (elapsedMs / 1000), projectile.spawn.range);\n return rawDistance >= distance ? predicted : impact;\n }\n\n private isSameTarget(a: ClientProjectileImpact, b: ClientProjectileImpact): boolean {\n return a.targetId !== undefined && a.targetId === b.targetId;\n }\n\n private touch(force = true): void {\n if (force) {\n this.version.update((value) => value + 1);\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/Gui/Gui.d.ts CHANGED
@@ -4,7 +4,7 @@ import { Subscription } from 'rxjs';
4
4
  interface GuiOptions {
5
5
  name?: string;
6
6
  id?: string;
7
- component: any;
7
+ component?: any;
8
8
  display?: boolean;
9
9
  data?: any;
10
10
  /**
@@ -24,14 +24,19 @@ interface GuiOptions {
24
24
  * @default false
25
25
  */
26
26
  attachToSprite?: boolean;
27
+ /**
28
+ * Vue v4 compatibility flag. Prefer attachToSprite in v5 projects.
29
+ */
30
+ rpgAttachToSprite?: boolean;
27
31
  }
28
- interface GuiInstance {
32
+ export interface GuiInstance {
29
33
  name: string;
30
34
  component: any;
31
35
  display: WritableSignal<boolean>;
32
36
  data: WritableSignal<any>;
37
+ openId?: string;
33
38
  autoDisplay: boolean;
34
- dependencies?: () => Signal[];
39
+ dependencies?: Signal[];
35
40
  subscription?: Subscription;
36
41
  attachToSprite?: boolean;
37
42
  }
@@ -79,7 +84,7 @@ export declare class RpgGui {
79
84
  */
80
85
  _initializeVueComponents(): void;
81
86
  guiInteraction(guiId: string, name: string, data: any): void;
82
- guiClose(guiId: string, data?: any): void;
87
+ guiClose(guiId: string, data?: any, guiOpenId?: unknown): void;
83
88
  /**
84
89
  * Add a GUI component to the system
85
90
  *
@@ -113,7 +118,7 @@ export declare class RpgGui {
113
118
  * });
114
119
  * ```
115
120
  */
116
- add(gui: GuiOptions): void;
121
+ add(gui: GuiOptions | any): void;
117
122
  registerOptimisticReducer(guiId: string, reducer: OptimisticReducer): void;
118
123
  /**
119
124
  * Get all attached GUI components (attachToSprite: true)
@@ -130,6 +135,8 @@ export declare class RpgGui {
130
135
  * ```
131
136
  */
132
137
  getAttachedGuis(): GuiInstance[];
138
+ getVueGuis(): GuiInstance[];
139
+ getAttachedVueGuis(): GuiInstance[];
133
140
  /**
134
141
  * Check if a player should display attached GUIs
135
142
  *
@@ -161,7 +168,7 @@ export declare class RpgGui {
161
168
  * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);
162
169
  * ```
163
170
  */
164
- display(id: string, data?: {}, dependencies?: Signal[]): void;
171
+ display(id: string, data?: {}, dependencies?: Signal[], openId?: string): void;
165
172
  isDisplaying(id: string): boolean;
166
173
  /**
167
174
  * Handle Vue component display logic
@@ -187,6 +194,13 @@ export declare class RpgGui {
187
194
  */
188
195
  hide(id: string): void;
189
196
  private isVueComponent;
197
+ private isVueComponentInstance;
198
+ private removeCanvasGui;
199
+ private removeVueGui;
200
+ private resolveComponent;
201
+ private resolveGuiId;
202
+ private resolveAttachToSprite;
203
+ private toGuiState;
190
204
  private clearPendingActions;
191
205
  private applyReducers;
192
206
  private applyOptimisticAction;
package/dist/Gui/Gui.js CHANGED
@@ -1,12 +1,12 @@
1
- import { inject } from "../node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js";
1
+ import { inject } from "../node_modules/.pnpm/@signe_di@3.1.0/node_modules/@signe/di/dist/index.js";
2
2
  import { WebSocketToken } from "../services/AbstractSocket.js";
3
- import component from "../components/gui/dialogbox/index.ce.js";
4
- import component$1 from "../components/gui/shop/shop.ce.js";
5
- import component$2 from "../components/gui/save-load.ce.js";
6
- import component$3 from "../components/gui/menu/main-menu.ce.js";
7
- import component$4 from "../components/gui/notification/notification.ce.js";
8
- import component$5 from "../components/gui/title-screen.ce.js";
9
- import component$6 from "../components/gui/gameover.ce.js";
3
+ import __ce_component from "../components/gui/dialogbox/index.ce.js";
4
+ import __ce_component$1 from "../components/gui/shop/shop.ce.js";
5
+ import __ce_component$2 from "../components/gui/save-load.ce.js";
6
+ import __ce_component$3 from "../components/gui/menu/main-menu.ce.js";
7
+ import __ce_component$4 from "../components/gui/notification/notification.ce.js";
8
+ import __ce_component$5 from "../components/gui/title-screen.ce.js";
9
+ import __ce_component$6 from "../components/gui/gameover.ce.js";
10
10
  import "../components/gui/index.js";
11
11
  import { signal } from "canvasengine";
12
12
  import { PrebuiltGui } from "@rpgjs/common";
@@ -86,41 +86,45 @@ var RpgGui = class {
86
86
  this.webSocket = inject(context, WebSocketToken);
87
87
  this.add({
88
88
  name: "rpg-dialog",
89
- component
89
+ component: __ce_component
90
90
  });
91
91
  this.add({
92
92
  name: PrebuiltGui.MainMenu,
93
- component: component$3
93
+ component: __ce_component$3
94
94
  });
95
95
  this.add({
96
96
  name: PrebuiltGui.Shop,
97
- component: component$1
97
+ component: __ce_component$1
98
98
  });
99
99
  this.add({
100
100
  name: PrebuiltGui.Notification,
101
- component: component$4,
101
+ component: __ce_component$4,
102
102
  autoDisplay: true
103
103
  });
104
104
  this.add({
105
105
  name: PrebuiltGui.Save,
106
- component: component$2
106
+ component: __ce_component$2
107
107
  });
108
108
  this.add({
109
109
  name: PrebuiltGui.TitleScreen,
110
- component: component$5
110
+ component: __ce_component$5
111
111
  });
112
112
  this.add({
113
113
  name: PrebuiltGui.Gameover,
114
- component: component$6
114
+ component: __ce_component$6
115
115
  });
116
116
  this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);
117
117
  }
118
118
  async _initialize() {
119
119
  this.webSocket.on("gui.open", (data) => {
120
120
  this.clearPendingActions(data.guiId);
121
- this.display(data.guiId, data.data);
121
+ this.display(data.guiId, data.data, [], data.guiOpenId);
122
122
  });
123
- this.webSocket.on("gui.exit", (guiId) => {
123
+ this.webSocket.on("gui.exit", (payload) => {
124
+ const guiId = typeof payload === "string" ? payload : payload.guiId;
125
+ const guiOpenId = typeof payload === "string" ? void 0 : payload.guiOpenId;
126
+ const current = this.get(guiId);
127
+ if (guiOpenId && current?.openId && current.openId !== guiOpenId) return;
124
128
  this.hide(guiId);
125
129
  });
126
130
  this.webSocket.on("gui.update", (payload) => {
@@ -146,6 +150,7 @@ var RpgGui = class {
146
150
  */
147
151
  _setVueGuiInstance(vueGuiInstance) {
148
152
  this.vueGuiInstance = vueGuiInstance;
153
+ this._initializeVueComponents();
149
154
  }
150
155
  /**
151
156
  * Notify VueGui about GUI state changes
@@ -156,35 +161,16 @@ var RpgGui = class {
156
161
  * @param data - Component data
157
162
  */
158
163
  _notifyVueGui(guiId, display, data = {}) {
159
- if (this.vueGuiInstance && this.vueGuiInstance.vm) {
160
- const extraGui = this.extraGuis.find((gui) => gui.name === guiId);
161
- if (extraGui) {
162
- this.vueGuiInstance.vm.gui[guiId] = {
163
- name: guiId,
164
- display,
165
- data,
166
- attachToSprite: extraGui.attachToSprite || false
167
- };
168
- this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);
169
- }
170
- }
164
+ const extraGui = this.extraGuis.find((gui) => gui.name === guiId);
165
+ if (!extraGui) return;
166
+ this.vueGuiInstance?.updateGuiState?.(this.toGuiState(extraGui, display, data));
171
167
  }
172
168
  /**
173
169
  * Initialize Vue components in the VueGui instance
174
170
  * This should be called after VueGui is mounted
175
171
  */
176
172
  _initializeVueComponents() {
177
- if (this.vueGuiInstance && this.vueGuiInstance.vm) {
178
- this.extraGuis.forEach((gui) => {
179
- this.vueGuiInstance.vm.gui[gui.name] = {
180
- name: gui.name,
181
- display: gui.display(),
182
- data: gui.data(),
183
- attachToSprite: gui.attachToSprite || false
184
- };
185
- });
186
- this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);
187
- }
173
+ this.vueGuiInstance?.initializeGuiStates?.(this.extraGuis.map((gui) => this.toGuiState(gui)));
188
174
  }
189
175
  guiInteraction(guiId, name, data) {
190
176
  const clientActionId = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;
@@ -204,9 +190,11 @@ var RpgGui = class {
204
190
  data: actionData
205
191
  });
206
192
  }
207
- guiClose(guiId, data) {
193
+ guiClose(guiId, data, guiOpenId) {
194
+ const normalizedOpenId = typeof guiOpenId === "string" && guiOpenId.length > 0 ? guiOpenId : void 0;
208
195
  this.webSocket.emit("gui.exit", {
209
196
  guiId,
197
+ guiOpenId: normalizedOpenId,
210
198
  data
211
199
  });
212
200
  }
@@ -244,24 +232,35 @@ var RpgGui = class {
244
232
  * ```
245
233
  */
246
234
  add(gui) {
247
- const guiId = gui.name || gui.id;
235
+ const component = this.resolveComponent(gui);
236
+ const guiId = this.resolveGuiId(gui, component);
248
237
  if (!guiId) throw new Error("GUI must have a name or id");
238
+ const attachToSprite = this.resolveAttachToSprite(gui, component);
249
239
  const guiInstance = {
250
240
  name: guiId,
251
- component: gui.component,
241
+ component,
252
242
  display: signal(gui.display || false),
253
243
  data: signal(gui.data || {}),
244
+ openId: void 0,
254
245
  autoDisplay: gui.autoDisplay || false,
255
246
  dependencies: gui.dependencies ? gui.dependencies() : [],
256
- attachToSprite: gui.attachToSprite || false
247
+ attachToSprite
257
248
  };
258
- if (typeof gui.component !== "function") {
259
- guiInstance.component = gui;
260
- this.extraGuis.push(guiInstance);
261
- if (guiInstance.autoDisplay) this._notifyVueGui(guiId, true, gui.data || {});
249
+ if (this.isVueComponentInstance(guiInstance)) {
250
+ this.removeCanvasGui(guiId);
251
+ const existingIndex = this.extraGuis.findIndex((existing) => existing.name === guiId);
252
+ if (existingIndex >= 0) {
253
+ this.extraGuis[existingIndex].subscription?.unsubscribe();
254
+ this.extraGuis[existingIndex] = guiInstance;
255
+ } else this.extraGuis.push(guiInstance);
256
+ this._initializeVueComponents();
257
+ if (guiInstance.autoDisplay) this.display(guiId, gui.data);
258
+ else this._notifyVueGui(guiId, guiInstance.display(), guiInstance.data());
262
259
  return;
263
260
  }
261
+ this.removeVueGui(guiId);
264
262
  this.gui()[guiId] = guiInstance;
263
+ this._initializeVueComponents();
265
264
  if (guiInstance.autoDisplay && typeof gui.component === "function") this.display(guiId, gui.data);
266
265
  }
267
266
  registerOptimisticReducer(guiId, reducer) {
@@ -283,8 +282,13 @@ var RpgGui = class {
283
282
  * ```
284
283
  */
285
284
  getAttachedGuis() {
286
- const allGuis = this.getAll();
287
- return Object.values(allGuis).filter((gui) => gui.attachToSprite === true);
285
+ return Object.values(this.gui()).filter((gui) => gui.attachToSprite === true);
286
+ }
287
+ getVueGuis() {
288
+ return [...this.extraGuis];
289
+ }
290
+ getAttachedVueGuis() {
291
+ return this.extraGuis.filter((gui) => gui.attachToSprite === true);
288
292
  }
289
293
  /**
290
294
  * Check if a player should display attached GUIs
@@ -331,11 +335,12 @@ var RpgGui = class {
331
335
  * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);
332
336
  * ```
333
337
  */
334
- display(id, data = {}, dependencies = []) {
338
+ display(id, data = {}, dependencies = [], openId) {
335
339
  if (!this.exists(id)) throw throwError(id);
336
340
  const guiInstance = this.get(id);
337
- if (this.extraGuis.some((gui) => gui.name === id)) this._handleVueComponentDisplay(id, data, dependencies, guiInstance);
341
+ if (this.extraGuis.some((gui) => gui.name === id)) this._handleVueComponentDisplay(id, data, dependencies, guiInstance, openId);
338
342
  else {
343
+ guiInstance.openId = openId;
339
344
  guiInstance.data.set(data);
340
345
  guiInstance.display.set(true);
341
346
  }
@@ -353,15 +358,16 @@ var RpgGui = class {
353
358
  * @param dependencies - Runtime dependencies
354
359
  * @param guiInstance - GUI instance
355
360
  */
356
- _handleVueComponentDisplay(id, data, dependencies, guiInstance) {
361
+ _handleVueComponentDisplay(id, data, dependencies, guiInstance, openId) {
357
362
  if (guiInstance.subscription) {
358
363
  guiInstance.subscription.unsubscribe();
359
364
  guiInstance.subscription = void 0;
360
365
  }
361
- const deps = dependencies.length > 0 ? dependencies : guiInstance.dependencies ? guiInstance.dependencies() : [];
366
+ const deps = dependencies.length > 0 ? dependencies : guiInstance.dependencies ?? [];
362
367
  if (deps.length > 0) {
363
368
  guiInstance.subscription = combineLatest(deps.map((dependency) => dependency.observable)).subscribe((values) => {
364
369
  if (values.every((value) => value !== void 0)) {
370
+ guiInstance.openId = openId;
365
371
  guiInstance.data.set(data);
366
372
  guiInstance.display.set(true);
367
373
  this._notifyVueGui(id, true, data);
@@ -369,6 +375,7 @@ var RpgGui = class {
369
375
  });
370
376
  return;
371
377
  }
378
+ guiInstance.openId = openId;
372
379
  guiInstance.data.set(data);
373
380
  guiInstance.display.set(true);
374
381
  this._notifyVueGui(id, true, data);
@@ -394,11 +401,46 @@ var RpgGui = class {
394
401
  guiInstance.subscription = void 0;
395
402
  }
396
403
  guiInstance.display.set(false);
404
+ guiInstance.openId = void 0;
397
405
  if (this.extraGuis.some((gui) => gui.name === id)) this._notifyVueGui(id, false);
398
406
  }
399
407
  isVueComponent(id) {
400
408
  return this.extraGuis.some((gui) => gui.name === id);
401
409
  }
410
+ isVueComponentInstance(gui) {
411
+ return typeof gui.component !== "function";
412
+ }
413
+ removeCanvasGui(guiId) {
414
+ const current = this.gui();
415
+ if (!(guiId in current)) return;
416
+ const next = { ...current };
417
+ delete next[guiId];
418
+ this.gui.set(next);
419
+ }
420
+ removeVueGui(guiId) {
421
+ const removed = this.extraGuis.filter((existing) => existing.name === guiId);
422
+ removed.forEach((gui) => gui.subscription?.unsubscribe());
423
+ if (removed.length > 0) this.extraGuis = this.extraGuis.filter((existing) => existing.name !== guiId);
424
+ }
425
+ resolveComponent(gui) {
426
+ return gui?.component ?? gui;
427
+ }
428
+ resolveGuiId(gui, component) {
429
+ return gui?.name || gui?.id || component?.name || component?.__name;
430
+ }
431
+ resolveAttachToSprite(gui, component) {
432
+ return !!(gui?.attachToSprite || gui?.rpgAttachToSprite || component?.attachToSprite || component?.rpgAttachToSprite);
433
+ }
434
+ toGuiState(gui, display = gui.display(), data = gui.data()) {
435
+ return {
436
+ name: gui.name,
437
+ component: gui.component,
438
+ display,
439
+ data,
440
+ openId: gui.openId,
441
+ attachToSprite: gui.attachToSprite || false
442
+ };
443
+ }
402
444
  clearPendingActions(guiId) {
403
445
  this.pendingActions.delete(guiId);
404
446
  }