@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.
- package/dist/{index30.js → Game/AnimationManager.js} +1 -1
- package/dist/Game/AnimationManager.js.map +1 -0
- package/dist/{index24.js → Game/Event.js} +2 -2
- package/dist/Game/Event.js.map +1 -0
- package/dist/{index29.js → Game/Map.js} +6 -6
- package/dist/Game/Map.js.map +1 -0
- package/dist/{index22.js → Game/Object.js} +4 -4
- package/dist/Game/Object.js.map +1 -0
- package/dist/{index23.js → Game/Player.js} +2 -2
- package/dist/Game/Player.js.map +1 -0
- package/dist/{index9.js → Gui/Gui.js} +10 -11
- package/dist/{index9.js.map → Gui/Gui.js.map} +1 -1
- package/dist/{index19.js → Resource.js} +1 -1
- package/dist/Resource.js.map +1 -0
- package/dist/RpgClientEngine.d.ts +66 -115
- package/dist/{index2.js → RpgClientEngine.js} +234 -176
- package/dist/RpgClientEngine.js.map +1 -0
- package/dist/{index18.js → Sound.js} +1 -1
- package/dist/Sound.js.map +1 -0
- package/dist/{index35.js → components/animations/animation.ce.js} +3 -3
- package/dist/components/animations/animation.ce.js.map +1 -0
- package/dist/{index34.js → components/animations/hit.ce.js} +1 -1
- package/dist/components/animations/hit.ce.js.map +1 -0
- package/dist/{index12.js → components/animations/index.js} +3 -3
- package/dist/components/animations/index.js.map +1 -0
- package/dist/{index17.js → components/character.ce.js} +4 -4
- package/dist/components/character.ce.js.map +1 -0
- package/dist/{index51.js → components/dynamics/parse-value.js} +1 -1
- package/dist/components/dynamics/parse-value.js.map +1 -0
- package/dist/{index40.js → components/dynamics/text.ce.js} +2 -2
- package/dist/components/dynamics/text.ce.js.map +1 -0
- package/dist/{index11.js → components/gui/box.ce.js} +8 -8
- package/dist/components/gui/box.ce.js.map +1 -0
- package/dist/{index10.js → components/gui/dialogbox/index.ce.js} +4 -4
- package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
- package/dist/{index52.js → components/gui/dialogbox/itemMenu.ce.js} +1 -1
- package/dist/components/gui/dialogbox/itemMenu.ce.js.map +1 -0
- package/dist/{index47.js → components/gui/dialogbox/selection.ce.js} +4 -4
- package/dist/components/gui/dialogbox/selection.ce.js.map +1 -0
- package/dist/components/gui/mobile/index.d.ts +1 -1
- package/dist/{index25.js → components/gui/mobile/index.js} +5 -5
- package/dist/components/gui/mobile/index.js.map +1 -0
- package/dist/components/gui/mobile/mobile.ce.js +17 -0
- package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
- package/dist/{index13.js → components/prebuilt/hp-bar.ce.js} +1 -1
- package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
- package/dist/{index14.js → components/prebuilt/light-halo.ce.js} +2 -3
- package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
- package/dist/{index26.js → components/scenes/canvas.ce.js} +6 -7
- package/dist/components/scenes/canvas.ce.js.map +1 -0
- package/dist/{index46.js → components/scenes/draw-map.ce.js} +3 -3
- package/dist/components/scenes/draw-map.ce.js.map +1 -0
- package/dist/{index16.js → components/scenes/event-layer.ce.js} +4 -4
- package/dist/components/scenes/event-layer.ce.js.map +1 -0
- package/dist/{index6.js → core/inject.js} +2 -2
- package/dist/core/inject.js.map +1 -0
- package/dist/{index5.js → core/setup.js} +4 -4
- package/dist/core/setup.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +25 -24
- package/dist/index.js.map +1 -1
- package/dist/{index8.js → module.js} +10 -5
- package/dist/module.js.map +1 -0
- package/dist/{index20.js → node_modules/.pnpm/@signe_di@2.6.0/node_modules/@signe/di/dist/index.js} +1 -1
- package/dist/node_modules/.pnpm/@signe_di@2.6.0/node_modules/@signe/di/dist/index.js.map +1 -0
- package/dist/{index45.js → node_modules/.pnpm/@signe_reactive@2.6.0/node_modules/@signe/reactive/dist/index.js} +216 -11
- package/dist/node_modules/.pnpm/@signe_reactive@2.6.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
- package/dist/{index32.js → node_modules/.pnpm/@signe_room@2.6.0/node_modules/@signe/room/dist/index.js} +29 -30
- package/dist/node_modules/.pnpm/@signe_room@2.6.0/node_modules/@signe/room/dist/index.js.map +1 -0
- package/dist/{index42.js → node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js} +1 -1
- package/dist/node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/{index33.js → node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/client/index.js} +5 -5
- package/dist/node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/client/index.js.map +1 -0
- package/dist/{index28.js → node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/index.js} +3 -3
- package/dist/node_modules/.pnpm/@signe_sync@2.6.0/node_modules/@signe/sync/dist/index.js.map +1 -0
- package/dist/{index48.js → node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js} +1 -1
- package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +1 -0
- package/dist/{index43.js → node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js} +2 -15
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
- package/dist/{index44.js → node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js} +2 -5
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
- package/dist/{index50.js → node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js} +813 -100
- package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
- package/dist/{index36.js → presets/animation.js} +1 -1
- package/dist/presets/animation.js.map +1 -0
- package/dist/{index39.js → presets/faceset.js} +1 -1
- package/dist/presets/faceset.js.map +1 -0
- package/dist/presets/index.js +14 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/{index37.js → presets/lpc.js} +1 -1
- package/dist/presets/lpc.js.map +1 -0
- package/dist/{index38.js → presets/rmspritesheet.js} +1 -1
- package/dist/presets/rmspritesheet.js.map +1 -0
- package/dist/{index27.js → services/AbstractSocket.js} +1 -1
- package/dist/services/AbstractSocket.js.map +1 -0
- package/dist/{index21.js → services/keyboardControls.js} +1 -1
- package/dist/services/keyboardControls.js.map +1 -0
- package/dist/{index7.js → services/loadMap.js} +2 -2
- package/dist/services/loadMap.js.map +1 -0
- package/dist/{index4.js → services/mmorpg.js} +6 -6
- package/dist/services/mmorpg.js.map +1 -0
- package/dist/services/standalone.d.ts +3 -0
- package/dist/{index3.js → services/standalone.js} +18 -12
- package/dist/services/standalone.js.map +1 -0
- package/package.json +9 -9
- package/src/Gui/Gui.ts +0 -1
- package/src/RpgClientEngine.ts +298 -182
- package/src/components/character.ce +2 -3
- package/src/components/gui/mobile/index.ts +1 -1
- package/src/components/gui/mobile/mobile.ce +73 -88
- package/src/components/prebuilt/light-halo.ce +2 -71
- package/src/components/scenes/canvas.ce +0 -10
- package/src/components/scenes/event-layer.ce +1 -0
- package/src/index.ts +2 -1
- package/src/module.ts +6 -1
- package/src/services/standalone.ts +16 -7
- package/vite.config.ts +4 -2
- package/dist/Game/TransitionManager.d.ts +0 -56
- package/dist/index10.js.map +0 -1
- package/dist/index11.js.map +0 -1
- package/dist/index12.js.map +0 -1
- package/dist/index13.js.map +0 -1
- package/dist/index14.js.map +0 -1
- package/dist/index15.js +0 -14
- package/dist/index15.js.map +0 -1
- package/dist/index16.js.map +0 -1
- package/dist/index17.js.map +0 -1
- package/dist/index18.js.map +0 -1
- package/dist/index19.js.map +0 -1
- package/dist/index2.js.map +0 -1
- package/dist/index20.js.map +0 -1
- package/dist/index21.js.map +0 -1
- package/dist/index22.js.map +0 -1
- package/dist/index23.js.map +0 -1
- package/dist/index24.js.map +0 -1
- package/dist/index25.js.map +0 -1
- package/dist/index26.js.map +0 -1
- package/dist/index27.js.map +0 -1
- package/dist/index28.js.map +0 -1
- package/dist/index29.js.map +0 -1
- package/dist/index3.js.map +0 -1
- package/dist/index30.js.map +0 -1
- package/dist/index31.js +0 -53
- package/dist/index31.js.map +0 -1
- package/dist/index32.js.map +0 -1
- package/dist/index33.js.map +0 -1
- package/dist/index34.js.map +0 -1
- package/dist/index35.js.map +0 -1
- package/dist/index36.js.map +0 -1
- package/dist/index37.js.map +0 -1
- package/dist/index38.js.map +0 -1
- package/dist/index39.js.map +0 -1
- package/dist/index4.js.map +0 -1
- package/dist/index40.js.map +0 -1
- package/dist/index41.js +0 -43
- package/dist/index41.js.map +0 -1
- package/dist/index42.js.map +0 -1
- package/dist/index43.js.map +0 -1
- package/dist/index44.js.map +0 -1
- package/dist/index45.js.map +0 -1
- package/dist/index46.js.map +0 -1
- package/dist/index47.js.map +0 -1
- package/dist/index48.js.map +0 -1
- package/dist/index49.js +0 -7
- package/dist/index49.js.map +0 -1
- package/dist/index5.js.map +0 -1
- package/dist/index50.js.map +0 -1
- package/dist/index51.js.map +0 -1
- package/dist/index52.js.map +0 -1
- package/dist/index53.js +0 -6
- package/dist/index53.js.map +0 -1
- package/dist/index54.js +0 -12
- package/dist/index54.js.map +0 -1
- package/dist/index55.js +0 -113
- package/dist/index55.js.map +0 -1
- package/dist/index56.js +0 -136
- package/dist/index56.js.map +0 -1
- package/dist/index57.js +0 -137
- package/dist/index57.js.map +0 -1
- package/dist/index58.js +0 -112
- package/dist/index58.js.map +0 -1
- package/dist/index59.js +0 -9
- package/dist/index59.js.map +0 -1
- package/dist/index6.js.map +0 -1
- package/dist/index7.js.map +0 -1
- package/dist/index8.js.map +0 -1
- package/src/Game/TransitionManager.ts +0 -75
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import component from './
|
|
2
|
-
import { inject } from './
|
|
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 './
|
|
5
|
-
import { LoadMapToken } from './
|
|
6
|
-
import { RpgSound } from './
|
|
7
|
-
import { RpgResource } from './
|
|
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 './
|
|
10
|
-
import { RpgClientMap } from './
|
|
11
|
-
import { RpgGui } from './
|
|
12
|
-
import { AnimationManager } from './
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
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 './
|
|
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
|
-
|
|
148
|
+
this.resizeHandler = () => {
|
|
140
149
|
this.hooks.callHooks("client-engine-onWindowResize", this).subscribe();
|
|
141
|
-
}
|
|
142
|
-
this.
|
|
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)
|
|
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)
|
|
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
|
-
|
|
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
|
|
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 -
|
|
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
|
-
|
|
947
|
-
|
|
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
|
-
|
|
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=
|
|
1230
|
+
//# sourceMappingURL=RpgClientEngine.js.map
|