@rpgjs/client 5.0.0-beta.7 → 5.0.0-beta.9
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/CHANGELOG.md +27 -0
- package/dist/Game/AnimationManager.js.map +1 -1
- package/dist/Game/Event.js.map +1 -1
- package/dist/Game/Map.d.ts +9 -1
- package/dist/Game/Map.js +63 -5
- package/dist/Game/Map.js.map +1 -1
- package/dist/Game/Object.d.ts +17 -9
- package/dist/Game/Object.js +1 -12
- package/dist/Game/Object.js.map +1 -1
- package/dist/Game/Player.js.map +1 -1
- package/dist/Gui/Gui.d.ts +17 -4
- package/dist/Gui/Gui.js +64 -34
- package/dist/Gui/Gui.js.map +1 -1
- package/dist/Gui/Gui.spec.d.ts +1 -0
- package/dist/Gui/NotificationManager.js.map +1 -1
- package/dist/Resource.js +1 -1
- package/dist/Resource.js.map +1 -1
- package/dist/RpgClient.d.ts +35 -2
- package/dist/RpgClientEngine.d.ts +41 -5
- package/dist/RpgClientEngine.js +50 -5
- package/dist/RpgClientEngine.js.map +1 -1
- package/dist/Sound.js.map +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.128.0 → _@oxc-project_runtime@0.130.0}/helpers/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.128.0 → _@oxc-project_runtime@0.130.0}/helpers/decorateMetadata.js +1 -1
- package/dist/components/animations/animation.ce.js.map +1 -1
- package/dist/components/animations/hit.ce.js.map +1 -1
- package/dist/components/animations/index.js.map +1 -1
- package/dist/components/character.ce.js +259 -5
- package/dist/components/character.ce.js.map +1 -1
- package/dist/components/dynamics/bar.ce.js +96 -0
- package/dist/components/dynamics/bar.ce.js.map +1 -0
- package/dist/components/dynamics/image.ce.js +23 -0
- package/dist/components/dynamics/image.ce.js.map +1 -0
- package/dist/components/dynamics/parse-value.d.ts +3 -0
- package/dist/components/dynamics/parse-value.js +51 -35
- package/dist/components/dynamics/parse-value.js.map +1 -1
- package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
- package/dist/components/dynamics/shape-utils.d.ts +16 -0
- package/dist/components/dynamics/shape-utils.js +73 -0
- package/dist/components/dynamics/shape-utils.js.map +1 -0
- package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
- package/dist/components/dynamics/shape.ce.js +83 -0
- package/dist/components/dynamics/shape.ce.js.map +1 -0
- package/dist/components/dynamics/text.ce.js +28 -41
- package/dist/components/dynamics/text.ce.js.map +1 -1
- package/dist/components/gui/box.ce.js.map +1 -1
- package/dist/components/gui/dialogbox/index.ce.js +3 -3
- package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
- package/dist/components/gui/gameover.ce.js +1 -1
- package/dist/components/gui/gameover.ce.js.map +1 -1
- package/dist/components/gui/hud/hud.ce.js +1 -1
- package/dist/components/gui/hud/hud.ce.js.map +1 -1
- package/dist/components/gui/menu/equip-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/exit-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/options-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/skills-menu.ce.js.map +1 -1
- package/dist/components/gui/mobile/index.js.map +1 -1
- package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
- package/dist/components/gui/notification/notification.ce.js.map +1 -1
- package/dist/components/gui/save-load.ce.js.map +1 -1
- package/dist/components/gui/shop/shop.ce.js +1 -1
- package/dist/components/gui/shop/shop.ce.js.map +1 -1
- package/dist/components/gui/title-screen.ce.js +2 -2
- package/dist/components/gui/title-screen.ce.js.map +1 -1
- package/dist/components/player-components-utils.d.ts +67 -0
- package/dist/components/player-components-utils.js +162 -0
- package/dist/components/player-components-utils.js.map +1 -0
- package/dist/components/player-components-utils.spec.d.ts +1 -0
- package/dist/components/player-components.ce.js +188 -0
- package/dist/components/player-components.ce.js.map +1 -0
- package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
- package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
- package/dist/components/scenes/canvas.ce.js +147 -4
- package/dist/components/scenes/canvas.ce.js.map +1 -1
- package/dist/components/scenes/draw-map.ce.js +2 -8
- package/dist/components/scenes/draw-map.ce.js.map +1 -1
- package/dist/components/scenes/event-layer.ce.js.map +1 -1
- package/dist/core/inject.js +1 -1
- package/dist/core/inject.js.map +1 -1
- package/dist/core/setup.js +1 -1
- package/dist/core/setup.js.map +1 -1
- package/dist/decorators/spritesheet.d.ts +1 -0
- package/dist/decorators/spritesheet.js +11 -0
- package/dist/decorators/spritesheet.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -2
- package/dist/module.js +4 -1
- package/dist/module.js.map +1 -1
- package/dist/node_modules/.pnpm/{@signe_di@2.10.0 → @signe_di@3.0.1}/node_modules/@signe/di/dist/index.js +1 -1
- package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{@signe_reactive@2.9.2 → @signe_reactive@3.0.1}/node_modules/@signe/reactive/dist/index.js +15 -3
- package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
- package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
- package/dist/node_modules/.pnpm/{@signe_room@2.10.0 → @signe_room@3.0.1}/node_modules/@signe/room/dist/index.js +124 -39
- package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{@signe_sync@2.10.0 → @signe_sync@3.0.1}/node_modules/@signe/sync/dist/client/index.js +1 -1
- package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{@signe_sync@2.10.0 → @signe_sync@3.0.1}/node_modules/@signe/sync/dist/index.js +36 -13
- package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -1
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -1
- package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -1
- package/dist/presets/animation.js.map +1 -1
- package/dist/presets/faceset.js.map +1 -1
- package/dist/presets/icon.js.map +1 -1
- package/dist/presets/index.js.map +1 -1
- package/dist/presets/lpc.js.map +1 -1
- package/dist/presets/rmspritesheet.js.map +1 -1
- package/dist/services/AbstractSocket.js.map +1 -1
- package/dist/services/keyboardControls.js.map +1 -1
- package/dist/services/loadMap.d.ts +6 -0
- package/dist/services/loadMap.js +1 -1
- package/dist/services/loadMap.js.map +1 -1
- package/dist/services/mmorpg.js +7 -3
- package/dist/services/mmorpg.js.map +1 -1
- package/dist/services/save.js.map +1 -1
- package/dist/services/standalone.js +1 -1
- package/dist/services/standalone.js.map +1 -1
- package/dist/utils/getEntityProp.js.map +1 -1
- package/package.json +10 -10
- package/src/Game/Map.ts +91 -2
- package/src/Game/Object.ts +22 -35
- package/src/Gui/Gui.spec.ts +273 -0
- package/src/Gui/Gui.ts +105 -50
- package/src/Resource.ts +1 -2
- package/src/RpgClient.ts +36 -2
- package/src/RpgClientEngine.ts +74 -11
- package/src/components/character.ce +318 -9
- package/src/components/dynamics/bar.ce +87 -0
- package/src/components/dynamics/image.ce +20 -0
- package/src/components/dynamics/parse-value.spec.ts +41 -0
- package/src/components/dynamics/parse-value.ts +102 -37
- package/src/components/dynamics/shape-utils.spec.ts +46 -0
- package/src/components/dynamics/shape-utils.ts +61 -0
- package/src/components/dynamics/shape.ce +89 -0
- package/src/components/dynamics/text.ce +34 -149
- package/src/components/player-components-utils.spec.ts +109 -0
- package/src/components/player-components-utils.ts +205 -0
- package/src/components/player-components.ce +221 -0
- package/src/components/scenes/canvas.ce +165 -6
- package/src/components/scenes/draw-map.ce +2 -15
- package/src/components/scenes/event-layer.ce +1 -2
- package/src/core/setup.ts +2 -2
- package/src/decorators/spritesheet.ts +8 -0
- package/src/index.ts +1 -0
- package/src/module.ts +5 -1
- package/src/services/loadMap.ts +2 -0
- package/src/services/mmorpg.ts +8 -2
- package/dist/node_modules/.pnpm/@signe_di@2.10.0/node_modules/@signe/di/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js +0 -45
- package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/index.js.map +0 -1
package/src/RpgClientEngine.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import Canvas from "./components/scenes/canvas.ce";
|
|
2
2
|
import { inject } from './core/inject'
|
|
3
|
-
import { signal, bootstrapCanvas, Howl, trigger } from "canvasengine";
|
|
3
|
+
import { signal, bootstrapCanvas, Howl, trigger, type Trigger } from "canvasengine";
|
|
4
4
|
import { AbstractWebsocket, WebSocketToken } from "./services/AbstractSocket";
|
|
5
5
|
import { LoadMapService, LoadMapToken } from "./services/loadMap";
|
|
6
6
|
import { RpgSound } from "./Sound";
|
|
7
7
|
import { RpgResource } from "./Resource";
|
|
8
|
-
import { Hooks, ModulesToken, Direction } from "@rpgjs/common";
|
|
8
|
+
import { Hooks, ModulesToken, Direction, normalizeLightingState } from "@rpgjs/common";
|
|
9
9
|
import { load } from "@signe/sync";
|
|
10
10
|
import { RpgClientMap } from "./Game/Map"
|
|
11
11
|
import { RpgGui } from "./Gui/Gui";
|
|
@@ -14,6 +14,10 @@ import { lastValueFrom, Observable, combineLatest, BehaviorSubject, filter, swit
|
|
|
14
14
|
import { GlobalConfigToken } from "./module";
|
|
15
15
|
import * as PIXI from "pixi.js";
|
|
16
16
|
import { PrebuiltComponentAnimations } from "./components/animations";
|
|
17
|
+
import TextComponent from "./components/dynamics/text.ce";
|
|
18
|
+
import BarComponent from "./components/dynamics/bar.ce";
|
|
19
|
+
import ShapeComponent from "./components/dynamics/shape.ce";
|
|
20
|
+
import ImageComponent from "./components/dynamics/image.ce";
|
|
17
21
|
import {
|
|
18
22
|
PredictionController,
|
|
19
23
|
type PredictionHistoryEntry,
|
|
@@ -32,6 +36,17 @@ interface MovementTrajectoryPoint {
|
|
|
32
36
|
direction?: Direction;
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
type ConfigurableTrigger<T> = Omit<Trigger<T>, "start"> & {
|
|
40
|
+
start(config?: T): Promise<void>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type MapShakeOptions = {
|
|
44
|
+
intensity?: number;
|
|
45
|
+
duration?: number;
|
|
46
|
+
frequency?: number;
|
|
47
|
+
direction?: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
35
50
|
export class RpgClientEngine<T = any> {
|
|
36
51
|
private guiService: RpgGui;
|
|
37
52
|
private webSocket: AbstractWebsocket;
|
|
@@ -44,10 +59,10 @@ export class RpgClientEngine<T = any> {
|
|
|
44
59
|
stopProcessingInput = false;
|
|
45
60
|
width = signal("100%");
|
|
46
61
|
height = signal("100%");
|
|
47
|
-
spritesheets: Map<string, any> = new Map();
|
|
62
|
+
spritesheets: Map<string | number, any> = new Map();
|
|
48
63
|
sounds: Map<string, any> = new Map();
|
|
49
64
|
componentAnimations: any[] = [];
|
|
50
|
-
private spritesheetResolver?: (id: string) => any | Promise<any>;
|
|
65
|
+
private spritesheetResolver?: (id: string | number) => any | Promise<any>;
|
|
51
66
|
private soundResolver?: (id: string) => any | Promise<any>;
|
|
52
67
|
particleSettings: {
|
|
53
68
|
emitters: any[]
|
|
@@ -61,10 +76,11 @@ export class RpgClientEngine<T = any> {
|
|
|
61
76
|
playerIdSignal = signal<string | null>(null);
|
|
62
77
|
spriteComponentsBehind = signal<any[]>([]);
|
|
63
78
|
spriteComponentsInFront = signal<any[]>([]);
|
|
79
|
+
spriteComponents: Map<string, any> = new Map();
|
|
64
80
|
/** ID of the sprite that the camera should follow. null means follow the current player */
|
|
65
81
|
cameraFollowTargetId = signal<string | null>(null);
|
|
66
82
|
/** Trigger for map shake animation */
|
|
67
|
-
mapShakeTrigger = trigger();
|
|
83
|
+
mapShakeTrigger: ConfigurableTrigger<MapShakeOptions> = trigger<MapShakeOptions>();
|
|
68
84
|
|
|
69
85
|
controlsReady = signal(undefined);
|
|
70
86
|
gamePause = signal(false);
|
|
@@ -123,6 +139,13 @@ export class RpgClientEngine<T = any> {
|
|
|
123
139
|
component: PrebuiltComponentAnimations.Animation
|
|
124
140
|
})
|
|
125
141
|
|
|
142
|
+
this.registerSpriteComponent("rpg:text", TextComponent);
|
|
143
|
+
this.registerSpriteComponent("rpg:hpBar", BarComponent);
|
|
144
|
+
this.registerSpriteComponent("rpg:spBar", BarComponent);
|
|
145
|
+
this.registerSpriteComponent("rpg:bar", BarComponent);
|
|
146
|
+
this.registerSpriteComponent("rpg:shape", ShapeComponent);
|
|
147
|
+
this.registerSpriteComponent("rpg:image", ImageComponent);
|
|
148
|
+
|
|
126
149
|
this.predictionEnabled = (this.globalConfig as any)?.prediction?.enabled !== false;
|
|
127
150
|
this.initializePredictionController();
|
|
128
151
|
}
|
|
@@ -233,7 +256,7 @@ export class RpgClientEngine<T = any> {
|
|
|
233
256
|
|
|
234
257
|
await this.webSocket.connection(() => {
|
|
235
258
|
const saveClient = inject(SaveClientService);
|
|
236
|
-
saveClient.initialize(
|
|
259
|
+
saveClient.initialize();
|
|
237
260
|
this.initListeners()
|
|
238
261
|
this.guiService._initialize()
|
|
239
262
|
this.startPingPong();
|
|
@@ -355,6 +378,7 @@ export class RpgClientEngine<T = any> {
|
|
|
355
378
|
|
|
356
379
|
this.webSocket.on("changeMap", (data) => {
|
|
357
380
|
this.sceneResetQueued = true;
|
|
381
|
+
this.sceneMap.clearLightSpots();
|
|
358
382
|
// Reset camera follow to default (follow current player) when changing maps
|
|
359
383
|
this.cameraFollowTargetId.set(null);
|
|
360
384
|
const transferToken = typeof data?.transferToken === "string" ? data.transferToken : undefined;
|
|
@@ -425,7 +449,7 @@ export class RpgClientEngine<T = any> {
|
|
|
425
449
|
|
|
426
450
|
this.webSocket.on("shakeMap", (data) => {
|
|
427
451
|
const { intensity, duration, frequency, direction } = data || {};
|
|
428
|
-
|
|
452
|
+
this.mapShakeTrigger.start({
|
|
429
453
|
intensity,
|
|
430
454
|
duration,
|
|
431
455
|
frequency,
|
|
@@ -459,6 +483,14 @@ export class RpgClientEngine<T = any> {
|
|
|
459
483
|
});
|
|
460
484
|
});
|
|
461
485
|
|
|
486
|
+
this.webSocket.on("lightingState", (data) => {
|
|
487
|
+
const raw = (data && typeof data === "object" && "value" in data)
|
|
488
|
+
? (data as any).value
|
|
489
|
+
: data;
|
|
490
|
+
|
|
491
|
+
this.sceneMap.lightingState.set(normalizeLightingState(raw));
|
|
492
|
+
});
|
|
493
|
+
|
|
462
494
|
this.webSocket.on('open', () => {
|
|
463
495
|
this.hooks.callHooks("client-engine-onConnected", this, this.socket).subscribe();
|
|
464
496
|
// Start ping/pong for synchronization
|
|
@@ -574,7 +606,7 @@ export class RpgClientEngine<T = any> {
|
|
|
574
606
|
})
|
|
575
607
|
await this.webSocket.reconnect(() => {
|
|
576
608
|
const saveClient = inject(SaveClientService);
|
|
577
|
-
saveClient.initialize(
|
|
609
|
+
saveClient.initialize();
|
|
578
610
|
this.initListeners()
|
|
579
611
|
this.guiService._initialize()
|
|
580
612
|
})
|
|
@@ -635,7 +667,7 @@ export class RpgClientEngine<T = any> {
|
|
|
635
667
|
* });
|
|
636
668
|
* ```
|
|
637
669
|
*/
|
|
638
|
-
setSpritesheetResolver(resolver: (id: string) => any | Promise<any>): void {
|
|
670
|
+
setSpritesheetResolver(resolver: (id: string | number) => any | Promise<any>): void {
|
|
639
671
|
this.spritesheetResolver = resolver;
|
|
640
672
|
}
|
|
641
673
|
|
|
@@ -646,7 +678,7 @@ export class RpgClientEngine<T = any> {
|
|
|
646
678
|
* If not found and a resolver is set, it calls the resolver to create the spritesheet.
|
|
647
679
|
* The resolved spritesheet is automatically cached for future use.
|
|
648
680
|
*
|
|
649
|
-
* @param id - The spritesheet ID to retrieve
|
|
681
|
+
* @param id - The spritesheet ID or legacy tile ID to retrieve
|
|
650
682
|
* @returns The spritesheet if found or created, or undefined if not found and no resolver
|
|
651
683
|
* @returns Promise<any> if the resolver is asynchronous
|
|
652
684
|
*
|
|
@@ -659,7 +691,7 @@ export class RpgClientEngine<T = any> {
|
|
|
659
691
|
* const spritesheet = await engine.getSpriteSheet('dynamic-sprite');
|
|
660
692
|
* ```
|
|
661
693
|
*/
|
|
662
|
-
getSpriteSheet(id: string): any | Promise<any> {
|
|
694
|
+
getSpriteSheet(id: string | number): any | Promise<any> {
|
|
663
695
|
// Check cache first
|
|
664
696
|
if (this.spritesheets.has(id)) {
|
|
665
697
|
return this.spritesheets.get(id);
|
|
@@ -1093,6 +1125,37 @@ export class RpgClientEngine<T = any> {
|
|
|
1093
1125
|
return component
|
|
1094
1126
|
}
|
|
1095
1127
|
|
|
1128
|
+
/**
|
|
1129
|
+
* Register a reusable sprite component that can be addressed by the server.
|
|
1130
|
+
*
|
|
1131
|
+
* Server-side component definitions only carry the component id and
|
|
1132
|
+
* serializable props. The client registry maps that id to the CanvasEngine
|
|
1133
|
+
* component that performs the actual rendering.
|
|
1134
|
+
*
|
|
1135
|
+
* @param id - Stable component id used by server component definitions
|
|
1136
|
+
* @param component - CanvasEngine component to render for this id
|
|
1137
|
+
* @returns The registered component
|
|
1138
|
+
*
|
|
1139
|
+
* @example
|
|
1140
|
+
* ```ts
|
|
1141
|
+
* engine.registerSpriteComponent('guildBadge', GuildBadgeComponent);
|
|
1142
|
+
* ```
|
|
1143
|
+
*/
|
|
1144
|
+
registerSpriteComponent(id: string, component: any) {
|
|
1145
|
+
this.spriteComponents.set(id, component);
|
|
1146
|
+
return component;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Get a reusable sprite component by id.
|
|
1151
|
+
*
|
|
1152
|
+
* @param id - Component id registered on the client
|
|
1153
|
+
* @returns The CanvasEngine component, or undefined when missing
|
|
1154
|
+
*/
|
|
1155
|
+
getSpriteComponent(id: string) {
|
|
1156
|
+
return this.spriteComponents.get(id);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1096
1159
|
/**
|
|
1097
1160
|
* Add a component animation to the engine
|
|
1098
1161
|
*
|
|
@@ -4,19 +4,26 @@
|
|
|
4
4
|
<compConfig.component object ...compConfig.props />
|
|
5
5
|
</Container>
|
|
6
6
|
}
|
|
7
|
+
<PlayerComponents object position="bottom" graphicBounds />
|
|
8
|
+
<PlayerComponents object position="left" graphicBounds />
|
|
7
9
|
<Particle emit={emitParticleTrigger} settings={particleSettings} zIndex={1000} name={particleName} />
|
|
8
10
|
<Container>
|
|
9
11
|
@for (graphicObj of graphicsSignals) {
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
<Container scale={graphicScale(graphicObj)}>
|
|
13
|
+
<Sprite
|
|
14
|
+
sheet={sheet(graphicObj)}
|
|
15
|
+
direction
|
|
16
|
+
tint
|
|
17
|
+
hitbox
|
|
18
|
+
shadowCaster={shadowCaster(graphicObj)}
|
|
19
|
+
flash={flashConfig}
|
|
20
|
+
/>
|
|
21
|
+
</Container>
|
|
18
22
|
}
|
|
19
23
|
</Container>
|
|
24
|
+
<PlayerComponents object position="center" graphicBounds />
|
|
25
|
+
<PlayerComponents object position="right" graphicBounds />
|
|
26
|
+
<PlayerComponents object position="top" graphicBounds />
|
|
20
27
|
@for (compConfig of normalizedComponentsInFront) {
|
|
21
28
|
<Container dependencies={compConfig.dependencies}>
|
|
22
29
|
<compConfig.component object ...compConfig.props />
|
|
@@ -37,13 +44,14 @@
|
|
|
37
44
|
|
|
38
45
|
<script>
|
|
39
46
|
import { signal, effect, mount, computed, tick, animatedSignal, on } from "canvasengine";
|
|
47
|
+
import { Assets } from "pixi.js";
|
|
40
48
|
|
|
41
49
|
import { lastValueFrom, combineLatest, pairwise, filter, map, startWith } from "rxjs";
|
|
42
50
|
import { Particle } from "@canvasengine/presets";
|
|
43
51
|
import { GameEngineToken, ModulesToken } from "@rpgjs/common";
|
|
44
52
|
import { RpgClientEngine } from "../RpgClientEngine";
|
|
45
53
|
import { inject } from "../core/inject";
|
|
46
|
-
import { Direction } from "@rpgjs/common";
|
|
54
|
+
import { Direction, Animation } from "@rpgjs/common";
|
|
47
55
|
import Hit from "./effects/hit.ce";
|
|
48
56
|
import PlayerComponents from "./player-components.ce";
|
|
49
57
|
import { RpgGui } from "../Gui/Gui";
|
|
@@ -59,6 +67,10 @@
|
|
|
59
67
|
const componentsBehind = client.spriteComponentsBehind;
|
|
60
68
|
const componentsInFront = client.spriteComponentsInFront;
|
|
61
69
|
const isMe = computed(() => id() === playerId);
|
|
70
|
+
const shadowsEnabled = computed(() => {
|
|
71
|
+
const lighting = client.sceneMap?.lighting?.();
|
|
72
|
+
return Boolean(lighting?.shadows?.enabled || (lighting?.spots?.length ?? 0) > 0);
|
|
73
|
+
});
|
|
62
74
|
|
|
63
75
|
/**
|
|
64
76
|
* Normalize a single sprite component configuration
|
|
@@ -390,6 +402,303 @@
|
|
|
390
402
|
return undefined;
|
|
391
403
|
}
|
|
392
404
|
|
|
405
|
+
const shadowCaster = (graphicObject) => {
|
|
406
|
+
const box = hitbox();
|
|
407
|
+
const bounds = graphicBounds();
|
|
408
|
+
const scale = graphicScale(graphicObject);
|
|
409
|
+
const scaleY = Array.isArray(scale) && typeof scale[1] === 'number' ? Math.abs(scale[1]) : 1;
|
|
410
|
+
const height = Math.max(bounds?.height ?? box?.h ?? 32, box?.h ?? 32) * scaleY;
|
|
411
|
+
|
|
412
|
+
return {
|
|
413
|
+
enabled: shadowsEnabled,
|
|
414
|
+
height,
|
|
415
|
+
footAnchor: { x: 0.5, y: 1 },
|
|
416
|
+
footOffset: { x: 0, y: 2 },
|
|
417
|
+
alpha: 0.5,
|
|
418
|
+
blur: 3.5,
|
|
419
|
+
gradientPower: 2,
|
|
420
|
+
hardness: 0.42,
|
|
421
|
+
minLength: Math.max(6, (box?.h ?? 32) * 0.25),
|
|
422
|
+
maxLength: Math.max(90, height * 1.8),
|
|
423
|
+
contactAlpha: 0.3,
|
|
424
|
+
contactScale: 0.3,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const imageDimensions = signal({});
|
|
429
|
+
const loadingImageDimensions = new Set();
|
|
430
|
+
|
|
431
|
+
const toPositiveNumber = (value) => {
|
|
432
|
+
const number = typeof value === 'number' ? value : parseFloat(value);
|
|
433
|
+
return Number.isFinite(number) && number > 0 ? number : undefined;
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const toFiniteNumber = (value, fallback = 0) => {
|
|
437
|
+
const number = typeof value === 'number' ? value : parseFloat(value);
|
|
438
|
+
return Number.isFinite(number) ? number : fallback;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const clampRatio = (value) => Math.min(1, Math.max(0, value));
|
|
442
|
+
|
|
443
|
+
const normalizePair = (value, fallback = [1, 1]) => {
|
|
444
|
+
if (Array.isArray(value)) {
|
|
445
|
+
const x = toFiniteNumber(value[0], fallback[0]);
|
|
446
|
+
const y = toFiniteNumber(value[1] ?? value[0], x);
|
|
447
|
+
return [x, y];
|
|
448
|
+
}
|
|
449
|
+
if (typeof value === 'number') {
|
|
450
|
+
return [value, value];
|
|
451
|
+
}
|
|
452
|
+
if (value && typeof value === 'object') {
|
|
453
|
+
const x = toFiniteNumber(value.x, fallback[0]);
|
|
454
|
+
const y = toFiniteNumber(value.y ?? value.x, x);
|
|
455
|
+
return [x, y];
|
|
456
|
+
}
|
|
457
|
+
return fallback;
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const normalizeAnchor = (value) => {
|
|
461
|
+
if (!Array.isArray(value)) return undefined;
|
|
462
|
+
const [x, y] = normalizePair(value, [0, 0]);
|
|
463
|
+
return [clampRatio(x), clampRatio(y)];
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const resolveImageSource = (image) => {
|
|
467
|
+
if (typeof image === 'string') return image;
|
|
468
|
+
if (typeof image?.default === 'string') return image.default;
|
|
469
|
+
return undefined;
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const parentTextureOptions = (graphicObject) => {
|
|
473
|
+
const props = [
|
|
474
|
+
'width',
|
|
475
|
+
'height',
|
|
476
|
+
'framesHeight',
|
|
477
|
+
'framesWidth',
|
|
478
|
+
'rectWidth',
|
|
479
|
+
'rectHeight',
|
|
480
|
+
'offset',
|
|
481
|
+
'image',
|
|
482
|
+
'sound',
|
|
483
|
+
'spriteRealSize',
|
|
484
|
+
'scale',
|
|
485
|
+
'anchor',
|
|
486
|
+
'pivot',
|
|
487
|
+
'x',
|
|
488
|
+
'y',
|
|
489
|
+
'opacity'
|
|
490
|
+
];
|
|
491
|
+
|
|
492
|
+
return props.reduce((options, prop) => {
|
|
493
|
+
if (graphicObject?.[prop] !== undefined) {
|
|
494
|
+
options[prop] = graphicObject[prop];
|
|
495
|
+
}
|
|
496
|
+
return options;
|
|
497
|
+
}, {});
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
const resolveTextureOptions = (graphicObject) => {
|
|
501
|
+
const textures = graphicObject?.textures ?? {};
|
|
502
|
+
const texture =
|
|
503
|
+
textures[realAnimationName()] ??
|
|
504
|
+
textures[Animation.Stand] ??
|
|
505
|
+
Object.values(textures)[0] ??
|
|
506
|
+
{};
|
|
507
|
+
|
|
508
|
+
return {
|
|
509
|
+
...parentTextureOptions(graphicObject),
|
|
510
|
+
...texture
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
const resolveFirstAnimationFrame = (textureOptions) => {
|
|
515
|
+
const animations = textureOptions?.animations;
|
|
516
|
+
if (!animations) return {};
|
|
517
|
+
|
|
518
|
+
try {
|
|
519
|
+
const frames = typeof animations === 'function'
|
|
520
|
+
? animations({ direction: direction() })
|
|
521
|
+
: animations;
|
|
522
|
+
if (!Array.isArray(frames)) return {};
|
|
523
|
+
const firstGroup = frames[0];
|
|
524
|
+
return Array.isArray(firstGroup) ? firstGroup[0] ?? {} : firstGroup ?? {};
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
return {};
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
const optionValue = (prop, frame, textureOptions, graphicObject) => {
|
|
532
|
+
return frame?.[prop] ?? textureOptions?.[prop] ?? graphicObject?.[prop];
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const resolveFrameSize = (textureOptions, dimensions) => {
|
|
536
|
+
const framesWidth = toPositiveNumber(textureOptions?.framesWidth) ?? 1;
|
|
537
|
+
const framesHeight = toPositiveNumber(textureOptions?.framesHeight) ?? 1;
|
|
538
|
+
const imageSource = resolveImageSource(textureOptions?.image);
|
|
539
|
+
const loadedSize = imageSource ? dimensions[imageSource] : undefined;
|
|
540
|
+
const fullWidth = toPositiveNumber(textureOptions?.width) ?? loadedSize?.width;
|
|
541
|
+
const fullHeight = toPositiveNumber(textureOptions?.height) ?? loadedSize?.height;
|
|
542
|
+
const width = toPositiveNumber(textureOptions?.rectWidth) ??
|
|
543
|
+
toPositiveNumber(textureOptions?.spriteWidth) ??
|
|
544
|
+
(fullWidth ? fullWidth / framesWidth : undefined);
|
|
545
|
+
const height = toPositiveNumber(textureOptions?.rectHeight) ??
|
|
546
|
+
toPositiveNumber(textureOptions?.spriteHeight) ??
|
|
547
|
+
(fullHeight ? fullHeight / framesHeight : undefined);
|
|
548
|
+
|
|
549
|
+
return {
|
|
550
|
+
width,
|
|
551
|
+
height
|
|
552
|
+
};
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const resolveHitboxAnchor = (spriteWidth, spriteHeight, realSize, box) => {
|
|
556
|
+
if (!spriteWidth || !spriteHeight || !box) {
|
|
557
|
+
return [0, 0];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const heightOfSprite = typeof realSize === 'number' ? realSize : realSize?.height;
|
|
561
|
+
const resolvedHeight = toPositiveNumber(heightOfSprite) ?? spriteHeight;
|
|
562
|
+
const gap = Math.max(0, (spriteHeight - resolvedHeight) / 2);
|
|
563
|
+
const hitboxTopLeftX = clampRatio((spriteWidth - box.w) / 2 / spriteWidth);
|
|
564
|
+
const hitboxTopLeftY = clampRatio((spriteHeight - box.h - gap) / spriteHeight);
|
|
565
|
+
const hitboxCenterX = clampRatio(hitboxTopLeftX + box.w / 2 / spriteWidth);
|
|
566
|
+
const hitboxCenterY = clampRatio(hitboxTopLeftY + box.h / 2 / spriteHeight);
|
|
567
|
+
const footY = clampRatio((spriteHeight - gap) / spriteHeight);
|
|
568
|
+
|
|
569
|
+
switch (box.anchorMode ?? 'top-left') {
|
|
570
|
+
case 'center':
|
|
571
|
+
return [hitboxCenterX, hitboxCenterY];
|
|
572
|
+
case 'foot':
|
|
573
|
+
return [hitboxCenterX, footY];
|
|
574
|
+
case 'top-left':
|
|
575
|
+
default:
|
|
576
|
+
return [hitboxTopLeftX, hitboxTopLeftY];
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const loadImageDimensions = (image) => {
|
|
581
|
+
const source = resolveImageSource(image);
|
|
582
|
+
if (!source || imageDimensions()[source] || loadingImageDimensions.has(source)) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
loadingImageDimensions.add(source);
|
|
587
|
+
Assets.load(source)
|
|
588
|
+
.then((texture) => {
|
|
589
|
+
const width = toPositiveNumber(texture?.width);
|
|
590
|
+
const height = toPositiveNumber(texture?.height);
|
|
591
|
+
if (!width || !height) return;
|
|
592
|
+
|
|
593
|
+
imageDimensions.update((dimensions) => ({
|
|
594
|
+
...dimensions,
|
|
595
|
+
[source]: { width, height }
|
|
596
|
+
}));
|
|
597
|
+
})
|
|
598
|
+
.catch(() => {})
|
|
599
|
+
.finally(() => {
|
|
600
|
+
loadingImageDimensions.delete(source);
|
|
601
|
+
});
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
effect(() => {
|
|
605
|
+
const sources = new Set();
|
|
606
|
+
|
|
607
|
+
graphicsSignals().forEach((graphicObject) => {
|
|
608
|
+
const baseImage = resolveImageSource(graphicObject?.image);
|
|
609
|
+
if (baseImage) sources.add(baseImage);
|
|
610
|
+
|
|
611
|
+
Object.values(graphicObject?.textures ?? {}).forEach((textureOptions) => {
|
|
612
|
+
const image = resolveImageSource(textureOptions?.image ?? graphicObject?.image);
|
|
613
|
+
if (image) sources.add(image);
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
sources.forEach((source) => loadImageDimensions(source));
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
const hitboxBounds = computed(() => {
|
|
621
|
+
const box = hitbox();
|
|
622
|
+
const width = box?.w ?? 0;
|
|
623
|
+
const height = box?.h ?? 0;
|
|
624
|
+
|
|
625
|
+
return {
|
|
626
|
+
left: 0,
|
|
627
|
+
top: 0,
|
|
628
|
+
right: width,
|
|
629
|
+
bottom: height,
|
|
630
|
+
width,
|
|
631
|
+
height,
|
|
632
|
+
centerX: width / 2,
|
|
633
|
+
centerY: height / 2
|
|
634
|
+
};
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
const graphicBounds = computed(() => {
|
|
638
|
+
const box = hitbox();
|
|
639
|
+
const fallback = hitboxBounds();
|
|
640
|
+
const dimensions = imageDimensions();
|
|
641
|
+
const graphics = graphicsSignals();
|
|
642
|
+
let bounds = null;
|
|
643
|
+
|
|
644
|
+
graphics.forEach((graphicObject) => {
|
|
645
|
+
const textureOptions = resolveTextureOptions(graphicObject);
|
|
646
|
+
const frame = resolveFirstAnimationFrame(textureOptions);
|
|
647
|
+
const size = resolveFrameSize(textureOptions, dimensions);
|
|
648
|
+
const spriteWidth = size.width ?? box?.w;
|
|
649
|
+
const spriteHeight = size.height ?? box?.h;
|
|
650
|
+
|
|
651
|
+
if (!spriteWidth || !spriteHeight) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
const explicitAnchor = normalizeAnchor(optionValue('anchor', frame, textureOptions, graphicObject));
|
|
656
|
+
const anchor = explicitAnchor ?? resolveHitboxAnchor(
|
|
657
|
+
spriteWidth,
|
|
658
|
+
spriteHeight,
|
|
659
|
+
optionValue('spriteRealSize', frame, textureOptions, graphicObject),
|
|
660
|
+
box
|
|
661
|
+
);
|
|
662
|
+
const scale = normalizePair(optionValue('scale', frame, textureOptions, graphicObject) ?? graphicScale(graphicObject));
|
|
663
|
+
const x = toFiniteNumber(optionValue('x', frame, textureOptions, graphicObject), 0);
|
|
664
|
+
const y = toFiniteNumber(optionValue('y', frame, textureOptions, graphicObject), 0);
|
|
665
|
+
const leftEdge = -anchor[0] * spriteWidth * scale[0];
|
|
666
|
+
const rightEdge = (1 - anchor[0]) * spriteWidth * scale[0];
|
|
667
|
+
const topEdge = -anchor[1] * spriteHeight * scale[1];
|
|
668
|
+
const bottomEdge = (1 - anchor[1]) * spriteHeight * scale[1];
|
|
669
|
+
const graphic = {
|
|
670
|
+
left: x + Math.min(leftEdge, rightEdge),
|
|
671
|
+
top: y + Math.min(topEdge, bottomEdge),
|
|
672
|
+
right: x + Math.max(leftEdge, rightEdge),
|
|
673
|
+
bottom: y + Math.max(topEdge, bottomEdge)
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
bounds = bounds
|
|
677
|
+
? {
|
|
678
|
+
left: Math.min(bounds.left, graphic.left),
|
|
679
|
+
top: Math.min(bounds.top, graphic.top),
|
|
680
|
+
right: Math.max(bounds.right, graphic.right),
|
|
681
|
+
bottom: Math.max(bounds.bottom, graphic.bottom)
|
|
682
|
+
}
|
|
683
|
+
: graphic;
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
if (!bounds) {
|
|
687
|
+
return fallback;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const width = bounds.right - bounds.left;
|
|
691
|
+
const height = bounds.bottom - bounds.top;
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
...bounds,
|
|
695
|
+
width,
|
|
696
|
+
height,
|
|
697
|
+
centerX: bounds.left + width / 2,
|
|
698
|
+
centerY: bounds.top + height / 2
|
|
699
|
+
};
|
|
700
|
+
});
|
|
701
|
+
|
|
393
702
|
// Combine animation change detection with movement state from smoothX/smoothY
|
|
394
703
|
const movementAnimations = ['walk', 'stand'];
|
|
395
704
|
const epsilon = 0; // movement threshold to consider the easing still running
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<Container width={width} height={containerHeight} minWidth={width} minHeight={containerHeight}>
|
|
2
|
+
<Graphics width={width} height={containerHeight} draw={drawBar} />
|
|
3
|
+
@if (hasLabel) {
|
|
4
|
+
<Text text={labelText} x={labelPosition.x} y={labelPosition.y} size={labelSize} color={labelColor} />
|
|
5
|
+
}
|
|
6
|
+
</Container>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
import { computed } from "canvasengine";
|
|
10
|
+
import { resolveDynamicValue } from "./parse-value";
|
|
11
|
+
|
|
12
|
+
const { object, current, max, style, text } = defineProps();
|
|
13
|
+
|
|
14
|
+
const read = (prop, fallback) => prop ? prop() : fallback;
|
|
15
|
+
|
|
16
|
+
const toNumber = (value, fallback = 0) => {
|
|
17
|
+
const resolved = resolveDynamicValue(value, object);
|
|
18
|
+
const num = typeof resolved === 'number' ? resolved : parseFloat(resolved);
|
|
19
|
+
return Number.isFinite(num) ? num : fallback;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const toColor = (value, fallback) => {
|
|
23
|
+
const resolved = resolveDynamicValue(value, object);
|
|
24
|
+
if (typeof resolved === 'number') return resolved;
|
|
25
|
+
if (typeof resolved === 'string' && resolved.startsWith('#')) {
|
|
26
|
+
return parseInt(resolved.slice(1), 16);
|
|
27
|
+
}
|
|
28
|
+
return resolved ?? fallback;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const config = computed(() => read(style, {}) ?? {});
|
|
32
|
+
const width = computed(() => toNumber(config().width, 50));
|
|
33
|
+
const height = computed(() => toNumber(config().height, 8));
|
|
34
|
+
const borderRadius = computed(() => toNumber(config().borderRadius, 3));
|
|
35
|
+
const borderWidth = computed(() => toNumber(config().borderWidth, 1));
|
|
36
|
+
const backgroundColor = computed(() => toColor(config().bgColor, 0x16213e));
|
|
37
|
+
const fillColor = computed(() => toColor(config().fillColor, 0x4ade80));
|
|
38
|
+
const borderColor = computed(() => toColor(config().borderColor, 0x4a5568));
|
|
39
|
+
const opacity = computed(() => Math.max(0, Math.min(1, toNumber(config().opacity, 1))));
|
|
40
|
+
|
|
41
|
+
const currentValue = computed(() => toNumber(read(current, 0), 0));
|
|
42
|
+
const maxValue = computed(() => Math.max(0, toNumber(read(max, 0), 0)));
|
|
43
|
+
const percent = computed(() => {
|
|
44
|
+
const max = maxValue();
|
|
45
|
+
if (max <= 0) return 0;
|
|
46
|
+
return Math.max(0, Math.min(1, currentValue() / max));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const fillWidth = computed(() => Math.max(0, width() * percent()));
|
|
50
|
+
const labelTemplate = computed(() => read(text, null));
|
|
51
|
+
const labelText = computed(() => {
|
|
52
|
+
const template = labelTemplate();
|
|
53
|
+
if (template == null || template === '') return '';
|
|
54
|
+
|
|
55
|
+
const value = String(template)
|
|
56
|
+
.replace(/\{\$current\}/g, String(currentValue()))
|
|
57
|
+
.replace(/\{\$max\}/g, String(maxValue()))
|
|
58
|
+
.replace(/\{\$percent\}/g, String(Math.round(percent() * 100)));
|
|
59
|
+
|
|
60
|
+
return String(resolveDynamicValue(value, object) ?? '');
|
|
61
|
+
});
|
|
62
|
+
const labelSize = computed(() => toNumber(config().fontSize, 10));
|
|
63
|
+
const hasLabel = computed(() => labelText().length > 0);
|
|
64
|
+
const labelOffset = computed(() => hasLabel() ? labelSize() + 2 : 0);
|
|
65
|
+
const containerHeight = computed(() => labelOffset() + height());
|
|
66
|
+
const labelColor = computed(() => toColor(config().textColor, 0xffffff));
|
|
67
|
+
const labelPosition = computed(() => ({
|
|
68
|
+
x: 0,
|
|
69
|
+
y: 0
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
const drawBar = (g) => {
|
|
73
|
+
g.roundRect(0, labelOffset(), width(), height(), borderRadius());
|
|
74
|
+
g.fill({ color: backgroundColor(), alpha: opacity() });
|
|
75
|
+
|
|
76
|
+
const currentWidth = fillWidth();
|
|
77
|
+
if (currentWidth > 0) {
|
|
78
|
+
g.roundRect(0, labelOffset(), currentWidth, height(), borderRadius());
|
|
79
|
+
g.fill({ color: fillColor(), alpha: opacity() });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const strokeWidth = borderWidth();
|
|
83
|
+
if (strokeWidth <= 0) return;
|
|
84
|
+
g.roundRect(0, labelOffset(), width(), height(), borderRadius());
|
|
85
|
+
g.stroke({ color: borderColor(), width: strokeWidth, alpha: opacity() });
|
|
86
|
+
};
|
|
87
|
+
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<Sprite sheet={sheet} />
|
|
2
|
+
|
|
3
|
+
<script>
|
|
4
|
+
import { computed } from "canvasengine";
|
|
5
|
+
import { RpgClientEngine } from "../../RpgClientEngine";
|
|
6
|
+
import { inject } from "../../core/inject";
|
|
7
|
+
import { resolveDynamicValue } from "./parse-value";
|
|
8
|
+
|
|
9
|
+
const { object, value } = defineProps();
|
|
10
|
+
const client = inject(RpgClientEngine);
|
|
11
|
+
|
|
12
|
+
const sheet = computed(() => {
|
|
13
|
+
const id = resolveDynamicValue(value?.(), object);
|
|
14
|
+
if (!id) return null;
|
|
15
|
+
return {
|
|
16
|
+
definition: client.getSpriteSheet(id),
|
|
17
|
+
playing: 'default'
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
</script>
|