@rpgjs/client 5.0.0-alpha.3 → 5.0.0-alpha.30

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 (275) hide show
  1. package/dist/Game/AnimationManager.d.ts +8 -0
  2. package/dist/{index19.js → Game/AnimationManager.js} +4 -3
  3. package/dist/Game/AnimationManager.js.map +1 -0
  4. package/dist/{index30.js → Game/Event.js} +2 -2
  5. package/dist/Game/Event.js.map +1 -0
  6. package/dist/Game/Map.d.ts +8 -1
  7. package/dist/Game/Map.js +54 -0
  8. package/dist/Game/Map.js.map +1 -0
  9. package/dist/Game/Object.d.ts +129 -0
  10. package/dist/Game/Object.js +218 -0
  11. package/dist/Game/Object.js.map +1 -0
  12. package/dist/{index29.js → Game/Player.js} +2 -2
  13. package/dist/Game/Player.js.map +1 -0
  14. package/dist/Gui/Gui.d.ts +177 -5
  15. package/dist/Gui/Gui.js +478 -0
  16. package/dist/Gui/Gui.js.map +1 -0
  17. package/dist/Gui/NotificationManager.d.ts +23 -0
  18. package/dist/Gui/NotificationManager.js +51 -0
  19. package/dist/Gui/NotificationManager.js.map +1 -0
  20. package/dist/Resource.d.ts +97 -0
  21. package/dist/Resource.js +114 -0
  22. package/dist/Resource.js.map +1 -0
  23. package/dist/RpgClient.d.ts +259 -59
  24. package/dist/RpgClientEngine.d.ts +632 -9
  25. package/dist/RpgClientEngine.js +1262 -0
  26. package/dist/RpgClientEngine.js.map +1 -0
  27. package/dist/Sound.d.ts +199 -0
  28. package/dist/Sound.js +97 -0
  29. package/dist/Sound.js.map +1 -0
  30. package/dist/components/animations/animation.ce.js +21 -0
  31. package/dist/components/animations/animation.ce.js.map +1 -0
  32. package/dist/{index23.js → components/animations/hit.ce.js} +3 -3
  33. package/dist/components/animations/hit.ce.js.map +1 -0
  34. package/dist/components/animations/index.d.ts +4 -0
  35. package/dist/components/animations/index.js +10 -0
  36. package/dist/components/animations/index.js.map +1 -0
  37. package/dist/components/character.ce.js +316 -0
  38. package/dist/components/character.ce.js.map +1 -0
  39. package/dist/components/dynamics/parse-value.d.ts +1 -0
  40. package/dist/components/dynamics/parse-value.js +54 -0
  41. package/dist/components/dynamics/parse-value.js.map +1 -0
  42. package/dist/components/dynamics/text.ce.js +141 -0
  43. package/dist/components/dynamics/text.ce.js.map +1 -0
  44. package/dist/components/gui/box.ce.js +27 -0
  45. package/dist/components/gui/box.ce.js.map +1 -0
  46. package/dist/components/gui/dialogbox/index.ce.js +152 -0
  47. package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
  48. package/dist/components/gui/gameover.ce.js +141 -0
  49. package/dist/components/gui/gameover.ce.js.map +1 -0
  50. package/dist/components/gui/hud/hud.ce.js +35 -0
  51. package/dist/components/gui/hud/hud.ce.js.map +1 -0
  52. package/dist/components/gui/index.d.ts +15 -3
  53. package/dist/components/gui/menu/equip-menu.ce.js +349 -0
  54. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -0
  55. package/dist/components/gui/menu/exit-menu.ce.js +35 -0
  56. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -0
  57. package/dist/components/gui/menu/items-menu.ce.js +229 -0
  58. package/dist/components/gui/menu/items-menu.ce.js.map +1 -0
  59. package/dist/components/gui/menu/main-menu.ce.js +205 -0
  60. package/dist/components/gui/menu/main-menu.ce.js.map +1 -0
  61. package/dist/components/gui/menu/options-menu.ce.js +28 -0
  62. package/dist/components/gui/menu/options-menu.ce.js.map +1 -0
  63. package/dist/components/gui/menu/skills-menu.ce.js +53 -0
  64. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -0
  65. package/dist/components/gui/mobile/index.d.ts +8 -0
  66. package/dist/components/gui/mobile/index.js +24 -0
  67. package/dist/components/gui/mobile/index.js.map +1 -0
  68. package/dist/components/gui/mobile/mobile.ce.js +17 -0
  69. package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
  70. package/dist/components/gui/notification/notification.ce.js +38 -0
  71. package/dist/components/gui/notification/notification.ce.js.map +1 -0
  72. package/dist/components/gui/save-load.ce.js +242 -0
  73. package/dist/components/gui/save-load.ce.js.map +1 -0
  74. package/dist/components/gui/shop/shop.ce.js +322 -0
  75. package/dist/components/gui/shop/shop.ce.js.map +1 -0
  76. package/dist/components/gui/title-screen.ce.js +148 -0
  77. package/dist/components/gui/title-screen.ce.js.map +1 -0
  78. package/dist/components/index.d.ts +3 -1
  79. package/dist/components/prebuilt/hp-bar.ce.js +106 -0
  80. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
  81. package/dist/components/prebuilt/index.d.ts +19 -0
  82. package/dist/components/prebuilt/light-halo.ce.js +76 -0
  83. package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
  84. package/dist/components/scenes/canvas.ce.js +44 -0
  85. package/dist/components/scenes/canvas.ce.js.map +1 -0
  86. package/dist/components/scenes/draw-map.ce.js +34 -0
  87. package/dist/components/scenes/draw-map.ce.js.map +1 -0
  88. package/dist/{index13.js → components/scenes/event-layer.ce.js} +7 -6
  89. package/dist/components/scenes/event-layer.ce.js.map +1 -0
  90. package/dist/{index6.js → core/inject.js} +2 -2
  91. package/dist/core/inject.js.map +1 -0
  92. package/dist/core/setup.js +16 -0
  93. package/dist/core/setup.js.map +1 -0
  94. package/dist/index.d.ts +15 -1
  95. package/dist/index.js +40 -12
  96. package/dist/index.js.map +1 -1
  97. package/dist/module.d.ts +43 -4
  98. package/dist/module.js +175 -0
  99. package/dist/module.js.map +1 -0
  100. package/dist/node_modules/.pnpm/@signe_di@2.8.2/node_modules/@signe/di/dist/index.js +366 -0
  101. package/dist/node_modules/.pnpm/@signe_di@2.8.2/node_modules/@signe/di/dist/index.js.map +1 -0
  102. package/dist/{index27.js → node_modules/.pnpm/@signe_reactive@2.8.2/node_modules/@signe/reactive/dist/index.js} +229 -11
  103. package/dist/node_modules/.pnpm/@signe_reactive@2.8.2/node_modules/@signe/reactive/dist/index.js.map +1 -0
  104. package/dist/{index20.js → node_modules/.pnpm/@signe_room@2.8.2/node_modules/@signe/room/dist/index.js} +308 -40
  105. package/dist/node_modules/.pnpm/@signe_room@2.8.2/node_modules/@signe/room/dist/index.js.map +1 -0
  106. package/dist/{index26.js → node_modules/.pnpm/@signe_sync@2.8.2/node_modules/@signe/sync/dist/chunk-7QVYU63E.js} +1 -1
  107. package/dist/node_modules/.pnpm/@signe_sync@2.8.2/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +1 -0
  108. package/dist/{index21.js → node_modules/.pnpm/@signe_sync@2.8.2/node_modules/@signe/sync/dist/client/index.js} +5 -5
  109. package/dist/node_modules/.pnpm/@signe_sync@2.8.2/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  110. package/dist/{index17.js → node_modules/.pnpm/@signe_sync@2.8.2/node_modules/@signe/sync/dist/index.js} +89 -12
  111. package/dist/node_modules/.pnpm/@signe_sync@2.8.2/node_modules/@signe/sync/dist/index.js.map +1 -0
  112. package/dist/{index33.js → node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js} +1 -1
  113. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +1 -0
  114. package/dist/{index31.js → node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js} +2 -2
  115. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
  116. package/dist/{index32.js → node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js} +1 -1
  117. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
  118. package/dist/{index34.js → node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js} +1 -1
  119. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
  120. package/dist/presets/animation.d.ts +31 -0
  121. package/dist/presets/animation.js +27 -0
  122. package/dist/presets/animation.js.map +1 -0
  123. package/dist/presets/faceset.d.ts +30 -0
  124. package/dist/presets/faceset.js +24 -0
  125. package/dist/presets/faceset.js.map +1 -0
  126. package/dist/presets/icon.d.ts +20 -0
  127. package/dist/presets/icon.js +15 -0
  128. package/dist/presets/icon.js.map +1 -0
  129. package/dist/presets/index.d.ts +123 -0
  130. package/dist/presets/index.js +16 -0
  131. package/dist/presets/index.js.map +1 -0
  132. package/dist/presets/lpc.d.ts +89 -0
  133. package/dist/presets/lpc.js +95 -0
  134. package/dist/presets/lpc.js.map +1 -0
  135. package/dist/{index25.js → presets/rmspritesheet.js} +1 -1
  136. package/dist/presets/rmspritesheet.js.map +1 -0
  137. package/dist/{index16.js → services/AbstractSocket.js} +1 -1
  138. package/dist/services/AbstractSocket.js.map +1 -0
  139. package/dist/services/keyboardControls.d.ts +15 -0
  140. package/dist/services/keyboardControls.js +21 -0
  141. package/dist/services/keyboardControls.js.map +1 -0
  142. package/dist/services/loadMap.d.ts +123 -2
  143. package/dist/{index7.js → services/loadMap.js} +12 -4
  144. package/dist/services/loadMap.js.map +1 -0
  145. package/dist/services/mmorpg.d.ts +16 -4
  146. package/dist/services/mmorpg.js +84 -0
  147. package/dist/services/mmorpg.js.map +1 -0
  148. package/dist/services/save.d.ts +19 -0
  149. package/dist/services/save.js +69 -0
  150. package/dist/services/save.js.map +1 -0
  151. package/dist/services/standalone.d.ts +65 -3
  152. package/dist/services/standalone.js +170 -0
  153. package/dist/services/standalone.js.map +1 -0
  154. package/dist/utils/getEntityProp.d.ts +39 -0
  155. package/dist/utils/getEntityProp.js +54 -0
  156. package/dist/utils/getEntityProp.js.map +1 -0
  157. package/package.json +24 -18
  158. package/src/Game/{EffectManager.ts → AnimationManager.ts} +3 -2
  159. package/src/Game/Map.ts +37 -2
  160. package/src/Game/Object.ts +296 -11
  161. package/src/Gui/Gui.ts +506 -18
  162. package/src/Gui/NotificationManager.ts +69 -0
  163. package/src/Resource.ts +150 -0
  164. package/src/RpgClient.ts +264 -58
  165. package/src/RpgClientEngine.ts +1421 -44
  166. package/src/Sound.ts +253 -0
  167. package/src/components/{effects → animations}/animation.ce +3 -6
  168. package/src/components/{effects → animations}/index.ts +1 -1
  169. package/src/components/character.ce +406 -40
  170. package/src/components/dynamics/parse-value.ts +80 -0
  171. package/src/components/dynamics/text.ce +183 -0
  172. package/src/components/gui/box.ce +17 -0
  173. package/src/components/gui/dialogbox/index.ce +204 -187
  174. package/src/components/gui/gameover.ce +158 -0
  175. package/src/components/gui/hud/hud.ce +56 -0
  176. package/src/components/gui/index.ts +30 -4
  177. package/src/components/gui/menu/equip-menu.ce +410 -0
  178. package/src/components/gui/menu/exit-menu.ce +41 -0
  179. package/src/components/gui/menu/items-menu.ce +317 -0
  180. package/src/components/gui/menu/main-menu.ce +291 -0
  181. package/src/components/gui/menu/options-menu.ce +35 -0
  182. package/src/components/gui/menu/skills-menu.ce +83 -0
  183. package/src/components/gui/mobile/index.ts +24 -0
  184. package/src/components/gui/mobile/mobile.ce +80 -0
  185. package/src/components/gui/notification/notification.ce +51 -0
  186. package/src/components/gui/save-load.ce +208 -0
  187. package/src/components/gui/shop/shop.ce +493 -0
  188. package/src/components/gui/title-screen.ce +163 -0
  189. package/src/components/index.ts +5 -1
  190. package/src/components/prebuilt/hp-bar.ce +255 -0
  191. package/src/components/prebuilt/index.ts +24 -0
  192. package/src/components/prebuilt/light-halo.ce +148 -0
  193. package/src/components/scenes/canvas.ce +19 -14
  194. package/src/components/scenes/draw-map.ce +21 -29
  195. package/src/components/scenes/event-layer.ce +10 -3
  196. package/src/components/scenes/transition.ce +60 -0
  197. package/src/core/setup.ts +2 -0
  198. package/src/index.ts +16 -2
  199. package/src/module.ts +145 -9
  200. package/src/presets/animation.ts +46 -0
  201. package/src/presets/faceset.ts +60 -0
  202. package/src/presets/icon.ts +17 -0
  203. package/src/presets/index.ts +9 -1
  204. package/src/presets/lpc.ts +108 -0
  205. package/src/services/keyboardControls.ts +20 -0
  206. package/src/services/loadMap.ts +132 -3
  207. package/src/services/mmorpg.ts +39 -5
  208. package/src/services/save.ts +103 -0
  209. package/src/services/standalone.ts +107 -15
  210. package/src/utils/getEntityProp.ts +87 -0
  211. package/tsconfig.json +1 -1
  212. package/vite.config.ts +5 -3
  213. package/CHANGELOG.md +0 -9
  214. package/dist/Game/EffectManager.d.ts +0 -5
  215. package/dist/components/effects/index.d.ts +0 -4
  216. package/dist/index10.js +0 -8
  217. package/dist/index10.js.map +0 -1
  218. package/dist/index11.js +0 -10
  219. package/dist/index11.js.map +0 -1
  220. package/dist/index12.js +0 -8
  221. package/dist/index12.js.map +0 -1
  222. package/dist/index13.js.map +0 -1
  223. package/dist/index14.js +0 -50
  224. package/dist/index14.js.map +0 -1
  225. package/dist/index15.js +0 -191
  226. package/dist/index15.js.map +0 -1
  227. package/dist/index16.js.map +0 -1
  228. package/dist/index17.js.map +0 -1
  229. package/dist/index18.js +0 -31
  230. package/dist/index18.js.map +0 -1
  231. package/dist/index19.js.map +0 -1
  232. package/dist/index2.js +0 -112
  233. package/dist/index2.js.map +0 -1
  234. package/dist/index20.js.map +0 -1
  235. package/dist/index21.js.map +0 -1
  236. package/dist/index22.js +0 -109
  237. package/dist/index22.js.map +0 -1
  238. package/dist/index23.js.map +0 -1
  239. package/dist/index24.js +0 -21
  240. package/dist/index24.js.map +0 -1
  241. package/dist/index25.js.map +0 -1
  242. package/dist/index26.js.map +0 -1
  243. package/dist/index27.js.map +0 -1
  244. package/dist/index28.js +0 -25
  245. package/dist/index28.js.map +0 -1
  246. package/dist/index29.js.map +0 -1
  247. package/dist/index3.js +0 -87
  248. package/dist/index3.js.map +0 -1
  249. package/dist/index30.js.map +0 -1
  250. package/dist/index31.js.map +0 -1
  251. package/dist/index32.js.map +0 -1
  252. package/dist/index33.js.map +0 -1
  253. package/dist/index34.js.map +0 -1
  254. package/dist/index35.js +0 -91
  255. package/dist/index35.js.map +0 -1
  256. package/dist/index36.js +0 -61
  257. package/dist/index36.js.map +0 -1
  258. package/dist/index37.js +0 -20
  259. package/dist/index37.js.map +0 -1
  260. package/dist/index38.js +0 -20
  261. package/dist/index38.js.map +0 -1
  262. package/dist/index4.js +0 -54
  263. package/dist/index4.js.map +0 -1
  264. package/dist/index5.js +0 -15
  265. package/dist/index5.js.map +0 -1
  266. package/dist/index6.js.map +0 -1
  267. package/dist/index7.js.map +0 -1
  268. package/dist/index8.js +0 -90
  269. package/dist/index8.js.map +0 -1
  270. package/dist/index9.js +0 -76
  271. package/dist/index9.js.map +0 -1
  272. package/src/components/gui/dialogbox/itemMenu.ce +0 -23
  273. package/src/components/gui/dialogbox/selection.ce +0 -67
  274. package/src/components/scenes/element-map.ce +0 -23
  275. /package/src/components/{effects → animations}/hit.ce +0 -0
package/src/module.ts CHANGED
@@ -1,14 +1,69 @@
1
1
  import { findModules, provideModules } from "@rpgjs/common";
2
+ import { FactoryProvider } from "@signe/di";
2
3
  import { RpgClientEngine } from "./RpgClientEngine";
3
4
  import { RpgClient } from "./RpgClient";
4
5
  import { inject } from "@signe/di";
5
6
  import { RpgGui } from "./Gui/Gui";
7
+ import { getSoundMetadata } from "./Sound";
6
8
 
7
- export function provideClientModules(modules: RpgClient[]) {
9
+ /**
10
+ * Type for client modules that can be either:
11
+ * - An object implementing RpgClient interface
12
+ * - A class decorated with @RpgModule decorator
13
+ */
14
+ export type RpgClientModule = RpgClient | (new () => any);
15
+
16
+ /**
17
+ * Provides client modules configuration to Dependency Injection
18
+ *
19
+ * This function accepts an array of client modules that can be either:
20
+ * - Objects implementing the RpgClient interface
21
+ * - Classes decorated with the @RpgModule decorator (which will be instantiated)
22
+ *
23
+ * @param modules - Array of client modules (objects or classes)
24
+ * @returns FactoryProvider configuration for DI
25
+ * @example
26
+ * ```ts
27
+ * // Using an object
28
+ * provideClientModules([
29
+ * {
30
+ * engine: {
31
+ * onConnected(engine) {
32
+ * console.log('Client connected')
33
+ * }
34
+ * }
35
+ * }
36
+ * ])
37
+ *
38
+ * // Using a decorated class
39
+ * @RpgModule<RpgClient>({
40
+ * engine: {
41
+ * onStart(engine) {
42
+ * console.log('Client started')
43
+ * }
44
+ * }
45
+ * })
46
+ * class MyClientModule {}
47
+ *
48
+ * provideClientModules([MyClientModule])
49
+ * ```
50
+ */
51
+ export function provideClientModules(modules: RpgClientModule[]): FactoryProvider {
8
52
  return provideModules(modules, "client", (modules, context) => {
9
53
  const mainModuleClient = findModules(context, 'Client')
10
54
  modules = [...mainModuleClient, ...modules]
11
55
  modules = modules.map((module) => {
56
+ // If module is a class (constructor function), instantiate it
57
+ // The RpgModule decorator adds properties to the prototype, which will be accessible via the instance
58
+ if (typeof module === 'function') {
59
+ const instance = new module() as any;
60
+ // Copy all enumerable properties (including from prototype) to a plain object
61
+ const moduleObj: any = {};
62
+ for (const key in instance) {
63
+ moduleObj[key] = instance[key];
64
+ }
65
+ module = moduleObj;
66
+ }
12
67
  if ('client' in module) {
13
68
  module = module.client as any;
14
69
  }
@@ -22,33 +77,95 @@ export function provideClientModules(modules: RpgClient[]) {
22
77
  },
23
78
  };
24
79
  }
80
+ if (module.spritesheetResolver) {
81
+ const resolver = module.spritesheetResolver;
82
+ module.spritesheetResolver = {
83
+ load: (engine: RpgClientEngine) => {
84
+ engine.setSpritesheetResolver(resolver);
85
+ },
86
+ };
87
+ }
25
88
  if (module.sounds) {
26
89
  const sounds = [...module.sounds];
27
90
  module.sounds = {
28
91
  load: (engine: RpgClientEngine) => {
29
92
  sounds.forEach((sound) => {
30
- engine.addSound(sound);
93
+ // Check if it's a class decorated with @Sound
94
+ if (typeof sound === 'function' || (sound && sound.constructor && sound.constructor !== Object)) {
95
+ const metadata = getSoundMetadata(sound);
96
+ if (metadata) {
97
+ // Handle single sound
98
+ if (metadata.id && metadata.sound) {
99
+ engine.addSound({
100
+ id: metadata.id,
101
+ src: metadata.sound,
102
+ loop: metadata.loop,
103
+ volume: metadata.volume,
104
+ });
105
+ }
106
+ // Handle multiple sounds
107
+ if (metadata.sounds) {
108
+ Object.entries(metadata.sounds).forEach(([soundId, soundSrc]) => {
109
+ engine.addSound({
110
+ id: soundId,
111
+ src: soundSrc,
112
+ loop: metadata.loop,
113
+ volume: metadata.volume,
114
+ });
115
+ });
116
+ }
117
+ } else {
118
+ // Not a decorated class, treat as regular sound object
119
+ engine.addSound(sound);
120
+ }
121
+ } else {
122
+ // Regular sound object
123
+ engine.addSound(sound);
124
+ }
31
125
  });
32
126
  },
33
127
  };
34
128
  }
129
+ if (module.soundResolver) {
130
+ const resolver = module.soundResolver;
131
+ module.soundResolver = {
132
+ load: (engine: RpgClientEngine) => {
133
+ engine.setSoundResolver(resolver);
134
+ },
135
+ };
136
+ }
35
137
  if (module.gui) {
36
138
  const gui = [...module.gui];
37
139
  module.gui = {
38
140
  load: (engine: RpgClientEngine) => {
39
- const guiService = inject(engine.context, RpgGui);
141
+ const guiService = inject(engine.context, RpgGui) as RpgGui;
40
142
  gui.forEach((gui) => {
41
143
  guiService.add(gui);
42
144
  });
43
145
  },
44
146
  };
45
147
  }
46
- if (module.effects) {
47
- const effects = [...module.effects];
48
- module.effects = {
148
+ if (module.componentAnimations) {
149
+ const componentAnimations = [...module.componentAnimations];
150
+ module.componentAnimations = {
49
151
  load: (engine: RpgClientEngine) => {
50
- effects.forEach((effect) => {
51
- engine.addEffect(effect);
152
+ componentAnimations.forEach((componentAnimation) => {
153
+ engine.addComponentAnimation(componentAnimation);
154
+ });
155
+ },
156
+ };
157
+ }
158
+ if (module.transitions) {
159
+ const transitions = [...module.transitions];
160
+ module.transitions = {
161
+ load: (engine: RpgClientEngine) => {
162
+ const guiService = inject(engine.context, RpgGui) as RpgGui;
163
+ transitions.forEach((transition) => {
164
+ guiService.add({
165
+ name: transition.id,
166
+ component: transition.component,
167
+ data: transition.props || {}
168
+ });
52
169
  });
53
170
  },
54
171
  };
@@ -63,6 +180,24 @@ export function provideClientModules(modules: RpgClient[]) {
63
180
  },
64
181
  };
65
182
  }
183
+ if (module.sprite) {
184
+ const sprite = {...module.sprite};
185
+ module.sprite = {
186
+ ...sprite,
187
+ load: (engine: RpgClientEngine) => {
188
+ if (sprite.componentsBehind) {
189
+ sprite.componentsBehind.forEach((component) => {
190
+ engine.addSpriteComponentBehind(component);
191
+ });
192
+ }
193
+ if (sprite.componentsInFront) {
194
+ sprite.componentsInFront.forEach((component) => {
195
+ engine.addSpriteComponentInFront(component);
196
+ });
197
+ }
198
+ },
199
+ };
200
+ }
66
201
  return module;
67
202
  });
68
203
  return modules
@@ -85,7 +220,8 @@ export function provideClientGlobalConfig(config: any = {}) {
85
220
  down: 'down',
86
221
  left: 'left',
87
222
  right: 'right',
88
- action: 'space'
223
+ action: 'space',
224
+ escape: 'escape'
89
225
  }
90
226
  }
91
227
  return provideGlobalConfig(config)
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Creates an animation spritesheet preset with automatic frame generation
3
+ *
4
+ * This function generates animation frames based on the provided width and height dimensions.
5
+ * It creates a sequence of frames that progresses through the spritesheet from left to right,
6
+ * top to bottom, with each frame having a 10ms time increment.
7
+ *
8
+ * @param {number} framesWidth - The number of frames horizontally in the spritesheet
9
+ * @param {number} framesHeight - The number of frames vertically in the spritesheet
10
+ * @returns {Object} Animation preset configuration object
11
+ *
12
+ * @example
13
+ * ```javascript
14
+ * // For a 4x4 spritesheet
15
+ * const preset = AnimationSpritesheetPreset(4, 4);
16
+ * // This will generate 16 frames with coordinates from (0,0) to (3,3)
17
+ * ```
18
+ */
19
+ export const AnimationSpritesheetPreset = (framesWidth: number, framesHeight: number) => {
20
+
21
+ const animations: Array<{ time: number; frameX: number; frameY: number }> = [];
22
+
23
+ for (let y = 0; y < framesHeight; y++) {
24
+ for (let x = 0; x < framesWidth; x++) {
25
+ const frameIndex = y * framesWidth + x;
26
+ animations.push({
27
+ time: frameIndex * 10,
28
+ frameX: x,
29
+ frameY: y
30
+ });
31
+ }
32
+ }
33
+
34
+ return {
35
+ framesWidth,
36
+ framesHeight,
37
+ textures: {
38
+ default: {
39
+ animations: () => [
40
+ animations
41
+ ],
42
+ }
43
+ }
44
+ };
45
+ };
46
+
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Creates a faceset preset for character expressions
3
+ *
4
+ * This preset allows you to define multiple facial expressions for a character,
5
+ * where each expression corresponds to a specific frame position (frameX, frameY)
6
+ * within a single faceset texture. Each expression is defined by its position
7
+ * in the faceset grid.
8
+ *
9
+ * @param options - Object containing the faceset configuration
10
+ * @param framesWidth - Number of frames horizontally in the faceset texture
11
+ * @param framesHeight - Number of frames vertically in the faceset texture
12
+ * @param expressions - Object mapping expression names to their frame positions as tuples [frameX, frameY]
13
+ * @returns Faceset configuration with animations for each expression
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const faceset = FacesetPreset({
18
+ * id: "facesetId",
19
+ * image: "faceset.png",
20
+ * width: 1024,
21
+ * height: 1024,
22
+ * }, 4, 2, {
23
+ * happy: [0, 0],
24
+ * sad: [1, 0],
25
+ * angry: [2, 0],
26
+ * surprised: [3, 0]
27
+ * });
28
+ * ```
29
+ */
30
+ export const FacesetPreset = (
31
+ options: any,
32
+ framesWidth: number,
33
+ framesHeight: number,
34
+ expressions: Record<string, [number, number]>,
35
+ ) => {
36
+
37
+ const textures: Record<string, any> = {};
38
+
39
+ // Create texture configuration for each expression
40
+ Object.keys(expressions).forEach((expressionName) => {
41
+ const [frameX, frameY] = expressions[expressionName];
42
+ textures[expressionName] = {
43
+ animations: () => [
44
+ [{
45
+ time: 0,
46
+ frameX: frameX,
47
+ frameY: frameY
48
+ }]
49
+ ],
50
+ };
51
+ });
52
+
53
+ return {
54
+ ...options,
55
+ framesWidth,
56
+ framesHeight,
57
+ textures
58
+ };
59
+ };
60
+
@@ -0,0 +1,17 @@
1
+ export const IconPreset = (options: {
2
+ image: string;
3
+ framesWidth: number;
4
+ framesHeight: number;
5
+ id: string;
6
+ }) => {
7
+ return {
8
+ textures: {
9
+ default: {
10
+ animations: () => [
11
+ [{ time: 0, frameX: 0, frameY: 0 }]
12
+ ]
13
+ }
14
+ },
15
+ ...options
16
+ }
17
+ }
@@ -1,5 +1,13 @@
1
+ import { AnimationSpritesheetPreset } from "./animation";
2
+ import { LPCSpritesheetPreset } from "./lpc";
1
3
  import { RMSpritesheet } from "./rmspritesheet";
4
+ import { FacesetPreset } from "./faceset";
5
+ import { IconPreset } from "./icon";
2
6
 
3
7
  export const Presets = {
4
- RMSpritesheet
8
+ RMSpritesheet,
9
+ LPCSpritesheetPreset,
10
+ AnimationSpritesheetPreset,
11
+ FacesetPreset,
12
+ IconPreset
5
13
  }
@@ -0,0 +1,108 @@
1
+ import { Animation, Direction } from "@rpgjs/common";
2
+
3
+ export const LPCSpritesheetPreset = (options: {
4
+ id: string;
5
+ imageSource: string;
6
+ width: number;
7
+ height: number;
8
+ ratio?: number;
9
+ }) => {
10
+ const ratio = options.ratio ?? 1;
11
+
12
+ const frameY = (direction: Direction) => {
13
+ return {
14
+ [Direction.Down]: 2,
15
+ [Direction.Left]: 1,
16
+ [Direction.Right]: 3,
17
+ [Direction.Up]: 0,
18
+ }[direction];
19
+ };
20
+
21
+ const stand = (direction: Direction) => [
22
+ { time: 0, frameX: 0, frameY: frameY(direction) },
23
+ ];
24
+ const anim = (
25
+ direction: Direction,
26
+ framesWidth: number,
27
+ speed: number = 5
28
+ ) => {
29
+ const array: any = [];
30
+ for (let i = 0; i < framesWidth; i++) {
31
+ array.push({ time: i * speed, frameX: i, frameY: frameY(direction) });
32
+ }
33
+ return array;
34
+ };
35
+
36
+ return {
37
+ id: options.id,
38
+ image: options.imageSource,
39
+ width: options.width,
40
+ height: options.height,
41
+ opacity: 1,
42
+ rectWidth: 64 * ratio,
43
+ rectHeight: 64 * ratio,
44
+ framesWidth: 6,
45
+ framesHeight: 4,
46
+ spriteRealSize: {
47
+ width: 48 * ratio,
48
+ height: 52 * ratio,
49
+ },
50
+ textures: {
51
+ [Animation.Stand]: {
52
+ offset: {
53
+ x: 0,
54
+ y: 512 * ratio,
55
+ },
56
+ animations: ({ direction }) => [stand(direction)],
57
+ },
58
+ [Animation.Walk]: {
59
+ offset: {
60
+ x: 0,
61
+ y: 512 * ratio,
62
+ },
63
+ framesWidth: 9,
64
+ framesHeight: 4,
65
+ animations: ({ direction }) => [anim(direction, 9)],
66
+ },
67
+ [Animation.Attack]: {
68
+ offset: {
69
+ x: 0,
70
+ y: 768 * ratio,
71
+ },
72
+ framesWidth: 6,
73
+ framesHeight: 4,
74
+ animations: ({ direction }) => [anim(direction, 6, 3)],
75
+ },
76
+ [Animation.Skill]: {
77
+ framesWidth: 7,
78
+ framesHeight: 4,
79
+ animations: ({ direction }) => [anim(direction, 7, 3)],
80
+ },
81
+ attack2: {
82
+ offset: {
83
+ x: 0,
84
+ y: 256 * ratio,
85
+ },
86
+ framesWidth: 7,
87
+ framesHeight: 8,
88
+ animations: ({ direction }) => [anim(direction, 7, 3)],
89
+ },
90
+ ...(options.height > 3000
91
+ ? {
92
+ attack3: {
93
+ offset: {
94
+ x: 0,
95
+ y: 5568 - 288 * 4,
96
+ },
97
+ rectWidth: 288,
98
+ rectHeight: 288,
99
+ framesWidth: 6,
100
+ framesHeight: 4,
101
+ animations: ({ direction }) => [anim(direction, 6, 3)],
102
+ },
103
+ }
104
+ : {}),
105
+ },
106
+ };
107
+ };
108
+
@@ -0,0 +1,20 @@
1
+ import { KeyboardControls } from "canvasengine";
2
+
3
+ export enum Control {
4
+ Action = 'action',
5
+ Attack = 'attack',
6
+ Defense = 'defense',
7
+ Skill = 'skill',
8
+ Back = 'back',
9
+ Up = 1,
10
+ Down = 3,
11
+ Right = 2,
12
+ Left = 4
13
+ }
14
+
15
+ export function provideKeyboardControls() {
16
+ return {
17
+ provide: 'KeyboardControls',
18
+ useValue: null,
19
+ };
20
+ }
@@ -3,27 +3,156 @@ import { UpdateMapToken, UpdateMapService } from "@rpgjs/common";
3
3
 
4
4
  export const LoadMapToken = 'LoadMapToken'
5
5
 
6
- export type LoadMapOptions = (mapId: string) => Promise<void>
6
+ /**
7
+ * Represents the structure of map data that should be returned by the load map callback.
8
+ * This interface defines all the properties that can be provided when loading a custom map.
9
+ *
10
+ * @interface MapData
11
+ */
12
+ type MapData = {
13
+ /** Raw map data that will be passed to the map component */
14
+ data: any;
15
+ /** CanvasEngine component that will render the map */
16
+ component: any;
17
+ /** Optional map width in pixels, used for viewport calculations */
18
+ width?: number;
19
+ /** Optional map height in pixels, used for viewport calculations */
20
+ height?: number;
21
+ /** Optional map events data (NPCs, interactive objects, etc.) */
22
+ events?: any;
23
+ /** Optional map identifier, defaults to the mapId parameter if not provided */
24
+ id?: string;
25
+ }
26
+
27
+ /**
28
+ * Callback function type for loading map data.
29
+ * This function receives a map ID and should return either a MapData object directly
30
+ * or a Promise that resolves to a MapData object.
31
+ *
32
+ * @callback LoadMapOptions
33
+ * @param {string} mapId - The identifier of the map to load
34
+ * @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it
35
+ */
36
+ export type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData
7
37
 
8
38
  export class LoadMapService {
9
39
  private updateMapService: UpdateMapService;
10
40
 
11
41
  constructor(private context: Context, private options: LoadMapOptions) {
42
+ if (context['side'] === 'server') {
43
+ return
44
+ }
12
45
  this.updateMapService = inject(context, UpdateMapToken);
13
46
  }
14
47
 
15
48
  async load(mapId: string) {
16
49
  const map = await this.options(mapId.replace('map-', ''))
17
- await this.updateMapService.update(mapId, map);
50
+ await this.updateMapService.update(map);
18
51
  return map;
19
52
  }
20
53
  }
21
54
 
55
+ /**
56
+ * Creates a dependency injection configuration for custom map loading on the client side.
57
+ *
58
+ * This function allows you to customize how maps are loaded and displayed by providing
59
+ * a callback that defines custom map data and rendering components. It's designed to work
60
+ * with the RPG-JS dependency injection system and enables integration of custom map formats
61
+ * like Tiled TMX files or any other map data structure.
62
+ *
63
+ * The function sets up the necessary service providers for map loading, including:
64
+ * - UpdateMapToken: Handles map updates in the client context
65
+ * - LoadMapToken: Provides the LoadMapService with your custom loading logic
66
+ *
67
+ * **Design Concept:**
68
+ * The function follows the provider pattern, creating a modular way to inject custom
69
+ * map loading behavior into the RPG-JS client engine. It separates the concern of
70
+ * map data fetching from map rendering, allowing developers to focus on their specific
71
+ * map format while leveraging the engine's rendering capabilities.
72
+ *
73
+ * @param {LoadMapOptions} options - Callback function that handles map loading logic
74
+ * @returns {Array<Object>} Array of dependency injection provider configurations
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * import { provideLoadMap } from '@rpgjs/client'
79
+ * import { createModule } from '@rpgjs/common'
80
+ * import MyTiledMapComponent from './MyTiledMapComponent.ce'
81
+ *
82
+ * // Basic usage with JSON map data
83
+ * export function provideCustomMap() {
84
+ * return createModule("CustomMap", [
85
+ * provideLoadMap(async (mapId) => {
86
+ * const response = await fetch(`/maps/${mapId}.json`)
87
+ * const mapData = await response.json()
88
+ *
89
+ * return {
90
+ * data: mapData,
91
+ * component: MyTiledMapComponent,
92
+ * width: mapData.width,
93
+ * height: mapData.height,
94
+ * events: mapData.events
95
+ * }
96
+ * })
97
+ * ])
98
+ * }
99
+ *
100
+ * // Advanced usage with Tiled TMX files
101
+ * export function provideTiledMap() {
102
+ * return createModule("TiledMap", [
103
+ * provideLoadMap(async (mapId) => {
104
+ * // Load TMX file
105
+ * const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)
106
+ * const tmxData = await tmxResponse.text()
107
+ *
108
+ * // Parse TMX data (using a TMX parser)
109
+ * const parsedMap = parseTMX(tmxData)
110
+ *
111
+ * return {
112
+ * data: parsedMap,
113
+ * component: TiledMapRenderer,
114
+ * width: parsedMap.width * parsedMap.tilewidth,
115
+ * height: parsedMap.height * parsedMap.tileheight,
116
+ * events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects
117
+ * }
118
+ * })
119
+ * ])
120
+ * }
121
+ *
122
+ * // Synchronous usage for static maps
123
+ * export function provideStaticMap() {
124
+ * return createModule("StaticMap", [
125
+ * provideLoadMap((mapId) => {
126
+ * const staticMaps = {
127
+ * 'town': { tiles: [...], npcs: [...] },
128
+ * 'dungeon': { tiles: [...], monsters: [...] }
129
+ * }
130
+ *
131
+ * return {
132
+ * data: staticMaps[mapId],
133
+ * component: StaticMapComponent,
134
+ * width: 800,
135
+ * height: 600
136
+ * }
137
+ * })
138
+ * ])
139
+ * }
140
+ * ```
141
+ *
142
+ * @since 4.0.0
143
+ * @see {@link LoadMapOptions} for callback function signature
144
+ * @see {@link MapData} for return data structure
145
+ */
22
146
  export function provideLoadMap(options: LoadMapOptions) {
23
147
  return [
24
148
  {
25
149
  provide: UpdateMapToken,
26
- useFactory: (context: Context) => console.warn('UpdateMapToken is not overridden'),
150
+ useFactory: (context: Context) => {
151
+ if (context['side'] === 'client') {
152
+ console.warn('UpdateMapToken is not overridden')
153
+ }
154
+ return
155
+ },
27
156
  },
28
157
  {
29
158
  provide: LoadMapToken,