@rpgjs/client 5.0.0-beta.2 → 5.0.0-beta.20
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 +123 -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 +96 -54
- 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 +176 -11
- package/dist/RpgClientEngine.js +669 -68
- 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 +606 -248
- 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.js +2 -2
- package/dist/components/gui/mobile/index.js.map +1 -1
- package/dist/components/gui/mobile/mobile.ce.js +7 -5
- 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 +7 -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/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 +340 -0
- package/src/Gui/Gui.ts +129 -57
- package/src/Resource.ts +1 -2
- package/src/RpgClient.ts +220 -17
- package/src/RpgClientEngine.ts +959 -116
- package/src/components/animations/fx.ce +101 -0
- package/src/components/animations/index.ts +4 -2
- package/src/components/character.ce +681 -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/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 +7 -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/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,125 @@
|
|
|
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);
|
|
34
109
|
this.mapShakeTrigger = trigger();
|
|
35
110
|
this.controlsReady = signal(void 0);
|
|
36
111
|
this.gamePause = signal(false);
|
|
37
112
|
this.predictionEnabled = false;
|
|
38
113
|
this.SERVER_CORRECTION_THRESHOLD = 30;
|
|
114
|
+
this.localMovementAuthority = false;
|
|
115
|
+
this.lastLocalMovementInputAt = 0;
|
|
116
|
+
this.LOCAL_MOVEMENT_AUTHORITY_ACK_GRACE_MS = 250;
|
|
39
117
|
this.inputFrameCounter = 0;
|
|
40
118
|
this.pendingPredictionFrames = [];
|
|
41
119
|
this.lastClientPhysicsStepAt = 0;
|
|
42
120
|
this.frameOffset = 0;
|
|
121
|
+
this.latestServerTickAt = 0;
|
|
122
|
+
this.dashLockedUntil = 0;
|
|
43
123
|
this.rtt = 0;
|
|
44
124
|
this.pingInterval = null;
|
|
45
125
|
this.PING_INTERVAL_MS = 5e3;
|
|
@@ -53,12 +133,20 @@ var RpgClientEngine = class {
|
|
|
53
133
|
this.playersReceived$ = new BehaviorSubject(false);
|
|
54
134
|
this.eventsReceived$ = new BehaviorSubject(false);
|
|
55
135
|
this.sceneResetQueued = false;
|
|
136
|
+
this.mapTransitionInProgress = false;
|
|
137
|
+
this.socketListenersInitialized = false;
|
|
138
|
+
this.clientReadyForMapChanges = false;
|
|
139
|
+
this.pendingMapChanges = [];
|
|
56
140
|
this.tickSubscriptions = [];
|
|
141
|
+
this.pendingSyncPackets = [];
|
|
57
142
|
this.notificationManager = new NotificationManager();
|
|
58
143
|
this.webSocket = inject(WebSocketToken);
|
|
59
144
|
this.guiService = inject(RpgGui);
|
|
60
145
|
this.loadMapService = inject(LoadMapToken);
|
|
61
146
|
this.hooks = inject(ModulesToken);
|
|
147
|
+
this.i18nService = getOrCreateI18nService(context);
|
|
148
|
+
this.i18nService.addMessages(RpgClientBuiltinI18n, "rpgjs-client", 0);
|
|
149
|
+
this.projectiles = new ProjectileManager(this.hooks, (projectile) => this.predictProjectileImpact(projectile));
|
|
62
150
|
this.globalConfig = inject(GlobalConfigToken);
|
|
63
151
|
if (!this.globalConfig) this.globalConfig = {};
|
|
64
152
|
if (!this.globalConfig.box) this.globalConfig.box = {
|
|
@@ -72,9 +160,38 @@ var RpgClientEngine = class {
|
|
|
72
160
|
id: "animation",
|
|
73
161
|
component: PrebuiltComponentAnimations.Animation
|
|
74
162
|
});
|
|
163
|
+
this.registerSpriteComponent("rpg:text", __ce_component$2);
|
|
164
|
+
this.registerSpriteComponent("rpg:hpBar", __ce_component$3);
|
|
165
|
+
this.registerSpriteComponent("rpg:spBar", __ce_component$3);
|
|
166
|
+
this.registerSpriteComponent("rpg:bar", __ce_component$3);
|
|
167
|
+
this.registerSpriteComponent("rpg:shape", __ce_component$4);
|
|
168
|
+
this.registerSpriteComponent("rpg:image", __ce_component$5);
|
|
75
169
|
this.predictionEnabled = this.globalConfig?.prediction?.enabled !== false;
|
|
170
|
+
this.localMovementAuthority = this.resolveLocalMovementAuthority();
|
|
76
171
|
this.initializePredictionController();
|
|
77
172
|
}
|
|
173
|
+
resolveLocalMovementAuthority() {
|
|
174
|
+
const predictionConfig = this.globalConfig?.prediction;
|
|
175
|
+
const configured = this.globalConfig?.movementAuthority ?? predictionConfig?.movementAuthority ?? predictionConfig?.authority ?? predictionConfig?.mode;
|
|
176
|
+
if (configured === "server" || configured === "network" || configured === false) return false;
|
|
177
|
+
if (configured === "client" || configured === "local" || configured === true) return true;
|
|
178
|
+
return this.webSocket.mode === "standalone";
|
|
179
|
+
}
|
|
180
|
+
setLocale(locale) {
|
|
181
|
+
this.locale = locale;
|
|
182
|
+
}
|
|
183
|
+
getLocale() {
|
|
184
|
+
return this.locale || this.i18nService.defaultLocale;
|
|
185
|
+
}
|
|
186
|
+
t(key, params) {
|
|
187
|
+
return this.i18nService.t(key, params, this.getLocale());
|
|
188
|
+
}
|
|
189
|
+
i18n() {
|
|
190
|
+
return {
|
|
191
|
+
locale: this.getLocale(),
|
|
192
|
+
t: (key, params) => this.t(key, params)
|
|
193
|
+
};
|
|
194
|
+
}
|
|
78
195
|
/**
|
|
79
196
|
* Assigns a CanvasEngine KeyboardControls instance to the dependency injection context
|
|
80
197
|
*
|
|
@@ -120,12 +237,25 @@ var RpgClientEngine = class {
|
|
|
120
237
|
this.sceneMap = new RpgClientMap();
|
|
121
238
|
this.sceneMap.configureClientPrediction(this.predictionEnabled);
|
|
122
239
|
this.sceneMap.loadPhysic();
|
|
240
|
+
this.resolveSceneMapComponent();
|
|
241
|
+
inject(SaveClientService).initialize();
|
|
242
|
+
this.initListeners();
|
|
243
|
+
this.guiService._initialize();
|
|
244
|
+
try {
|
|
245
|
+
await this.webSocket.connection();
|
|
246
|
+
} catch (error) {
|
|
247
|
+
this.stopPingPong();
|
|
248
|
+
await this.callConnectError(error);
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
123
251
|
this.selector = document.body.querySelector("#rpg");
|
|
124
252
|
const bootstrapOptions = this.globalConfig?.bootstrapCanvasOptions;
|
|
125
|
-
const { app, canvasElement } = await bootstrapCanvas(this.selector,
|
|
253
|
+
const { app, canvasElement } = await bootstrapCanvas(this.selector, __ce_component, bootstrapOptions);
|
|
254
|
+
this.installCanvasResizeGuard(app);
|
|
126
255
|
this.canvasApp = app;
|
|
127
256
|
this.canvasElement = canvasElement;
|
|
128
257
|
this.renderer = app.renderer;
|
|
258
|
+
this.setupPointerTracking();
|
|
129
259
|
this.tick = canvasElement?.propObservables?.context["tick"].observable;
|
|
130
260
|
const inputCheckSubscription = this.tick.subscribe(() => {
|
|
131
261
|
if (Date.now() - this.lastInputTime > 100) {
|
|
@@ -137,6 +267,7 @@ var RpgClientEngine = class {
|
|
|
137
267
|
this.tickSubscriptions.push(inputCheckSubscription);
|
|
138
268
|
this.hooks.callHooks("client-spritesheets-load", this).subscribe();
|
|
139
269
|
this.hooks.callHooks("client-spritesheetResolver-load", this).subscribe();
|
|
270
|
+
this.flushPendingSyncPackets();
|
|
140
271
|
this.hooks.callHooks("client-sounds-load", this).subscribe();
|
|
141
272
|
this.hooks.callHooks("client-soundResolver-load", this).subscribe();
|
|
142
273
|
RpgSound.init(this);
|
|
@@ -144,14 +275,20 @@ var RpgClientEngine = class {
|
|
|
144
275
|
this.hooks.callHooks("client-gui-load", this).subscribe();
|
|
145
276
|
this.hooks.callHooks("client-particles-load", this).subscribe();
|
|
146
277
|
this.hooks.callHooks("client-componentAnimations-load", this).subscribe();
|
|
278
|
+
this.hooks.callHooks("client-clientVisuals-load", this).subscribe();
|
|
279
|
+
this.hooks.callHooks("client-projectiles-load", this).subscribe();
|
|
280
|
+
this.hooks.callHooks("client-interactions-load", this).subscribe();
|
|
147
281
|
this.hooks.callHooks("client-sprite-load", this).subscribe();
|
|
148
282
|
await lastValueFrom(this.hooks.callHooks("client-engine-onStart", this));
|
|
283
|
+
this.clientReadyForMapChanges = true;
|
|
284
|
+
this.flushPendingMapChanges();
|
|
149
285
|
this.resizeHandler = () => {
|
|
150
286
|
this.hooks.callHooks("client-engine-onWindowResize", this).subscribe();
|
|
151
287
|
};
|
|
152
288
|
window.addEventListener("resize", this.resizeHandler);
|
|
153
289
|
const tickSubscription = this.tick.subscribe((tick) => {
|
|
154
290
|
this.stepClientPhysicsTick();
|
|
291
|
+
this.projectiles.step();
|
|
155
292
|
this.flushPendingPredictedStates();
|
|
156
293
|
this.flushPendingMovePath();
|
|
157
294
|
this.hooks.callHooks("client-engine-onStep", this, tick).subscribe();
|
|
@@ -162,12 +299,133 @@ var RpgClientEngine = class {
|
|
|
162
299
|
}
|
|
163
300
|
});
|
|
164
301
|
this.tickSubscriptions.push(tickSubscription);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
302
|
+
this.startPingPong();
|
|
303
|
+
}
|
|
304
|
+
installCanvasResizeGuard(app) {
|
|
305
|
+
if (!app || typeof app.resize !== "function") return;
|
|
306
|
+
const originalResize = app.resize.bind(app);
|
|
307
|
+
app.resize = () => {
|
|
308
|
+
const targetSize = this.readCanvasResizeTargetSize(app);
|
|
309
|
+
const rendererSize = this.readCanvasRendererSize(app);
|
|
310
|
+
if (targetSize && rendererSize && targetSize.width === rendererSize.width && targetSize.height === rendererSize.height) {
|
|
311
|
+
this.cancelCanvasResizeFrame(app);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
originalResize();
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
readCanvasResizeTargetSize(app) {
|
|
318
|
+
const resizeTarget = app?.resizeTo;
|
|
319
|
+
if (!resizeTarget || typeof window === "undefined") return null;
|
|
320
|
+
const rawWidth = resizeTarget === window ? window.innerWidth : resizeTarget.clientWidth;
|
|
321
|
+
const rawHeight = resizeTarget === window ? window.innerHeight : resizeTarget.clientHeight;
|
|
322
|
+
const width = Math.round(Number(rawWidth));
|
|
323
|
+
const height = Math.round(Number(rawHeight));
|
|
324
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width < 0 || height < 0) return null;
|
|
325
|
+
return {
|
|
326
|
+
width,
|
|
327
|
+
height
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
readCanvasRendererSize(app) {
|
|
331
|
+
const screen = app?.renderer?.screen;
|
|
332
|
+
const width = Math.round(Number(screen?.width));
|
|
333
|
+
const height = Math.round(Number(screen?.height));
|
|
334
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) return null;
|
|
335
|
+
return {
|
|
336
|
+
width,
|
|
337
|
+
height
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
cancelCanvasResizeFrame(app) {
|
|
341
|
+
if (typeof app?._cancelResize === "function") app._cancelResize();
|
|
342
|
+
}
|
|
343
|
+
resolveSceneMapComponent() {
|
|
344
|
+
const components = this.hooks.getHookFunctions("client-sceneMap-component");
|
|
345
|
+
const component = components[components.length - 1];
|
|
346
|
+
if (component) this.sceneMapComponent = component;
|
|
347
|
+
}
|
|
348
|
+
setupPointerTracking() {
|
|
349
|
+
const renderer = this.renderer;
|
|
350
|
+
const canvas = renderer?.canvas ?? renderer?.view ?? this.canvasApp?.canvas;
|
|
351
|
+
if (!canvas || typeof canvas.addEventListener !== "function") return;
|
|
352
|
+
this.pointerCanvas = canvas;
|
|
353
|
+
const updatePointer = (event) => {
|
|
354
|
+
const rect = canvas.getBoundingClientRect();
|
|
355
|
+
const screen = {
|
|
356
|
+
x: event.clientX - rect.left,
|
|
357
|
+
y: event.clientY - rect.top
|
|
358
|
+
};
|
|
359
|
+
const viewport = this.findViewportInstance();
|
|
360
|
+
let world = screen;
|
|
361
|
+
if (viewport && typeof viewport.toWorld === "function") {
|
|
362
|
+
const point = viewport.toWorld(screen.x, screen.y);
|
|
363
|
+
world = {
|
|
364
|
+
x: Number(point.x),
|
|
365
|
+
y: Number(point.y)
|
|
366
|
+
};
|
|
367
|
+
} else if (viewport && typeof viewport.toLocal === "function") {
|
|
368
|
+
const point = viewport.toLocal(screen);
|
|
369
|
+
world = {
|
|
370
|
+
x: Number(point.x),
|
|
371
|
+
y: Number(point.y)
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
this.pointer.update(screen, world);
|
|
375
|
+
};
|
|
376
|
+
this.pointerMoveHandler = (event) => {
|
|
377
|
+
updatePointer(event);
|
|
378
|
+
this.interactions.handlePointerMove(event);
|
|
379
|
+
};
|
|
380
|
+
this.pointerUpHandler = (event) => {
|
|
381
|
+
updatePointer(event);
|
|
382
|
+
this.interactions.handlePointerUp(event);
|
|
383
|
+
};
|
|
384
|
+
this.pointerCancelHandler = (event) => {
|
|
385
|
+
updatePointer(event);
|
|
386
|
+
this.interactions.cancelDrag(event);
|
|
387
|
+
};
|
|
388
|
+
canvas.addEventListener("pointermove", this.pointerMoveHandler);
|
|
389
|
+
canvas.addEventListener("pointerdown", this.pointerMoveHandler);
|
|
390
|
+
canvas.addEventListener("pointerup", this.pointerUpHandler);
|
|
391
|
+
canvas.addEventListener("pointercancel", this.pointerCancelHandler);
|
|
392
|
+
canvas.addEventListener("pointerleave", this.pointerCancelHandler);
|
|
393
|
+
}
|
|
394
|
+
updatePointerFromInteractionEvent(event) {
|
|
395
|
+
const global = event?.global ?? event?.data?.global;
|
|
396
|
+
if (!global) {
|
|
397
|
+
this.pointer.updateFromEvent(event);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const screen = {
|
|
401
|
+
x: Number(global.x),
|
|
402
|
+
y: Number(global.y)
|
|
403
|
+
};
|
|
404
|
+
if (!Number.isFinite(screen.x) || !Number.isFinite(screen.y)) {
|
|
405
|
+
this.pointer.updateFromEvent(event);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const viewport = this.findViewportInstance();
|
|
409
|
+
if (viewport && typeof viewport.toWorld === "function") {
|
|
410
|
+
const point = viewport.toWorld(screen.x, screen.y);
|
|
411
|
+
this.pointer.update(screen, {
|
|
412
|
+
x: Number(point.x),
|
|
413
|
+
y: Number(point.y)
|
|
414
|
+
});
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
this.pointer.update(screen);
|
|
418
|
+
}
|
|
419
|
+
findViewportInstance() {
|
|
420
|
+
const find = (node) => {
|
|
421
|
+
if (!node) return void 0;
|
|
422
|
+
if (typeof node?.toWorld === "function" || node?.constructor?.name === "Viewport") return node;
|
|
423
|
+
for (const child of node.children ?? []) {
|
|
424
|
+
const viewport = find(child);
|
|
425
|
+
if (viewport) return viewport;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
return find(this.canvasApp?.stage);
|
|
171
429
|
}
|
|
172
430
|
prepareSyncPayload(data) {
|
|
173
431
|
const payload = { ...data ?? {} };
|
|
@@ -175,7 +433,8 @@ var RpgClientEngine = class {
|
|
|
175
433
|
delete payload.timestamp;
|
|
176
434
|
const myId = this.playerIdSignal();
|
|
177
435
|
const players = payload.players;
|
|
178
|
-
|
|
436
|
+
const localPatch = myId && players ? players[myId] : void 0;
|
|
437
|
+
if (this.shouldPreserveLocalPlayerPosition(localPatch) && myId && players && players[myId]) {
|
|
179
438
|
const localPatch = { ...players[myId] };
|
|
180
439
|
delete localPatch.x;
|
|
181
440
|
delete localPatch.y;
|
|
@@ -188,6 +447,18 @@ var RpgClientEngine = class {
|
|
|
188
447
|
}
|
|
189
448
|
return payload;
|
|
190
449
|
}
|
|
450
|
+
shouldPreserveLocalPlayerPosition(localPatch) {
|
|
451
|
+
if (!localPatch) return false;
|
|
452
|
+
if (this.predictionEnabled && !!this.prediction?.hasPendingInputs()) return true;
|
|
453
|
+
return this.shouldKeepLocalPlayerMovement();
|
|
454
|
+
}
|
|
455
|
+
shouldKeepLocalPlayerMovement() {
|
|
456
|
+
if (!this.localMovementAuthority || this.mapTransitionInProgress) return false;
|
|
457
|
+
const myId = this.playerIdSignal();
|
|
458
|
+
if (!(myId ? this.sceneMap?.players?.()?.[myId] : void 0)) return false;
|
|
459
|
+
if (this.prediction?.hasPendingInputs()) return true;
|
|
460
|
+
return Date.now() - this.lastLocalMovementInputAt <= this.LOCAL_MOVEMENT_AUTHORITY_ACK_GRACE_MS;
|
|
461
|
+
}
|
|
191
462
|
normalizeAckWithSyncState(ack, syncData) {
|
|
192
463
|
const myId = this.playerIdSignal();
|
|
193
464
|
if (!myId) return ack;
|
|
@@ -201,43 +472,30 @@ var RpgClientEngine = class {
|
|
|
201
472
|
};
|
|
202
473
|
}
|
|
203
474
|
initListeners() {
|
|
475
|
+
if (this.socketListenersInitialized) return;
|
|
476
|
+
this.socketListenersInitialized = true;
|
|
204
477
|
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];
|
|
478
|
+
if (!this.tick) {
|
|
479
|
+
this.pendingSyncPackets.push(data);
|
|
480
|
+
return;
|
|
224
481
|
}
|
|
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);
|
|
482
|
+
this.applySyncPacket(data);
|
|
228
483
|
});
|
|
229
484
|
this.webSocket.on("pong", (data) => {
|
|
230
|
-
|
|
485
|
+
const now = Date.now();
|
|
486
|
+
this.rtt = now - data.clientTime;
|
|
231
487
|
const estimatedTicksInFlight = Math.floor(this.rtt / 2 / (1e3 / 60));
|
|
232
488
|
const estimatedServerTickNow = data.serverTick + estimatedTicksInFlight;
|
|
489
|
+
this.updateServerTickEstimate(estimatedServerTickNow, now);
|
|
233
490
|
if (this.inputFrameCounter > 0) this.frameOffset = estimatedServerTickNow - data.clientFrame;
|
|
234
491
|
console.debug(`[Ping/Pong] RTT: ${this.rtt}ms, ServerTick: ${data.serverTick}, FrameOffset: ${this.frameOffset}`);
|
|
235
492
|
});
|
|
236
493
|
this.webSocket.on("changeMap", (data) => {
|
|
237
|
-
this.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
494
|
+
if (!this.clientReadyForMapChanges) {
|
|
495
|
+
this.pendingMapChanges.push(data);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
this.handleChangeMap(data);
|
|
241
499
|
});
|
|
242
500
|
this.webSocket.on("showComponentAnimation", (data) => {
|
|
243
501
|
const { params, object, position, id } = data;
|
|
@@ -245,14 +503,42 @@ var RpgClientEngine = class {
|
|
|
245
503
|
const player = object ? this.sceneMap.getObjectById(object) : void 0;
|
|
246
504
|
this.getComponentAnimation(id).displayEffect(params, player || position);
|
|
247
505
|
});
|
|
506
|
+
this.webSocket.on("clientVisual", (data) => {
|
|
507
|
+
this.playClientVisual(data);
|
|
508
|
+
});
|
|
509
|
+
this.webSocket.on("projectile:spawnBatch", (data) => {
|
|
510
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
511
|
+
this.projectiles.spawnBatch(data?.projectiles ?? [], {
|
|
512
|
+
mapId: data?.mapId,
|
|
513
|
+
currentServerTick: this.estimateServerTick(),
|
|
514
|
+
tickDurationMs: this.getPhysicsTickDurationMs()
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
this.webSocket.on("projectile:impactBatch", (data) => {
|
|
518
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
519
|
+
this.projectiles.impactBatch(data?.impacts ?? [], { mapId: data?.mapId });
|
|
520
|
+
});
|
|
521
|
+
this.webSocket.on("projectile:destroyBatch", (data) => {
|
|
522
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
523
|
+
this.projectiles.destroyBatch(data?.projectiles ?? [], { mapId: data?.mapId });
|
|
524
|
+
});
|
|
525
|
+
this.webSocket.on("projectile:clear", (data) => {
|
|
526
|
+
if (!this.shouldProcessProjectilePacket(data)) return;
|
|
527
|
+
this.projectiles.clear();
|
|
528
|
+
});
|
|
248
529
|
this.webSocket.on("notification", (data) => {
|
|
249
530
|
this.notificationManager.add(data);
|
|
250
531
|
});
|
|
251
532
|
this.webSocket.on("setAnimation", (data) => {
|
|
252
|
-
const { animationName, nbTimes, object, graphic } = data;
|
|
253
|
-
const player = this.sceneMap.getObjectById(object);
|
|
254
|
-
if (
|
|
255
|
-
|
|
533
|
+
const { animationName, nbTimes, object, graphic, restoreAnimationName, restoreGraphics } = data;
|
|
534
|
+
const player = object ? this.sceneMap.getObjectById(object) : void 0;
|
|
535
|
+
if (!player) return;
|
|
536
|
+
const restoreOptions = {
|
|
537
|
+
restoreAnimationName,
|
|
538
|
+
restoreGraphics
|
|
539
|
+
};
|
|
540
|
+
if (graphic !== void 0) player.setAnimation(animationName, graphic, nbTimes, restoreOptions);
|
|
541
|
+
else player.setAnimation(animationName, nbTimes, restoreOptions);
|
|
256
542
|
});
|
|
257
543
|
this.webSocket.on("playSound", (data) => {
|
|
258
544
|
const { soundId, volume, loop } = data;
|
|
@@ -314,6 +600,10 @@ var RpgClientEngine = class {
|
|
|
314
600
|
seed: raw.seed
|
|
315
601
|
});
|
|
316
602
|
});
|
|
603
|
+
this.webSocket.on("lightingState", (data) => {
|
|
604
|
+
const raw = data && typeof data === "object" && "value" in data ? data.value : data;
|
|
605
|
+
this.sceneMap.lightingState.set(normalizeLightingState(raw));
|
|
606
|
+
});
|
|
317
607
|
this.webSocket.on("open", () => {
|
|
318
608
|
this.hooks.callHooks("client-engine-onConnected", this, this.socket).subscribe();
|
|
319
609
|
this.startPingPong();
|
|
@@ -323,9 +613,82 @@ var RpgClientEngine = class {
|
|
|
323
613
|
this.stopPingPong();
|
|
324
614
|
});
|
|
325
615
|
this.webSocket.on("error", (error) => {
|
|
326
|
-
this.
|
|
616
|
+
this.callConnectError(error);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
beginMapTransfer(nextMapId) {
|
|
620
|
+
this.mapTransitionInProgress = true;
|
|
621
|
+
this.currentMapRoomId = nextMapId;
|
|
622
|
+
this.sceneResetQueued = false;
|
|
623
|
+
this.clearClientPredictionStates();
|
|
624
|
+
this.sceneMap.weatherState.set(null);
|
|
625
|
+
this.sceneMap.lightingState.set(null);
|
|
626
|
+
this.sceneMap.clearLightSpots();
|
|
627
|
+
this.clearComponentAnimations();
|
|
628
|
+
this.projectiles.setMapId(nextMapId);
|
|
629
|
+
this.cameraFollowTargetId.set(null);
|
|
630
|
+
this.sceneMap.reset();
|
|
631
|
+
this.sceneMap.loadPhysic();
|
|
632
|
+
}
|
|
633
|
+
clearComponentAnimations() {
|
|
634
|
+
this.componentAnimations.forEach((componentAnimation) => {
|
|
635
|
+
componentAnimation.instance?.clear?.();
|
|
327
636
|
});
|
|
328
637
|
}
|
|
638
|
+
shouldProcessProjectilePacket(data) {
|
|
639
|
+
if (this.mapTransitionInProgress) return false;
|
|
640
|
+
const packetMapId = normalizeRoomMapId(typeof data?.mapId === "string" ? data.mapId : void 0);
|
|
641
|
+
const currentMapId = normalizeRoomMapId(this.currentMapRoomId);
|
|
642
|
+
return !packetMapId || !currentMapId || packetMapId === currentMapId;
|
|
643
|
+
}
|
|
644
|
+
async callConnectError(error) {
|
|
645
|
+
await lastValueFrom(this.hooks.callHooks("client-engine-onConnectError", this, error, this.socket));
|
|
646
|
+
}
|
|
647
|
+
flushPendingSyncPackets() {
|
|
648
|
+
const packets = this.pendingSyncPackets;
|
|
649
|
+
this.pendingSyncPackets = [];
|
|
650
|
+
packets.forEach((packet) => this.applySyncPacket(packet));
|
|
651
|
+
}
|
|
652
|
+
flushPendingMapChanges() {
|
|
653
|
+
const packets = this.pendingMapChanges;
|
|
654
|
+
this.pendingMapChanges = [];
|
|
655
|
+
packets.forEach((packet) => this.handleChangeMap(packet));
|
|
656
|
+
}
|
|
657
|
+
handleChangeMap(data) {
|
|
658
|
+
const nextMapId = typeof data?.mapId === "string" ? data.mapId : void 0;
|
|
659
|
+
this.beginMapTransfer(nextMapId);
|
|
660
|
+
const transferToken = typeof data?.transferToken === "string" ? data.transferToken : void 0;
|
|
661
|
+
this.loadScene(data.mapId, transferToken);
|
|
662
|
+
}
|
|
663
|
+
applySyncPacket(data) {
|
|
664
|
+
if (data.pId) {
|
|
665
|
+
this.playerIdSignal.set(data.pId);
|
|
666
|
+
this.playerIdReceived$.next(true);
|
|
667
|
+
}
|
|
668
|
+
if (this.sceneResetQueued) {
|
|
669
|
+
const weatherState = this.sceneMap.weatherState();
|
|
670
|
+
const lightingState = this.sceneMap.lightingState();
|
|
671
|
+
this.sceneMap.reset();
|
|
672
|
+
this.sceneMap.weatherState.set(weatherState);
|
|
673
|
+
this.sceneMap.lightingState.set(lightingState);
|
|
674
|
+
this.sceneMap.loadPhysic();
|
|
675
|
+
this.sceneResetQueued = false;
|
|
676
|
+
}
|
|
677
|
+
this.hooks.callHooks("client-sceneMap-onChanges", this.sceneMap, { partial: data }).subscribe();
|
|
678
|
+
const ack = data?.ack;
|
|
679
|
+
const normalizedAck = ack && typeof ack.frame === "number" ? this.normalizeAckWithSyncState(ack, data) : void 0;
|
|
680
|
+
const payload = this.prepareSyncPayload(data);
|
|
681
|
+
load(this.sceneMap, payload, true);
|
|
682
|
+
if (normalizedAck) this.applyServerAck(normalizedAck);
|
|
683
|
+
for (const playerId in payload.players ?? {}) {
|
|
684
|
+
const player = payload.players[playerId];
|
|
685
|
+
if (!player._param) continue;
|
|
686
|
+
for (const param in player._param) this.sceneMap.players()[playerId]._param()[param] = player._param[param];
|
|
687
|
+
}
|
|
688
|
+
const players = payload.players || this.sceneMap.players();
|
|
689
|
+
if (players && Object.keys(players).length > 0) this.playersReceived$.next(true);
|
|
690
|
+
if ((payload.events || this.sceneMap.events()) !== void 0) this.eventsReceived$.next(true);
|
|
691
|
+
}
|
|
329
692
|
/**
|
|
330
693
|
* Start periodic ping/pong for client-server synchronization
|
|
331
694
|
*
|
|
@@ -402,18 +765,25 @@ var RpgClientEngine = class {
|
|
|
402
765
|
room: mapId,
|
|
403
766
|
query: transferToken ? { transferToken } : void 0
|
|
404
767
|
});
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
this.
|
|
409
|
-
|
|
768
|
+
try {
|
|
769
|
+
await this.webSocket.reconnect();
|
|
770
|
+
} catch (error) {
|
|
771
|
+
this.mapTransitionInProgress = false;
|
|
772
|
+
this.stopPingPong();
|
|
773
|
+
await this.callConnectError(error);
|
|
774
|
+
throw error;
|
|
775
|
+
}
|
|
410
776
|
const res = await this.loadMapService.load(mapId);
|
|
777
|
+
const loadedLighting = typeof res?.lighting !== "undefined" ? res.lighting : res?.data?.lighting;
|
|
778
|
+
if (typeof loadedLighting !== "undefined") this.sceneMap.lightingState.set(normalizeLightingState(loadedLighting));
|
|
411
779
|
this.sceneMap.data.set(res);
|
|
412
780
|
if (this.playerIdSignal()) this.playerIdReceived$.next(true);
|
|
413
781
|
const players = this.sceneMap.players();
|
|
414
782
|
if (players && Object.keys(players).length > 0) this.playersReceived$.next(true);
|
|
415
783
|
if (this.sceneMap.events() !== void 0) this.eventsReceived$.next(true);
|
|
416
784
|
this.mapLoadCompleted$.next(true);
|
|
785
|
+
this.currentMapRoomId = mapId;
|
|
786
|
+
this.mapTransitionInProgress = false;
|
|
417
787
|
this.sceneMap.configureClientPrediction(this.predictionEnabled);
|
|
418
788
|
this.sceneMap.loadPhysic();
|
|
419
789
|
}
|
|
@@ -458,7 +828,7 @@ var RpgClientEngine = class {
|
|
|
458
828
|
* If not found and a resolver is set, it calls the resolver to create the spritesheet.
|
|
459
829
|
* The resolved spritesheet is automatically cached for future use.
|
|
460
830
|
*
|
|
461
|
-
* @param id - The spritesheet ID to retrieve
|
|
831
|
+
* @param id - The spritesheet ID or legacy tile ID to retrieve
|
|
462
832
|
* @returns The spritesheet if found or created, or undefined if not found and no resolver
|
|
463
833
|
* @returns Promise<any> if the resolver is asynchronous
|
|
464
834
|
*
|
|
@@ -474,12 +844,20 @@ var RpgClientEngine = class {
|
|
|
474
844
|
getSpriteSheet(id) {
|
|
475
845
|
if (this.spritesheets.has(id)) return this.spritesheets.get(id);
|
|
476
846
|
if (this.spritesheetResolver) {
|
|
847
|
+
if (this.spritesheetPromises.has(id)) return this.spritesheetPromises.get(id);
|
|
477
848
|
const result = this.spritesheetResolver(id);
|
|
478
|
-
if (result instanceof Promise)
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
849
|
+
if (result instanceof Promise) {
|
|
850
|
+
const promise = result.then((spritesheet) => {
|
|
851
|
+
if (spritesheet) this.spritesheets.set(id, spritesheet);
|
|
852
|
+
this.spritesheetPromises.delete(id);
|
|
853
|
+
return spritesheet;
|
|
854
|
+
}).catch((error) => {
|
|
855
|
+
this.spritesheetPromises.delete(id);
|
|
856
|
+
throw error;
|
|
857
|
+
});
|
|
858
|
+
this.spritesheetPromises.set(id, promise);
|
|
859
|
+
return promise;
|
|
860
|
+
} else {
|
|
483
861
|
if (result) this.spritesheets.set(id, result);
|
|
484
862
|
return result;
|
|
485
863
|
}
|
|
@@ -807,6 +1185,95 @@ var RpgClientEngine = class {
|
|
|
807
1185
|
return component;
|
|
808
1186
|
}
|
|
809
1187
|
/**
|
|
1188
|
+
* Register a reusable sprite component that can be addressed by the server.
|
|
1189
|
+
*
|
|
1190
|
+
* Server-side component definitions only carry the component id and
|
|
1191
|
+
* serializable props. The client registry maps that id to the CanvasEngine
|
|
1192
|
+
* component that performs the actual rendering.
|
|
1193
|
+
*
|
|
1194
|
+
* @param id - Stable component id used by server component definitions
|
|
1195
|
+
* @param component - CanvasEngine component to render for this id
|
|
1196
|
+
* @returns The registered component
|
|
1197
|
+
*
|
|
1198
|
+
* @example
|
|
1199
|
+
* ```ts
|
|
1200
|
+
* engine.registerSpriteComponent('guildBadge', GuildBadgeComponent);
|
|
1201
|
+
* ```
|
|
1202
|
+
*/
|
|
1203
|
+
registerSpriteComponent(id, component) {
|
|
1204
|
+
this.spriteComponents.set(id, component);
|
|
1205
|
+
return component;
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Get a reusable sprite component by id.
|
|
1209
|
+
*
|
|
1210
|
+
* @param id - Component id registered on the client
|
|
1211
|
+
* @returns The CanvasEngine component, or undefined when missing
|
|
1212
|
+
*/
|
|
1213
|
+
getSpriteComponent(id) {
|
|
1214
|
+
return this.spriteComponents.get(id);
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Register a custom event component resolver.
|
|
1218
|
+
*
|
|
1219
|
+
* The last resolver returning a component wins. This lets later modules
|
|
1220
|
+
* override earlier defaults without replacing the whole map scene.
|
|
1221
|
+
*
|
|
1222
|
+
* @param resolver - Function receiving the synced event object
|
|
1223
|
+
* @returns The registered resolver
|
|
1224
|
+
*/
|
|
1225
|
+
addEventComponentResolver(resolver) {
|
|
1226
|
+
return this.eventComponentResolvers.add(resolver);
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Resolve the custom CanvasEngine component for an event, if any.
|
|
1230
|
+
*
|
|
1231
|
+
* @param event - Synced client event object
|
|
1232
|
+
* @returns The component/config returned by the last matching resolver
|
|
1233
|
+
*/
|
|
1234
|
+
resolveEventComponent(event) {
|
|
1235
|
+
return this.eventComponentResolvers.resolve(event);
|
|
1236
|
+
}
|
|
1237
|
+
registerProjectileComponent(type, component) {
|
|
1238
|
+
return this.projectiles.register(type, component);
|
|
1239
|
+
}
|
|
1240
|
+
getProjectileComponent(type) {
|
|
1241
|
+
return this.projectiles.get(type);
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Register a named client visual macro.
|
|
1245
|
+
*
|
|
1246
|
+
* Client visuals are small client-side functions that group existing visual
|
|
1247
|
+
* primitives such as flash, sound, component animations, sprite animation, or
|
|
1248
|
+
* map shake. The server sends only the visual name and a serializable payload.
|
|
1249
|
+
*
|
|
1250
|
+
* @param name - Stable visual name sent by the server
|
|
1251
|
+
* @param handler - Client-side visual handler
|
|
1252
|
+
* @returns The registered handler
|
|
1253
|
+
*/
|
|
1254
|
+
registerClientVisual(name, handler) {
|
|
1255
|
+
return this.clientVisuals.register(name, handler);
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Register several named client visual macros.
|
|
1259
|
+
*
|
|
1260
|
+
* @param visuals - Map of visual names to client-side handlers
|
|
1261
|
+
*/
|
|
1262
|
+
registerClientVisuals(visuals) {
|
|
1263
|
+
this.clientVisuals.registerMany(visuals);
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Play a registered client visual locally.
|
|
1267
|
+
*
|
|
1268
|
+
* This is also used by the websocket listener when the server calls
|
|
1269
|
+
* `player.clientVisual()` or `map.clientVisual()`.
|
|
1270
|
+
*
|
|
1271
|
+
* @param packet - Visual name and serializable payload
|
|
1272
|
+
*/
|
|
1273
|
+
playClientVisual(packet) {
|
|
1274
|
+
return this.clientVisuals.play(packet, this);
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
810
1277
|
* Add a component animation to the engine
|
|
811
1278
|
*
|
|
812
1279
|
* Component animations are temporary visual effects that can be displayed
|
|
@@ -882,18 +1349,47 @@ var RpgClientEngine = class {
|
|
|
882
1349
|
* duration: 1000,
|
|
883
1350
|
* onFinish: () => console.log('Fade complete')
|
|
884
1351
|
* });
|
|
1352
|
+
*
|
|
1353
|
+
* // Wait until the transition component calls onFinish
|
|
1354
|
+
* await engine.startTransition('fade', { duration: 1000 });
|
|
885
1355
|
* ```
|
|
886
1356
|
*/
|
|
887
1357
|
startTransition(id, props = {}) {
|
|
888
1358
|
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
|
-
|
|
1359
|
+
return new Promise((resolve) => {
|
|
1360
|
+
let finished = false;
|
|
1361
|
+
const finish = (data) => {
|
|
1362
|
+
if (finished) return;
|
|
1363
|
+
finished = true;
|
|
1364
|
+
props?.onFinish?.(data);
|
|
1365
|
+
resolve();
|
|
1366
|
+
};
|
|
1367
|
+
this.guiService.display(id, {
|
|
1368
|
+
...props,
|
|
1369
|
+
onFinish: finish
|
|
1370
|
+
});
|
|
1371
|
+
});
|
|
890
1372
|
}
|
|
891
1373
|
async processInput({ input }) {
|
|
1374
|
+
if (this.stopProcessingInput) return;
|
|
1375
|
+
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
1376
|
+
if (!(!currentPlayer || getCanMoveValue(currentPlayer))) {
|
|
1377
|
+
this.interruptCurrentPlayerMovement(currentPlayer);
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
892
1380
|
const timestamp = Date.now();
|
|
1381
|
+
const movementInput = isDashInput(input) ? normalizeDashInput(input, currentPlayer?.direction?.()) : input;
|
|
1382
|
+
if (!movementInput) return;
|
|
1383
|
+
if (isDashInput(movementInput)) {
|
|
1384
|
+
const cooldown = movementInput.cooldown ?? DEFAULT_DASH_COOLDOWN_MS;
|
|
1385
|
+
if (timestamp < this.dashLockedUntil) return;
|
|
1386
|
+
this.dashLockedUntil = timestamp + cooldown;
|
|
1387
|
+
}
|
|
1388
|
+
this.lastLocalMovementInputAt = timestamp;
|
|
893
1389
|
let frame;
|
|
894
1390
|
let tick;
|
|
895
1391
|
if (this.predictionEnabled && this.prediction) {
|
|
896
|
-
const meta = this.prediction.recordInput(
|
|
1392
|
+
const meta = this.prediction.recordInput(movementInput, timestamp);
|
|
897
1393
|
frame = meta.frame;
|
|
898
1394
|
tick = meta.tick;
|
|
899
1395
|
} else {
|
|
@@ -902,29 +1398,38 @@ var RpgClientEngine = class {
|
|
|
902
1398
|
}
|
|
903
1399
|
this.inputFrameCounter = frame;
|
|
904
1400
|
this.hooks.callHooks("client-engine-onInput", this, {
|
|
905
|
-
input,
|
|
1401
|
+
input: movementInput,
|
|
906
1402
|
playerId: this.playerId
|
|
907
1403
|
}).subscribe();
|
|
908
|
-
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
909
1404
|
const bodyReady = this.ensureCurrentPlayerBody();
|
|
910
1405
|
if (currentPlayer && bodyReady) {
|
|
911
|
-
|
|
912
|
-
this.sceneMap.moveBody(currentPlayer, input);
|
|
1406
|
+
this.applyPredictedMovementInput(currentPlayer, movementInput);
|
|
913
1407
|
if (this.predictionEnabled && this.prediction) {
|
|
914
1408
|
this.pendingPredictionFrames.push(frame);
|
|
915
1409
|
if (this.pendingPredictionFrames.length > 240) this.pendingPredictionFrames = this.pendingPredictionFrames.slice(-240);
|
|
916
1410
|
}
|
|
917
1411
|
}
|
|
918
|
-
this.emitMovePacket(
|
|
919
|
-
this.lastInputTime = Date.now();
|
|
1412
|
+
this.emitMovePacket(movementInput, frame, tick, timestamp, true);
|
|
1413
|
+
this.lastInputTime = isDashInput(movementInput) ? Date.now() + (movementInput.duration ?? DEFAULT_DASH_DURATION_MS) : Date.now();
|
|
920
1414
|
}
|
|
921
|
-
|
|
1415
|
+
async processDash(input = {}) {
|
|
1416
|
+
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
1417
|
+
const dashInput = normalizeDashInput(input, typeof currentPlayer?.direction === "function" ? currentPlayer.direction() : currentPlayer?.direction);
|
|
1418
|
+
if (!dashInput) return;
|
|
1419
|
+
await this.processInput({ input: dashInput });
|
|
1420
|
+
}
|
|
1421
|
+
processAction(action, data) {
|
|
922
1422
|
if (this.stopProcessingInput) return;
|
|
1423
|
+
const currentPlayer = this.sceneMap.getCurrentPlayer();
|
|
1424
|
+
if (!(!currentPlayer || getCanMoveValue(currentPlayer))) return;
|
|
1425
|
+
const payload = normalizeActionInput(action, data);
|
|
923
1426
|
this.hooks.callHooks("client-engine-onInput", this, {
|
|
924
|
-
input:
|
|
1427
|
+
input: payload.action,
|
|
1428
|
+
action: payload.action,
|
|
1429
|
+
data: payload.data,
|
|
925
1430
|
playerId: this.playerId
|
|
926
1431
|
}).subscribe();
|
|
927
|
-
this.webSocket.emit("action",
|
|
1432
|
+
this.webSocket.emit("action", payload);
|
|
928
1433
|
}
|
|
929
1434
|
get PIXI() {
|
|
930
1435
|
return PIXI;
|
|
@@ -938,9 +1443,43 @@ var RpgClientEngine = class {
|
|
|
938
1443
|
get scene() {
|
|
939
1444
|
return this.sceneMap;
|
|
940
1445
|
}
|
|
1446
|
+
getObjectById(id) {
|
|
1447
|
+
return this.sceneMap?.getObjectById(id);
|
|
1448
|
+
}
|
|
941
1449
|
getPhysicsTick() {
|
|
942
1450
|
return this.sceneMap?.getTick?.() ?? 0;
|
|
943
1451
|
}
|
|
1452
|
+
getPhysicsTickDurationMs() {
|
|
1453
|
+
const timeStep = this.sceneMap?.physic?.getWorld?.()?.getTimeStep?.();
|
|
1454
|
+
return typeof timeStep === "number" && Number.isFinite(timeStep) && timeStep > 0 ? timeStep * 1e3 : 1e3 / 60;
|
|
1455
|
+
}
|
|
1456
|
+
updateServerTickEstimate(serverTick, now = Date.now()) {
|
|
1457
|
+
if (typeof serverTick !== "number" || !Number.isFinite(serverTick)) return;
|
|
1458
|
+
this.latestServerTick = serverTick;
|
|
1459
|
+
this.latestServerTickAt = now;
|
|
1460
|
+
}
|
|
1461
|
+
estimateServerTick(now = Date.now()) {
|
|
1462
|
+
if (typeof this.latestServerTick !== "number" || this.latestServerTickAt <= 0) return;
|
|
1463
|
+
const elapsedTicks = Math.max(0, (now - this.latestServerTickAt) / this.getPhysicsTickDurationMs());
|
|
1464
|
+
return this.latestServerTick + elapsedTicks;
|
|
1465
|
+
}
|
|
1466
|
+
predictProjectileImpact(projectile) {
|
|
1467
|
+
if (projectile.predictImpact === false) return null;
|
|
1468
|
+
const sceneMap = this.sceneMap;
|
|
1469
|
+
if (!sceneMap?.physic || !Number.isFinite(projectile.range) || projectile.range <= 0) return null;
|
|
1470
|
+
const origin = projectile.origin;
|
|
1471
|
+
const direction = projectile.direction;
|
|
1472
|
+
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;
|
|
1473
|
+
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);
|
|
1474
|
+
if (!hit) return null;
|
|
1475
|
+
return {
|
|
1476
|
+
id: projectile.id,
|
|
1477
|
+
targetId: hit.entity.uuid,
|
|
1478
|
+
x: hit.point.x,
|
|
1479
|
+
y: hit.point.y,
|
|
1480
|
+
distance: hit.distance
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
944
1483
|
ensureCurrentPlayerBody() {
|
|
945
1484
|
const player = this.sceneMap?.getCurrentPlayer();
|
|
946
1485
|
const myId = this.playerIdSignal();
|
|
@@ -986,7 +1525,7 @@ var RpgClientEngine = class {
|
|
|
986
1525
|
input: entry.direction,
|
|
987
1526
|
x: state.x,
|
|
988
1527
|
y: state.y,
|
|
989
|
-
direction: state.direction ?? entry.direction
|
|
1528
|
+
direction: state.direction ?? resolveMoveDirection(entry.direction)
|
|
990
1529
|
});
|
|
991
1530
|
}
|
|
992
1531
|
if (trajectory.length > this.MAX_MOVE_TRAJECTORY_POINTS) return trajectory.slice(-this.MAX_MOVE_TRAJECTORY_POINTS);
|
|
@@ -1008,6 +1547,11 @@ var RpgClientEngine = class {
|
|
|
1008
1547
|
}
|
|
1009
1548
|
flushPendingMovePath() {
|
|
1010
1549
|
if (!this.predictionEnabled || !this.prediction) return;
|
|
1550
|
+
const player = this.sceneMap?.getCurrentPlayer?.();
|
|
1551
|
+
if (player && !getCanMoveValue(player)) {
|
|
1552
|
+
this.interruptCurrentPlayerMovement(player);
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1011
1555
|
const pendingInputs = this.prediction.getPendingInputs();
|
|
1012
1556
|
if (pendingInputs.length === 0) return;
|
|
1013
1557
|
const latest = pendingInputs[pendingInputs.length - 1];
|
|
@@ -1016,6 +1560,17 @@ var RpgClientEngine = class {
|
|
|
1016
1560
|
if (now - this.lastMovePathSentAt < this.MOVE_PATH_RESEND_INTERVAL_MS) return;
|
|
1017
1561
|
this.emitMovePacket(latest.direction, latest.frame, latest.tick, now, false);
|
|
1018
1562
|
}
|
|
1563
|
+
applyPredictedMovementInput(player, input) {
|
|
1564
|
+
if (isDashInput(input)) {
|
|
1565
|
+
const direction = vectorToDirection(input.direction);
|
|
1566
|
+
player.changeDirection(direction);
|
|
1567
|
+
return Boolean(this.sceneMap.dashBody?.(player, input));
|
|
1568
|
+
}
|
|
1569
|
+
const direction = resolveMoveDirection(input);
|
|
1570
|
+
if (!direction) return false;
|
|
1571
|
+
player.changeDirection(direction);
|
|
1572
|
+
return Boolean(this.sceneMap.moveBody?.(player, direction));
|
|
1573
|
+
}
|
|
1019
1574
|
getLocalPlayerState() {
|
|
1020
1575
|
const currentPlayer = this.sceneMap?.getCurrentPlayer();
|
|
1021
1576
|
if (!currentPlayer) return {
|
|
@@ -1124,6 +1679,31 @@ var RpgClientEngine = class {
|
|
|
1124
1679
|
this.lastMovePathSentFrame = 0;
|
|
1125
1680
|
}
|
|
1126
1681
|
/**
|
|
1682
|
+
* Stop local movement immediately and discard pending predicted movement.
|
|
1683
|
+
*
|
|
1684
|
+
* Use this before a blocking action such as an A-RPG attack, dialog, dash
|
|
1685
|
+
* startup, or any client-side state where already buffered movement inputs
|
|
1686
|
+
* must not be replayed after server reconciliation.
|
|
1687
|
+
*
|
|
1688
|
+
* @param player - Player object to stop. Defaults to the current player.
|
|
1689
|
+
* @returns `true` when a player was found and interrupted.
|
|
1690
|
+
*
|
|
1691
|
+
* @example
|
|
1692
|
+
* ```ts
|
|
1693
|
+
* engine.interruptCurrentPlayerMovement();
|
|
1694
|
+
* ```
|
|
1695
|
+
*/
|
|
1696
|
+
interruptCurrentPlayerMovement(player = this.sceneMap?.getCurrentPlayer?.()) {
|
|
1697
|
+
if (!player) return false;
|
|
1698
|
+
this.sceneMap?.stopMovement?.(player);
|
|
1699
|
+
this.prediction?.clearPendingInputs();
|
|
1700
|
+
this.pendingPredictionFrames = [];
|
|
1701
|
+
this.lastInputTime = 0;
|
|
1702
|
+
this.lastMovePathSentAt = Date.now();
|
|
1703
|
+
this.lastMovePathSentFrame = this.inputFrameCounter;
|
|
1704
|
+
return true;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1127
1707
|
* Trigger a flash animation on a sprite
|
|
1128
1708
|
*
|
|
1129
1709
|
* This method allows you to trigger a flash effect on any sprite from client-side code.
|
|
@@ -1177,11 +1757,13 @@ var RpgClientEngine = class {
|
|
|
1177
1757
|
if (sprite && typeof sprite.flash === "function") sprite.flash(options);
|
|
1178
1758
|
}
|
|
1179
1759
|
applyServerAck(ack) {
|
|
1760
|
+
this.updateServerTickEstimate(ack.serverTick);
|
|
1761
|
+
const keepLocalMovement = this.shouldKeepLocalPlayerMovement();
|
|
1180
1762
|
if (this.predictionEnabled && this.prediction) {
|
|
1181
1763
|
const result = this.prediction.applyServerAck({
|
|
1182
1764
|
frame: ack.frame,
|
|
1183
1765
|
serverTick: ack.serverTick,
|
|
1184
|
-
state: typeof ack.x === "number" && typeof ack.y === "number" ? {
|
|
1766
|
+
state: !keepLocalMovement && typeof ack.x === "number" && typeof ack.y === "number" ? {
|
|
1185
1767
|
x: ack.x,
|
|
1186
1768
|
y: ack.y,
|
|
1187
1769
|
direction: ack.direction
|
|
@@ -1191,6 +1773,7 @@ var RpgClientEngine = class {
|
|
|
1191
1773
|
return;
|
|
1192
1774
|
}
|
|
1193
1775
|
if (typeof ack.x !== "number" || typeof ack.y !== "number") return;
|
|
1776
|
+
if (keepLocalMovement) return;
|
|
1194
1777
|
const player = this.getCurrentPlayer();
|
|
1195
1778
|
const myId = this.playerIdSignal();
|
|
1196
1779
|
if (!player || !myId) return;
|
|
@@ -1205,13 +1788,17 @@ var RpgClientEngine = class {
|
|
|
1205
1788
|
reconcilePrediction(authoritativeState, pendingInputs) {
|
|
1206
1789
|
const player = this.getCurrentPlayer();
|
|
1207
1790
|
if (!player) return;
|
|
1791
|
+
if (!getCanMoveValue(player)) {
|
|
1792
|
+
this.interruptCurrentPlayerMovement(player);
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1208
1795
|
this.sceneMap.stopMovement(player);
|
|
1209
1796
|
this.applyAuthoritativeState(authoritativeState);
|
|
1210
1797
|
if (!pendingInputs.length) return;
|
|
1211
1798
|
const replayInputs = pendingInputs.slice(-600);
|
|
1212
1799
|
for (const entry of replayInputs) {
|
|
1213
1800
|
if (!entry?.direction) continue;
|
|
1214
|
-
this.
|
|
1801
|
+
this.applyPredictedMovementInput(player, entry.direction);
|
|
1215
1802
|
this.sceneMap.stepPredictionTick();
|
|
1216
1803
|
this.prediction?.attachPredictedState(entry.frame, this.getLocalPlayerState());
|
|
1217
1804
|
}
|
|
@@ -1277,6 +1864,19 @@ var RpgClientEngine = class {
|
|
|
1277
1864
|
window.removeEventListener("resize", this.resizeHandler);
|
|
1278
1865
|
this.resizeHandler = void 0;
|
|
1279
1866
|
}
|
|
1867
|
+
if (this.pointerMoveHandler && this.pointerCanvas) {
|
|
1868
|
+
this.pointerCanvas.removeEventListener("pointermove", this.pointerMoveHandler);
|
|
1869
|
+
this.pointerCanvas.removeEventListener("pointerdown", this.pointerMoveHandler);
|
|
1870
|
+
if (this.pointerUpHandler) this.pointerCanvas.removeEventListener("pointerup", this.pointerUpHandler);
|
|
1871
|
+
if (this.pointerCancelHandler) {
|
|
1872
|
+
this.pointerCanvas.removeEventListener("pointercancel", this.pointerCancelHandler);
|
|
1873
|
+
this.pointerCanvas.removeEventListener("pointerleave", this.pointerCancelHandler);
|
|
1874
|
+
}
|
|
1875
|
+
this.pointerMoveHandler = void 0;
|
|
1876
|
+
this.pointerUpHandler = void 0;
|
|
1877
|
+
this.pointerCancelHandler = void 0;
|
|
1878
|
+
this.pointerCanvas = void 0;
|
|
1879
|
+
}
|
|
1280
1880
|
const rendererStillExists = this.renderer && typeof this.renderer.destroy === "function";
|
|
1281
1881
|
if (this.canvasApp && typeof this.canvasApp.destroy === "function") {
|
|
1282
1882
|
try {
|
|
@@ -1308,6 +1908,7 @@ var RpgClientEngine = class {
|
|
|
1308
1908
|
this.cameraFollowTargetId.set(null);
|
|
1309
1909
|
this.spriteComponentsBehind.set([]);
|
|
1310
1910
|
this.spriteComponentsInFront.set([]);
|
|
1911
|
+
this.eventComponentResolvers.clear();
|
|
1311
1912
|
this.spritesheets.clear();
|
|
1312
1913
|
this.sounds.clear();
|
|
1313
1914
|
this.componentAnimations = [];
|