@rpgjs/client 5.0.0-alpha.9 → 5.0.0-beta.10

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 (347) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +19 -0
  3. package/dist/Game/AnimationManager.d.ts +8 -0
  4. package/dist/Game/AnimationManager.js +35 -0
  5. package/dist/Game/AnimationManager.js.map +1 -0
  6. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  7. package/dist/Game/Event.d.ts +1 -1
  8. package/dist/Game/Event.js +12 -0
  9. package/dist/Game/Event.js.map +1 -0
  10. package/dist/Game/Map.d.ts +31 -2
  11. package/dist/Game/Map.js +138 -0
  12. package/dist/Game/Map.js.map +1 -0
  13. package/dist/Game/Object.d.ts +189 -0
  14. package/dist/Game/Object.js +255 -0
  15. package/dist/Game/Object.js.map +1 -0
  16. package/dist/Game/Player.d.ts +1 -1
  17. package/dist/Game/Player.js +12 -0
  18. package/dist/Game/Player.js.map +1 -0
  19. package/dist/Gui/Gui.d.ts +192 -7
  20. package/dist/Gui/Gui.js +475 -0
  21. package/dist/Gui/Gui.js.map +1 -0
  22. package/dist/Gui/Gui.spec.d.ts +1 -0
  23. package/dist/Gui/NotificationManager.d.ts +23 -0
  24. package/dist/Gui/NotificationManager.js +49 -0
  25. package/dist/Gui/NotificationManager.js.map +1 -0
  26. package/dist/Resource.d.ts +97 -0
  27. package/dist/Resource.js +133 -0
  28. package/dist/Resource.js.map +1 -0
  29. package/dist/RpgClient.d.ts +295 -13
  30. package/dist/RpgClientEngine.d.ts +671 -15
  31. package/dist/RpgClientEngine.js +1442 -0
  32. package/dist/RpgClientEngine.js.map +1 -0
  33. package/dist/Sound.d.ts +199 -0
  34. package/dist/Sound.js +167 -0
  35. package/dist/Sound.js.map +1 -0
  36. package/dist/_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js +9 -0
  37. package/dist/_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js +6 -0
  38. package/dist/components/animations/animation.ce.js +23 -0
  39. package/dist/components/animations/animation.ce.js.map +1 -0
  40. package/dist/components/animations/hit.ce.js +64 -0
  41. package/dist/components/animations/hit.ce.js.map +1 -0
  42. package/dist/components/animations/index.d.ts +4 -0
  43. package/dist/components/animations/index.js +11 -0
  44. package/dist/components/animations/index.js.map +1 -0
  45. package/dist/components/character.ce.js +572 -0
  46. package/dist/components/character.ce.js.map +1 -0
  47. package/dist/components/dynamics/bar.ce.js +96 -0
  48. package/dist/components/dynamics/bar.ce.js.map +1 -0
  49. package/dist/components/dynamics/image.ce.js +23 -0
  50. package/dist/components/dynamics/image.ce.js.map +1 -0
  51. package/dist/components/dynamics/parse-value.d.ts +4 -0
  52. package/dist/components/dynamics/parse-value.js +63 -0
  53. package/dist/components/dynamics/parse-value.js.map +1 -0
  54. package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
  55. package/dist/components/dynamics/shape-utils.d.ts +16 -0
  56. package/dist/components/dynamics/shape-utils.js +73 -0
  57. package/dist/components/dynamics/shape-utils.js.map +1 -0
  58. package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
  59. package/dist/components/dynamics/shape.ce.js +83 -0
  60. package/dist/components/dynamics/shape.ce.js.map +1 -0
  61. package/dist/components/dynamics/text.ce.js +50 -0
  62. package/dist/components/dynamics/text.ce.js.map +1 -0
  63. package/dist/components/gui/box.ce.js +26 -0
  64. package/dist/components/gui/box.ce.js.map +1 -0
  65. package/dist/components/gui/dialogbox/index.ce.js +198 -0
  66. package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
  67. package/dist/components/gui/gameover.ce.js +169 -0
  68. package/dist/components/gui/gameover.ce.js.map +1 -0
  69. package/dist/components/gui/hud/hud.ce.js +83 -0
  70. package/dist/components/gui/hud/hud.ce.js.map +1 -0
  71. package/dist/components/gui/index.d.ts +15 -3
  72. package/dist/components/gui/index.js +14 -0
  73. package/dist/components/gui/menu/equip-menu.ce.js +427 -0
  74. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -0
  75. package/dist/components/gui/menu/exit-menu.ce.js +55 -0
  76. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -0
  77. package/dist/components/gui/menu/items-menu.ce.js +326 -0
  78. package/dist/components/gui/menu/items-menu.ce.js.map +1 -0
  79. package/dist/components/gui/menu/main-menu.ce.js +399 -0
  80. package/dist/components/gui/menu/main-menu.ce.js.map +1 -0
  81. package/dist/components/gui/menu/options-menu.ce.js +49 -0
  82. package/dist/components/gui/menu/options-menu.ce.js.map +1 -0
  83. package/dist/components/gui/menu/skills-menu.ce.js +102 -0
  84. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -0
  85. package/dist/components/gui/mobile/index.d.ts +8 -0
  86. package/dist/components/gui/mobile/index.js +21 -0
  87. package/dist/components/gui/mobile/index.js.map +1 -0
  88. package/dist/components/gui/mobile/mobile.ce.js +79 -0
  89. package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
  90. package/dist/components/gui/notification/notification.ce.js +62 -0
  91. package/dist/components/gui/notification/notification.ce.js.map +1 -0
  92. package/dist/components/gui/save-load.ce.js +211 -0
  93. package/dist/components/gui/save-load.ce.js.map +1 -0
  94. package/dist/components/gui/shop/shop.ce.js +614 -0
  95. package/dist/components/gui/shop/shop.ce.js.map +1 -0
  96. package/dist/components/gui/title-screen.ce.js +164 -0
  97. package/dist/components/gui/title-screen.ce.js.map +1 -0
  98. package/dist/components/index.d.ts +1 -0
  99. package/dist/components/index.js +4 -0
  100. package/dist/components/player-components-utils.d.ts +67 -0
  101. package/dist/components/player-components-utils.js +162 -0
  102. package/dist/components/player-components-utils.js.map +1 -0
  103. package/dist/components/player-components-utils.spec.d.ts +1 -0
  104. package/dist/components/player-components.ce.js +188 -0
  105. package/dist/components/player-components.ce.js.map +1 -0
  106. package/dist/components/prebuilt/hp-bar.ce.js +113 -0
  107. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
  108. package/dist/components/prebuilt/index.d.ts +19 -0
  109. package/dist/components/prebuilt/index.js +2 -0
  110. package/dist/components/prebuilt/light-halo.ce.js +70 -0
  111. package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
  112. package/dist/components/scenes/canvas.ce.js +196 -0
  113. package/dist/components/scenes/canvas.ce.js.map +1 -0
  114. package/dist/components/scenes/draw-map.ce.js +79 -0
  115. package/dist/components/scenes/draw-map.ce.js.map +1 -0
  116. package/dist/components/scenes/event-layer.ce.js +29 -0
  117. package/dist/components/scenes/event-layer.ce.js.map +1 -0
  118. package/dist/core/inject.js +18 -0
  119. package/dist/core/inject.js.map +1 -0
  120. package/dist/core/setup.js +16 -0
  121. package/dist/core/setup.js.map +1 -0
  122. package/dist/decorators/spritesheet.d.ts +1 -0
  123. package/dist/decorators/spritesheet.js +11 -0
  124. package/dist/decorators/spritesheet.js.map +1 -0
  125. package/dist/index.d.ts +16 -1
  126. package/dist/index.js +45 -14
  127. package/dist/module.d.ts +43 -4
  128. package/dist/module.js +179 -0
  129. package/dist/module.js.map +1 -0
  130. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js +167 -0
  131. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js.map +1 -0
  132. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js +239 -0
  133. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js.map +1 -0
  134. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  135. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
  136. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js +696 -0
  137. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js.map +1 -0
  138. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js +44 -0
  139. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  140. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js +241 -0
  141. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js.map +1 -0
  142. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js +115 -0
  143. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
  144. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js +401 -0
  145. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
  146. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +2 -0
  147. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js +3756 -0
  148. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
  149. package/dist/presets/animation.d.ts +31 -0
  150. package/dist/presets/animation.js +39 -0
  151. package/dist/presets/animation.js.map +1 -0
  152. package/dist/presets/faceset.d.ts +30 -0
  153. package/dist/presets/faceset.js +51 -0
  154. package/dist/presets/faceset.js.map +1 -0
  155. package/dist/presets/icon.d.ts +20 -0
  156. package/dist/presets/icon.js +15 -0
  157. package/dist/presets/icon.js.map +1 -0
  158. package/dist/presets/index.d.ts +123 -0
  159. package/dist/presets/index.js +17 -0
  160. package/dist/presets/index.js.map +1 -0
  161. package/dist/presets/lpc.d.ts +89 -0
  162. package/dist/presets/lpc.js +98 -0
  163. package/dist/presets/lpc.js.map +1 -0
  164. package/dist/presets/rmspritesheet.js +42 -0
  165. package/dist/presets/rmspritesheet.js.map +1 -0
  166. package/dist/services/AbstractSocket.d.ts +9 -5
  167. package/dist/services/AbstractSocket.js +11 -0
  168. package/dist/services/AbstractSocket.js.map +1 -0
  169. package/dist/services/keyboardControls.d.ts +15 -0
  170. package/dist/services/keyboardControls.js +23 -0
  171. package/dist/services/keyboardControls.js.map +1 -0
  172. package/dist/services/loadMap.d.ts +6 -0
  173. package/dist/services/loadMap.js +123 -0
  174. package/dist/services/loadMap.js.map +1 -0
  175. package/dist/services/mmorpg.d.ts +21 -9
  176. package/dist/services/mmorpg.js +136 -0
  177. package/dist/services/mmorpg.js.map +1 -0
  178. package/dist/services/save.d.ts +19 -0
  179. package/dist/services/save.js +77 -0
  180. package/dist/services/save.js.map +1 -0
  181. package/dist/services/save.spec.d.ts +1 -0
  182. package/dist/services/standalone.d.ts +67 -7
  183. package/dist/services/standalone.js +168 -0
  184. package/dist/services/standalone.js.map +1 -0
  185. package/dist/utils/getEntityProp.d.ts +39 -0
  186. package/dist/utils/getEntityProp.js +53 -0
  187. package/dist/utils/getEntityProp.js.map +1 -0
  188. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  189. package/dist/utils/readPropValue.d.ts +2 -0
  190. package/dist/utils/readPropValue.js +13 -0
  191. package/dist/utils/readPropValue.js.map +1 -0
  192. package/package.json +14 -11
  193. package/src/Game/AnimationManager.spec.ts +30 -0
  194. package/src/Game/AnimationManager.ts +33 -0
  195. package/src/Game/Event.ts +1 -1
  196. package/src/Game/Map.ts +184 -3
  197. package/src/Game/Object.ts +409 -14
  198. package/src/Game/Player.ts +1 -1
  199. package/src/Gui/Gui.spec.ts +273 -0
  200. package/src/Gui/Gui.ts +566 -23
  201. package/src/Gui/NotificationManager.ts +69 -0
  202. package/src/Resource.ts +149 -0
  203. package/src/RpgClient.ts +309 -14
  204. package/src/RpgClientEngine.ts +1790 -63
  205. package/src/Sound.ts +253 -0
  206. package/src/components/{effects → animations}/animation.ce +3 -6
  207. package/src/components/{effects → animations}/index.ts +1 -1
  208. package/src/components/character.ce +801 -59
  209. package/src/components/dynamics/bar.ce +87 -0
  210. package/src/components/dynamics/image.ce +20 -0
  211. package/src/components/dynamics/parse-value.spec.ts +83 -0
  212. package/src/components/dynamics/parse-value.ts +154 -0
  213. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  214. package/src/components/dynamics/shape-utils.ts +61 -0
  215. package/src/components/dynamics/shape.ce +89 -0
  216. package/src/components/dynamics/text.ce +68 -0
  217. package/src/components/gui/box.ce +17 -0
  218. package/src/components/gui/dialogbox/index.ce +213 -187
  219. package/src/components/gui/gameover.ce +158 -0
  220. package/src/components/gui/hud/hud.ce +61 -0
  221. package/src/components/gui/index.ts +30 -4
  222. package/src/components/gui/menu/equip-menu.ce +410 -0
  223. package/src/components/gui/menu/exit-menu.ce +41 -0
  224. package/src/components/gui/menu/items-menu.ce +317 -0
  225. package/src/components/gui/menu/main-menu.ce +294 -0
  226. package/src/components/gui/menu/options-menu.ce +35 -0
  227. package/src/components/gui/menu/skills-menu.ce +83 -0
  228. package/src/components/gui/mobile/index.ts +24 -0
  229. package/src/components/gui/mobile/mobile.ce +80 -0
  230. package/src/components/gui/notification/notification.ce +51 -0
  231. package/src/components/gui/save-load.ce +208 -0
  232. package/src/components/gui/shop/shop.ce +493 -0
  233. package/src/components/gui/title-screen.ce +163 -0
  234. package/src/components/index.ts +3 -0
  235. package/src/components/player-components-utils.spec.ts +109 -0
  236. package/src/components/player-components-utils.ts +205 -0
  237. package/src/components/player-components.ce +221 -0
  238. package/src/components/prebuilt/hp-bar.ce +255 -0
  239. package/src/components/prebuilt/index.ts +24 -0
  240. package/src/components/prebuilt/light-halo.ce +148 -0
  241. package/src/components/scenes/canvas.ce +185 -21
  242. package/src/components/scenes/draw-map.ce +55 -21
  243. package/src/components/scenes/event-layer.ce +8 -2
  244. package/src/components/scenes/transition.ce +60 -0
  245. package/src/core/setup.ts +2 -2
  246. package/src/decorators/spritesheet.ts +8 -0
  247. package/src/index.ts +17 -2
  248. package/src/module.ts +132 -10
  249. package/src/presets/animation.ts +46 -0
  250. package/src/presets/faceset.ts +60 -0
  251. package/src/presets/icon.ts +17 -0
  252. package/src/presets/index.ts +9 -1
  253. package/src/presets/lpc.ts +108 -0
  254. package/src/services/AbstractSocket.ts +10 -2
  255. package/src/services/keyboardControls.ts +20 -0
  256. package/src/services/loadMap.ts +3 -1
  257. package/src/services/mmorpg.ts +106 -12
  258. package/src/services/save.spec.ts +127 -0
  259. package/src/services/save.ts +103 -0
  260. package/src/services/standalone.ts +110 -18
  261. package/src/utils/getEntityProp.spec.ts +96 -0
  262. package/src/utils/getEntityProp.ts +88 -0
  263. package/src/utils/readPropValue.ts +16 -0
  264. package/vite.config.ts +4 -2
  265. package/dist/Game/EffectManager.d.ts +0 -5
  266. package/dist/components/effects/index.d.ts +0 -4
  267. package/dist/index.js.map +0 -1
  268. package/dist/index10.js +0 -8
  269. package/dist/index10.js.map +0 -1
  270. package/dist/index11.js +0 -10
  271. package/dist/index11.js.map +0 -1
  272. package/dist/index12.js +0 -8
  273. package/dist/index12.js.map +0 -1
  274. package/dist/index13.js +0 -17
  275. package/dist/index13.js.map +0 -1
  276. package/dist/index14.js +0 -107
  277. package/dist/index14.js.map +0 -1
  278. package/dist/index15.js +0 -50
  279. package/dist/index15.js.map +0 -1
  280. package/dist/index16.js +0 -191
  281. package/dist/index16.js.map +0 -1
  282. package/dist/index17.js +0 -9
  283. package/dist/index17.js.map +0 -1
  284. package/dist/index18.js +0 -387
  285. package/dist/index18.js.map +0 -1
  286. package/dist/index19.js +0 -31
  287. package/dist/index19.js.map +0 -1
  288. package/dist/index2.js +0 -181
  289. package/dist/index2.js.map +0 -1
  290. package/dist/index20.js +0 -24
  291. package/dist/index20.js.map +0 -1
  292. package/dist/index21.js +0 -2421
  293. package/dist/index21.js.map +0 -1
  294. package/dist/index22.js +0 -114
  295. package/dist/index22.js.map +0 -1
  296. package/dist/index23.js +0 -109
  297. package/dist/index23.js.map +0 -1
  298. package/dist/index24.js +0 -71
  299. package/dist/index24.js.map +0 -1
  300. package/dist/index25.js +0 -21
  301. package/dist/index25.js.map +0 -1
  302. package/dist/index26.js +0 -41
  303. package/dist/index26.js.map +0 -1
  304. package/dist/index27.js +0 -5
  305. package/dist/index27.js.map +0 -1
  306. package/dist/index28.js +0 -322
  307. package/dist/index28.js.map +0 -1
  308. package/dist/index29.js +0 -27
  309. package/dist/index29.js.map +0 -1
  310. package/dist/index3.js +0 -87
  311. package/dist/index3.js.map +0 -1
  312. package/dist/index30.js +0 -11
  313. package/dist/index30.js.map +0 -1
  314. package/dist/index31.js +0 -11
  315. package/dist/index31.js.map +0 -1
  316. package/dist/index32.js +0 -174
  317. package/dist/index32.js.map +0 -1
  318. package/dist/index33.js +0 -501
  319. package/dist/index33.js.map +0 -1
  320. package/dist/index34.js +0 -12
  321. package/dist/index34.js.map +0 -1
  322. package/dist/index35.js +0 -4403
  323. package/dist/index35.js.map +0 -1
  324. package/dist/index36.js +0 -316
  325. package/dist/index36.js.map +0 -1
  326. package/dist/index37.js +0 -61
  327. package/dist/index37.js.map +0 -1
  328. package/dist/index38.js +0 -20
  329. package/dist/index38.js.map +0 -1
  330. package/dist/index39.js +0 -20
  331. package/dist/index39.js.map +0 -1
  332. package/dist/index4.js +0 -67
  333. package/dist/index4.js.map +0 -1
  334. package/dist/index5.js +0 -16
  335. package/dist/index5.js.map +0 -1
  336. package/dist/index6.js +0 -17
  337. package/dist/index6.js.map +0 -1
  338. package/dist/index7.js +0 -39
  339. package/dist/index7.js.map +0 -1
  340. package/dist/index8.js +0 -108
  341. package/dist/index8.js.map +0 -1
  342. package/dist/index9.js +0 -76
  343. package/dist/index9.js.map +0 -1
  344. package/src/Game/EffectManager.ts +0 -20
  345. package/src/components/gui/dialogbox/itemMenu.ce +0 -23
  346. package/src/components/gui/dialogbox/selection.ce +0 -67
  347. /package/src/components/{effects → animations}/hit.ce +0 -0
@@ -0,0 +1,475 @@
1
+ import { inject } from "../node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js";
2
+ import { WebSocketToken } from "../services/AbstractSocket.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
+ import "../components/gui/index.js";
11
+ import { signal } from "canvasengine";
12
+ import { PrebuiltGui } from "@rpgjs/common";
13
+ import { combineLatest } from "rxjs";
14
+ //#region src/Gui/Gui.ts
15
+ var throwError = (id) => {
16
+ throw `The GUI named ${id} is non-existent. Please add the component in the gui property of the decorator @RpgClient`;
17
+ };
18
+ var updateItemQuantity = (items, id) => {
19
+ const index = items.findIndex((item) => item?.id === id);
20
+ if (index === -1) return items;
21
+ const item = items[index];
22
+ if (item?.usable === false) return items;
23
+ if (item?.consumable === false) return items;
24
+ const quantity = typeof item?.quantity === "number" ? item.quantity : 1;
25
+ const nextQuantity = Math.max(0, quantity - 1);
26
+ if (nextQuantity === quantity) return items;
27
+ if (nextQuantity <= 0) return items.filter((_, idx) => idx !== index);
28
+ const nextItems = items.slice();
29
+ nextItems[index] = {
30
+ ...item,
31
+ quantity: nextQuantity
32
+ };
33
+ return nextItems;
34
+ };
35
+ var updateEquippedFlag = (items, id, equip) => {
36
+ const index = items.findIndex((item) => item?.id === id);
37
+ if (index === -1) return items;
38
+ const item = items[index];
39
+ if (item?.equipped === equip) return items;
40
+ const nextItems = items.slice();
41
+ nextItems[index] = {
42
+ ...item,
43
+ equipped: equip
44
+ };
45
+ return nextItems;
46
+ };
47
+ var mainMenuOptimisticReducer = (data, action) => {
48
+ if (!data || typeof data !== "object") return data;
49
+ if (action.name === "useItem") {
50
+ if (!Array.isArray(data.items)) return data;
51
+ const id = action.data?.id;
52
+ if (!id) return data;
53
+ const nextItems = updateItemQuantity(data.items, id);
54
+ if (nextItems === data.items) return data;
55
+ return {
56
+ ...data,
57
+ items: nextItems
58
+ };
59
+ }
60
+ if (action.name === "equipItem") {
61
+ const id = action.data?.id;
62
+ if (!id || typeof action.data?.equip !== "boolean") return data;
63
+ const equip = action.data.equip;
64
+ let nextItems = data.items;
65
+ let nextEquips = data.equips;
66
+ if (Array.isArray(data.items)) nextItems = updateEquippedFlag(data.items, id, equip);
67
+ if (Array.isArray(data.equips)) nextEquips = updateEquippedFlag(data.equips, id, equip);
68
+ if (nextItems === data.items && nextEquips === data.equips) return data;
69
+ return {
70
+ ...data,
71
+ ...nextItems !== data.items ? { items: nextItems } : {},
72
+ ...nextEquips !== data.equips ? { equips: nextEquips } : {}
73
+ };
74
+ }
75
+ return data;
76
+ };
77
+ var RpgGui = class {
78
+ constructor(context) {
79
+ this.context = context;
80
+ this.gui = signal({});
81
+ this.extraGuis = [];
82
+ this.vueGuiInstance = null;
83
+ this.optimisticReducers = /* @__PURE__ */ new Map();
84
+ this.pendingActions = /* @__PURE__ */ new Map();
85
+ this.attachedGuiDisplayState = signal({});
86
+ this.webSocket = inject(context, WebSocketToken);
87
+ this.add({
88
+ name: "rpg-dialog",
89
+ component: __ce_component
90
+ });
91
+ this.add({
92
+ name: PrebuiltGui.MainMenu,
93
+ component: __ce_component$3
94
+ });
95
+ this.add({
96
+ name: PrebuiltGui.Shop,
97
+ component: __ce_component$1
98
+ });
99
+ this.add({
100
+ name: PrebuiltGui.Notification,
101
+ component: __ce_component$4,
102
+ autoDisplay: true
103
+ });
104
+ this.add({
105
+ name: PrebuiltGui.Save,
106
+ component: __ce_component$2
107
+ });
108
+ this.add({
109
+ name: PrebuiltGui.TitleScreen,
110
+ component: __ce_component$5
111
+ });
112
+ this.add({
113
+ name: PrebuiltGui.Gameover,
114
+ component: __ce_component$6
115
+ });
116
+ this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);
117
+ }
118
+ async _initialize() {
119
+ this.webSocket.on("gui.open", (data) => {
120
+ this.clearPendingActions(data.guiId);
121
+ this.display(data.guiId, data.data);
122
+ });
123
+ this.webSocket.on("gui.exit", (guiId) => {
124
+ this.hide(guiId);
125
+ });
126
+ this.webSocket.on("gui.update", (payload) => {
127
+ this.applyServerUpdate(payload.guiId, payload.data, payload.clientActionId);
128
+ });
129
+ /**
130
+ * Listen for tooltip display state changes from server
131
+ * This is triggered by showAttachedGui/hideAttachedGui on the server
132
+ */
133
+ this.webSocket.on("gui.tooltip", (data) => {
134
+ const currentState = { ...this.attachedGuiDisplayState() };
135
+ data.players.forEach((playerId) => {
136
+ currentState[playerId] = data.display;
137
+ });
138
+ this.attachedGuiDisplayState.set(currentState);
139
+ });
140
+ }
141
+ /**
142
+ * Set the VueGui instance reference for Vue component management
143
+ * This is called by VueGui when it's initialized
144
+ *
145
+ * @param vueGuiInstance - The VueGui instance
146
+ */
147
+ _setVueGuiInstance(vueGuiInstance) {
148
+ this.vueGuiInstance = vueGuiInstance;
149
+ this._initializeVueComponents();
150
+ }
151
+ /**
152
+ * Notify VueGui about GUI state changes
153
+ * This synchronizes the Vue component display state
154
+ *
155
+ * @param guiId - The GUI component ID
156
+ * @param display - Display state
157
+ * @param data - Component data
158
+ */
159
+ _notifyVueGui(guiId, display, data = {}) {
160
+ const extraGui = this.extraGuis.find((gui) => gui.name === guiId);
161
+ if (!extraGui) return;
162
+ this.vueGuiInstance?.updateGuiState?.(this.toGuiState(extraGui, display, data));
163
+ }
164
+ /**
165
+ * Initialize Vue components in the VueGui instance
166
+ * This should be called after VueGui is mounted
167
+ */
168
+ _initializeVueComponents() {
169
+ this.vueGuiInstance?.initializeGuiStates?.(this.extraGuis.map((gui) => this.toGuiState(gui)));
170
+ }
171
+ guiInteraction(guiId, name, data) {
172
+ const clientActionId = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;
173
+ const actionData = {
174
+ ...data || {},
175
+ clientActionId
176
+ };
177
+ this.applyOptimisticAction({
178
+ guiId,
179
+ name,
180
+ data: actionData,
181
+ clientActionId
182
+ });
183
+ this.webSocket.emit("gui.interaction", {
184
+ guiId,
185
+ name,
186
+ data: actionData
187
+ });
188
+ }
189
+ guiClose(guiId, data) {
190
+ this.webSocket.emit("gui.exit", {
191
+ guiId,
192
+ data
193
+ });
194
+ }
195
+ /**
196
+ * Add a GUI component to the system
197
+ *
198
+ * By default, only CanvasEngine components (.ce files) are accepted.
199
+ * Vue components should be handled by the @rpgjs/vue package.
200
+ *
201
+ * @param gui - GUI configuration options
202
+ * @param gui.name - Name or ID of the GUI component
203
+ * @param gui.id - Alternative ID if name is not provided
204
+ * @param gui.component - The component to render (must be a CanvasEngine component)
205
+ * @param gui.display - Initial display state (default: false)
206
+ * @param gui.data - Initial data for the component
207
+ * @param gui.autoDisplay - Auto display when added (default: false)
208
+ * @param gui.dependencies - Function returning Signal dependencies
209
+ * @param gui.attachToSprite - Attach GUI to sprites instead of global display (default: false)
210
+ *
211
+ * @example
212
+ * ```ts
213
+ * gui.add({
214
+ * name: 'inventory',
215
+ * component: InventoryComponent, // Must be a .ce component
216
+ * autoDisplay: true,
217
+ * dependencies: () => [playerSignal, inventorySignal]
218
+ * });
219
+ *
220
+ * // Attach to sprites
221
+ * gui.add({
222
+ * name: 'tooltip',
223
+ * component: TooltipComponent,
224
+ * attachToSprite: true
225
+ * });
226
+ * ```
227
+ */
228
+ add(gui) {
229
+ const component = this.resolveComponent(gui);
230
+ const guiId = this.resolveGuiId(gui, component);
231
+ if (!guiId) throw new Error("GUI must have a name or id");
232
+ const attachToSprite = this.resolveAttachToSprite(gui, component);
233
+ const guiInstance = {
234
+ name: guiId,
235
+ component,
236
+ display: signal(gui.display || false),
237
+ data: signal(gui.data || {}),
238
+ autoDisplay: gui.autoDisplay || false,
239
+ dependencies: gui.dependencies ? gui.dependencies() : [],
240
+ attachToSprite
241
+ };
242
+ if (this.isVueComponentInstance(guiInstance)) {
243
+ this.removeCanvasGui(guiId);
244
+ const existingIndex = this.extraGuis.findIndex((existing) => existing.name === guiId);
245
+ if (existingIndex >= 0) {
246
+ this.extraGuis[existingIndex].subscription?.unsubscribe();
247
+ this.extraGuis[existingIndex] = guiInstance;
248
+ } else this.extraGuis.push(guiInstance);
249
+ this._initializeVueComponents();
250
+ if (guiInstance.autoDisplay) this.display(guiId, gui.data);
251
+ else this._notifyVueGui(guiId, guiInstance.display(), guiInstance.data());
252
+ return;
253
+ }
254
+ this.removeVueGui(guiId);
255
+ this.gui()[guiId] = guiInstance;
256
+ this._initializeVueComponents();
257
+ if (guiInstance.autoDisplay && typeof gui.component === "function") this.display(guiId, gui.data);
258
+ }
259
+ registerOptimisticReducer(guiId, reducer) {
260
+ const existing = this.optimisticReducers.get(guiId) || [];
261
+ this.optimisticReducers.set(guiId, existing.concat(reducer));
262
+ }
263
+ /**
264
+ * Get all attached GUI components (attachToSprite: true)
265
+ *
266
+ * Returns all GUI instances that are configured to be attached to sprites.
267
+ * These GUIs should be rendered in character.ce instead of canvas.ce.
268
+ *
269
+ * @returns Array of GUI instances with attachToSprite: true
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * const attachedGuis = gui.getAttachedGuis();
274
+ * // Use in character.ce to render tooltips
275
+ * ```
276
+ */
277
+ getAttachedGuis() {
278
+ return Object.values(this.gui()).filter((gui) => gui.attachToSprite === true);
279
+ }
280
+ getVueGuis() {
281
+ return [...this.extraGuis];
282
+ }
283
+ getAttachedVueGuis() {
284
+ return this.extraGuis.filter((gui) => gui.attachToSprite === true);
285
+ }
286
+ /**
287
+ * Check if a player should display attached GUIs
288
+ *
289
+ * @param playerId - The player ID to check
290
+ * @returns true if attached GUIs should be displayed for this player
291
+ */
292
+ shouldDisplayAttachedGui(playerId) {
293
+ return this.attachedGuiDisplayState()[playerId] === true;
294
+ }
295
+ get(id) {
296
+ const canvasGui = this.gui()[id];
297
+ if (canvasGui) return canvasGui;
298
+ return this.extraGuis.find((gui) => gui.name === id);
299
+ }
300
+ exists(id) {
301
+ return !!this.get(id);
302
+ }
303
+ getAll() {
304
+ const allGuis = { ...this.gui() };
305
+ this.extraGuis.forEach((gui) => {
306
+ allGuis[gui.name] = gui;
307
+ });
308
+ return allGuis;
309
+ }
310
+ /**
311
+ * Display a GUI component
312
+ *
313
+ * Displays the GUI immediately if no dependencies are configured,
314
+ * or waits for all dependencies to be resolved if dependencies are present.
315
+ * Automatically manages subscriptions to prevent memory leaks.
316
+ * Works with both CanvasEngine components and Vue components.
317
+ *
318
+ * @param id - The GUI component ID
319
+ * @param data - Data to pass to the component
320
+ * @param dependencies - Optional runtime dependencies (overrides config dependencies)
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * // Display immediately
325
+ * gui.display('inventory', { items: [] });
326
+ *
327
+ * // Display with runtime dependencies
328
+ * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);
329
+ * ```
330
+ */
331
+ display(id, data = {}, dependencies = []) {
332
+ if (!this.exists(id)) throw throwError(id);
333
+ const guiInstance = this.get(id);
334
+ if (this.extraGuis.some((gui) => gui.name === id)) this._handleVueComponentDisplay(id, data, dependencies, guiInstance);
335
+ else {
336
+ guiInstance.data.set(data);
337
+ guiInstance.display.set(true);
338
+ }
339
+ }
340
+ isDisplaying(id) {
341
+ const guiInstance = this.get(id);
342
+ if (!guiInstance) return false;
343
+ return guiInstance.display();
344
+ }
345
+ /**
346
+ * Handle Vue component display logic
347
+ *
348
+ * @param id - GUI component ID
349
+ * @param data - Component data
350
+ * @param dependencies - Runtime dependencies
351
+ * @param guiInstance - GUI instance
352
+ */
353
+ _handleVueComponentDisplay(id, data, dependencies, guiInstance) {
354
+ if (guiInstance.subscription) {
355
+ guiInstance.subscription.unsubscribe();
356
+ guiInstance.subscription = void 0;
357
+ }
358
+ const deps = dependencies.length > 0 ? dependencies : guiInstance.dependencies ?? [];
359
+ if (deps.length > 0) {
360
+ guiInstance.subscription = combineLatest(deps.map((dependency) => dependency.observable)).subscribe((values) => {
361
+ if (values.every((value) => value !== void 0)) {
362
+ guiInstance.data.set(data);
363
+ guiInstance.display.set(true);
364
+ this._notifyVueGui(id, true, data);
365
+ }
366
+ });
367
+ return;
368
+ }
369
+ guiInstance.data.set(data);
370
+ guiInstance.display.set(true);
371
+ this._notifyVueGui(id, true, data);
372
+ }
373
+ /**
374
+ * Hide a GUI component
375
+ *
376
+ * Hides the GUI and cleans up any active subscriptions.
377
+ * Works with both CanvasEngine components and Vue components.
378
+ *
379
+ * @param id - The GUI component ID
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * gui.hide('inventory');
384
+ * ```
385
+ */
386
+ hide(id) {
387
+ if (!this.exists(id)) throw throwError(id);
388
+ const guiInstance = this.get(id);
389
+ if (guiInstance.subscription) {
390
+ guiInstance.subscription.unsubscribe();
391
+ guiInstance.subscription = void 0;
392
+ }
393
+ guiInstance.display.set(false);
394
+ if (this.extraGuis.some((gui) => gui.name === id)) this._notifyVueGui(id, false);
395
+ }
396
+ isVueComponent(id) {
397
+ return this.extraGuis.some((gui) => gui.name === id);
398
+ }
399
+ isVueComponentInstance(gui) {
400
+ return typeof gui.component !== "function";
401
+ }
402
+ removeCanvasGui(guiId) {
403
+ const current = this.gui();
404
+ if (!(guiId in current)) return;
405
+ const next = { ...current };
406
+ delete next[guiId];
407
+ this.gui.set(next);
408
+ }
409
+ removeVueGui(guiId) {
410
+ const removed = this.extraGuis.filter((existing) => existing.name === guiId);
411
+ removed.forEach((gui) => gui.subscription?.unsubscribe());
412
+ if (removed.length > 0) this.extraGuis = this.extraGuis.filter((existing) => existing.name !== guiId);
413
+ }
414
+ resolveComponent(gui) {
415
+ return gui?.component ?? gui;
416
+ }
417
+ resolveGuiId(gui, component) {
418
+ return gui?.name || gui?.id || component?.name || component?.__name;
419
+ }
420
+ resolveAttachToSprite(gui, component) {
421
+ return !!(gui?.attachToSprite || gui?.rpgAttachToSprite || component?.attachToSprite || component?.rpgAttachToSprite);
422
+ }
423
+ toGuiState(gui, display = gui.display(), data = gui.data()) {
424
+ return {
425
+ name: gui.name,
426
+ component: gui.component,
427
+ display,
428
+ data,
429
+ attachToSprite: gui.attachToSprite || false
430
+ };
431
+ }
432
+ clearPendingActions(guiId) {
433
+ this.pendingActions.delete(guiId);
434
+ }
435
+ applyReducers(guiId, data, actions) {
436
+ const reducers = this.optimisticReducers.get(guiId);
437
+ if (!reducers || reducers.length === 0) return data;
438
+ let next = data;
439
+ for (const action of actions) for (const reducer of reducers) {
440
+ const updated = reducer(next, action);
441
+ if (updated !== void 0 && updated !== null && updated !== next) next = updated;
442
+ }
443
+ return next;
444
+ }
445
+ applyOptimisticAction(action) {
446
+ const guiInstance = this.get(action.guiId);
447
+ if (!guiInstance) return;
448
+ const reducers = this.optimisticReducers.get(action.guiId);
449
+ if (!reducers || reducers.length === 0) return;
450
+ const currentData = guiInstance.data();
451
+ const nextData = this.applyReducers(action.guiId, currentData, [action]);
452
+ if (nextData === currentData) return;
453
+ guiInstance.data.set(nextData);
454
+ const pending = this.pendingActions.get(action.guiId) || [];
455
+ pending.push(action);
456
+ this.pendingActions.set(action.guiId, pending);
457
+ if (this.isVueComponent(action.guiId)) this._notifyVueGui(action.guiId, guiInstance.display(), nextData);
458
+ }
459
+ applyServerUpdate(guiId, data, clientActionId) {
460
+ const guiInstance = this.get(guiId);
461
+ if (!guiInstance) return;
462
+ let pending = this.pendingActions.get(guiId) || [];
463
+ if (clientActionId) pending = pending.filter((action) => action.clientActionId !== clientActionId);
464
+ else pending = [];
465
+ let nextData = data;
466
+ if (pending.length) nextData = this.applyReducers(guiId, nextData, pending);
467
+ guiInstance.data.set(nextData);
468
+ this.pendingActions.set(guiId, pending);
469
+ if (this.isVueComponent(guiId)) this._notifyVueGui(guiId, guiInstance.display(), nextData);
470
+ }
471
+ };
472
+ //#endregion
473
+ export { RpgGui };
474
+
475
+ //# sourceMappingURL=Gui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Gui.js","names":[],"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, ShopComponent, SaveLoadComponent, MainMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent } from \"../components/gui\";\nimport { combineLatest, Subscription } from \"rxjs\";\nimport { PrebuiltGui } from \"@rpgjs/common\";\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 * Vue v4 compatibility flag. Prefer attachToSprite in v5 projects.\n */\n rpgAttachToSprite?: boolean;\n}\n\nexport interface 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\ntype GuiState = {\n name: string;\n component: any;\n display: boolean;\n data: any;\n attachToSprite: boolean;\n};\n\ntype VueGuiBridge = {\n updateGuiState?: (state: GuiState) => void;\n initializeGuiStates?: (states: GuiState[]) => void;\n};\n\ninterface GuiAction {\n guiId: string;\n name: string;\n data: any;\n clientActionId: string;\n}\n\ntype OptimisticReducer = (data: any, action: GuiAction) => any;\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\nconst updateItemQuantity = (items: any[], id: string) => {\n const index = items.findIndex((item) => item?.id === id);\n if (index === -1) return items;\n const item = items[index];\n if (item?.usable === false) return items;\n if (item?.consumable === false) return items;\n const quantity = typeof item?.quantity === \"number\" ? item.quantity : 1;\n const nextQuantity = Math.max(0, quantity - 1);\n if (nextQuantity === quantity) return items;\n if (nextQuantity <= 0) {\n return items.filter((_, idx) => idx !== index);\n }\n const nextItems = items.slice();\n nextItems[index] = { ...item, quantity: nextQuantity };\n return nextItems;\n};\n\nconst updateEquippedFlag = (items: any[], id: string, equip: boolean) => {\n const index = items.findIndex((item) => item?.id === id);\n if (index === -1) return items;\n const item = items[index];\n if (item?.equipped === equip) return items;\n const nextItems = items.slice();\n nextItems[index] = { ...item, equipped: equip };\n return nextItems;\n};\n\nconst mainMenuOptimisticReducer: OptimisticReducer = (data, action) => {\n if (!data || typeof data !== \"object\") return data;\n if (action.name === \"useItem\") {\n if (!Array.isArray(data.items)) return data;\n const id = action.data?.id;\n if (!id) return data;\n const nextItems = updateItemQuantity(data.items, id);\n if (nextItems === data.items) return data;\n return { ...data, items: nextItems };\n }\n if (action.name === \"equipItem\") {\n const id = action.data?.id;\n if (!id || typeof action.data?.equip !== \"boolean\") return data;\n const equip = action.data.equip;\n let nextItems = data.items;\n let nextEquips = data.equips;\n if (Array.isArray(data.items)) {\n nextItems = updateEquippedFlag(data.items, id, equip);\n }\n if (Array.isArray(data.equips)) {\n nextEquips = updateEquippedFlag(data.equips, id, equip);\n }\n if (nextItems === data.items && nextEquips === data.equips) return data;\n return {\n ...data,\n ...(nextItems !== data.items ? { items: nextItems } : {}),\n ...(nextEquips !== data.equips ? { equips: nextEquips } : {})\n };\n }\n return data;\n};\n\nexport class RpgGui {\n private webSocket: AbstractWebsocket;\n gui = signal<Record<string, GuiInstance>>({});\n extraGuis: GuiInstance[] = [];\n private vueGuiInstance: VueGuiBridge | null = null;\n private optimisticReducers = new Map<string, OptimisticReducer[]>();\n private pendingActions = new Map<string, GuiAction[]>();\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 this.add({\n name: PrebuiltGui.MainMenu,\n component: MainMenuComponent,\n });\n this.add({\n name: PrebuiltGui.Shop,\n component: ShopComponent,\n });\n this.add({\n name: PrebuiltGui.Notification,\n component: NotificationComponent,\n autoDisplay: true,\n });\n this.add({\n name: PrebuiltGui.Save,\n component: SaveLoadComponent,\n });\n this.add({\n name: PrebuiltGui.TitleScreen,\n component: TitleScreenComponent,\n });\n this.add({\n name: PrebuiltGui.Gameover,\n component: GameoverComponent,\n });\n\n this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);\n }\n\n async _initialize() {\n this.webSocket.on(\"gui.open\", (data: { guiId: string; data: any }) => {\n this.clearPendingActions(data.guiId);\n this.display(data.guiId, data.data);\n });\n\n this.webSocket.on(\"gui.exit\", (guiId: string) => {\n this.hide(guiId);\n });\n\n this.webSocket.on(\"gui.update\", (payload: { guiId: string; data: any; clientActionId?: string }) => {\n this.applyServerUpdate(payload.guiId, payload.data, payload.clientActionId);\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 this._initializeVueComponents();\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 const extraGui = this.extraGuis.find(gui => gui.name === guiId);\n if (!extraGui) return;\n this.vueGuiInstance?.updateGuiState?.(this.toGuiState(extraGui, display, data));\n }\n\n /**\n * Initialize Vue components in the VueGui instance\n * This should be called after VueGui is mounted\n */\n _initializeVueComponents() {\n this.vueGuiInstance?.initializeGuiStates?.(\n this.extraGuis.map(gui => this.toGuiState(gui))\n );\n }\n\n guiInteraction(guiId: string, name: string, data: any) {\n const clientActionId = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;\n const actionData = { ...(data || {}), clientActionId };\n this.applyOptimisticAction({\n guiId,\n name,\n data: actionData,\n clientActionId\n });\n this.webSocket.emit(\"gui.interaction\", {\n guiId,\n name,\n data: actionData,\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 | any) {\n const component = this.resolveComponent(gui);\n const guiId = this.resolveGuiId(gui, component);\n if (!guiId) {\n throw new Error(\"GUI must have a name or id\");\n }\n const attachToSprite = this.resolveAttachToSprite(gui, component);\n const guiInstance: GuiInstance = {\n name: guiId,\n component,\n display: signal<boolean>(gui.display || false),\n data: signal<any>(gui.data || {}),\n autoDisplay: gui.autoDisplay || false,\n dependencies: gui.dependencies ? gui.dependencies() : [],\n attachToSprite,\n };\n\n if (this.isVueComponentInstance(guiInstance)) {\n this.removeCanvasGui(guiId);\n const existingIndex = this.extraGuis.findIndex(existing => existing.name === guiId);\n if (existingIndex >= 0) {\n this.extraGuis[existingIndex].subscription?.unsubscribe();\n this.extraGuis[existingIndex] = guiInstance;\n } else {\n this.extraGuis.push(guiInstance);\n }\n\n this._initializeVueComponents();\n \n if (guiInstance.autoDisplay) {\n this.display(guiId, gui.data);\n } else {\n this._notifyVueGui(guiId, guiInstance.display(), guiInstance.data());\n }\n return;\n }\n\n this.removeVueGui(guiId);\n this.gui()[guiId] = guiInstance;\n this._initializeVueComponents();\n\n // Auto display if enabled and it's a CanvasEngine component\n if (guiInstance.autoDisplay && typeof gui.component === 'function') {\n this.display(guiId, gui.data);\n }\n }\n\n registerOptimisticReducer(guiId: string, reducer: OptimisticReducer) {\n const existing = this.optimisticReducers.get(guiId) || [];\n this.optimisticReducers.set(guiId, existing.concat(reducer));\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 return Object.values(this.gui()).filter(gui => gui.attachToSprite === true);\n }\n\n getVueGuis(): GuiInstance[] {\n return [...this.extraGuis];\n }\n\n getAttachedVueGuis(): GuiInstance[] {\n return this.extraGuis.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 isDisplaying(id: string): boolean {\n const guiInstance = this.get(id);\n if (!guiInstance) return false;\n return guiInstance.display();\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 ?? []);\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 * 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 private isVueComponent(id: string) {\n return this.extraGuis.some(gui => gui.name === id);\n }\n\n private isVueComponentInstance(gui: GuiInstance) {\n return typeof gui.component !== \"function\";\n }\n\n private removeCanvasGui(guiId: string) {\n const current = this.gui();\n if (!(guiId in current)) return;\n const next = { ...current };\n delete next[guiId];\n this.gui.set(next);\n }\n\n private removeVueGui(guiId: string) {\n const removed = this.extraGuis.filter(existing => existing.name === guiId);\n removed.forEach(gui => gui.subscription?.unsubscribe());\n if (removed.length > 0) {\n this.extraGuis = this.extraGuis.filter(existing => existing.name !== guiId);\n }\n }\n\n private resolveComponent(gui: GuiOptions | any) {\n return gui?.component ?? gui;\n }\n\n private resolveGuiId(gui: GuiOptions | any, component: any) {\n return gui?.name || gui?.id || component?.name || component?.__name;\n }\n\n private resolveAttachToSprite(gui: GuiOptions | any, component: any) {\n return !!(gui?.attachToSprite || gui?.rpgAttachToSprite || component?.attachToSprite || component?.rpgAttachToSprite);\n }\n\n private toGuiState(gui: GuiInstance, display = gui.display(), data = gui.data()): GuiState {\n return {\n name: gui.name,\n component: gui.component,\n display,\n data,\n attachToSprite: gui.attachToSprite || false,\n };\n }\n\n private clearPendingActions(guiId: string) {\n this.pendingActions.delete(guiId);\n }\n\n private applyReducers(guiId: string, data: any, actions: GuiAction[]) {\n const reducers = this.optimisticReducers.get(guiId);\n if (!reducers || reducers.length === 0) return data;\n let next = data;\n for (const action of actions) {\n for (const reducer of reducers) {\n const updated = reducer(next, action);\n if (updated !== undefined && updated !== null && updated !== next) {\n next = updated;\n }\n }\n }\n return next;\n }\n\n private applyOptimisticAction(action: GuiAction) {\n const guiInstance = this.get(action.guiId);\n if (!guiInstance) return;\n const reducers = this.optimisticReducers.get(action.guiId);\n if (!reducers || reducers.length === 0) return;\n const currentData = guiInstance.data();\n const nextData = this.applyReducers(action.guiId, currentData, [action]);\n if (nextData === currentData) return;\n guiInstance.data.set(nextData);\n const pending = this.pendingActions.get(action.guiId) || [];\n pending.push(action);\n this.pendingActions.set(action.guiId, pending);\n if (this.isVueComponent(action.guiId)) {\n this._notifyVueGui(action.guiId, guiInstance.display(), nextData);\n }\n }\n\n private applyServerUpdate(guiId: string, data: any, clientActionId?: string) {\n const guiInstance = this.get(guiId);\n if (!guiInstance) return;\n let pending = this.pendingActions.get(guiId) || [];\n if (clientActionId) {\n pending = pending.filter(action => action.clientActionId !== clientActionId);\n } else {\n pending = [];\n }\n let nextData = data;\n if (pending.length) {\n nextData = this.applyReducers(guiId, nextData, pending);\n }\n guiInstance.data.set(nextData);\n this.pendingActions.set(guiId, pending);\n if (this.isVueComponent(guiId)) {\n this._notifyVueGui(guiId, guiInstance.display(), nextData);\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ export type NotificationType = "info" | "warn" | "error";
2
+ export interface NotificationPayload {
3
+ message: string;
4
+ type?: NotificationType;
5
+ icon?: string;
6
+ time?: number;
7
+ sound?: string;
8
+ }
9
+ export interface NotificationItem extends NotificationPayload {
10
+ id: number;
11
+ opacity: any;
12
+ offset: any;
13
+ layoutY: any;
14
+ removing: boolean;
15
+ }
16
+ export declare class NotificationManager {
17
+ stack: import('canvasengine').WritableArraySignal<NotificationItem[]>;
18
+ private _counter;
19
+ add(payload: NotificationPayload, engine?: {
20
+ playSound?: (id: string) => void;
21
+ }): void;
22
+ remove(id: number): void;
23
+ }
@@ -0,0 +1,49 @@
1
+ import { animatedSignal, signal } from "canvasengine";
2
+ //#region src/Gui/NotificationManager.ts
3
+ var DEFAULT_DURATION = 220;
4
+ var NotificationManager = class {
5
+ constructor() {
6
+ this.stack = signal([]);
7
+ this._counter = 0;
8
+ }
9
+ add(payload, engine) {
10
+ const id = ++this._counter;
11
+ const opacity = animatedSignal(0, { duration: DEFAULT_DURATION });
12
+ const offset = animatedSignal(12, { duration: DEFAULT_DURATION });
13
+ const layoutY = animatedSignal(0, { duration: DEFAULT_DURATION });
14
+ const item = {
15
+ id,
16
+ message: payload.message,
17
+ type: payload.type || "info",
18
+ icon: payload.icon,
19
+ time: payload.time,
20
+ sound: payload.sound,
21
+ opacity,
22
+ offset,
23
+ layoutY,
24
+ removing: false
25
+ };
26
+ this.stack.update((list) => [...list, item]);
27
+ opacity.set(1);
28
+ offset.set(0);
29
+ if (payload.sound && engine?.playSound) engine.playSound(payload.sound);
30
+ const delay = typeof payload.time === "number" ? payload.time : 2e3;
31
+ setTimeout(() => {
32
+ this.remove(id);
33
+ }, delay);
34
+ }
35
+ remove(id) {
36
+ const item = this.stack().find((it) => it.id === id);
37
+ if (!item || item.removing) return;
38
+ item.removing = true;
39
+ item.opacity.set(0);
40
+ item.offset.set(-8);
41
+ setTimeout(() => {
42
+ this.stack.update((items) => items.filter((it) => it.id !== id));
43
+ }, DEFAULT_DURATION);
44
+ }
45
+ };
46
+ //#endregion
47
+ export { NotificationManager };
48
+
49
+ //# sourceMappingURL=NotificationManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationManager.js","names":[],"sources":["../../src/Gui/NotificationManager.ts"],"sourcesContent":["import { signal, animatedSignal } from \"canvasengine\";\n\nexport type NotificationType = \"info\" | \"warn\" | \"error\";\n\nexport interface NotificationPayload {\n message: string;\n type?: NotificationType;\n icon?: string;\n time?: number;\n sound?: string;\n}\n\nexport interface NotificationItem extends NotificationPayload {\n id: number;\n opacity: any;\n offset: any;\n layoutY: any;\n removing: boolean;\n}\n\nconst DEFAULT_DURATION = 220;\n\nexport class NotificationManager {\n stack = signal<NotificationItem[]>([]);\n private _counter = 0;\n\n add(payload: NotificationPayload, engine?: { playSound?: (id: string) => void }) {\n const id = ++this._counter;\n const opacity = animatedSignal(0, { duration: DEFAULT_DURATION });\n const offset = animatedSignal(12, { duration: DEFAULT_DURATION });\n const layoutY = animatedSignal(0, { duration: DEFAULT_DURATION });\n const item: NotificationItem = {\n id,\n message: payload.message,\n type: payload.type || \"info\",\n icon: payload.icon,\n time: payload.time,\n sound: payload.sound,\n opacity,\n offset,\n layoutY,\n removing: false,\n };\n this.stack.update((list) => [...list, item]);\n opacity.set(1);\n offset.set(0);\n\n if (payload.sound && engine?.playSound) {\n engine.playSound(payload.sound);\n }\n\n const delay = typeof payload.time === \"number\" ? payload.time : 2000;\n setTimeout(() => {\n this.remove(id);\n }, delay);\n }\n\n remove(id: number) {\n const list = this.stack();\n const item = list.find((it) => it.id === id);\n if (!item || item.removing) return;\n item.removing = true;\n item.opacity.set(0);\n item.offset.set(-8);\n setTimeout(() => {\n this.stack.update((items) => items.filter((it) => it.id !== id));\n }, DEFAULT_DURATION);\n }\n}\n"],"mappings":";;AAoBA,IAAM,mBAAmB;AAEzB,IAAa,sBAAb,MAAiC;;eACvB,OAA2B,CAAC,CAAC;kBAClB;;CAEnB,IAAI,SAA8B,QAA+C;EAC/E,MAAM,KAAK,EAAE,KAAK;EAClB,MAAM,UAAU,eAAe,GAAG,EAAE,UAAU,iBAAiB,CAAC;EAChE,MAAM,SAAS,eAAe,IAAI,EAAE,UAAU,iBAAiB,CAAC;EAChE,MAAM,UAAU,eAAe,GAAG,EAAE,UAAU,iBAAiB,CAAC;EAChE,MAAM,OAAyB;GAC7B;GACA,SAAS,QAAQ;GACjB,MAAM,QAAQ,QAAQ;GACtB,MAAM,QAAQ;GACd,MAAM,QAAQ;GACd,OAAO,QAAQ;GACf;GACA;GACA;GACA,UAAU;EACZ;EACA,KAAK,MAAM,QAAQ,SAAS,CAAC,GAAG,MAAM,IAAI,CAAC;EAC3C,QAAQ,IAAI,CAAC;EACb,OAAO,IAAI,CAAC;EAEZ,IAAI,QAAQ,SAAS,QAAQ,WAC3B,OAAO,UAAU,QAAQ,KAAK;EAGhC,MAAM,QAAQ,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;EAChE,iBAAiB;GACf,KAAK,OAAO,EAAE;EAChB,GAAG,KAAK;CACV;CAEA,OAAO,IAAY;EAEjB,MAAM,OADO,KAAK,MACL,EAAK,MAAM,OAAO,GAAG,OAAO,EAAE;EAC3C,IAAI,CAAC,QAAQ,KAAK,UAAU;EAC5B,KAAK,WAAW;EAChB,KAAK,QAAQ,IAAI,CAAC;EAClB,KAAK,OAAO,IAAI,EAAE;EAClB,iBAAiB;GACf,KAAK,MAAM,QAAQ,UAAU,MAAM,QAAQ,OAAO,GAAG,OAAO,EAAE,CAAC;EACjE,GAAG,gBAAgB;CACrB;AACF"}