@rpgjs/client 5.0.0-beta.26 → 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 +47 -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 +36 -17
- 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/inject.d.ts +4 -4
- package/dist/core/inject.js.map +1 -1
- package/dist/core/setup.d.ts +3 -3
- package/dist/core/setup.js +1 -1
- package/dist/core/setup.js.map +1 -1
- package/dist/core/setup.spec.d.ts +1 -0
- package/dist/i18n.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -2
- package/dist/module.d.ts +2 -2
- 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/public-api-types.spec.d.ts +1 -0
- package/dist/services/AbstractSocket.d.ts +3 -3
- package/dist/services/AbstractSocket.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/loadMap.d.ts +3 -7
- package/dist/services/loadMap.js +2 -2
- package/dist/services/loadMap.js.map +1 -1
- package/dist/services/mapStreaming.d.ts +2 -16
- 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.d.ts +4 -26
- 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.d.ts +2 -98
- 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 +10 -10
- package/src/Game/Object.spec.ts +1 -1
- package/src/Game/Object.ts +4 -4
- package/src/Gui/Gui.spec.ts +26 -1
- package/src/Gui/Gui.ts +104 -40
- package/src/RpgClient.ts +2 -63
- package/src/core/inject.ts +6 -5
- package/src/core/setup.spec.ts +35 -0
- package/src/core/setup.ts +8 -6
- package/src/index.ts +12 -1
- package/src/module.ts +2 -2
- package/src/public-api-types.spec.ts +37 -0
- package/src/services/AbstractSocket.ts +2 -2
- package/src/services/loadMap.ts +8 -8
- package/src/services/mapStreaming.ts +7 -5
- package/src/services/mmorpg.ts +6 -7
- package/src/services/standalone.ts +4 -5
|
@@ -38,7 +38,8 @@ function createClientPointerContext() {
|
|
|
38
38
|
update,
|
|
39
39
|
updateFromEvent(event) {
|
|
40
40
|
const global = extractGlobalPoint(event);
|
|
41
|
-
|
|
41
|
+
const world = extractWorldPoint(event, global);
|
|
42
|
+
return update(global, world);
|
|
42
43
|
}
|
|
43
44
|
};
|
|
44
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pointerContext.js","names":[],"sources":["../../src/services/pointerContext.ts"],"sourcesContent":["export interface ClientPointerPosition {\n x: number;\n y: number;\n}\n\nexport interface ClientPointerContext {\n screen(): ClientPointerPosition | null;\n world(): ClientPointerPosition | null;\n update(screen: ClientPointerPosition | null, world?: ClientPointerPosition | null): ClientPointerPosition | null;\n updateFromEvent(event: any): ClientPointerPosition | null;\n}\n\nfunction toPosition(point: any): ClientPointerPosition | null {\n const x = Number(point?.x);\n const y = Number(point?.y);\n\n if (!Number.isFinite(x) || !Number.isFinite(y)) {\n return null;\n }\n\n return { x, y };\n}\n\nfunction extractGlobalPoint(event: any): ClientPointerPosition | null {\n return toPosition(event?.global)\n ?? toPosition(event?.data?.global)\n ?? toPosition(event);\n}\n\nfunction extractWorldPoint(event: any, global: ClientPointerPosition | null): ClientPointerPosition | null {\n const target = event?.currentTarget ?? event?.target;\n\n if (target && global && typeof target.toLocal === \"function\") {\n return toPosition(target.toLocal(global));\n }\n\n if (typeof event?.getLocalPosition === \"function\") {\n return toPosition(event.getLocalPosition(target));\n }\n\n if (typeof event?.data?.getLocalPosition === \"function\") {\n return toPosition(event.data.getLocalPosition(target));\n }\n\n return global;\n}\n\nexport function createClientPointerContext(): ClientPointerContext {\n let lastScreen: ClientPointerPosition | null = null;\n let lastWorld: ClientPointerPosition | null = null;\n\n const update = (screen: ClientPointerPosition | null, world?: ClientPointerPosition | null) => {\n const nextScreen = toPosition(screen);\n const nextWorld = toPosition(world) ?? nextScreen;\n\n if (nextScreen) {\n lastScreen = nextScreen;\n }\n\n if (nextWorld) {\n lastWorld = nextWorld;\n }\n\n return lastWorld ? { ...lastWorld } : null;\n };\n\n return {\n screen() {\n return lastScreen ? { ...lastScreen } : null;\n },\n\n world() {\n return lastWorld ? { ...lastWorld } : null;\n },\n\n update,\n\n updateFromEvent(event: any) {\n const global = extractGlobalPoint(event);\n const world = extractWorldPoint(event, global);\n return update(global, world);\n },\n };\n}\n"],"mappings":";AAYA,SAAS,WAAW,OAA0C;CAC5D,MAAM,IAAI,OAAO,OAAO,CAAC;CACzB,MAAM,IAAI,OAAO,OAAO,CAAC;CAEzB,IAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAC3C,OAAO;CAGT,OAAO;EAAE;EAAG;CAAE;AAChB;AAEA,SAAS,mBAAmB,OAA0C;CACpE,OAAO,WAAW,OAAO,MAAM,KAC1B,WAAW,OAAO,MAAM,MAAM,KAC9B,WAAW,KAAK;AACvB;AAEA,SAAS,kBAAkB,OAAY,QAAoE;CACzG,MAAM,SAAS,OAAO,iBAAiB,OAAO;CAE9C,IAAI,UAAU,UAAU,OAAO,OAAO,YAAY,YAChD,OAAO,WAAW,OAAO,QAAQ,MAAM,CAAC;CAG1C,IAAI,OAAO,OAAO,qBAAqB,YACrC,OAAO,WAAW,MAAM,iBAAiB,MAAM,CAAC;CAGlD,IAAI,OAAO,OAAO,MAAM,qBAAqB,YAC3C,OAAO,WAAW,MAAM,KAAK,iBAAiB,MAAM,CAAC;CAGvD,OAAO;AACT;AAEA,SAAgB,6BAAmD;CACjE,IAAI,aAA2C;CAC/C,IAAI,YAA0C;CAE9C,MAAM,UAAU,QAAsC,UAAyC;EAC7F,MAAM,aAAa,WAAW,MAAM;EACpC,MAAM,YAAY,WAAW,KAAK,KAAK;EAEvC,IAAI,YACF,aAAa;EAGf,IAAI,WACF,YAAY;EAGd,OAAO,YAAY,EAAE,GAAG,UAAU,IAAI;CACxC;CAEA,OAAO;EACL,SAAS;GACP,OAAO,aAAa,EAAE,GAAG,WAAW,IAAI;EAC1C;EAEA,QAAQ;GACN,OAAO,YAAY,EAAE,GAAG,UAAU,IAAI;EACxC;EAEA;EAEA,gBAAgB,OAAY;GAC1B,MAAM,SAAS,mBAAmB,KAAK;
|
|
1
|
+
{"version":3,"file":"pointerContext.js","names":[],"sources":["../../src/services/pointerContext.ts"],"sourcesContent":["export interface ClientPointerPosition {\n x: number;\n y: number;\n}\n\nexport interface ClientPointerContext {\n screen(): ClientPointerPosition | null;\n world(): ClientPointerPosition | null;\n update(screen: ClientPointerPosition | null, world?: ClientPointerPosition | null): ClientPointerPosition | null;\n updateFromEvent(event: any): ClientPointerPosition | null;\n}\n\nfunction toPosition(point: any): ClientPointerPosition | null {\n const x = Number(point?.x);\n const y = Number(point?.y);\n\n if (!Number.isFinite(x) || !Number.isFinite(y)) {\n return null;\n }\n\n return { x, y };\n}\n\nfunction extractGlobalPoint(event: any): ClientPointerPosition | null {\n return toPosition(event?.global)\n ?? toPosition(event?.data?.global)\n ?? toPosition(event);\n}\n\nfunction extractWorldPoint(event: any, global: ClientPointerPosition | null): ClientPointerPosition | null {\n const target = event?.currentTarget ?? event?.target;\n\n if (target && global && typeof target.toLocal === \"function\") {\n return toPosition(target.toLocal(global));\n }\n\n if (typeof event?.getLocalPosition === \"function\") {\n return toPosition(event.getLocalPosition(target));\n }\n\n if (typeof event?.data?.getLocalPosition === \"function\") {\n return toPosition(event.data.getLocalPosition(target));\n }\n\n return global;\n}\n\nexport function createClientPointerContext(): ClientPointerContext {\n let lastScreen: ClientPointerPosition | null = null;\n let lastWorld: ClientPointerPosition | null = null;\n\n const update = (screen: ClientPointerPosition | null, world?: ClientPointerPosition | null) => {\n const nextScreen = toPosition(screen);\n const nextWorld = toPosition(world) ?? nextScreen;\n\n if (nextScreen) {\n lastScreen = nextScreen;\n }\n\n if (nextWorld) {\n lastWorld = nextWorld;\n }\n\n return lastWorld ? { ...lastWorld } : null;\n };\n\n return {\n screen() {\n return lastScreen ? { ...lastScreen } : null;\n },\n\n world() {\n return lastWorld ? { ...lastWorld } : null;\n },\n\n update,\n\n updateFromEvent(event: any) {\n const global = extractGlobalPoint(event);\n const world = extractWorldPoint(event, global);\n return update(global, world);\n },\n };\n}\n"],"mappings":";AAYA,SAAS,WAAW,OAA0C;CAC5D,MAAM,IAAI,OAAO,OAAO,CAAC;CACzB,MAAM,IAAI,OAAO,OAAO,CAAC;CAEzB,IAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAC3C,OAAO;CAGT,OAAO;EAAE;EAAG;CAAE;AAChB;AAEA,SAAS,mBAAmB,OAA0C;CACpE,OAAO,WAAW,OAAO,MAAM,KAC1B,WAAW,OAAO,MAAM,MAAM,KAC9B,WAAW,KAAK;AACvB;AAEA,SAAS,kBAAkB,OAAY,QAAoE;CACzG,MAAM,SAAS,OAAO,iBAAiB,OAAO;CAE9C,IAAI,UAAU,UAAU,OAAO,OAAO,YAAY,YAChD,OAAO,WAAW,OAAO,QAAQ,MAAM,CAAC;CAG1C,IAAI,OAAO,OAAO,qBAAqB,YACrC,OAAO,WAAW,MAAM,iBAAiB,MAAM,CAAC;CAGlD,IAAI,OAAO,OAAO,MAAM,qBAAqB,YAC3C,OAAO,WAAW,MAAM,KAAK,iBAAiB,MAAM,CAAC;CAGvD,OAAO;AACT;AAEA,SAAgB,6BAAmD;CACjE,IAAI,aAA2C;CAC/C,IAAI,YAA0C;CAE9C,MAAM,UAAU,QAAsC,UAAyC;EAC7F,MAAM,aAAa,WAAW,MAAM;EACpC,MAAM,YAAY,WAAW,KAAK,KAAK;EAEvC,IAAI,YACF,aAAa;EAGf,IAAI,WACF,YAAY;EAGd,OAAO,YAAY,EAAE,GAAG,UAAU,IAAI;CACxC;CAEA,OAAO;EACL,SAAS;GACP,OAAO,aAAa,EAAE,GAAG,WAAW,IAAI;EAC1C;EAEA,QAAQ;GACN,OAAO,YAAY,EAAE,GAAG,UAAU,IAAI;EACxC;EAEA;EAEA,gBAAgB,OAAY;GAC1B,MAAM,SAAS,mBAAmB,KAAK;GACvC,MAAM,QAAQ,kBAAkB,OAAO,MAAM;GAC7C,OAAO,OAAO,QAAQ,KAAK;EAC7B;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save.js","names":[],"sources":["../../src/services/save.ts"],"sourcesContent":["import type { SaveSlotList, SaveSlotMeta } from \"@rpgjs/common\";\nimport { inject } from \"../core/inject\";\nimport { AbstractWebsocket, WebSocketToken } from \"./AbstractSocket\";\n\nexport const SaveClientToken = \"SaveClientToken\";\n\ntype SaveListResult = {\n requestId: string;\n slots: SaveSlotList;\n};\n\ntype SaveSaveResult = {\n requestId: string;\n index: number;\n slots: SaveSlotList;\n};\n\ntype SaveLoadResult = {\n requestId: string;\n index: number;\n ok: boolean;\n slot?: SaveSlotMeta;\n};\n\ntype SaveErrorResult = {\n requestId: string;\n message: string;\n};\n\ntype PendingRequest = {\n resolve: (value: any) => void;\n reject: (error: Error) => void;\n};\n\nexport class SaveClientService {\n private webSocket: AbstractWebsocket = inject(WebSocketToken);\n private pending: Map<string, PendingRequest> = new Map();\n private requestCounter = 0;\n\n initialize() {\n const saveListResult = (data: SaveListResult) => this.resolveRequest(data.requestId, data);\n const saveSaveResult = (data: SaveSaveResult) => this.resolveRequest(data.requestId, data);\n const saveLoadResult = (data: SaveLoadResult) => this.resolveRequest(data.requestId, data);\n const saveErrorResult = (data: SaveErrorResult) => this.rejectRequest(data.requestId, data.message);\n this.webSocket.off(\"save.list.result\", saveListResult);\n this.webSocket.off(\"save.save.result\", saveSaveResult);\n this.webSocket.off(\"save.load.result\", saveLoadResult);\n this.webSocket.off(\"save.error\", saveErrorResult);\n this.webSocket.on(\"save.list.result\", saveListResult);\n this.webSocket.on(\"save.save.result\", saveSaveResult);\n this.webSocket.on(\"save.load.result\", saveLoadResult);\n this.webSocket.on(\"save.error\", saveErrorResult);\n }\n\n listSlots(): Promise<SaveSlotList> {\n return this.request<SaveListResult>(\"save.list\", {}).then((result) => result.slots);\n }\n\n saveSlot(index: number, meta: SaveSlotMeta = {}): Promise<SaveSlotList> {\n return this.request<SaveSaveResult>(\"save.save\", { index, meta }).then((result) => result.slots);\n }\n\n loadSlot(index: number): Promise<boolean> {\n return this.request<SaveLoadResult>(\"save.load\", { index }).then((result) => result.ok);\n }\n\n private request<T>(event: string, payload: Record<string, any>): Promise<T> {\n return new Promise((resolve, reject) => {\n if (!this.webSocket) {\n this.initialize();\n }\n const requestId = this.nextRequestId();\n this.pending.set(requestId, { resolve, reject });\n this.webSocket?.emit(event, { requestId, ...payload });\n });\n }\n\n private resolveRequest(requestId: string, result: any) {\n const pending = this.pending.get(requestId);\n if (!pending) return;\n this.pending.delete(requestId);\n pending.resolve(result);\n }\n\n private rejectRequest(requestId: string, message: string) {\n const pending = this.pending.get(requestId);\n if (!pending) return;\n this.pending.delete(requestId);\n pending.reject(new Error(message));\n }\n\n private nextRequestId(): string {\n this.requestCounter += 1;\n return `${Date.now()}-${this.requestCounter}`;\n }\n}\n\nexport function provideSaveClient() {\n return {\n provide: SaveClientService,\n useClass: SaveClientService,\n };\n}\n"],"mappings":";;;AAIA,IAAa,kBAAkB;AA8B/B,IAAa,oBAAb,MAA+B;;mBACU,OAAO,cAAc;iCACb,IAAI,IAAI;wBAC9B;;CAEzB,aAAa;EACX,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,IAAI;EACzF,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,IAAI;EACzF,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,IAAI;EACzF,MAAM,mBAAmB,SAA0B,KAAK,cAAc,KAAK,WAAW,KAAK,OAAO;EAClG,KAAK,UAAU,IAAI,oBAAoB,cAAc;EACrD,KAAK,UAAU,IAAI,oBAAoB,cAAc;EACrD,KAAK,UAAU,IAAI,oBAAoB,cAAc;EACrD,KAAK,UAAU,IAAI,cAAc,eAAe;EAChD,KAAK,UAAU,GAAG,oBAAoB,cAAc;EACpD,KAAK,UAAU,GAAG,oBAAoB,cAAc;EACpD,KAAK,UAAU,GAAG,oBAAoB,cAAc;EACpD,KAAK,UAAU,GAAG,cAAc,eAAe;CACjD;CAEA,YAAmC;EACjC,OAAO,KAAK,QAAwB,aAAa,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"save.js","names":[],"sources":["../../src/services/save.ts"],"sourcesContent":["import type { SaveSlotList, SaveSlotMeta } from \"@rpgjs/common\";\nimport { inject } from \"../core/inject\";\nimport { AbstractWebsocket, WebSocketToken } from \"./AbstractSocket\";\n\nexport const SaveClientToken = \"SaveClientToken\";\n\ntype SaveListResult = {\n requestId: string;\n slots: SaveSlotList;\n};\n\ntype SaveSaveResult = {\n requestId: string;\n index: number;\n slots: SaveSlotList;\n};\n\ntype SaveLoadResult = {\n requestId: string;\n index: number;\n ok: boolean;\n slot?: SaveSlotMeta;\n};\n\ntype SaveErrorResult = {\n requestId: string;\n message: string;\n};\n\ntype PendingRequest = {\n resolve: (value: any) => void;\n reject: (error: Error) => void;\n};\n\nexport class SaveClientService {\n private webSocket: AbstractWebsocket = inject(WebSocketToken);\n private pending: Map<string, PendingRequest> = new Map();\n private requestCounter = 0;\n\n initialize() {\n const saveListResult = (data: SaveListResult) => this.resolveRequest(data.requestId, data);\n const saveSaveResult = (data: SaveSaveResult) => this.resolveRequest(data.requestId, data);\n const saveLoadResult = (data: SaveLoadResult) => this.resolveRequest(data.requestId, data);\n const saveErrorResult = (data: SaveErrorResult) => this.rejectRequest(data.requestId, data.message);\n this.webSocket.off(\"save.list.result\", saveListResult);\n this.webSocket.off(\"save.save.result\", saveSaveResult);\n this.webSocket.off(\"save.load.result\", saveLoadResult);\n this.webSocket.off(\"save.error\", saveErrorResult);\n this.webSocket.on(\"save.list.result\", saveListResult);\n this.webSocket.on(\"save.save.result\", saveSaveResult);\n this.webSocket.on(\"save.load.result\", saveLoadResult);\n this.webSocket.on(\"save.error\", saveErrorResult);\n }\n\n listSlots(): Promise<SaveSlotList> {\n return this.request<SaveListResult>(\"save.list\", {}).then((result) => result.slots);\n }\n\n saveSlot(index: number, meta: SaveSlotMeta = {}): Promise<SaveSlotList> {\n return this.request<SaveSaveResult>(\"save.save\", { index, meta }).then((result) => result.slots);\n }\n\n loadSlot(index: number): Promise<boolean> {\n return this.request<SaveLoadResult>(\"save.load\", { index }).then((result) => result.ok);\n }\n\n private request<T>(event: string, payload: Record<string, any>): Promise<T> {\n return new Promise((resolve, reject) => {\n if (!this.webSocket) {\n this.initialize();\n }\n const requestId = this.nextRequestId();\n this.pending.set(requestId, { resolve, reject });\n this.webSocket?.emit(event, { requestId, ...payload });\n });\n }\n\n private resolveRequest(requestId: string, result: any) {\n const pending = this.pending.get(requestId);\n if (!pending) return;\n this.pending.delete(requestId);\n pending.resolve(result);\n }\n\n private rejectRequest(requestId: string, message: string) {\n const pending = this.pending.get(requestId);\n if (!pending) return;\n this.pending.delete(requestId);\n pending.reject(new Error(message));\n }\n\n private nextRequestId(): string {\n this.requestCounter += 1;\n return `${Date.now()}-${this.requestCounter}`;\n }\n}\n\nexport function provideSaveClient() {\n return {\n provide: SaveClientService,\n useClass: SaveClientService,\n };\n}\n"],"mappings":";;;AAIA,IAAa,kBAAkB;AA8B/B,IAAa,oBAAb,MAA+B;;mBACU,OAAO,cAAc;iCACb,IAAI,IAAI;wBAC9B;;CAEzB,aAAa;EACX,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,IAAI;EACzF,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,IAAI;EACzF,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,IAAI;EACzF,MAAM,mBAAmB,SAA0B,KAAK,cAAc,KAAK,WAAW,KAAK,OAAO;EAClG,KAAK,UAAU,IAAI,oBAAoB,cAAc;EACrD,KAAK,UAAU,IAAI,oBAAoB,cAAc;EACrD,KAAK,UAAU,IAAI,oBAAoB,cAAc;EACrD,KAAK,UAAU,IAAI,cAAc,eAAe;EAChD,KAAK,UAAU,GAAG,oBAAoB,cAAc;EACpD,KAAK,UAAU,GAAG,oBAAoB,cAAc;EACpD,KAAK,UAAU,GAAG,oBAAoB,cAAc;EACpD,KAAK,UAAU,GAAG,cAAc,eAAe;CACjD;CAEA,YAAmC;EACjC,OAAO,KAAK,QAAwB,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,WAAW,OAAO,KAAK;CACpF;CAEA,SAAS,OAAe,OAAqB,CAAC,GAA0B;EACtE,OAAO,KAAK,QAAwB,aAAa;GAAE;GAAO;EAAK,CAAC,CAAC,CAAC,MAAM,WAAW,OAAO,KAAK;CACjG;CAEA,SAAS,OAAiC;EACxC,OAAO,KAAK,QAAwB,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,WAAW,OAAO,EAAE;CACxF;CAEA,QAAmB,OAAe,SAA0C;EAC1E,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,CAAC,KAAK,WACR,KAAK,WAAW;GAElB,MAAM,YAAY,KAAK,cAAc;GACrC,KAAK,QAAQ,IAAI,WAAW;IAAE;IAAS;GAAO,CAAC;GAC/C,KAAK,WAAW,KAAK,OAAO;IAAE;IAAW,GAAG;GAAQ,CAAC;EACvD,CAAC;CACH;CAEA,eAAuB,WAAmB,QAAa;EACrD,MAAM,UAAU,KAAK,QAAQ,IAAI,SAAS;EAC1C,IAAI,CAAC,SAAS;EACd,KAAK,QAAQ,OAAO,SAAS;EAC7B,QAAQ,QAAQ,MAAM;CACxB;CAEA,cAAsB,WAAmB,SAAiB;EACxD,MAAM,UAAU,KAAK,QAAQ,IAAI,SAAS;EAC1C,IAAI,CAAC,SAAS;EACd,KAAK,QAAQ,OAAO,SAAS;EAC7B,QAAQ,OAAO,IAAI,MAAM,OAAO,CAAC;CACnC;CAEA,gBAAgC;EAC9B,KAAK,kBAAkB;EACvB,OAAO,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK;CAC/B;AACF;AAEA,SAAgB,oBAAoB;CAClC,OAAO;EACL,SAAS;EACT,UAAU;CACZ;AACF"}
|
|
@@ -1,102 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Context } from '@signe/di';
|
|
3
|
-
import { RpgClientEngine } from '../RpgClientEngine';
|
|
4
|
-
import { UpdateMapService } from '@rpgjs/common';
|
|
5
|
-
import { RpgGui } from '../Gui/Gui';
|
|
1
|
+
import { RpgProvider } from '@rpgjs/common';
|
|
6
2
|
interface StandaloneOptions {
|
|
7
3
|
env?: Record<string, any>;
|
|
8
4
|
}
|
|
9
|
-
declare
|
|
10
|
-
protected context: Context;
|
|
11
|
-
private server;
|
|
12
|
-
readonly mode: "standalone";
|
|
13
|
-
private room;
|
|
14
|
-
private socket;
|
|
15
|
-
private socketRoom?;
|
|
16
|
-
private roomId;
|
|
17
|
-
private query?;
|
|
18
|
-
private readonly privateId;
|
|
19
|
-
private listeners;
|
|
20
|
-
private rooms;
|
|
21
|
-
private serverInstance;
|
|
22
|
-
constructor(context: Context, server: any, options?: StandaloneOptions);
|
|
23
|
-
connection(listeners?: (data: any) => void): Promise<any>;
|
|
24
|
-
private _connection;
|
|
25
|
-
on(key: string, callback: (data: any) => void): void;
|
|
26
|
-
off(event: string, callback: (data: any) => void): void;
|
|
27
|
-
emit(event: string, data: any): void;
|
|
28
|
-
/**
|
|
29
|
-
* Update underlying connection properties before a reconnect
|
|
30
|
-
*
|
|
31
|
-
* Design
|
|
32
|
-
* - Dynamically register a factory for the requested room to ensure a fresh server instance
|
|
33
|
-
* - Swap the internal ServerIo to target the new room
|
|
34
|
-
*
|
|
35
|
-
* @param params - Properties to update
|
|
36
|
-
* @param params.room - The target room id (e.g. `map-simplemap2`)
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* websocket.updateProperties({ room: 'map-simplemap2' })
|
|
41
|
-
* await websocket.reconnect()
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
updateProperties({ room, query }: SocketUpdateProperties): void;
|
|
45
|
-
/**
|
|
46
|
-
* Reconnect the client to the current Party room
|
|
47
|
-
*
|
|
48
|
-
* Design
|
|
49
|
-
* - Must be called after `updateProperties()` when switching rooms
|
|
50
|
-
* - Rebuilds the client <-> server bridge and re-triggers connection listeners
|
|
51
|
-
*
|
|
52
|
-
* @param listeners - Optional callback to re-bind event handlers on the new socket
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```ts
|
|
56
|
-
* websocket.updateProperties({ room: 'map-dungeon' })
|
|
57
|
-
* await websocket.reconnect((socket) => {
|
|
58
|
-
* // re-bind events here
|
|
59
|
-
* })
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
reconnect(listeners?: (data: any) => void): Promise<void>;
|
|
63
|
-
private connectToRoom;
|
|
64
|
-
private normalizeQuery;
|
|
65
|
-
private detachCurrentSocket;
|
|
66
|
-
getServer(): any;
|
|
67
|
-
getSocket(): any;
|
|
68
|
-
}
|
|
69
|
-
declare class UpdateMapStandaloneService extends UpdateMapService {
|
|
70
|
-
private server;
|
|
71
|
-
/**
|
|
72
|
-
* Update the current room map data on the server side
|
|
73
|
-
*
|
|
74
|
-
* Design
|
|
75
|
-
* - Uses the in-memory server instance stored in context (standalone mode)
|
|
76
|
-
* - Builds a local HTTP-like request to the current Party room endpoint
|
|
77
|
-
*
|
|
78
|
-
* @param map - The map payload to apply on the server
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```ts
|
|
82
|
-
* await updateMapService.update({ width: 1024, height: 768, events: [] })
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
update(map: any): Promise<void>;
|
|
86
|
-
}
|
|
87
|
-
export declare function provideRpg(server: any, options?: StandaloneOptions): (typeof RpgClientEngine | typeof RpgGui | {
|
|
88
|
-
provide: typeof import('./save').SaveClientService;
|
|
89
|
-
useClass: typeof import('./save').SaveClientService;
|
|
90
|
-
} | {
|
|
91
|
-
provide: string;
|
|
92
|
-
useValue: null;
|
|
93
|
-
} | {
|
|
94
|
-
provide: string;
|
|
95
|
-
useFactory: (context: Context) => BridgeWebsocket;
|
|
96
|
-
useClass?: undefined;
|
|
97
|
-
} | {
|
|
98
|
-
provide: string;
|
|
99
|
-
useClass: typeof UpdateMapStandaloneService;
|
|
100
|
-
useFactory?: undefined;
|
|
101
|
-
})[];
|
|
5
|
+
export declare function provideRpg(server: any, options?: StandaloneOptions): RpgProvider[];
|
|
102
6
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standalone.js","names":[],"sources":["../../src/services/standalone.ts"],"sourcesContent":["import { AbstractWebsocket, SocketUpdateProperties, WebSocketToken } from \"./AbstractSocket\";\nimport { ClientIo, ServerIo } from \"@signe/room\";\nimport { Context } from \"@signe/di\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { UpdateMapService, UpdateMapToken } from \"@rpgjs/common\";\nimport { LoadMapToken } from \"./loadMap\";\nimport { RpgGui } from \"../Gui/Gui\";\nimport { provideKeyboardControls } from \"./keyboardControls\";\nimport { provideSaveClient } from \"./save\";\nimport { normalizeStandaloneMessage } from \"./standalone-message\";\nimport type { SocketQuery } from \"./AbstractSocket\";\n\ntype ServerIo = any;\ntype ClientIo = any;\n\ninterface StandaloneOptions {\n env?: Record<string, any>;\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n readonly mode = \"standalone\" as const;\n\n private room: ServerIo;\n private socket: ClientIo;\n private socketRoom?: ServerIo;\n private roomId = \"lobby-1\";\n private query?: SocketQuery;\n private readonly privateId = \"player-client-id\";\n private listeners: Array<{\n event: string;\n callback: (data: any) => void;\n handler: (event: any) => void;\n }> = [];\n private rooms = {\n partyFn: async (roomId: string) => {\n const room = new ServerIo(roomId, this.rooms);\n const server = new this.server(room)\n await server.onStart();\n await server.subRoom.onStart()\n return server\n },\n env: {}\n }\n private serverInstance: any;\n\n constructor(protected context: Context, private server: any, options: StandaloneOptions = {}) {\n super(context);\n // fake room\n this.rooms.env = options.env || {};\n this.room = new ServerIo(\"lobby-1\", this.rooms);\n }\n\n async connection(listeners?: (data: any) => void) {\n this.serverInstance = new this.server(this.room);\n await this.serverInstance.onStart();\n await this.serverInstance.subRoom.onStart()\n this.context.set('server', this.serverInstance)\n return this._connection(listeners)\n }\n\n private async _connection(listeners?: (data: any) => void) {\n this.detachCurrentSocket();\n await this.connectToRoom();\n listeners?.(this.socket)\n return this.socket\n }\n\n on(key: string, callback: (data: any) => void) {\n if (\n this.listeners.some(\n (listener) => listener.event === key && listener.callback === callback\n )\n ) {\n return;\n }\n const handler = (event) => {\n const object = normalizeStandaloneMessage(event);\n if (object.type === key) {\n callback(object.value);\n }\n };\n this.listeners.push({ event: key, callback, handler });\n this.socket?.addEventListener(\"message\", handler);\n }\n\n off(event: string, callback: (data: any) => void) {\n const remaining: typeof this.listeners = [];\n for (const listener of this.listeners) {\n if (listener.event === event && listener.callback === callback) {\n this.socket?.removeEventListener(\"message\", listener.handler);\n continue;\n }\n remaining.push(listener);\n }\n this.listeners = remaining;\n }\n\n emit(event: string, data: any) {\n this.socket.send({\n action: event,\n value: data,\n });\n }\n\n /**\n * Update underlying connection properties before a reconnect\n *\n * Design\n * - Dynamically register a factory for the requested room to ensure a fresh server instance\n * - Swap the internal ServerIo to target the new room\n *\n * @param params - Properties to update\n * @param params.room - The target room id (e.g. `map-simplemap2`)\n *\n * @example\n * ```ts\n * websocket.updateProperties({ room: 'map-simplemap2' })\n * await websocket.reconnect()\n * ```\n */\n updateProperties({ room, query }: SocketUpdateProperties) {\n this.roomId = room;\n this.query = query;\n }\n\n /**\n * Reconnect the client to the current Party room\n *\n * Design\n * - Must be called after `updateProperties()` when switching rooms\n * - Rebuilds the client <-> server bridge and re-triggers connection listeners\n *\n * @param listeners - Optional callback to re-bind event handlers on the new socket\n *\n * @example\n * ```ts\n * websocket.updateProperties({ room: 'map-dungeon' })\n * await websocket.reconnect((socket) => {\n * // re-bind events here\n * })\n * ```\n */\n async reconnect(listeners?: (data: any) => void): Promise<void> {\n await this._connection((socket) => {\n listeners?.(socket)\n })\n }\n\n private async connectToRoom() {\n if (this.serverInstance?.room?.id !== this.roomId) {\n const party = await this.room.context.parties.main.get(this.roomId);\n this.serverInstance = party.server;\n this.context.set('server', this.serverInstance);\n this.room = this.serverInstance.room;\n }\n else {\n this.serverInstance = this.context.get('server');\n }\n\n this.socket = new ClientIo(this.serverInstance, this.privateId);\n const url = new URL('http://localhost');\n const query = this.normalizeQuery(this.query);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n url.searchParams.set(key, value);\n }\n }\n const request = new Request(url.toString(), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n this.room.clients.set(this.socket.id, this.socket);\n this.socketRoom = this.room;\n this.listeners.forEach(({ handler }) => {\n this.socket.addEventListener(\"message\", handler);\n });\n await this.serverInstance.onConnect(this.socket.conn as any, { request } as any);\n }\n\n private normalizeQuery(query?: SocketQuery): Record<string, string> | undefined {\n if (!query) {\n return undefined;\n }\n return Object.fromEntries(\n Object.entries(query)\n .filter((entry): entry is [string, string] => typeof entry[1] === \"string\")\n );\n }\n\n private detachCurrentSocket() {\n if (!this.socket) return;\n this.listeners.forEach(({ handler }) => {\n this.socket.removeEventListener(\"message\", handler);\n });\n this.socketRoom?.clients?.delete?.(this.socket.id);\n this.socket = undefined as any;\n this.socketRoom = undefined;\n }\n\n getServer() {\n return this.serverInstance\n }\n\n getSocket() {\n return this.socket\n }\n}\n\nclass UpdateMapStandaloneService extends UpdateMapService {\n private server: any;\n\n /**\n * Update the current room map data on the server side\n *\n * Design\n * - Uses the in-memory server instance stored in context (standalone mode)\n * - Builds a local HTTP-like request to the current Party room endpoint\n *\n * @param map - The map payload to apply on the server\n *\n * @example\n * ```ts\n * await updateMapService.update({ width: 1024, height: 768, events: [] })\n * ```\n */\n async update(map: any) {\n this.server = this.context.get('server')\n const roomId = this.server?.room?.id ?? 'lobby-1'\n const req = {\n url: `http://localhost/parties/main/${roomId}/map/update`,\n method: 'POST',\n headers: new Headers({}),\n json: async () => {\n return map;\n }\n };\n await this.server.onRequest(req)\n }\n}\n\nexport function provideRpg(server: any, options: StandaloneOptions = {}) {\n return [\n {\n provide: WebSocketToken,\n useFactory: (context: Context) => new BridgeWebsocket(context, server, options),\n },\n {\n provide: UpdateMapToken,\n useClass: UpdateMapStandaloneService,\n },\n provideKeyboardControls(),\n provideSaveClient(),\n RpgGui,\n RpgClientEngine,\n ];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"standalone.js","names":[],"sources":["../../src/services/standalone.ts"],"sourcesContent":["import { AbstractWebsocket, SocketUpdateProperties, WebSocketToken } from \"./AbstractSocket\";\nimport { ClientIo, ServerIo } from \"@signe/room\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { UpdateMapService, UpdateMapToken, type RpgContext, type RpgProvider } from \"@rpgjs/common\";\nimport { LoadMapToken } from \"./loadMap\";\nimport { RpgGui } from \"../Gui/Gui\";\nimport { provideKeyboardControls } from \"./keyboardControls\";\nimport { provideSaveClient } from \"./save\";\nimport { normalizeStandaloneMessage } from \"./standalone-message\";\nimport type { SocketQuery } from \"./AbstractSocket\";\n\ntype ServerIo = any;\ntype ClientIo = any;\n\ninterface StandaloneOptions {\n env?: Record<string, any>;\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n readonly mode = \"standalone\" as const;\n\n private room: ServerIo;\n private socket: ClientIo;\n private socketRoom?: ServerIo;\n private roomId = \"lobby-1\";\n private query?: SocketQuery;\n private readonly privateId = \"player-client-id\";\n private listeners: Array<{\n event: string;\n callback: (data: any) => void;\n handler: (event: any) => void;\n }> = [];\n private rooms = {\n partyFn: async (roomId: string) => {\n const room = new ServerIo(roomId, this.rooms);\n const server = new this.server(room)\n await server.onStart();\n await server.subRoom.onStart()\n return server\n },\n env: {}\n }\n private serverInstance: any;\n\n constructor(protected context: RpgContext, private server: any, options: StandaloneOptions = {}) {\n super(context);\n // fake room\n this.rooms.env = options.env || {};\n this.room = new ServerIo(\"lobby-1\", this.rooms);\n }\n\n async connection(listeners?: (data: any) => void) {\n this.serverInstance = new this.server(this.room);\n await this.serverInstance.onStart();\n await this.serverInstance.subRoom.onStart()\n this.context.set('server', this.serverInstance)\n return this._connection(listeners)\n }\n\n private async _connection(listeners?: (data: any) => void) {\n this.detachCurrentSocket();\n await this.connectToRoom();\n listeners?.(this.socket)\n return this.socket\n }\n\n on(key: string, callback: (data: any) => void) {\n if (\n this.listeners.some(\n (listener) => listener.event === key && listener.callback === callback\n )\n ) {\n return;\n }\n const handler = (event) => {\n const object = normalizeStandaloneMessage(event);\n if (object.type === key) {\n callback(object.value);\n }\n };\n this.listeners.push({ event: key, callback, handler });\n this.socket?.addEventListener(\"message\", handler);\n }\n\n off(event: string, callback: (data: any) => void) {\n const remaining: typeof this.listeners = [];\n for (const listener of this.listeners) {\n if (listener.event === event && listener.callback === callback) {\n this.socket?.removeEventListener(\"message\", listener.handler);\n continue;\n }\n remaining.push(listener);\n }\n this.listeners = remaining;\n }\n\n emit(event: string, data: any) {\n this.socket.send({\n action: event,\n value: data,\n });\n }\n\n /**\n * Update underlying connection properties before a reconnect\n *\n * Design\n * - Dynamically register a factory for the requested room to ensure a fresh server instance\n * - Swap the internal ServerIo to target the new room\n *\n * @param params - Properties to update\n * @param params.room - The target room id (e.g. `map-simplemap2`)\n *\n * @example\n * ```ts\n * websocket.updateProperties({ room: 'map-simplemap2' })\n * await websocket.reconnect()\n * ```\n */\n updateProperties({ room, query }: SocketUpdateProperties) {\n this.roomId = room;\n this.query = query;\n }\n\n /**\n * Reconnect the client to the current Party room\n *\n * Design\n * - Must be called after `updateProperties()` when switching rooms\n * - Rebuilds the client <-> server bridge and re-triggers connection listeners\n *\n * @param listeners - Optional callback to re-bind event handlers on the new socket\n *\n * @example\n * ```ts\n * websocket.updateProperties({ room: 'map-dungeon' })\n * await websocket.reconnect((socket) => {\n * // re-bind events here\n * })\n * ```\n */\n async reconnect(listeners?: (data: any) => void): Promise<void> {\n await this._connection((socket) => {\n listeners?.(socket)\n })\n }\n\n private async connectToRoom() {\n if (this.serverInstance?.room?.id !== this.roomId) {\n const party = await this.room.context.parties.main.get(this.roomId);\n this.serverInstance = party.server;\n this.context.set('server', this.serverInstance);\n this.room = this.serverInstance.room;\n }\n else {\n this.serverInstance = this.context.get('server');\n }\n\n this.socket = new ClientIo(this.serverInstance, this.privateId);\n const url = new URL('http://localhost');\n const query = this.normalizeQuery(this.query);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n url.searchParams.set(key, value);\n }\n }\n const request = new Request(url.toString(), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n this.room.clients.set(this.socket.id, this.socket);\n this.socketRoom = this.room;\n this.listeners.forEach(({ handler }) => {\n this.socket.addEventListener(\"message\", handler);\n });\n await this.serverInstance.onConnect(this.socket.conn as any, { request } as any);\n }\n\n private normalizeQuery(query?: SocketQuery): Record<string, string> | undefined {\n if (!query) {\n return undefined;\n }\n return Object.fromEntries(\n Object.entries(query)\n .filter((entry): entry is [string, string] => typeof entry[1] === \"string\")\n );\n }\n\n private detachCurrentSocket() {\n if (!this.socket) return;\n this.listeners.forEach(({ handler }) => {\n this.socket.removeEventListener(\"message\", handler);\n });\n this.socketRoom?.clients?.delete?.(this.socket.id);\n this.socket = undefined as any;\n this.socketRoom = undefined;\n }\n\n getServer() {\n return this.serverInstance\n }\n\n getSocket() {\n return this.socket\n }\n}\n\nclass UpdateMapStandaloneService extends UpdateMapService {\n private server: any;\n\n /**\n * Update the current room map data on the server side\n *\n * Design\n * - Uses the in-memory server instance stored in context (standalone mode)\n * - Builds a local HTTP-like request to the current Party room endpoint\n *\n * @param map - The map payload to apply on the server\n *\n * @example\n * ```ts\n * await updateMapService.update({ width: 1024, height: 768, events: [] })\n * ```\n */\n async update(map: any) {\n this.server = this.context.get('server')\n const roomId = this.server?.room?.id ?? 'lobby-1'\n const req = {\n url: `http://localhost/parties/main/${roomId}/map/update`,\n method: 'POST',\n headers: new Headers({}),\n json: async () => {\n return map;\n }\n };\n await this.server.onRequest(req)\n }\n}\n\nexport function provideRpg(server: any, options: StandaloneOptions = {}): RpgProvider[] {\n return [\n {\n provide: WebSocketToken,\n useFactory: (context: RpgContext) => new BridgeWebsocket(context, server, options),\n },\n {\n provide: UpdateMapToken,\n useClass: UpdateMapStandaloneService,\n },\n provideKeyboardControls(),\n provideSaveClient(),\n RpgGui,\n RpgClientEngine,\n ];\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getEntityProp.js","names":[],"sources":["../../src/utils/getEntityProp.ts"],"sourcesContent":["import { computed, Signal } from \"canvasengine\";\nimport { RpgClientObject } from \"../Game/Object\";\nimport { readPropValue } from \"./readPropValue\";\n\nconst BUILTIN_PARAM_KEYS = [\n \"maxHp\",\n \"maxSp\",\n \"atk\",\n \"pdef\",\n \"sdef\",\n \"str\",\n \"agi\",\n \"int\",\n \"dex\",\n] as const;\n\ntype BuiltInParamKey = typeof BUILTIN_PARAM_KEYS[number];\ntype ParamPropKey = `params.${BuiltInParamKey}` | `params.${string}`;\n\nconst entityPropMap = {\n level: (entity: RpgClientObject) => entity._level(),\n exp: (entity: RpgClientObject) => entity._exp(),\n gold: (entity: RpgClientObject) => entity._gold(),\n hp: (entity: RpgClientObject) => entity.hpSignal(),\n sp: (entity: RpgClientObject) => entity.spSignal(),\n name: (entity: RpgClientObject) => entity.name,\n type: (entity: RpgClientObject) => entity.type(),\n x: (entity: RpgClientObject) => entity.x(),\n y: (entity: RpgClientObject) => entity.y(),\n z: (entity: RpgClientObject) => entity.z(),\n tint: (entity: RpgClientObject) => entity.tint(),\n direction: (entity: RpgClientObject) => entity.direction(),\n speed: (entity: RpgClientObject) => entity.speed,\n hitbox: (entity: RpgClientObject) => entity.hitbox(),\n animation: (entity: RpgClientObject) => entity.animationName(),\n canMove: (entity: RpgClientObject) => readPropValue<boolean>((entity as any)._canMove ?? entity.canMove),\n graphics: (entity: RpgClientObject) => entity.graphics(),\n items: (entity: RpgClientObject) => entity.items(),\n equipments: (entity: RpgClientObject) => entity.equipments(),\n states: (entity: RpgClientObject) => entity.states(),\n skills: (entity: RpgClientObject) => entity.skills(),\n effects: (entity: RpgClientObject) => entity._effects(),\n componentsTop: (entity: RpgClientObject) => entity.componentsTop(),\n componentsBottom: (entity: RpgClientObject) => entity.componentsBottom(),\n componentsCenter: (entity: RpgClientObject) => entity.componentsCenter(),\n componentsLeft: (entity: RpgClientObject) => entity.componentsLeft(),\n componentsRight: (entity: RpgClientObject) => entity.componentsRight(),\n} as const;\n\ntype EntityPropMap = typeof entityPropMap;\ntype EntityPropKey = keyof EntityPropMap | ParamPropKey;\ntype EntityPropValue<K extends EntityPropKey> = K extends keyof EntityPropMap\n ? ReturnType<EntityPropMap[K]>\n : K extends `params.${string}`\n ? number | undefined\n : never;\n\nconst isSignal = <T>(value: unknown): value is Signal<T> =>\n typeof value === \"function\";\n\nconst toSignal = <T>(value: Signal<T> | T): Signal<T> =>\n isSignal<T>(value) ? value : computed(() => value);\n\nexport const getEntityProp = <K extends EntityPropKey>(\n entity: Signal<RpgClientObject | undefined> | RpgClientObject | undefined,\n key: K\n): Signal<EntityPropValue<K>> => {\n const entitySignal = toSignal(entity);\n\n return computed(() => {\n const current = entitySignal();\n if (!current) {\n return undefined as EntityPropValue<K>;\n }\n\n if (Object.prototype.hasOwnProperty.call(entityPropMap, key)) {\n const getter = entityPropMap[key as keyof EntityPropMap];\n return getter(current) as EntityPropValue<K>;\n }\n\n if (key.startsWith(\"params.\")) {\n const paramKey = key.slice(\"params.\".length);\n return current._param?.()?.[paramKey] as EntityPropValue<K>;\n }\n\n return undefined as EntityPropValue<K>;\n });\n};\n"],"mappings":";;;AAmBA,IAAM,gBAAgB;CACpB,QAAQ,WAA4B,OAAO,OAAO;CAClD,MAAM,WAA4B,OAAO,KAAK;CAC9C,OAAO,WAA4B,OAAO,MAAM;CAChD,KAAK,WAA4B,OAAO,SAAS;CACjD,KAAK,WAA4B,OAAO,SAAS;CACjD,OAAO,WAA4B,OAAO;CAC1C,OAAO,WAA4B,OAAO,KAAK;CAC/C,IAAI,WAA4B,OAAO,EAAE;CACzC,IAAI,WAA4B,OAAO,EAAE;CACzC,IAAI,WAA4B,OAAO,EAAE;CACzC,OAAO,WAA4B,OAAO,KAAK;CAC/C,YAAY,WAA4B,OAAO,UAAU;CACzD,QAAQ,WAA4B,OAAO;CAC3C,SAAS,WAA4B,OAAO,OAAO;CACnD,YAAY,WAA4B,OAAO,cAAc;CAC7D,UAAU,WAA4B,cAAwB,OAAe,YAAY,OAAO,OAAO;CACvG,WAAW,WAA4B,OAAO,SAAS;CACvD,QAAQ,WAA4B,OAAO,MAAM;CACjD,aAAa,WAA4B,OAAO,WAAW;CAC3D,SAAS,WAA4B,OAAO,OAAO;CACnD,SAAS,WAA4B,OAAO,OAAO;CACnD,UAAU,WAA4B,OAAO,SAAS;CACtD,gBAAgB,WAA4B,OAAO,cAAc;CACjE,mBAAmB,WAA4B,OAAO,iBAAiB;CACvE,mBAAmB,WAA4B,OAAO,iBAAiB;CACvE,iBAAiB,WAA4B,OAAO,eAAe;CACnE,kBAAkB,WAA4B,OAAO,gBAAgB;AACvE;AAUA,IAAM,YAAe,UACnB,OAAO,UAAU;AAEnB,IAAM,YAAe,UACnB,SAAY,KAAK,IAAI,QAAQ,eAAe,KAAK;AAEnD,IAAa,iBACX,QACA,QAC+B;CAC/B,MAAM,eAAe,SAAS,MAAM;CAEpC,OAAO,eAAe;EACpB,MAAM,UAAU,aAAa;EAC7B,IAAI,CAAC,SACH;EAGF,IAAI,OAAO,UAAU,eAAe,KAAK,eAAe,GAAG,GAAG;GAC5D,MAAM,SAAS,cAAc;GAC7B,OAAO,OAAO,OAAO;EACvB;EAEA,IAAI,IAAI,WAAW,SAAS,GAAG;GAC7B,MAAM,WAAW,IAAI,MAAM,CAAgB;GAC3C,OAAO,QAAQ,SAAS,
|
|
1
|
+
{"version":3,"file":"getEntityProp.js","names":[],"sources":["../../src/utils/getEntityProp.ts"],"sourcesContent":["import { computed, Signal } from \"canvasengine\";\nimport { RpgClientObject } from \"../Game/Object\";\nimport { readPropValue } from \"./readPropValue\";\n\nconst BUILTIN_PARAM_KEYS = [\n \"maxHp\",\n \"maxSp\",\n \"atk\",\n \"pdef\",\n \"sdef\",\n \"str\",\n \"agi\",\n \"int\",\n \"dex\",\n] as const;\n\ntype BuiltInParamKey = typeof BUILTIN_PARAM_KEYS[number];\ntype ParamPropKey = `params.${BuiltInParamKey}` | `params.${string}`;\n\nconst entityPropMap = {\n level: (entity: RpgClientObject) => entity._level(),\n exp: (entity: RpgClientObject) => entity._exp(),\n gold: (entity: RpgClientObject) => entity._gold(),\n hp: (entity: RpgClientObject) => entity.hpSignal(),\n sp: (entity: RpgClientObject) => entity.spSignal(),\n name: (entity: RpgClientObject) => entity.name,\n type: (entity: RpgClientObject) => entity.type(),\n x: (entity: RpgClientObject) => entity.x(),\n y: (entity: RpgClientObject) => entity.y(),\n z: (entity: RpgClientObject) => entity.z(),\n tint: (entity: RpgClientObject) => entity.tint(),\n direction: (entity: RpgClientObject) => entity.direction(),\n speed: (entity: RpgClientObject) => entity.speed,\n hitbox: (entity: RpgClientObject) => entity.hitbox(),\n animation: (entity: RpgClientObject) => entity.animationName(),\n canMove: (entity: RpgClientObject) => readPropValue<boolean>((entity as any)._canMove ?? entity.canMove),\n graphics: (entity: RpgClientObject) => entity.graphics(),\n items: (entity: RpgClientObject) => entity.items(),\n equipments: (entity: RpgClientObject) => entity.equipments(),\n states: (entity: RpgClientObject) => entity.states(),\n skills: (entity: RpgClientObject) => entity.skills(),\n effects: (entity: RpgClientObject) => entity._effects(),\n componentsTop: (entity: RpgClientObject) => entity.componentsTop(),\n componentsBottom: (entity: RpgClientObject) => entity.componentsBottom(),\n componentsCenter: (entity: RpgClientObject) => entity.componentsCenter(),\n componentsLeft: (entity: RpgClientObject) => entity.componentsLeft(),\n componentsRight: (entity: RpgClientObject) => entity.componentsRight(),\n} as const;\n\ntype EntityPropMap = typeof entityPropMap;\ntype EntityPropKey = keyof EntityPropMap | ParamPropKey;\ntype EntityPropValue<K extends EntityPropKey> = K extends keyof EntityPropMap\n ? ReturnType<EntityPropMap[K]>\n : K extends `params.${string}`\n ? number | undefined\n : never;\n\nconst isSignal = <T>(value: unknown): value is Signal<T> =>\n typeof value === \"function\";\n\nconst toSignal = <T>(value: Signal<T> | T): Signal<T> =>\n isSignal<T>(value) ? value : computed(() => value);\n\nexport const getEntityProp = <K extends EntityPropKey>(\n entity: Signal<RpgClientObject | undefined> | RpgClientObject | undefined,\n key: K\n): Signal<EntityPropValue<K>> => {\n const entitySignal = toSignal(entity);\n\n return computed(() => {\n const current = entitySignal();\n if (!current) {\n return undefined as EntityPropValue<K>;\n }\n\n if (Object.prototype.hasOwnProperty.call(entityPropMap, key)) {\n const getter = entityPropMap[key as keyof EntityPropMap];\n return getter(current) as EntityPropValue<K>;\n }\n\n if (key.startsWith(\"params.\")) {\n const paramKey = key.slice(\"params.\".length);\n return current._param?.()?.[paramKey] as EntityPropValue<K>;\n }\n\n return undefined as EntityPropValue<K>;\n });\n};\n"],"mappings":";;;AAmBA,IAAM,gBAAgB;CACpB,QAAQ,WAA4B,OAAO,OAAO;CAClD,MAAM,WAA4B,OAAO,KAAK;CAC9C,OAAO,WAA4B,OAAO,MAAM;CAChD,KAAK,WAA4B,OAAO,SAAS;CACjD,KAAK,WAA4B,OAAO,SAAS;CACjD,OAAO,WAA4B,OAAO;CAC1C,OAAO,WAA4B,OAAO,KAAK;CAC/C,IAAI,WAA4B,OAAO,EAAE;CACzC,IAAI,WAA4B,OAAO,EAAE;CACzC,IAAI,WAA4B,OAAO,EAAE;CACzC,OAAO,WAA4B,OAAO,KAAK;CAC/C,YAAY,WAA4B,OAAO,UAAU;CACzD,QAAQ,WAA4B,OAAO;CAC3C,SAAS,WAA4B,OAAO,OAAO;CACnD,YAAY,WAA4B,OAAO,cAAc;CAC7D,UAAU,WAA4B,cAAwB,OAAe,YAAY,OAAO,OAAO;CACvG,WAAW,WAA4B,OAAO,SAAS;CACvD,QAAQ,WAA4B,OAAO,MAAM;CACjD,aAAa,WAA4B,OAAO,WAAW;CAC3D,SAAS,WAA4B,OAAO,OAAO;CACnD,SAAS,WAA4B,OAAO,OAAO;CACnD,UAAU,WAA4B,OAAO,SAAS;CACtD,gBAAgB,WAA4B,OAAO,cAAc;CACjE,mBAAmB,WAA4B,OAAO,iBAAiB;CACvE,mBAAmB,WAA4B,OAAO,iBAAiB;CACvE,iBAAiB,WAA4B,OAAO,eAAe;CACnE,kBAAkB,WAA4B,OAAO,gBAAgB;AACvE;AAUA,IAAM,YAAe,UACnB,OAAO,UAAU;AAEnB,IAAM,YAAe,UACnB,SAAY,KAAK,IAAI,QAAQ,eAAe,KAAK;AAEnD,IAAa,iBACX,QACA,QAC+B;CAC/B,MAAM,eAAe,SAAS,MAAM;CAEpC,OAAO,eAAe;EACpB,MAAM,UAAU,aAAa;EAC7B,IAAI,CAAC,SACH;EAGF,IAAI,OAAO,UAAU,eAAe,KAAK,eAAe,GAAG,GAAG;GAC5D,MAAM,SAAS,cAAc;GAC7B,OAAO,OAAO,OAAO;EACvB;EAEA,IAAI,IAAI,WAAW,SAAS,GAAG;GAC7B,MAAM,WAAW,IAAI,MAAM,CAAgB;GAC3C,OAAO,QAAQ,SAAS,CAAC,GAAG;EAC9B;CAGF,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncHitbox.js","names":[],"sources":["../../src/utils/syncHitbox.ts"],"sourcesContent":["interface HitboxSize {\n width: number;\n height: number;\n}\n\nconst toPositiveNumber = (value: unknown): number | null => {\n const numberValue = typeof value === \"string\" ? Number(value) : value;\n return typeof numberValue === \"number\" && Number.isFinite(numberValue) && numberValue > 0\n ? Math.round(numberValue)\n : null;\n};\n\nconst readSignalValue = (value: any): any => {\n if (typeof value === \"function\") {\n try {\n return value();\n }\n catch {\n return undefined;\n }\n }\n return value;\n};\n\nconst normalizeHitbox = (source: unknown): HitboxSize | null => {\n if (!source || typeof source !== \"object\") {\n return null;\n }\n\n const hitbox = source as any;\n const width = toPositiveNumber(hitbox.w ?? hitbox.width);\n const height = toPositiveNumber(hitbox.h ?? hitbox.height);\n\n return width && height ? { width, height } : null;\n};\n\nconst readObjectHitbox = (object: any): HitboxSize | null => {\n return normalizeHitbox(readSignalValue(object?.hitbox));\n};\n\nconst readCoordinate = (object: any, key: \"x\" | \"y\"): number | null => {\n const value = readSignalValue(object?.[key]);\n const numberValue = typeof value === \"string\" ? Number(value) : value;\n return typeof numberValue === \"number\" && Number.isFinite(numberValue)\n ? numberValue\n : null;\n};\n\nconst getObjectById = (sceneMap: any, id: string): any => {\n return sceneMap?.getObjectById?.(id)\n ?? sceneMap?.players?.()?.[id]\n ?? sceneMap?.events?.()?.[id];\n};\n\nconst applyHitboxToObject = (\n sceneMap: any,\n id: string,\n object: any,\n hitbox: HitboxSize,\n): void => {\n if (!object) {\n return;\n }\n\n const current = readObjectHitbox(object);\n if (current?.width !== hitbox.width || current?.height !== hitbox.height) {\n if (typeof object.hitbox?.set === \"function\") {\n object.hitbox.set({ w: hitbox.width, h: hitbox.height });\n }\n else if (typeof object.setHitbox === \"function\") {\n object.setHitbox(hitbox.width, hitbox.height);\n return;\n }\n }\n\n const objectId = typeof object.id === \"string\" && object.id ? object.id : id;\n const x = readCoordinate(object, \"x\");\n const y = readCoordinate(object, \"y\");\n if (objectId && x !== null && y !== null) {\n sceneMap?.updateHitbox?.(objectId, x, y, hitbox.width, hitbox.height);\n }\n};\n\nconst applyHitboxCollection = (sceneMap: any, collection: unknown): void => {\n if (!collection || typeof collection !== \"object\") {\n return;\n }\n\n for (const [id, patch] of Object.entries(collection)) {\n if (!patch || typeof patch !== \"object\") {\n continue;\n }\n const hitbox = normalizeHitbox((patch as any).hitbox);\n if (!hitbox) {\n continue;\n }\n applyHitboxToObject(sceneMap, id, getObjectById(sceneMap, id), hitbox);\n }\n};\n\nexport const applySyncedHitboxPayload = (sceneMap: any, payload: any): void => {\n applyHitboxCollection(sceneMap, payload?.players);\n applyHitboxCollection(sceneMap, payload?.events);\n};\n"],"mappings":";AAKA,IAAM,oBAAoB,UAAkC;CAC1D,MAAM,cAAc,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;CAChE,OAAO,OAAO,gBAAgB,YAAY,OAAO,SAAS,WAAW,KAAK,cAAc,IACpF,KAAK,MAAM,WAAW,IACtB;AACN;AAEA,IAAM,mBAAmB,UAAoB;CAC3C,IAAI,OAAO,UAAU,YACnB,IAAI;EACF,OAAO,MAAM;CACf,QACM;EACJ;CACF;CAEF,OAAO;AACT;AAEA,IAAM,mBAAmB,WAAuC;CAC9D,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,OAAO;CAGT,MAAM,SAAS;CACf,MAAM,QAAQ,iBAAiB,OAAO,KAAK,OAAO,KAAK;CACvD,MAAM,SAAS,iBAAiB,OAAO,KAAK,OAAO,MAAM;CAEzD,OAAO,SAAS,SAAS;EAAE;EAAO;CAAO,IAAI;AAC/C;AAEA,IAAM,oBAAoB,WAAmC;CAC3D,OAAO,gBAAgB,gBAAgB,QAAQ,MAAM,CAAC;AACxD;AAEA,IAAM,kBAAkB,QAAa,QAAkC;CACrE,MAAM,QAAQ,gBAAgB,SAAS,IAAI;CAC3C,MAAM,cAAc,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;CAChE,OAAO,OAAO,gBAAgB,YAAY,OAAO,SAAS,WAAW,IACjE,cACA;AACN;AAEA,IAAM,iBAAiB,UAAe,OAAoB;CACxD,OAAO,UAAU,gBAAgB,EAAE,KAC9B,UAAU,UAAU,
|
|
1
|
+
{"version":3,"file":"syncHitbox.js","names":[],"sources":["../../src/utils/syncHitbox.ts"],"sourcesContent":["interface HitboxSize {\n width: number;\n height: number;\n}\n\nconst toPositiveNumber = (value: unknown): number | null => {\n const numberValue = typeof value === \"string\" ? Number(value) : value;\n return typeof numberValue === \"number\" && Number.isFinite(numberValue) && numberValue > 0\n ? Math.round(numberValue)\n : null;\n};\n\nconst readSignalValue = (value: any): any => {\n if (typeof value === \"function\") {\n try {\n return value();\n }\n catch {\n return undefined;\n }\n }\n return value;\n};\n\nconst normalizeHitbox = (source: unknown): HitboxSize | null => {\n if (!source || typeof source !== \"object\") {\n return null;\n }\n\n const hitbox = source as any;\n const width = toPositiveNumber(hitbox.w ?? hitbox.width);\n const height = toPositiveNumber(hitbox.h ?? hitbox.height);\n\n return width && height ? { width, height } : null;\n};\n\nconst readObjectHitbox = (object: any): HitboxSize | null => {\n return normalizeHitbox(readSignalValue(object?.hitbox));\n};\n\nconst readCoordinate = (object: any, key: \"x\" | \"y\"): number | null => {\n const value = readSignalValue(object?.[key]);\n const numberValue = typeof value === \"string\" ? Number(value) : value;\n return typeof numberValue === \"number\" && Number.isFinite(numberValue)\n ? numberValue\n : null;\n};\n\nconst getObjectById = (sceneMap: any, id: string): any => {\n return sceneMap?.getObjectById?.(id)\n ?? sceneMap?.players?.()?.[id]\n ?? sceneMap?.events?.()?.[id];\n};\n\nconst applyHitboxToObject = (\n sceneMap: any,\n id: string,\n object: any,\n hitbox: HitboxSize,\n): void => {\n if (!object) {\n return;\n }\n\n const current = readObjectHitbox(object);\n if (current?.width !== hitbox.width || current?.height !== hitbox.height) {\n if (typeof object.hitbox?.set === \"function\") {\n object.hitbox.set({ w: hitbox.width, h: hitbox.height });\n }\n else if (typeof object.setHitbox === \"function\") {\n object.setHitbox(hitbox.width, hitbox.height);\n return;\n }\n }\n\n const objectId = typeof object.id === \"string\" && object.id ? object.id : id;\n const x = readCoordinate(object, \"x\");\n const y = readCoordinate(object, \"y\");\n if (objectId && x !== null && y !== null) {\n sceneMap?.updateHitbox?.(objectId, x, y, hitbox.width, hitbox.height);\n }\n};\n\nconst applyHitboxCollection = (sceneMap: any, collection: unknown): void => {\n if (!collection || typeof collection !== \"object\") {\n return;\n }\n\n for (const [id, patch] of Object.entries(collection)) {\n if (!patch || typeof patch !== \"object\") {\n continue;\n }\n const hitbox = normalizeHitbox((patch as any).hitbox);\n if (!hitbox) {\n continue;\n }\n applyHitboxToObject(sceneMap, id, getObjectById(sceneMap, id), hitbox);\n }\n};\n\nexport const applySyncedHitboxPayload = (sceneMap: any, payload: any): void => {\n applyHitboxCollection(sceneMap, payload?.players);\n applyHitboxCollection(sceneMap, payload?.events);\n};\n"],"mappings":";AAKA,IAAM,oBAAoB,UAAkC;CAC1D,MAAM,cAAc,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;CAChE,OAAO,OAAO,gBAAgB,YAAY,OAAO,SAAS,WAAW,KAAK,cAAc,IACpF,KAAK,MAAM,WAAW,IACtB;AACN;AAEA,IAAM,mBAAmB,UAAoB;CAC3C,IAAI,OAAO,UAAU,YACnB,IAAI;EACF,OAAO,MAAM;CACf,QACM;EACJ;CACF;CAEF,OAAO;AACT;AAEA,IAAM,mBAAmB,WAAuC;CAC9D,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,OAAO;CAGT,MAAM,SAAS;CACf,MAAM,QAAQ,iBAAiB,OAAO,KAAK,OAAO,KAAK;CACvD,MAAM,SAAS,iBAAiB,OAAO,KAAK,OAAO,MAAM;CAEzD,OAAO,SAAS,SAAS;EAAE;EAAO;CAAO,IAAI;AAC/C;AAEA,IAAM,oBAAoB,WAAmC;CAC3D,OAAO,gBAAgB,gBAAgB,QAAQ,MAAM,CAAC;AACxD;AAEA,IAAM,kBAAkB,QAAa,QAAkC;CACrE,MAAM,QAAQ,gBAAgB,SAAS,IAAI;CAC3C,MAAM,cAAc,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;CAChE,OAAO,OAAO,gBAAgB,YAAY,OAAO,SAAS,WAAW,IACjE,cACA;AACN;AAEA,IAAM,iBAAiB,UAAe,OAAoB;CACxD,OAAO,UAAU,gBAAgB,EAAE,KAC9B,UAAU,UAAU,CAAC,GAAG,OACxB,UAAU,SAAS,CAAC,GAAG;AAC9B;AAEA,IAAM,uBACJ,UACA,IACA,QACA,WACS;CACT,IAAI,CAAC,QACH;CAGF,MAAM,UAAU,iBAAiB,MAAM;CACvC,IAAI,SAAS,UAAU,OAAO,SAAS,SAAS,WAAW,OAAO;MAC5D,OAAO,OAAO,QAAQ,QAAQ,YAChC,OAAO,OAAO,IAAI;GAAE,GAAG,OAAO;GAAO,GAAG,OAAO;EAAO,CAAC;OAEpD,IAAI,OAAO,OAAO,cAAc,YAAY;GAC/C,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM;GAC5C;EACF;;CAGF,MAAM,WAAW,OAAO,OAAO,OAAO,YAAY,OAAO,KAAK,OAAO,KAAK;CAC1E,MAAM,IAAI,eAAe,QAAQ,GAAG;CACpC,MAAM,IAAI,eAAe,QAAQ,GAAG;CACpC,IAAI,YAAY,MAAM,QAAQ,MAAM,MAClC,UAAU,eAAe,UAAU,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAExE;AAEA,IAAM,yBAAyB,UAAe,eAA8B;CAC1E,IAAI,CAAC,cAAc,OAAO,eAAe,UACvC;CAGF,KAAK,MAAM,CAAC,IAAI,UAAU,OAAO,QAAQ,UAAU,GAAG;EACpD,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B;EAEF,MAAM,SAAS,gBAAiB,MAAc,MAAM;EACpD,IAAI,CAAC,QACH;EAEF,oBAAoB,UAAU,IAAI,cAAc,UAAU,EAAE,GAAG,MAAM;CACvE;AACF;AAEA,IAAa,4BAA4B,UAAe,YAAuB;CAC7E,sBAAsB,UAAU,SAAS,OAAO;CAChD,sBAAsB,UAAU,SAAS,MAAM;AACjD"}
|
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
|
-
"@rpgjs/common": "5.0.0-beta.
|
|
26
|
-
"@rpgjs/server": "5.0.0-beta.
|
|
27
|
-
"@rpgjs/ui-css": "5.0.0-beta.
|
|
25
|
+
"@rpgjs/common": "5.0.0-beta.26",
|
|
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/Game/Object.spec.ts
CHANGED
|
@@ -101,7 +101,7 @@ describe("RpgClientObject animations", () => {
|
|
|
101
101
|
const object = createObject();
|
|
102
102
|
const animationChanges: Array<{ name: string; isPlaying: boolean }> = [];
|
|
103
103
|
|
|
104
|
-
object.animationName.observable.subscribe((name) => {
|
|
104
|
+
(object.animationName as any).observable.subscribe((name) => {
|
|
105
105
|
animationChanges.push({
|
|
106
106
|
name,
|
|
107
107
|
isPlaying: object.animationIsPlaying(),
|
package/src/Game/Object.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hooks, ModulesToken, RpgCommonPlayer } from "@rpgjs/common";
|
|
2
2
|
import { trigger, signal, type Trigger } from "canvasengine";
|
|
3
|
-
import { combineLatest, from, map, of, startWith, Subscription, switchMap } from "rxjs";
|
|
3
|
+
import { combineLatest, from, map, of, startWith, Subscription, switchMap, type Observable } from "rxjs";
|
|
4
4
|
import { inject } from "../core/inject";
|
|
5
5
|
import { RpgClientEngine } from "../RpgClientEngine";
|
|
6
6
|
type Frame = { x: number; y: number; ts: number };
|
|
@@ -123,7 +123,7 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
123
123
|
const engine = this.engine;
|
|
124
124
|
this.hooks.callHooks("client-sprite-onInit", this).subscribe();
|
|
125
125
|
|
|
126
|
-
this._frames.observable.subscribe(({ items }) => {
|
|
126
|
+
(this._frames as any).observable.subscribe(({ items }) => {
|
|
127
127
|
if (!this.id) return;
|
|
128
128
|
//if (this.id == this.engine.playerIdSignal()!) return;
|
|
129
129
|
this.frames = mergeFreshFramePayload(
|
|
@@ -133,8 +133,8 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
133
133
|
);
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
const graphics
|
|
137
|
-
const graphicScale
|
|
136
|
+
const graphics$: Observable<unknown> = (this.graphics as any).observable.pipe(map(({ items }) => items));
|
|
137
|
+
const graphicScale$: Observable<unknown> = (this._graphicScale as any).observable.pipe(
|
|
138
138
|
startWith({ value: this._graphicScale() }),
|
|
139
139
|
map((payload: any) => payload?.value ?? payload),
|
|
140
140
|
);
|
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,
|