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

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 (325) hide show
  1. package/CHANGELOG.md +130 -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 +132 -57
  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 +191 -19
  36. package/dist/RpgClientEngine.js +693 -74
  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 +748 -249
  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.d.ts +51 -2
  90. package/dist/components/gui/mobile/index.js +14 -6
  91. package/dist/components/gui/mobile/index.js.map +1 -1
  92. package/dist/components/gui/mobile/index.spec.d.ts +1 -0
  93. package/dist/components/gui/mobile/mobile.ce.js +309 -59
  94. package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
  95. package/dist/components/gui/notification/notification.ce.js +28 -26
  96. package/dist/components/gui/notification/notification.ce.js.map +1 -1
  97. package/dist/components/gui/save-load.ce.js +81 -256
  98. package/dist/components/gui/save-load.ce.js.map +1 -1
  99. package/dist/components/gui/shop/shop.ce.js +107 -142
  100. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  101. package/dist/components/gui/title-screen.ce.js +50 -73
  102. package/dist/components/gui/title-screen.ce.js.map +1 -1
  103. package/dist/components/index.d.ts +2 -1
  104. package/dist/components/index.js +1 -0
  105. package/dist/components/interaction-components.ce.js +22 -0
  106. package/dist/components/interaction-components.ce.js.map +1 -0
  107. package/dist/components/player-components-utils.d.ts +67 -0
  108. package/dist/components/player-components-utils.js +162 -0
  109. package/dist/components/player-components-utils.js.map +1 -0
  110. package/dist/components/player-components-utils.spec.d.ts +1 -0
  111. package/dist/components/player-components.ce.js +191 -0
  112. package/dist/components/player-components.ce.js.map +1 -0
  113. package/dist/components/prebuilt/hp-bar.ce.js +45 -45
  114. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
  115. package/dist/components/prebuilt/light-halo.ce.js +39 -60
  116. package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
  117. package/dist/components/scenes/canvas.ce.js +205 -27
  118. package/dist/components/scenes/canvas.ce.js.map +1 -1
  119. package/dist/components/scenes/draw-map.ce.js +39 -39
  120. package/dist/components/scenes/draw-map.ce.js.map +1 -1
  121. package/dist/components/scenes/event-layer.ce.js +51 -10
  122. package/dist/components/scenes/event-layer.ce.js.map +1 -1
  123. package/dist/core/inject.js +1 -1
  124. package/dist/core/inject.js.map +1 -1
  125. package/dist/core/setup.js +1 -1
  126. package/dist/core/setup.js.map +1 -1
  127. package/dist/decorators/spritesheet.d.ts +1 -0
  128. package/dist/decorators/spritesheet.js +11 -0
  129. package/dist/decorators/spritesheet.js.map +1 -0
  130. package/dist/i18n.d.ts +55 -0
  131. package/dist/i18n.js +60 -0
  132. package/dist/i18n.js.map +1 -0
  133. package/dist/i18n.spec.d.ts +1 -0
  134. package/dist/index.d.ts +8 -0
  135. package/dist/index.js +29 -21
  136. package/dist/module.js +45 -4
  137. package/dist/module.js.map +1 -1
  138. package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@3.1.0}/node_modules/@signe/di/dist/index.js +7 -117
  139. package/dist/node_modules/.pnpm/@signe_di@3.1.0/node_modules/@signe/di/dist/index.js.map +1 -0
  140. package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js +239 -0
  141. package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
  142. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  143. 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
  144. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js +698 -0
  145. package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js.map +1 -0
  146. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js +43 -0
  147. 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
  148. 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
  149. package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/index.js.map +1 -0
  150. 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
  151. package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js.map +1 -0
  152. 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
  153. package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js.map +1 -0
  154. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js +13 -0
  155. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js.map +1 -0
  156. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js +106 -0
  157. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js.map +1 -0
  158. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js +13 -0
  159. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js.map +1 -0
  160. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js +121 -0
  161. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js.map +1 -0
  162. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js +10 -0
  163. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js.map +1 -0
  164. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js +110 -0
  165. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js.map +1 -0
  166. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js +99 -0
  167. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js.map +1 -0
  168. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js +82 -0
  169. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js.map +1 -0
  170. 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
  171. package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js.map +1 -0
  172. package/dist/presets/animation.js.map +1 -1
  173. package/dist/presets/faceset.js.map +1 -1
  174. package/dist/presets/icon.js.map +1 -1
  175. package/dist/presets/index.js.map +1 -1
  176. package/dist/presets/lpc.js.map +1 -1
  177. package/dist/presets/rmspritesheet.js.map +1 -1
  178. package/dist/services/AbstractSocket.d.ts +2 -0
  179. package/dist/services/AbstractSocket.js.map +1 -1
  180. package/dist/services/actionInput.d.ts +14 -0
  181. package/dist/services/actionInput.js +59 -0
  182. package/dist/services/actionInput.js.map +1 -0
  183. package/dist/services/actionInput.spec.d.ts +1 -0
  184. package/dist/services/cameraFollow.d.ts +51 -0
  185. package/dist/services/cameraFollow.js +134 -0
  186. package/dist/services/cameraFollow.js.map +1 -0
  187. package/dist/services/cameraFollow.spec.d.ts +1 -0
  188. package/dist/services/interactions.d.ts +159 -0
  189. package/dist/services/interactions.js +460 -0
  190. package/dist/services/interactions.js.map +1 -0
  191. package/dist/services/interactions.spec.d.ts +1 -0
  192. package/dist/services/keyboardControls.d.ts +1 -0
  193. package/dist/services/keyboardControls.js +1 -0
  194. package/dist/services/keyboardControls.js.map +1 -1
  195. package/dist/services/loadMap.d.ts +9 -0
  196. package/dist/services/loadMap.js +1 -1
  197. package/dist/services/loadMap.js.map +1 -1
  198. package/dist/services/mmorpg-connection.d.ts +5 -0
  199. package/dist/services/mmorpg-connection.js +50 -0
  200. package/dist/services/mmorpg-connection.js.map +1 -0
  201. package/dist/services/mmorpg-connection.spec.d.ts +1 -0
  202. package/dist/services/mmorpg.d.ts +11 -4
  203. package/dist/services/mmorpg.js +57 -33
  204. package/dist/services/mmorpg.js.map +1 -1
  205. package/dist/services/pointerContext.d.ts +11 -0
  206. package/dist/services/pointerContext.js +48 -0
  207. package/dist/services/pointerContext.js.map +1 -0
  208. package/dist/services/pointerContext.spec.d.ts +1 -0
  209. package/dist/services/save.js.map +1 -1
  210. package/dist/services/save.spec.d.ts +1 -0
  211. package/dist/services/standalone-message.d.ts +1 -0
  212. package/dist/services/standalone-message.js +9 -0
  213. package/dist/services/standalone-message.js.map +1 -0
  214. package/dist/services/standalone.d.ts +4 -1
  215. package/dist/services/standalone.js +36 -16
  216. package/dist/services/standalone.js.map +1 -1
  217. package/dist/services/standalone.spec.d.ts +1 -0
  218. package/dist/utils/getEntityProp.js +4 -3
  219. package/dist/utils/getEntityProp.js.map +1 -1
  220. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  221. package/dist/utils/mapId.d.ts +1 -0
  222. package/dist/utils/mapId.js +6 -0
  223. package/dist/utils/mapId.js.map +1 -0
  224. package/dist/utils/readPropValue.d.ts +2 -0
  225. package/dist/utils/readPropValue.js +13 -0
  226. package/dist/utils/readPropValue.js.map +1 -0
  227. package/package.json +13 -13
  228. package/src/Game/AnimationManager.spec.ts +30 -0
  229. package/src/Game/AnimationManager.ts +26 -10
  230. package/src/Game/ClientVisuals.spec.ts +56 -0
  231. package/src/Game/ClientVisuals.ts +184 -0
  232. package/src/Game/EventComponentResolver.spec.ts +84 -0
  233. package/src/Game/EventComponentResolver.ts +74 -0
  234. package/src/Game/Map.ts +134 -2
  235. package/src/Game/Object.spec.ts +59 -0
  236. package/src/Game/Object.ts +181 -77
  237. package/src/Game/ProjectileManager.spec.ts +449 -0
  238. package/src/Game/ProjectileManager.ts +346 -0
  239. package/src/Gui/Gui.spec.ts +359 -0
  240. package/src/Gui/Gui.ts +178 -67
  241. package/src/Resource.ts +1 -2
  242. package/src/RpgClient.ts +220 -17
  243. package/src/RpgClientEngine.ts +995 -133
  244. package/src/components/animations/fx.ce +101 -0
  245. package/src/components/animations/index.ts +4 -2
  246. package/src/components/character.ce +839 -45
  247. package/src/components/dynamics/bar.ce +88 -0
  248. package/src/components/dynamics/image.ce +21 -0
  249. package/src/components/dynamics/parse-value.spec.ts +83 -0
  250. package/src/components/dynamics/parse-value.ts +111 -37
  251. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  252. package/src/components/dynamics/shape-utils.ts +61 -0
  253. package/src/components/dynamics/shape.ce +90 -0
  254. package/src/components/dynamics/text.ce +35 -149
  255. package/src/components/gui/dialogbox/index.ce +52 -21
  256. package/src/components/gui/gameover.ce +6 -4
  257. package/src/components/gui/menu/equip-menu.ce +11 -9
  258. package/src/components/gui/menu/exit-menu.ce +6 -4
  259. package/src/components/gui/menu/items-menu.ce +11 -9
  260. package/src/components/gui/menu/main-menu.ce +14 -12
  261. package/src/components/gui/menu/options-menu.ce +4 -3
  262. package/src/components/gui/menu/skills-menu.ce +2 -1
  263. package/src/components/gui/mobile/index.spec.ts +94 -0
  264. package/src/components/gui/mobile/index.ts +74 -6
  265. package/src/components/gui/mobile/mobile.ce +347 -65
  266. package/src/components/gui/notification/notification.ce +7 -1
  267. package/src/components/gui/save-load.ce +13 -11
  268. package/src/components/gui/shop/shop.ce +20 -18
  269. package/src/components/gui/title-screen.ce +6 -4
  270. package/src/components/index.ts +2 -1
  271. package/src/components/interaction-components.ce +23 -0
  272. package/src/components/player-components-utils.spec.ts +109 -0
  273. package/src/components/player-components-utils.ts +205 -0
  274. package/src/components/player-components.ce +222 -0
  275. package/src/components/prebuilt/hp-bar.ce +4 -3
  276. package/src/components/prebuilt/light-halo.ce +2 -2
  277. package/src/components/scenes/canvas.ce +219 -15
  278. package/src/components/scenes/draw-map.ce +34 -22
  279. package/src/components/scenes/event-layer.ce +55 -4
  280. package/src/core/setup.ts +2 -2
  281. package/src/decorators/spritesheet.ts +8 -0
  282. package/src/i18n.spec.ts +39 -0
  283. package/src/i18n.ts +59 -0
  284. package/src/index.ts +19 -0
  285. package/src/module.ts +61 -11
  286. package/src/services/AbstractSocket.ts +3 -0
  287. package/src/services/actionInput.spec.ts +155 -0
  288. package/src/services/actionInput.ts +120 -0
  289. package/src/services/cameraFollow.spec.ts +220 -0
  290. package/src/services/cameraFollow.ts +222 -0
  291. package/src/services/interactions.spec.ts +175 -0
  292. package/src/services/interactions.ts +722 -0
  293. package/src/services/keyboardControls.ts +2 -1
  294. package/src/services/loadMap.ts +5 -1
  295. package/src/services/mmorpg-connection.spec.ts +99 -0
  296. package/src/services/mmorpg-connection.ts +69 -0
  297. package/src/services/mmorpg.ts +70 -36
  298. package/src/services/pointerContext.spec.ts +36 -0
  299. package/src/services/pointerContext.ts +84 -0
  300. package/src/services/save.spec.ts +127 -0
  301. package/src/services/standalone-message.ts +7 -0
  302. package/src/services/standalone.spec.ts +54 -0
  303. package/src/services/standalone.ts +44 -12
  304. package/src/utils/getEntityProp.spec.ts +96 -0
  305. package/src/utils/getEntityProp.ts +4 -3
  306. package/src/utils/mapId.ts +2 -0
  307. package/src/utils/readPropValue.ts +16 -0
  308. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +0 -1
  309. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js +0 -457
  310. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js.map +0 -1
  311. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +0 -463
  312. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
  313. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +0 -2191
  314. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +0 -1
  315. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +0 -10
  316. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +0 -1
  317. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +0 -91
  318. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
  319. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +0 -1
  320. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +0 -14
  321. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +0 -1
  322. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +0 -1
  323. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +0 -1
  324. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +0 -2
  325. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +0 -1
package/src/Game/Map.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import {
2
2
  RpgCommonMap,
3
+ cloneLightingState,
4
+ normalizeLightingState,
5
+ type LightSpot,
6
+ type LightingState,
3
7
  type WeatherState,
4
8
  type MapPhysicsInitContext,
5
9
  type MapPhysicsEntityContext,
@@ -11,6 +15,43 @@ import { RpgClientEvent } from "./Event";
11
15
  import { RpgClientEngine } from "../RpgClientEngine";
12
16
  import { inject } from "../core/inject";
13
17
 
18
+ type TestGlobalScope = typeof globalThis & {
19
+ process?: {
20
+ env?: {
21
+ TEST?: string;
22
+ };
23
+ };
24
+ __RPGJS_TEST__?: boolean;
25
+ };
26
+
27
+ const lightingColorsEqual = (
28
+ left: LightSpot["color"],
29
+ right: LightSpot["color"],
30
+ ): boolean => {
31
+ if (Array.isArray(left) || Array.isArray(right)) {
32
+ return Array.isArray(left)
33
+ && Array.isArray(right)
34
+ && left.length === right.length
35
+ && left.every((value, index) => value === right[index]);
36
+ }
37
+ return left === right;
38
+ };
39
+
40
+ const lightSpotsEqual = (left: LightSpot | undefined, right: LightSpot): boolean => {
41
+ if (!left) return false;
42
+ return left.id === right.id
43
+ && left.x === right.x
44
+ && left.y === right.y
45
+ && left.radius === right.radius
46
+ && left.intensity === right.intensity
47
+ && lightingColorsEqual(left.color, right.color)
48
+ && left.flicker === right.flicker
49
+ && left.flickerSpeed === right.flickerSpeed
50
+ && left.pulse === right.pulse
51
+ && left.pulseSpeed === right.pulseSpeed
52
+ && left.phase === right.phase;
53
+ };
54
+
14
55
  export class RpgClientMap extends RpgCommonMap<any> {
15
56
  engine: RpgClientEngine = inject(RpgClientEngine)
16
57
  @users(RpgClientPlayer) players = signal<Record<string, RpgClientPlayer>>({});
@@ -18,19 +59,43 @@ export class RpgClientMap extends RpgCommonMap<any> {
18
59
  currentPlayer = computed(() => this.players()[this.engine.playerIdSignal()!])
19
60
  weatherState = signal<WeatherState | null>(null);
20
61
  localWeatherOverride = signal<WeatherState | null>(null);
62
+ lightingState = signal<LightingState | null>(null);
63
+ localLightSpots = signal<Record<string, LightSpot>>({});
21
64
  weather = computed<WeatherState | null>(() => {
22
65
  const local = this.localWeatherOverride()
23
66
  const state = this.weatherState()
24
67
  return local ?? state
25
68
  });
69
+ lighting = computed<LightingState | null>(() => {
70
+ const state = cloneLightingState(this.lightingState());
71
+ const localSpots = Object.entries(this.localLightSpots()).map(([id, spot]) => ({
72
+ ...spot,
73
+ id: spot.id ?? id,
74
+ }));
75
+
76
+ if (!state && localSpots.length === 0) {
77
+ return null;
78
+ }
79
+
80
+ const next: LightingState = { ...(state ?? {}) };
81
+ if (!state?.ambient) {
82
+ delete next.ambient;
83
+ }
84
+ next.spots = [
85
+ ...(state?.spots ?? []),
86
+ ...localSpots,
87
+ ];
88
+ return next;
89
+ });
26
90
  private manualClientPhysicsTick = false;
27
91
  private readonly isTestEnvironment: boolean;
28
92
 
29
93
  constructor() {
30
94
  super();
31
95
  // Détecter l'environnement de test
32
- const isTest = (typeof process !== 'undefined' && process.env?.TEST === 'true')
33
- || (typeof window !== 'undefined' && (window as any).__RPGJS_TEST__ === true);
96
+ const testGlobal = globalThis as TestGlobalScope;
97
+ const isTest = testGlobal.process?.env?.TEST === 'true'
98
+ || testGlobal.__RPGJS_TEST__ === true;
34
99
  this.isTestEnvironment = isTest;
35
100
  if (isTest) {
36
101
  this.autoTickEnabled = false;
@@ -51,6 +116,16 @@ export class RpgClientMap extends RpgCommonMap<any> {
51
116
  const currentPlayer = !force && currentPlayerId
52
117
  ? this.players()[currentPlayerId]
53
118
  : undefined;
119
+ const players = this.players();
120
+ const events = this.events();
121
+
122
+ Object.entries(players).forEach(([id, player]) => {
123
+ if (!player || (!force && id === currentPlayerId)) return;
124
+ (player as any).resetAnimationState?.();
125
+ });
126
+ Object.values(events).forEach((event) => {
127
+ (event as any)?.resetAnimationState?.();
128
+ });
54
129
 
55
130
  this.players.set(
56
131
  currentPlayerId && currentPlayer ? { [currentPlayerId]: currentPlayer } : {}
@@ -58,6 +133,8 @@ export class RpgClientMap extends RpgCommonMap<any> {
58
133
  this.events.set({})
59
134
  this.weatherState.set(null);
60
135
  this.localWeatherOverride.set(null);
136
+ this.lightingState.set(null);
137
+ this.localLightSpots.set({});
61
138
  this.clearPhysic()
62
139
  }
63
140
 
@@ -73,6 +150,61 @@ export class RpgClientMap extends RpgCommonMap<any> {
73
150
  this.localWeatherOverride.set(null);
74
151
  }
75
152
 
153
+ getLighting(): LightingState | null {
154
+ return this.lighting();
155
+ }
156
+
157
+ addLightSpot(id: string, spot: LightSpot): void {
158
+ const normalized = normalizeLightingState({ spots: [{ ...spot, id }] });
159
+ const nextSpot = normalized?.spots?.[0];
160
+ if (!nextSpot) {
161
+ return;
162
+ }
163
+ this.localLightSpots.update((spots) => {
164
+ if (lightSpotsEqual(spots[id], nextSpot)) {
165
+ return spots;
166
+ }
167
+ return {
168
+ ...spots,
169
+ [id]: nextSpot,
170
+ };
171
+ });
172
+ }
173
+
174
+ patchLightSpot(id: string, patch: Partial<LightSpot>): void {
175
+ this.localLightSpots.update((spots) => {
176
+ const current = spots[id];
177
+ if (!current) {
178
+ return spots;
179
+ }
180
+ return {
181
+ ...spots,
182
+ [id]: {
183
+ ...current,
184
+ ...patch,
185
+ id,
186
+ x: patch.x ?? current.x,
187
+ y: patch.y ?? current.y,
188
+ },
189
+ };
190
+ });
191
+ }
192
+
193
+ removeLightSpot(id: string): void {
194
+ this.localLightSpots.update((spots) => {
195
+ if (!(id in spots)) {
196
+ return spots;
197
+ }
198
+ const next = { ...spots };
199
+ delete next[id];
200
+ return next;
201
+ });
202
+ }
203
+
204
+ clearLightSpots(): void {
205
+ this.localLightSpots.set({});
206
+ }
207
+
76
208
  stepClientPhysics(deltaMs: number): number {
77
209
  if (!this.manualClientPhysicsTick) {
78
210
  return 0;
@@ -0,0 +1,59 @@
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import { signal } from "canvasengine";
3
+ import { appendFramePayload, RpgClientObject, withGraphicDisplayScale } from "./Object";
4
+
5
+ vi.mock("../RpgClientEngine", () => ({
6
+ RpgClientEngine: class RpgClientEngine {},
7
+ }));
8
+
9
+ vi.mock("../core/inject", () => ({
10
+ inject: () => ({}),
11
+ }));
12
+
13
+ function createObject() {
14
+ const object = Object.create(RpgClientObject.prototype) as RpgClientObject;
15
+ object.animationName = signal("stand");
16
+ object.graphics = signal(["hero"]) as any;
17
+ object.animationCurrentIndex = signal(0);
18
+ object.animationIsPlaying = signal(false);
19
+ return object;
20
+ }
21
+
22
+ describe("RpgClientObject animations", () => {
23
+ test("accepts a single frame payload without requiring iterable spread", () => {
24
+ expect(
25
+ appendFramePayload({ stale: true }, { x: 10, y: 20, ts: 1 }),
26
+ ).toEqual([{ x: 10, y: 20, ts: 1 }]);
27
+ });
28
+
29
+ test("keeps instance scale outside the spritesheet transform scale", () => {
30
+ expect(withGraphicDisplayScale({ id: "hero" }, 0.5)).toEqual({
31
+ id: "hero",
32
+ displayScale: 0.5,
33
+ });
34
+ });
35
+
36
+ test("marks temporary animation as finished before restoring locomotion animation", async () => {
37
+ const object = createObject();
38
+ const animationChanges: Array<{ name: string; isPlaying: boolean }> = [];
39
+
40
+ object.animationName.observable.subscribe((name) => {
41
+ animationChanges.push({
42
+ name,
43
+ isPlaying: object.animationIsPlaying(),
44
+ });
45
+ });
46
+
47
+ const done = object.setAnimation("attack", 1, { timeoutMs: 10000 });
48
+ object.animationCurrentIndex.set(1);
49
+
50
+ await done;
51
+
52
+ expect(object.animationName()).toBe("stand");
53
+ expect(object.animationIsPlaying()).toBe(false);
54
+ expect(animationChanges).toContainEqual({
55
+ name: "stand",
56
+ isPlaying: false,
57
+ });
58
+ });
59
+ });
@@ -1,15 +1,51 @@
1
1
  import { Hooks, ModulesToken, RpgCommonPlayer } from "@rpgjs/common";
2
- import { trigger, signal, effect } from "canvasengine";
3
- import { filter, from, map, Subscription, switchMap } from "rxjs";
2
+ import { trigger, signal, type Trigger } from "canvasengine";
3
+ import { combineLatest, from, map, of, startWith, Subscription, switchMap } from "rxjs";
4
4
  import { inject } from "../core/inject";
5
5
  import { RpgClientEngine } from "../RpgClientEngine";
6
- import TextComponent from "../components/dynamics/text.ce";
6
+ type Frame = { x: number; y: number; ts: number };
7
7
 
8
- const DYNAMIC_COMPONENTS = {
9
- text: TextComponent,
10
- }
8
+ type AnimationRestoreOptions = {
9
+ restoreAnimationName?: string;
10
+ restoreGraphics?: any[];
11
+ timeoutMs?: number;
12
+ };
11
13
 
12
- type Frame = { x: number; y: number; ts: number };
14
+ type FlashType = 'alpha' | 'tint' | 'both';
15
+
16
+ type FlashOptions = {
17
+ type?: FlashType;
18
+ duration?: number;
19
+ cycles?: number;
20
+ alpha?: number;
21
+ tint?: number | string;
22
+ };
23
+
24
+ type FlashTriggerOptions = Omit<FlashOptions, "tint"> & {
25
+ tint: number;
26
+ };
27
+
28
+ type ConfigurableTrigger<T> = Omit<Trigger<T>, "start"> & {
29
+ start(config?: T): Promise<void>;
30
+ };
31
+
32
+ export const withGraphicDisplayScale = (spritesheet: any, scale: unknown): any => {
33
+ if (!spritesheet || typeof spritesheet !== "object") return spritesheet;
34
+ if (scale === undefined || scale === null) return spritesheet;
35
+ return {
36
+ ...spritesheet,
37
+ displayScale: scale,
38
+ };
39
+ };
40
+
41
+ export const appendFramePayload = (current: unknown, items: unknown): Frame[] => {
42
+ const frameItems = Array.isArray(items) ? items : items ? [items] : [];
43
+ const nextFrames = frameItems.flatMap((item): Frame[] =>
44
+ Array.isArray(item) ? item : [item as Frame]
45
+ );
46
+ const currentFrames = Array.isArray(current) ? current as Frame[] : [];
47
+ return currentFrames.concat(nextFrames);
48
+ };
13
49
 
14
50
  export abstract class RpgClientObject extends RpgCommonPlayer {
15
51
  abstract _type: string;
@@ -20,51 +56,45 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
20
56
  _param = signal({});
21
57
  frames: Frame[] = [];
22
58
  graphicsSignals = signal<any[]>([]);
23
- _component = {} // temporary component memory
24
- flashTrigger = trigger();
59
+ flashTrigger: ConfigurableTrigger<FlashTriggerOptions> = trigger<FlashTriggerOptions>();
60
+ private animationRestoreState?: {
61
+ animationName: string;
62
+ graphics: any[];
63
+ };
25
64
 
26
65
  constructor() {
27
66
  super();
67
+ const engine = this.engine;
28
68
  this.hooks.callHooks("client-sprite-onInit", this).subscribe();
29
69
 
30
70
  this._frames.observable.subscribe(({ items }) => {
31
71
  if (!this.id) return;
32
72
  //if (this.id == this.engine.playerIdSignal()!) return;
33
- const nextFrames = items.flatMap((item): Frame[] =>
34
- Array.isArray(item) ? item : [item]
35
- );
36
- this.frames = [...this.frames, ...nextFrames];
73
+ this.frames = appendFramePayload(this.frames, items);
37
74
  });
38
75
 
39
- this.graphics.observable
76
+ const graphics$ = this.graphics.observable.pipe(map(({ items }) => items));
77
+ const graphicScale$ = this._graphicScale.observable.pipe(
78
+ startWith({ value: this._graphicScale() }),
79
+ map((payload: any) => payload?.value ?? payload),
80
+ );
81
+
82
+ combineLatest([graphics$, graphicScale$])
40
83
  .pipe(
41
- map(({ items }) => items),
42
- filter(graphics => graphics.length > 0),
43
- switchMap(graphics => from(Promise.all(graphics.map(graphic => this.engine.getSpriteSheet(graphic)))))
84
+ switchMap(([graphics, scale]) => {
85
+ const graphicRefs = Array.isArray(graphics) ? graphics : [];
86
+ if (graphicRefs.length === 0) return of([]);
87
+ return from(Promise.all(graphicRefs.map(async (graphic) => {
88
+ const spritesheet = await engine.getSpriteSheet(graphic);
89
+ return withGraphicDisplayScale(spritesheet, scale);
90
+ })));
91
+ })
44
92
  )
45
93
  .subscribe((sheets) => {
46
94
  this.graphicsSignals.set(sheets);
47
95
  });
48
96
 
49
- this.componentsTop.observable
50
- .pipe(
51
- filter(value => value !== null && value !== undefined),
52
- map((value) => typeof value === 'string' ? JSON.parse(value) : value),
53
- )
54
- .subscribe(({components}) => {
55
- for (const component of components) {
56
- for (const [key, value] of Object.entries(component)) {
57
- this._component = value as any; // temporary component memory
58
- console.log(value)
59
- const type = (value as any).type as keyof typeof DYNAMIC_COMPONENTS;
60
- if (DYNAMIC_COMPONENTS[type]) {
61
- this.engine.addSpriteComponentInFront(DYNAMIC_COMPONENTS[type]);
62
- }
63
- }
64
- }
65
- });
66
-
67
- this.engine.tick
97
+ engine.tick
68
98
  .pipe
69
99
  //throttleTime(10)
70
100
  ()
@@ -72,7 +102,7 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
72
102
  const frame = this.frames.shift();
73
103
  if (frame) {
74
104
  if (typeof frame.x !== "number" || typeof frame.y !== "number") return;
75
- this.engine.scene.setBodyPosition(
105
+ engine.scene.setBodyPosition(
76
106
  this.id,
77
107
  frame.x,
78
108
  frame.y,
@@ -101,6 +131,38 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
101
131
  }
102
132
 
103
133
  private animationSubscription?: Subscription;
134
+ private animationResetTimeout?: ReturnType<typeof setTimeout>;
135
+ private animationWaitResolve?: () => void;
136
+
137
+ private clearAnimationControls() {
138
+ if (this.animationSubscription) {
139
+ this.animationSubscription.unsubscribe();
140
+ this.animationSubscription = undefined;
141
+ }
142
+ if (this.animationResetTimeout) {
143
+ clearTimeout(this.animationResetTimeout);
144
+ this.animationResetTimeout = undefined;
145
+ }
146
+ }
147
+
148
+ private resolveAnimationWait() {
149
+ const resolve = this.animationWaitResolve;
150
+ this.animationWaitResolve = undefined;
151
+ resolve?.();
152
+ }
153
+
154
+ private finishTemporaryAnimation() {
155
+ const restoreState = this.animationRestoreState;
156
+ this.clearAnimationControls();
157
+ this.animationCurrentIndex.set(0);
158
+ this.animationRestoreState = undefined;
159
+ this.animationIsPlaying.set(false);
160
+ if (restoreState) {
161
+ this.animationName.set(restoreState.animationName);
162
+ this.graphics.set([...restoreState.graphics]);
163
+ }
164
+ this.resolveAnimationWait();
165
+ }
104
166
 
105
167
  /**
106
168
  * Trigger a flash animation on this sprite
@@ -148,13 +210,7 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
148
210
  * });
149
211
  * ```
150
212
  */
151
- flash(options?: {
152
- type?: 'alpha' | 'tint' | 'both';
153
- duration?: number;
154
- cycles?: number;
155
- alpha?: number;
156
- tint?: number | string;
157
- }): void {
213
+ flash(options?: FlashOptions): void {
158
214
  const flashOptions = {
159
215
  type: options?.type || 'alpha',
160
216
  duration: options?.duration ?? 300,
@@ -199,12 +255,14 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
199
255
  * ```
200
256
  */
201
257
  resetAnimationState() {
258
+ if (this.animationRestoreState) {
259
+ this.finishTemporaryAnimation();
260
+ return;
261
+ }
202
262
  this.animationIsPlaying.set(false);
203
263
  this.animationCurrentIndex.set(0);
204
- if (this.animationSubscription) {
205
- this.animationSubscription.unsubscribe();
206
- this.animationSubscription = undefined;
207
- }
264
+ this.clearAnimationControls();
265
+ this.resolveAnimationWait();
208
266
  }
209
267
 
210
268
  /**
@@ -216,17 +274,19 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
216
274
  *
217
275
  * @param animationName - Name of the animation to play
218
276
  * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
277
+ * @param options - Restore and timeout options
278
+ * @returns A promise resolved when a finite animation finishes, is interrupted, or times out
219
279
  *
220
280
  * @example
221
281
  * ```ts
222
282
  * // Play attack animation 3 times
223
- * player.setAnimation('attack', 3);
283
+ * await player.setAnimation('attack', 3);
224
284
  *
225
285
  * // Play continuous spell animation
226
286
  * player.setAnimation('spell');
227
287
  * ```
228
288
  */
229
- setAnimation(animationName: string, nbTimes?: number): void;
289
+ setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;
230
290
  /**
231
291
  * Set a custom animation with temporary graphic change
232
292
  *
@@ -237,37 +297,68 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
237
297
  * @param animationName - Name of the animation to play
238
298
  * @param graphic - The graphic(s) to temporarily use during the animation
239
299
  * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
300
+ * @param options - Restore and timeout options
301
+ * @returns A promise resolved when a finite animation finishes, is interrupted, or times out
240
302
  *
241
303
  * @example
242
304
  * ```ts
243
305
  * // Play attack animation with temporary graphic change
244
- * player.setAnimation('attack', 'hero_attack', 3);
306
+ * await player.setAnimation('attack', 'hero_attack', 3);
245
307
  * ```
246
308
  */
247
- setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number): void;
248
- setAnimation(animationName: string, graphicOrNbTimes?: string | string[] | number, nbTimes?: number): void {
249
- if (this.animationIsPlaying()) return;
250
- this.animationIsPlaying.set(true);
251
- const previousAnimationName = this.animationName();
252
- const previousGraphics = this.graphics();
253
- this.animationCurrentIndex.set(0);
254
-
309
+ setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;
310
+ setAnimation(
311
+ animationName: string,
312
+ graphicOrNbTimes?: string | string[] | number,
313
+ nbTimesOrOptions?: number | AnimationRestoreOptions,
314
+ options?: AnimationRestoreOptions
315
+ ): Promise<void> {
255
316
  let graphic: string | string[] | undefined;
256
317
  let finalNbTimes: number = Infinity;
318
+ let restoreOptions: AnimationRestoreOptions | undefined = options;
257
319
 
258
320
  // Handle overloads
259
321
  if (typeof graphicOrNbTimes === 'number') {
260
322
  // setAnimation(animationName, nbTimes)
261
323
  finalNbTimes = graphicOrNbTimes;
324
+ restoreOptions = typeof nbTimesOrOptions === 'object' ? nbTimesOrOptions : options;
262
325
  } else if (graphicOrNbTimes !== undefined) {
263
326
  // setAnimation(animationName, graphic, nbTimes)
264
327
  graphic = graphicOrNbTimes;
265
- finalNbTimes = nbTimes ?? Infinity;
328
+ if (typeof nbTimesOrOptions === 'number') {
329
+ finalNbTimes = nbTimesOrOptions;
330
+ } else {
331
+ finalNbTimes = Infinity;
332
+ restoreOptions = nbTimesOrOptions ?? options;
333
+ }
266
334
  } else {
267
335
  // setAnimation(animationName) - nbTimes remains Infinity
268
336
  finalNbTimes = Infinity;
269
337
  }
270
338
 
339
+ if (this.animationIsPlaying()) {
340
+ this.finishTemporaryAnimation();
341
+ }
342
+
343
+ const waitPromise =
344
+ finalNbTimes === Infinity
345
+ ? Promise.resolve()
346
+ : new Promise<void>((resolve) => {
347
+ this.animationWaitResolve = resolve;
348
+ });
349
+
350
+ this.animationIsPlaying.set(true);
351
+ const previousAnimationName =
352
+ restoreOptions?.restoreAnimationName ?? this.animationName();
353
+ const previousGraphics = restoreOptions?.restoreGraphics
354
+ ? [...restoreOptions.restoreGraphics]
355
+ : [...this.graphics()];
356
+ this.animationRestoreState = {
357
+ animationName: previousAnimationName,
358
+ graphics: previousGraphics,
359
+ };
360
+ this.animationCurrentIndex.set(0);
361
+
271
362
  // Temporarily change graphic if provided
272
363
  if (graphic !== undefined) {
273
364
  if (Array.isArray(graphic)) {
@@ -277,28 +368,26 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
277
368
  }
278
369
  }
279
370
 
280
- // Clean up any existing subscription
281
- if (this.animationSubscription) {
282
- this.animationSubscription.unsubscribe();
283
- }
371
+ this.clearAnimationControls();
284
372
 
285
373
  this.animationSubscription =
286
374
  this.animationCurrentIndex.observable.subscribe((index) => {
287
375
  if (index >= finalNbTimes) {
288
- this.animationCurrentIndex.set(0);
289
- this.animationName.set(previousAnimationName);
290
- // Reset graphic to previous value if it was changed
291
- if (graphic !== undefined) {
292
- this.graphics.set(previousGraphics);
293
- }
294
- this.animationIsPlaying.set(false);
295
- if (this.animationSubscription) {
296
- this.animationSubscription.unsubscribe();
297
- this.animationSubscription = undefined;
298
- }
376
+ this.finishTemporaryAnimation();
299
377
  }
300
378
  });
379
+
380
+ if (finalNbTimes !== Infinity) {
381
+ this.animationResetTimeout = setTimeout(() => {
382
+ if (this.animationIsPlaying()) {
383
+ this.finishTemporaryAnimation();
384
+ }
385
+ }, restoreOptions?.timeoutMs ?? Math.max(1000, finalNbTimes * 1000));
386
+ }
387
+
301
388
  this.animationName.set(animationName);
389
+
390
+ return waitPromise;
302
391
  }
303
392
 
304
393
  /**
@@ -306,10 +395,25 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
306
395
  *
307
396
  * @param id - Identifier of the component animation to play.
308
397
  * @param params - Parameters forwarded to the animation effect.
398
+ * @returns A promise resolved when the animation component calls `onFinish`.
309
399
  */
310
- showComponentAnimation(id: string, params: any) {
400
+ showComponentAnimation(id: string, params: any): Promise<void> {
311
401
  const engine = inject(RpgClientEngine);
312
- engine.getComponentAnimation(id).displayEffect(params, this);
402
+ return engine.getComponentAnimation(id).displayEffect(params, this);
403
+ }
404
+
405
+ /**
406
+ * Display a registered spritesheet animation effect on this object.
407
+ *
408
+ * @param graphic - Identifier of the spritesheet to use.
409
+ * @param animationName - Name of the animation inside the spritesheet.
410
+ * @returns A promise resolved when the animation component calls `onFinish`.
411
+ */
412
+ showAnimation(graphic: string, animationName: string = 'default'): Promise<void> {
413
+ return this.showComponentAnimation('animation', {
414
+ graphic,
415
+ animationName,
416
+ });
313
417
  }
314
418
 
315
419
  /**