@rpgjs/client 5.0.0-beta.6 → 5.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Game/AnimationManager.d.ts +2 -2
- package/dist/Game/AnimationManager.js +18 -9
- package/dist/Game/AnimationManager.js.map +1 -1
- package/dist/Game/AnimationManager.spec.d.ts +1 -0
- package/dist/Game/Map.d.ts +7 -9
- package/dist/Game/Map.js +3 -3
- package/dist/Game/Map.js.map +1 -1
- package/dist/Game/Object.d.ts +28 -12
- package/dist/Game/Object.js +27 -2
- package/dist/Game/Object.js.map +1 -1
- package/dist/Gui/Gui.d.ts +2 -2
- package/dist/Gui/Gui.js +1 -1
- package/dist/Gui/Gui.js.map +1 -1
- package/dist/Gui/NotificationManager.d.ts +1 -1
- package/dist/Gui/NotificationManager.js.map +1 -1
- package/dist/Resource.js.map +1 -1
- package/dist/RpgClient.d.ts +22 -0
- package/dist/RpgClientEngine.d.ts +15 -12
- package/dist/RpgClientEngine.js +17 -2
- package/dist/RpgClientEngine.js.map +1 -1
- package/dist/Sound.js.map +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.128.0}/helpers/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.128.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/character.ce.js +55 -1
- package/dist/components/character.ce.js.map +1 -1
- package/dist/components/dynamics/parse-value.d.ts +1 -1
- package/dist/components/dynamics/parse-value.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/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.d.ts +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.map +1 -1
- package/dist/components/gui/title-screen.ce.js.map +1 -1
- 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.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/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/index.js +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@2.10.0}/node_modules/@signe/di/dist/index.js +7 -117
- package/dist/node_modules/.pnpm/@signe_di@2.10.0/node_modules/@signe/di/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js +45 -0
- package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js +227 -0
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js +611 -0
- package/dist/node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/client/index.js +44 -0
- package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/client/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{@signe_sync@2.9.0 → @signe_sync@2.10.0}/node_modules/@signe/sync/dist/index.js +29 -136
- package/dist/node_modules/.pnpm/@signe_sync@2.10.0/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/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.js +1 -1
- package/dist/services/loadMap.js.map +1 -1
- package/dist/services/mmorpg.js +1 -1
- 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 +8 -8
- package/src/Game/AnimationManager.spec.ts +30 -0
- package/src/Game/AnimationManager.ts +22 -10
- package/src/Game/Object.ts +46 -8
- package/src/RpgClient.ts +27 -0
- package/src/RpgClientEngine.ts +18 -2
- package/src/components/character.ce +72 -0
- package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +0 -463
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +0 -2191
- package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +0 -10
- package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +0 -91
- package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
- package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +0 -1
- package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +0 -14
- package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animation.js","names":[],"sources":["../../src/presets/animation.ts"],"sourcesContent":["/**\n * Creates an animation spritesheet preset with automatic frame generation\n * \n * This function generates animation frames based on the provided width and height dimensions.\n * It creates a sequence of frames that progresses through the spritesheet from left to right,\n * top to bottom, with each frame having a 10ms time increment.\n * \n * @param {number} framesWidth - The number of frames horizontally in the spritesheet\n * @param {number} framesHeight - The number of frames vertically in the spritesheet\n * @returns {Object} Animation preset configuration object\n * \n * @example\n * ```javascript\n * // For a 4x4 spritesheet\n * const preset = AnimationSpritesheetPreset(4, 4);\n * // This will generate 16 frames with coordinates from (0,0) to (3,3)\n * ```\n */\nexport const AnimationSpritesheetPreset = (framesWidth: number, framesHeight: number) => {\n \n const animations: Array<{ time: number; frameX: number; frameY: number }> = [];\n\n for (let y = 0; y < framesHeight; y++) {\n for (let x = 0; x < framesWidth; x++) {\n const frameIndex = y * framesWidth + x;\n animations.push({ \n time: frameIndex * 10, \n frameX: x, \n frameY: y \n });\n }\n }\n \n return {\n framesWidth,\n framesHeight,\n textures: {\n default: {\n animations: () => [\n animations\n ],\n }\n }\n };\n};\n "],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,IAAa,8BAA8B,aAAqB,iBAAyB;CAErF,MAAM,aAAsE,EAAE;
|
|
1
|
+
{"version":3,"file":"animation.js","names":[],"sources":["../../src/presets/animation.ts"],"sourcesContent":["/**\n * Creates an animation spritesheet preset with automatic frame generation\n * \n * This function generates animation frames based on the provided width and height dimensions.\n * It creates a sequence of frames that progresses through the spritesheet from left to right,\n * top to bottom, with each frame having a 10ms time increment.\n * \n * @param {number} framesWidth - The number of frames horizontally in the spritesheet\n * @param {number} framesHeight - The number of frames vertically in the spritesheet\n * @returns {Object} Animation preset configuration object\n * \n * @example\n * ```javascript\n * // For a 4x4 spritesheet\n * const preset = AnimationSpritesheetPreset(4, 4);\n * // This will generate 16 frames with coordinates from (0,0) to (3,3)\n * ```\n */\nexport const AnimationSpritesheetPreset = (framesWidth: number, framesHeight: number) => {\n \n const animations: Array<{ time: number; frameX: number; frameY: number }> = [];\n\n for (let y = 0; y < framesHeight; y++) {\n for (let x = 0; x < framesWidth; x++) {\n const frameIndex = y * framesWidth + x;\n animations.push({ \n time: frameIndex * 10, \n frameX: x, \n frameY: y \n });\n }\n }\n \n return {\n framesWidth,\n framesHeight,\n textures: {\n default: {\n animations: () => [\n animations\n ],\n }\n }\n };\n};\n "],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,IAAa,8BAA8B,aAAqB,iBAAyB;CAErF,MAAM,aAAsE,EAAE;CAE9E,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,KAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,KAAK;EAClC,MAAM,aAAa,IAAI,cAAc;EACrC,WAAW,KAAK;GACZ,MAAM,aAAa;GACnB,QAAQ;GACR,QAAQ;GACX,CAAC;;CAIV,OAAO;EACH;EACA;EACA,UAAU,EACN,SAAS,EACL,kBAAkB,CACd,WACH,EACJ,EACJ;EACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"faceset.js","names":[],"sources":["../../src/presets/faceset.ts"],"sourcesContent":["/**\n * Creates a faceset preset for character expressions\n * \n * This preset allows you to define multiple facial expressions for a character,\n * where each expression corresponds to a specific frame position (frameX, frameY)\n * within a single faceset texture. Each expression is defined by its position\n * in the faceset grid.\n * \n * @param options - Object containing the faceset configuration\n * @param framesWidth - Number of frames horizontally in the faceset texture\n * @param framesHeight - Number of frames vertically in the faceset texture\n * @param expressions - Object mapping expression names to their frame positions as tuples [frameX, frameY]\n * @returns Faceset configuration with animations for each expression\n * \n * @example\n * ```typescript\n * const faceset = FacesetPreset({\n * id: \"facesetId\",\n * image: \"faceset.png\",\n * width: 1024,\n * height: 1024,\n * }, 4, 2, {\n * happy: [0, 0],\n * sad: [1, 0],\n * angry: [2, 0],\n * surprised: [3, 0]\n * });\n * ```\n */\nexport const FacesetPreset = (\n options: any,\n framesWidth: number, \n framesHeight: number,\n expressions: Record<string, [number, number]>,\n) => {\n \n const textures: Record<string, any> = {};\n \n // Create texture configuration for each expression\n Object.keys(expressions).forEach((expressionName) => {\n const [frameX, frameY] = expressions[expressionName];\n textures[expressionName] = {\n animations: () => [\n [{ \n time: 0, \n frameX: frameX, \n frameY: frameY \n }]\n ],\n };\n });\n \n return {\n ...options,\n framesWidth,\n framesHeight,\n textures\n };\n};\n "],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,iBACT,SACA,aACA,cACA,gBACC;CAED,MAAM,WAAgC,EAAE;
|
|
1
|
+
{"version":3,"file":"faceset.js","names":[],"sources":["../../src/presets/faceset.ts"],"sourcesContent":["/**\n * Creates a faceset preset for character expressions\n * \n * This preset allows you to define multiple facial expressions for a character,\n * where each expression corresponds to a specific frame position (frameX, frameY)\n * within a single faceset texture. Each expression is defined by its position\n * in the faceset grid.\n * \n * @param options - Object containing the faceset configuration\n * @param framesWidth - Number of frames horizontally in the faceset texture\n * @param framesHeight - Number of frames vertically in the faceset texture\n * @param expressions - Object mapping expression names to their frame positions as tuples [frameX, frameY]\n * @returns Faceset configuration with animations for each expression\n * \n * @example\n * ```typescript\n * const faceset = FacesetPreset({\n * id: \"facesetId\",\n * image: \"faceset.png\",\n * width: 1024,\n * height: 1024,\n * }, 4, 2, {\n * happy: [0, 0],\n * sad: [1, 0],\n * angry: [2, 0],\n * surprised: [3, 0]\n * });\n * ```\n */\nexport const FacesetPreset = (\n options: any,\n framesWidth: number, \n framesHeight: number,\n expressions: Record<string, [number, number]>,\n) => {\n \n const textures: Record<string, any> = {};\n \n // Create texture configuration for each expression\n Object.keys(expressions).forEach((expressionName) => {\n const [frameX, frameY] = expressions[expressionName];\n textures[expressionName] = {\n animations: () => [\n [{ \n time: 0, \n frameX: frameX, \n frameY: frameY \n }]\n ],\n };\n });\n \n return {\n ...options,\n framesWidth,\n framesHeight,\n textures\n };\n};\n "],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,iBACT,SACA,aACA,cACA,gBACC;CAED,MAAM,WAAgC,EAAE;CAGxC,OAAO,KAAK,YAAY,CAAC,SAAS,mBAAmB;EACjD,MAAM,CAAC,QAAQ,UAAU,YAAY;EACrC,SAAS,kBAAkB,EACvB,kBAAkB,CACd,CAAC;GACG,MAAM;GACE;GACA;GACX,CAAC,CACL,EACJ;GACH;CAEF,OAAO;EACH,GAAG;EACH;EACA;EACA;EACH"}
|
package/dist/presets/icon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.js","names":[],"sources":["../../src/presets/icon.ts"],"sourcesContent":["export const IconPreset = (options: {\n image: string;\n framesWidth: number;\n framesHeight: number;\n id: string;\n}) => {\n return {\n textures: {\n default: {\n animations: () => [\n [{ time: 0, frameX: 0, frameY: 0 }]\n ]\n }\n },\n ...options\n }\n}"],"mappings":";AAAA,IAAa,cAAc,YAKrB;
|
|
1
|
+
{"version":3,"file":"icon.js","names":[],"sources":["../../src/presets/icon.ts"],"sourcesContent":["export const IconPreset = (options: {\n image: string;\n framesWidth: number;\n framesHeight: number;\n id: string;\n}) => {\n return {\n textures: {\n default: {\n animations: () => [\n [{ time: 0, frameX: 0, frameY: 0 }]\n ]\n }\n },\n ...options\n }\n}"],"mappings":";AAAA,IAAa,cAAc,YAKrB;CACF,OAAO;EACH,UAAU,EACN,SAAS,EACL,kBAAkB,CACd,CAAC;GAAE,MAAM;GAAG,QAAQ;GAAG,QAAQ;GAAG,CAAC,CACtC,EACJ,EACJ;EACD,GAAG;EACN"}
|
package/dist/presets/lpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lpc.js","names":[],"sources":["../../src/presets/lpc.ts"],"sourcesContent":["import { Animation, Direction } from \"@rpgjs/common\";\n\nexport const LPCSpritesheetPreset = (options: {\n id: string;\n imageSource: string;\n width: number;\n height: number;\n ratio?: number;\n }) => {\n const ratio = options.ratio ?? 1;\n\n const frameY = (direction: Direction) => {\n return {\n [Direction.Down]: 2,\n [Direction.Left]: 1,\n [Direction.Right]: 3,\n [Direction.Up]: 0,\n }[direction];\n };\n \n const stand = (direction: Direction) => [\n { time: 0, frameX: 0, frameY: frameY(direction) },\n ];\n const anim = (\n direction: Direction,\n framesWidth: number,\n speed: number = 5\n ) => {\n const array: any = [];\n for (let i = 0; i < framesWidth; i++) {\n array.push({ time: i * speed, frameX: i, frameY: frameY(direction) });\n }\n return array;\n };\n \n return {\n id: options.id,\n image: options.imageSource,\n width: options.width,\n height: options.height,\n opacity: 1,\n rectWidth: 64 * ratio,\n rectHeight: 64 * ratio,\n framesWidth: 6,\n framesHeight: 4,\n spriteRealSize: {\n width: 48 * ratio,\n height: 52 * ratio,\n },\n textures: {\n [Animation.Stand]: {\n offset: {\n x: 0,\n y: 512 * ratio,\n },\n animations: ({ direction }) => [stand(direction)],\n },\n [Animation.Walk]: {\n offset: {\n x: 0,\n y: 512 * ratio,\n },\n framesWidth: 9,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 9)],\n },\n [Animation.Attack]: {\n offset: {\n x: 0,\n y: 768 * ratio,\n },\n framesWidth: 6,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 6, 3)],\n },\n [Animation.Skill]: {\n framesWidth: 7,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 7, 3)],\n },\n attack2: {\n offset: {\n x: 0,\n y: 256 * ratio,\n },\n framesWidth: 7,\n framesHeight: 8,\n animations: ({ direction }) => [anim(direction, 7, 3)],\n },\n ...(options.height > 3000\n ? {\n attack3: {\n offset: {\n x: 0,\n y: 5568 - 288 * 4,\n },\n rectWidth: 288,\n rectHeight: 288,\n framesWidth: 6,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 6, 3)],\n },\n }\n : {}),\n },\n };\n };\n "],"mappings":";;AAEA,IAAa,wBAAwB,YAM7B;CACJ,MAAM,QAAQ,QAAQ,SAAS;CAE/B,MAAM,UAAU,cAAyB;
|
|
1
|
+
{"version":3,"file":"lpc.js","names":[],"sources":["../../src/presets/lpc.ts"],"sourcesContent":["import { Animation, Direction } from \"@rpgjs/common\";\n\nexport const LPCSpritesheetPreset = (options: {\n id: string;\n imageSource: string;\n width: number;\n height: number;\n ratio?: number;\n }) => {\n const ratio = options.ratio ?? 1;\n\n const frameY = (direction: Direction) => {\n return {\n [Direction.Down]: 2,\n [Direction.Left]: 1,\n [Direction.Right]: 3,\n [Direction.Up]: 0,\n }[direction];\n };\n \n const stand = (direction: Direction) => [\n { time: 0, frameX: 0, frameY: frameY(direction) },\n ];\n const anim = (\n direction: Direction,\n framesWidth: number,\n speed: number = 5\n ) => {\n const array: any = [];\n for (let i = 0; i < framesWidth; i++) {\n array.push({ time: i * speed, frameX: i, frameY: frameY(direction) });\n }\n return array;\n };\n \n return {\n id: options.id,\n image: options.imageSource,\n width: options.width,\n height: options.height,\n opacity: 1,\n rectWidth: 64 * ratio,\n rectHeight: 64 * ratio,\n framesWidth: 6,\n framesHeight: 4,\n spriteRealSize: {\n width: 48 * ratio,\n height: 52 * ratio,\n },\n textures: {\n [Animation.Stand]: {\n offset: {\n x: 0,\n y: 512 * ratio,\n },\n animations: ({ direction }) => [stand(direction)],\n },\n [Animation.Walk]: {\n offset: {\n x: 0,\n y: 512 * ratio,\n },\n framesWidth: 9,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 9)],\n },\n [Animation.Attack]: {\n offset: {\n x: 0,\n y: 768 * ratio,\n },\n framesWidth: 6,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 6, 3)],\n },\n [Animation.Skill]: {\n framesWidth: 7,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 7, 3)],\n },\n attack2: {\n offset: {\n x: 0,\n y: 256 * ratio,\n },\n framesWidth: 7,\n framesHeight: 8,\n animations: ({ direction }) => [anim(direction, 7, 3)],\n },\n ...(options.height > 3000\n ? {\n attack3: {\n offset: {\n x: 0,\n y: 5568 - 288 * 4,\n },\n rectWidth: 288,\n rectHeight: 288,\n framesWidth: 6,\n framesHeight: 4,\n animations: ({ direction }) => [anim(direction, 6, 3)],\n },\n }\n : {}),\n },\n };\n };\n "],"mappings":";;AAEA,IAAa,wBAAwB,YAM7B;CACJ,MAAM,QAAQ,QAAQ,SAAS;CAE/B,MAAM,UAAU,cAAyB;EACvC,OAAO;IACJ,UAAU,OAAO;IACjB,UAAU,OAAO;IACjB,UAAU,QAAQ;IAClB,UAAU,KAAK;GACjB,CAAC;;CAGJ,MAAM,SAAS,cAAyB,CACtC;EAAE,MAAM;EAAG,QAAQ;EAAG,QAAQ,OAAO,UAAU;EAAE,CAClD;CACD,MAAM,QACJ,WACA,aACA,QAAgB,MACb;EACH,MAAM,QAAa,EAAE;EACrB,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,KAC/B,MAAM,KAAK;GAAE,MAAM,IAAI;GAAO,QAAQ;GAAG,QAAQ,OAAO,UAAU;GAAE,CAAC;EAEvE,OAAO;;CAGT,OAAO;EACL,IAAI,QAAQ;EACZ,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,SAAS;EACT,WAAW,KAAK;EAChB,YAAY,KAAK;EACjB,aAAa;EACb,cAAc;EACd,gBAAgB;GACd,OAAO,KAAK;GACZ,QAAQ,KAAK;GACd;EACD,UAAU;IACP,UAAU,QAAQ;IACjB,QAAQ;KACN,GAAG;KACH,GAAG,MAAM;KACV;IACD,aAAa,EAAE,gBAAgB,CAAC,MAAM,UAAU,CAAC;IAClD;IACA,UAAU,OAAO;IAChB,QAAQ;KACN,GAAG;KACH,GAAG,MAAM;KACV;IACD,aAAa;IACb,cAAc;IACd,aAAa,EAAE,gBAAgB,CAAC,KAAK,WAAW,EAAE,CAAC;IACpD;IACA,UAAU,SAAS;IAClB,QAAQ;KACN,GAAG;KACH,GAAG,MAAM;KACV;IACD,aAAa;IACb,cAAc;IACd,aAAa,EAAE,gBAAgB,CAAC,KAAK,WAAW,GAAG,EAAE,CAAC;IACvD;IACA,UAAU,QAAQ;IACjB,aAAa;IACb,cAAc;IACd,aAAa,EAAE,gBAAgB,CAAC,KAAK,WAAW,GAAG,EAAE,CAAC;IACvD;GACD,SAAS;IACP,QAAQ;KACN,GAAG;KACH,GAAG,MAAM;KACV;IACD,aAAa;IACb,cAAc;IACd,aAAa,EAAE,gBAAgB,CAAC,KAAK,WAAW,GAAG,EAAE,CAAC;IACvD;GACD,GAAI,QAAQ,SAAS,MACjB,EACE,SAAS;IACP,QAAQ;KACN,GAAG;KACH,GAAG,OAAO,MAAM;KACjB;IACD,WAAW;IACX,YAAY;IACZ,aAAa;IACb,cAAc;IACd,aAAa,EAAE,gBAAgB,CAAC,KAAK,WAAW,GAAG,EAAE,CAAC;IACvD,EACF,GACD,EAAE;GACP;EACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rmspritesheet.js","names":[],"sources":["../../src/presets/rmspritesheet.ts"],"sourcesContent":["import { Direction, Animation } from '@rpgjs/common'\n\nexport const RMSpritesheet = (framesWidth: number, framesHeight: number, frameStand: number = 1) => {\n\n if (framesWidth <= frameStand) {\n frameStand = framesWidth - 1\n }\n\n const frameY = direction => {\n const gap = Math.max(4 - framesHeight, 0)\n return {\n [Direction.Down]: 0,\n [Direction.Left]: Math.max(0, 1 - gap),\n [Direction.Right]: Math.max(0, 2 - gap),\n [Direction.Up]: Math.max(0, 3 - gap)\n }[direction]\n }\n\n const stand = (direction: number) => [{ time: 0, frameX: frameStand, frameY: frameY(direction) }]\n const walk = direction => {\n const array: any = []\n const durationFrame = 10\n for (let i = 0; i < framesWidth; i++) {\n array.push({ time: i * durationFrame, frameX: i, frameY: frameY(direction) })\n }\n array.push({ time: array[array.length - 1].time + durationFrame })\n return array\n }\n\n return {\n textures: {\n [Animation.Stand]: {\n animations: ({direction}) => [stand(direction)]\n },\n [Animation.Walk]: {\n animations: ({direction}) => [walk(direction)]\n }\n },\n framesHeight,\n framesWidth\n }\n}"],"mappings":";;AAEA,IAAa,iBAAiB,aAAqB,cAAsB,aAAqB,MAAM;
|
|
1
|
+
{"version":3,"file":"rmspritesheet.js","names":[],"sources":["../../src/presets/rmspritesheet.ts"],"sourcesContent":["import { Direction, Animation } from '@rpgjs/common'\n\nexport const RMSpritesheet = (framesWidth: number, framesHeight: number, frameStand: number = 1) => {\n\n if (framesWidth <= frameStand) {\n frameStand = framesWidth - 1\n }\n\n const frameY = direction => {\n const gap = Math.max(4 - framesHeight, 0)\n return {\n [Direction.Down]: 0,\n [Direction.Left]: Math.max(0, 1 - gap),\n [Direction.Right]: Math.max(0, 2 - gap),\n [Direction.Up]: Math.max(0, 3 - gap)\n }[direction]\n }\n\n const stand = (direction: number) => [{ time: 0, frameX: frameStand, frameY: frameY(direction) }]\n const walk = direction => {\n const array: any = []\n const durationFrame = 10\n for (let i = 0; i < framesWidth; i++) {\n array.push({ time: i * durationFrame, frameX: i, frameY: frameY(direction) })\n }\n array.push({ time: array[array.length - 1].time + durationFrame })\n return array\n }\n\n return {\n textures: {\n [Animation.Stand]: {\n animations: ({direction}) => [stand(direction)]\n },\n [Animation.Walk]: {\n animations: ({direction}) => [walk(direction)]\n }\n },\n framesHeight,\n framesWidth\n }\n}"],"mappings":";;AAEA,IAAa,iBAAiB,aAAqB,cAAsB,aAAqB,MAAM;CAEhG,IAAI,eAAe,YACf,aAAa,cAAc;CAG/B,MAAM,UAAS,cAAa;EACxB,MAAM,MAAM,KAAK,IAAI,IAAI,cAAc,EAAE;EACzC,OAAO;IACF,UAAU,OAAO;IACjB,UAAU,OAAO,KAAK,IAAI,GAAG,IAAI,IAAI;IACrC,UAAU,QAAQ,KAAK,IAAI,GAAG,IAAI,IAAI;IACtC,UAAU,KAAK,KAAK,IAAI,GAAG,IAAI,IAAI;GACvC,CAAC;;CAGN,MAAM,SAAS,cAAsB,CAAC;EAAE,MAAM;EAAG,QAAQ;EAAY,QAAQ,OAAO,UAAU;EAAE,CAAC;CACjG,MAAM,QAAO,cAAa;EACtB,MAAM,QAAa,EAAE;EACrB,MAAM,gBAAgB;EACtB,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,KAC7B,MAAM,KAAK;GAAE,MAAM,IAAI;GAAe,QAAQ;GAAG,QAAQ,OAAO,UAAU;GAAE,CAAC;EAEjF,MAAM,KAAK,EAAE,MAAM,MAAM,MAAM,SAAS,GAAG,OAAO,eAAe,CAAC;EAClE,OAAO;;CAGX,OAAO;EACH,UAAU;IACL,UAAU,QAAQ,EACf,aAAa,EAAC,gBAAe,CAAC,MAAM,UAAU,CAAC,EAClD;IACA,UAAU,OAAO,EACd,aAAa,EAAC,gBAAe,CAAC,KAAK,UAAU,CAAC,EACjD;GACJ;EACD;EACA;EACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractSocket.js","names":[],"sources":["../../src/services/AbstractSocket.ts"],"sourcesContent":["import { Context } from \"@signe/di\";\n\nexport const WebSocketToken = \"websocket\";\n\nexport type SocketQueryValue = string | null | undefined;\nexport type SocketQuery = Record<string, SocketQueryValue>;\nexport type SocketUpdateProperties = {\n room: string;\n host?: string;\n query?: SocketQuery;\n};\n\nexport abstract class AbstractWebsocket {\n constructor(protected context: Context) {}\n\n abstract connection(listeners?: (data: any) => void): Promise<void>;\n abstract emit(event: string, data: any): void;\n abstract on(event: string, callback: (data: any) => void): void;\n abstract off(event: string, callback: (data: any) => void): void;\n abstract updateProperties(params: SocketUpdateProperties): void;\n abstract reconnect(listeners?: (data: any) => void): Promise<void>;\n}\n"],"mappings":";AAEA,IAAa,iBAAiB;AAU9B,IAAsB,oBAAtB,MAAwC;CACtC,YAAY,SAA4B;
|
|
1
|
+
{"version":3,"file":"AbstractSocket.js","names":[],"sources":["../../src/services/AbstractSocket.ts"],"sourcesContent":["import { Context } from \"@signe/di\";\n\nexport const WebSocketToken = \"websocket\";\n\nexport type SocketQueryValue = string | null | undefined;\nexport type SocketQuery = Record<string, SocketQueryValue>;\nexport type SocketUpdateProperties = {\n room: string;\n host?: string;\n query?: SocketQuery;\n};\n\nexport abstract class AbstractWebsocket {\n constructor(protected context: Context) {}\n\n abstract connection(listeners?: (data: any) => void): Promise<void>;\n abstract emit(event: string, data: any): void;\n abstract on(event: string, callback: (data: any) => void): void;\n abstract off(event: string, callback: (data: any) => void): void;\n abstract updateProperties(params: SocketUpdateProperties): void;\n abstract reconnect(listeners?: (data: any) => void): Promise<void>;\n}\n"],"mappings":";AAEA,IAAa,iBAAiB;AAU9B,IAAsB,oBAAtB,MAAwC;CACtC,YAAY,SAA4B;EAAlB,KAAA,UAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboardControls.js","names":[],"sources":["../../src/services/keyboardControls.ts"],"sourcesContent":["import { KeyboardControls } from \"canvasengine\";\n\nexport enum Control {\n Action = 'action',\n Attack = 'attack',\n Defense = 'defense',\n Skill = 'skill',\n Back = 'back',\n Up = 1,\n Down = 3,\n Right = 2,\n Left = 4\n}\n\nexport function provideKeyboardControls() {\n return {\n provide: 'KeyboardControls',\n useValue: null,\n };\n}"],"mappings":";AAEA,IAAY,UAAL,yBAAA,SAAA;
|
|
1
|
+
{"version":3,"file":"keyboardControls.js","names":[],"sources":["../../src/services/keyboardControls.ts"],"sourcesContent":["import { KeyboardControls } from \"canvasengine\";\n\nexport enum Control {\n Action = 'action',\n Attack = 'attack',\n Defense = 'defense',\n Skill = 'skill',\n Back = 'back',\n Up = 1,\n Down = 3,\n Right = 2,\n Left = 4\n}\n\nexport function provideKeyboardControls() {\n return {\n provide: 'KeyboardControls',\n useValue: null,\n };\n}"],"mappings":";AAEA,IAAY,UAAL,yBAAA,SAAA;CACL,QAAA,YAAS;CACT,QAAA,YAAS;CACT,QAAA,aAAU;CACV,QAAA,WAAQ;CACR,QAAA,UAAO;CACP,QAAA,QAAA,QAAK,KAAA;CACL,QAAA,QAAA,UAAO,KAAA;CACP,QAAA,QAAA,WAAQ,KAAA;CACR,QAAA,QAAA,UAAO,KAAA;;KACR;AAED,SAAgB,0BAA0B;CACxC,OAAO;EACL,SAAS;EACT,UAAU;EACX"}
|
package/dist/services/loadMap.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inject } from "../node_modules/.pnpm/@signe_di@2.
|
|
1
|
+
import { inject } from "../node_modules/.pnpm/@signe_di@2.10.0/node_modules/@signe/di/dist/index.js";
|
|
2
2
|
import { UpdateMapToken } from "@rpgjs/common";
|
|
3
3
|
//#region src/services/loadMap.ts
|
|
4
4
|
var LoadMapToken = "LoadMapToken";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadMap.js","names":[],"sources":["../../src/services/loadMap.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { UpdateMapToken, UpdateMapService } from \"@rpgjs/common\";\n\nexport const LoadMapToken = 'LoadMapToken'\n\n/**\n * Represents the structure of map data that should be returned by the load map callback.\n * This interface defines all the properties that can be provided when loading a custom map.\n * \n * @interface MapData\n */\ntype MapData = {\n /** Raw map data that will be passed to the map component */\n data: any;\n /** CanvasEngine component that will render the map */\n component: any;\n /** Optional map width in pixels, used for viewport calculations */\n width?: number;\n /** Optional map height in pixels, used for viewport calculations */\n height?: number;\n /** Optional map events data (NPCs, interactive objects, etc.) */\n events?: any;\n /** Optional map identifier, defaults to the mapId parameter if not provided */\n id?: string;\n}\n\n/**\n * Callback function type for loading map data.\n * This function receives a map ID and should return either a MapData object directly\n * or a Promise that resolves to a MapData object.\n * \n * @callback LoadMapOptions\n * @param {string} mapId - The identifier of the map to load\n * @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it\n */\nexport type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData \n\nexport class LoadMapService {\n private updateMapService: UpdateMapService;\n\n constructor(private context: Context, private options: LoadMapOptions) {\n if (context['side'] === 'server') {\n return\n }\n this.updateMapService = inject(context, UpdateMapToken);\n }\n\n async load(mapId: string) {\n const map = await this.options(mapId.replace('map-', ''))\n await this.updateMapService.update(map);\n return map;\n }\n}\n\n/**\n * Creates a dependency injection configuration for custom map loading on the client side.\n * \n * This function allows you to customize how maps are loaded and displayed by providing\n * a callback that defines custom map data and rendering components. It's designed to work\n * with the RPG-JS dependency injection system and enables integration of custom map formats\n * like Tiled TMX files or any other map data structure.\n * \n * The function sets up the necessary service providers for map loading, including:\n * - UpdateMapToken: Handles map updates in the client context\n * - LoadMapToken: Provides the LoadMapService with your custom loading logic\n * \n * **Design Concept:**\n * The function follows the provider pattern, creating a modular way to inject custom\n * map loading behavior into the RPG-JS client engine. It separates the concern of\n * map data fetching from map rendering, allowing developers to focus on their specific\n * map format while leveraging the engine's rendering capabilities.\n * \n * @param {LoadMapOptions} options - Callback function that handles map loading logic\n * @returns {Array<Object>} Array of dependency injection provider configurations\n * \n * @example\n * ```typescript\n * import { provideLoadMap } from '@rpgjs/client'\n * import { createModule } from '@rpgjs/common'\n * import MyTiledMapComponent from './MyTiledMapComponent.ce'\n * \n * // Basic usage with JSON map data\n * export function provideCustomMap() {\n * return createModule(\"CustomMap\", [\n * provideLoadMap(async (mapId) => {\n * const response = await fetch(`/maps/${mapId}.json`)\n * const mapData = await response.json()\n * \n * return {\n * data: mapData,\n * component: MyTiledMapComponent,\n * width: mapData.width,\n * height: mapData.height,\n * events: mapData.events\n * }\n * })\n * ])\n * }\n * \n * // Advanced usage with Tiled TMX files\n * export function provideTiledMap() {\n * return createModule(\"TiledMap\", [\n * provideLoadMap(async (mapId) => {\n * // Load TMX file\n * const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)\n * const tmxData = await tmxResponse.text()\n * \n * // Parse TMX data (using a TMX parser)\n * const parsedMap = parseTMX(tmxData)\n * \n * return {\n * data: parsedMap,\n * component: TiledMapRenderer,\n * width: parsedMap.width * parsedMap.tilewidth,\n * height: parsedMap.height * parsedMap.tileheight,\n * events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects\n * }\n * })\n * ])\n * }\n * \n * // Synchronous usage for static maps\n * export function provideStaticMap() {\n * return createModule(\"StaticMap\", [\n * provideLoadMap((mapId) => {\n * const staticMaps = {\n * 'town': { tiles: [...], npcs: [...] },\n * 'dungeon': { tiles: [...], monsters: [...] }\n * }\n * \n * return {\n * data: staticMaps[mapId],\n * component: StaticMapComponent,\n * width: 800,\n * height: 600\n * }\n * })\n * ])\n * }\n * ```\n * \n * @since 4.0.0\n * @see {@link LoadMapOptions} for callback function signature\n * @see {@link MapData} for return data structure\n */\nexport function provideLoadMap(options: LoadMapOptions) {\n return [\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => {\n if (context['side'] === 'client') {\n console.warn('UpdateMapToken is not overridden')\n }\n return\n },\n },\n {\n provide: LoadMapToken,\n useFactory: (context: Context) => new LoadMapService(context, options),\n },\n ];\n}\n"],"mappings":";;;AAGA,IAAa,eAAe;AAkC5B,IAAa,iBAAb,MAA4B;CAG1B,YAAY,SAA0B,SAAiC;
|
|
1
|
+
{"version":3,"file":"loadMap.js","names":[],"sources":["../../src/services/loadMap.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { UpdateMapToken, UpdateMapService } from \"@rpgjs/common\";\n\nexport const LoadMapToken = 'LoadMapToken'\n\n/**\n * Represents the structure of map data that should be returned by the load map callback.\n * This interface defines all the properties that can be provided when loading a custom map.\n * \n * @interface MapData\n */\ntype MapData = {\n /** Raw map data that will be passed to the map component */\n data: any;\n /** CanvasEngine component that will render the map */\n component: any;\n /** Optional map width in pixels, used for viewport calculations */\n width?: number;\n /** Optional map height in pixels, used for viewport calculations */\n height?: number;\n /** Optional map events data (NPCs, interactive objects, etc.) */\n events?: any;\n /** Optional map identifier, defaults to the mapId parameter if not provided */\n id?: string;\n}\n\n/**\n * Callback function type for loading map data.\n * This function receives a map ID and should return either a MapData object directly\n * or a Promise that resolves to a MapData object.\n * \n * @callback LoadMapOptions\n * @param {string} mapId - The identifier of the map to load\n * @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it\n */\nexport type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData \n\nexport class LoadMapService {\n private updateMapService: UpdateMapService;\n\n constructor(private context: Context, private options: LoadMapOptions) {\n if (context['side'] === 'server') {\n return\n }\n this.updateMapService = inject(context, UpdateMapToken);\n }\n\n async load(mapId: string) {\n const map = await this.options(mapId.replace('map-', ''))\n await this.updateMapService.update(map);\n return map;\n }\n}\n\n/**\n * Creates a dependency injection configuration for custom map loading on the client side.\n * \n * This function allows you to customize how maps are loaded and displayed by providing\n * a callback that defines custom map data and rendering components. It's designed to work\n * with the RPG-JS dependency injection system and enables integration of custom map formats\n * like Tiled TMX files or any other map data structure.\n * \n * The function sets up the necessary service providers for map loading, including:\n * - UpdateMapToken: Handles map updates in the client context\n * - LoadMapToken: Provides the LoadMapService with your custom loading logic\n * \n * **Design Concept:**\n * The function follows the provider pattern, creating a modular way to inject custom\n * map loading behavior into the RPG-JS client engine. It separates the concern of\n * map data fetching from map rendering, allowing developers to focus on their specific\n * map format while leveraging the engine's rendering capabilities.\n * \n * @param {LoadMapOptions} options - Callback function that handles map loading logic\n * @returns {Array<Object>} Array of dependency injection provider configurations\n * \n * @example\n * ```typescript\n * import { provideLoadMap } from '@rpgjs/client'\n * import { createModule } from '@rpgjs/common'\n * import MyTiledMapComponent from './MyTiledMapComponent.ce'\n * \n * // Basic usage with JSON map data\n * export function provideCustomMap() {\n * return createModule(\"CustomMap\", [\n * provideLoadMap(async (mapId) => {\n * const response = await fetch(`/maps/${mapId}.json`)\n * const mapData = await response.json()\n * \n * return {\n * data: mapData,\n * component: MyTiledMapComponent,\n * width: mapData.width,\n * height: mapData.height,\n * events: mapData.events\n * }\n * })\n * ])\n * }\n * \n * // Advanced usage with Tiled TMX files\n * export function provideTiledMap() {\n * return createModule(\"TiledMap\", [\n * provideLoadMap(async (mapId) => {\n * // Load TMX file\n * const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)\n * const tmxData = await tmxResponse.text()\n * \n * // Parse TMX data (using a TMX parser)\n * const parsedMap = parseTMX(tmxData)\n * \n * return {\n * data: parsedMap,\n * component: TiledMapRenderer,\n * width: parsedMap.width * parsedMap.tilewidth,\n * height: parsedMap.height * parsedMap.tileheight,\n * events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects\n * }\n * })\n * ])\n * }\n * \n * // Synchronous usage for static maps\n * export function provideStaticMap() {\n * return createModule(\"StaticMap\", [\n * provideLoadMap((mapId) => {\n * const staticMaps = {\n * 'town': { tiles: [...], npcs: [...] },\n * 'dungeon': { tiles: [...], monsters: [...] }\n * }\n * \n * return {\n * data: staticMaps[mapId],\n * component: StaticMapComponent,\n * width: 800,\n * height: 600\n * }\n * })\n * ])\n * }\n * ```\n * \n * @since 4.0.0\n * @see {@link LoadMapOptions} for callback function signature\n * @see {@link MapData} for return data structure\n */\nexport function provideLoadMap(options: LoadMapOptions) {\n return [\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => {\n if (context['side'] === 'client') {\n console.warn('UpdateMapToken is not overridden')\n }\n return\n },\n },\n {\n provide: LoadMapToken,\n useFactory: (context: Context) => new LoadMapService(context, options),\n },\n ];\n}\n"],"mappings":";;;AAGA,IAAa,eAAe;AAkC5B,IAAa,iBAAb,MAA4B;CAG1B,YAAY,SAA0B,SAAiC;EAAnD,KAAA,UAAA;EAA0B,KAAA,UAAA;EAC5C,IAAI,QAAQ,YAAY,UACtB;EAEF,KAAK,mBAAmB,OAAO,SAAS,eAAe;;CAGzD,MAAM,KAAK,OAAe;EACxB,MAAM,MAAM,MAAM,KAAK,QAAQ,MAAM,QAAQ,QAAQ,GAAG,CAAC;EACzD,MAAM,KAAK,iBAAiB,OAAO,IAAI;EACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FX,SAAgB,eAAe,SAAyB;CACtD,OAAO,CACL;EACE,SAAS;EACT,aAAa,YAAqB;GAChC,IAAI,QAAQ,YAAY,UACtB,QAAQ,KAAK,mCAAmC;;EAIrD,EACD;EACE,SAAS;EACT,aAAa,YAAqB,IAAI,eAAe,SAAS,QAAQ;EACvE,CACF"}
|
package/dist/services/mmorpg.js
CHANGED
|
@@ -3,7 +3,7 @@ import { provideSaveClient } from "./save.js";
|
|
|
3
3
|
import { RpgGui } from "../Gui/Gui.js";
|
|
4
4
|
import { RpgClientEngine } from "../RpgClientEngine.js";
|
|
5
5
|
import { provideKeyboardControls } from "./keyboardControls.js";
|
|
6
|
-
import { connectionRoom } from "../node_modules/.pnpm/@signe_sync@2.
|
|
6
|
+
import { connectionRoom } from "../node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/client/index.js";
|
|
7
7
|
import { UpdateMapService, UpdateMapToken } from "@rpgjs/common";
|
|
8
8
|
//#region src/services/mmorpg.ts
|
|
9
9
|
var BridgeWebsocket = class extends AbstractWebsocket {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mmorpg.js","names":[],"sources":["../../src/services/mmorpg.ts"],"sourcesContent":["import { Context } from \"@signe/di\";\nimport { connectionRoom } from \"@signe/sync/client\";\nimport { RpgGui } from \"../Gui/Gui\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { AbstractWebsocket, SocketUpdateProperties, WebSocketToken } from \"./AbstractSocket\";\nimport { UpdateMapService, UpdateMapToken } from \"@rpgjs/common\";\nimport { provideKeyboardControls } from \"./keyboardControls\";\nimport { provideSaveClient } from \"./save\";\n\ninterface MmorpgOptions {\n host?: string;\n connectionId?: string;\n connectionIdScope?: \"local\" | \"session\" | \"ephemeral\";\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n private socket: any;\n private privateId: string;\n private pendingOn: Array<{ event: string; callback: (data: any) => void }> = [];\n private targetRoom = \"lobby-1\";\n\n constructor(protected context: Context, private options: MmorpgOptions = {}) {\n super(context);\n this.privateId = this.resolveConnectionId();\n }\n\n private resolveConnectionId(): string {\n if (this.options.connectionId) {\n return this.options.connectionId;\n }\n\n const scope = this.options.connectionIdScope ?? \"local\";\n const key = \"rpgjs-user-id\";\n\n if (scope === \"ephemeral\") {\n return crypto.randomUUID();\n }\n\n const storage =\n scope === \"session\"\n ? window.sessionStorage\n : window.localStorage;\n\n const existing = storage.getItem(key);\n if (existing) {\n return existing;\n }\n\n const id = crypto.randomUUID();\n storage.setItem(key, id);\n return id;\n }\n\n async connection(listeners?: (data: any) => void) {\n // tmp\n class Room {\n \n }\n const instance = new Room()\n const host = this.options.host || window.location.host;\n this.socket = await connectionRoom({\n host,\n room: this.targetRoom,\n id: this.privateId\n }, instance)\n\n listeners?.(this.socket)\n this.pendingOn.forEach(({ event, callback }) => this.socket.on(event, callback));\n this.pendingOn = [];\n }\n\n on(key: string, callback: (data: any) => void) {\n if (!this.socket) {\n this.pendingOn.push({ event: key, callback });\n return;\n }\n this.socket.on(key, callback);\n }\n\n off(event: string, callback: (data: any) => void) {\n if (!this.socket) return;\n this.socket.off(event, callback);\n }\n\n emit(event: string, data: any) {\n this.socket.emit(event, data);\n }\n\n updateProperties({ room, host, query }: SocketUpdateProperties) {\n if (!this.socket?.conn) return;\n this.targetRoom = room;\n this.socket.conn.updateProperties({\n room,\n id: this.privateId,\n host: host || this.options.host || window.location.host,\n query,\n })\n }\n\n private waitForNextOpen(conn: any, timeoutMs = 10000): Promise<void> {\n return new Promise((resolve, reject) => {\n let timeoutId: number | undefined;\n const onOpen = () => {\n cleanup();\n resolve();\n };\n const onError = () => {\n cleanup();\n reject(new Error(\"WebSocket reconnect failed\"));\n };\n const cleanup = () => {\n conn.removeEventListener(\"open\", onOpen);\n conn.removeEventListener(\"error\", onError);\n if (timeoutId !== undefined) {\n window.clearTimeout(timeoutId);\n }\n };\n\n conn.addEventListener(\"open\", onOpen);\n conn.addEventListener(\"error\", onError);\n timeoutId = window.setTimeout(() => {\n cleanup();\n reject(new Error(\"WebSocket reconnect timeout\"));\n }, timeoutMs);\n });\n }\n\n async reconnect(_listeners?: (data: any) => void): Promise<void> {\n if (!this.socket?.conn) return;\n const conn = this.socket.conn;\n const opened = this.waitForNextOpen(conn);\n conn.reconnect();\n await opened;\n }\n\n getCurrentRoom(): string {\n return this.targetRoom || this.socket?.conn?.room || \"lobby-1\";\n }\n}\n\nclass UpdateMapStandaloneService extends UpdateMapService {\n constructor(protected context: Context, private _options: MmorpgOptions) {\n super(context);\n }\n\n async update(_map: any) {\n // In MMORPG mode, clients are untrusted and must not push map definitions.\n // Map bootstrap/update is handled server-side by @rpgjs/vite.\n return;\n }\n}\n\nexport function provideMmorpg(options: MmorpgOptions) {\n return [\n {\n provide: WebSocketToken,\n useFactory: (context: Context) => new BridgeWebsocket(context, options),\n },\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => new UpdateMapStandaloneService(context, options),\n },\n provideKeyboardControls(),\n provideSaveClient(),\n RpgGui,\n RpgClientEngine,\n ];\n}\n"],"mappings":";;;;;;;;AAeA,IAAM,kBAAN,cAA8B,kBAAkB;CAM9C,YAAY,SAA4B,UAAiC,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"mmorpg.js","names":[],"sources":["../../src/services/mmorpg.ts"],"sourcesContent":["import { Context } from \"@signe/di\";\nimport { connectionRoom } from \"@signe/sync/client\";\nimport { RpgGui } from \"../Gui/Gui\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { AbstractWebsocket, SocketUpdateProperties, WebSocketToken } from \"./AbstractSocket\";\nimport { UpdateMapService, UpdateMapToken } from \"@rpgjs/common\";\nimport { provideKeyboardControls } from \"./keyboardControls\";\nimport { provideSaveClient } from \"./save\";\n\ninterface MmorpgOptions {\n host?: string;\n connectionId?: string;\n connectionIdScope?: \"local\" | \"session\" | \"ephemeral\";\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n private socket: any;\n private privateId: string;\n private pendingOn: Array<{ event: string; callback: (data: any) => void }> = [];\n private targetRoom = \"lobby-1\";\n\n constructor(protected context: Context, private options: MmorpgOptions = {}) {\n super(context);\n this.privateId = this.resolveConnectionId();\n }\n\n private resolveConnectionId(): string {\n if (this.options.connectionId) {\n return this.options.connectionId;\n }\n\n const scope = this.options.connectionIdScope ?? \"local\";\n const key = \"rpgjs-user-id\";\n\n if (scope === \"ephemeral\") {\n return crypto.randomUUID();\n }\n\n const storage =\n scope === \"session\"\n ? window.sessionStorage\n : window.localStorage;\n\n const existing = storage.getItem(key);\n if (existing) {\n return existing;\n }\n\n const id = crypto.randomUUID();\n storage.setItem(key, id);\n return id;\n }\n\n async connection(listeners?: (data: any) => void) {\n // tmp\n class Room {\n \n }\n const instance = new Room()\n const host = this.options.host || window.location.host;\n this.socket = await connectionRoom({\n host,\n room: this.targetRoom,\n id: this.privateId\n }, instance)\n\n listeners?.(this.socket)\n this.pendingOn.forEach(({ event, callback }) => this.socket.on(event, callback));\n this.pendingOn = [];\n }\n\n on(key: string, callback: (data: any) => void) {\n if (!this.socket) {\n this.pendingOn.push({ event: key, callback });\n return;\n }\n this.socket.on(key, callback);\n }\n\n off(event: string, callback: (data: any) => void) {\n if (!this.socket) return;\n this.socket.off(event, callback);\n }\n\n emit(event: string, data: any) {\n this.socket.emit(event, data);\n }\n\n updateProperties({ room, host, query }: SocketUpdateProperties) {\n if (!this.socket?.conn) return;\n this.targetRoom = room;\n this.socket.conn.updateProperties({\n room,\n id: this.privateId,\n host: host || this.options.host || window.location.host,\n query,\n })\n }\n\n private waitForNextOpen(conn: any, timeoutMs = 10000): Promise<void> {\n return new Promise((resolve, reject) => {\n let timeoutId: number | undefined;\n const onOpen = () => {\n cleanup();\n resolve();\n };\n const onError = () => {\n cleanup();\n reject(new Error(\"WebSocket reconnect failed\"));\n };\n const cleanup = () => {\n conn.removeEventListener(\"open\", onOpen);\n conn.removeEventListener(\"error\", onError);\n if (timeoutId !== undefined) {\n window.clearTimeout(timeoutId);\n }\n };\n\n conn.addEventListener(\"open\", onOpen);\n conn.addEventListener(\"error\", onError);\n timeoutId = window.setTimeout(() => {\n cleanup();\n reject(new Error(\"WebSocket reconnect timeout\"));\n }, timeoutMs);\n });\n }\n\n async reconnect(_listeners?: (data: any) => void): Promise<void> {\n if (!this.socket?.conn) return;\n const conn = this.socket.conn;\n const opened = this.waitForNextOpen(conn);\n conn.reconnect();\n await opened;\n }\n\n getCurrentRoom(): string {\n return this.targetRoom || this.socket?.conn?.room || \"lobby-1\";\n }\n}\n\nclass UpdateMapStandaloneService extends UpdateMapService {\n constructor(protected context: Context, private _options: MmorpgOptions) {\n super(context);\n }\n\n async update(_map: any) {\n // In MMORPG mode, clients are untrusted and must not push map definitions.\n // Map bootstrap/update is handled server-side by @rpgjs/vite.\n return;\n }\n}\n\nexport function provideMmorpg(options: MmorpgOptions) {\n return [\n {\n provide: WebSocketToken,\n useFactory: (context: Context) => new BridgeWebsocket(context, options),\n },\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => new UpdateMapStandaloneService(context, options),\n },\n provideKeyboardControls(),\n provideSaveClient(),\n RpgGui,\n RpgClientEngine,\n ];\n}\n"],"mappings":"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"}
|
|
@@ -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,eAAe;iCACd,IAAI,KAAK;wBAC/B;;CAEzB,aAAa;EACX,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,KAAK;EAC1F,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,KAAK;EAC1F,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,KAAK;EAC1F,MAAM,mBAAmB,SAA0B,KAAK,cAAc,KAAK,WAAW,KAAK,QAAQ;
|
|
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,eAAe;iCACd,IAAI,KAAK;wBAC/B;;CAEzB,aAAa;EACX,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,KAAK;EAC1F,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,KAAK;EAC1F,MAAM,kBAAkB,SAAyB,KAAK,eAAe,KAAK,WAAW,KAAK;EAC1F,MAAM,mBAAmB,SAA0B,KAAK,cAAc,KAAK,WAAW,KAAK,QAAQ;EACnG,KAAK,UAAU,IAAI,oBAAoB,eAAe;EACtD,KAAK,UAAU,IAAI,oBAAoB,eAAe;EACtD,KAAK,UAAU,IAAI,oBAAoB,eAAe;EACtD,KAAK,UAAU,IAAI,cAAc,gBAAgB;EACjD,KAAK,UAAU,GAAG,oBAAoB,eAAe;EACrD,KAAK,UAAU,GAAG,oBAAoB,eAAe;EACrD,KAAK,UAAU,GAAG,oBAAoB,eAAe;EACrD,KAAK,UAAU,GAAG,cAAc,gBAAgB;;CAGlD,YAAmC;EACjC,OAAO,KAAK,QAAwB,aAAa,EAAE,CAAC,CAAC,MAAM,WAAW,OAAO,MAAM;;CAGrF,SAAS,OAAe,OAAqB,EAAE,EAAyB;EACtE,OAAO,KAAK,QAAwB,aAAa;GAAE;GAAO;GAAM,CAAC,CAAC,MAAM,WAAW,OAAO,MAAM;;CAGlG,SAAS,OAAiC;EACxC,OAAO,KAAK,QAAwB,aAAa,EAAE,OAAO,CAAC,CAAC,MAAM,WAAW,OAAO,GAAG;;CAGzF,QAAmB,OAAe,SAA0C;EAC1E,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,CAAC,KAAK,WACR,KAAK,YAAY;GAEnB,MAAM,YAAY,KAAK,eAAe;GACtC,KAAK,QAAQ,IAAI,WAAW;IAAE;IAAS;IAAQ,CAAC;GAChD,KAAK,WAAW,KAAK,OAAO;IAAE;IAAW,GAAG;IAAS,CAAC;IACtD;;CAGJ,eAAuB,WAAmB,QAAa;EACrD,MAAM,UAAU,KAAK,QAAQ,IAAI,UAAU;EAC3C,IAAI,CAAC,SAAS;EACd,KAAK,QAAQ,OAAO,UAAU;EAC9B,QAAQ,QAAQ,OAAO;;CAGzB,cAAsB,WAAmB,SAAiB;EACxD,MAAM,UAAU,KAAK,QAAQ,IAAI,UAAU;EAC3C,IAAI,CAAC,SAAS;EACd,KAAK,QAAQ,OAAO,UAAU;EAC9B,QAAQ,OAAO,IAAI,MAAM,QAAQ,CAAC;;CAGpC,gBAAgC;EAC9B,KAAK,kBAAkB;EACvB,OAAO,GAAG,KAAK,KAAK,CAAC,GAAG,KAAK;;;AAIjC,SAAgB,oBAAoB;CAClC,OAAO;EACL,SAAS;EACT,UAAU;EACX"}
|
|
@@ -2,7 +2,7 @@ import { AbstractWebsocket, WebSocketToken } from "./AbstractSocket.js";
|
|
|
2
2
|
import { provideSaveClient } from "./save.js";
|
|
3
3
|
import { RpgGui } from "../Gui/Gui.js";
|
|
4
4
|
import { RpgClientEngine } from "../RpgClientEngine.js";
|
|
5
|
-
import { ClientIo, ServerIo } from "../node_modules/.pnpm/@signe_room@2.
|
|
5
|
+
import { ClientIo, ServerIo } from "../node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js";
|
|
6
6
|
import { provideKeyboardControls } from "./keyboardControls.js";
|
|
7
7
|
import { UpdateMapService, UpdateMapToken } from "@rpgjs/common";
|
|
8
8
|
//#region src/services/standalone.ts
|
|
@@ -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\";\n\ntype ServerIo = any;\ntype ClientIo = any;\n\ninterface StandaloneOptions {\n env?: Record<string, any>;\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n private room: ServerIo;\n private socket: ClientIo;\n private pendingOn: Array<{ event: string; callback: (data: any) => void }> = [];\n private rooms = {\n partyFn: async (roomId: string) => {\n this.room = new ServerIo(roomId, this.rooms);\n const server = new this.server(this.room)\n await server.onStart();\n await server.subRoom.onStart()\n this.context.set('server', server)\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.serverInstance = this.context.get('server')\n this.socket = new ClientIo(this.serverInstance, 'player-client-id');\n const url = new URL('http://localhost')\n const request = new Request(url.toString(), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n listeners?.(this.socket)\n await this.serverInstance.onConnect(this.socket.conn as any, { request } as any);\n this.room.clients.set(this.socket.id, this.socket);\n this.pendingOn.forEach(({ event, callback }) => this.socket.addEventListener(event, callback));\n this.pendingOn = [];\n return this.socket\n }\n\n on(key: string, callback: (data: any) => void) {\n const handler = (event) => {\n const object = JSON.parse(event);\n if (object.type === key) {\n callback(object.value);\n }\n };\n if (!this.socket) {\n this.pendingOn.push({ event: \"message\", callback: handler });\n return;\n }\n this.socket.addEventListener(\"message\", handler);\n }\n\n off(event: string, callback: (data: any) => void) {\n if (!this.socket) return;\n this.socket.removeEventListener(event, callback);\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(_params: SocketUpdateProperties) {\n // empty\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 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":";;;;;;;;AAiBA,IAAM,kBAAN,cAA8B,kBAAkB;CAiB9C,YAAY,SAA4B,QAAqB,UAA6B,EAAE,EAAE;
|
|
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\";\n\ntype ServerIo = any;\ntype ClientIo = any;\n\ninterface StandaloneOptions {\n env?: Record<string, any>;\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n private room: ServerIo;\n private socket: ClientIo;\n private pendingOn: Array<{ event: string; callback: (data: any) => void }> = [];\n private rooms = {\n partyFn: async (roomId: string) => {\n this.room = new ServerIo(roomId, this.rooms);\n const server = new this.server(this.room)\n await server.onStart();\n await server.subRoom.onStart()\n this.context.set('server', server)\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.serverInstance = this.context.get('server')\n this.socket = new ClientIo(this.serverInstance, 'player-client-id');\n const url = new URL('http://localhost')\n const request = new Request(url.toString(), {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n listeners?.(this.socket)\n await this.serverInstance.onConnect(this.socket.conn as any, { request } as any);\n this.room.clients.set(this.socket.id, this.socket);\n this.pendingOn.forEach(({ event, callback }) => this.socket.addEventListener(event, callback));\n this.pendingOn = [];\n return this.socket\n }\n\n on(key: string, callback: (data: any) => void) {\n const handler = (event) => {\n const object = JSON.parse(event);\n if (object.type === key) {\n callback(object.value);\n }\n };\n if (!this.socket) {\n this.pendingOn.push({ event: \"message\", callback: handler });\n return;\n }\n this.socket.addEventListener(\"message\", handler);\n }\n\n off(event: string, callback: (data: any) => void) {\n if (!this.socket) return;\n this.socket.removeEventListener(event, callback);\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(_params: SocketUpdateProperties) {\n // empty\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 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getEntityProp.js","names":[],"sources":["../../src/utils/getEntityProp.ts"],"sourcesContent":["import { computed, Signal } from \"canvasengine\";\nimport { RpgClientObject } from \"../Game/Object\";\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) => 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":";;AAkBA,IAAM,gBAAgB;CACpB,QAAQ,WAA4B,OAAO,QAAQ;CACnD,MAAM,WAA4B,OAAO,MAAM;CAC/C,OAAO,WAA4B,OAAO,OAAO;CACjD,KAAK,WAA4B,OAAO,UAAU;CAClD,KAAK,WAA4B,OAAO,UAAU;CAClD,OAAO,WAA4B,OAAO,MAAM;CAChD,OAAO,WAA4B,OAAO,MAAM;CAChD,IAAI,WAA4B,OAAO,GAAG;CAC1C,IAAI,WAA4B,OAAO,GAAG;CAC1C,IAAI,WAA4B,OAAO,GAAG;CAC1C,OAAO,WAA4B,OAAO,MAAM;CAChD,YAAY,WAA4B,OAAO,WAAW;CAC1D,QAAQ,WAA4B,OAAO,OAAO;CAClD,SAAS,WAA4B,OAAO,QAAQ;CACpD,YAAY,WAA4B,OAAO,eAAe;CAC9D,UAAU,WAA4B,OAAO,SAAS;CACtD,WAAW,WAA4B,OAAO,UAAU;CACxD,QAAQ,WAA4B,OAAO,OAAO;CAClD,aAAa,WAA4B,OAAO,YAAY;CAC5D,SAAS,WAA4B,OAAO,QAAQ;CACpD,SAAS,WAA4B,OAAO,QAAQ;CACpD,UAAU,WAA4B,OAAO,UAAU;CACvD,gBAAgB,WAA4B,OAAO,eAAe;CAClE,mBAAmB,WAA4B,OAAO,kBAAkB;CACxE,mBAAmB,WAA4B,OAAO,kBAAkB;CACxE,iBAAiB,WAA4B,OAAO,gBAAgB;CACpE,kBAAkB,WAA4B,OAAO,iBAAiB;CACvE;AAUD,IAAM,YAAe,UACnB,OAAO,UAAU;AAEnB,IAAM,YAAe,UACnB,SAAY,MAAM,GAAG,QAAQ,eAAe,MAAM;AAEpD,IAAa,iBACX,QACA,QAC+B;CAC/B,MAAM,eAAe,SAAS,OAAO;
|
|
1
|
+
{"version":3,"file":"getEntityProp.js","names":[],"sources":["../../src/utils/getEntityProp.ts"],"sourcesContent":["import { computed, Signal } from \"canvasengine\";\nimport { RpgClientObject } from \"../Game/Object\";\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) => 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":";;AAkBA,IAAM,gBAAgB;CACpB,QAAQ,WAA4B,OAAO,QAAQ;CACnD,MAAM,WAA4B,OAAO,MAAM;CAC/C,OAAO,WAA4B,OAAO,OAAO;CACjD,KAAK,WAA4B,OAAO,UAAU;CAClD,KAAK,WAA4B,OAAO,UAAU;CAClD,OAAO,WAA4B,OAAO,MAAM;CAChD,OAAO,WAA4B,OAAO,MAAM;CAChD,IAAI,WAA4B,OAAO,GAAG;CAC1C,IAAI,WAA4B,OAAO,GAAG;CAC1C,IAAI,WAA4B,OAAO,GAAG;CAC1C,OAAO,WAA4B,OAAO,MAAM;CAChD,YAAY,WAA4B,OAAO,WAAW;CAC1D,QAAQ,WAA4B,OAAO,OAAO;CAClD,SAAS,WAA4B,OAAO,QAAQ;CACpD,YAAY,WAA4B,OAAO,eAAe;CAC9D,UAAU,WAA4B,OAAO,SAAS;CACtD,WAAW,WAA4B,OAAO,UAAU;CACxD,QAAQ,WAA4B,OAAO,OAAO;CAClD,aAAa,WAA4B,OAAO,YAAY;CAC5D,SAAS,WAA4B,OAAO,QAAQ;CACpD,SAAS,WAA4B,OAAO,QAAQ;CACpD,UAAU,WAA4B,OAAO,UAAU;CACvD,gBAAgB,WAA4B,OAAO,eAAe;CAClE,mBAAmB,WAA4B,OAAO,kBAAkB;CACxE,mBAAmB,WAA4B,OAAO,kBAAkB;CACxE,iBAAiB,WAA4B,OAAO,gBAAgB;CACpE,kBAAkB,WAA4B,OAAO,iBAAiB;CACvE;AAUD,IAAM,YAAe,UACnB,OAAO,UAAU;AAEnB,IAAM,YAAe,UACnB,SAAY,MAAM,GAAG,QAAQ,eAAe,MAAM;AAEpD,IAAa,iBACX,QACA,QAC+B;CAC/B,MAAM,eAAe,SAAS,OAAO;CAErC,OAAO,eAAe;EACpB,MAAM,UAAU,cAAc;EAC9B,IAAI,CAAC,SACH;EAGF,IAAI,OAAO,UAAU,eAAe,KAAK,eAAe,IAAI,EAAE;GAC5D,MAAM,SAAS,cAAc;GAC7B,OAAO,OAAO,QAAQ;;EAGxB,IAAI,IAAI,WAAW,UAAU,EAAE;GAC7B,MAAM,WAAW,IAAI,MAAM,EAAiB;GAC5C,OAAO,QAAQ,UAAU,GAAG;;GAI9B"}
|
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.7",
|
|
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",
|
|
@@ -22,18 +22,18 @@
|
|
|
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.
|
|
28
|
-
"@signe/di": "
|
|
29
|
-
"@signe/room": "
|
|
30
|
-
"@signe/sync": "
|
|
25
|
+
"@rpgjs/common": "5.0.0-beta.7",
|
|
26
|
+
"@rpgjs/server": "5.0.0-beta.7",
|
|
27
|
+
"@rpgjs/ui-css": "5.0.0-beta.7",
|
|
28
|
+
"@signe/di": "2.10.0",
|
|
29
|
+
"@signe/room": "2.10.0",
|
|
30
|
+
"@signe/sync": "2.10.0",
|
|
31
31
|
"pixi-filters": "^6.1.5",
|
|
32
32
|
"rxjs": "^7.8.2"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@canvasengine/compiler": "2.0.0-beta.61",
|
|
36
|
-
"vite": "^8.0.
|
|
36
|
+
"vite": "^8.0.11",
|
|
37
37
|
"vite-plugin-dts": "^5.0.0",
|
|
38
38
|
"vitest": "^4.1.5"
|
|
39
39
|
},
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { AnimationManager } from "./AnimationManager";
|
|
3
|
+
|
|
4
|
+
describe("AnimationManager", () => {
|
|
5
|
+
test("resolves displayEffect when the component calls onFinish", async () => {
|
|
6
|
+
const manager = new AnimationManager();
|
|
7
|
+
const done = manager.displayEffect({}, { x: 10, y: 20 });
|
|
8
|
+
|
|
9
|
+
expect(manager.current()).toHaveLength(1);
|
|
10
|
+
manager.current()[0].onFinish();
|
|
11
|
+
|
|
12
|
+
await expect(done).resolves.toBeUndefined();
|
|
13
|
+
expect(manager.current()).toHaveLength(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("keeps onFinish idempotent and forwards user callback data", async () => {
|
|
17
|
+
const manager = new AnimationManager();
|
|
18
|
+
const onFinish = vi.fn();
|
|
19
|
+
const done = manager.displayEffect({ onFinish }, { x: 10, y: 20 });
|
|
20
|
+
const finish = manager.current()[0].onFinish;
|
|
21
|
+
|
|
22
|
+
finish({ ok: true });
|
|
23
|
+
finish({ ok: false });
|
|
24
|
+
|
|
25
|
+
await done;
|
|
26
|
+
expect(onFinish).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(onFinish).toHaveBeenCalledWith({ ok: true });
|
|
28
|
+
expect(manager.current()).toHaveLength(0);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -4,18 +4,30 @@ import { signal } from "canvasengine";
|
|
|
4
4
|
export class AnimationManager {
|
|
5
5
|
current = signal<any[]>([]);
|
|
6
6
|
|
|
7
|
-
displayEffect(params: any, player: RpgCommonPlayer | { x: number, y: number }) {
|
|
7
|
+
displayEffect(params: any, player: RpgCommonPlayer | { x: number, y: number }): Promise<void> {
|
|
8
8
|
const id = generateUID();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
onFinish: () => {
|
|
9
|
+
const effectParams = params ?? {};
|
|
10
|
+
return new Promise<void>((resolve) => {
|
|
11
|
+
let finished = false;
|
|
12
|
+
const finish = (data?: any) => {
|
|
13
|
+
if (finished) return;
|
|
14
|
+
finished = true;
|
|
16
15
|
const index = this.current().findIndex((value) => value.id === id);
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (index !== -1) {
|
|
17
|
+
this.current().splice(index, 1);
|
|
18
|
+
}
|
|
19
|
+
effectParams.onFinish?.(data);
|
|
20
|
+
resolve();
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.current().push({
|
|
24
|
+
...effectParams,
|
|
25
|
+
id,
|
|
26
|
+
x: player.x,
|
|
27
|
+
y: player.y,
|
|
28
|
+
object: player,
|
|
29
|
+
onFinish: finish,
|
|
30
|
+
});
|
|
19
31
|
});
|
|
20
32
|
}
|
|
21
33
|
}
|
package/src/Game/Object.ts
CHANGED
|
@@ -14,6 +14,7 @@ type Frame = { x: number; y: number; ts: number };
|
|
|
14
14
|
type AnimationRestoreOptions = {
|
|
15
15
|
restoreAnimationName?: string;
|
|
16
16
|
restoreGraphics?: any[];
|
|
17
|
+
timeoutMs?: number;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
@@ -113,6 +114,7 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
113
114
|
|
|
114
115
|
private animationSubscription?: Subscription;
|
|
115
116
|
private animationResetTimeout?: ReturnType<typeof setTimeout>;
|
|
117
|
+
private animationWaitResolve?: () => void;
|
|
116
118
|
|
|
117
119
|
private clearAnimationControls() {
|
|
118
120
|
if (this.animationSubscription) {
|
|
@@ -125,6 +127,12 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
|
|
130
|
+
private resolveAnimationWait() {
|
|
131
|
+
const resolve = this.animationWaitResolve;
|
|
132
|
+
this.animationWaitResolve = undefined;
|
|
133
|
+
resolve?.();
|
|
134
|
+
}
|
|
135
|
+
|
|
128
136
|
private finishTemporaryAnimation() {
|
|
129
137
|
const restoreState = this.animationRestoreState;
|
|
130
138
|
this.clearAnimationControls();
|
|
@@ -135,6 +143,7 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
135
143
|
}
|
|
136
144
|
this.animationRestoreState = undefined;
|
|
137
145
|
this.animationIsPlaying.set(false);
|
|
146
|
+
this.resolveAnimationWait();
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
/**
|
|
@@ -241,6 +250,7 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
241
250
|
this.animationIsPlaying.set(false);
|
|
242
251
|
this.animationCurrentIndex.set(0);
|
|
243
252
|
this.clearAnimationControls();
|
|
253
|
+
this.resolveAnimationWait();
|
|
244
254
|
}
|
|
245
255
|
|
|
246
256
|
/**
|
|
@@ -252,17 +262,19 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
252
262
|
*
|
|
253
263
|
* @param animationName - Name of the animation to play
|
|
254
264
|
* @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
|
|
265
|
+
* @param options - Restore and timeout options
|
|
266
|
+
* @returns A promise resolved when a finite animation finishes, is interrupted, or times out
|
|
255
267
|
*
|
|
256
268
|
* @example
|
|
257
269
|
* ```ts
|
|
258
270
|
* // Play attack animation 3 times
|
|
259
|
-
* player.setAnimation('attack', 3);
|
|
271
|
+
* await player.setAnimation('attack', 3);
|
|
260
272
|
*
|
|
261
273
|
* // Play continuous spell animation
|
|
262
274
|
* player.setAnimation('spell');
|
|
263
275
|
* ```
|
|
264
276
|
*/
|
|
265
|
-
setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): void
|
|
277
|
+
setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;
|
|
266
278
|
/**
|
|
267
279
|
* Set a custom animation with temporary graphic change
|
|
268
280
|
*
|
|
@@ -273,20 +285,22 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
273
285
|
* @param animationName - Name of the animation to play
|
|
274
286
|
* @param graphic - The graphic(s) to temporarily use during the animation
|
|
275
287
|
* @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
|
|
288
|
+
* @param options - Restore and timeout options
|
|
289
|
+
* @returns A promise resolved when a finite animation finishes, is interrupted, or times out
|
|
276
290
|
*
|
|
277
291
|
* @example
|
|
278
292
|
* ```ts
|
|
279
293
|
* // Play attack animation with temporary graphic change
|
|
280
|
-
* player.setAnimation('attack', 'hero_attack', 3);
|
|
294
|
+
* await player.setAnimation('attack', 'hero_attack', 3);
|
|
281
295
|
* ```
|
|
282
296
|
*/
|
|
283
|
-
setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): void
|
|
297
|
+
setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;
|
|
284
298
|
setAnimation(
|
|
285
299
|
animationName: string,
|
|
286
300
|
graphicOrNbTimes?: string | string[] | number,
|
|
287
301
|
nbTimesOrOptions?: number | AnimationRestoreOptions,
|
|
288
302
|
options?: AnimationRestoreOptions
|
|
289
|
-
): void {
|
|
303
|
+
): Promise<void> {
|
|
290
304
|
let graphic: string | string[] | undefined;
|
|
291
305
|
let finalNbTimes: number = Infinity;
|
|
292
306
|
let restoreOptions: AnimationRestoreOptions | undefined = options;
|
|
@@ -314,6 +328,13 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
314
328
|
this.finishTemporaryAnimation();
|
|
315
329
|
}
|
|
316
330
|
|
|
331
|
+
const waitPromise =
|
|
332
|
+
finalNbTimes === Infinity
|
|
333
|
+
? Promise.resolve()
|
|
334
|
+
: new Promise<void>((resolve) => {
|
|
335
|
+
this.animationWaitResolve = resolve;
|
|
336
|
+
});
|
|
337
|
+
|
|
317
338
|
this.animationIsPlaying.set(true);
|
|
318
339
|
const previousAnimationName =
|
|
319
340
|
restoreOptions?.restoreAnimationName ?? this.animationName();
|
|
@@ -349,10 +370,12 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
349
370
|
if (this.animationIsPlaying()) {
|
|
350
371
|
this.finishTemporaryAnimation();
|
|
351
372
|
}
|
|
352
|
-
}, Math.max(1000, finalNbTimes * 1000));
|
|
373
|
+
}, restoreOptions?.timeoutMs ?? Math.max(1000, finalNbTimes * 1000));
|
|
353
374
|
}
|
|
354
375
|
|
|
355
376
|
this.animationName.set(animationName);
|
|
377
|
+
|
|
378
|
+
return waitPromise;
|
|
356
379
|
}
|
|
357
380
|
|
|
358
381
|
/**
|
|
@@ -360,10 +383,25 @@ export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
|
360
383
|
*
|
|
361
384
|
* @param id - Identifier of the component animation to play.
|
|
362
385
|
* @param params - Parameters forwarded to the animation effect.
|
|
386
|
+
* @returns A promise resolved when the animation component calls `onFinish`.
|
|
363
387
|
*/
|
|
364
|
-
showComponentAnimation(id: string, params: any) {
|
|
388
|
+
showComponentAnimation(id: string, params: any): Promise<void> {
|
|
365
389
|
const engine = inject(RpgClientEngine);
|
|
366
|
-
engine.getComponentAnimation(id).displayEffect(params, this);
|
|
390
|
+
return engine.getComponentAnimation(id).displayEffect(params, this);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Display a registered spritesheet animation effect on this object.
|
|
395
|
+
*
|
|
396
|
+
* @param graphic - Identifier of the spritesheet to use.
|
|
397
|
+
* @param animationName - Name of the animation inside the spritesheet.
|
|
398
|
+
* @returns A promise resolved when the animation component calls `onFinish`.
|
|
399
|
+
*/
|
|
400
|
+
showAnimation(graphic: string, animationName: string = 'default'): Promise<void> {
|
|
401
|
+
return this.showComponentAnimation('animation', {
|
|
402
|
+
graphic,
|
|
403
|
+
animationName,
|
|
404
|
+
});
|
|
367
405
|
}
|
|
368
406
|
|
|
369
407
|
/**
|
package/src/RpgClient.ts
CHANGED
|
@@ -8,6 +8,18 @@ type RpgClass<T = any> = new (...args: any[]) => T
|
|
|
8
8
|
type RpgComponent = RpgClientObject
|
|
9
9
|
type SceneMap = Container
|
|
10
10
|
|
|
11
|
+
export interface RpgSpriteBeforeRemoveContext {
|
|
12
|
+
reason?: string
|
|
13
|
+
data?: any
|
|
14
|
+
transition?: {
|
|
15
|
+
animation?: string
|
|
16
|
+
graphic?: string | string[]
|
|
17
|
+
duration?: number
|
|
18
|
+
effect?: string
|
|
19
|
+
}
|
|
20
|
+
timeoutMs?: number
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
export interface RpgClientEngineHooks {
|
|
12
24
|
/**
|
|
13
25
|
* When the engine is started. If you send false, you prevent the client from connecting to the server
|
|
@@ -114,6 +126,21 @@ export interface RpgSpriteHooks {
|
|
|
114
126
|
*/
|
|
115
127
|
onDestroy?: (sprite: RpgComponent) => any
|
|
116
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Called when a sprite removal is requested, before it disappears from the scene.
|
|
131
|
+
*
|
|
132
|
+
* Return a promise to keep the sprite visible while an animation, effect, or
|
|
133
|
+
* sound transition is running. The server still owns gameplay removal and
|
|
134
|
+
* uses the timeout carried by the remove request as a safety limit.
|
|
135
|
+
*
|
|
136
|
+
* @prop { (sprite: RpgSprite, context: RpgSpriteBeforeRemoveContext) => any } [onBeforeRemove]
|
|
137
|
+
* @memberof RpgSpriteHooks
|
|
138
|
+
*/
|
|
139
|
+
onBeforeRemove?: (
|
|
140
|
+
sprite: RpgComponent,
|
|
141
|
+
context: RpgSpriteBeforeRemoveContext
|
|
142
|
+
) => any
|
|
143
|
+
|
|
117
144
|
/**
|
|
118
145
|
* As soon as a data is changed on the server side (the name for example), you are able to know the new data but also the old data.
|
|
119
146
|
*
|