@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
@@ -1,31 +1,64 @@
1
- <Container x={smoothX} y={smoothY} zIndex={z} viewportFollow={shouldFollowCamera} controls onBeforeDestroy visible>
1
+ <Container
2
+ x={smoothX}
3
+ y={smoothY}
4
+ zIndex={z}
5
+ controls
6
+ onBeforeDestroy
7
+ visible
8
+ cursor={interactionCursor}
9
+ pointerover={interactionPointerOver}
10
+ pointerout={interactionPointerOut}
11
+ pointerdown={interactionPointerDown}
12
+ pointerup={interactionPointerUp}
13
+ pointermove={interactionPointerMove}
14
+ click={interactionClick}
15
+ >
2
16
  @for (compConfig of normalizedComponentsBehind) {
3
17
  <Container>
4
- <compConfig.component object ...compConfig.props />
18
+ <compConfig.component object={sprite} ...compConfig.props />
5
19
  </Container>
6
20
  }
21
+ <PlayerComponents object={sprite} position="bottom" graphicBounds />
22
+ <PlayerComponents object={sprite} position="left" graphicBounds />
7
23
  <Particle emit={emitParticleTrigger} settings={particleSettings} zIndex={1000} name={particleName} />
8
24
  <Container>
9
- @for (graphicObj of graphicsSignals) {
10
- <Sprite
11
- sheet={sheet(graphicObj)}
12
- direction
13
- tint
14
- hitbox
15
- flash={flashConfig}
16
- />
25
+ @for (graphicObj of renderedGraphics) {
26
+ <Container scale={graphicScale(graphicObj)}>
27
+ <Sprite
28
+ sheet={sheet(graphicObj)}
29
+ direction
30
+ tint
31
+ hitbox
32
+ shadowCaster={shadowCaster(graphicObj)}
33
+ flash={flashConfig}
34
+ />
35
+ </Container>
36
+ }
37
+ @for (eventComponent of resolvedEventComponents) {
38
+ <Container dependencies={eventComponent.dependencies}>
39
+ <eventComponent.component ...eventComponent.props />
40
+ </Container>
17
41
  }
18
42
  </Container>
43
+ <PlayerComponents object={sprite} position="center" graphicBounds />
44
+ <PlayerComponents object={sprite} position="right" graphicBounds />
45
+ <PlayerComponents object={sprite} position="top" graphicBounds />
19
46
  @for (compConfig of normalizedComponentsInFront) {
20
47
  <Container dependencies={compConfig.dependencies}>
21
- <compConfig.component object ...compConfig.props />
48
+ <compConfig.component object={sprite} ...compConfig.props />
22
49
  </Container>
23
50
  }
51
+ <InteractionComponents
52
+ object={sprite}
53
+ bounds={graphicBounds}
54
+ hitboxBounds={hitboxBounds}
55
+ graphicBounds={graphicBounds}
56
+ />
24
57
  @for (attachedGui of attachedGuis) {
25
58
  @if (shouldDisplayAttachedGui) {
26
59
  <Container>
27
- <attachedGui.component ...attachedGui.data() dependencies={attachedGui.dependencies} object={object} onFinish={(data) => {
28
- onAttachedGuiFinish(attachedGui, data)
60
+ <attachedGui.component ...attachedGui.data() dependencies={attachedGui.dependencies} object={sprite} guiOpenId={attachedGui.openId} onFinish={(data, guiOpenId) => {
61
+ onAttachedGuiFinish(attachedGui, data, guiOpenId)
29
62
  }} onInteraction={(name, data) => {
30
63
  onAttachedGuiInteraction(attachedGui, name, data)
31
64
  }} />
@@ -36,28 +69,52 @@
36
69
 
37
70
  <script>
38
71
  import { signal, effect, mount, computed, tick, animatedSignal, on } from "canvasengine";
72
+ import { Assets } from "pixi.js";
39
73
 
40
74
  import { lastValueFrom, combineLatest, pairwise, filter, map, startWith } from "rxjs";
41
75
  import { Particle } from "@canvasengine/presets";
42
- import { GameEngineToken, ModulesToken } from "@rpgjs/common";
76
+ import { GameEngineToken, ModulesToken, shouldRenderLightingShadows } from "@rpgjs/common";
43
77
  import { RpgClientEngine } from "../RpgClientEngine";
78
+ import { applyCameraFollow, clearCameraFollowPlugins, ownsCameraFollowRevision } from "../services/cameraFollow";
44
79
  import { inject } from "../core/inject";
45
- import { Direction } from "@rpgjs/common";
80
+ import { Direction, Animation } from "@rpgjs/common";
81
+ import { normalizeEventComponent } from "../Game/EventComponentResolver";
46
82
  import Hit from "./effects/hit.ce";
47
83
  import PlayerComponents from "./player-components.ce";
84
+ import InteractionComponents from "./interaction-components.ce";
48
85
  import { RpgGui } from "../Gui/Gui";
86
+ import { getCanMoveValue } from "../utils/readPropValue";
87
+ import {
88
+ getKeyboardControlBind,
89
+ keyboardEventMatchesBind,
90
+ resolveKeyboardActionInput,
91
+ resolveKeyboardDirectionInput,
92
+ } from "../services/actionInput";
49
93
 
50
94
  const { object, id } = defineProps();
95
+ const sprite = object();
51
96
 
52
97
  const client = inject(RpgClientEngine);
53
98
  const hooks = inject(ModulesToken);
54
99
  const guiService = inject(RpgGui);
55
100
 
56
101
  const spritesheets = client.spritesheets;
57
- const playerId = client.playerId;
58
102
  const componentsBehind = client.spriteComponentsBehind;
59
103
  const componentsInFront = client.spriteComponentsInFront;
60
- const isMe = computed(() => id() === playerId);
104
+ const readProp = (value) => typeof value === 'function' ? value() : value;
105
+ const isCurrentPlayer = () => {
106
+ const playerId = client.playerIdSignal();
107
+ const currentPlayer = playerId ? client.sceneMap?.players?.()?.[playerId] : undefined;
108
+ return readProp(id) === playerId
109
+ || readProp(sprite?.id) === playerId
110
+ || sprite === currentPlayer
111
+ || sprite === client.sceneMap?.getCurrentPlayer?.();
112
+ };
113
+ const isMe = computed(isCurrentPlayer);
114
+ const shadowsEnabled = computed(() => {
115
+ const lighting = client.sceneMap?.lighting?.();
116
+ return shouldRenderLightingShadows(lighting);
117
+ });
61
118
 
62
119
  /**
63
120
  * Normalize a single sprite component configuration
@@ -128,8 +185,8 @@
128
185
  // The computed will be created in the template when needed
129
186
  return {
130
187
  component: componentRef,
131
- props: typeof propsValue === 'function' ? propsValue(object) : propsValue || {},
132
- dependencies: dependenciesFn ? dependenciesFn(object) : []
188
+ props: typeof propsValue === 'function' ? propsValue(sprite) : propsValue || {},
189
+ dependencies: dependenciesFn ? dependenciesFn(sprite) : []
133
190
  };
134
191
  };
135
192
 
@@ -189,6 +246,18 @@
189
246
  const normalizedComponentsInFront = computed(() => {
190
247
  return normalizeComponents(componentsInFront());
191
248
  });
249
+
250
+ const isEventSprite = () => {
251
+ return typeof sprite?.isEvent === 'function'
252
+ ? sprite.isEvent()
253
+ : sprite?._type === 'event';
254
+ };
255
+
256
+ const resolvedEventComponents = computed(() => {
257
+ if (!isEventSprite()) return [];
258
+ const eventComponent = normalizeEventComponent(client.resolveEventComponent(sprite), sprite);
259
+ return eventComponent ? [eventComponent] : [];
260
+ });
192
261
 
193
262
  /**
194
263
  * Determine if the camera should follow this sprite
@@ -237,7 +306,13 @@
237
306
  isConnected,
238
307
  graphicsSignals,
239
308
  flashTrigger
240
- } = object;
309
+ } = sprite;
310
+
311
+ const renderedGraphics = computed(() => {
312
+ const eventComponent = resolvedEventComponents()[0];
313
+ if (eventComponent && !eventComponent.renderGraphic) return [];
314
+ return graphicsSignals();
315
+ });
241
316
 
242
317
  /**
243
318
  * Flash configuration signals for dynamic options
@@ -282,50 +357,266 @@
282
357
 
283
358
  const particleSettings = client.particleSettings;
284
359
 
285
- const canControls = () => isMe() && object.canMove()
360
+ const canControls = () => isMe() && getCanMoveValue(sprite)
286
361
  const keyboardControls = client.globalConfig.keyboardControls;
362
+ const activeDirectionKeys = new Map();
363
+ const activeControlDirections = new Map();
364
+ const activeControlDirectionReleaseTimers = new Map();
365
+ const CONTROL_DIRECTION_RELEASE_GRACE_MS = 160;
366
+
367
+ const hasHeldDirection = () =>
368
+ activeDirectionKeys.size > 0 || activeControlDirections.size > 0;
369
+
370
+ const publishMobileDebug = (type, payload = {}) => {
371
+ const target = typeof window !== "undefined" ? window : globalThis;
372
+ if (!target.__RPGJS_MOBILE_DEBUG__) return;
373
+ const event = {
374
+ source: "character",
375
+ type,
376
+ time: Date.now(),
377
+ isCurrentPlayer: isCurrentPlayer(),
378
+ animationName: animationName(),
379
+ realAnimationName: realAnimationName?.(),
380
+ activeKeyboardDirections: Array.from(activeDirectionKeys.values()),
381
+ activeControlDirections: Array.from(activeControlDirections.values()),
382
+ heldDirection: resolveHeldDirection(),
383
+ canControls: canControls(),
384
+ x: x(),
385
+ y: y(),
386
+ ...payload
387
+ };
388
+ target.__RPGJS_MOBILE_DEBUG_EVENTS__ = [
389
+ ...(target.__RPGJS_MOBILE_DEBUG_EVENTS__ || []).slice(-199),
390
+ event
391
+ ];
392
+ target.__RPGJS_MOBILE_DEBUG_LAST__ = event;
393
+ };
394
+
395
+ const resolveHeldDirection = () => {
396
+ const directions = [
397
+ ...Array.from(activeDirectionKeys.values()),
398
+ ...Array.from(activeControlDirections.values()),
399
+ ];
400
+ return directions[directions.length - 1];
401
+ };
402
+
403
+ const resolveSpriteDirection = () => {
404
+ const heldDirection = resolveHeldDirection();
405
+ if (heldDirection) return heldDirection;
406
+ if (typeof sprite.getDirection === 'function') return sprite.getDirection();
407
+ if (typeof sprite.direction === 'function') return sprite.direction();
408
+ return direction();
409
+ };
410
+
411
+ const directionToDashVector = (currentDirection) => {
412
+ switch (currentDirection) {
413
+ case Direction.Left:
414
+ return { x: -1, y: 0 };
415
+ case Direction.Right:
416
+ return { x: 1, y: 0 };
417
+ case Direction.Up:
418
+ return { x: 0, y: -1 };
419
+ case Direction.Down:
420
+ default:
421
+ return { x: 0, y: 1 };
422
+ }
423
+ };
424
+
425
+ const withCurrentDirection = (payload) => {
426
+ if (payload.action !== 'action') return payload;
427
+ const data = payload.data && typeof payload.data === 'object'
428
+ ? { ...payload.data }
429
+ : {};
430
+ return {
431
+ ...payload,
432
+ data: {
433
+ ...data,
434
+ direction: data.direction ?? resolveSpriteDirection(),
435
+ },
436
+ };
437
+ };
438
+
439
+ const resolveCurrentActionInput = () =>
440
+ withCurrentDirection(
441
+ resolveKeyboardActionInput(keyboardControls.action, client, sprite)
442
+ );
443
+
444
+ const playPredictedWalkAnimation = () => {
445
+ if (sprite.animationFixed) {
446
+ publishMobileDebug("walk:skip", { reason: "animationFixed" });
447
+ return;
448
+ }
449
+ if (sprite.animationIsPlaying && sprite.animationIsPlaying()) {
450
+ publishMobileDebug("walk:skip", { reason: "animationIsPlaying" });
451
+ return;
452
+ }
453
+ realAnimationName.set('walk');
454
+ publishMobileDebug("walk:set", { reason: "predicted" });
455
+ };
456
+
457
+ const resumeHeldDirectionWalkAnimation = () => {
458
+ if (!isCurrentPlayer()) {
459
+ publishMobileDebug("walk:resume-fail", { reason: "notCurrentPlayer" });
460
+ return false;
461
+ }
462
+ if (!hasHeldDirection()) {
463
+ publishMobileDebug("walk:resume-fail", { reason: "noHeldDirection" });
464
+ return false;
465
+ }
466
+ if (!canControls()) {
467
+ publishMobileDebug("walk:resume-fail", { reason: "cannotControl" });
468
+ return false;
469
+ }
470
+ if (sprite.animationFixed) {
471
+ publishMobileDebug("walk:resume-fail", { reason: "animationFixed" });
472
+ return false;
473
+ }
474
+ if (sprite.animationIsPlaying && sprite.animationIsPlaying()) {
475
+ publishMobileDebug("walk:resume-fail", { reason: "animationIsPlaying" });
476
+ return false;
477
+ }
478
+ realAnimationName.set('walk');
479
+ publishMobileDebug("walk:set", { reason: "resumeHeldDirection" });
480
+ return true;
481
+ };
482
+
483
+ const processMovementInput = (input) => {
484
+ if (!canControls()) return;
485
+ publishMobileDebug("movement:input", { input });
486
+ client.processInput({ input });
487
+ playPredictedWalkAnimation();
488
+ };
489
+
490
+ const activateControlDirection = (name, directionInput) => {
491
+ const releaseTimer = activeControlDirectionReleaseTimers.get(name);
492
+ if (releaseTimer) {
493
+ clearTimeout(releaseTimer);
494
+ activeControlDirectionReleaseTimers.delete(name);
495
+ }
496
+ activeControlDirections.delete(name);
497
+ activeControlDirections.set(name, directionInput);
498
+ publishMobileDebug("control:activate", { name, directionInput });
499
+ resumeHeldDirectionWalkAnimation();
500
+ };
501
+
502
+ const releaseControlDirection = (name) => {
503
+ const previousTimer = activeControlDirectionReleaseTimers.get(name);
504
+ if (previousTimer) clearTimeout(previousTimer);
505
+ activeControlDirectionReleaseTimers.set(name, setTimeout(() => {
506
+ activeControlDirectionReleaseTimers.delete(name);
507
+ activeControlDirections.delete(name);
508
+ publishMobileDebug("control:release", { name });
509
+ if (!hasHeldDirection() && animationName() === 'stand') {
510
+ realAnimationName.set('stand');
511
+ publishMobileDebug("stand:set", { reason: "controlRelease" });
512
+ }
513
+ }, CONTROL_DIRECTION_RELEASE_GRACE_MS));
514
+ };
515
+
516
+ const processDashInput = () => {
517
+ if (!canControls()) return;
518
+ client.processDash({
519
+ direction: directionToDashVector(resolveSpriteDirection()),
520
+ });
521
+ };
522
+
523
+ const actionBind = () => getKeyboardControlBind(keyboardControls.action);
524
+ const keyboardEventId = (event) => `${event.keyCode}:${event.code}:${event.key}`;
525
+
526
+ const handleNativeActionWhileMoving = (event) => {
527
+ const inputDirection = resolveKeyboardDirectionInput(event, keyboardControls);
528
+ if (inputDirection) {
529
+ const keyId = keyboardEventId(event);
530
+ if (event.type === 'keydown') {
531
+ activeDirectionKeys.delete(keyId);
532
+ activeDirectionKeys.set(keyId, inputDirection);
533
+ resumeHeldDirectionWalkAnimation();
534
+ }
535
+ else {
536
+ activeDirectionKeys.delete(keyId);
537
+ }
538
+ }
539
+
540
+ if (!isCurrentPlayer()) return;
541
+ if (event.type !== 'keydown' || event.repeat) return;
542
+ if (activeDirectionKeys.size === 0) return;
543
+ if (!keyboardEventMatchesBind(event, actionBind())) return;
544
+ if (!canControls()) return;
545
+
546
+ client.processAction(resolveCurrentActionInput());
547
+ };
287
548
 
288
549
  const visible = computed(() => {
289
- if (object.isEvent()) {
550
+ if (sprite.isEvent()) {
290
551
  return true
291
552
  }
292
553
  return isConnected()
293
554
  });
294
555
 
295
- const controls = signal({
556
+ const controls = {
296
557
  down: {
297
558
  repeat: true,
298
559
  bind: keyboardControls.down,
299
560
  keyDown() {
300
- if (canControls()) client.processInput({ input: Direction.Down })
561
+ activateControlDirection('down', Direction.Down)
562
+ processMovementInput(Direction.Down)
563
+ },
564
+ keyUp() {
565
+ releaseControlDirection('down')
301
566
  },
302
567
  },
303
568
  up: {
304
569
  repeat: true,
305
570
  bind: keyboardControls.up,
306
571
  keyDown() {
307
- if (canControls()) client.processInput({ input: Direction.Up })
572
+ activateControlDirection('up', Direction.Up)
573
+ processMovementInput(Direction.Up)
574
+ },
575
+ keyUp() {
576
+ releaseControlDirection('up')
308
577
  },
309
578
  },
310
579
  left: {
311
580
  repeat: true,
312
581
  bind: keyboardControls.left,
313
582
  keyDown() {
314
- if (canControls()) client.processInput({ input: Direction.Left })
583
+ activateControlDirection('left', Direction.Left)
584
+ processMovementInput(Direction.Left)
585
+ },
586
+ keyUp() {
587
+ releaseControlDirection('left')
315
588
  },
316
589
  },
317
590
  right: {
318
591
  repeat: true,
319
592
  bind: keyboardControls.right,
320
593
  keyDown() {
321
- if (canControls()) client.processInput({ input: Direction.Right })
594
+ activateControlDirection('right', Direction.Right)
595
+ processMovementInput(Direction.Right)
596
+ },
597
+ keyUp() {
598
+ releaseControlDirection('right')
322
599
  },
323
600
  },
324
601
  action: {
325
- bind: keyboardControls.action,
602
+ bind: getKeyboardControlBind(keyboardControls.action),
326
603
  keyDown() {
327
604
  if (canControls()) {
328
- client.processAction({ action: 'action' })
605
+ client.processAction(resolveCurrentActionInput())
606
+ }
607
+ },
608
+ },
609
+ dash: {
610
+ bind: keyboardControls.dash,
611
+ keyDown() {
612
+ processDashInput()
613
+ },
614
+ },
615
+ back: {
616
+ bind: keyboardControls.escape,
617
+ keyDown() {
618
+ if (canControls()) {
619
+ client.processAction({ action: 'escape' })
329
620
  }
330
621
  },
331
622
  },
@@ -337,10 +628,25 @@
337
628
  }
338
629
  },
339
630
  },
631
+ joystick: {
632
+ enabled: true,
633
+ directionMapping: {
634
+ top: 'up',
635
+ bottom: 'down',
636
+ left: 'left',
637
+ right: 'right',
638
+ top_left: ['up', 'left'],
639
+ top_right: ['up', 'right'],
640
+ bottom_left: ['down', 'left'],
641
+ bottom_right: ['down', 'right']
642
+ },
643
+ moveInterval: 50,
644
+ threshold: 0.1
645
+ },
340
646
  gamepad: {
341
647
  enabled: true
342
648
  }
343
- });
649
+ };
344
650
 
345
651
  const smoothX = animatedSignal(x(), {
346
652
  duration: isMe() ? 0 : 0
@@ -351,7 +657,8 @@
351
657
  });
352
658
 
353
659
  const z = computed(() => {
354
- return object.y() + object.z()
660
+ const box = hitbox?.()
661
+ return sprite.y() + (box?.h ?? 0) + sprite.z()
355
662
  });
356
663
 
357
664
  const realAnimationName = signal(animationName());
@@ -377,6 +684,344 @@
377
684
  };
378
685
  }
379
686
 
687
+ const graphicScale = (graphicObject) => {
688
+ const scale = graphicObject?.displayScale ?? graphicObject?.scale;
689
+ if (Array.isArray(scale)) return scale;
690
+ if (typeof scale === 'number') return [scale, scale];
691
+ if (scale && typeof scale === 'object') {
692
+ const x = typeof scale.x === 'number' ? scale.x : 1;
693
+ const y = typeof scale.y === 'number' ? scale.y : x;
694
+ return [x, y];
695
+ }
696
+ return undefined;
697
+ }
698
+
699
+ const shadowCaster = (graphicObject) => {
700
+ const box = hitbox();
701
+ const bounds = graphicBounds();
702
+ const scale = graphicScale(graphicObject);
703
+ const scaleY = Array.isArray(scale) && typeof scale[1] === 'number' ? Math.abs(scale[1]) : 1;
704
+ const height = Math.max(bounds?.height ?? box?.h ?? 32, box?.h ?? 32) * scaleY;
705
+
706
+ return {
707
+ enabled: shadowsEnabled,
708
+ height,
709
+ footAnchor: { x: 0.5, y: 1 },
710
+ footOffset: { x: 0, y: 2 },
711
+ alpha: 0.5,
712
+ blur: 3.5,
713
+ gradientPower: 2,
714
+ hardness: 0.42,
715
+ minLength: Math.max(6, (box?.h ?? 32) * 0.25),
716
+ maxLength: Math.max(90, height * 1.8),
717
+ contactAlpha: 0.3,
718
+ contactScale: 0.3,
719
+ };
720
+ }
721
+
722
+ const imageDimensions = signal({});
723
+ const loadingImageDimensions = new Set();
724
+
725
+ const toPositiveNumber = (value) => {
726
+ const number = typeof value === 'number' ? value : parseFloat(value);
727
+ return Number.isFinite(number) && number > 0 ? number : undefined;
728
+ };
729
+
730
+ const toFiniteNumber = (value, fallback = 0) => {
731
+ const number = typeof value === 'number' ? value : parseFloat(value);
732
+ return Number.isFinite(number) ? number : fallback;
733
+ };
734
+
735
+ const clampRatio = (value) => Math.min(1, Math.max(0, value));
736
+
737
+ const normalizePair = (value, fallback = [1, 1]) => {
738
+ if (Array.isArray(value)) {
739
+ const x = toFiniteNumber(value[0], fallback[0]);
740
+ const y = toFiniteNumber(value[1] ?? value[0], x);
741
+ return [x, y];
742
+ }
743
+ if (typeof value === 'number') {
744
+ return [value, value];
745
+ }
746
+ if (value && typeof value === 'object') {
747
+ const x = toFiniteNumber(value.x, fallback[0]);
748
+ const y = toFiniteNumber(value.y ?? value.x, x);
749
+ return [x, y];
750
+ }
751
+ return fallback;
752
+ };
753
+
754
+ const normalizeAnchor = (value) => {
755
+ if (!Array.isArray(value)) return undefined;
756
+ const [x, y] = normalizePair(value, [0, 0]);
757
+ return [clampRatio(x), clampRatio(y)];
758
+ };
759
+
760
+ const resolveImageSource = (image) => {
761
+ if (typeof image === 'string') return image;
762
+ if (typeof image?.default === 'string') return image.default;
763
+ return undefined;
764
+ };
765
+
766
+ const parentTextureOptions = (graphicObject) => {
767
+ const props = [
768
+ 'width',
769
+ 'height',
770
+ 'framesHeight',
771
+ 'framesWidth',
772
+ 'rectWidth',
773
+ 'rectHeight',
774
+ 'offset',
775
+ 'image',
776
+ 'sound',
777
+ 'spriteRealSize',
778
+ 'scale',
779
+ 'anchor',
780
+ 'pivot',
781
+ 'x',
782
+ 'y',
783
+ 'opacity'
784
+ ];
785
+
786
+ return props.reduce((options, prop) => {
787
+ if (graphicObject?.[prop] !== undefined) {
788
+ options[prop] = graphicObject[prop];
789
+ }
790
+ return options;
791
+ }, {});
792
+ };
793
+
794
+ const resolveTextureOptions = (graphicObject) => {
795
+ const textures = graphicObject?.textures ?? {};
796
+ const texture =
797
+ textures[realAnimationName()] ??
798
+ textures[Animation.Stand] ??
799
+ Object.values(textures)[0] ??
800
+ {};
801
+
802
+ return {
803
+ ...parentTextureOptions(graphicObject),
804
+ ...texture
805
+ };
806
+ };
807
+
808
+ const resolveFirstAnimationFrame = (textureOptions) => {
809
+ const animations = textureOptions?.animations;
810
+ if (!animations) return {};
811
+
812
+ try {
813
+ const frames = typeof animations === 'function'
814
+ ? animations({ direction: direction() })
815
+ : animations;
816
+ if (!Array.isArray(frames)) return {};
817
+ const firstGroup = frames[0];
818
+ return Array.isArray(firstGroup) ? firstGroup[0] ?? {} : firstGroup ?? {};
819
+ }
820
+ catch {
821
+ return {};
822
+ }
823
+ };
824
+
825
+ const optionValue = (prop, frame, textureOptions, graphicObject) => {
826
+ return frame?.[prop] ?? textureOptions?.[prop] ?? graphicObject?.[prop];
827
+ };
828
+
829
+ const resolveFrameSize = (textureOptions, dimensions) => {
830
+ const framesWidth = toPositiveNumber(textureOptions?.framesWidth) ?? 1;
831
+ const framesHeight = toPositiveNumber(textureOptions?.framesHeight) ?? 1;
832
+ const imageSource = resolveImageSource(textureOptions?.image);
833
+ const loadedSize = imageSource ? dimensions[imageSource] : undefined;
834
+ const fullWidth = toPositiveNumber(textureOptions?.width) ?? loadedSize?.width;
835
+ const fullHeight = toPositiveNumber(textureOptions?.height) ?? loadedSize?.height;
836
+ const width = toPositiveNumber(textureOptions?.rectWidth) ??
837
+ toPositiveNumber(textureOptions?.spriteWidth) ??
838
+ (fullWidth ? fullWidth / framesWidth : undefined);
839
+ const height = toPositiveNumber(textureOptions?.rectHeight) ??
840
+ toPositiveNumber(textureOptions?.spriteHeight) ??
841
+ (fullHeight ? fullHeight / framesHeight : undefined);
842
+
843
+ return {
844
+ width,
845
+ height
846
+ };
847
+ };
848
+
849
+ const resolveHitboxAnchor = (spriteWidth, spriteHeight, realSize, box) => {
850
+ if (!spriteWidth || !spriteHeight || !box) {
851
+ return [0, 0];
852
+ }
853
+
854
+ const heightOfSprite = typeof realSize === 'number' ? realSize : realSize?.height;
855
+ const resolvedHeight = toPositiveNumber(heightOfSprite) ?? spriteHeight;
856
+ const gap = Math.max(0, (spriteHeight - resolvedHeight) / 2);
857
+ const hitboxTopLeftX = clampRatio((spriteWidth - box.w) / 2 / spriteWidth);
858
+ const hitboxTopLeftY = clampRatio((spriteHeight - box.h - gap) / spriteHeight);
859
+ const hitboxCenterX = clampRatio(hitboxTopLeftX + box.w / 2 / spriteWidth);
860
+ const hitboxCenterY = clampRatio(hitboxTopLeftY + box.h / 2 / spriteHeight);
861
+ const footY = clampRatio((spriteHeight - gap) / spriteHeight);
862
+
863
+ switch (box.anchorMode ?? 'top-left') {
864
+ case 'center':
865
+ return [hitboxCenterX, hitboxCenterY];
866
+ case 'foot':
867
+ return [hitboxCenterX, footY];
868
+ case 'top-left':
869
+ default:
870
+ return [hitboxTopLeftX, hitboxTopLeftY];
871
+ }
872
+ };
873
+
874
+ const loadImageDimensions = (image) => {
875
+ const source = resolveImageSource(image);
876
+ if (!source || imageDimensions()[source] || loadingImageDimensions.has(source)) {
877
+ return;
878
+ }
879
+
880
+ loadingImageDimensions.add(source);
881
+ Assets.load(source)
882
+ .then((texture) => {
883
+ const width = toPositiveNumber(texture?.width);
884
+ const height = toPositiveNumber(texture?.height);
885
+ if (!width || !height) return;
886
+
887
+ imageDimensions.update((dimensions) => ({
888
+ ...dimensions,
889
+ [source]: { width, height }
890
+ }));
891
+ })
892
+ .catch(() => {})
893
+ .finally(() => {
894
+ loadingImageDimensions.delete(source);
895
+ });
896
+ };
897
+
898
+ effect(() => {
899
+ const sources = new Set();
900
+
901
+ graphicsSignals().forEach((graphicObject) => {
902
+ const baseImage = resolveImageSource(graphicObject?.image);
903
+ if (baseImage) sources.add(baseImage);
904
+
905
+ Object.values(graphicObject?.textures ?? {}).forEach((textureOptions) => {
906
+ const image = resolveImageSource(textureOptions?.image ?? graphicObject?.image);
907
+ if (image) sources.add(image);
908
+ });
909
+ });
910
+
911
+ sources.forEach((source) => loadImageDimensions(source));
912
+ });
913
+
914
+ const hitboxBounds = computed(() => {
915
+ const box = hitbox();
916
+ const width = box?.w ?? 0;
917
+ const height = box?.h ?? 0;
918
+
919
+ return {
920
+ left: 0,
921
+ top: 0,
922
+ right: width,
923
+ bottom: height,
924
+ width,
925
+ height,
926
+ centerX: width / 2,
927
+ centerY: height / 2
928
+ };
929
+ });
930
+
931
+ const graphicBounds = computed(() => {
932
+ const box = hitbox();
933
+ const fallback = hitboxBounds();
934
+ const customEventComponent = resolvedEventComponents()[0];
935
+ if (customEventComponent && !customEventComponent.renderGraphic) {
936
+ return fallback;
937
+ }
938
+ const dimensions = imageDimensions();
939
+ const graphics = graphicsSignals();
940
+ let bounds = null;
941
+
942
+ graphics.forEach((graphicObject) => {
943
+ const textureOptions = resolveTextureOptions(graphicObject);
944
+ const frame = resolveFirstAnimationFrame(textureOptions);
945
+ const size = resolveFrameSize(textureOptions, dimensions);
946
+ const spriteWidth = size.width ?? box?.w;
947
+ const spriteHeight = size.height ?? box?.h;
948
+
949
+ if (!spriteWidth || !spriteHeight) {
950
+ return;
951
+ }
952
+
953
+ const explicitAnchor = normalizeAnchor(optionValue('anchor', frame, textureOptions, graphicObject));
954
+ const anchor = explicitAnchor ?? resolveHitboxAnchor(
955
+ spriteWidth,
956
+ spriteHeight,
957
+ optionValue('spriteRealSize', frame, textureOptions, graphicObject),
958
+ box
959
+ );
960
+ const scale = normalizePair(optionValue('scale', frame, textureOptions, graphicObject) ?? graphicScale(graphicObject));
961
+ const x = toFiniteNumber(optionValue('x', frame, textureOptions, graphicObject), 0);
962
+ const y = toFiniteNumber(optionValue('y', frame, textureOptions, graphicObject), 0);
963
+ const leftEdge = -anchor[0] * spriteWidth * scale[0];
964
+ const rightEdge = (1 - anchor[0]) * spriteWidth * scale[0];
965
+ const topEdge = -anchor[1] * spriteHeight * scale[1];
966
+ const bottomEdge = (1 - anchor[1]) * spriteHeight * scale[1];
967
+ const graphic = {
968
+ left: x + Math.min(leftEdge, rightEdge),
969
+ top: y + Math.min(topEdge, bottomEdge),
970
+ right: x + Math.max(leftEdge, rightEdge),
971
+ bottom: y + Math.max(topEdge, bottomEdge)
972
+ };
973
+
974
+ bounds = bounds
975
+ ? {
976
+ left: Math.min(bounds.left, graphic.left),
977
+ top: Math.min(bounds.top, graphic.top),
978
+ right: Math.max(bounds.right, graphic.right),
979
+ bottom: Math.max(bounds.bottom, graphic.bottom)
980
+ }
981
+ : graphic;
982
+ });
983
+
984
+ if (!bounds) {
985
+ return fallback;
986
+ }
987
+
988
+ const width = bounds.right - bounds.left;
989
+ const height = bounds.bottom - bounds.top;
990
+
991
+ return {
992
+ ...bounds,
993
+ width,
994
+ height,
995
+ centerX: bounds.left + width / 2,
996
+ centerY: bounds.top + height / 2
997
+ };
998
+ });
999
+
1000
+ const interactionBounds = () => ({
1001
+ bounds: graphicBounds(),
1002
+ hitbox: hitboxBounds(),
1003
+ graphic: graphicBounds()
1004
+ });
1005
+
1006
+ const interactionCursor = computed(() =>
1007
+ client.interactions.cursorFor(sprite, interactionBounds())
1008
+ );
1009
+
1010
+ const handleInteraction = (type) => (event) => {
1011
+ client.updatePointerFromInteractionEvent(event);
1012
+ client.interactions.handle(sprite, type, {
1013
+ event,
1014
+ bounds: interactionBounds()
1015
+ });
1016
+ };
1017
+
1018
+ const interactionPointerOver = handleInteraction('pointerover');
1019
+ const interactionPointerOut = handleInteraction('pointerout');
1020
+ const interactionPointerDown = handleInteraction('pointerdown');
1021
+ const interactionPointerUp = handleInteraction('pointerup');
1022
+ const interactionPointerMove = handleInteraction('pointermove');
1023
+ const interactionClick = handleInteraction('click');
1024
+
380
1025
  // Combine animation change detection with movement state from smoothX/smoothY
381
1026
  const movementAnimations = ['walk', 'stand'];
382
1027
  const epsilon = 0; // movement threshold to consider the easing still running
@@ -400,25 +1045,91 @@
400
1045
  filter(([prev, curr]) => prev !== curr)
401
1046
  );
402
1047
 
1048
+ let beforeRemovePromise = null;
1049
+ let beforeRemoveTransitionValue = null;
1050
+ const resolveRemoveContext = () => {
1051
+ if (!sprite._removeTransition) return null;
1052
+ const value = sprite._removeTransition();
1053
+ if (!value || typeof value !== 'string') return null;
1054
+ try {
1055
+ const context = JSON.parse(value);
1056
+ if (!context || typeof context !== 'object' || !context.active) return null;
1057
+ context.__transitionValue = value;
1058
+ return context;
1059
+ }
1060
+ catch {
1061
+ return null;
1062
+ }
1063
+ };
1064
+
1065
+ const withTimeout = (promise, timeoutMs = 0) => {
1066
+ if (!timeoutMs || timeoutMs <= 0) return promise;
1067
+ return Promise.race([
1068
+ promise,
1069
+ new Promise((resolve) => setTimeout(resolve, timeoutMs)),
1070
+ ]);
1071
+ };
1072
+
1073
+ const runBeforeRemove = () => {
1074
+ const context = resolveRemoveContext();
1075
+ if (!context) return Promise.resolve();
1076
+ if (beforeRemovePromise && beforeRemoveTransitionValue === context.__transitionValue) {
1077
+ return beforeRemovePromise;
1078
+ }
1079
+ beforeRemoveTransitionValue = context.__transitionValue;
1080
+ beforeRemovePromise = withTimeout(
1081
+ lastValueFrom(hooks.callHooks("client-sprite-onBeforeRemove", sprite, context)),
1082
+ context.timeoutMs
1083
+ );
1084
+ return beforeRemovePromise;
1085
+ };
1086
+
1087
+ const removeTransitionSubscription = sprite._removeTransition?.observable?.subscribe(() => {
1088
+ if (resolveRemoveContext()) {
1089
+ runBeforeRemove();
1090
+ }
1091
+ });
1092
+
403
1093
  const animationMovementSubscription = combineLatest([animationChange$, moving$]).subscribe(([[prev, curr], isMoving]) => {
404
- if (curr == 'stand' && !isMoving) {
1094
+ const isMovementAnimation = movementAnimations.includes(curr);
1095
+ const isTemporaryAnimationPlaying =
1096
+ sprite.animationIsPlaying && sprite.animationIsPlaying();
1097
+
1098
+ if (sprite.animationFixed && isMovementAnimation) {
405
1099
  realAnimationName.set(curr);
1100
+ return;
1101
+ }
1102
+
1103
+ if (curr == 'stand' && !isMoving) {
1104
+ if (!resumeHeldDirectionWalkAnimation()) {
1105
+ realAnimationName.set(curr);
1106
+ }
406
1107
  }
407
1108
  else if (curr == 'walk' && isMoving) {
408
1109
  realAnimationName.set(curr);
409
1110
  }
410
- else if (!movementAnimations.includes(curr)) {
1111
+ else if (!isMovementAnimation) {
411
1112
  realAnimationName.set(curr);
412
1113
  }
413
- if (!isMoving && object.animationIsPlaying && object.animationIsPlaying()) {
414
- if (movementAnimations.includes(curr)) {
415
- if (typeof object.resetAnimationState === 'function') {
416
- object.resetAnimationState();
1114
+ if (!isMoving && isTemporaryAnimationPlaying) {
1115
+ if (isMovementAnimation) {
1116
+ if (typeof sprite.resetAnimationState === 'function') {
1117
+ sprite.resetAnimationState();
417
1118
  }
418
1119
  }
419
1120
  }
420
1121
  });
421
1122
 
1123
+ const resumeWalkSubscriptions = [
1124
+ sprite._canMove,
1125
+ sprite._animationFixed,
1126
+ sprite.animationIsPlaying,
1127
+ ]
1128
+ .filter(signal => signal?.observable)
1129
+ .map(signal => signal.observable.subscribe(() => {
1130
+ resumeHeldDirectionWalkAnimation();
1131
+ }));
1132
+
422
1133
  /**
423
1134
  * Cleanup subscriptions and call hooks before sprite destruction.
424
1135
  *
@@ -429,18 +1140,93 @@
429
1140
  * @example
430
1141
  * await onBeforeDestroy();
431
1142
  */
1143
+ const waitForTemporaryAnimationEnd = (maxDuration = 1200) => {
1144
+ if (!sprite.animationIsPlaying || !sprite.animationIsPlaying()) {
1145
+ return Promise.resolve();
1146
+ }
1147
+
1148
+ return new Promise((resolve) => {
1149
+ let finished = false;
1150
+ let timeout;
1151
+ let subscription;
1152
+ const finish = () => {
1153
+ if (finished) return;
1154
+ finished = true;
1155
+ clearTimeout(timeout);
1156
+ subscription?.unsubscribe();
1157
+ resolve();
1158
+ };
1159
+ timeout = setTimeout(finish, maxDuration);
1160
+ subscription = sprite.animationIsPlaying.observable.subscribe((isPlaying) => {
1161
+ if (!isPlaying) finish();
1162
+ });
1163
+ if (finished) subscription.unsubscribe();
1164
+ });
1165
+ };
1166
+
432
1167
  const onBeforeDestroy = async () => {
1168
+ await runBeforeRemove();
1169
+ await waitForTemporaryAnimationEnd();
1170
+ if (typeof document !== 'undefined') {
1171
+ document.removeEventListener('keydown', handleNativeActionWhileMoving);
1172
+ document.removeEventListener('keyup', handleNativeActionWhileMoving);
1173
+ }
1174
+ removeTransitionSubscription?.unsubscribe();
433
1175
  animationMovementSubscription.unsubscribe();
1176
+ resumeWalkSubscriptions.forEach(subscription => subscription.unsubscribe());
1177
+ activeControlDirectionReleaseTimers.forEach(timer => clearTimeout(timer));
1178
+ activeControlDirectionReleaseTimers.clear();
434
1179
  xSubscription.unsubscribe();
435
1180
  ySubscription.unsubscribe();
436
- await lastValueFrom(hooks.callHooks("client-sprite-onDestroy", object))
437
- await lastValueFrom(hooks.callHooks("client-sceneMap-onRemoveSprite", client.sceneMap, object))
1181
+ await lastValueFrom(hooks.callHooks("client-sprite-onDestroy", sprite))
1182
+ await lastValueFrom(hooks.callHooks("client-sceneMap-onRemoveSprite", client.sceneMap, sprite))
438
1183
  }
439
1184
 
440
1185
  mount((element) => {
441
- hooks.callHooks("client-sprite-onAdd", object).subscribe()
442
- hooks.callHooks("client-sceneMap-onAddSprite", client.sceneMap, object).subscribe()
443
- if (isMe()) client.setKeyboardControls(element.directives.controls)
1186
+ let appliedCameraFollowRevision = null;
1187
+ if (typeof document !== 'undefined') {
1188
+ document.addEventListener('keydown', handleNativeActionWhileMoving);
1189
+ document.addEventListener('keyup', handleNativeActionWhileMoving);
1190
+ }
1191
+ hooks.callHooks("client-sprite-onAdd", sprite).subscribe()
1192
+ hooks.callHooks("client-sceneMap-onAddSprite", client.sceneMap, sprite).subscribe()
1193
+ effect(() => {
1194
+ if (isCurrentPlayer()) {
1195
+ client.setKeyboardControls(element.directives.controls)
1196
+ }
1197
+ })
1198
+
1199
+ effect(() => {
1200
+ const followRevision = client.cameraFollowRevision();
1201
+ if (!shouldFollowCamera()) {
1202
+ appliedCameraFollowRevision = null;
1203
+ return;
1204
+ }
1205
+
1206
+ const smoothMove = client.cameraFollowSmoothMove;
1207
+ const viewport = element.props.context?.viewport;
1208
+ const target = element.componentInstance;
1209
+ if (!viewport || !target) {
1210
+ appliedCameraFollowRevision = null;
1211
+ return;
1212
+ }
1213
+
1214
+ const appliedCameraFollow = applyCameraFollow({
1215
+ viewport,
1216
+ target,
1217
+ smoothMove,
1218
+ followRevision,
1219
+ isCurrentRevision: (revision) => client.cameraFollowRevision() === revision,
1220
+ shouldFollowCamera
1221
+ });
1222
+ appliedCameraFollowRevision = appliedCameraFollow ? followRevision : null;
1223
+ })
1224
+
1225
+ return () => {
1226
+ if (ownsCameraFollowRevision(appliedCameraFollowRevision, client.cameraFollowRevision())) {
1227
+ clearCameraFollowPlugins(element.props.context?.viewport);
1228
+ }
1229
+ }
444
1230
  })
445
1231
 
446
1232
  /**
@@ -449,8 +1235,16 @@
449
1235
  * @param gui - The GUI instance
450
1236
  * @param data - Data passed from the GUI component
451
1237
  */
452
- const onAttachedGuiFinish = (gui, data) => {
453
- guiService.guiClose(gui.name, data);
1238
+ const normalizeOpenId = (value) => {
1239
+ const resolved = typeof value === "function" ? value() : value;
1240
+ return typeof resolved === "string" && resolved.length > 0 ? resolved : undefined;
1241
+ };
1242
+
1243
+ const onAttachedGuiFinish = (gui, data, guiOpenId) => {
1244
+ const completedOpenId = normalizeOpenId(guiOpenId);
1245
+ const currentOpenId = normalizeOpenId(gui.openId);
1246
+ if (completedOpenId && currentOpenId && completedOpenId !== currentOpenId) return;
1247
+ guiService.guiClose(gui.name, data, completedOpenId ?? currentOpenId);
454
1248
  };
455
1249
 
456
1250
  /**
@@ -467,4 +1261,4 @@
467
1261
  tick(() => {
468
1262
  hooks.callHooks("client-sprite-onUpdate").subscribe()
469
1263
  })
470
- </script>
1264
+ </script>