@rpgjs/client 5.0.0-alpha.23 → 5.0.0-alpha.25

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 (187) hide show
  1. package/dist/{index30.js → Game/AnimationManager.js} +1 -1
  2. package/dist/Game/AnimationManager.js.map +1 -0
  3. package/dist/{index24.js → Game/Event.js} +2 -2
  4. package/dist/Game/Event.js.map +1 -0
  5. package/dist/{index29.js → Game/Map.js} +6 -6
  6. package/dist/Game/Map.js.map +1 -0
  7. package/dist/{index22.js → Game/Object.js} +4 -4
  8. package/dist/Game/Object.js.map +1 -0
  9. package/dist/{index23.js → Game/Player.js} +2 -2
  10. package/dist/Game/Player.js.map +1 -0
  11. package/dist/{index9.js → Gui/Gui.js} +10 -11
  12. package/dist/{index9.js.map → Gui/Gui.js.map} +1 -1
  13. package/dist/{index19.js → Resource.js} +1 -1
  14. package/dist/Resource.js.map +1 -0
  15. package/dist/RpgClientEngine.d.ts +66 -115
  16. package/dist/{index2.js → RpgClientEngine.js} +234 -176
  17. package/dist/RpgClientEngine.js.map +1 -0
  18. package/dist/{index18.js → Sound.js} +1 -1
  19. package/dist/Sound.js.map +1 -0
  20. package/dist/{index35.js → components/animations/animation.ce.js} +3 -3
  21. package/dist/components/animations/animation.ce.js.map +1 -0
  22. package/dist/{index34.js → components/animations/hit.ce.js} +1 -1
  23. package/dist/components/animations/hit.ce.js.map +1 -0
  24. package/dist/{index12.js → components/animations/index.js} +3 -3
  25. package/dist/components/animations/index.js.map +1 -0
  26. package/dist/{index17.js → components/character.ce.js} +4 -4
  27. package/dist/components/character.ce.js.map +1 -0
  28. package/dist/{index51.js → components/dynamics/parse-value.js} +1 -1
  29. package/dist/components/dynamics/parse-value.js.map +1 -0
  30. package/dist/{index40.js → components/dynamics/text.ce.js} +2 -2
  31. package/dist/components/dynamics/text.ce.js.map +1 -0
  32. package/dist/{index11.js → components/gui/box.ce.js} +8 -8
  33. package/dist/components/gui/box.ce.js.map +1 -0
  34. package/dist/{index10.js → components/gui/dialogbox/index.ce.js} +4 -4
  35. package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
  36. package/dist/{index52.js → components/gui/dialogbox/itemMenu.ce.js} +1 -1
  37. package/dist/components/gui/dialogbox/itemMenu.ce.js.map +1 -0
  38. package/dist/{index47.js → components/gui/dialogbox/selection.ce.js} +4 -4
  39. package/dist/components/gui/dialogbox/selection.ce.js.map +1 -0
  40. package/dist/components/gui/mobile/index.d.ts +1 -1
  41. package/dist/{index25.js → components/gui/mobile/index.js} +5 -5
  42. package/dist/components/gui/mobile/index.js.map +1 -0
  43. package/dist/components/gui/mobile/mobile.ce.js +17 -0
  44. package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
  45. package/dist/{index13.js → components/prebuilt/hp-bar.ce.js} +1 -1
  46. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
  47. package/dist/{index14.js → components/prebuilt/light-halo.ce.js} +2 -3
  48. package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
  49. package/dist/{index26.js → components/scenes/canvas.ce.js} +6 -7
  50. package/dist/components/scenes/canvas.ce.js.map +1 -0
  51. package/dist/{index46.js → components/scenes/draw-map.ce.js} +3 -3
  52. package/dist/components/scenes/draw-map.ce.js.map +1 -0
  53. package/dist/{index16.js → components/scenes/event-layer.ce.js} +4 -4
  54. package/dist/components/scenes/event-layer.ce.js.map +1 -0
  55. package/dist/{index6.js → core/inject.js} +2 -2
  56. package/dist/core/inject.js.map +1 -0
  57. package/dist/{index5.js → core/setup.js} +4 -4
  58. package/dist/core/setup.js.map +1 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +25 -24
  61. package/dist/index.js.map +1 -1
  62. package/dist/{index8.js → module.js} +10 -5
  63. package/dist/module.js.map +1 -0
  64. package/dist/{index20.js → node_modules/.pnpm/@signe_di@2.6.0/node_modules/@signe/di/dist/index.js} +1 -1
  65. package/dist/node_modules/.pnpm/@signe_di@2.6.0/node_modules/@signe/di/dist/index.js.map +1 -0
  66. package/dist/{index45.js → node_modules/.pnpm/@signe_reactive@2.6.0/node_modules/@signe/reactive/dist/index.js} +216 -11
  67. package/dist/node_modules/.pnpm/@signe_reactive@2.6.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
  68. package/dist/{index32.js → node_modules/.pnpm/@signe_room@2.6.0/node_modules/@signe/room/dist/index.js} +29 -30
  69. package/dist/node_modules/.pnpm/@signe_room@2.6.0/node_modules/@signe/room/dist/index.js.map +1 -0
  70. package/dist/{index42.js → node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js} +1 -1
  71. package/dist/node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +1 -0
  72. package/dist/{index33.js → node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/client/index.js} +5 -5
  73. package/dist/node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  74. package/dist/{index28.js → node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/index.js} +3 -3
  75. package/dist/node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/index.js.map +1 -0
  76. package/dist/{index48.js → node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js} +1 -1
  77. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +1 -0
  78. package/dist/{index43.js → node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js} +2 -15
  79. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
  80. package/dist/{index44.js → node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js} +2 -5
  81. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
  82. package/dist/{index50.js → node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js} +813 -100
  83. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
  84. package/dist/{index36.js → presets/animation.js} +1 -1
  85. package/dist/presets/animation.js.map +1 -0
  86. package/dist/{index39.js → presets/faceset.js} +1 -1
  87. package/dist/presets/faceset.js.map +1 -0
  88. package/dist/presets/index.js +14 -0
  89. package/dist/presets/index.js.map +1 -0
  90. package/dist/{index37.js → presets/lpc.js} +1 -1
  91. package/dist/presets/lpc.js.map +1 -0
  92. package/dist/{index38.js → presets/rmspritesheet.js} +1 -1
  93. package/dist/presets/rmspritesheet.js.map +1 -0
  94. package/dist/{index27.js → services/AbstractSocket.js} +1 -1
  95. package/dist/services/AbstractSocket.js.map +1 -0
  96. package/dist/{index21.js → services/keyboardControls.js} +1 -1
  97. package/dist/services/keyboardControls.js.map +1 -0
  98. package/dist/{index7.js → services/loadMap.js} +2 -2
  99. package/dist/services/loadMap.js.map +1 -0
  100. package/dist/{index4.js → services/mmorpg.js} +6 -6
  101. package/dist/services/mmorpg.js.map +1 -0
  102. package/dist/services/standalone.d.ts +3 -0
  103. package/dist/{index3.js → services/standalone.js} +18 -12
  104. package/dist/services/standalone.js.map +1 -0
  105. package/package.json +9 -9
  106. package/src/Gui/Gui.ts +0 -1
  107. package/src/RpgClientEngine.ts +298 -182
  108. package/src/components/character.ce +2 -3
  109. package/src/components/gui/mobile/index.ts +1 -1
  110. package/src/components/gui/mobile/mobile.ce +73 -88
  111. package/src/components/prebuilt/light-halo.ce +2 -71
  112. package/src/components/scenes/canvas.ce +0 -10
  113. package/src/components/scenes/event-layer.ce +1 -0
  114. package/src/index.ts +2 -1
  115. package/src/module.ts +6 -1
  116. package/src/services/standalone.ts +16 -7
  117. package/vite.config.ts +4 -2
  118. package/dist/Game/TransitionManager.d.ts +0 -56
  119. package/dist/index10.js.map +0 -1
  120. package/dist/index11.js.map +0 -1
  121. package/dist/index12.js.map +0 -1
  122. package/dist/index13.js.map +0 -1
  123. package/dist/index14.js.map +0 -1
  124. package/dist/index15.js +0 -14
  125. package/dist/index15.js.map +0 -1
  126. package/dist/index16.js.map +0 -1
  127. package/dist/index17.js.map +0 -1
  128. package/dist/index18.js.map +0 -1
  129. package/dist/index19.js.map +0 -1
  130. package/dist/index2.js.map +0 -1
  131. package/dist/index20.js.map +0 -1
  132. package/dist/index21.js.map +0 -1
  133. package/dist/index22.js.map +0 -1
  134. package/dist/index23.js.map +0 -1
  135. package/dist/index24.js.map +0 -1
  136. package/dist/index25.js.map +0 -1
  137. package/dist/index26.js.map +0 -1
  138. package/dist/index27.js.map +0 -1
  139. package/dist/index28.js.map +0 -1
  140. package/dist/index29.js.map +0 -1
  141. package/dist/index3.js.map +0 -1
  142. package/dist/index30.js.map +0 -1
  143. package/dist/index31.js +0 -53
  144. package/dist/index31.js.map +0 -1
  145. package/dist/index32.js.map +0 -1
  146. package/dist/index33.js.map +0 -1
  147. package/dist/index34.js.map +0 -1
  148. package/dist/index35.js.map +0 -1
  149. package/dist/index36.js.map +0 -1
  150. package/dist/index37.js.map +0 -1
  151. package/dist/index38.js.map +0 -1
  152. package/dist/index39.js.map +0 -1
  153. package/dist/index4.js.map +0 -1
  154. package/dist/index40.js.map +0 -1
  155. package/dist/index41.js +0 -43
  156. package/dist/index41.js.map +0 -1
  157. package/dist/index42.js.map +0 -1
  158. package/dist/index43.js.map +0 -1
  159. package/dist/index44.js.map +0 -1
  160. package/dist/index45.js.map +0 -1
  161. package/dist/index46.js.map +0 -1
  162. package/dist/index47.js.map +0 -1
  163. package/dist/index48.js.map +0 -1
  164. package/dist/index49.js +0 -7
  165. package/dist/index49.js.map +0 -1
  166. package/dist/index5.js.map +0 -1
  167. package/dist/index50.js.map +0 -1
  168. package/dist/index51.js.map +0 -1
  169. package/dist/index52.js.map +0 -1
  170. package/dist/index53.js +0 -6
  171. package/dist/index53.js.map +0 -1
  172. package/dist/index54.js +0 -12
  173. package/dist/index54.js.map +0 -1
  174. package/dist/index55.js +0 -113
  175. package/dist/index55.js.map +0 -1
  176. package/dist/index56.js +0 -136
  177. package/dist/index56.js.map +0 -1
  178. package/dist/index57.js +0 -137
  179. package/dist/index57.js.map +0 -1
  180. package/dist/index58.js +0 -112
  181. package/dist/index58.js.map +0 -1
  182. package/dist/index59.js +0 -9
  183. package/dist/index59.js.map +0 -1
  184. package/dist/index6.js.map +0 -1
  185. package/dist/index7.js.map +0 -1
  186. package/dist/index8.js.map +0 -1
  187. package/src/Game/TransitionManager.ts +0 -75
@@ -1,20 +1,19 @@
1
- import component from './index26.js';
2
- import { inject } from './index6.js';
1
+ import component from './components/scenes/canvas.ce.js';
2
+ import { inject } from './core/inject.js';
3
3
  import { signal, trigger, bootstrapCanvas, Howl } from 'canvasengine';
4
- import { WebSocketToken } from './index27.js';
5
- import { LoadMapToken } from './index7.js';
6
- import { RpgSound } from './index18.js';
7
- import { RpgResource } from './index19.js';
4
+ import { WebSocketToken } from './services/AbstractSocket.js';
5
+ import { LoadMapToken } from './services/loadMap.js';
6
+ import { RpgSound } from './Sound.js';
7
+ import { RpgResource } from './Resource.js';
8
8
  import { Direction, PredictionController, ModulesToken } from '@rpgjs/common';
9
- import { load } from './index28.js';
10
- import { RpgClientMap } from './index29.js';
11
- import { RpgGui } from './index9.js';
12
- import { AnimationManager } from './index30.js';
13
- import { TransitionManager } from './index31.js';
14
- import { lastValueFrom } from 'rxjs';
15
- import { GlobalConfigToken } from './index8.js';
9
+ import { load } from './node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/index.js';
10
+ import { RpgClientMap } from './Game/Map.js';
11
+ import { RpgGui } from './Gui/Gui.js';
12
+ import { AnimationManager } from './Game/AnimationManager.js';
13
+ import { BehaviorSubject, lastValueFrom, combineLatest, filter, take, switchMap } from 'rxjs';
14
+ import { GlobalConfigToken } from './module.js';
16
15
  import * as PIXI from 'pixi.js';
17
- import { PrebuiltComponentAnimations } from './index12.js';
16
+ import { PrebuiltComponentAnimations } from './components/animations/index.js';
18
17
 
19
18
  class RpgClientEngine {
20
19
  constructor(context) {
@@ -25,7 +24,6 @@ class RpgClientEngine {
25
24
  this.spritesheets = /* @__PURE__ */ new Map();
26
25
  this.sounds = /* @__PURE__ */ new Map();
27
26
  this.componentAnimations = [];
28
- this.transitions = [];
29
27
  this.particleSettings = {
30
28
  emitters: []
31
29
  };
@@ -36,6 +34,7 @@ class RpgClientEngine {
36
34
  this.cameraFollowTargetId = signal(null);
37
35
  /** Trigger for map shake animation */
38
36
  this.mapShakeTrigger = trigger();
37
+ this.controlsReady = signal(void 0);
39
38
  this.predictionEnabled = false;
40
39
  this.SERVER_CORRECTION_THRESHOLD = 30;
41
40
  this.inputFrameCounter = 0;
@@ -47,6 +46,13 @@ class RpgClientEngine {
47
46
  this.PING_INTERVAL_MS = 5e3;
48
47
  // Send ping every 5 seconds
49
48
  this.lastInputTime = 0;
49
+ // Track map loading state for onAfterLoading hook using RxJS
50
+ this.mapLoadCompleted$ = new BehaviorSubject(false);
51
+ this.playerIdReceived$ = new BehaviorSubject(false);
52
+ this.playersReceived$ = new BehaviorSubject(false);
53
+ this.eventsReceived$ = new BehaviorSubject(false);
54
+ // Store subscriptions and event listeners for cleanup
55
+ this.tickSubscriptions = [];
50
56
  this.webSocket = inject(WebSocketToken);
51
57
  this.guiService = inject(RpgGui);
52
58
  this.loadMapService = inject(LoadMapToken);
@@ -110,20 +116,24 @@ class RpgClientEngine {
110
116
  ...currentValues,
111
117
  values: /* @__PURE__ */ new Map([["__default__", controlInstance]])
112
118
  };
119
+ this.controlsReady.set(void 0);
113
120
  }
114
121
  async start() {
115
122
  this.sceneMap = new RpgClientMap();
116
123
  this.selector = document.body.querySelector("#rpg");
117
124
  const { app, canvasElement } = await bootstrapCanvas(this.selector, component);
125
+ this.canvasApp = app;
126
+ this.canvasElement = canvasElement;
118
127
  this.renderer = app.renderer;
119
128
  this.tick = canvasElement?.propObservables?.context["tick"].observable;
120
- this.tick.subscribe(() => {
129
+ const inputCheckSubscription = this.tick.subscribe(() => {
121
130
  if (Date.now() - this.lastInputTime > 100) {
122
131
  const player = this.getCurrentPlayer();
123
132
  if (!player) return;
124
133
  this.sceneMap.stopMovement(player);
125
134
  }
126
135
  });
136
+ this.tickSubscriptions.push(inputCheckSubscription);
127
137
  this.hooks.callHooks("client-spritesheets-load", this).subscribe();
128
138
  this.hooks.callHooks("client-spritesheetResolver-load", this).subscribe();
129
139
  this.hooks.callHooks("client-sounds-load", this).subscribe();
@@ -133,13 +143,13 @@ class RpgClientEngine {
133
143
  this.hooks.callHooks("client-gui-load", this).subscribe();
134
144
  this.hooks.callHooks("client-particles-load", this).subscribe();
135
145
  this.hooks.callHooks("client-componentAnimations-load", this).subscribe();
136
- this.hooks.callHooks("client-transitions-load", this).subscribe();
137
146
  this.hooks.callHooks("client-sprite-load", this).subscribe();
138
147
  await lastValueFrom(this.hooks.callHooks("client-engine-onStart", this));
139
- window.addEventListener("resize", () => {
148
+ this.resizeHandler = () => {
140
149
  this.hooks.callHooks("client-engine-onWindowResize", this).subscribe();
141
- });
142
- this.tick.subscribe((tick) => {
150
+ };
151
+ window.addEventListener("resize", this.resizeHandler);
152
+ const tickSubscription = this.tick.subscribe((tick) => {
143
153
  this.hooks.callHooks("client-engine-onStep", this, tick).subscribe();
144
154
  if (tick % 60 === 0) {
145
155
  const now = Date.now();
@@ -147,6 +157,7 @@ class RpgClientEngine {
147
157
  this.prediction?.tryApplyPendingSnapshot();
148
158
  }
149
159
  });
160
+ this.tickSubscriptions.push(tickSubscription);
150
161
  await this.webSocket.connection(() => {
151
162
  this.initListeners();
152
163
  this.guiService._initialize();
@@ -154,9 +165,20 @@ class RpgClientEngine {
154
165
  }
155
166
  initListeners() {
156
167
  this.webSocket.on("sync", (data) => {
157
- if (data.pId) this.playerIdSignal.set(data.pId);
168
+ if (data.pId) {
169
+ this.playerIdSignal.set(data.pId);
170
+ this.playerIdReceived$.next(true);
171
+ }
158
172
  this.hooks.callHooks("client-sceneMap-onChanges", this.sceneMap, { partial: data }).subscribe();
159
173
  load(this.sceneMap, data, true);
174
+ const players = data.players || this.sceneMap.players();
175
+ if (players && Object.keys(players).length > 0) {
176
+ this.playersReceived$.next(true);
177
+ }
178
+ const events = data.events || this.sceneMap.events();
179
+ if (events !== void 0) {
180
+ this.eventsReceived$.next(true);
181
+ }
160
182
  });
161
183
  this.webSocket.on("pong", (data) => {
162
184
  const now = Date.now();
@@ -292,8 +314,16 @@ class RpgClientEngine {
292
314
  });
293
315
  }
294
316
  async loadScene(mapId) {
295
- this.hooks.callHooks("client-sceneMap-onBeforeLoading", this.sceneMap).subscribe();
317
+ await lastValueFrom(this.hooks.callHooks("client-sceneMap-onBeforeLoading", this.sceneMap));
296
318
  this.clearClientPredictionStates();
319
+ this.mapLoadCompleted$.next(false);
320
+ this.playerIdReceived$.next(false);
321
+ this.playersReceived$.next(false);
322
+ this.eventsReceived$.next(false);
323
+ if (this.onAfterLoadingSubscription) {
324
+ this.onAfterLoadingSubscription.unsubscribe();
325
+ }
326
+ this.setupOnAfterLoadingObserver();
297
327
  this.webSocket.updateProperties({ room: mapId });
298
328
  await this.webSocket.reconnect(() => {
299
329
  this.initListeners();
@@ -301,7 +331,18 @@ class RpgClientEngine {
301
331
  });
302
332
  const res = await this.loadMapService.load(mapId);
303
333
  this.sceneMap.data.set(res);
304
- this.hooks.callHooks("client-sceneMap-onAfterLoading", this.sceneMap).subscribe();
334
+ if (this.playerIdSignal()) {
335
+ this.playerIdReceived$.next(true);
336
+ }
337
+ const players = this.sceneMap.players();
338
+ if (players && Object.keys(players).length > 0) {
339
+ this.playersReceived$.next(true);
340
+ }
341
+ const events = this.sceneMap.events();
342
+ if (events !== void 0) {
343
+ this.eventsReceived$.next(true);
344
+ }
345
+ this.mapLoadCompleted$.next(true);
305
346
  this.sceneMap.loadPhysic();
306
347
  }
307
348
  addSpriteSheet(spritesheetClass, id) {
@@ -788,147 +829,13 @@ class RpgClientEngine {
788
829
  }
789
830
  return componentAnimation.instance;
790
831
  }
791
- /**
792
- * Add a transition to the engine
793
- *
794
- * Transitions are screen effects that can be displayed during scene changes,
795
- * map loading, or any other moment where a visual transition is needed.
796
- * They are displayed on top of the entire canvas and can have custom props
797
- * that can be functions (similar to ComponentAnimation).
798
- *
799
- * @param transition - The transition configuration
800
- * @param transition.id - Unique identifier for the transition
801
- * @param transition.component - The component function to render
802
- * @param transition.props - Optional props to pass to the component (can be a function)
803
- * @returns The added transition configuration
804
- *
805
- * @example
806
- * ```ts
807
- * // Add a fade transition
808
- * engine.addTransition({
809
- * id: 'fade',
810
- * component: FadeComponent
811
- * });
812
- *
813
- * // Add a transition with props
814
- * engine.addTransition({
815
- * id: 'slide',
816
- * component: SlideComponent,
817
- * props: { direction: 'left', duration: 500 }
818
- * });
819
- *
820
- * // Add a transition with function props
821
- * engine.addTransition({
822
- * id: 'custom',
823
- * component: CustomTransition,
824
- * props: (engine) => ({ width: engine.width(), height: engine.height() })
825
- * });
826
- * ```
827
- */
828
- addTransition(transition) {
829
- const instance = new TransitionManager();
830
- this.transitions.push({
831
- id: transition.id,
832
- component: transition.component,
833
- props: transition.props,
834
- instance,
835
- current: instance.current
836
- });
837
- return transition;
838
- }
839
- /**
840
- * Remove a transition from the engine
841
- *
842
- * Removes a transition by its ID. This will not affect any currently
843
- * running transitions, only prevent new ones from being started.
844
- *
845
- * @param id - The unique identifier of the transition to remove
846
- * @returns true if the transition was found and removed, false otherwise
847
- *
848
- * @example
849
- * ```ts
850
- * // Remove a transition
851
- * engine.removeTransition('fade');
852
- * ```
853
- */
854
- removeTransition(id) {
855
- const index = this.transitions.findIndex((transition) => transition.id === id);
856
- if (index !== -1) {
857
- this.transitions.splice(index, 1);
858
- return true;
859
- }
860
- return false;
861
- }
862
- /**
863
- * Modify an existing transition
864
- *
865
- * Updates the component or props of an existing transition. This will
866
- * not affect any currently running transitions, only future ones.
867
- *
868
- * @param id - The unique identifier of the transition to modify
869
- * @param updates - The updates to apply (component and/or props)
870
- * @returns true if the transition was found and modified, false otherwise
871
- *
872
- * @example
873
- * ```ts
874
- * // Update transition props
875
- * engine.modifyTransition('fade', {
876
- * props: { duration: 2000, color: 'white' }
877
- * });
878
- *
879
- * // Update transition component
880
- * engine.modifyTransition('fade', {
881
- * component: NewFadeComponent
882
- * });
883
- * ```
884
- */
885
- modifyTransition(id, updates) {
886
- const transition = this.transitions.find((transition2) => transition2.id === id);
887
- if (!transition) {
888
- return false;
889
- }
890
- if (updates.component !== void 0) {
891
- transition.component = updates.component;
892
- }
893
- if (updates.props !== void 0) {
894
- transition.props = updates.props;
895
- }
896
- return true;
897
- }
898
- /**
899
- * Get a transition by its ID
900
- *
901
- * Retrieves the TransitionManager instance for a specific transition,
902
- * which can be used to start the transition.
903
- *
904
- * @param id - The unique identifier of the transition
905
- * @returns The TransitionManager instance for the transition
906
- * @throws Error if the transition is not found
907
- *
908
- * @example
909
- * ```ts
910
- * // Get a transition and start it
911
- * const fadeTransition = engine.getTransition('fade');
912
- * fadeTransition.start({ duration: 1000 });
913
- * ```
914
- */
915
- getTransition(id) {
916
- const transition = this.transitions.find((transition2) => transition2.id === id);
917
- if (!transition) {
918
- throw new Error(`Transition with id ${id} not found`);
919
- }
920
- return transition.instance;
921
- }
922
832
  /**
923
833
  * Start a transition
924
834
  *
925
- * Convenience method to start a transition by its ID. This combines
926
- * getTransition and start into a single call. The transition will
927
- * automatically receive an onFinish callback to remove itself when done.
835
+ * Convenience method to display a transition by its ID using the GUI system.
928
836
  *
929
837
  * @param id - The unique identifier of the transition to start
930
- * @param props - Additional props to pass to the transition component
931
- * @returns The created transition object
838
+ * @param props - Props to pass to the transition component
932
839
  *
933
840
  * @example
934
841
  * ```ts
@@ -943,23 +850,10 @@ class RpgClientEngine {
943
850
  * ```
944
851
  */
945
852
  startTransition(id, props = {}) {
946
- const transition = this.transitions.find((t) => t.id === id);
947
- if (!transition) {
948
- throw new Error(`Transition with id ${id} not found`);
949
- }
950
- let baseProps = {};
951
- if (transition.props) {
952
- if (typeof transition.props === "function") {
953
- baseProps = transition.props(this);
954
- } else {
955
- baseProps = transition.props;
956
- }
853
+ if (!this.guiService.exists(id)) {
854
+ throw new Error(`Transition with id ${id} not found. Make sure to add it using engine.addTransition() or in your module's transitions property.`);
957
855
  }
958
- const finalProps = {
959
- ...baseProps,
960
- ...props
961
- };
962
- return transition.instance.start(finalProps);
856
+ this.guiService.display(id, props);
963
857
  }
964
858
  async processInput({ input }) {
965
859
  const timestamp = Date.now();
@@ -1050,6 +944,45 @@ class RpgClientEngine {
1050
944
  getCurrentPlayer() {
1051
945
  return this.sceneMap.getCurrentPlayer();
1052
946
  }
947
+ /**
948
+ * Setup RxJS observer to wait for all conditions before calling onAfterLoading hook
949
+ *
950
+ * This method uses RxJS `combineLatest` to wait for all conditions to be met,
951
+ * regardless of the order in which they arrive:
952
+ * 1. The map loading is completed (loadMapService.load is finished)
953
+ * 2. We received a player ID (pId)
954
+ * 3. Players array has at least one element
955
+ * 4. Events property is present in the sync data
956
+ *
957
+ * Once all conditions are met, it uses `switchMap` to call the onAfterLoading hook once.
958
+ *
959
+ * ## Design
960
+ *
961
+ * Uses BehaviorSubjects to track each condition state, allowing events to arrive
962
+ * in any order. The `combineLatest` operator waits until all observables emit `true`,
963
+ * then `take(1)` ensures the hook is called only once, and `switchMap` handles
964
+ * the hook execution.
965
+ *
966
+ * @example
967
+ * ```ts
968
+ * // Called automatically in loadScene to setup the observer
969
+ * this.setupOnAfterLoadingObserver();
970
+ * ```
971
+ */
972
+ setupOnAfterLoadingObserver() {
973
+ this.onAfterLoadingSubscription = combineLatest([
974
+ this.mapLoadCompleted$.pipe(filter((completed) => completed === true)),
975
+ this.playerIdReceived$.pipe(filter((received) => received === true)),
976
+ this.playersReceived$.pipe(filter((received) => received === true)),
977
+ this.eventsReceived$.pipe(filter((received) => received === true))
978
+ ]).pipe(
979
+ take(1),
980
+ // Only execute once when all conditions are met
981
+ switchMap(() => {
982
+ return this.hooks.callHooks("client-sceneMap-onAfterLoading", this.sceneMap);
983
+ })
984
+ ).subscribe();
985
+ }
1053
986
  /**
1054
987
  * Clear client prediction states for cleanup
1055
988
  *
@@ -1166,7 +1099,132 @@ class RpgClientEngine {
1166
1099
  */
1167
1100
  async replayUnackedInputsFromFrame(_startFrame) {
1168
1101
  }
1102
+ /**
1103
+ * Clear all client resources and reset state
1104
+ *
1105
+ * This method should be called to clean up all client-side resources when
1106
+ * shutting down or resetting the client engine. It:
1107
+ * - Destroys the PIXI renderer
1108
+ * - Stops all sounds
1109
+ * - Cleans up subscriptions and event listeners
1110
+ * - Resets scene map
1111
+ * - Stops ping/pong interval
1112
+ * - Clears prediction states
1113
+ *
1114
+ * ## Design
1115
+ *
1116
+ * This method is used primarily in testing environments to ensure clean
1117
+ * state between tests. In production, the client engine typically persists
1118
+ * for the lifetime of the application.
1119
+ *
1120
+ * @example
1121
+ * ```ts
1122
+ * // In test cleanup
1123
+ * afterEach(() => {
1124
+ * clientEngine.clear();
1125
+ * });
1126
+ * ```
1127
+ */
1128
+ clear() {
1129
+ try {
1130
+ for (const subscription of this.tickSubscriptions) {
1131
+ if (subscription && typeof subscription.unsubscribe === "function") {
1132
+ subscription.unsubscribe();
1133
+ }
1134
+ }
1135
+ this.tickSubscriptions = [];
1136
+ if (this.pingInterval) {
1137
+ clearInterval(this.pingInterval);
1138
+ this.pingInterval = null;
1139
+ }
1140
+ if (this.onAfterLoadingSubscription && typeof this.onAfterLoadingSubscription.unsubscribe === "function") {
1141
+ this.onAfterLoadingSubscription.unsubscribe();
1142
+ this.onAfterLoadingSubscription = void 0;
1143
+ }
1144
+ if (this.canvasElement) {
1145
+ try {
1146
+ if (typeof this.canvasElement.destroy === "function") {
1147
+ this.canvasElement.destroy();
1148
+ }
1149
+ this.canvasElement = void 0;
1150
+ } catch (error) {
1151
+ }
1152
+ }
1153
+ if (this.sceneMap && typeof this.sceneMap.reset === "function") {
1154
+ this.sceneMap.reset();
1155
+ }
1156
+ this.stopAllSounds();
1157
+ if (this.resizeHandler && typeof window !== "undefined") {
1158
+ window.removeEventListener("resize", this.resizeHandler);
1159
+ this.resizeHandler = void 0;
1160
+ }
1161
+ const rendererStillExists = this.renderer && typeof this.renderer.destroy === "function";
1162
+ if (this.canvasApp && typeof this.canvasApp.destroy === "function") {
1163
+ try {
1164
+ if (this.canvasApp.ticker) {
1165
+ if (typeof this.canvasApp.ticker.stop === "function") {
1166
+ this.canvasApp.ticker.stop();
1167
+ }
1168
+ if (typeof this.canvasApp.ticker.removeAll === "function") {
1169
+ this.canvasApp.ticker.removeAll();
1170
+ }
1171
+ }
1172
+ if (this.renderer && this.renderer.ticker) {
1173
+ if (typeof this.renderer.ticker.stop === "function") {
1174
+ this.renderer.ticker.stop();
1175
+ }
1176
+ if (typeof this.renderer.ticker.removeAll === "function") {
1177
+ this.renderer.ticker.removeAll();
1178
+ }
1179
+ }
1180
+ if (this.canvasApp.canvas && this.canvasApp.canvas.parentNode) {
1181
+ this.canvasApp.canvas.parentNode.removeChild(this.canvasApp.canvas);
1182
+ }
1183
+ this.canvasApp.destroy(true);
1184
+ } catch (error) {
1185
+ }
1186
+ this.canvasApp = void 0;
1187
+ this.renderer = null;
1188
+ } else if (rendererStillExists) {
1189
+ try {
1190
+ if (this.renderer.ticker) {
1191
+ if (typeof this.renderer.ticker.stop === "function") {
1192
+ this.renderer.ticker.stop();
1193
+ }
1194
+ if (typeof this.renderer.ticker.removeAll === "function") {
1195
+ this.renderer.ticker.removeAll();
1196
+ }
1197
+ }
1198
+ this.renderer.destroy(true);
1199
+ } catch (error) {
1200
+ }
1201
+ this.renderer = null;
1202
+ }
1203
+ if (this.prediction) {
1204
+ this.prediction = void 0;
1205
+ }
1206
+ this.playerIdSignal.set(null);
1207
+ this.cameraFollowTargetId.set(null);
1208
+ this.spriteComponentsBehind.set([]);
1209
+ this.spriteComponentsInFront.set([]);
1210
+ this.spritesheets.clear();
1211
+ this.sounds.clear();
1212
+ this.componentAnimations = [];
1213
+ this.particleSettings.emitters = [];
1214
+ this.stopProcessingInput = false;
1215
+ this.lastInputTime = 0;
1216
+ this.inputFrameCounter = 0;
1217
+ this.frameOffset = 0;
1218
+ this.rtt = 0;
1219
+ this.mapLoadCompleted$.next(false);
1220
+ this.playerIdReceived$.next(false);
1221
+ this.playersReceived$.next(false);
1222
+ this.eventsReceived$.next(false);
1223
+ } catch (error) {
1224
+ console.warn("Error during client engine cleanup:", error);
1225
+ }
1226
+ }
1169
1227
  }
1170
1228
 
1171
1229
  export { RpgClientEngine };
1172
- //# sourceMappingURL=index2.js.map
1230
+ //# sourceMappingURL=RpgClientEngine.js.map