@rpgjs/client 5.0.0-beta.2 → 5.0.0-beta.22
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 +130 -0
- package/dist/Game/AnimationManager.d.ts +2 -1
- package/dist/Game/AnimationManager.js +21 -9
- package/dist/Game/AnimationManager.js.map +1 -1
- package/dist/Game/AnimationManager.spec.d.ts +1 -0
- package/dist/Game/ClientVisuals.d.ts +61 -0
- package/dist/Game/ClientVisuals.js +96 -0
- package/dist/Game/ClientVisuals.js.map +1 -0
- package/dist/Game/ClientVisuals.spec.d.ts +1 -0
- package/dist/Game/Event.js.map +1 -1
- package/dist/Game/EventComponentResolver.d.ts +16 -0
- package/dist/Game/EventComponentResolver.js +52 -0
- package/dist/Game/EventComponentResolver.js.map +1 -0
- package/dist/Game/EventComponentResolver.spec.d.ts +1 -0
- package/dist/Game/Map.d.ts +9 -1
- package/dist/Game/Map.js +83 -5
- package/dist/Game/Map.js.map +1 -1
- package/dist/Game/Object.d.ts +49 -15
- package/dist/Game/Object.js +101 -42
- package/dist/Game/Object.js.map +1 -1
- package/dist/Game/Object.spec.d.ts +1 -0
- package/dist/Game/Player.js.map +1 -1
- package/dist/Game/ProjectileManager.d.ts +98 -0
- package/dist/Game/ProjectileManager.js +196 -0
- package/dist/Game/ProjectileManager.js.map +1 -0
- package/dist/Game/ProjectileManager.spec.d.ts +1 -0
- package/dist/Gui/Gui.d.ts +20 -6
- package/dist/Gui/Gui.js +132 -57
- package/dist/Gui/Gui.js.map +1 -1
- package/dist/Gui/Gui.spec.d.ts +1 -0
- package/dist/Gui/NotificationManager.js.map +1 -1
- package/dist/Resource.js +1 -1
- package/dist/Resource.js.map +1 -1
- package/dist/RpgClient.d.ts +194 -15
- package/dist/RpgClientEngine.d.ts +191 -19
- package/dist/RpgClientEngine.js +693 -74
- package/dist/RpgClientEngine.js.map +1 -1
- package/dist/Sound.js.map +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.122.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.122.0/helpers → _@oxc-project_runtime@0.133.0/helpers/esm}/decorateMetadata.js +1 -1
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/components/animations/animation.ce.js +6 -5
- package/dist/components/animations/animation.ce.js.map +1 -1
- package/dist/components/animations/fx.ce.js +60 -0
- package/dist/components/animations/fx.ce.js.map +1 -0
- package/dist/components/animations/hit.ce.js +24 -28
- package/dist/components/animations/hit.ce.js.map +1 -1
- package/dist/components/animations/index.d.ts +1 -0
- package/dist/components/animations/index.js +6 -4
- package/dist/components/animations/index.js.map +1 -1
- package/dist/components/character.ce.js +748 -249
- package/dist/components/character.ce.js.map +1 -1
- package/dist/components/dynamics/bar.ce.js +99 -0
- package/dist/components/dynamics/bar.ce.js.map +1 -0
- package/dist/components/dynamics/image.ce.js +26 -0
- package/dist/components/dynamics/image.ce.js.map +1 -0
- package/dist/components/dynamics/parse-value.d.ts +3 -0
- package/dist/components/dynamics/parse-value.js +54 -35
- package/dist/components/dynamics/parse-value.js.map +1 -1
- package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
- package/dist/components/dynamics/shape-utils.d.ts +16 -0
- package/dist/components/dynamics/shape-utils.js +73 -0
- package/dist/components/dynamics/shape-utils.js.map +1 -0
- package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
- package/dist/components/dynamics/shape.ce.js +86 -0
- package/dist/components/dynamics/shape.ce.js.map +1 -0
- package/dist/components/dynamics/text.ce.js +36 -56
- package/dist/components/dynamics/text.ce.js.map +1 -1
- package/dist/components/gui/box.ce.js +9 -9
- package/dist/components/gui/box.ce.js.map +1 -1
- package/dist/components/gui/dialogbox/index.ce.js +75 -65
- package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
- package/dist/components/gui/gameover.ce.js +47 -68
- package/dist/components/gui/gameover.ce.js.map +1 -1
- package/dist/components/gui/hud/hud.ce.js +23 -31
- package/dist/components/gui/hud/hud.ce.js.map +1 -1
- package/dist/components/gui/menu/equip-menu.ce.js +121 -172
- package/dist/components/gui/menu/equip-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/exit-menu.ce.js +15 -10
- package/dist/components/gui/menu/exit-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/items-menu.ce.js +62 -77
- package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/main-menu.ce.js +89 -104
- package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/options-menu.ce.js +12 -8
- package/dist/components/gui/menu/options-menu.ce.js.map +1 -1
- package/dist/components/gui/menu/skills-menu.ce.js +17 -19
- package/dist/components/gui/menu/skills-menu.ce.js.map +1 -1
- package/dist/components/gui/mobile/index.d.ts +51 -2
- package/dist/components/gui/mobile/index.js +14 -6
- package/dist/components/gui/mobile/index.js.map +1 -1
- package/dist/components/gui/mobile/index.spec.d.ts +1 -0
- package/dist/components/gui/mobile/mobile.ce.js +309 -59
- package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
- package/dist/components/gui/notification/notification.ce.js +28 -26
- package/dist/components/gui/notification/notification.ce.js.map +1 -1
- package/dist/components/gui/save-load.ce.js +81 -256
- package/dist/components/gui/save-load.ce.js.map +1 -1
- package/dist/components/gui/shop/shop.ce.js +107 -142
- package/dist/components/gui/shop/shop.ce.js.map +1 -1
- package/dist/components/gui/title-screen.ce.js +50 -73
- package/dist/components/gui/title-screen.ce.js.map +1 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/components/index.js +1 -0
- package/dist/components/interaction-components.ce.js +22 -0
- package/dist/components/interaction-components.ce.js.map +1 -0
- package/dist/components/player-components-utils.d.ts +67 -0
- package/dist/components/player-components-utils.js +162 -0
- package/dist/components/player-components-utils.js.map +1 -0
- package/dist/components/player-components-utils.spec.d.ts +1 -0
- package/dist/components/player-components.ce.js +191 -0
- package/dist/components/player-components.ce.js.map +1 -0
- package/dist/components/prebuilt/hp-bar.ce.js +45 -45
- package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
- package/dist/components/prebuilt/light-halo.ce.js +39 -60
- package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
- package/dist/components/scenes/canvas.ce.js +205 -27
- package/dist/components/scenes/canvas.ce.js.map +1 -1
- package/dist/components/scenes/draw-map.ce.js +39 -39
- package/dist/components/scenes/draw-map.ce.js.map +1 -1
- package/dist/components/scenes/event-layer.ce.js +51 -10
- package/dist/components/scenes/event-layer.ce.js.map +1 -1
- package/dist/core/inject.js +1 -1
- package/dist/core/inject.js.map +1 -1
- package/dist/core/setup.js +1 -1
- package/dist/core/setup.js.map +1 -1
- package/dist/decorators/spritesheet.d.ts +1 -0
- package/dist/decorators/spritesheet.js +11 -0
- package/dist/decorators/spritesheet.js.map +1 -0
- package/dist/i18n.d.ts +55 -0
- package/dist/i18n.js +60 -0
- package/dist/i18n.js.map +1 -0
- package/dist/i18n.spec.d.ts +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +29 -21
- package/dist/module.js +45 -4
- package/dist/module.js.map +1 -1
- package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@3.1.0}/node_modules/@signe/di/dist/index.js +7 -117
- package/dist/node_modules/.pnpm/@signe_di@3.1.0/node_modules/@signe/di/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js +239 -0
- package/dist/node_modules/.pnpm/@signe_reactive@3.1.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
- package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js +698 -0
- package/dist/node_modules/.pnpm/@signe_room@3.1.0_react@19.2.7/node_modules/@signe/room/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js +43 -0
- package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/client/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{@signe_sync@2.9.0 → @signe_sync@3.1.0_react@19.2.7}/node_modules/@signe/sync/dist/index.js +57 -141
- package/dist/node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/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 → partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js} +30 -17
- package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js → partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js} +65 -34
- package/dist/node_modules/.pnpm/partysocket@1.2.0_react@19.2.7/node_modules/partysocket/dist/ws.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js +13 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js +106 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js +13 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js +121 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js +10 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js +110 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js +99 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js.map +1 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js +82 -0
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js.map +1 -0
- package/dist/node_modules/.pnpm/{zod@3.24.2/node_modules/zod/lib/index.js → zod@3.25.76/node_modules/zod/v3/types.js} +74 -611
- package/dist/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js.map +1 -0
- package/dist/presets/animation.js.map +1 -1
- package/dist/presets/faceset.js.map +1 -1
- package/dist/presets/icon.js.map +1 -1
- package/dist/presets/index.js.map +1 -1
- package/dist/presets/lpc.js.map +1 -1
- package/dist/presets/rmspritesheet.js.map +1 -1
- package/dist/services/AbstractSocket.d.ts +2 -0
- package/dist/services/AbstractSocket.js.map +1 -1
- package/dist/services/actionInput.d.ts +14 -0
- package/dist/services/actionInput.js +59 -0
- package/dist/services/actionInput.js.map +1 -0
- package/dist/services/actionInput.spec.d.ts +1 -0
- package/dist/services/cameraFollow.d.ts +51 -0
- package/dist/services/cameraFollow.js +134 -0
- package/dist/services/cameraFollow.js.map +1 -0
- package/dist/services/cameraFollow.spec.d.ts +1 -0
- package/dist/services/interactions.d.ts +159 -0
- package/dist/services/interactions.js +460 -0
- package/dist/services/interactions.js.map +1 -0
- package/dist/services/interactions.spec.d.ts +1 -0
- package/dist/services/keyboardControls.d.ts +1 -0
- package/dist/services/keyboardControls.js +1 -0
- package/dist/services/keyboardControls.js.map +1 -1
- package/dist/services/loadMap.d.ts +9 -0
- package/dist/services/loadMap.js +1 -1
- package/dist/services/loadMap.js.map +1 -1
- package/dist/services/mmorpg-connection.d.ts +5 -0
- package/dist/services/mmorpg-connection.js +50 -0
- package/dist/services/mmorpg-connection.js.map +1 -0
- package/dist/services/mmorpg-connection.spec.d.ts +1 -0
- package/dist/services/mmorpg.d.ts +11 -4
- package/dist/services/mmorpg.js +57 -33
- package/dist/services/mmorpg.js.map +1 -1
- package/dist/services/pointerContext.d.ts +11 -0
- package/dist/services/pointerContext.js +48 -0
- package/dist/services/pointerContext.js.map +1 -0
- package/dist/services/pointerContext.spec.d.ts +1 -0
- package/dist/services/save.js.map +1 -1
- package/dist/services/save.spec.d.ts +1 -0
- package/dist/services/standalone-message.d.ts +1 -0
- package/dist/services/standalone-message.js +9 -0
- package/dist/services/standalone-message.js.map +1 -0
- package/dist/services/standalone.d.ts +4 -1
- package/dist/services/standalone.js +36 -16
- package/dist/services/standalone.js.map +1 -1
- package/dist/services/standalone.spec.d.ts +1 -0
- package/dist/utils/getEntityProp.js +4 -3
- package/dist/utils/getEntityProp.js.map +1 -1
- package/dist/utils/getEntityProp.spec.d.ts +1 -0
- package/dist/utils/mapId.d.ts +1 -0
- package/dist/utils/mapId.js +6 -0
- package/dist/utils/mapId.js.map +1 -0
- package/dist/utils/readPropValue.d.ts +2 -0
- package/dist/utils/readPropValue.js +13 -0
- package/dist/utils/readPropValue.js.map +1 -0
- package/package.json +13 -13
- package/src/Game/AnimationManager.spec.ts +30 -0
- package/src/Game/AnimationManager.ts +26 -10
- package/src/Game/ClientVisuals.spec.ts +56 -0
- package/src/Game/ClientVisuals.ts +184 -0
- package/src/Game/EventComponentResolver.spec.ts +84 -0
- package/src/Game/EventComponentResolver.ts +74 -0
- package/src/Game/Map.ts +134 -2
- package/src/Game/Object.spec.ts +59 -0
- package/src/Game/Object.ts +181 -77
- package/src/Game/ProjectileManager.spec.ts +449 -0
- package/src/Game/ProjectileManager.ts +346 -0
- package/src/Gui/Gui.spec.ts +359 -0
- package/src/Gui/Gui.ts +178 -67
- package/src/Resource.ts +1 -2
- package/src/RpgClient.ts +220 -17
- package/src/RpgClientEngine.ts +995 -133
- package/src/components/animations/fx.ce +101 -0
- package/src/components/animations/index.ts +4 -2
- package/src/components/character.ce +839 -45
- package/src/components/dynamics/bar.ce +88 -0
- package/src/components/dynamics/image.ce +21 -0
- package/src/components/dynamics/parse-value.spec.ts +83 -0
- package/src/components/dynamics/parse-value.ts +111 -37
- package/src/components/dynamics/shape-utils.spec.ts +46 -0
- package/src/components/dynamics/shape-utils.ts +61 -0
- package/src/components/dynamics/shape.ce +90 -0
- package/src/components/dynamics/text.ce +35 -149
- package/src/components/gui/dialogbox/index.ce +52 -21
- package/src/components/gui/gameover.ce +6 -4
- package/src/components/gui/menu/equip-menu.ce +11 -9
- package/src/components/gui/menu/exit-menu.ce +6 -4
- package/src/components/gui/menu/items-menu.ce +11 -9
- package/src/components/gui/menu/main-menu.ce +14 -12
- package/src/components/gui/menu/options-menu.ce +4 -3
- package/src/components/gui/menu/skills-menu.ce +2 -1
- package/src/components/gui/mobile/index.spec.ts +94 -0
- package/src/components/gui/mobile/index.ts +74 -6
- package/src/components/gui/mobile/mobile.ce +347 -65
- package/src/components/gui/notification/notification.ce +7 -1
- package/src/components/gui/save-load.ce +13 -11
- package/src/components/gui/shop/shop.ce +20 -18
- package/src/components/gui/title-screen.ce +6 -4
- package/src/components/index.ts +2 -1
- package/src/components/interaction-components.ce +23 -0
- package/src/components/player-components-utils.spec.ts +109 -0
- package/src/components/player-components-utils.ts +205 -0
- package/src/components/player-components.ce +222 -0
- package/src/components/prebuilt/hp-bar.ce +4 -3
- package/src/components/prebuilt/light-halo.ce +2 -2
- package/src/components/scenes/canvas.ce +219 -15
- package/src/components/scenes/draw-map.ce +34 -22
- package/src/components/scenes/event-layer.ce +55 -4
- package/src/core/setup.ts +2 -2
- package/src/decorators/spritesheet.ts +8 -0
- package/src/i18n.spec.ts +39 -0
- package/src/i18n.ts +59 -0
- package/src/index.ts +19 -0
- package/src/module.ts +61 -11
- package/src/services/AbstractSocket.ts +3 -0
- package/src/services/actionInput.spec.ts +155 -0
- package/src/services/actionInput.ts +120 -0
- package/src/services/cameraFollow.spec.ts +220 -0
- package/src/services/cameraFollow.ts +222 -0
- package/src/services/interactions.spec.ts +175 -0
- package/src/services/interactions.ts +722 -0
- package/src/services/keyboardControls.ts +2 -1
- package/src/services/loadMap.ts +5 -1
- package/src/services/mmorpg-connection.spec.ts +99 -0
- package/src/services/mmorpg-connection.ts +69 -0
- package/src/services/mmorpg.ts +70 -36
- package/src/services/pointerContext.spec.ts +36 -0
- package/src/services/pointerContext.ts +84 -0
- package/src/services/save.spec.ts +127 -0
- package/src/services/standalone-message.ts +7 -0
- package/src/services/standalone.spec.ts +54 -0
- package/src/services/standalone.ts +44 -12
- package/src/utils/getEntityProp.spec.ts +96 -0
- package/src/utils/getEntityProp.ts +4 -3
- package/src/utils/mapId.ts +2 -0
- package/src/utils/readPropValue.ts +16 -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.8.3/node_modules/@signe/reactive/dist/index.js +0 -457
- package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/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
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +0 -1
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +0 -1
- package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +0 -2
- package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +0 -1
package/dist/RpgClientEngine.js
CHANGED
|
@@ -1,45 +1,127 @@
|
|
|
1
1
|
import { inject } from "./core/inject.js";
|
|
2
2
|
import { WebSocketToken } from "./services/AbstractSocket.js";
|
|
3
|
+
import { normalizeActionInput } from "./services/actionInput.js";
|
|
4
|
+
import { getCanMoveValue } from "./utils/readPropValue.js";
|
|
3
5
|
import { SaveClientService } from "./services/save.js";
|
|
4
6
|
import { RpgGui } from "./Gui/Gui.js";
|
|
5
|
-
import
|
|
7
|
+
import __ce_component from "./components/scenes/canvas.ce.js";
|
|
8
|
+
import __ce_component$1 from "./components/scenes/draw-map.ce.js";
|
|
6
9
|
import { LoadMapToken } from "./services/loadMap.js";
|
|
7
10
|
import { RpgSound } from "./Sound.js";
|
|
8
11
|
import { RpgResource } from "./Resource.js";
|
|
9
|
-
import { load } from "./node_modules/.pnpm/@signe_sync@2.
|
|
12
|
+
import { load } from "./node_modules/.pnpm/@signe_sync@3.1.0_react@19.2.7/node_modules/@signe/sync/dist/index.js";
|
|
10
13
|
import { RpgClientMap } from "./Game/Map.js";
|
|
11
14
|
import { AnimationManager } from "./Game/AnimationManager.js";
|
|
12
15
|
import { GlobalConfigToken } from "./module.js";
|
|
13
16
|
import { PrebuiltComponentAnimations } from "./components/animations/index.js";
|
|
17
|
+
import __ce_component$2 from "./components/dynamics/text.ce.js";
|
|
18
|
+
import __ce_component$3 from "./components/dynamics/bar.ce.js";
|
|
19
|
+
import __ce_component$4 from "./components/dynamics/shape.ce.js";
|
|
20
|
+
import __ce_component$5 from "./components/dynamics/image.ce.js";
|
|
14
21
|
import { NotificationManager } from "./Gui/NotificationManager.js";
|
|
22
|
+
import { normalizeRoomMapId } from "./utils/mapId.js";
|
|
23
|
+
import { ProjectileManager } from "./Game/ProjectileManager.js";
|
|
24
|
+
import { ClientVisualRegistry } from "./Game/ClientVisuals.js";
|
|
25
|
+
import { createClientPointerContext } from "./services/pointerContext.js";
|
|
26
|
+
import { RpgClientInteractions } from "./services/interactions.js";
|
|
27
|
+
import { EventComponentResolverRegistry } from "./Game/EventComponentResolver.js";
|
|
28
|
+
import { RpgClientBuiltinI18n } from "./i18n.js";
|
|
15
29
|
import { Howl, bootstrapCanvas, signal, trigger } from "canvasengine";
|
|
16
|
-
import { Direction, ModulesToken, PredictionController } from "@rpgjs/common";
|
|
30
|
+
import { Direction, ModulesToken, PredictionController, Vector2, getOrCreateI18nService, normalizeLightingState } from "@rpgjs/common";
|
|
17
31
|
import { BehaviorSubject, combineLatest, filter, lastValueFrom, switchMap, take } from "rxjs";
|
|
18
32
|
import * as PIXI from "pixi.js";
|
|
19
33
|
//#region src/RpgClientEngine.ts
|
|
34
|
+
var DEFAULT_DASH_ADDITIONAL_SPEED = 8;
|
|
35
|
+
var DEFAULT_DASH_DURATION_MS = 180;
|
|
36
|
+
var DEFAULT_DASH_COOLDOWN_MS = 450;
|
|
37
|
+
var isDashInput = (input) => typeof input === "object" && input !== null && input.type === "dash";
|
|
38
|
+
var isMoveInput = (input) => typeof input === "object" && input !== null && input.type === "move";
|
|
39
|
+
var resolveMoveDirection = (input) => {
|
|
40
|
+
if (isMoveInput(input)) return input.direction;
|
|
41
|
+
if (typeof input === "string" || typeof input === "number") return input;
|
|
42
|
+
};
|
|
43
|
+
var directionToVector = (direction) => {
|
|
44
|
+
switch (direction) {
|
|
45
|
+
case Direction.Left: return {
|
|
46
|
+
x: -1,
|
|
47
|
+
y: 0
|
|
48
|
+
};
|
|
49
|
+
case Direction.Right: return {
|
|
50
|
+
x: 1,
|
|
51
|
+
y: 0
|
|
52
|
+
};
|
|
53
|
+
case Direction.Up: return {
|
|
54
|
+
x: 0,
|
|
55
|
+
y: -1
|
|
56
|
+
};
|
|
57
|
+
case Direction.Down:
|
|
58
|
+
default: return {
|
|
59
|
+
x: 0,
|
|
60
|
+
y: 1
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
var vectorToDirection = (direction) => {
|
|
65
|
+
if (Math.abs(direction.x) > Math.abs(direction.y)) return direction.x < 0 ? Direction.Left : Direction.Right;
|
|
66
|
+
return direction.y < 0 ? Direction.Up : Direction.Down;
|
|
67
|
+
};
|
|
68
|
+
var normalizeDashInput = (input, fallbackDirection) => {
|
|
69
|
+
const rawDirection = input.direction ?? directionToVector(fallbackDirection);
|
|
70
|
+
const rawX = Number(rawDirection?.x ?? 0);
|
|
71
|
+
const rawY = Number(rawDirection?.y ?? 0);
|
|
72
|
+
const magnitude = Math.hypot(rawX, rawY);
|
|
73
|
+
if (!Number.isFinite(magnitude) || magnitude <= 0) return null;
|
|
74
|
+
const additionalSpeed = typeof input.additionalSpeed === "number" && Number.isFinite(input.additionalSpeed) ? Math.max(0, Math.min(input.additionalSpeed, 64)) : DEFAULT_DASH_ADDITIONAL_SPEED;
|
|
75
|
+
const duration = typeof input.duration === "number" && Number.isFinite(input.duration) ? Math.max(1, Math.min(input.duration, 1e3)) : DEFAULT_DASH_DURATION_MS;
|
|
76
|
+
const cooldown = typeof input.cooldown === "number" && Number.isFinite(input.cooldown) ? Math.max(0, Math.min(input.cooldown, 5e3)) : DEFAULT_DASH_COOLDOWN_MS;
|
|
77
|
+
return {
|
|
78
|
+
type: "dash",
|
|
79
|
+
direction: {
|
|
80
|
+
x: rawX / magnitude,
|
|
81
|
+
y: rawY / magnitude
|
|
82
|
+
},
|
|
83
|
+
additionalSpeed,
|
|
84
|
+
duration,
|
|
85
|
+
cooldown
|
|
86
|
+
};
|
|
87
|
+
};
|
|
20
88
|
var RpgClientEngine = class {
|
|
21
89
|
constructor(context) {
|
|
22
90
|
this.context = context;
|
|
91
|
+
this.sceneMapComponent = __ce_component$1;
|
|
23
92
|
this.stopProcessingInput = false;
|
|
24
93
|
this.width = signal("100%");
|
|
25
94
|
this.height = signal("100%");
|
|
26
95
|
this.spritesheets = /* @__PURE__ */ new Map();
|
|
96
|
+
this.spritesheetPromises = /* @__PURE__ */ new Map();
|
|
27
97
|
this.sounds = /* @__PURE__ */ new Map();
|
|
28
98
|
this.componentAnimations = [];
|
|
99
|
+
this.clientVisuals = new ClientVisualRegistry();
|
|
100
|
+
this.pointer = createClientPointerContext();
|
|
101
|
+
this.interactions = new RpgClientInteractions(this);
|
|
29
102
|
this.particleSettings = { emitters: [] };
|
|
30
103
|
this.playerIdSignal = signal(null);
|
|
31
104
|
this.spriteComponentsBehind = signal([]);
|
|
32
105
|
this.spriteComponentsInFront = signal([]);
|
|
106
|
+
this.spriteComponents = /* @__PURE__ */ new Map();
|
|
107
|
+
this.eventComponentResolvers = new EventComponentResolverRegistry();
|
|
33
108
|
this.cameraFollowTargetId = signal(null);
|
|
109
|
+
this.cameraFollowSmoothMove = false;
|
|
110
|
+
this.cameraFollowRevision = signal(0);
|
|
34
111
|
this.mapShakeTrigger = trigger();
|
|
35
112
|
this.controlsReady = signal(void 0);
|
|
36
113
|
this.gamePause = signal(false);
|
|
37
114
|
this.predictionEnabled = false;
|
|
38
115
|
this.SERVER_CORRECTION_THRESHOLD = 30;
|
|
116
|
+
this.localMovementAuthority = false;
|
|
117
|
+
this.lastLocalMovementInputAt = 0;
|
|
118
|
+
this.LOCAL_MOVEMENT_AUTHORITY_ACK_GRACE_MS = 250;
|
|
39
119
|
this.inputFrameCounter = 0;
|
|
40
120
|
this.pendingPredictionFrames = [];
|
|
41
121
|
this.lastClientPhysicsStepAt = 0;
|
|
42
122
|
this.frameOffset = 0;
|
|
123
|
+
this.latestServerTickAt = 0;
|
|
124
|
+
this.dashLockedUntil = 0;
|
|
43
125
|
this.rtt = 0;
|
|
44
126
|
this.pingInterval = null;
|
|
45
127
|
this.PING_INTERVAL_MS = 5e3;
|
|
@@ -53,12 +135,20 @@ var RpgClientEngine = class {
|
|
|
53
135
|
this.playersReceived$ = new BehaviorSubject(false);
|
|
54
136
|
this.eventsReceived$ = new BehaviorSubject(false);
|
|
55
137
|
this.sceneResetQueued = false;
|
|
138
|
+
this.mapTransitionInProgress = false;
|
|
139
|
+
this.socketListenersInitialized = false;
|
|
140
|
+
this.clientReadyForMapChanges = false;
|
|
141
|
+
this.pendingMapChanges = [];
|
|
56
142
|
this.tickSubscriptions = [];
|
|
143
|
+
this.pendingSyncPackets = [];
|
|
57
144
|
this.notificationManager = new NotificationManager();
|
|
58
145
|
this.webSocket = inject(WebSocketToken);
|
|
59
146
|
this.guiService = inject(RpgGui);
|
|
60
147
|
this.loadMapService = inject(LoadMapToken);
|
|
61
148
|
this.hooks = inject(ModulesToken);
|
|
149
|
+
this.i18nService = getOrCreateI18nService(context);
|
|
150
|
+
this.i18nService.addMessages(RpgClientBuiltinI18n, "rpgjs-client", 0);
|
|
151
|
+
this.projectiles = new ProjectileManager(this.hooks, (projectile) => this.predictProjectileImpact(projectile));
|
|
62
152
|
this.globalConfig = inject(GlobalConfigToken);
|
|
63
153
|
if (!this.globalConfig) this.globalConfig = {};
|
|
64
154
|
if (!this.globalConfig.box) this.globalConfig.box = {
|
|
@@ -72,9 +162,38 @@ var RpgClientEngine = class {
|
|
|
72
162
|
id: "animation",
|
|
73
163
|
component: PrebuiltComponentAnimations.Animation
|
|
74
164
|
});
|
|
165
|
+
this.registerSpriteComponent("rpg:text", __ce_component$2);
|
|
166
|
+
this.registerSpriteComponent("rpg:hpBar", __ce_component$3);
|
|
167
|
+
this.registerSpriteComponent("rpg:spBar", __ce_component$3);
|
|
168
|
+
this.registerSpriteComponent("rpg:bar", __ce_component$3);
|
|
169
|
+
this.registerSpriteComponent("rpg:shape", __ce_component$4);
|
|
170
|
+
this.registerSpriteComponent("rpg:image", __ce_component$5);
|
|
75
171
|
this.predictionEnabled = this.globalConfig?.prediction?.enabled !== false;
|
|
172
|
+
this.localMovementAuthority = this.resolveLocalMovementAuthority();
|
|
76
173
|
this.initializePredictionController();
|
|
77
174
|
}
|
|
175
|
+
resolveLocalMovementAuthority() {
|
|
176
|
+
const predictionConfig = this.globalConfig?.prediction;
|
|
177
|
+
const configured = this.globalConfig?.movementAuthority ?? predictionConfig?.movementAuthority ?? predictionConfig?.authority ?? predictionConfig?.mode;
|
|
178
|
+
if (configured === "server" || configured === "network" || configured === false) return false;
|
|
179
|
+
if (configured === "client" || configured === "local" || configured === true) return true;
|
|
180
|
+
return this.webSocket.mode === "standalone";
|
|
181
|
+
}
|
|
182
|
+
setLocale(locale) {
|
|
183
|
+
this.locale = locale;
|
|
184
|
+
}
|
|
185
|
+
getLocale() {
|
|
186
|
+
return this.locale || this.i18nService.defaultLocale;
|
|
187
|
+
}
|
|
188
|
+
t(key, params) {
|
|
189
|
+
return this.i18nService.t(key, params, this.getLocale());
|
|
190
|
+
}
|
|
191
|
+
i18n() {
|
|
192
|
+
return {
|
|
193
|
+
locale: this.getLocale(),
|
|
194
|
+
t: (key, params) => this.t(key, params)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
78
197
|
/**
|
|
79
198
|
* Assigns a CanvasEngine KeyboardControls instance to the dependency injection context
|
|
80
199
|
*
|
|
@@ -114,18 +233,31 @@ var RpgClientEngine = class {
|
|
|
114
233
|
...currentValues,
|
|
115
234
|
values: new Map([["__default__", controlInstance]])
|
|
116
235
|
};
|
|
117
|
-
this.controlsReady.set(
|
|
236
|
+
this.controlsReady.set(true);
|
|
118
237
|
}
|
|
119
238
|
async start() {
|
|
120
239
|
this.sceneMap = new RpgClientMap();
|
|
121
240
|
this.sceneMap.configureClientPrediction(this.predictionEnabled);
|
|
122
241
|
this.sceneMap.loadPhysic();
|
|
242
|
+
this.resolveSceneMapComponent();
|
|
243
|
+
inject(SaveClientService).initialize();
|
|
244
|
+
this.initListeners();
|
|
245
|
+
this.guiService._initialize();
|
|
246
|
+
try {
|
|
247
|
+
await this.webSocket.connection();
|
|
248
|
+
} catch (error) {
|
|
249
|
+
this.stopPingPong();
|
|
250
|
+
await this.callConnectError(error);
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
123
253
|
this.selector = document.body.querySelector("#rpg");
|
|
124
254
|
const bootstrapOptions = this.globalConfig?.bootstrapCanvasOptions;
|
|
125
|
-
const { app, canvasElement } = await bootstrapCanvas(this.selector,
|
|
255
|
+
const { app, canvasElement } = await bootstrapCanvas(this.selector, __ce_component, bootstrapOptions);
|
|
256
|
+
this.installCanvasResizeGuard(app);
|
|
126
257
|
this.canvasApp = app;
|
|
127
258
|
this.canvasElement = canvasElement;
|
|
128
259
|
this.renderer = app.renderer;
|
|
260
|
+
this.setupPointerTracking();
|
|
129
261
|
this.tick = canvasElement?.propObservables?.context["tick"].observable;
|
|
130
262
|
const inputCheckSubscription = this.tick.subscribe(() => {
|
|
131
263
|
if (Date.now() - this.lastInputTime > 100) {
|
|
@@ -137,6 +269,7 @@ var RpgClientEngine = class {
|
|
|
137
269
|
this.tickSubscriptions.push(inputCheckSubscription);
|
|
138
270
|
this.hooks.callHooks("client-spritesheets-load", this).subscribe();
|
|
139
271
|
this.hooks.callHooks("client-spritesheetResolver-load", this).subscribe();
|
|
272
|
+
this.flushPendingSyncPackets();
|
|
140
273
|
this.hooks.callHooks("client-sounds-load", this).subscribe();
|
|
141
274
|
this.hooks.callHooks("client-soundResolver-load", this).subscribe();
|
|
142
275
|
RpgSound.init(this);
|
|
@@ -144,14 +277,20 @@ var RpgClientEngine = class {
|
|
|
144
277
|
this.hooks.callHooks("client-gui-load", this).subscribe();
|
|
145
278
|
this.hooks.callHooks("client-particles-load", this).subscribe();
|
|
146
279
|
this.hooks.callHooks("client-componentAnimations-load", this).subscribe();
|
|
280
|
+
this.hooks.callHooks("client-clientVisuals-load", this).subscribe();
|
|
281
|
+
this.hooks.callHooks("client-projectiles-load", this).subscribe();
|
|
282
|
+
this.hooks.callHooks("client-interactions-load", this).subscribe();
|
|
147
283
|
this.hooks.callHooks("client-sprite-load", this).subscribe();
|
|
148
284
|
await lastValueFrom(this.hooks.callHooks("client-engine-onStart", this));
|
|
285
|
+
this.clientReadyForMapChanges = true;
|
|
286
|
+
this.flushPendingMapChanges();
|
|
149
287
|
this.resizeHandler = () => {
|
|
150
288
|
this.hooks.callHooks("client-engine-onWindowResize", this).subscribe();
|
|
151
289
|
};
|
|
152
290
|
window.addEventListener("resize", this.resizeHandler);
|
|
153
291
|
const tickSubscription = this.tick.subscribe((tick) => {
|
|
154
292
|
this.stepClientPhysicsTick();
|
|
293
|
+
this.projectiles.step();
|
|
155
294
|
this.flushPendingPredictedStates();
|
|
156
295
|
this.flushPendingMovePath();
|
|
157
296
|
this.hooks.callHooks("client-engine-onStep", this, tick).subscribe();
|
|
@@ -162,12 +301,138 @@ var RpgClientEngine = class {
|
|
|
162
301
|
}
|
|
163
302
|
});
|
|
164
303
|
this.tickSubscriptions.push(tickSubscription);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
304
|
+
this.startPingPong();
|
|
305
|
+
}
|
|
306
|
+
installCanvasResizeGuard(app) {
|
|
307
|
+
if (!app || typeof app.resize !== "function") return;
|
|
308
|
+
const originalResize = app.resize.bind(app);
|
|
309
|
+
app.resize = () => {
|
|
310
|
+
const targetSize = this.readCanvasResizeTargetSize(app);
|
|
311
|
+
const rendererSize = this.readCanvasRendererSize(app);
|
|
312
|
+
if (targetSize && rendererSize && targetSize.width === rendererSize.width && targetSize.height === rendererSize.height) {
|
|
313
|
+
this.cancelCanvasResizeFrame(app);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
originalResize();
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
readCanvasResizeTargetSize(app) {
|
|
320
|
+
const resizeTarget = app?.resizeTo;
|
|
321
|
+
if (!resizeTarget || typeof window === "undefined") return null;
|
|
322
|
+
const rawWidth = resizeTarget === window ? window.innerWidth : resizeTarget.clientWidth;
|
|
323
|
+
const rawHeight = resizeTarget === window ? window.innerHeight : resizeTarget.clientHeight;
|
|
324
|
+
const width = Math.round(Number(rawWidth));
|
|
325
|
+
const height = Math.round(Number(rawHeight));
|
|
326
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width < 0 || height < 0) return null;
|
|
327
|
+
return {
|
|
328
|
+
width,
|
|
329
|
+
height
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
readCanvasRendererSize(app) {
|
|
333
|
+
const screen = app?.renderer?.screen;
|
|
334
|
+
const width = Math.round(Number(screen?.width));
|
|
335
|
+
const height = Math.round(Number(screen?.height));
|
|
336
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) return null;
|
|
337
|
+
return {
|
|
338
|
+
width,
|
|
339
|
+
height
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
cancelCanvasResizeFrame(app) {
|
|
343
|
+
if (typeof app?._cancelResize === "function") app._cancelResize();
|
|
344
|
+
}
|
|
345
|
+
resolveSceneMapComponent() {
|
|
346
|
+
const components = this.hooks.getHookFunctions("client-sceneMap-component");
|
|
347
|
+
const component = components[components.length - 1];
|
|
348
|
+
if (component) this.sceneMapComponent = component;
|
|
349
|
+
}
|
|
350
|
+
setupPointerTracking() {
|
|
351
|
+
const renderer = this.renderer;
|
|
352
|
+
const canvas = renderer?.canvas ?? renderer?.view ?? this.canvasApp?.canvas;
|
|
353
|
+
if (!canvas || typeof canvas.addEventListener !== "function") return;
|
|
354
|
+
this.pointerCanvas = canvas;
|
|
355
|
+
const updatePointer = (event) => {
|
|
356
|
+
const rect = canvas.getBoundingClientRect();
|
|
357
|
+
const screen = {
|
|
358
|
+
x: event.clientX - rect.left,
|
|
359
|
+
y: event.clientY - rect.top
|
|
360
|
+
};
|
|
361
|
+
const viewport = this.findViewportInstance();
|
|
362
|
+
let world = screen;
|
|
363
|
+
if (viewport && typeof viewport.toWorld === "function") {
|
|
364
|
+
const point = viewport.toWorld(screen.x, screen.y);
|
|
365
|
+
world = {
|
|
366
|
+
x: Number(point.x),
|
|
367
|
+
y: Number(point.y)
|
|
368
|
+
};
|
|
369
|
+
} else if (viewport && typeof viewport.toLocal === "function") {
|
|
370
|
+
const point = viewport.toLocal(screen);
|
|
371
|
+
world = {
|
|
372
|
+
x: Number(point.x),
|
|
373
|
+
y: Number(point.y)
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
this.pointer.update(screen, world);
|
|
377
|
+
};
|
|
378
|
+
this.pointerMoveHandler = (event) => {
|
|
379
|
+
updatePointer(event);
|
|
380
|
+
this.interactions.handlePointerMove(event);
|
|
381
|
+
};
|
|
382
|
+
this.pointerUpHandler = (event) => {
|
|
383
|
+
updatePointer(event);
|
|
384
|
+
this.interactions.handlePointerUp(event);
|
|
385
|
+
};
|
|
386
|
+
this.pointerCancelHandler = (event) => {
|
|
387
|
+
updatePointer(event);
|
|
388
|
+
this.interactions.cancelDrag(event);
|
|
389
|
+
};
|
|
390
|
+
canvas.addEventListener("pointermove", this.pointerMoveHandler);
|
|
391
|
+
canvas.addEventListener("pointerdown", this.pointerMoveHandler);
|
|
392
|
+
canvas.addEventListener("pointerup", this.pointerUpHandler);
|
|
393
|
+
canvas.addEventListener("pointercancel", this.pointerCancelHandler);
|
|
394
|
+
canvas.addEventListener("pointerleave", this.pointerCancelHandler);
|
|
395
|
+
}
|
|
396
|
+
updatePointerFromInteractionEvent(event) {
|
|
397
|
+
const global = event?.global ?? event?.data?.global;
|
|
398
|
+
if (!global) {
|
|
399
|
+
this.pointer.updateFromEvent(event);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const screen = {
|
|
403
|
+
x: Number(global.x),
|
|
404
|
+
y: Number(global.y)
|
|
405
|
+
};
|
|
406
|
+
if (!Number.isFinite(screen.x) || !Number.isFinite(screen.y)) {
|
|
407
|
+
this.pointer.updateFromEvent(event);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const viewport = this.findViewportInstance();
|
|
411
|
+
if (viewport && typeof viewport.toWorld === "function") {
|
|
412
|
+
const point = viewport.toWorld(screen.x, screen.y);
|
|
413
|
+
this.pointer.update(screen, {
|
|
414
|
+
x: Number(point.x),
|
|
415
|
+
y: Number(point.y)
|
|
416
|
+
});
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
this.pointer.update(screen);
|
|
420
|
+
}
|
|
421
|
+
findViewportInstance() {
|
|
422
|
+
const find = (node) => {
|
|
423
|
+
if (!node) return void 0;
|
|
424
|
+
if (typeof node?.toWorld === "function" || node?.constructor?.name === "Viewport") return node;
|
|
425
|
+
for (const child of node.children ?? []) {
|
|
426
|
+
const viewport = find(child);
|
|
427
|
+
if (viewport) return viewport;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
return find(this.canvasApp?.stage);
|
|
431
|
+
}
|
|
432
|
+
clearCameraFollowViewportPlugins() {
|
|
433
|
+
const viewport = this.findViewportInstance();
|
|
434
|
+
viewport?.plugins?.remove?.("animate");
|
|
435
|
+
viewport?.plugins?.remove?.("follow");
|
|
171
436
|
}
|
|
172
437
|
prepareSyncPayload(data) {
|
|
173
438
|
const payload = { ...data ?? {} };
|
|
@@ -175,7 +440,8 @@ var RpgClientEngine = class {
|
|
|
175
440
|
delete payload.timestamp;
|
|
176
441
|
const myId = this.playerIdSignal();
|
|
177
442
|
const players = payload.players;
|
|
178
|
-
|
|
443
|
+
const localPatch = myId && players ? players[myId] : void 0;
|
|
444
|
+
if (this.shouldPreserveLocalPlayerPosition(localPatch) && myId && players && players[myId]) {
|
|
179
445
|
const localPatch = { ...players[myId] };
|
|
180
446
|
delete localPatch.x;
|
|
181
447
|
delete localPatch.y;
|
|
@@ -188,6 +454,18 @@ var RpgClientEngine = class {
|
|
|
188
454
|
}
|
|
189
455
|
return payload;
|
|
190
456
|
}
|
|
457
|
+
shouldPreserveLocalPlayerPosition(localPatch) {
|
|
458
|
+
if (!localPatch) return false;
|
|
459
|
+
if (this.predictionEnabled && !!this.prediction?.hasPendingInputs()) return true;
|
|
460
|
+
return this.shouldKeepLocalPlayerMovement();
|
|
461
|
+
}
|
|
462
|
+
shouldKeepLocalPlayerMovement() {
|
|
463
|
+
if (!this.localMovementAuthority || this.mapTransitionInProgress) return false;
|
|
464
|
+
const myId = this.playerIdSignal();
|
|
465
|
+
if (!(myId ? this.sceneMap?.players?.()?.[myId] : void 0)) return false;
|
|
466
|
+
if (this.prediction?.hasPendingInputs()) return true;
|
|
467
|
+
return Date.now() - this.lastLocalMovementInputAt <= this.LOCAL_MOVEMENT_AUTHORITY_ACK_GRACE_MS;
|
|
468
|
+
}
|
|
191
469
|
normalizeAckWithSyncState(ack, syncData) {
|
|
192
470
|
const myId = this.playerIdSignal();
|
|
193
471
|
if (!myId) return ack;
|
|
@@ -201,43 +479,30 @@ var RpgClientEngine = class {
|
|
|
201
479
|
};
|
|
202
480
|
}
|
|
203
481
|
initListeners() {
|
|
482
|
+
if (this.socketListenersInitialized) return;
|
|
483
|
+
this.socketListenersInitialized = true;
|
|
204
484
|
this.webSocket.on("sync", (data) => {
|
|
205
|
-
if (
|
|
206
|
-
this.
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
if (this.sceneResetQueued) {
|
|
210
|
-
this.sceneMap.reset();
|
|
211
|
-
this.sceneMap.loadPhysic();
|
|
212
|
-
this.sceneResetQueued = false;
|
|
213
|
-
}
|
|
214
|
-
this.hooks.callHooks("client-sceneMap-onChanges", this.sceneMap, { partial: data }).subscribe();
|
|
215
|
-
const ack = data?.ack;
|
|
216
|
-
const normalizedAck = ack && typeof ack.frame === "number" ? this.normalizeAckWithSyncState(ack, data) : void 0;
|
|
217
|
-
const payload = this.prepareSyncPayload(data);
|
|
218
|
-
load(this.sceneMap, payload, true);
|
|
219
|
-
if (normalizedAck) this.applyServerAck(normalizedAck);
|
|
220
|
-
for (const playerId in payload.players ?? {}) {
|
|
221
|
-
const player = payload.players[playerId];
|
|
222
|
-
if (!player._param) continue;
|
|
223
|
-
for (const param in player._param) this.sceneMap.players()[playerId]._param()[param] = player._param[param];
|
|
485
|
+
if (!this.tick) {
|
|
486
|
+
this.pendingSyncPackets.push(data);
|
|
487
|
+
return;
|
|
224
488
|
}
|
|
225
|
-
|
|
226
|
-
if (players && Object.keys(players).length > 0) this.playersReceived$.next(true);
|
|
227
|
-
if ((payload.events || this.sceneMap.events()) !== void 0) this.eventsReceived$.next(true);
|
|
489
|
+
this.applySyncPacket(data);
|
|
228
490
|
});
|
|
229
491
|
this.webSocket.on("pong", (data) => {
|
|
230
|
-
|
|
492
|
+
const now = Date.now();
|
|
493
|
+
this.rtt = now - data.clientTime;
|
|
231
494
|
const estimatedTicksInFlight = Math.floor(this.rtt / 2 / (1e3 / 60));
|
|
232
495
|
const estimatedServerTickNow = data.serverTick + estimatedTicksInFlight;
|
|
496
|
+
this.updateServerTickEstimate(estimatedServerTickNow, now);
|
|
233
497
|
if (this.inputFrameCounter > 0) this.frameOffset = estimatedServerTickNow - data.clientFrame;
|
|
234
498
|
console.debug(`[Ping/Pong] RTT: ${this.rtt}ms, ServerTick: ${data.serverTick}, FrameOffset: ${this.frameOffset}`);
|
|
235
499
|
});
|
|
236
500
|
this.webSocket.on("changeMap", (data) => {
|
|
237
|
-
this.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
501
|
+
if (!this.clientReadyForMapChanges) {
|
|
502
|
+
this.pendingMapChanges.push(data);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
this.handleChangeMap(data);
|
|
241
506
|
});
|
|
242
507
|
this.webSocket.on("showComponentAnimation", (data) => {
|
|
243
508
|
const { params, object, position, id } = data;
|
|
@@ -245,14 +510,42 @@ var RpgClientEngine = class {
|
|
|
245
510
|
const player = object ? this.sceneMap.getObjectById(object) : void 0;
|
|
246
511
|
this.getComponentAnimation(id).displayEffect(params, player || position);
|
|
247
512
|
});
|
|
513
|
+
this.webSocket.on("clientVisual", (data) => {
|
|
514
|
+
this.playClientVisual(data);
|
|
515
|
+
});
|
|
516
|
+
this.webSocket.on("projectile:spawnBatch", (data) => {
|
|
517
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
518
|
+
this.projectiles.spawnBatch(data?.projectiles ?? [], {
|
|
519
|
+
mapId: data?.mapId,
|
|
520
|
+
currentServerTick: this.estimateServerTick(),
|
|
521
|
+
tickDurationMs: this.getPhysicsTickDurationMs()
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
this.webSocket.on("projectile:impactBatch", (data) => {
|
|
525
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
526
|
+
this.projectiles.impactBatch(data?.impacts ?? [], { mapId: data?.mapId });
|
|
527
|
+
});
|
|
528
|
+
this.webSocket.on("projectile:destroyBatch", (data) => {
|
|
529
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
530
|
+
this.projectiles.destroyBatch(data?.projectiles ?? [], { mapId: data?.mapId });
|
|
531
|
+
});
|
|
532
|
+
this.webSocket.on("projectile:clear", (data) => {
|
|
533
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
534
|
+
this.projectiles.clear();
|
|
535
|
+
});
|
|
248
536
|
this.webSocket.on("notification", (data) => {
|
|
249
537
|
this.notificationManager.add(data);
|
|
250
538
|
});
|
|
251
539
|
this.webSocket.on("setAnimation", (data) => {
|
|
252
|
-
const { animationName, nbTimes, object, graphic } = data;
|
|
253
|
-
const player = this.sceneMap.getObjectById(object);
|
|
254
|
-
if (
|
|
255
|
-
|
|
540
|
+
const { animationName, nbTimes, object, graphic, restoreAnimationName, restoreGraphics } = data;
|
|
541
|
+
const player = object ? this.sceneMap.getObjectById(object) : void 0;
|
|
542
|
+
if (!player) return;
|
|
543
|
+
const restoreOptions = {
|
|
544
|
+
restoreAnimationName,
|
|
545
|
+
restoreGraphics
|
|
546
|
+
};
|
|
547
|
+
if (graphic !== void 0) player.setAnimation(animationName, graphic, nbTimes, restoreOptions);
|
|
548
|
+
else player.setAnimation(animationName, nbTimes, restoreOptions);
|
|
256
549
|
});
|
|
257
550
|
this.webSocket.on("playSound", (data) => {
|
|
258
551
|
const { soundId, volume, loop } = data;
|
|
@@ -314,6 +607,10 @@ var RpgClientEngine = class {
|
|
|
314
607
|
seed: raw.seed
|
|
315
608
|
});
|
|
316
609
|
});
|
|
610
|
+
this.webSocket.on("lightingState", (data) => {
|
|
611
|
+
const raw = data && typeof data === "object" && "value" in data ? data.value : data;
|
|
612
|
+
this.sceneMap.lightingState.set(normalizeLightingState(raw));
|
|
613
|
+
});
|
|
317
614
|
this.webSocket.on("open", () => {
|
|
318
615
|
this.hooks.callHooks("client-engine-onConnected", this, this.socket).subscribe();
|
|
319
616
|
this.startPingPong();
|
|
@@ -323,9 +620,82 @@ var RpgClientEngine = class {
|
|
|
323
620
|
this.stopPingPong();
|
|
324
621
|
});
|
|
325
622
|
this.webSocket.on("error", (error) => {
|
|
326
|
-
this.
|
|
623
|
+
this.callConnectError(error);
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
beginMapTransfer(nextMapId) {
|
|
627
|
+
this.mapTransitionInProgress = true;
|
|
628
|
+
this.currentMapRoomId = nextMapId;
|
|
629
|
+
this.sceneResetQueued = false;
|
|
630
|
+
this.clearClientPredictionStates();
|
|
631
|
+
this.sceneMap.weatherState.set(null);
|
|
632
|
+
this.sceneMap.lightingState.set(null);
|
|
633
|
+
this.sceneMap.clearLightSpots();
|
|
634
|
+
this.clearComponentAnimations();
|
|
635
|
+
this.projectiles.setMapId(nextMapId);
|
|
636
|
+
this.resetCameraFollow(false);
|
|
637
|
+
this.sceneMap.reset();
|
|
638
|
+
this.sceneMap.loadPhysic();
|
|
639
|
+
}
|
|
640
|
+
clearComponentAnimations() {
|
|
641
|
+
this.componentAnimations.forEach((componentAnimation) => {
|
|
642
|
+
componentAnimation.instance?.clear?.();
|
|
327
643
|
});
|
|
328
644
|
}
|
|
645
|
+
shouldProcessProjectilePacket(data) {
|
|
646
|
+
if (this.mapTransitionInProgress) return false;
|
|
647
|
+
const packetMapId = normalizeRoomMapId(typeof data?.mapId === "string" ? data.mapId : void 0);
|
|
648
|
+
const currentMapId = normalizeRoomMapId(this.currentMapRoomId);
|
|
649
|
+
return !packetMapId || !currentMapId || packetMapId === currentMapId;
|
|
650
|
+
}
|
|
651
|
+
async callConnectError(error) {
|
|
652
|
+
await lastValueFrom(this.hooks.callHooks("client-engine-onConnectError", this, error, this.socket));
|
|
653
|
+
}
|
|
654
|
+
flushPendingSyncPackets() {
|
|
655
|
+
const packets = this.pendingSyncPackets;
|
|
656
|
+
this.pendingSyncPackets = [];
|
|
657
|
+
packets.forEach((packet) => this.applySyncPacket(packet));
|
|
658
|
+
}
|
|
659
|
+
flushPendingMapChanges() {
|
|
660
|
+
const packets = this.pendingMapChanges;
|
|
661
|
+
this.pendingMapChanges = [];
|
|
662
|
+
packets.forEach((packet) => this.handleChangeMap(packet));
|
|
663
|
+
}
|
|
664
|
+
handleChangeMap(data) {
|
|
665
|
+
const nextMapId = typeof data?.mapId === "string" ? data.mapId : void 0;
|
|
666
|
+
this.beginMapTransfer(nextMapId);
|
|
667
|
+
const transferToken = typeof data?.transferToken === "string" ? data.transferToken : void 0;
|
|
668
|
+
this.loadScene(data.mapId, transferToken);
|
|
669
|
+
}
|
|
670
|
+
applySyncPacket(data) {
|
|
671
|
+
if (data.pId) {
|
|
672
|
+
this.playerIdSignal.set(data.pId);
|
|
673
|
+
this.playerIdReceived$.next(true);
|
|
674
|
+
}
|
|
675
|
+
if (this.sceneResetQueued) {
|
|
676
|
+
const weatherState = this.sceneMap.weatherState();
|
|
677
|
+
const lightingState = this.sceneMap.lightingState();
|
|
678
|
+
this.sceneMap.reset();
|
|
679
|
+
this.sceneMap.weatherState.set(weatherState);
|
|
680
|
+
this.sceneMap.lightingState.set(lightingState);
|
|
681
|
+
this.sceneMap.loadPhysic();
|
|
682
|
+
this.sceneResetQueued = false;
|
|
683
|
+
}
|
|
684
|
+
this.hooks.callHooks("client-sceneMap-onChanges", this.sceneMap, { partial: data }).subscribe();
|
|
685
|
+
const ack = data?.ack;
|
|
686
|
+
const normalizedAck = ack && typeof ack.frame === "number" ? this.normalizeAckWithSyncState(ack, data) : void 0;
|
|
687
|
+
const payload = this.prepareSyncPayload(data);
|
|
688
|
+
load(this.sceneMap, payload, true);
|
|
689
|
+
if (normalizedAck) this.applyServerAck(normalizedAck);
|
|
690
|
+
for (const playerId in payload.players ?? {}) {
|
|
691
|
+
const player = payload.players[playerId];
|
|
692
|
+
if (!player._param) continue;
|
|
693
|
+
for (const param in player._param) this.sceneMap.players()[playerId]._param()[param] = player._param[param];
|
|
694
|
+
}
|
|
695
|
+
const players = payload.players || this.sceneMap.players();
|
|
696
|
+
if (players && Object.keys(players).length > 0) this.playersReceived$.next(true);
|
|
697
|
+
if ((payload.events || this.sceneMap.events()) !== void 0) this.eventsReceived$.next(true);
|
|
698
|
+
}
|
|
329
699
|
/**
|
|
330
700
|
* Start periodic ping/pong for client-server synchronization
|
|
331
701
|
*
|
|
@@ -402,18 +772,25 @@ var RpgClientEngine = class {
|
|
|
402
772
|
room: mapId,
|
|
403
773
|
query: transferToken ? { transferToken } : void 0
|
|
404
774
|
});
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
this.
|
|
409
|
-
|
|
775
|
+
try {
|
|
776
|
+
await this.webSocket.reconnect();
|
|
777
|
+
} catch (error) {
|
|
778
|
+
this.mapTransitionInProgress = false;
|
|
779
|
+
this.stopPingPong();
|
|
780
|
+
await this.callConnectError(error);
|
|
781
|
+
throw error;
|
|
782
|
+
}
|
|
410
783
|
const res = await this.loadMapService.load(mapId);
|
|
784
|
+
const loadedLighting = typeof res?.lighting !== "undefined" ? res.lighting : res?.data?.lighting;
|
|
785
|
+
if (typeof loadedLighting !== "undefined") this.sceneMap.lightingState.set(normalizeLightingState(loadedLighting));
|
|
411
786
|
this.sceneMap.data.set(res);
|
|
412
787
|
if (this.playerIdSignal()) this.playerIdReceived$.next(true);
|
|
413
788
|
const players = this.sceneMap.players();
|
|
414
789
|
if (players && Object.keys(players).length > 0) this.playersReceived$.next(true);
|
|
415
790
|
if (this.sceneMap.events() !== void 0) this.eventsReceived$.next(true);
|
|
416
791
|
this.mapLoadCompleted$.next(true);
|
|
792
|
+
this.currentMapRoomId = mapId;
|
|
793
|
+
this.mapTransitionInProgress = false;
|
|
417
794
|
this.sceneMap.configureClientPrediction(this.predictionEnabled);
|
|
418
795
|
this.sceneMap.loadPhysic();
|
|
419
796
|
}
|
|
@@ -458,7 +835,7 @@ var RpgClientEngine = class {
|
|
|
458
835
|
* If not found and a resolver is set, it calls the resolver to create the spritesheet.
|
|
459
836
|
* The resolved spritesheet is automatically cached for future use.
|
|
460
837
|
*
|
|
461
|
-
* @param id - The spritesheet ID to retrieve
|
|
838
|
+
* @param id - The spritesheet ID or legacy tile ID to retrieve
|
|
462
839
|
* @returns The spritesheet if found or created, or undefined if not found and no resolver
|
|
463
840
|
* @returns Promise<any> if the resolver is asynchronous
|
|
464
841
|
*
|
|
@@ -474,12 +851,20 @@ var RpgClientEngine = class {
|
|
|
474
851
|
getSpriteSheet(id) {
|
|
475
852
|
if (this.spritesheets.has(id)) return this.spritesheets.get(id);
|
|
476
853
|
if (this.spritesheetResolver) {
|
|
854
|
+
if (this.spritesheetPromises.has(id)) return this.spritesheetPromises.get(id);
|
|
477
855
|
const result = this.spritesheetResolver(id);
|
|
478
|
-
if (result instanceof Promise)
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
856
|
+
if (result instanceof Promise) {
|
|
857
|
+
const promise = result.then((spritesheet) => {
|
|
858
|
+
if (spritesheet) this.spritesheets.set(id, spritesheet);
|
|
859
|
+
this.spritesheetPromises.delete(id);
|
|
860
|
+
return spritesheet;
|
|
861
|
+
}).catch((error) => {
|
|
862
|
+
this.spritesheetPromises.delete(id);
|
|
863
|
+
throw error;
|
|
864
|
+
});
|
|
865
|
+
this.spritesheetPromises.set(id, promise);
|
|
866
|
+
return promise;
|
|
867
|
+
} else {
|
|
483
868
|
if (result) this.spritesheets.set(id, result);
|
|
484
869
|
return result;
|
|
485
870
|
}
|
|
@@ -682,19 +1067,22 @@ var RpgClientEngine = class {
|
|
|
682
1067
|
* Set the camera to follow a specific sprite
|
|
683
1068
|
*
|
|
684
1069
|
* This method changes which sprite the camera viewport should follow.
|
|
685
|
-
* The camera
|
|
1070
|
+
* The camera can smoothly animate to the target sprite before continuous follow starts.
|
|
686
1071
|
*
|
|
687
1072
|
* ## Design
|
|
688
1073
|
*
|
|
689
1074
|
* The camera follow target is stored in a signal that is read by sprite components.
|
|
690
1075
|
* Each sprite checks if it should be followed by comparing its ID with the target ID.
|
|
691
|
-
* When smoothMove options are provided, the
|
|
692
|
-
* viewport system.
|
|
1076
|
+
* When smoothMove options are provided, the transition is handled by pixi-viewport's
|
|
1077
|
+
* animation plugin, then continuous follow is handled by CanvasEngine's viewport system.
|
|
693
1078
|
*
|
|
694
1079
|
* @param targetId - The ID of the sprite to follow. Set to null to follow the current player
|
|
695
1080
|
* @param smoothMove - Animation options. Can be a boolean (default: true) or an object with time and ease
|
|
696
1081
|
* @param smoothMove.time - Duration of the animation in milliseconds (optional)
|
|
697
1082
|
* @param smoothMove.ease - Easing function name from https://easings.net (optional)
|
|
1083
|
+
* @param smoothMove.speed - Continuous follow speed after the transition (optional)
|
|
1084
|
+
* @param smoothMove.acceleration - Continuous follow acceleration after the transition (optional)
|
|
1085
|
+
* @param smoothMove.radius - Center radius where the target can move without moving the viewport (optional)
|
|
698
1086
|
*
|
|
699
1087
|
* @example
|
|
700
1088
|
* ```ts
|
|
@@ -715,8 +1103,16 @@ var RpgClientEngine = class {
|
|
|
715
1103
|
* ```
|
|
716
1104
|
*/
|
|
717
1105
|
setCameraFollow(targetId, smoothMove) {
|
|
1106
|
+
this.clearCameraFollowViewportPlugins();
|
|
1107
|
+
this.cameraFollowSmoothMove = smoothMove ?? true;
|
|
718
1108
|
this.cameraFollowTargetId.set(targetId);
|
|
719
|
-
|
|
1109
|
+
this.cameraFollowRevision.set(this.cameraFollowRevision() + 1);
|
|
1110
|
+
}
|
|
1111
|
+
resetCameraFollow(smoothMove = false) {
|
|
1112
|
+
this.clearCameraFollowViewportPlugins();
|
|
1113
|
+
this.cameraFollowSmoothMove = smoothMove;
|
|
1114
|
+
this.cameraFollowTargetId.set(null);
|
|
1115
|
+
this.cameraFollowRevision.set(this.cameraFollowRevision() + 1);
|
|
720
1116
|
}
|
|
721
1117
|
addParticle(particle) {
|
|
722
1118
|
this.particleSettings.emitters.push(particle);
|
|
@@ -807,6 +1203,95 @@ var RpgClientEngine = class {
|
|
|
807
1203
|
return component;
|
|
808
1204
|
}
|
|
809
1205
|
/**
|
|
1206
|
+
* Register a reusable sprite component that can be addressed by the server.
|
|
1207
|
+
*
|
|
1208
|
+
* Server-side component definitions only carry the component id and
|
|
1209
|
+
* serializable props. The client registry maps that id to the CanvasEngine
|
|
1210
|
+
* component that performs the actual rendering.
|
|
1211
|
+
*
|
|
1212
|
+
* @param id - Stable component id used by server component definitions
|
|
1213
|
+
* @param component - CanvasEngine component to render for this id
|
|
1214
|
+
* @returns The registered component
|
|
1215
|
+
*
|
|
1216
|
+
* @example
|
|
1217
|
+
* ```ts
|
|
1218
|
+
* engine.registerSpriteComponent('guildBadge', GuildBadgeComponent);
|
|
1219
|
+
* ```
|
|
1220
|
+
*/
|
|
1221
|
+
registerSpriteComponent(id, component) {
|
|
1222
|
+
this.spriteComponents.set(id, component);
|
|
1223
|
+
return component;
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Get a reusable sprite component by id.
|
|
1227
|
+
*
|
|
1228
|
+
* @param id - Component id registered on the client
|
|
1229
|
+
* @returns The CanvasEngine component, or undefined when missing
|
|
1230
|
+
*/
|
|
1231
|
+
getSpriteComponent(id) {
|
|
1232
|
+
return this.spriteComponents.get(id);
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Register a custom event component resolver.
|
|
1236
|
+
*
|
|
1237
|
+
* The last resolver returning a component wins. This lets later modules
|
|
1238
|
+
* override earlier defaults without replacing the whole map scene.
|
|
1239
|
+
*
|
|
1240
|
+
* @param resolver - Function receiving the synced event object
|
|
1241
|
+
* @returns The registered resolver
|
|
1242
|
+
*/
|
|
1243
|
+
addEventComponentResolver(resolver) {
|
|
1244
|
+
return this.eventComponentResolvers.add(resolver);
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Resolve the custom CanvasEngine component for an event, if any.
|
|
1248
|
+
*
|
|
1249
|
+
* @param event - Synced client event object
|
|
1250
|
+
* @returns The component/config returned by the last matching resolver
|
|
1251
|
+
*/
|
|
1252
|
+
resolveEventComponent(event) {
|
|
1253
|
+
return this.eventComponentResolvers.resolve(event);
|
|
1254
|
+
}
|
|
1255
|
+
registerProjectileComponent(type, component) {
|
|
1256
|
+
return this.projectiles.register(type, component);
|
|
1257
|
+
}
|
|
1258
|
+
getProjectileComponent(type) {
|
|
1259
|
+
return this.projectiles.get(type);
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Register a named client visual macro.
|
|
1263
|
+
*
|
|
1264
|
+
* Client visuals are small client-side functions that group existing visual
|
|
1265
|
+
* primitives such as flash, sound, component animations, sprite animation, or
|
|
1266
|
+
* map shake. The server sends only the visual name and a serializable payload.
|
|
1267
|
+
*
|
|
1268
|
+
* @param name - Stable visual name sent by the server
|
|
1269
|
+
* @param handler - Client-side visual handler
|
|
1270
|
+
* @returns The registered handler
|
|
1271
|
+
*/
|
|
1272
|
+
registerClientVisual(name, handler) {
|
|
1273
|
+
return this.clientVisuals.register(name, handler);
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Register several named client visual macros.
|
|
1277
|
+
*
|
|
1278
|
+
* @param visuals - Map of visual names to client-side handlers
|
|
1279
|
+
*/
|
|
1280
|
+
registerClientVisuals(visuals) {
|
|
1281
|
+
this.clientVisuals.registerMany(visuals);
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Play a registered client visual locally.
|
|
1285
|
+
*
|
|
1286
|
+
* This is also used by the websocket listener when the server calls
|
|
1287
|
+
* `player.clientVisual()` or `map.clientVisual()`.
|
|
1288
|
+
*
|
|
1289
|
+
* @param packet - Visual name and serializable payload
|
|
1290
|
+
*/
|
|
1291
|
+
playClientVisual(packet) {
|
|
1292
|
+
return this.clientVisuals.play(packet, this);
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
810
1295
|
* Add a component animation to the engine
|
|
811
1296
|
*
|
|
812
1297
|
* Component animations are temporary visual effects that can be displayed
|
|
@@ -882,18 +1367,47 @@ var RpgClientEngine = class {
|
|
|
882
1367
|
* duration: 1000,
|
|
883
1368
|
* onFinish: () => console.log('Fade complete')
|
|
884
1369
|
* });
|
|
1370
|
+
*
|
|
1371
|
+
* // Wait until the transition component calls onFinish
|
|
1372
|
+
* await engine.startTransition('fade', { duration: 1000 });
|
|
885
1373
|
* ```
|
|
886
1374
|
*/
|
|
887
1375
|
startTransition(id, props = {}) {
|
|
888
1376
|
if (!this.guiService.exists(id)) throw new Error(`Transition with id ${id} not found. Make sure to add it using engine.addTransition() or in your module's transitions property.`);
|
|
889
|
-
|
|
1377
|
+
return new Promise((resolve) => {
|
|
1378
|
+
let finished = false;
|
|
1379
|
+
const finish = (data) => {
|
|
1380
|
+
if (finished) return;
|
|
1381
|
+
finished = true;
|
|
1382
|
+
props?.onFinish?.(data);
|
|
1383
|
+
resolve();
|
|
1384
|
+
};
|
|
1385
|
+
this.guiService.display(id, {
|
|
1386
|
+
...props,
|
|
1387
|
+
onFinish: finish
|
|
1388
|
+
});
|
|
1389
|
+
});
|
|
890
1390
|
}
|
|
891
1391
|
async processInput({ input }) {
|
|
1392
|
+
if (this.stopProcessingInput) return;
|
|
1393
|
+
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
1394
|
+
if (!(!currentPlayer || getCanMoveValue(currentPlayer))) {
|
|
1395
|
+
this.interruptCurrentPlayerMovement(currentPlayer);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
892
1398
|
const timestamp = Date.now();
|
|
1399
|
+
const movementInput = isDashInput(input) ? normalizeDashInput(input, currentPlayer?.direction?.()) : input;
|
|
1400
|
+
if (!movementInput) return;
|
|
1401
|
+
if (isDashInput(movementInput)) {
|
|
1402
|
+
const cooldown = movementInput.cooldown ?? DEFAULT_DASH_COOLDOWN_MS;
|
|
1403
|
+
if (timestamp < this.dashLockedUntil) return;
|
|
1404
|
+
this.dashLockedUntil = timestamp + cooldown;
|
|
1405
|
+
}
|
|
1406
|
+
this.lastLocalMovementInputAt = timestamp;
|
|
893
1407
|
let frame;
|
|
894
1408
|
let tick;
|
|
895
1409
|
if (this.predictionEnabled && this.prediction) {
|
|
896
|
-
const meta = this.prediction.recordInput(
|
|
1410
|
+
const meta = this.prediction.recordInput(movementInput, timestamp);
|
|
897
1411
|
frame = meta.frame;
|
|
898
1412
|
tick = meta.tick;
|
|
899
1413
|
} else {
|
|
@@ -902,29 +1416,38 @@ var RpgClientEngine = class {
|
|
|
902
1416
|
}
|
|
903
1417
|
this.inputFrameCounter = frame;
|
|
904
1418
|
this.hooks.callHooks("client-engine-onInput", this, {
|
|
905
|
-
input,
|
|
1419
|
+
input: movementInput,
|
|
906
1420
|
playerId: this.playerId
|
|
907
1421
|
}).subscribe();
|
|
908
|
-
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
909
1422
|
const bodyReady = this.ensureCurrentPlayerBody();
|
|
910
1423
|
if (currentPlayer && bodyReady) {
|
|
911
|
-
|
|
912
|
-
this.sceneMap.moveBody(currentPlayer, input);
|
|
1424
|
+
this.applyPredictedMovementInput(currentPlayer, movementInput);
|
|
913
1425
|
if (this.predictionEnabled && this.prediction) {
|
|
914
1426
|
this.pendingPredictionFrames.push(frame);
|
|
915
1427
|
if (this.pendingPredictionFrames.length > 240) this.pendingPredictionFrames = this.pendingPredictionFrames.slice(-240);
|
|
916
1428
|
}
|
|
917
1429
|
}
|
|
918
|
-
this.emitMovePacket(
|
|
919
|
-
this.lastInputTime = Date.now();
|
|
1430
|
+
this.emitMovePacket(movementInput, frame, tick, timestamp, true);
|
|
1431
|
+
this.lastInputTime = isDashInput(movementInput) ? Date.now() + (movementInput.duration ?? DEFAULT_DASH_DURATION_MS) : Date.now();
|
|
920
1432
|
}
|
|
921
|
-
|
|
1433
|
+
async processDash(input = {}) {
|
|
1434
|
+
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
1435
|
+
const dashInput = normalizeDashInput(input, typeof currentPlayer?.direction === "function" ? currentPlayer.direction() : currentPlayer?.direction);
|
|
1436
|
+
if (!dashInput) return;
|
|
1437
|
+
await this.processInput({ input: dashInput });
|
|
1438
|
+
}
|
|
1439
|
+
processAction(action, data) {
|
|
922
1440
|
if (this.stopProcessingInput) return;
|
|
1441
|
+
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
1442
|
+
if (!(!currentPlayer || getCanMoveValue(currentPlayer))) return;
|
|
1443
|
+
const payload = normalizeActionInput(action, data);
|
|
923
1444
|
this.hooks.callHooks("client-engine-onInput", this, {
|
|
924
|
-
input:
|
|
1445
|
+
input: payload.action,
|
|
1446
|
+
action: payload.action,
|
|
1447
|
+
data: payload.data,
|
|
925
1448
|
playerId: this.playerId
|
|
926
1449
|
}).subscribe();
|
|
927
|
-
this.webSocket.emit("action",
|
|
1450
|
+
this.webSocket.emit("action", payload);
|
|
928
1451
|
}
|
|
929
1452
|
get PIXI() {
|
|
930
1453
|
return PIXI;
|
|
@@ -938,9 +1461,43 @@ var RpgClientEngine = class {
|
|
|
938
1461
|
get scene() {
|
|
939
1462
|
return this.sceneMap;
|
|
940
1463
|
}
|
|
1464
|
+
getObjectById(id) {
|
|
1465
|
+
return this.sceneMap?.getObjectById(id);
|
|
1466
|
+
}
|
|
941
1467
|
getPhysicsTick() {
|
|
942
1468
|
return this.sceneMap?.getTick?.() ?? 0;
|
|
943
1469
|
}
|
|
1470
|
+
getPhysicsTickDurationMs() {
|
|
1471
|
+
const timeStep = this.sceneMap?.physic?.getWorld?.()?.getTimeStep?.();
|
|
1472
|
+
return typeof timeStep === "number" && Number.isFinite(timeStep) && timeStep > 0 ? timeStep * 1e3 : 1e3 / 60;
|
|
1473
|
+
}
|
|
1474
|
+
updateServerTickEstimate(serverTick, now = Date.now()) {
|
|
1475
|
+
if (typeof serverTick !== "number" || !Number.isFinite(serverTick)) return;
|
|
1476
|
+
this.latestServerTick = serverTick;
|
|
1477
|
+
this.latestServerTickAt = now;
|
|
1478
|
+
}
|
|
1479
|
+
estimateServerTick(now = Date.now()) {
|
|
1480
|
+
if (typeof this.latestServerTick !== "number" || this.latestServerTickAt <= 0) return;
|
|
1481
|
+
const elapsedTicks = Math.max(0, (now - this.latestServerTickAt) / this.getPhysicsTickDurationMs());
|
|
1482
|
+
return this.latestServerTick + elapsedTicks;
|
|
1483
|
+
}
|
|
1484
|
+
predictProjectileImpact(projectile) {
|
|
1485
|
+
if (projectile.predictImpact === false) return null;
|
|
1486
|
+
const sceneMap = this.sceneMap;
|
|
1487
|
+
if (!sceneMap?.physic || !Number.isFinite(projectile.range) || projectile.range <= 0) return null;
|
|
1488
|
+
const origin = projectile.origin;
|
|
1489
|
+
const direction = projectile.direction;
|
|
1490
|
+
if (!origin || !direction || !Number.isFinite(origin.x) || !Number.isFinite(origin.y) || !Number.isFinite(direction.x) || !Number.isFinite(direction.y) || direction.x === 0 && direction.y === 0) return null;
|
|
1491
|
+
const hit = sceneMap.physic.raycast(new Vector2(origin.x, origin.y), new Vector2(direction.x, direction.y), projectile.range, projectile.collisionMask, (entity) => projectile.ignoreOwner === false || !projectile.ownerId || entity.uuid !== projectile.ownerId);
|
|
1492
|
+
if (!hit) return null;
|
|
1493
|
+
return {
|
|
1494
|
+
id: projectile.id,
|
|
1495
|
+
targetId: hit.entity.uuid,
|
|
1496
|
+
x: hit.point.x,
|
|
1497
|
+
y: hit.point.y,
|
|
1498
|
+
distance: hit.distance
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
944
1501
|
ensureCurrentPlayerBody() {
|
|
945
1502
|
const player = this.sceneMap?.getCurrentPlayer();
|
|
946
1503
|
const myId = this.playerIdSignal();
|
|
@@ -986,7 +1543,7 @@ var RpgClientEngine = class {
|
|
|
986
1543
|
input: entry.direction,
|
|
987
1544
|
x: state.x,
|
|
988
1545
|
y: state.y,
|
|
989
|
-
direction: state.direction ?? entry.direction
|
|
1546
|
+
direction: state.direction ?? resolveMoveDirection(entry.direction)
|
|
990
1547
|
});
|
|
991
1548
|
}
|
|
992
1549
|
if (trajectory.length > this.MAX_MOVE_TRAJECTORY_POINTS) return trajectory.slice(-this.MAX_MOVE_TRAJECTORY_POINTS);
|
|
@@ -1008,6 +1565,11 @@ var RpgClientEngine = class {
|
|
|
1008
1565
|
}
|
|
1009
1566
|
flushPendingMovePath() {
|
|
1010
1567
|
if (!this.predictionEnabled || !this.prediction) return;
|
|
1568
|
+
const player = this.sceneMap?.getCurrentPlayer?.();
|
|
1569
|
+
if (player && !getCanMoveValue(player)) {
|
|
1570
|
+
this.interruptCurrentPlayerMovement(player);
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1011
1573
|
const pendingInputs = this.prediction.getPendingInputs();
|
|
1012
1574
|
if (pendingInputs.length === 0) return;
|
|
1013
1575
|
const latest = pendingInputs[pendingInputs.length - 1];
|
|
@@ -1016,6 +1578,17 @@ var RpgClientEngine = class {
|
|
|
1016
1578
|
if (now - this.lastMovePathSentAt < this.MOVE_PATH_RESEND_INTERVAL_MS) return;
|
|
1017
1579
|
this.emitMovePacket(latest.direction, latest.frame, latest.tick, now, false);
|
|
1018
1580
|
}
|
|
1581
|
+
applyPredictedMovementInput(player, input) {
|
|
1582
|
+
if (isDashInput(input)) {
|
|
1583
|
+
const direction = vectorToDirection(input.direction);
|
|
1584
|
+
player.changeDirection(direction);
|
|
1585
|
+
return Boolean(this.sceneMap.dashBody?.(player, input));
|
|
1586
|
+
}
|
|
1587
|
+
const direction = resolveMoveDirection(input);
|
|
1588
|
+
if (!direction) return false;
|
|
1589
|
+
player.changeDirection(direction);
|
|
1590
|
+
return Boolean(this.sceneMap.moveBody?.(player, direction));
|
|
1591
|
+
}
|
|
1019
1592
|
getLocalPlayerState() {
|
|
1020
1593
|
const currentPlayer = this.sceneMap?.getCurrentPlayer();
|
|
1021
1594
|
if (!currentPlayer) return {
|
|
@@ -1124,6 +1697,31 @@ var RpgClientEngine = class {
|
|
|
1124
1697
|
this.lastMovePathSentFrame = 0;
|
|
1125
1698
|
}
|
|
1126
1699
|
/**
|
|
1700
|
+
* Stop local movement immediately and discard pending predicted movement.
|
|
1701
|
+
*
|
|
1702
|
+
* Use this before a blocking action such as an A-RPG attack, dialog, dash
|
|
1703
|
+
* startup, or any client-side state where already buffered movement inputs
|
|
1704
|
+
* must not be replayed after server reconciliation.
|
|
1705
|
+
*
|
|
1706
|
+
* @param player - Player object to stop. Defaults to the current player.
|
|
1707
|
+
* @returns `true` when a player was found and interrupted.
|
|
1708
|
+
*
|
|
1709
|
+
* @example
|
|
1710
|
+
* ```ts
|
|
1711
|
+
* engine.interruptCurrentPlayerMovement();
|
|
1712
|
+
* ```
|
|
1713
|
+
*/
|
|
1714
|
+
interruptCurrentPlayerMovement(player = this.sceneMap?.getCurrentPlayer?.()) {
|
|
1715
|
+
if (!player) return false;
|
|
1716
|
+
this.sceneMap?.stopMovement?.(player);
|
|
1717
|
+
this.prediction?.clearPendingInputs();
|
|
1718
|
+
this.pendingPredictionFrames = [];
|
|
1719
|
+
this.lastInputTime = 0;
|
|
1720
|
+
this.lastMovePathSentAt = Date.now();
|
|
1721
|
+
this.lastMovePathSentFrame = this.inputFrameCounter;
|
|
1722
|
+
return true;
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1127
1725
|
* Trigger a flash animation on a sprite
|
|
1128
1726
|
*
|
|
1129
1727
|
* This method allows you to trigger a flash effect on any sprite from client-side code.
|
|
@@ -1177,11 +1775,13 @@ var RpgClientEngine = class {
|
|
|
1177
1775
|
if (sprite && typeof sprite.flash === "function") sprite.flash(options);
|
|
1178
1776
|
}
|
|
1179
1777
|
applyServerAck(ack) {
|
|
1778
|
+
this.updateServerTickEstimate(ack.serverTick);
|
|
1779
|
+
const keepLocalMovement = this.shouldKeepLocalPlayerMovement();
|
|
1180
1780
|
if (this.predictionEnabled && this.prediction) {
|
|
1181
1781
|
const result = this.prediction.applyServerAck({
|
|
1182
1782
|
frame: ack.frame,
|
|
1183
1783
|
serverTick: ack.serverTick,
|
|
1184
|
-
state: typeof ack.x === "number" && typeof ack.y === "number" ? {
|
|
1784
|
+
state: !keepLocalMovement && typeof ack.x === "number" && typeof ack.y === "number" ? {
|
|
1185
1785
|
x: ack.x,
|
|
1186
1786
|
y: ack.y,
|
|
1187
1787
|
direction: ack.direction
|
|
@@ -1191,6 +1791,7 @@ var RpgClientEngine = class {
|
|
|
1191
1791
|
return;
|
|
1192
1792
|
}
|
|
1193
1793
|
if (typeof ack.x !== "number" || typeof ack.y !== "number") return;
|
|
1794
|
+
if (keepLocalMovement) return;
|
|
1194
1795
|
const player = this.getCurrentPlayer();
|
|
1195
1796
|
const myId = this.playerIdSignal();
|
|
1196
1797
|
if (!player || !myId) return;
|
|
@@ -1205,13 +1806,17 @@ var RpgClientEngine = class {
|
|
|
1205
1806
|
reconcilePrediction(authoritativeState, pendingInputs) {
|
|
1206
1807
|
const player = this.getCurrentPlayer();
|
|
1207
1808
|
if (!player) return;
|
|
1809
|
+
if (!getCanMoveValue(player)) {
|
|
1810
|
+
this.interruptCurrentPlayerMovement(player);
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1208
1813
|
this.sceneMap.stopMovement(player);
|
|
1209
1814
|
this.applyAuthoritativeState(authoritativeState);
|
|
1210
1815
|
if (!pendingInputs.length) return;
|
|
1211
1816
|
const replayInputs = pendingInputs.slice(-600);
|
|
1212
1817
|
for (const entry of replayInputs) {
|
|
1213
1818
|
if (!entry?.direction) continue;
|
|
1214
|
-
this.
|
|
1819
|
+
this.applyPredictedMovementInput(player, entry.direction);
|
|
1215
1820
|
this.sceneMap.stepPredictionTick();
|
|
1216
1821
|
this.prediction?.attachPredictedState(entry.frame, this.getLocalPlayerState());
|
|
1217
1822
|
}
|
|
@@ -1277,6 +1882,19 @@ var RpgClientEngine = class {
|
|
|
1277
1882
|
window.removeEventListener("resize", this.resizeHandler);
|
|
1278
1883
|
this.resizeHandler = void 0;
|
|
1279
1884
|
}
|
|
1885
|
+
if (this.pointerMoveHandler && this.pointerCanvas) {
|
|
1886
|
+
this.pointerCanvas.removeEventListener("pointermove", this.pointerMoveHandler);
|
|
1887
|
+
this.pointerCanvas.removeEventListener("pointerdown", this.pointerMoveHandler);
|
|
1888
|
+
if (this.pointerUpHandler) this.pointerCanvas.removeEventListener("pointerup", this.pointerUpHandler);
|
|
1889
|
+
if (this.pointerCancelHandler) {
|
|
1890
|
+
this.pointerCanvas.removeEventListener("pointercancel", this.pointerCancelHandler);
|
|
1891
|
+
this.pointerCanvas.removeEventListener("pointerleave", this.pointerCancelHandler);
|
|
1892
|
+
}
|
|
1893
|
+
this.pointerMoveHandler = void 0;
|
|
1894
|
+
this.pointerUpHandler = void 0;
|
|
1895
|
+
this.pointerCancelHandler = void 0;
|
|
1896
|
+
this.pointerCanvas = void 0;
|
|
1897
|
+
}
|
|
1280
1898
|
const rendererStillExists = this.renderer && typeof this.renderer.destroy === "function";
|
|
1281
1899
|
if (this.canvasApp && typeof this.canvasApp.destroy === "function") {
|
|
1282
1900
|
try {
|
|
@@ -1305,9 +1923,10 @@ var RpgClientEngine = class {
|
|
|
1305
1923
|
}
|
|
1306
1924
|
if (this.prediction) this.prediction = void 0;
|
|
1307
1925
|
this.playerIdSignal.set(null);
|
|
1308
|
-
this.
|
|
1926
|
+
this.resetCameraFollow(false);
|
|
1309
1927
|
this.spriteComponentsBehind.set([]);
|
|
1310
1928
|
this.spriteComponentsInFront.set([]);
|
|
1929
|
+
this.eventComponentResolvers.clear();
|
|
1311
1930
|
this.spritesheets.clear();
|
|
1312
1931
|
this.sounds.clear();
|
|
1313
1932
|
this.componentAnimations = [];
|