@rpgjs/client 5.0.0-beta.5 → 5.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/Game/AnimationManager.d.ts +2 -2
  2. package/dist/Game/AnimationManager.js +18 -9
  3. package/dist/Game/AnimationManager.js.map +1 -1
  4. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  5. package/dist/Game/Map.d.ts +7 -9
  6. package/dist/Game/Map.js +3 -3
  7. package/dist/Game/Map.js.map +1 -1
  8. package/dist/Game/Object.d.ts +28 -12
  9. package/dist/Game/Object.js +29 -4
  10. package/dist/Game/Object.js.map +1 -1
  11. package/dist/Gui/Gui.d.ts +2 -2
  12. package/dist/Gui/Gui.js +15 -15
  13. package/dist/Gui/Gui.js.map +1 -1
  14. package/dist/Gui/NotificationManager.d.ts +1 -1
  15. package/dist/Gui/NotificationManager.js.map +1 -1
  16. package/dist/Resource.js.map +1 -1
  17. package/dist/RpgClient.d.ts +22 -0
  18. package/dist/RpgClientEngine.d.ts +15 -12
  19. package/dist/RpgClientEngine.js +19 -4
  20. package/dist/RpgClientEngine.js.map +1 -1
  21. package/dist/Sound.js.map +1 -1
  22. package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.128.0}/helpers/decorate.js +1 -1
  23. package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.128.0}/helpers/decorateMetadata.js +1 -1
  24. package/dist/components/animations/animation.ce.js +2 -1
  25. package/dist/components/animations/animation.ce.js.map +1 -1
  26. package/dist/components/animations/hit.ce.js +2 -1
  27. package/dist/components/animations/hit.ce.js.map +1 -1
  28. package/dist/components/animations/index.js +4 -4
  29. package/dist/components/character.ce.js +57 -2
  30. package/dist/components/character.ce.js.map +1 -1
  31. package/dist/components/dynamics/parse-value.d.ts +1 -1
  32. package/dist/components/dynamics/parse-value.js.map +1 -1
  33. package/dist/components/dynamics/text.ce.js +2 -1
  34. package/dist/components/dynamics/text.ce.js.map +1 -1
  35. package/dist/components/gui/box.ce.js +2 -1
  36. package/dist/components/gui/box.ce.js.map +1 -1
  37. package/dist/components/gui/dialogbox/index.ce.js +2 -1
  38. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  39. package/dist/components/gui/gameover.ce.js +2 -1
  40. package/dist/components/gui/gameover.ce.js.map +1 -1
  41. package/dist/components/gui/hud/hud.ce.js +2 -1
  42. package/dist/components/gui/hud/hud.ce.js.map +1 -1
  43. package/dist/components/gui/menu/equip-menu.ce.js +2 -1
  44. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -1
  45. package/dist/components/gui/menu/exit-menu.ce.js +2 -1
  46. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -1
  47. package/dist/components/gui/menu/items-menu.ce.js +2 -1
  48. package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
  49. package/dist/components/gui/menu/main-menu.ce.js +14 -13
  50. package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
  51. package/dist/components/gui/menu/options-menu.ce.js +2 -1
  52. package/dist/components/gui/menu/options-menu.ce.js.map +1 -1
  53. package/dist/components/gui/menu/skills-menu.ce.js +2 -1
  54. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -1
  55. package/dist/components/gui/mobile/index.d.ts +1 -1
  56. package/dist/components/gui/mobile/index.js +2 -2
  57. package/dist/components/gui/mobile/index.js.map +1 -1
  58. package/dist/components/gui/mobile/mobile.ce.js +2 -1
  59. package/dist/components/gui/mobile/mobile.ce.js.map +1 -1
  60. package/dist/components/gui/notification/notification.ce.js +9 -5
  61. package/dist/components/gui/notification/notification.ce.js.map +1 -1
  62. package/dist/components/gui/save-load.ce.js +2 -1
  63. package/dist/components/gui/save-load.ce.js.map +1 -1
  64. package/dist/components/gui/shop/shop.ce.js +2 -1
  65. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  66. package/dist/components/gui/title-screen.ce.js +2 -1
  67. package/dist/components/gui/title-screen.ce.js.map +1 -1
  68. package/dist/components/prebuilt/hp-bar.ce.js +2 -1
  69. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -1
  70. package/dist/components/prebuilt/light-halo.ce.js +2 -1
  71. package/dist/components/prebuilt/light-halo.ce.js.map +1 -1
  72. package/dist/components/scenes/canvas.ce.js +4 -3
  73. package/dist/components/scenes/canvas.ce.js.map +1 -1
  74. package/dist/components/scenes/draw-map.ce.js +2 -1
  75. package/dist/components/scenes/draw-map.ce.js.map +1 -1
  76. package/dist/components/scenes/event-layer.ce.js +5 -4
  77. package/dist/components/scenes/event-layer.ce.js.map +1 -1
  78. package/dist/core/inject.js +1 -1
  79. package/dist/core/inject.js.map +1 -1
  80. package/dist/core/setup.js +1 -1
  81. package/dist/core/setup.js.map +1 -1
  82. package/dist/index.js +20 -20
  83. package/dist/module.js +1 -1
  84. package/dist/module.js.map +1 -1
  85. package/dist/node_modules/.pnpm/{@signe_di@2.9.0 → @signe_di@2.10.0}/node_modules/@signe/di/dist/index.js +7 -117
  86. package/dist/node_modules/.pnpm/@signe_di@2.10.0/node_modules/@signe/di/dist/index.js.map +1 -0
  87. package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js +45 -0
  88. package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
  89. package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js +227 -0
  90. package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js.map +1 -0
  91. package/dist/node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js +611 -0
  92. package/dist/node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js.map +1 -0
  93. package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/client/index.js +44 -0
  94. package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  95. package/dist/node_modules/.pnpm/{@signe_sync@2.9.0 → @signe_sync@2.10.0}/node_modules/@signe/sync/dist/index.js +29 -136
  96. package/dist/node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/index.js.map +1 -0
  97. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -1
  98. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -1
  99. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -1
  100. package/dist/presets/animation.js.map +1 -1
  101. package/dist/presets/faceset.js.map +1 -1
  102. package/dist/presets/icon.js.map +1 -1
  103. package/dist/presets/lpc.js.map +1 -1
  104. package/dist/presets/rmspritesheet.js.map +1 -1
  105. package/dist/services/AbstractSocket.js.map +1 -1
  106. package/dist/services/keyboardControls.js.map +1 -1
  107. package/dist/services/loadMap.js +1 -1
  108. package/dist/services/loadMap.js.map +1 -1
  109. package/dist/services/mmorpg.js +1 -1
  110. package/dist/services/mmorpg.js.map +1 -1
  111. package/dist/services/save.js.map +1 -1
  112. package/dist/services/standalone.js +1 -1
  113. package/dist/services/standalone.js.map +1 -1
  114. package/dist/utils/getEntityProp.js.map +1 -1
  115. package/package.json +10 -10
  116. package/src/Game/AnimationManager.spec.ts +30 -0
  117. package/src/Game/AnimationManager.ts +22 -10
  118. package/src/Game/Object.ts +46 -8
  119. package/src/RpgClient.ts +27 -0
  120. package/src/RpgClientEngine.ts +18 -2
  121. package/src/components/character.ce +72 -0
  122. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +0 -1
  123. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +0 -463
  124. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +0 -1
  125. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +0 -2191
  126. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +0 -1
  127. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +0 -10
  128. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +0 -1
  129. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +0 -91
  130. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +0 -1
  131. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +0 -1
  132. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +0 -14
  133. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { RpgCommonPlayer } from '@rpgjs/common';
2
2
  export declare class AnimationManager {
3
- current: import('canvasengine').WritableArraySignal<any[]>;
3
+ current: any;
4
4
  displayEffect(params: any, player: RpgCommonPlayer | {
5
5
  x: number;
6
6
  y: number;
7
- }): void;
7
+ }): Promise<void>;
8
8
  }
@@ -7,16 +7,25 @@ var AnimationManager = class {
7
7
  }
8
8
  displayEffect(params, player) {
9
9
  const id = generateUID();
10
- this.current().push({
11
- ...params,
12
- id,
13
- x: player.x,
14
- y: player.y,
15
- object: player,
16
- onFinish: () => {
10
+ const effectParams = params ?? {};
11
+ return new Promise((resolve) => {
12
+ let finished = false;
13
+ const finish = (data) => {
14
+ if (finished) return;
15
+ finished = true;
17
16
  const index = this.current().findIndex((value) => value.id === id);
18
- this.current().splice(index, 1);
19
- }
17
+ if (index !== -1) this.current().splice(index, 1);
18
+ effectParams.onFinish?.(data);
19
+ resolve();
20
+ };
21
+ this.current().push({
22
+ ...effectParams,
23
+ id,
24
+ x: player.x,
25
+ y: player.y,
26
+ object: player,
27
+ onFinish: finish
28
+ });
20
29
  });
21
30
  }
22
31
  };
@@ -1 +1 @@
1
- {"version":3,"file":"AnimationManager.js","names":[],"sources":["../../src/Game/AnimationManager.ts"],"sourcesContent":["import { generateUID, RpgCommonPlayer } from \"@rpgjs/common\";\nimport { signal } from \"canvasengine\";\n\nexport class AnimationManager {\n current = signal<any[]>([]);\n\n displayEffect(params: any, player: RpgCommonPlayer | { x: number, y: number }) {\n const id = generateUID();\n this.current().push({\n ...params,\n id,\n x: player.x,\n y: player.y,\n object: player,\n onFinish: () => {\n const index = this.current().findIndex((value) => value.id === id);\n this.current().splice(index, 1);\n },\n });\n }\n}\n"],"mappings":";;;AAGA,IAAa,mBAAb,MAA8B;;iBAClB,OAAc,EAAE,CAAC;;CAE3B,cAAc,QAAa,QAAoD;EAC7E,MAAM,KAAK,aAAa;AACxB,OAAK,SAAS,CAAC,KAAK;GAClB,GAAG;GACH;GACA,GAAG,OAAO;GACV,GAAG,OAAO;GACV,QAAQ;GACR,gBAAgB;IACd,MAAM,QAAQ,KAAK,SAAS,CAAC,WAAW,UAAU,MAAM,OAAO,GAAG;AAClE,SAAK,SAAS,CAAC,OAAO,OAAO,EAAE;;GAElC,CAAC"}
1
+ {"version":3,"file":"AnimationManager.js","names":[],"sources":["../../src/Game/AnimationManager.ts"],"sourcesContent":["import { generateUID, RpgCommonPlayer } from \"@rpgjs/common\";\nimport { signal } from \"canvasengine\";\n\nexport class AnimationManager {\n current = signal<any[]>([]);\n\n displayEffect(params: any, player: RpgCommonPlayer | { x: number, y: number }): Promise<void> {\n const id = generateUID();\n const effectParams = params ?? {};\n return new Promise<void>((resolve) => {\n let finished = false;\n const finish = (data?: any) => {\n if (finished) return;\n finished = true;\n const index = this.current().findIndex((value) => value.id === id);\n if (index !== -1) {\n this.current().splice(index, 1);\n }\n effectParams.onFinish?.(data);\n resolve();\n };\n\n this.current().push({\n ...effectParams,\n id,\n x: player.x,\n y: player.y,\n object: player,\n onFinish: finish,\n });\n });\n }\n}\n"],"mappings":";;;AAGA,IAAa,mBAAb,MAA8B;;iBAClB,OAAc,EAAE,CAAC;;CAE3B,cAAc,QAAa,QAAmE;EAC5F,MAAM,KAAK,aAAa;EACxB,MAAM,eAAe,UAAU,EAAE;EACjC,OAAO,IAAI,SAAe,YAAY;GACpC,IAAI,WAAW;GACf,MAAM,UAAU,SAAe;IAC7B,IAAI,UAAU;IACd,WAAW;IACX,MAAM,QAAQ,KAAK,SAAS,CAAC,WAAW,UAAU,MAAM,OAAO,GAAG;IAClE,IAAI,UAAU,IACZ,KAAK,SAAS,CAAC,OAAO,OAAO,EAAE;IAEjC,aAAa,WAAW,KAAK;IAC7B,SAAS;;GAGX,KAAK,SAAS,CAAC,KAAK;IAClB,GAAG;IACH;IACA,GAAG,OAAO;IACV,GAAG,OAAO;IACV,QAAQ;IACR,UAAU;IACX,CAAC;IACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,20 +1,18 @@
1
1
  import { RpgCommonMap, WeatherState, MapPhysicsInitContext, MapPhysicsEntityContext } from '@rpgjs/common';
2
- import { RpgClientPlayer } from './Player';
3
- import { RpgClientEvent } from './Event';
4
2
  import { RpgClientEngine } from '../RpgClientEngine';
5
3
  export declare class RpgClientMap extends RpgCommonMap<any> {
6
4
  engine: RpgClientEngine;
7
- players: import('canvasengine').WritableObjectSignal<Record<string, RpgClientPlayer>>;
8
- events: import('canvasengine').WritableObjectSignal<Record<string, RpgClientEvent>>;
9
- currentPlayer: import('canvasengine').ComputedSignal<RpgClientPlayer>;
10
- weatherState: import('canvasengine').WritableSignal<WeatherState | null>;
11
- localWeatherOverride: import('canvasengine').WritableSignal<WeatherState | null>;
12
- weather: import('canvasengine').ComputedSignal<WeatherState | null>;
5
+ players: any;
6
+ events: any;
7
+ currentPlayer: any;
8
+ weatherState: any;
9
+ localWeatherOverride: any;
10
+ weather: any;
13
11
  private manualClientPhysicsTick;
14
12
  private readonly isTestEnvironment;
15
13
  constructor();
16
14
  configureClientPrediction(enabled: boolean): void;
17
- getCurrentPlayer(): RpgClientPlayer;
15
+ getCurrentPlayer(): any;
18
16
  reset(force?: boolean): void;
19
17
  getWeather(): WeatherState | null;
20
18
  setLocalWeather(next: WeatherState | null): void;
package/dist/Game/Map.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { inject } from "../core/inject.js";
2
- import { sync, users } from "../node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js";
2
+ import { sync, users } from "../node_modules/.pnpm/@signe_sync@2.10.0/node_modules/@signe/sync/dist/index.js";
3
3
  import { RpgClientPlayer } from "./Player.js";
4
4
  import { RpgClientEvent } from "./Event.js";
5
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
6
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
5
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.128.0/helpers/decorateMetadata.js";
6
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.128.0/helpers/decorate.js";
7
7
  import { RpgClientEngine } from "../RpgClientEngine.js";
8
8
  import { computed, signal } from "canvasengine";
9
9
  import { RpgCommonMap } from "@rpgjs/common";
@@ -1 +1 @@
1
- {"version":3,"file":"Map.js","names":[],"sources":["../../src/Game/Map.ts"],"sourcesContent":["import {\n RpgCommonMap,\n type WeatherState,\n type MapPhysicsInitContext,\n type MapPhysicsEntityContext,\n} from \"@rpgjs/common\";\nimport { sync, users } from \"@signe/sync\";\nimport { RpgClientPlayer } from \"./Player\";\nimport { Signal, signal, computed, effect } from \"canvasengine\";\nimport { RpgClientEvent } from \"./Event\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { inject } from \"../core/inject\";\n\nexport class RpgClientMap extends RpgCommonMap<any> {\n engine: RpgClientEngine = inject(RpgClientEngine)\n @users(RpgClientPlayer) players = signal<Record<string, RpgClientPlayer>>({});\n @sync(RpgClientEvent) events = signal<Record<string, RpgClientEvent>>({});\n currentPlayer = computed(() => this.players()[this.engine.playerIdSignal()!])\n weatherState = signal<WeatherState | null>(null);\n localWeatherOverride = signal<WeatherState | null>(null);\n weather = computed<WeatherState | null>(() => {\n const local = this.localWeatherOverride() \n const state = this.weatherState()\n return local ?? state\n });\n private manualClientPhysicsTick = false;\n private readonly isTestEnvironment: boolean;\n\n constructor() {\n super();\n // Détecter l'environnement de test\n const isTest = (typeof process !== 'undefined' && process.env?.TEST === 'true')\n || (typeof window !== 'undefined' && (window as any).__RPGJS_TEST__ === true);\n this.isTestEnvironment = isTest;\n if (isTest) {\n this.autoTickEnabled = false;\n }\n }\n\n configureClientPrediction(enabled: boolean): void {\n this.manualClientPhysicsTick = enabled;\n this.autoTickEnabled = enabled ? false : !this.isTestEnvironment;\n }\n\n getCurrentPlayer() {\n return this.currentPlayer()\n }\n\n reset(force = false) {\n const currentPlayerId = this.engine.playerIdSignal();\n const currentPlayer = !force && currentPlayerId\n ? this.players()[currentPlayerId]\n : undefined;\n\n this.players.set(\n currentPlayerId && currentPlayer ? { [currentPlayerId]: currentPlayer } : {}\n );\n this.events.set({})\n this.weatherState.set(null);\n this.localWeatherOverride.set(null);\n this.clearPhysic()\n }\n\n getWeather(): WeatherState | null {\n return this.weather();\n }\n\n setLocalWeather(next: WeatherState | null): void {\n this.localWeatherOverride.set(next);\n }\n\n clearLocalWeather(): void {\n this.localWeatherOverride.set(null);\n }\n\n stepClientPhysics(deltaMs: number): number {\n if (!this.manualClientPhysicsTick) {\n return 0;\n }\n return this.nextTick(deltaMs);\n }\n\n stepPredictionTick(): void {\n this.forceSingleTick();\n }\n\n protected emitPhysicsInit(context: MapPhysicsInitContext): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsInit\", this, context);\n }\n\n protected emitPhysicsEntityAdd(context: MapPhysicsEntityContext): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsEntityAdd\", this, context);\n }\n\n protected emitPhysicsEntityRemove(context: MapPhysicsEntityContext): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsEntityRemove\", this, context);\n }\n\n protected emitPhysicsReset(): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsReset\", this);\n }\n}\n"],"mappings":";;;;;;;;;;AAaA,IAAa,eAAb,cAAkC,aAAkB;CAelD,cAAc;AACZ,SAAO;gBAfiB,OAAO,gBAAgB;iBACf,OAAwC,EAAE,CAAC;gBAC9C,OAAuC,EAAE,CAAC;uBACzD,eAAe,KAAK,SAAS,CAAC,KAAK,OAAO,gBAAgB,EAAG;sBAC9D,OAA4B,KAAK;8BACzB,OAA4B,KAAK;iBAC9C,eAAoC;GAC5C,MAAM,QAAQ,KAAK,sBAAsB;GACzC,MAAM,QAAQ,KAAK,cAAc;AACjC,UAAO,SAAS;IAChB;iCACgC;EAMhC,MAAM,SAAU,OAAO,YAAY,eAAe,QAAQ,KAAK,SAAS,UAClE,OAAO,WAAW,eAAgB,OAAe,mBAAmB;AAC1E,OAAK,oBAAoB;AACzB,MAAI,OACF,MAAK,kBAAkB;;CAI3B,0BAA0B,SAAwB;AAChD,OAAK,0BAA0B;AAC/B,OAAK,kBAAkB,UAAU,QAAQ,CAAC,KAAK;;CAGjD,mBAAmB;AACjB,SAAO,KAAK,eAAe;;CAG7B,MAAM,QAAQ,OAAO;EACnB,MAAM,kBAAkB,KAAK,OAAO,gBAAgB;EACpD,MAAM,gBAAgB,CAAC,SAAS,kBAC5B,KAAK,SAAS,CAAC,mBACf,KAAA;AAEJ,OAAK,QAAQ,IACX,mBAAmB,gBAAgB,GAAG,kBAAkB,eAAe,GAAG,EAAE,CAC7E;AACD,OAAK,OAAO,IAAI,EAAE,CAAC;AACnB,OAAK,aAAa,IAAI,KAAK;AAC3B,OAAK,qBAAqB,IAAI,KAAK;AACnC,OAAK,aAAa;;CAGpB,aAAkC;AAChC,SAAO,KAAK,SAAS;;CAGvB,gBAAgB,MAAiC;AAC/C,OAAK,qBAAqB,IAAI,KAAK;;CAGrC,oBAA0B;AACxB,OAAK,qBAAqB,IAAI,KAAK;;CAGrC,kBAAkB,SAAyB;AACzC,MAAI,CAAC,KAAK,wBACR,QAAO;AAET,SAAO,KAAK,SAAS,QAAQ;;CAG/B,qBAA2B;AACzB,OAAK,iBAAiB;;CAGxB,gBAA0B,SAAsC;AAC9D,OAAK,QAAQ,mBAAmB,iBAAiB,MAAM,QAAQ;;CAGjE,qBAA+B,SAAwC;AACrE,OAAK,QAAQ,mBAAmB,sBAAsB,MAAM,QAAQ;;CAGtE,wBAAkC,SAAwC;AACxE,OAAK,QAAQ,mBAAmB,yBAAyB,MAAM,QAAQ;;CAGzE,mBAAmC;AACjC,OAAK,QAAQ,mBAAmB,kBAAkB,KAAK;;;YApFxD,MAAM,gBAAgB,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,aAAA,WAAA,WAAA,KAAA,EAAA;YACtB,KAAK,eAAe,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,aAAA,WAAA,UAAA,KAAA,EAAA"}
1
+ {"version":3,"file":"Map.js","names":[],"sources":["../../src/Game/Map.ts"],"sourcesContent":["import {\n RpgCommonMap,\n type WeatherState,\n type MapPhysicsInitContext,\n type MapPhysicsEntityContext,\n} from \"@rpgjs/common\";\nimport { sync, users } from \"@signe/sync\";\nimport { RpgClientPlayer } from \"./Player\";\nimport { Signal, signal, computed, effect } from \"canvasengine\";\nimport { RpgClientEvent } from \"./Event\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { inject } from \"../core/inject\";\n\nexport class RpgClientMap extends RpgCommonMap<any> {\n engine: RpgClientEngine = inject(RpgClientEngine)\n @users(RpgClientPlayer) players = signal<Record<string, RpgClientPlayer>>({});\n @sync(RpgClientEvent) events = signal<Record<string, RpgClientEvent>>({});\n currentPlayer = computed(() => this.players()[this.engine.playerIdSignal()!])\n weatherState = signal<WeatherState | null>(null);\n localWeatherOverride = signal<WeatherState | null>(null);\n weather = computed<WeatherState | null>(() => {\n const local = this.localWeatherOverride() \n const state = this.weatherState()\n return local ?? state\n });\n private manualClientPhysicsTick = false;\n private readonly isTestEnvironment: boolean;\n\n constructor() {\n super();\n // Détecter l'environnement de test\n const isTest = (typeof process !== 'undefined' && process.env?.TEST === 'true')\n || (typeof window !== 'undefined' && (window as any).__RPGJS_TEST__ === true);\n this.isTestEnvironment = isTest;\n if (isTest) {\n this.autoTickEnabled = false;\n }\n }\n\n configureClientPrediction(enabled: boolean): void {\n this.manualClientPhysicsTick = enabled;\n this.autoTickEnabled = enabled ? false : !this.isTestEnvironment;\n }\n\n getCurrentPlayer() {\n return this.currentPlayer()\n }\n\n reset(force = false) {\n const currentPlayerId = this.engine.playerIdSignal();\n const currentPlayer = !force && currentPlayerId\n ? this.players()[currentPlayerId]\n : undefined;\n\n this.players.set(\n currentPlayerId && currentPlayer ? { [currentPlayerId]: currentPlayer } : {}\n );\n this.events.set({})\n this.weatherState.set(null);\n this.localWeatherOverride.set(null);\n this.clearPhysic()\n }\n\n getWeather(): WeatherState | null {\n return this.weather();\n }\n\n setLocalWeather(next: WeatherState | null): void {\n this.localWeatherOverride.set(next);\n }\n\n clearLocalWeather(): void {\n this.localWeatherOverride.set(null);\n }\n\n stepClientPhysics(deltaMs: number): number {\n if (!this.manualClientPhysicsTick) {\n return 0;\n }\n return this.nextTick(deltaMs);\n }\n\n stepPredictionTick(): void {\n this.forceSingleTick();\n }\n\n protected emitPhysicsInit(context: MapPhysicsInitContext): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsInit\", this, context);\n }\n\n protected emitPhysicsEntityAdd(context: MapPhysicsEntityContext): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsEntityAdd\", this, context);\n }\n\n protected emitPhysicsEntityRemove(context: MapPhysicsEntityContext): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsEntityRemove\", this, context);\n }\n\n protected emitPhysicsReset(): void {\n this.engine?.emitSceneMapHook?.(\"onPhysicsReset\", this);\n }\n}\n"],"mappings":";;;;;;;;;;AAaA,IAAa,eAAb,cAAkC,aAAkB;CAelD,cAAc;EACZ,OAAO;gBAfiB,OAAO,gBAAgB;iBACf,OAAwC,EAAE,CAAC;gBAC9C,OAAuC,EAAE,CAAC;uBACzD,eAAe,KAAK,SAAS,CAAC,KAAK,OAAO,gBAAgB,EAAG;sBAC9D,OAA4B,KAAK;8BACzB,OAA4B,KAAK;iBAC9C,eAAoC;GAC5C,MAAM,QAAQ,KAAK,sBAAsB;GACzC,MAAM,QAAQ,KAAK,cAAc;GACjC,OAAO,SAAS;IAChB;iCACgC;EAMhC,MAAM,SAAU,OAAO,YAAY,eAAe,QAAQ,KAAK,SAAS,UAClE,OAAO,WAAW,eAAgB,OAAe,mBAAmB;EAC1E,KAAK,oBAAoB;EACzB,IAAI,QACF,KAAK,kBAAkB;;CAI3B,0BAA0B,SAAwB;EAChD,KAAK,0BAA0B;EAC/B,KAAK,kBAAkB,UAAU,QAAQ,CAAC,KAAK;;CAGjD,mBAAmB;EACjB,OAAO,KAAK,eAAe;;CAG7B,MAAM,QAAQ,OAAO;EACnB,MAAM,kBAAkB,KAAK,OAAO,gBAAgB;EACpD,MAAM,gBAAgB,CAAC,SAAS,kBAC5B,KAAK,SAAS,CAAC,mBACf,KAAA;EAEJ,KAAK,QAAQ,IACX,mBAAmB,gBAAgB,GAAG,kBAAkB,eAAe,GAAG,EAAE,CAC7E;EACD,KAAK,OAAO,IAAI,EAAE,CAAC;EACnB,KAAK,aAAa,IAAI,KAAK;EAC3B,KAAK,qBAAqB,IAAI,KAAK;EACnC,KAAK,aAAa;;CAGpB,aAAkC;EAChC,OAAO,KAAK,SAAS;;CAGvB,gBAAgB,MAAiC;EAC/C,KAAK,qBAAqB,IAAI,KAAK;;CAGrC,oBAA0B;EACxB,KAAK,qBAAqB,IAAI,KAAK;;CAGrC,kBAAkB,SAAyB;EACzC,IAAI,CAAC,KAAK,yBACR,OAAO;EAET,OAAO,KAAK,SAAS,QAAQ;;CAG/B,qBAA2B;EACzB,KAAK,iBAAiB;;CAGxB,gBAA0B,SAAsC;EAC9D,KAAK,QAAQ,mBAAmB,iBAAiB,MAAM,QAAQ;;CAGjE,qBAA+B,SAAwC;EACrE,KAAK,QAAQ,mBAAmB,sBAAsB,MAAM,QAAQ;;CAGtE,wBAAkC,SAAwC;EACxE,KAAK,QAAQ,mBAAmB,yBAAyB,MAAM,QAAQ;;CAGzE,mBAAmC;EACjC,KAAK,QAAQ,mBAAmB,kBAAkB,KAAK;;;YApFxD,MAAM,gBAAgB,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,aAAA,WAAA,WAAA,KAAA,EAAA;YACtB,KAAK,eAAe,EAAA,mBAAA,eAAA,OAAA,CAAA,EAAA,aAAA,WAAA,UAAA,KAAA,EAAA"}
@@ -8,18 +8,19 @@ type Frame = {
8
8
  type AnimationRestoreOptions = {
9
9
  restoreAnimationName?: string;
10
10
  restoreGraphics?: any[];
11
+ timeoutMs?: number;
11
12
  };
12
13
  export declare abstract class RpgClientObject extends RpgCommonPlayer {
13
14
  abstract _type: string;
14
- emitParticleTrigger: import('canvasengine').Trigger<any>;
15
- particleName: import('canvasengine').WritableSignal<string>;
16
- animationCurrentIndex: import('canvasengine').WritableSignal<number>;
17
- animationIsPlaying: import('canvasengine').WritableSignal<boolean>;
18
- _param: import('canvasengine').WritableObjectSignal<{}>;
15
+ emitParticleTrigger: any;
16
+ particleName: any;
17
+ animationCurrentIndex: any;
18
+ animationIsPlaying: any;
19
+ _param: any;
19
20
  frames: Frame[];
20
- graphicsSignals: import('canvasengine').WritableArraySignal<any[]>;
21
+ graphicsSignals: any;
21
22
  _component: {};
22
- flashTrigger: import('canvasengine').Trigger<any>;
23
+ flashTrigger: any;
23
24
  private animationRestoreState?;
24
25
  constructor();
25
26
  /**
@@ -36,7 +37,9 @@ export declare abstract class RpgClientObject extends RpgCommonPlayer {
36
37
  get engine(): RpgClientEngine<unknown>;
37
38
  private animationSubscription?;
38
39
  private animationResetTimeout?;
40
+ private animationWaitResolve?;
39
41
  private clearAnimationControls;
42
+ private resolveAnimationWait;
40
43
  private finishTemporaryAnimation;
41
44
  /**
42
45
  * Trigger a flash animation on this sprite
@@ -113,17 +116,19 @@ export declare abstract class RpgClientObject extends RpgCommonPlayer {
113
116
  *
114
117
  * @param animationName - Name of the animation to play
115
118
  * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
119
+ * @param options - Restore and timeout options
120
+ * @returns A promise resolved when a finite animation finishes, is interrupted, or times out
116
121
  *
117
122
  * @example
118
123
  * ```ts
119
124
  * // Play attack animation 3 times
120
- * player.setAnimation('attack', 3);
125
+ * await player.setAnimation('attack', 3);
121
126
  *
122
127
  * // Play continuous spell animation
123
128
  * player.setAnimation('spell');
124
129
  * ```
125
130
  */
126
- setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): void;
131
+ setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;
127
132
  /**
128
133
  * Set a custom animation with temporary graphic change
129
134
  *
@@ -134,21 +139,32 @@ export declare abstract class RpgClientObject extends RpgCommonPlayer {
134
139
  * @param animationName - Name of the animation to play
135
140
  * @param graphic - The graphic(s) to temporarily use during the animation
136
141
  * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
142
+ * @param options - Restore and timeout options
143
+ * @returns A promise resolved when a finite animation finishes, is interrupted, or times out
137
144
  *
138
145
  * @example
139
146
  * ```ts
140
147
  * // Play attack animation with temporary graphic change
141
- * player.setAnimation('attack', 'hero_attack', 3);
148
+ * await player.setAnimation('attack', 'hero_attack', 3);
142
149
  * ```
143
150
  */
144
- setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): void;
151
+ setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;
145
152
  /**
146
153
  * Display a registered component animation effect on this object.
147
154
  *
148
155
  * @param id - Identifier of the component animation to play.
149
156
  * @param params - Parameters forwarded to the animation effect.
157
+ * @returns A promise resolved when the animation component calls `onFinish`.
150
158
  */
151
- showComponentAnimation(id: string, params: any): void;
159
+ showComponentAnimation(id: string, params: any): Promise<void>;
160
+ /**
161
+ * Display a registered spritesheet animation effect on this object.
162
+ *
163
+ * @param graphic - Identifier of the spritesheet to use.
164
+ * @param animationName - Name of the animation inside the spritesheet.
165
+ * @returns A promise resolved when the animation component calls `onFinish`.
166
+ */
167
+ showAnimation(graphic: string, animationName?: string): Promise<void>;
152
168
  /**
153
169
  * Check whether this client object represents an event.
154
170
  *
@@ -1,11 +1,11 @@
1
1
  import { inject } from "../core/inject.js";
2
- import component from "../components/dynamics/text.ce.js";
2
+ import __ce_component from "../components/dynamics/text.ce.js";
3
3
  import { RpgClientEngine } from "../RpgClientEngine.js";
4
4
  import { signal, trigger } from "canvasengine";
5
5
  import { ModulesToken, RpgCommonPlayer } from "@rpgjs/common";
6
6
  import { filter, from, map, of, switchMap } from "rxjs";
7
7
  //#region src/Game/Object.ts
8
- var DYNAMIC_COMPONENTS = { text: component };
8
+ var DYNAMIC_COMPONENTS = { text: __ce_component };
9
9
  var RpgClientObject = class extends RpgCommonPlayer {
10
10
  constructor() {
11
11
  super();
@@ -72,6 +72,11 @@ var RpgClientObject = class extends RpgCommonPlayer {
72
72
  this.animationResetTimeout = void 0;
73
73
  }
74
74
  }
75
+ resolveAnimationWait() {
76
+ const resolve = this.animationWaitResolve;
77
+ this.animationWaitResolve = void 0;
78
+ resolve?.();
79
+ }
75
80
  finishTemporaryAnimation() {
76
81
  const restoreState = this.animationRestoreState;
77
82
  this.clearAnimationControls();
@@ -82,6 +87,7 @@ var RpgClientObject = class extends RpgCommonPlayer {
82
87
  }
83
88
  this.animationRestoreState = void 0;
84
89
  this.animationIsPlaying.set(false);
90
+ this.resolveAnimationWait();
85
91
  }
86
92
  /**
87
93
  * Trigger a flash animation on this sprite
@@ -173,6 +179,7 @@ var RpgClientObject = class extends RpgCommonPlayer {
173
179
  this.animationIsPlaying.set(false);
174
180
  this.animationCurrentIndex.set(0);
175
181
  this.clearAnimationControls();
182
+ this.resolveAnimationWait();
176
183
  }
177
184
  setAnimation(animationName, graphicOrNbTimes, nbTimesOrOptions, options) {
178
185
  let graphic;
@@ -190,6 +197,9 @@ var RpgClientObject = class extends RpgCommonPlayer {
190
197
  }
191
198
  } else finalNbTimes = Infinity;
192
199
  if (this.animationIsPlaying()) this.finishTemporaryAnimation();
200
+ const waitPromise = finalNbTimes === Infinity ? Promise.resolve() : new Promise((resolve) => {
201
+ this.animationWaitResolve = resolve;
202
+ });
193
203
  this.animationIsPlaying.set(true);
194
204
  const previousAnimationName = restoreOptions?.restoreAnimationName ?? this.animationName();
195
205
  const previousGraphics = restoreOptions?.restoreGraphics ? [...restoreOptions.restoreGraphics] : [...this.graphics()];
@@ -206,17 +216,32 @@ var RpgClientObject = class extends RpgCommonPlayer {
206
216
  });
207
217
  if (finalNbTimes !== Infinity) this.animationResetTimeout = setTimeout(() => {
208
218
  if (this.animationIsPlaying()) this.finishTemporaryAnimation();
209
- }, Math.max(1e3, finalNbTimes * 1e3));
219
+ }, restoreOptions?.timeoutMs ?? Math.max(1e3, finalNbTimes * 1e3));
210
220
  this.animationName.set(animationName);
221
+ return waitPromise;
211
222
  }
212
223
  /**
213
224
  * Display a registered component animation effect on this object.
214
225
  *
215
226
  * @param id - Identifier of the component animation to play.
216
227
  * @param params - Parameters forwarded to the animation effect.
228
+ * @returns A promise resolved when the animation component calls `onFinish`.
217
229
  */
218
230
  showComponentAnimation(id, params) {
219
- inject(RpgClientEngine).getComponentAnimation(id).displayEffect(params, this);
231
+ return inject(RpgClientEngine).getComponentAnimation(id).displayEffect(params, this);
232
+ }
233
+ /**
234
+ * Display a registered spritesheet animation effect on this object.
235
+ *
236
+ * @param graphic - Identifier of the spritesheet to use.
237
+ * @param animationName - Name of the animation inside the spritesheet.
238
+ * @returns A promise resolved when the animation component calls `onFinish`.
239
+ */
240
+ showAnimation(graphic, animationName = "default") {
241
+ return this.showComponentAnimation("animation", {
242
+ graphic,
243
+ animationName
244
+ });
220
245
  }
221
246
  /**
222
247
  * Check whether this client object represents an event.
@@ -1 +1 @@
1
- {"version":3,"file":"Object.js","names":[],"sources":["../../src/Game/Object.ts"],"sourcesContent":["import { Hooks, ModulesToken, RpgCommonPlayer } from \"@rpgjs/common\";\nimport { trigger, signal, effect } from \"canvasengine\";\nimport { filter, from, map, of, Subscription, switchMap } from \"rxjs\";\nimport { inject } from \"../core/inject\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport TextComponent from \"../components/dynamics/text.ce\";\n\nconst DYNAMIC_COMPONENTS = {\n text: TextComponent,\n}\n\ntype Frame = { x: number; y: number; ts: number };\n\ntype AnimationRestoreOptions = {\n restoreAnimationName?: string;\n restoreGraphics?: any[];\n};\n\nexport abstract class RpgClientObject extends RpgCommonPlayer {\n abstract _type: string;\n emitParticleTrigger = trigger();\n particleName = signal(\"\");\n animationCurrentIndex = signal(0);\n animationIsPlaying = signal(false);\n _param = signal({});\n frames: Frame[] = [];\n graphicsSignals = signal<any[]>([]);\n _component = {} // temporary component memory\n flashTrigger = trigger();\n private animationRestoreState?: {\n animationName: string;\n graphics: any[];\n };\n\n constructor() {\n super();\n this.hooks.callHooks(\"client-sprite-onInit\", this).subscribe();\n\n this._frames.observable.subscribe(({ items }) => {\n if (!this.id) return;\n //if (this.id == this.engine.playerIdSignal()!) return;\n const nextFrames = items.flatMap((item): Frame[] =>\n Array.isArray(item) ? item : [item]\n );\n this.frames = [...this.frames, ...nextFrames];\n });\n\n this.graphics.observable\n .pipe(\n map(({ items }) => items),\n switchMap(graphics => {\n if (graphics.length === 0) return of([]);\n return from(Promise.all(graphics.map(graphic => this.engine.getSpriteSheet(graphic))));\n })\n )\n .subscribe((sheets) => { \n this.graphicsSignals.set(sheets);\n });\n\n this.componentsTop.observable\n .pipe(\n filter(value => value !== null && value !== undefined),\n map((value) => typeof value === 'string' ? JSON.parse(value) : value),\n )\n .subscribe(({components}) => {\n for (const component of components) {\n for (const [key, value] of Object.entries(component)) {\n this._component = value as any; // temporary component memory\n console.log(value)\n const type = (value as any).type as keyof typeof DYNAMIC_COMPONENTS;\n if (DYNAMIC_COMPONENTS[type]) {\n this.engine.addSpriteComponentInFront(DYNAMIC_COMPONENTS[type]);\n }\n }\n }\n });\n\n this.engine.tick\n .pipe\n //throttleTime(10)\n ()\n .subscribe(() => {\n const frame = this.frames.shift();\n if (frame) {\n if (typeof frame.x !== \"number\" || typeof frame.y !== \"number\") return;\n this.engine.scene.setBodyPosition(\n this.id,\n frame.x,\n frame.y,\n \"top-left\"\n );\n }\n });\n }\n\n /**\n * Access the shared client hook registry.\n *\n * @returns The hook service used to register and trigger client-side hooks.\n */\n get hooks() {\n return inject<Hooks>(ModulesToken);\n }\n\n /**\n * Access the current client engine instance.\n *\n * @returns The active {@link RpgClientEngine} instance.\n */\n get engine() {\n return inject(RpgClientEngine);\n }\n\n private animationSubscription?: Subscription;\n private animationResetTimeout?: ReturnType<typeof setTimeout>;\n\n private clearAnimationControls() {\n if (this.animationSubscription) {\n this.animationSubscription.unsubscribe();\n this.animationSubscription = undefined;\n }\n if (this.animationResetTimeout) {\n clearTimeout(this.animationResetTimeout);\n this.animationResetTimeout = undefined;\n }\n }\n\n private finishTemporaryAnimation() {\n const restoreState = this.animationRestoreState;\n this.clearAnimationControls();\n this.animationCurrentIndex.set(0);\n if (restoreState) {\n this.animationName.set(restoreState.animationName);\n this.graphics.set([...restoreState.graphics]);\n }\n this.animationRestoreState = undefined;\n this.animationIsPlaying.set(false);\n }\n\n /**\n * Trigger a flash animation on this sprite\n * \n * This method triggers a flash effect using CanvasEngine's flash directive.\n * The flash can be configured with various options including type (alpha, tint, or both),\n * duration, cycles, and color.\n * \n * ## Design\n * \n * The flash uses a trigger system that is connected to the flash directive in the\n * character component. This allows for flexible configuration and can be triggered\n * from both server events and client-side code.\n * \n * @param options - Flash configuration options\n * @param options.type - Type of flash effect: 'alpha' (opacity), 'tint' (color), or 'both' (default: 'alpha')\n * @param options.duration - Duration of the flash animation in milliseconds (default: 300)\n * @param options.cycles - Number of flash cycles (flash on/off) (default: 1)\n * @param options.alpha - Alpha value when flashing, from 0 to 1 (default: 0.3)\n * @param options.tint - Tint color when flashing as hex value or color name (default: 0xffffff - white)\n * \n * @example\n * ```ts\n * // Simple flash with default settings (alpha flash)\n * player.flash();\n * \n * // Flash with red tint\n * player.flash({ type: 'tint', tint: 0xff0000 });\n * \n * // Flash with both alpha and tint\n * player.flash({ \n * type: 'both', \n * alpha: 0.5, \n * tint: 0xff0000,\n * duration: 200,\n * cycles: 2\n * });\n * \n * // Quick damage flash\n * player.flash({ \n * type: 'tint', \n * tint: 0xff0000, \n * duration: 150,\n * cycles: 1\n * });\n * ```\n */\n flash(options?: {\n type?: 'alpha' | 'tint' | 'both';\n duration?: number;\n cycles?: number;\n alpha?: number;\n tint?: number | string;\n }): void {\n const flashOptions = {\n type: options?.type || 'alpha',\n duration: options?.duration ?? 300,\n cycles: options?.cycles ?? 1,\n alpha: options?.alpha ?? 0.3,\n tint: options?.tint ?? 0xffffff,\n };\n \n // Convert color name to hex if needed\n let tintValue = flashOptions.tint;\n if (typeof tintValue === 'string') {\n // Common color name to hex mapping\n const colorMap: Record<string, number> = {\n 'white': 0xffffff,\n 'red': 0xff0000,\n 'green': 0x00ff00,\n 'blue': 0x0000ff,\n 'yellow': 0xffff00,\n 'cyan': 0x00ffff,\n 'magenta': 0xff00ff,\n 'black': 0x000000,\n };\n tintValue = colorMap[tintValue.toLowerCase()] ?? 0xffffff;\n }\n \n this.flashTrigger.start({\n ...flashOptions,\n tint: tintValue,\n });\n }\n\n /**\n * Reset animation state when animation changes externally\n *\n * This method should be called when the animation changes due to movement\n * or other external factors to ensure the animation system doesn't get stuck\n *\n * @example\n * ```ts\n * // Reset when player starts moving\n * player.resetAnimationState();\n * ```\n */\n resetAnimationState() {\n if (this.animationRestoreState) {\n this.finishTemporaryAnimation();\n return;\n }\n this.animationIsPlaying.set(false);\n this.animationCurrentIndex.set(0);\n this.clearAnimationControls();\n }\n\n /**\n * Set a custom animation for a specific number of times\n *\n * Plays a custom animation for the specified number of repetitions.\n * The animation system prevents overlapping animations and automatically\n * returns to the previous animation when complete.\n *\n * @param animationName - Name of the animation to play\n * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)\n *\n * @example\n * ```ts\n * // Play attack animation 3 times\n * player.setAnimation('attack', 3);\n *\n * // Play continuous spell animation\n * player.setAnimation('spell');\n * ```\n */\n setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): void;\n /**\n * Set a custom animation with temporary graphic change\n *\n * Plays a custom animation for the specified number of repetitions and temporarily\n * changes the player's graphic (sprite sheet) during the animation. The graphic\n * is automatically reset when the animation finishes.\n *\n * @param animationName - Name of the animation to play\n * @param graphic - The graphic(s) to temporarily use during the animation\n * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)\n *\n * @example\n * ```ts\n * // Play attack animation with temporary graphic change\n * player.setAnimation('attack', 'hero_attack', 3);\n * ```\n */\n setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): void;\n setAnimation(\n animationName: string,\n graphicOrNbTimes?: string | string[] | number,\n nbTimesOrOptions?: number | AnimationRestoreOptions,\n options?: AnimationRestoreOptions\n ): void {\n let graphic: string | string[] | undefined;\n let finalNbTimes: number = Infinity;\n let restoreOptions: AnimationRestoreOptions | undefined = options;\n\n // Handle overloads\n if (typeof graphicOrNbTimes === 'number') {\n // setAnimation(animationName, nbTimes)\n finalNbTimes = graphicOrNbTimes;\n restoreOptions = typeof nbTimesOrOptions === 'object' ? nbTimesOrOptions : options;\n } else if (graphicOrNbTimes !== undefined) {\n // setAnimation(animationName, graphic, nbTimes)\n graphic = graphicOrNbTimes;\n if (typeof nbTimesOrOptions === 'number') {\n finalNbTimes = nbTimesOrOptions;\n } else {\n finalNbTimes = Infinity;\n restoreOptions = nbTimesOrOptions ?? options;\n }\n } else {\n // setAnimation(animationName) - nbTimes remains Infinity\n finalNbTimes = Infinity;\n }\n\n if (this.animationIsPlaying()) {\n this.finishTemporaryAnimation();\n }\n\n this.animationIsPlaying.set(true);\n const previousAnimationName =\n restoreOptions?.restoreAnimationName ?? this.animationName();\n const previousGraphics = restoreOptions?.restoreGraphics\n ? [...restoreOptions.restoreGraphics]\n : [...this.graphics()];\n this.animationRestoreState = {\n animationName: previousAnimationName,\n graphics: previousGraphics,\n };\n this.animationCurrentIndex.set(0);\n\n // Temporarily change graphic if provided\n if (graphic !== undefined) {\n if (Array.isArray(graphic)) {\n this.graphics.set(graphic);\n } else {\n this.graphics.set([graphic]);\n }\n }\n\n this.clearAnimationControls();\n\n this.animationSubscription =\n this.animationCurrentIndex.observable.subscribe((index) => {\n if (index >= finalNbTimes) {\n this.finishTemporaryAnimation();\n }\n });\n\n if (finalNbTimes !== Infinity) {\n this.animationResetTimeout = setTimeout(() => {\n if (this.animationIsPlaying()) {\n this.finishTemporaryAnimation();\n }\n }, Math.max(1000, finalNbTimes * 1000));\n }\n\n this.animationName.set(animationName);\n }\n\n /**\n * Display a registered component animation effect on this object.\n *\n * @param id - Identifier of the component animation to play.\n * @param params - Parameters forwarded to the animation effect.\n */\n showComponentAnimation(id: string, params: any) {\n const engine = inject(RpgClientEngine);\n engine.getComponentAnimation(id).displayEffect(params, this);\n }\n \n /**\n * Check whether this client object represents an event.\n *\n * @returns `true` if the object type is `event`, otherwise `false`.\n */\n isEvent(): boolean {\n return this._type === 'event';\n }\n\n /**\n * Check whether this client object represents a player.\n *\n * @returns `true` if the object type is `player`, otherwise `false`.\n */\n isPlayer(): boolean {\n return this._type === 'player';\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Object.js","names":[],"sources":["../../src/Game/Object.ts"],"sourcesContent":["import { Hooks, ModulesToken, RpgCommonPlayer } from \"@rpgjs/common\";\nimport { trigger, signal, effect } from \"canvasengine\";\nimport { filter, from, map, of, Subscription, switchMap } from \"rxjs\";\nimport { inject } from \"../core/inject\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport TextComponent from \"../components/dynamics/text.ce\";\n\nconst DYNAMIC_COMPONENTS = {\n text: TextComponent,\n}\n\ntype Frame = { x: number; y: number; ts: number };\n\ntype AnimationRestoreOptions = {\n restoreAnimationName?: string;\n restoreGraphics?: any[];\n timeoutMs?: number;\n};\n\nexport abstract class RpgClientObject extends RpgCommonPlayer {\n abstract _type: string;\n emitParticleTrigger = trigger();\n particleName = signal(\"\");\n animationCurrentIndex = signal(0);\n animationIsPlaying = signal(false);\n _param = signal({});\n frames: Frame[] = [];\n graphicsSignals = signal<any[]>([]);\n _component = {} // temporary component memory\n flashTrigger = trigger();\n private animationRestoreState?: {\n animationName: string;\n graphics: any[];\n };\n\n constructor() {\n super();\n this.hooks.callHooks(\"client-sprite-onInit\", this).subscribe();\n\n this._frames.observable.subscribe(({ items }) => {\n if (!this.id) return;\n //if (this.id == this.engine.playerIdSignal()!) return;\n const nextFrames = items.flatMap((item): Frame[] =>\n Array.isArray(item) ? item : [item]\n );\n this.frames = [...this.frames, ...nextFrames];\n });\n\n this.graphics.observable\n .pipe(\n map(({ items }) => items),\n switchMap(graphics => {\n if (graphics.length === 0) return of([]);\n return from(Promise.all(graphics.map(graphic => this.engine.getSpriteSheet(graphic))));\n })\n )\n .subscribe((sheets) => { \n this.graphicsSignals.set(sheets);\n });\n\n this.componentsTop.observable\n .pipe(\n filter(value => value !== null && value !== undefined),\n map((value) => typeof value === 'string' ? JSON.parse(value) : value),\n )\n .subscribe(({components}) => {\n for (const component of components) {\n for (const [key, value] of Object.entries(component)) {\n this._component = value as any; // temporary component memory\n console.log(value)\n const type = (value as any).type as keyof typeof DYNAMIC_COMPONENTS;\n if (DYNAMIC_COMPONENTS[type]) {\n this.engine.addSpriteComponentInFront(DYNAMIC_COMPONENTS[type]);\n }\n }\n }\n });\n\n this.engine.tick\n .pipe\n //throttleTime(10)\n ()\n .subscribe(() => {\n const frame = this.frames.shift();\n if (frame) {\n if (typeof frame.x !== \"number\" || typeof frame.y !== \"number\") return;\n this.engine.scene.setBodyPosition(\n this.id,\n frame.x,\n frame.y,\n \"top-left\"\n );\n }\n });\n }\n\n /**\n * Access the shared client hook registry.\n *\n * @returns The hook service used to register and trigger client-side hooks.\n */\n get hooks() {\n return inject<Hooks>(ModulesToken);\n }\n\n /**\n * Access the current client engine instance.\n *\n * @returns The active {@link RpgClientEngine} instance.\n */\n get engine() {\n return inject(RpgClientEngine);\n }\n\n private animationSubscription?: Subscription;\n private animationResetTimeout?: ReturnType<typeof setTimeout>;\n private animationWaitResolve?: () => void;\n\n private clearAnimationControls() {\n if (this.animationSubscription) {\n this.animationSubscription.unsubscribe();\n this.animationSubscription = undefined;\n }\n if (this.animationResetTimeout) {\n clearTimeout(this.animationResetTimeout);\n this.animationResetTimeout = undefined;\n }\n }\n\n private resolveAnimationWait() {\n const resolve = this.animationWaitResolve;\n this.animationWaitResolve = undefined;\n resolve?.();\n }\n\n private finishTemporaryAnimation() {\n const restoreState = this.animationRestoreState;\n this.clearAnimationControls();\n this.animationCurrentIndex.set(0);\n if (restoreState) {\n this.animationName.set(restoreState.animationName);\n this.graphics.set([...restoreState.graphics]);\n }\n this.animationRestoreState = undefined;\n this.animationIsPlaying.set(false);\n this.resolveAnimationWait();\n }\n\n /**\n * Trigger a flash animation on this sprite\n * \n * This method triggers a flash effect using CanvasEngine's flash directive.\n * The flash can be configured with various options including type (alpha, tint, or both),\n * duration, cycles, and color.\n * \n * ## Design\n * \n * The flash uses a trigger system that is connected to the flash directive in the\n * character component. This allows for flexible configuration and can be triggered\n * from both server events and client-side code.\n * \n * @param options - Flash configuration options\n * @param options.type - Type of flash effect: 'alpha' (opacity), 'tint' (color), or 'both' (default: 'alpha')\n * @param options.duration - Duration of the flash animation in milliseconds (default: 300)\n * @param options.cycles - Number of flash cycles (flash on/off) (default: 1)\n * @param options.alpha - Alpha value when flashing, from 0 to 1 (default: 0.3)\n * @param options.tint - Tint color when flashing as hex value or color name (default: 0xffffff - white)\n * \n * @example\n * ```ts\n * // Simple flash with default settings (alpha flash)\n * player.flash();\n * \n * // Flash with red tint\n * player.flash({ type: 'tint', tint: 0xff0000 });\n * \n * // Flash with both alpha and tint\n * player.flash({ \n * type: 'both', \n * alpha: 0.5, \n * tint: 0xff0000,\n * duration: 200,\n * cycles: 2\n * });\n * \n * // Quick damage flash\n * player.flash({ \n * type: 'tint', \n * tint: 0xff0000, \n * duration: 150,\n * cycles: 1\n * });\n * ```\n */\n flash(options?: {\n type?: 'alpha' | 'tint' | 'both';\n duration?: number;\n cycles?: number;\n alpha?: number;\n tint?: number | string;\n }): void {\n const flashOptions = {\n type: options?.type || 'alpha',\n duration: options?.duration ?? 300,\n cycles: options?.cycles ?? 1,\n alpha: options?.alpha ?? 0.3,\n tint: options?.tint ?? 0xffffff,\n };\n \n // Convert color name to hex if needed\n let tintValue = flashOptions.tint;\n if (typeof tintValue === 'string') {\n // Common color name to hex mapping\n const colorMap: Record<string, number> = {\n 'white': 0xffffff,\n 'red': 0xff0000,\n 'green': 0x00ff00,\n 'blue': 0x0000ff,\n 'yellow': 0xffff00,\n 'cyan': 0x00ffff,\n 'magenta': 0xff00ff,\n 'black': 0x000000,\n };\n tintValue = colorMap[tintValue.toLowerCase()] ?? 0xffffff;\n }\n \n this.flashTrigger.start({\n ...flashOptions,\n tint: tintValue,\n });\n }\n\n /**\n * Reset animation state when animation changes externally\n *\n * This method should be called when the animation changes due to movement\n * or other external factors to ensure the animation system doesn't get stuck\n *\n * @example\n * ```ts\n * // Reset when player starts moving\n * player.resetAnimationState();\n * ```\n */\n resetAnimationState() {\n if (this.animationRestoreState) {\n this.finishTemporaryAnimation();\n return;\n }\n this.animationIsPlaying.set(false);\n this.animationCurrentIndex.set(0);\n this.clearAnimationControls();\n this.resolveAnimationWait();\n }\n\n /**\n * Set a custom animation for a specific number of times\n *\n * Plays a custom animation for the specified number of repetitions.\n * The animation system prevents overlapping animations and automatically\n * returns to the previous animation when complete.\n *\n * @param animationName - Name of the animation to play\n * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)\n * @param options - Restore and timeout options\n * @returns A promise resolved when a finite animation finishes, is interrupted, or times out\n *\n * @example\n * ```ts\n * // Play attack animation 3 times\n * await player.setAnimation('attack', 3);\n *\n * // Play continuous spell animation\n * player.setAnimation('spell');\n * ```\n */\n setAnimation(animationName: string, nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;\n /**\n * Set a custom animation with temporary graphic change\n *\n * Plays a custom animation for the specified number of repetitions and temporarily\n * changes the player's graphic (sprite sheet) during the animation. The graphic\n * is automatically reset when the animation finishes.\n *\n * @param animationName - Name of the animation to play\n * @param graphic - The graphic(s) to temporarily use during the animation\n * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)\n * @param options - Restore and timeout options\n * @returns A promise resolved when a finite animation finishes, is interrupted, or times out\n *\n * @example\n * ```ts\n * // Play attack animation with temporary graphic change\n * await player.setAnimation('attack', 'hero_attack', 3);\n * ```\n */\n setAnimation(animationName: string, graphic?: string | string[], nbTimes?: number, options?: AnimationRestoreOptions): Promise<void>;\n setAnimation(\n animationName: string,\n graphicOrNbTimes?: string | string[] | number,\n nbTimesOrOptions?: number | AnimationRestoreOptions,\n options?: AnimationRestoreOptions\n ): Promise<void> {\n let graphic: string | string[] | undefined;\n let finalNbTimes: number = Infinity;\n let restoreOptions: AnimationRestoreOptions | undefined = options;\n\n // Handle overloads\n if (typeof graphicOrNbTimes === 'number') {\n // setAnimation(animationName, nbTimes)\n finalNbTimes = graphicOrNbTimes;\n restoreOptions = typeof nbTimesOrOptions === 'object' ? nbTimesOrOptions : options;\n } else if (graphicOrNbTimes !== undefined) {\n // setAnimation(animationName, graphic, nbTimes)\n graphic = graphicOrNbTimes;\n if (typeof nbTimesOrOptions === 'number') {\n finalNbTimes = nbTimesOrOptions;\n } else {\n finalNbTimes = Infinity;\n restoreOptions = nbTimesOrOptions ?? options;\n }\n } else {\n // setAnimation(animationName) - nbTimes remains Infinity\n finalNbTimes = Infinity;\n }\n\n if (this.animationIsPlaying()) {\n this.finishTemporaryAnimation();\n }\n\n const waitPromise =\n finalNbTimes === Infinity\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n this.animationWaitResolve = resolve;\n });\n\n this.animationIsPlaying.set(true);\n const previousAnimationName =\n restoreOptions?.restoreAnimationName ?? this.animationName();\n const previousGraphics = restoreOptions?.restoreGraphics\n ? [...restoreOptions.restoreGraphics]\n : [...this.graphics()];\n this.animationRestoreState = {\n animationName: previousAnimationName,\n graphics: previousGraphics,\n };\n this.animationCurrentIndex.set(0);\n\n // Temporarily change graphic if provided\n if (graphic !== undefined) {\n if (Array.isArray(graphic)) {\n this.graphics.set(graphic);\n } else {\n this.graphics.set([graphic]);\n }\n }\n\n this.clearAnimationControls();\n\n this.animationSubscription =\n this.animationCurrentIndex.observable.subscribe((index) => {\n if (index >= finalNbTimes) {\n this.finishTemporaryAnimation();\n }\n });\n\n if (finalNbTimes !== Infinity) {\n this.animationResetTimeout = setTimeout(() => {\n if (this.animationIsPlaying()) {\n this.finishTemporaryAnimation();\n }\n }, restoreOptions?.timeoutMs ?? Math.max(1000, finalNbTimes * 1000));\n }\n\n this.animationName.set(animationName);\n\n return waitPromise;\n }\n\n /**\n * Display a registered component animation effect on this object.\n *\n * @param id - Identifier of the component animation to play.\n * @param params - Parameters forwarded to the animation effect.\n * @returns A promise resolved when the animation component calls `onFinish`.\n */\n showComponentAnimation(id: string, params: any): Promise<void> {\n const engine = inject(RpgClientEngine);\n return engine.getComponentAnimation(id).displayEffect(params, this);\n }\n\n /**\n * Display a registered spritesheet animation effect on this object.\n *\n * @param graphic - Identifier of the spritesheet to use.\n * @param animationName - Name of the animation inside the spritesheet.\n * @returns A promise resolved when the animation component calls `onFinish`.\n */\n showAnimation(graphic: string, animationName: string = 'default'): Promise<void> {\n return this.showComponentAnimation('animation', {\n graphic,\n animationName,\n });\n }\n \n /**\n * Check whether this client object represents an event.\n *\n * @returns `true` if the object type is `event`, otherwise `false`.\n */\n isEvent(): boolean {\n return this._type === 'event';\n }\n\n /**\n * Check whether this client object represents a player.\n *\n * @returns `true` if the object type is `player`, otherwise `false`.\n */\n isPlayer(): boolean {\n return this._type === 'player';\n }\n}\n"],"mappings":"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"}
package/dist/Gui/Gui.d.ts CHANGED
@@ -45,7 +45,7 @@ type OptimisticReducer = (data: any, action: GuiAction) => any;
45
45
  export declare class RpgGui {
46
46
  private context;
47
47
  private webSocket;
48
- gui: import('canvasengine').WritableObjectSignal<Record<string, GuiInstance>>;
48
+ gui: any;
49
49
  extraGuis: GuiInstance[];
50
50
  private vueGuiInstance;
51
51
  private optimisticReducers;
@@ -54,7 +54,7 @@ export declare class RpgGui {
54
54
  * Signal tracking which player IDs should display attached GUIs
55
55
  * Key: player ID, Value: boolean (true = show, false = hide)
56
56
  */
57
- attachedGuiDisplayState: import('canvasengine').WritableObjectSignal<Record<string, boolean>>;
57
+ attachedGuiDisplayState: any;
58
58
  constructor(context: Context);
59
59
  _initialize(): Promise<void>;
60
60
  /**
package/dist/Gui/Gui.js CHANGED
@@ -1,12 +1,12 @@
1
- import { inject } from "../node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js";
1
+ import { inject } from "../node_modules/.pnpm/@signe_di@2.10.0/node_modules/@signe/di/dist/index.js";
2
2
  import { WebSocketToken } from "../services/AbstractSocket.js";
3
- import component from "../components/gui/dialogbox/index.ce.js";
4
- import component$1 from "../components/gui/shop/shop.ce.js";
5
- import component$2 from "../components/gui/save-load.ce.js";
6
- import component$3 from "../components/gui/menu/main-menu.ce.js";
7
- import component$4 from "../components/gui/notification/notification.ce.js";
8
- import component$5 from "../components/gui/title-screen.ce.js";
9
- import component$6 from "../components/gui/gameover.ce.js";
3
+ import __ce_component from "../components/gui/dialogbox/index.ce.js";
4
+ import __ce_component$1 from "../components/gui/shop/shop.ce.js";
5
+ import __ce_component$2 from "../components/gui/save-load.ce.js";
6
+ import __ce_component$3 from "../components/gui/menu/main-menu.ce.js";
7
+ import __ce_component$4 from "../components/gui/notification/notification.ce.js";
8
+ import __ce_component$5 from "../components/gui/title-screen.ce.js";
9
+ import __ce_component$6 from "../components/gui/gameover.ce.js";
10
10
  import "../components/gui/index.js";
11
11
  import { signal } from "canvasengine";
12
12
  import { PrebuiltGui } from "@rpgjs/common";
@@ -86,32 +86,32 @@ var RpgGui = class {
86
86
  this.webSocket = inject(context, WebSocketToken);
87
87
  this.add({
88
88
  name: "rpg-dialog",
89
- component
89
+ component: __ce_component
90
90
  });
91
91
  this.add({
92
92
  name: PrebuiltGui.MainMenu,
93
- component: component$3
93
+ component: __ce_component$3
94
94
  });
95
95
  this.add({
96
96
  name: PrebuiltGui.Shop,
97
- component: component$1
97
+ component: __ce_component$1
98
98
  });
99
99
  this.add({
100
100
  name: PrebuiltGui.Notification,
101
- component: component$4,
101
+ component: __ce_component$4,
102
102
  autoDisplay: true
103
103
  });
104
104
  this.add({
105
105
  name: PrebuiltGui.Save,
106
- component: component$2
106
+ component: __ce_component$2
107
107
  });
108
108
  this.add({
109
109
  name: PrebuiltGui.TitleScreen,
110
- component: component$5
110
+ component: __ce_component$5
111
111
  });
112
112
  this.add({
113
113
  name: PrebuiltGui.Gameover,
114
- component: component$6
114
+ component: __ce_component$6
115
115
  });
116
116
  this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);
117
117
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Gui.js","names":[],"sources":["../../src/Gui/Gui.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { signal, Signal, WritableSignal } from \"canvasengine\";\nimport { AbstractWebsocket, WebSocketToken } from \"../services/AbstractSocket\";\nimport { DialogboxComponent, ShopComponent, SaveLoadComponent, MainMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent } from \"../components/gui\";\nimport { combineLatest, Subscription } from \"rxjs\";\nimport { delay, PrebuiltGui } from \"@rpgjs/common\";\n\ninterface GuiOptions {\n name?: string;\n id?: string;\n component: any;\n display?: boolean;\n data?: any;\n /**\n * Auto display the GUI when added to the system\n * @default false\n */\n autoDisplay?: boolean;\n /**\n * Function that returns an array of Signal dependencies\n * The GUI will only display when all dependencies are resolved (!= undefined)\n * @returns Array of Signal dependencies\n */\n dependencies?: () => Signal[];\n /**\n * Attach the GUI to sprites instead of displaying globally\n * When true, the GUI will be rendered in character.ce for each sprite\n * @default false\n */\n attachToSprite?: boolean;\n}\n\ninterface GuiInstance {\n name: string;\n component: any;\n display: WritableSignal<boolean>;\n data: WritableSignal<any>;\n autoDisplay: boolean;\n dependencies?: () => Signal[];\n subscription?: Subscription;\n attachToSprite?: boolean;\n}\n\ninterface GuiAction {\n guiId: string;\n name: string;\n data: any;\n clientActionId: string;\n}\n\ntype OptimisticReducer = (data: any, action: GuiAction) => any;\n\nconst throwError = (id: string) => {\n throw `The GUI named ${id} is non-existent. Please add the component in the gui property of the decorator @RpgClient`;\n};\n\nconst updateItemQuantity = (items: any[], id: string) => {\n const index = items.findIndex((item) => item?.id === id);\n if (index === -1) return items;\n const item = items[index];\n if (item?.usable === false) return items;\n if (item?.consumable === false) return items;\n const quantity = typeof item?.quantity === \"number\" ? item.quantity : 1;\n const nextQuantity = Math.max(0, quantity - 1);\n if (nextQuantity === quantity) return items;\n if (nextQuantity <= 0) {\n return items.filter((_, idx) => idx !== index);\n }\n const nextItems = items.slice();\n nextItems[index] = { ...item, quantity: nextQuantity };\n return nextItems;\n};\n\nconst updateEquippedFlag = (items: any[], id: string, equip: boolean) => {\n const index = items.findIndex((item) => item?.id === id);\n if (index === -1) return items;\n const item = items[index];\n if (item?.equipped === equip) return items;\n const nextItems = items.slice();\n nextItems[index] = { ...item, equipped: equip };\n return nextItems;\n};\n\nconst mainMenuOptimisticReducer: OptimisticReducer = (data, action) => {\n if (!data || typeof data !== \"object\") return data;\n if (action.name === \"useItem\") {\n if (!Array.isArray(data.items)) return data;\n const id = action.data?.id;\n if (!id) return data;\n const nextItems = updateItemQuantity(data.items, id);\n if (nextItems === data.items) return data;\n return { ...data, items: nextItems };\n }\n if (action.name === \"equipItem\") {\n const id = action.data?.id;\n if (!id || typeof action.data?.equip !== \"boolean\") return data;\n const equip = action.data.equip;\n let nextItems = data.items;\n let nextEquips = data.equips;\n if (Array.isArray(data.items)) {\n nextItems = updateEquippedFlag(data.items, id, equip);\n }\n if (Array.isArray(data.equips)) {\n nextEquips = updateEquippedFlag(data.equips, id, equip);\n }\n if (nextItems === data.items && nextEquips === data.equips) return data;\n return {\n ...data,\n ...(nextItems !== data.items ? { items: nextItems } : {}),\n ...(nextEquips !== data.equips ? { equips: nextEquips } : {})\n };\n }\n return data;\n};\n\nexport class RpgGui {\n private webSocket: AbstractWebsocket;\n gui = signal<Record<string, GuiInstance>>({});\n extraGuis: GuiInstance[] = [];\n private vueGuiInstance: any = null; // Reference to VueGui instance\n private optimisticReducers = new Map<string, OptimisticReducer[]>();\n private pendingActions = new Map<string, GuiAction[]>();\n /**\n * Signal tracking which player IDs should display attached GUIs\n * Key: player ID, Value: boolean (true = show, false = hide)\n */\n attachedGuiDisplayState = signal<Record<string, boolean>>({});\n\n constructor(private context: Context) {\n this.webSocket = inject(context, WebSocketToken);\n this.add({\n name: \"rpg-dialog\",\n component: DialogboxComponent,\n });\n this.add({\n name: PrebuiltGui.MainMenu,\n component: MainMenuComponent,\n });\n this.add({\n name: PrebuiltGui.Shop,\n component: ShopComponent,\n });\n this.add({\n name: PrebuiltGui.Notification,\n component: NotificationComponent,\n autoDisplay: true,\n });\n this.add({\n name: PrebuiltGui.Save,\n component: SaveLoadComponent,\n });\n this.add({\n name: PrebuiltGui.TitleScreen,\n component: TitleScreenComponent,\n });\n this.add({\n name: PrebuiltGui.Gameover,\n component: GameoverComponent,\n });\n\n this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);\n }\n\n async _initialize() {\n this.webSocket.on(\"gui.open\", (data: { guiId: string; data: any }) => {\n this.clearPendingActions(data.guiId);\n this.display(data.guiId, data.data);\n });\n\n this.webSocket.on(\"gui.exit\", (guiId: string) => {\n this.hide(guiId);\n });\n\n this.webSocket.on(\"gui.update\", (payload: { guiId: string; data: any; clientActionId?: string }) => {\n this.applyServerUpdate(payload.guiId, payload.data, payload.clientActionId);\n });\n\n /**\n * Listen for tooltip display state changes from server\n * This is triggered by showAttachedGui/hideAttachedGui on the server\n */\n this.webSocket.on(\"gui.tooltip\", (data: { players: string[]; display: boolean }) => {\n const currentState = { ...this.attachedGuiDisplayState() };\n data.players.forEach((playerId) => {\n currentState[playerId] = data.display;\n });\n this.attachedGuiDisplayState.set(currentState);\n });\n }\n\n /**\n * Set the VueGui instance reference for Vue component management\n * This is called by VueGui when it's initialized\n * \n * @param vueGuiInstance - The VueGui instance\n */\n _setVueGuiInstance(vueGuiInstance: any) {\n this.vueGuiInstance = vueGuiInstance;\n }\n\n /**\n * Notify VueGui about GUI state changes\n * This synchronizes the Vue component display state\n * \n * @param guiId - The GUI component ID\n * @param display - Display state\n * @param data - Component data\n */\n private _notifyVueGui(guiId: string, display: boolean, data: any = {}) {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Find the GUI in extraGuis\n const extraGui = this.extraGuis.find(gui => gui.name === guiId);\n if (extraGui) {\n // Update the Vue component's display state and data\n this.vueGuiInstance.vm.gui[guiId] = {\n name: guiId,\n display,\n data,\n attachToSprite: extraGui.attachToSprite || false\n };\n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n }\n\n /**\n * Initialize Vue components in the VueGui instance\n * This should be called after VueGui is mounted\n */\n _initializeVueComponents() {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Initialize all extraGuis in the Vue instance\n this.extraGuis.forEach(gui => {\n this.vueGuiInstance.vm.gui[gui.name] = {\n name: gui.name,\n display: gui.display(),\n data: gui.data(),\n attachToSprite: gui.attachToSprite || false\n };\n });\n \n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n\n guiInteraction(guiId: string, name: string, data: any) {\n const clientActionId = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;\n const actionData = { ...(data || {}), clientActionId };\n this.applyOptimisticAction({\n guiId,\n name,\n data: actionData,\n clientActionId\n });\n this.webSocket.emit(\"gui.interaction\", {\n guiId,\n name,\n data: actionData,\n });\n }\n\n guiClose(guiId: string, data?: any) {\n this.webSocket.emit(\"gui.exit\", {\n guiId,\n data,\n });\n }\n\n /**\n * Add a GUI component to the system\n * \n * By default, only CanvasEngine components (.ce files) are accepted.\n * Vue components should be handled by the @rpgjs/vue package.\n * \n * @param gui - GUI configuration options\n * @param gui.name - Name or ID of the GUI component\n * @param gui.id - Alternative ID if name is not provided\n * @param gui.component - The component to render (must be a CanvasEngine component)\n * @param gui.display - Initial display state (default: false)\n * @param gui.data - Initial data for the component\n * @param gui.autoDisplay - Auto display when added (default: false)\n * @param gui.dependencies - Function returning Signal dependencies\n * @param gui.attachToSprite - Attach GUI to sprites instead of global display (default: false)\n * \n * @example\n * ```ts\n * gui.add({\n * name: 'inventory',\n * component: InventoryComponent, // Must be a .ce component\n * autoDisplay: true,\n * dependencies: () => [playerSignal, inventorySignal]\n * });\n * \n * // Attach to sprites\n * gui.add({\n * name: 'tooltip',\n * component: TooltipComponent,\n * attachToSprite: true\n * });\n * ```\n */\n add(gui: GuiOptions) {\n const guiId = gui.name || gui.id;\n if (!guiId) {\n throw new Error(\"GUI must have a name or id\");\n }\n const guiInstance: GuiInstance = {\n name: guiId,\n component: gui.component,\n display: signal(gui.display || false),\n data: signal(gui.data || {}),\n autoDisplay: gui.autoDisplay || false,\n dependencies: gui.dependencies ? gui.dependencies() : [],\n attachToSprite: gui.attachToSprite || false,\n };\n\n // Accept both CanvasEngine components (.ce) and Vue components\n // Vue components will be handled by VueGui if available\n if (typeof gui.component !== 'function') {\n guiInstance.component = gui;\n this.extraGuis.push(guiInstance);\n \n // Auto display Vue components if enabled\n if (guiInstance.autoDisplay) {\n this._notifyVueGui(guiId, true, gui.data || {});\n }\n return;\n }\n\n this.gui()[guiId] = guiInstance;\n\n // Auto display if enabled and it's a CanvasEngine component\n if (guiInstance.autoDisplay && typeof gui.component === 'function') {\n this.display(guiId, gui.data);\n }\n }\n\n registerOptimisticReducer(guiId: string, reducer: OptimisticReducer) {\n const existing = this.optimisticReducers.get(guiId) || [];\n this.optimisticReducers.set(guiId, existing.concat(reducer));\n }\n\n /**\n * Get all attached GUI components (attachToSprite: true)\n * \n * Returns all GUI instances that are configured to be attached to sprites.\n * These GUIs should be rendered in character.ce instead of canvas.ce.\n * \n * @returns Array of GUI instances with attachToSprite: true\n * \n * @example\n * ```ts\n * const attachedGuis = gui.getAttachedGuis();\n * // Use in character.ce to render tooltips\n * ```\n */\n getAttachedGuis(): GuiInstance[] {\n const allGuis = this.getAll();\n return Object.values(allGuis).filter(gui => gui.attachToSprite === true);\n }\n\n /**\n * Check if a player should display attached GUIs\n * \n * @param playerId - The player ID to check\n * @returns true if attached GUIs should be displayed for this player\n */\n shouldDisplayAttachedGui(playerId: string): boolean {\n return this.attachedGuiDisplayState()[playerId] === true;\n }\n\n get(id: string): GuiInstance | undefined {\n // Check CanvasEngine GUIs first\n const canvasGui = this.gui()[id];\n if (canvasGui) {\n return canvasGui;\n }\n \n // Check Vue GUIs in extraGuis\n return this.extraGuis.find(gui => gui.name === id);\n }\n\n exists(id: string): boolean {\n return !!this.get(id);\n }\n\n getAll(): Record<string, GuiInstance> {\n const allGuis = { ...this.gui() };\n \n // Add extraGuis to the result\n this.extraGuis.forEach(gui => {\n allGuis[gui.name] = gui;\n });\n \n return allGuis;\n }\n\n /**\n * Display a GUI component\n * \n * Displays the GUI immediately if no dependencies are configured,\n * or waits for all dependencies to be resolved if dependencies are present.\n * Automatically manages subscriptions to prevent memory leaks.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * @param data - Data to pass to the component\n * @param dependencies - Optional runtime dependencies (overrides config dependencies)\n * \n * @example\n * ```ts\n * // Display immediately\n * gui.display('inventory', { items: [] });\n * \n * // Display with runtime dependencies\n * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);\n * ```\n */\n display(id: string, data = {}, dependencies: Signal[] = []) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Check if it's a Vue component (in extraGuis)\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n \n if (isVueComponent) {\n // Handle Vue component display\n this._handleVueComponentDisplay(id, data, dependencies, guiInstance);\n } else {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n }\n }\n\n isDisplaying(id: string): boolean {\n const guiInstance = this.get(id);\n if (!guiInstance) return false;\n return guiInstance.display();\n }\n\n /**\n * Handle Vue component display logic\n * \n * @param id - GUI component ID\n * @param data - Component data\n * @param dependencies - Runtime dependencies\n * @param guiInstance - GUI instance\n */\n private _handleVueComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {\n // Unsubscribe from previous subscription if exists\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n // Use runtime dependencies or config dependencies\n const deps = dependencies.length > 0 \n ? dependencies \n : (guiInstance.dependencies ? guiInstance.dependencies() : []);\n\n if (deps.length > 0) {\n // Subscribe to dependencies\n guiInstance.subscription = combineLatest(\n deps.map(dependency => dependency.observable)\n ).subscribe((values) => {\n if (values.every(value => value !== undefined)) {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n });\n return;\n }\n\n // No dependencies, display immediately\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n\n /**\n * Hide a GUI component\n * \n * Hides the GUI and cleans up any active subscriptions.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * \n * @example\n * ```ts\n * gui.hide('inventory');\n * ```\n */\n hide(id: string) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Unsubscribe if there's an active subscription\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n guiInstance.display.set(false)\n \n // Check if it's a Vue component and notify VueGui\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n if (isVueComponent) {\n this._notifyVueGui(id, false);\n }\n }\n\n private isVueComponent(id: string) {\n return this.extraGuis.some(gui => gui.name === id);\n }\n\n private clearPendingActions(guiId: string) {\n this.pendingActions.delete(guiId);\n }\n\n private applyReducers(guiId: string, data: any, actions: GuiAction[]) {\n const reducers = this.optimisticReducers.get(guiId);\n if (!reducers || reducers.length === 0) return data;\n let next = data;\n for (const action of actions) {\n for (const reducer of reducers) {\n const updated = reducer(next, action);\n if (updated !== undefined && updated !== null && updated !== next) {\n next = updated;\n }\n }\n }\n return next;\n }\n\n private applyOptimisticAction(action: GuiAction) {\n const guiInstance = this.get(action.guiId);\n if (!guiInstance) return;\n const reducers = this.optimisticReducers.get(action.guiId);\n if (!reducers || reducers.length === 0) return;\n const currentData = guiInstance.data();\n const nextData = this.applyReducers(action.guiId, currentData, [action]);\n if (nextData === currentData) return;\n guiInstance.data.set(nextData);\n const pending = this.pendingActions.get(action.guiId) || [];\n pending.push(action);\n this.pendingActions.set(action.guiId, pending);\n if (this.isVueComponent(action.guiId)) {\n this._notifyVueGui(action.guiId, guiInstance.display(), nextData);\n }\n }\n\n private applyServerUpdate(guiId: string, data: any, clientActionId?: string) {\n const guiInstance = this.get(guiId);\n if (!guiInstance) return;\n let pending = this.pendingActions.get(guiId) || [];\n if (clientActionId) {\n pending = pending.filter(action => action.clientActionId !== clientActionId);\n } else {\n pending = [];\n }\n let nextData = data;\n if (pending.length) {\n nextData = this.applyReducers(guiId, nextData, pending);\n }\n guiInstance.data.set(nextData);\n this.pendingActions.set(guiId, pending);\n if (this.isVueComponent(guiId)) {\n this._notifyVueGui(guiId, guiInstance.display(), nextData);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Gui.js","names":[],"sources":["../../src/Gui/Gui.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { signal, Signal, WritableSignal } from \"canvasengine\";\nimport { AbstractWebsocket, WebSocketToken } from \"../services/AbstractSocket\";\nimport { DialogboxComponent, ShopComponent, SaveLoadComponent, MainMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent } from \"../components/gui\";\nimport { combineLatest, Subscription } from \"rxjs\";\nimport { delay, PrebuiltGui } from \"@rpgjs/common\";\n\ninterface GuiOptions {\n name?: string;\n id?: string;\n component: any;\n display?: boolean;\n data?: any;\n /**\n * Auto display the GUI when added to the system\n * @default false\n */\n autoDisplay?: boolean;\n /**\n * Function that returns an array of Signal dependencies\n * The GUI will only display when all dependencies are resolved (!= undefined)\n * @returns Array of Signal dependencies\n */\n dependencies?: () => Signal[];\n /**\n * Attach the GUI to sprites instead of displaying globally\n * When true, the GUI will be rendered in character.ce for each sprite\n * @default false\n */\n attachToSprite?: boolean;\n}\n\ninterface GuiInstance {\n name: string;\n component: any;\n display: WritableSignal<boolean>;\n data: WritableSignal<any>;\n autoDisplay: boolean;\n dependencies?: () => Signal[];\n subscription?: Subscription;\n attachToSprite?: boolean;\n}\n\ninterface GuiAction {\n guiId: string;\n name: string;\n data: any;\n clientActionId: string;\n}\n\ntype OptimisticReducer = (data: any, action: GuiAction) => any;\n\nconst throwError = (id: string) => {\n throw `The GUI named ${id} is non-existent. Please add the component in the gui property of the decorator @RpgClient`;\n};\n\nconst updateItemQuantity = (items: any[], id: string) => {\n const index = items.findIndex((item) => item?.id === id);\n if (index === -1) return items;\n const item = items[index];\n if (item?.usable === false) return items;\n if (item?.consumable === false) return items;\n const quantity = typeof item?.quantity === \"number\" ? item.quantity : 1;\n const nextQuantity = Math.max(0, quantity - 1);\n if (nextQuantity === quantity) return items;\n if (nextQuantity <= 0) {\n return items.filter((_, idx) => idx !== index);\n }\n const nextItems = items.slice();\n nextItems[index] = { ...item, quantity: nextQuantity };\n return nextItems;\n};\n\nconst updateEquippedFlag = (items: any[], id: string, equip: boolean) => {\n const index = items.findIndex((item) => item?.id === id);\n if (index === -1) return items;\n const item = items[index];\n if (item?.equipped === equip) return items;\n const nextItems = items.slice();\n nextItems[index] = { ...item, equipped: equip };\n return nextItems;\n};\n\nconst mainMenuOptimisticReducer: OptimisticReducer = (data, action) => {\n if (!data || typeof data !== \"object\") return data;\n if (action.name === \"useItem\") {\n if (!Array.isArray(data.items)) return data;\n const id = action.data?.id;\n if (!id) return data;\n const nextItems = updateItemQuantity(data.items, id);\n if (nextItems === data.items) return data;\n return { ...data, items: nextItems };\n }\n if (action.name === \"equipItem\") {\n const id = action.data?.id;\n if (!id || typeof action.data?.equip !== \"boolean\") return data;\n const equip = action.data.equip;\n let nextItems = data.items;\n let nextEquips = data.equips;\n if (Array.isArray(data.items)) {\n nextItems = updateEquippedFlag(data.items, id, equip);\n }\n if (Array.isArray(data.equips)) {\n nextEquips = updateEquippedFlag(data.equips, id, equip);\n }\n if (nextItems === data.items && nextEquips === data.equips) return data;\n return {\n ...data,\n ...(nextItems !== data.items ? { items: nextItems } : {}),\n ...(nextEquips !== data.equips ? { equips: nextEquips } : {})\n };\n }\n return data;\n};\n\nexport class RpgGui {\n private webSocket: AbstractWebsocket;\n gui = signal<Record<string, GuiInstance>>({});\n extraGuis: GuiInstance[] = [];\n private vueGuiInstance: any = null; // Reference to VueGui instance\n private optimisticReducers = new Map<string, OptimisticReducer[]>();\n private pendingActions = new Map<string, GuiAction[]>();\n /**\n * Signal tracking which player IDs should display attached GUIs\n * Key: player ID, Value: boolean (true = show, false = hide)\n */\n attachedGuiDisplayState = signal<Record<string, boolean>>({});\n\n constructor(private context: Context) {\n this.webSocket = inject(context, WebSocketToken);\n this.add({\n name: \"rpg-dialog\",\n component: DialogboxComponent,\n });\n this.add({\n name: PrebuiltGui.MainMenu,\n component: MainMenuComponent,\n });\n this.add({\n name: PrebuiltGui.Shop,\n component: ShopComponent,\n });\n this.add({\n name: PrebuiltGui.Notification,\n component: NotificationComponent,\n autoDisplay: true,\n });\n this.add({\n name: PrebuiltGui.Save,\n component: SaveLoadComponent,\n });\n this.add({\n name: PrebuiltGui.TitleScreen,\n component: TitleScreenComponent,\n });\n this.add({\n name: PrebuiltGui.Gameover,\n component: GameoverComponent,\n });\n\n this.registerOptimisticReducer(PrebuiltGui.MainMenu, mainMenuOptimisticReducer);\n }\n\n async _initialize() {\n this.webSocket.on(\"gui.open\", (data: { guiId: string; data: any }) => {\n this.clearPendingActions(data.guiId);\n this.display(data.guiId, data.data);\n });\n\n this.webSocket.on(\"gui.exit\", (guiId: string) => {\n this.hide(guiId);\n });\n\n this.webSocket.on(\"gui.update\", (payload: { guiId: string; data: any; clientActionId?: string }) => {\n this.applyServerUpdate(payload.guiId, payload.data, payload.clientActionId);\n });\n\n /**\n * Listen for tooltip display state changes from server\n * This is triggered by showAttachedGui/hideAttachedGui on the server\n */\n this.webSocket.on(\"gui.tooltip\", (data: { players: string[]; display: boolean }) => {\n const currentState = { ...this.attachedGuiDisplayState() };\n data.players.forEach((playerId) => {\n currentState[playerId] = data.display;\n });\n this.attachedGuiDisplayState.set(currentState);\n });\n }\n\n /**\n * Set the VueGui instance reference for Vue component management\n * This is called by VueGui when it's initialized\n * \n * @param vueGuiInstance - The VueGui instance\n */\n _setVueGuiInstance(vueGuiInstance: any) {\n this.vueGuiInstance = vueGuiInstance;\n }\n\n /**\n * Notify VueGui about GUI state changes\n * This synchronizes the Vue component display state\n * \n * @param guiId - The GUI component ID\n * @param display - Display state\n * @param data - Component data\n */\n private _notifyVueGui(guiId: string, display: boolean, data: any = {}) {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Find the GUI in extraGuis\n const extraGui = this.extraGuis.find(gui => gui.name === guiId);\n if (extraGui) {\n // Update the Vue component's display state and data\n this.vueGuiInstance.vm.gui[guiId] = {\n name: guiId,\n display,\n data,\n attachToSprite: extraGui.attachToSprite || false\n };\n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n }\n\n /**\n * Initialize Vue components in the VueGui instance\n * This should be called after VueGui is mounted\n */\n _initializeVueComponents() {\n if (this.vueGuiInstance && this.vueGuiInstance.vm) {\n // Initialize all extraGuis in the Vue instance\n this.extraGuis.forEach(gui => {\n this.vueGuiInstance.vm.gui[gui.name] = {\n name: gui.name,\n display: gui.display(),\n data: gui.data(),\n attachToSprite: gui.attachToSprite || false\n };\n });\n \n // Trigger Vue reactivity\n this.vueGuiInstance.vm.gui = Object.assign({}, this.vueGuiInstance.vm.gui);\n }\n }\n\n guiInteraction(guiId: string, name: string, data: any) {\n const clientActionId = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;\n const actionData = { ...(data || {}), clientActionId };\n this.applyOptimisticAction({\n guiId,\n name,\n data: actionData,\n clientActionId\n });\n this.webSocket.emit(\"gui.interaction\", {\n guiId,\n name,\n data: actionData,\n });\n }\n\n guiClose(guiId: string, data?: any) {\n this.webSocket.emit(\"gui.exit\", {\n guiId,\n data,\n });\n }\n\n /**\n * Add a GUI component to the system\n * \n * By default, only CanvasEngine components (.ce files) are accepted.\n * Vue components should be handled by the @rpgjs/vue package.\n * \n * @param gui - GUI configuration options\n * @param gui.name - Name or ID of the GUI component\n * @param gui.id - Alternative ID if name is not provided\n * @param gui.component - The component to render (must be a CanvasEngine component)\n * @param gui.display - Initial display state (default: false)\n * @param gui.data - Initial data for the component\n * @param gui.autoDisplay - Auto display when added (default: false)\n * @param gui.dependencies - Function returning Signal dependencies\n * @param gui.attachToSprite - Attach GUI to sprites instead of global display (default: false)\n * \n * @example\n * ```ts\n * gui.add({\n * name: 'inventory',\n * component: InventoryComponent, // Must be a .ce component\n * autoDisplay: true,\n * dependencies: () => [playerSignal, inventorySignal]\n * });\n * \n * // Attach to sprites\n * gui.add({\n * name: 'tooltip',\n * component: TooltipComponent,\n * attachToSprite: true\n * });\n * ```\n */\n add(gui: GuiOptions) {\n const guiId = gui.name || gui.id;\n if (!guiId) {\n throw new Error(\"GUI must have a name or id\");\n }\n const guiInstance: GuiInstance = {\n name: guiId,\n component: gui.component,\n display: signal(gui.display || false),\n data: signal(gui.data || {}),\n autoDisplay: gui.autoDisplay || false,\n dependencies: gui.dependencies ? gui.dependencies() : [],\n attachToSprite: gui.attachToSprite || false,\n };\n\n // Accept both CanvasEngine components (.ce) and Vue components\n // Vue components will be handled by VueGui if available\n if (typeof gui.component !== 'function') {\n guiInstance.component = gui;\n this.extraGuis.push(guiInstance);\n \n // Auto display Vue components if enabled\n if (guiInstance.autoDisplay) {\n this._notifyVueGui(guiId, true, gui.data || {});\n }\n return;\n }\n\n this.gui()[guiId] = guiInstance;\n\n // Auto display if enabled and it's a CanvasEngine component\n if (guiInstance.autoDisplay && typeof gui.component === 'function') {\n this.display(guiId, gui.data);\n }\n }\n\n registerOptimisticReducer(guiId: string, reducer: OptimisticReducer) {\n const existing = this.optimisticReducers.get(guiId) || [];\n this.optimisticReducers.set(guiId, existing.concat(reducer));\n }\n\n /**\n * Get all attached GUI components (attachToSprite: true)\n * \n * Returns all GUI instances that are configured to be attached to sprites.\n * These GUIs should be rendered in character.ce instead of canvas.ce.\n * \n * @returns Array of GUI instances with attachToSprite: true\n * \n * @example\n * ```ts\n * const attachedGuis = gui.getAttachedGuis();\n * // Use in character.ce to render tooltips\n * ```\n */\n getAttachedGuis(): GuiInstance[] {\n const allGuis = this.getAll();\n return Object.values(allGuis).filter(gui => gui.attachToSprite === true);\n }\n\n /**\n * Check if a player should display attached GUIs\n * \n * @param playerId - The player ID to check\n * @returns true if attached GUIs should be displayed for this player\n */\n shouldDisplayAttachedGui(playerId: string): boolean {\n return this.attachedGuiDisplayState()[playerId] === true;\n }\n\n get(id: string): GuiInstance | undefined {\n // Check CanvasEngine GUIs first\n const canvasGui = this.gui()[id];\n if (canvasGui) {\n return canvasGui;\n }\n \n // Check Vue GUIs in extraGuis\n return this.extraGuis.find(gui => gui.name === id);\n }\n\n exists(id: string): boolean {\n return !!this.get(id);\n }\n\n getAll(): Record<string, GuiInstance> {\n const allGuis = { ...this.gui() };\n \n // Add extraGuis to the result\n this.extraGuis.forEach(gui => {\n allGuis[gui.name] = gui;\n });\n \n return allGuis;\n }\n\n /**\n * Display a GUI component\n * \n * Displays the GUI immediately if no dependencies are configured,\n * or waits for all dependencies to be resolved if dependencies are present.\n * Automatically manages subscriptions to prevent memory leaks.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * @param data - Data to pass to the component\n * @param dependencies - Optional runtime dependencies (overrides config dependencies)\n * \n * @example\n * ```ts\n * // Display immediately\n * gui.display('inventory', { items: [] });\n * \n * // Display with runtime dependencies\n * gui.display('shop', { shopId: 1 }, [playerSignal, shopSignal]);\n * ```\n */\n display(id: string, data = {}, dependencies: Signal[] = []) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Check if it's a Vue component (in extraGuis)\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n \n if (isVueComponent) {\n // Handle Vue component display\n this._handleVueComponentDisplay(id, data, dependencies, guiInstance);\n } else {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n }\n }\n\n isDisplaying(id: string): boolean {\n const guiInstance = this.get(id);\n if (!guiInstance) return false;\n return guiInstance.display();\n }\n\n /**\n * Handle Vue component display logic\n * \n * @param id - GUI component ID\n * @param data - Component data\n * @param dependencies - Runtime dependencies\n * @param guiInstance - GUI instance\n */\n private _handleVueComponentDisplay(id: string, data: any, dependencies: Signal[], guiInstance: GuiInstance) {\n // Unsubscribe from previous subscription if exists\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n // Use runtime dependencies or config dependencies\n const deps = dependencies.length > 0 \n ? dependencies \n : (guiInstance.dependencies ? guiInstance.dependencies() : []);\n\n if (deps.length > 0) {\n // Subscribe to dependencies\n guiInstance.subscription = combineLatest(\n deps.map(dependency => dependency.observable)\n ).subscribe((values) => {\n if (values.every(value => value !== undefined)) {\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n });\n return;\n }\n\n // No dependencies, display immediately\n guiInstance.data.set(data);\n guiInstance.display.set(true);\n this._notifyVueGui(id, true, data);\n }\n\n /**\n * Hide a GUI component\n * \n * Hides the GUI and cleans up any active subscriptions.\n * Works with both CanvasEngine components and Vue components.\n * \n * @param id - The GUI component ID\n * \n * @example\n * ```ts\n * gui.hide('inventory');\n * ```\n */\n hide(id: string) {\n if (!this.exists(id)) {\n throw throwError(id);\n }\n\n const guiInstance = this.get(id)!;\n \n // Unsubscribe if there's an active subscription\n if (guiInstance.subscription) {\n guiInstance.subscription.unsubscribe();\n guiInstance.subscription = undefined;\n }\n\n guiInstance.display.set(false)\n \n // Check if it's a Vue component and notify VueGui\n const isVueComponent = this.extraGuis.some(gui => gui.name === id);\n if (isVueComponent) {\n this._notifyVueGui(id, false);\n }\n }\n\n private isVueComponent(id: string) {\n return this.extraGuis.some(gui => gui.name === id);\n }\n\n private clearPendingActions(guiId: string) {\n this.pendingActions.delete(guiId);\n }\n\n private applyReducers(guiId: string, data: any, actions: GuiAction[]) {\n const reducers = this.optimisticReducers.get(guiId);\n if (!reducers || reducers.length === 0) return data;\n let next = data;\n for (const action of actions) {\n for (const reducer of reducers) {\n const updated = reducer(next, action);\n if (updated !== undefined && updated !== null && updated !== next) {\n next = updated;\n }\n }\n }\n return next;\n }\n\n private applyOptimisticAction(action: GuiAction) {\n const guiInstance = this.get(action.guiId);\n if (!guiInstance) return;\n const reducers = this.optimisticReducers.get(action.guiId);\n if (!reducers || reducers.length === 0) return;\n const currentData = guiInstance.data();\n const nextData = this.applyReducers(action.guiId, currentData, [action]);\n if (nextData === currentData) return;\n guiInstance.data.set(nextData);\n const pending = this.pendingActions.get(action.guiId) || [];\n pending.push(action);\n this.pendingActions.set(action.guiId, pending);\n if (this.isVueComponent(action.guiId)) {\n this._notifyVueGui(action.guiId, guiInstance.display(), nextData);\n }\n }\n\n private applyServerUpdate(guiId: string, data: any, clientActionId?: string) {\n const guiInstance = this.get(guiId);\n if (!guiInstance) return;\n let pending = this.pendingActions.get(guiId) || [];\n if (clientActionId) {\n pending = pending.filter(action => action.clientActionId !== clientActionId);\n } else {\n pending = [];\n }\n let nextData = data;\n if (pending.length) {\n nextData = this.applyReducers(guiId, nextData, pending);\n }\n guiInstance.data.set(nextData);\n this.pendingActions.set(guiId, pending);\n if (this.isVueComponent(guiId)) {\n this._notifyVueGui(guiId, guiInstance.display(), nextData);\n }\n }\n}\n"],"mappings":"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"}
@@ -14,7 +14,7 @@ export interface NotificationItem extends NotificationPayload {
14
14
  removing: boolean;
15
15
  }
16
16
  export declare class NotificationManager {
17
- stack: import('canvasengine').WritableArraySignal<NotificationItem[]>;
17
+ stack: any;
18
18
  private _counter;
19
19
  add(payload: NotificationPayload, engine?: {
20
20
  playSound?: (id: string) => void;