@rpgjs/client 5.0.0-beta.27 → 5.0.0-beta.28
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/ClientVisuals.js.map +1 -1
- package/dist/Game/Map.js +2 -2
- package/dist/Game/Map.js.map +1 -1
- package/dist/Game/Object.js +1 -1
- package/dist/Game/Object.js.map +1 -1
- package/dist/Game/ProjectileManager.js.map +1 -1
- package/dist/Gui/Gui.d.ts +34 -15
- package/dist/Gui/Gui.js +40 -22
- package/dist/Gui/Gui.js.map +1 -1
- package/dist/Gui/NotificationManager.js.map +1 -1
- package/dist/RpgClient.d.ts +3 -64
- package/dist/RpgClientEngine.js +1 -1
- package/dist/RpgClientEngine.js.map +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.133.0 → _@oxc-project_runtime@0.139.0}/helpers/esm/decorate.js +2 -2
- package/dist/_virtual/{_@oxc-project_runtime@0.133.0 → _@oxc-project_runtime@0.139.0}/helpers/esm/decorateMetadata.js +2 -2
- package/dist/components/animations/animation.ce.js.map +1 -1
- package/dist/components/animations/fx.ce.js.map +1 -1
- package/dist/components/animations/hit.ce.js.map +1 -1
- package/dist/components/character-hitbox.js +1 -1
- package/dist/components/character.ce.js +3 -1
- package/dist/components/character.ce.js.map +1 -1
- package/dist/components/dynamics/bar.ce.js.map +1 -1
- package/dist/components/dynamics/image.ce.js.map +1 -1
- package/dist/components/dynamics/parse-value.js +1 -1
- package/dist/components/dynamics/parse-value.js.map +1 -1
- package/dist/components/dynamics/shape-utils.js +1 -1
- package/dist/components/dynamics/shape.ce.js.map +1 -1
- 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.map +1 -1
- package/dist/components/gui/gameover.ce.js.map +1 -1
- package/dist/components/gui/hud/hud.ce.js.map +1 -1
- package/dist/components/gui/index.js +17 -16
- package/dist/components/gui/input-field.ce.js.map +1 -1
- package/dist/components/gui/input.ce.js.map +1 -1
- package/dist/components/gui/menu/equip-menu.ce.js +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/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 +4 -2
- package/dist/components/gui/shop/shop.ce.js.map +1 -1
- package/dist/components/gui/title-screen.ce.js.map +1 -1
- package/dist/components/index.js +4 -3
- package/dist/components/interaction-components.ce.js.map +1 -1
- package/dist/components/player-components-utils.js +1 -1
- package/dist/components/player-components-utils.js.map +1 -1
- package/dist/components/player-components.ce.js.map +1 -1
- package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
- package/dist/components/prebuilt/index.js +3 -2
- package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
- package/dist/components/scenes/canvas.ce.js.map +1 -1
- package/dist/components/scenes/draw-map.ce.js.map +1 -1
- package/dist/components/scenes/event-layer.ce.js.map +1 -1
- package/dist/components/scenes/weather-tick-lifecycle.js.map +1 -1
- package/dist/core/setup.js.map +1 -1
- package/dist/module.js.map +1 -1
- package/dist/node_modules/.pnpm/@signe_di@3.1.0/node_modules/@signe/di/dist/index.js +1 -1
- package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js +1 -1
- package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js +2 -2
- package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js +1 -1
- package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/index.js +1 -1
- package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js +2 -2
- package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js +1 -1
- package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js.map +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js +7 -7
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js.map +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js +2 -2
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js.map +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js.map +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js.map +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js +1 -1
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js.map +1 -1
- package/dist/presets/faceset.js.map +1 -1
- package/dist/presets/rmspritesheet.js.map +1 -1
- package/dist/services/cameraFollow.js +1 -1
- package/dist/services/cameraFollow.js.map +1 -1
- package/dist/services/interactions.js.map +1 -1
- package/dist/services/mapStreaming.js.map +1 -1
- package/dist/services/mmorpg-connection.js +1 -1
- package/dist/services/mmorpg-connection.js.map +1 -1
- package/dist/services/mmorpg.js.map +1 -1
- package/dist/services/pointerContext.js +2 -1
- package/dist/services/pointerContext.js.map +1 -1
- package/dist/services/save.js.map +1 -1
- package/dist/services/standalone.js.map +1 -1
- package/dist/utils/getEntityProp.js.map +1 -1
- package/dist/utils/syncHitbox.js.map +1 -1
- package/package.json +9 -9
- package/src/Gui/Gui.spec.ts +26 -1
- package/src/Gui/Gui.ts +101 -37
- package/src/RpgClient.ts +2 -63
- package/src/public-api-types.spec.ts +19 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpgjs/client",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.28",
|
|
4
4
|
"description": "RPGJS is a framework for creating RPG/MMORPG games",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
"author": "Samuel Ronce",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@canvasengine/presets": "^2.
|
|
21
|
-
"canvasengine": "^2.
|
|
20
|
+
"@canvasengine/presets": "^2.1.0",
|
|
21
|
+
"canvasengine": "^2.1.1",
|
|
22
22
|
"pixi.js": "^8.9.2"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@rpgjs/common": "5.0.0-beta.26",
|
|
26
|
-
"@rpgjs/server": "5.0.0-beta.
|
|
27
|
-
"@rpgjs/ui-css": "5.0.0-beta.
|
|
26
|
+
"@rpgjs/server": "5.0.0-beta.28",
|
|
27
|
+
"@rpgjs/ui-css": "5.0.0-beta.24",
|
|
28
28
|
"@signe/di": "3.1.0",
|
|
29
29
|
"@signe/room": "3.1.0",
|
|
30
30
|
"@signe/sync": "3.1.0",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"rxjs": "^7.8.2"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@canvasengine/compiler": "2.
|
|
36
|
-
"vite": "^8.
|
|
37
|
-
"vite-plugin-dts": "^5.0.
|
|
38
|
-
"vitest": "^4.1.
|
|
35
|
+
"@canvasengine/compiler": "2.1.0",
|
|
36
|
+
"vite": "^8.1.5",
|
|
37
|
+
"vite-plugin-dts": "^5.0.3",
|
|
38
|
+
"vitest": "^4.1.10"
|
|
39
39
|
},
|
|
40
40
|
"type": "module",
|
|
41
41
|
"scripts": {
|
package/src/Gui/Gui.spec.ts
CHANGED
|
@@ -176,6 +176,29 @@ describe("RpgGui Vue integration", () => {
|
|
|
176
176
|
expect(gui.getAttachedVueGuis().map(item => item.name)).toEqual(["tooltip"]);
|
|
177
177
|
});
|
|
178
178
|
|
|
179
|
+
test("records explicit renderer ownership for both GUI registries", async () => {
|
|
180
|
+
const { gui } = await createGui();
|
|
181
|
+
|
|
182
|
+
gui.add({
|
|
183
|
+
id: "explicit-canvas",
|
|
184
|
+
component: CanvasGui,
|
|
185
|
+
renderer: "canvas",
|
|
186
|
+
});
|
|
187
|
+
gui.add({
|
|
188
|
+
id: "explicit-vue",
|
|
189
|
+
component: VueInventory,
|
|
190
|
+
renderer: "vue",
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(gui.getAll()["explicit-canvas"].renderer).toBe("canvas");
|
|
194
|
+
expect(gui.getVueGuis()).toEqual([
|
|
195
|
+
expect.objectContaining({
|
|
196
|
+
name: "explicit-vue",
|
|
197
|
+
renderer: "vue",
|
|
198
|
+
}),
|
|
199
|
+
]);
|
|
200
|
+
});
|
|
201
|
+
|
|
179
202
|
test("synchronizes Vue GUI display and hide states through the Vue bridge", async () => {
|
|
180
203
|
const { gui } = await createGui();
|
|
181
204
|
const bridge = {
|
|
@@ -334,7 +357,9 @@ describe("RpgGui Vue integration", () => {
|
|
|
334
357
|
|
|
335
358
|
gui.guiInteraction(PrebuiltGui.MainMenu, "useItem", { id: "potion" });
|
|
336
359
|
|
|
337
|
-
expect(gui.get
|
|
360
|
+
expect(gui.get<{ items: Array<{ id: string; quantity: number }> }>(
|
|
361
|
+
PrebuiltGui.MainMenu
|
|
362
|
+
)?.data().items).toEqual([
|
|
338
363
|
{
|
|
339
364
|
id: "potion",
|
|
340
365
|
quantity: 1,
|
package/src/Gui/Gui.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import { Context, inject } from "@signe/di";
|
|
2
|
-
import { signal, Signal, WritableSignal } from "canvasengine";
|
|
2
|
+
import { signal, Signal, WritableSignal, type ComponentFunction } from "canvasengine";
|
|
3
3
|
import { AbstractWebsocket, WebSocketToken } from "../services/AbstractSocket";
|
|
4
4
|
import { DialogboxComponent, ShopComponent, SaveLoadComponent, MainMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent, InputComponent } from "../components/gui";
|
|
5
5
|
import { combineLatest, Subscription } from "rxjs";
|
|
6
6
|
import { PrebuiltGui, type RpgContext } from "@rpgjs/common";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
export type GuiRenderer = "canvas" | "vue";
|
|
9
|
+
|
|
10
|
+
export type GuiComponent = ComponentFunction | object;
|
|
11
|
+
|
|
12
|
+
export interface GuiRegistration<
|
|
13
|
+
TData = unknown,
|
|
14
|
+
TComponent extends GuiComponent = GuiComponent,
|
|
15
|
+
> {
|
|
9
16
|
name?: string;
|
|
10
17
|
id?: string;
|
|
11
|
-
component
|
|
18
|
+
component: TComponent;
|
|
19
|
+
/**
|
|
20
|
+
* Renderer responsible for this component. CanvasEngine is the v5 default.
|
|
21
|
+
* `@rpgjs/vue` registers the official DOM overlay renderer.
|
|
22
|
+
*/
|
|
23
|
+
renderer?: GuiRenderer;
|
|
12
24
|
display?: boolean;
|
|
13
|
-
data?:
|
|
25
|
+
data?: TData;
|
|
14
26
|
/**
|
|
15
27
|
* Auto display the GUI when added to the system
|
|
16
28
|
* @default false
|
|
@@ -21,7 +33,7 @@ interface GuiOptions {
|
|
|
21
33
|
* The GUI will only display when all dependencies are resolved (!= undefined)
|
|
22
34
|
* @returns Array of Signal dependencies
|
|
23
35
|
*/
|
|
24
|
-
dependencies?: () => Signal[];
|
|
36
|
+
dependencies?: () => Signal<unknown>[];
|
|
25
37
|
/**
|
|
26
38
|
* Attach the GUI to sprites instead of displaying globally
|
|
27
39
|
* When true, the GUI will be rendered in character.ce for each sprite
|
|
@@ -34,30 +46,42 @@ interface GuiOptions {
|
|
|
34
46
|
rpgAttachToSprite?: boolean;
|
|
35
47
|
}
|
|
36
48
|
|
|
37
|
-
export
|
|
49
|
+
export type GuiEntry<TData = unknown> =
|
|
50
|
+
| GuiRegistration<TData>
|
|
51
|
+
| GuiComponent;
|
|
52
|
+
|
|
53
|
+
export interface GuiInstance<
|
|
54
|
+
TData = unknown,
|
|
55
|
+
TComponent extends GuiComponent = GuiComponent,
|
|
56
|
+
> {
|
|
38
57
|
name: string;
|
|
39
|
-
component:
|
|
58
|
+
component: TComponent;
|
|
59
|
+
renderer: GuiRenderer;
|
|
40
60
|
display: WritableSignal<boolean>;
|
|
41
|
-
data: WritableSignal<
|
|
61
|
+
data: WritableSignal<TData>;
|
|
42
62
|
openId?: string;
|
|
43
63
|
autoDisplay: boolean;
|
|
44
|
-
dependencies?: Signal[];
|
|
64
|
+
dependencies?: Signal<unknown>[];
|
|
45
65
|
subscription?: Subscription;
|
|
46
66
|
attachToSprite?: boolean;
|
|
47
67
|
}
|
|
48
68
|
|
|
49
|
-
type
|
|
69
|
+
export type GuiRenderState<
|
|
70
|
+
TData = unknown,
|
|
71
|
+
TComponent extends GuiComponent = GuiComponent,
|
|
72
|
+
> = {
|
|
50
73
|
name: string;
|
|
51
|
-
component:
|
|
74
|
+
component: TComponent;
|
|
75
|
+
renderer: GuiRenderer;
|
|
52
76
|
display: boolean;
|
|
53
|
-
data:
|
|
77
|
+
data: TData;
|
|
54
78
|
openId?: string;
|
|
55
79
|
attachToSprite: boolean;
|
|
56
80
|
};
|
|
57
81
|
|
|
58
82
|
type VueGuiBridge = {
|
|
59
|
-
updateGuiState?: (state:
|
|
60
|
-
initializeGuiStates?: (states:
|
|
83
|
+
updateGuiState?: (state: GuiRenderState) => void;
|
|
84
|
+
initializeGuiStates?: (states: GuiRenderState[]) => void;
|
|
61
85
|
};
|
|
62
86
|
|
|
63
87
|
interface GuiAction {
|
|
@@ -150,35 +174,43 @@ export class RpgGui {
|
|
|
150
174
|
this.add({
|
|
151
175
|
name: "rpg-dialog",
|
|
152
176
|
component: DialogboxComponent,
|
|
177
|
+
renderer: "canvas",
|
|
153
178
|
});
|
|
154
179
|
this.add({
|
|
155
180
|
name: PrebuiltGui.MainMenu,
|
|
156
181
|
component: MainMenuComponent,
|
|
182
|
+
renderer: "canvas",
|
|
157
183
|
});
|
|
158
184
|
this.add({
|
|
159
185
|
name: PrebuiltGui.Shop,
|
|
160
186
|
component: ShopComponent,
|
|
187
|
+
renderer: "canvas",
|
|
161
188
|
});
|
|
162
189
|
this.add({
|
|
163
190
|
name: PrebuiltGui.Notification,
|
|
164
191
|
component: NotificationComponent,
|
|
192
|
+
renderer: "canvas",
|
|
165
193
|
autoDisplay: true,
|
|
166
194
|
});
|
|
167
195
|
this.add({
|
|
168
196
|
name: PrebuiltGui.Save,
|
|
169
197
|
component: SaveLoadComponent,
|
|
198
|
+
renderer: "canvas",
|
|
170
199
|
});
|
|
171
200
|
this.add({
|
|
172
201
|
name: PrebuiltGui.TitleScreen,
|
|
173
202
|
component: TitleScreenComponent,
|
|
203
|
+
renderer: "canvas",
|
|
174
204
|
});
|
|
175
205
|
this.add({
|
|
176
206
|
name: PrebuiltGui.Gameover,
|
|
177
207
|
component: GameoverComponent,
|
|
208
|
+
renderer: "canvas",
|
|
178
209
|
});
|
|
179
210
|
this.add({
|
|
180
211
|
name: PrebuiltGui.Input,
|
|
181
212
|
component: InputComponent,
|
|
213
|
+
renderer: "canvas",
|
|
182
214
|
});
|
|
183
215
|
|
|
184
216
|
this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);
|
|
@@ -311,21 +343,24 @@ export class RpgGui {
|
|
|
311
343
|
* });
|
|
312
344
|
* ```
|
|
313
345
|
*/
|
|
314
|
-
add(gui:
|
|
315
|
-
const
|
|
316
|
-
const
|
|
346
|
+
add(gui: GuiEntry) {
|
|
347
|
+
const registration = this.resolveRegistration(gui);
|
|
348
|
+
const component = registration.component;
|
|
349
|
+
const guiId = registration.name || registration.id || this.resolveComponentName(component);
|
|
317
350
|
if (!guiId) {
|
|
318
351
|
throw new Error("GUI must have a name or id");
|
|
319
352
|
}
|
|
320
|
-
const attachToSprite = this.resolveAttachToSprite(
|
|
353
|
+
const attachToSprite = this.resolveAttachToSprite(registration, component);
|
|
354
|
+
const renderer = registration.renderer ?? this.resolveLegacyRenderer(component);
|
|
321
355
|
const guiInstance: GuiInstance = {
|
|
322
356
|
name: guiId,
|
|
323
357
|
component,
|
|
324
|
-
|
|
325
|
-
|
|
358
|
+
renderer,
|
|
359
|
+
display: signal<boolean>(registration.display || false),
|
|
360
|
+
data: signal(registration.data ?? {}),
|
|
326
361
|
openId: undefined,
|
|
327
|
-
autoDisplay:
|
|
328
|
-
dependencies:
|
|
362
|
+
autoDisplay: registration.autoDisplay || false,
|
|
363
|
+
dependencies: registration.dependencies ? registration.dependencies() : [],
|
|
329
364
|
attachToSprite,
|
|
330
365
|
};
|
|
331
366
|
|
|
@@ -342,7 +377,7 @@ export class RpgGui {
|
|
|
342
377
|
this._initializeVueComponents();
|
|
343
378
|
|
|
344
379
|
if (guiInstance.autoDisplay) {
|
|
345
|
-
this.display(guiId,
|
|
380
|
+
this.display(guiId, registration.data);
|
|
346
381
|
} else {
|
|
347
382
|
this._notifyVueGui(guiId, guiInstance.display(), guiInstance.data());
|
|
348
383
|
}
|
|
@@ -354,8 +389,8 @@ export class RpgGui {
|
|
|
354
389
|
this._initializeVueComponents();
|
|
355
390
|
|
|
356
391
|
// Auto display if enabled and it's a CanvasEngine component
|
|
357
|
-
if (guiInstance.autoDisplay && typeof
|
|
358
|
-
this.display(guiId,
|
|
392
|
+
if (guiInstance.autoDisplay && typeof component === 'function') {
|
|
393
|
+
this.display(guiId, registration.data);
|
|
359
394
|
}
|
|
360
395
|
}
|
|
361
396
|
|
|
@@ -400,15 +435,15 @@ export class RpgGui {
|
|
|
400
435
|
return this.attachedGuiDisplayState()[playerId] === true;
|
|
401
436
|
}
|
|
402
437
|
|
|
403
|
-
get(id: string): GuiInstance | undefined {
|
|
438
|
+
get<TData = unknown>(id: string): GuiInstance<TData> | undefined {
|
|
404
439
|
// Check CanvasEngine GUIs first
|
|
405
440
|
const canvasGui = this.gui()[id];
|
|
406
441
|
if (canvasGui) {
|
|
407
|
-
return canvasGui
|
|
442
|
+
return canvasGui as GuiInstance<TData>;
|
|
408
443
|
}
|
|
409
444
|
|
|
410
445
|
// Check Vue GUIs in extraGuis
|
|
411
|
-
return this.extraGuis.find(gui => gui.name === id);
|
|
446
|
+
return this.extraGuis.find(gui => gui.name === id) as GuiInstance<TData> | undefined;
|
|
412
447
|
}
|
|
413
448
|
|
|
414
449
|
exists(id: string): boolean {
|
|
@@ -447,7 +482,12 @@ export class RpgGui {
|
|
|
447
482
|
* gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);
|
|
448
483
|
* ```
|
|
449
484
|
*/
|
|
450
|
-
display(
|
|
485
|
+
display(
|
|
486
|
+
id: string,
|
|
487
|
+
data: unknown = {},
|
|
488
|
+
dependencies: Signal<unknown>[] = [],
|
|
489
|
+
openId?: string,
|
|
490
|
+
) {
|
|
451
491
|
if (!this.exists(id)) {
|
|
452
492
|
throw throwError(id);
|
|
453
493
|
}
|
|
@@ -595,7 +635,7 @@ export class RpgGui {
|
|
|
595
635
|
}
|
|
596
636
|
|
|
597
637
|
private isVueComponentInstance(gui: GuiInstance) {
|
|
598
|
-
return
|
|
638
|
+
return gui.renderer === "vue";
|
|
599
639
|
}
|
|
600
640
|
|
|
601
641
|
private removeCanvasGui(guiId: string) {
|
|
@@ -614,22 +654,46 @@ export class RpgGui {
|
|
|
614
654
|
}
|
|
615
655
|
}
|
|
616
656
|
|
|
617
|
-
private
|
|
618
|
-
|
|
657
|
+
private resolveRegistration(gui: GuiEntry): GuiRegistration {
|
|
658
|
+
if (
|
|
659
|
+
typeof gui === "object"
|
|
660
|
+
&& gui !== null
|
|
661
|
+
&& "component" in gui
|
|
662
|
+
) {
|
|
663
|
+
return gui as GuiRegistration;
|
|
664
|
+
}
|
|
665
|
+
return { component: gui };
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
private resolveComponentName(component: GuiComponent): string | undefined {
|
|
669
|
+
const named = component as { name?: unknown; __name?: unknown };
|
|
670
|
+
if (typeof named.name === "string" && named.name.length > 0) return named.name;
|
|
671
|
+
if (typeof named.__name === "string" && named.__name.length > 0) return named.__name;
|
|
672
|
+
return undefined;
|
|
619
673
|
}
|
|
620
674
|
|
|
621
|
-
private
|
|
622
|
-
return
|
|
675
|
+
private resolveLegacyRenderer(component: GuiComponent): GuiRenderer {
|
|
676
|
+
return typeof component === "function" ? "canvas" : "vue";
|
|
623
677
|
}
|
|
624
678
|
|
|
625
|
-
private resolveAttachToSprite(gui:
|
|
626
|
-
|
|
679
|
+
private resolveAttachToSprite(gui: GuiRegistration, component: GuiComponent) {
|
|
680
|
+
const componentOptions = component as {
|
|
681
|
+
attachToSprite?: unknown;
|
|
682
|
+
rpgAttachToSprite?: unknown;
|
|
683
|
+
};
|
|
684
|
+
return !!(
|
|
685
|
+
gui.attachToSprite
|
|
686
|
+
|| gui.rpgAttachToSprite
|
|
687
|
+
|| componentOptions.attachToSprite
|
|
688
|
+
|| componentOptions.rpgAttachToSprite
|
|
689
|
+
);
|
|
627
690
|
}
|
|
628
691
|
|
|
629
|
-
private toGuiState(gui: GuiInstance, display = gui.display(), data = gui.data()):
|
|
692
|
+
private toGuiState(gui: GuiInstance, display = gui.display(), data = gui.data()): GuiRenderState {
|
|
630
693
|
return {
|
|
631
694
|
name: gui.name,
|
|
632
695
|
component: gui.component,
|
|
696
|
+
renderer: gui.renderer,
|
|
633
697
|
display,
|
|
634
698
|
data,
|
|
635
699
|
openId: gui.openId,
|
package/src/RpgClient.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
RpgInteractionBehavior,
|
|
14
14
|
RpgInteractionMatcher,
|
|
15
15
|
} from './services/interactions'
|
|
16
|
+
import type { GuiEntry } from './Gui/Gui'
|
|
16
17
|
|
|
17
18
|
type RpgClass<T = any> = new (...args: any[]) => T
|
|
18
19
|
type RpgComponent = RpgClientObject
|
|
@@ -570,69 +571,7 @@ export interface RpgClient {
|
|
|
570
571
|
* @prop {Array<GuiOptions>} [gui]
|
|
571
572
|
* @memberof RpgClient
|
|
572
573
|
* */
|
|
573
|
-
gui?:
|
|
574
|
-
id: string,
|
|
575
|
-
component: ComponentFunction,
|
|
576
|
-
/**
|
|
577
|
-
* Auto display the GUI when added to the system
|
|
578
|
-
* @default false
|
|
579
|
-
*/
|
|
580
|
-
autoDisplay?: boolean,
|
|
581
|
-
/**
|
|
582
|
-
* Function that returns an array of Signal dependencies
|
|
583
|
-
* The GUI will only display when all dependencies are resolved (!= undefined)
|
|
584
|
-
*/
|
|
585
|
-
dependencies?: () => Signal[]
|
|
586
|
-
/**
|
|
587
|
-
* Attach the GUI to sprites instead of displaying globally
|
|
588
|
-
*
|
|
589
|
-
* When set to `true`, the GUI component will be rendered directly on each sprite
|
|
590
|
-
* in the game world, rather than being displayed as a fixed overlay on the screen.
|
|
591
|
-
* This is useful for tooltips, health bars, name tags, or any UI element that
|
|
592
|
-
* should follow a specific sprite.
|
|
593
|
-
*
|
|
594
|
-
* The GUI will be rendered in the `character.ce` component for each sprite.
|
|
595
|
-
* You can control the display state of attached GUIs from the server side using
|
|
596
|
-
* `player.showAttachedGui()` and `player.hideAttachedGui()` methods.
|
|
597
|
-
*
|
|
598
|
-
* @default false
|
|
599
|
-
* @example
|
|
600
|
-
* ```ts
|
|
601
|
-
* import { defineModule, RpgClient } from '@rpgjs/client'
|
|
602
|
-
* import TooltipComponent from './tooltip.ce'
|
|
603
|
-
*
|
|
604
|
-
* defineModule<RpgClient>({
|
|
605
|
-
* gui: [
|
|
606
|
-
* {
|
|
607
|
-
* id: "my-tooltip",
|
|
608
|
-
* component: TooltipComponent,
|
|
609
|
-
* attachToSprite: true
|
|
610
|
-
* }
|
|
611
|
-
* ]
|
|
612
|
-
* })
|
|
613
|
-
* ```
|
|
614
|
-
*
|
|
615
|
-
* On the server side, control the display:
|
|
616
|
-
* ```ts
|
|
617
|
-
* // Show the tooltip for this player
|
|
618
|
-
* player.showAttachedGui()
|
|
619
|
-
*
|
|
620
|
-
* // Hide the tooltip for this player
|
|
621
|
-
* player.hideAttachedGui()
|
|
622
|
-
*
|
|
623
|
-
* // Show tooltip for other players
|
|
624
|
-
* player.showAttachedGui([otherPlayer1, otherPlayer2])
|
|
625
|
-
* ```
|
|
626
|
-
*/
|
|
627
|
-
attachToSprite?: boolean
|
|
628
|
-
/**
|
|
629
|
-
* Vue v4 compatibility alias for `attachToSprite`.
|
|
630
|
-
*
|
|
631
|
-
* Prefer `attachToSprite` in v5 projects. This is read by `@rpgjs/vue`
|
|
632
|
-
* for Vue GUI components migrated from the v4 GUI API.
|
|
633
|
-
*/
|
|
634
|
-
rpgAttachToSprite?: boolean
|
|
635
|
-
} | any)[],
|
|
574
|
+
gui?: GuiEntry[],
|
|
636
575
|
|
|
637
576
|
/**
|
|
638
577
|
* Array containing the list of sounds
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { describe, expectTypeOf, test } from "vitest";
|
|
2
2
|
import type { RpgContext, RpgProvider } from "@rpgjs/common";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
provideMmorpg,
|
|
5
|
+
startGame,
|
|
6
|
+
type GuiRegistration,
|
|
7
|
+
type GuiRenderer,
|
|
8
|
+
} from "./index";
|
|
4
9
|
|
|
5
10
|
describe("client public API types", () => {
|
|
6
11
|
test("bootstrap and providers expose RPGJS-owned contracts", () => {
|
|
@@ -16,4 +21,17 @@ describe("client public API types", () => {
|
|
|
16
21
|
type LegacyContext = typeof import("./index")["Context"];
|
|
17
22
|
expectTypeOf<LegacyContext>();
|
|
18
23
|
});
|
|
24
|
+
|
|
25
|
+
test("GUI registrations expose renderer-neutral typed data", () => {
|
|
26
|
+
type DialogData = { message: string };
|
|
27
|
+
const registration: GuiRegistration<DialogData> = {
|
|
28
|
+
id: "dialog",
|
|
29
|
+
component: () => null,
|
|
30
|
+
renderer: "canvas",
|
|
31
|
+
data: { message: "Hello" },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
expectTypeOf(registration.renderer).toEqualTypeOf<GuiRenderer | undefined>();
|
|
35
|
+
expectTypeOf(registration.data).toEqualTypeOf<DialogData | undefined>();
|
|
36
|
+
});
|
|
19
37
|
});
|