@rpgjs/client 5.0.0-alpha.7 → 5.0.0-alpha.8

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.
@@ -10,7 +10,7 @@ export interface RpgClientEngineHooks {
10
10
  * @prop { (engine: RpgClientEngine) => boolean | any } [onStart]
11
11
  * @memberof RpgEngineHooks
12
12
  */
13
- onStart?: (engine: RpgClientEngine) => boolean | void;
13
+ onStart?: (engine: RpgClientEngine) => boolean | void | Promise<boolean | void>;
14
14
  /**
15
15
  * Each frame
16
16
  *
package/dist/index4.js CHANGED
@@ -5,16 +5,20 @@ import { WebSocketToken, AbstractWebsocket } from './index17.js';
5
5
  import { UpdateMapToken, UpdateMapService } from '@rpgjs/common';
6
6
 
7
7
  class BridgeWebsocket extends AbstractWebsocket {
8
- constructor(context, options) {
8
+ constructor(context, options = {}) {
9
9
  super(context);
10
10
  this.context = context;
11
11
  this.options = options;
12
12
  }
13
- async connection() {
13
+ async connection(listeners) {
14
14
  class Room {
15
15
  }
16
16
  const instance = new Room();
17
- this.socket = await connectionRoom(this.options, instance);
17
+ this.socket = await connectionRoom({
18
+ host: this.options.host || window.location.host,
19
+ room: "lobby-1"
20
+ }, instance);
21
+ listeners?.(this.socket);
18
22
  }
19
23
  on(key, callback) {
20
24
  this.socket.on(key, callback);
@@ -25,6 +29,15 @@ class BridgeWebsocket extends AbstractWebsocket {
25
29
  emit(event, data) {
26
30
  this.socket.emit(event, data);
27
31
  }
32
+ updateProperties({ room }) {
33
+ this.socket.conn.updateProperties({
34
+ room,
35
+ host: this.options.host
36
+ });
37
+ }
38
+ async reconnect(listeners) {
39
+ this.socket.conn.reconnect();
40
+ }
28
41
  }
29
42
  class UpdateMapStandaloneService extends UpdateMapService {
30
43
  constructor(context, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"index4.js","sources":["../src/services/mmorpg.ts"],"sourcesContent":["import { Context } from \"@signe/di\";\nimport { connectionRoom } from \"@signe/sync/client\";\nimport { RpgGui } from \"../Gui/Gui\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { AbstractWebsocket, WebSocketToken } from \"./AbstractSocket\";\nimport { UpdateMapService, UpdateMapToken } from \"@rpgjs/common\";\n\ninterface MmorpgOptions {\n host: string;\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n private socket: any;\n\n constructor(protected context: Context, private options: MmorpgOptions) {\n super(context);\n }\n\n async connection() {\n // tmp\n class Room {\n \n }\n const instance = new Room()\n this.socket = await connectionRoom(this.options, instance)\n }\n\n on(key: string, callback: (data: any) => void) {\n this.socket.on(key, callback);\n }\n\n off(event: string, callback: (data: any) => void) {\n this.socket.off(event, callback);\n }\n\n emit(event: string, data: any) {\n this.socket.emit(event, data);\n }\n}\n\nclass UpdateMapStandaloneService extends UpdateMapService {\n constructor(protected context: Context, private options: MmorpgOptions) {\n super(context);\n }\n\n async update(map: any) {\n // nothing\n }\n}\n\nexport function provideMmorpg(options: MmorpgOptions) {\n return [\n {\n provide: WebSocketToken,\n useFactory: (context: Context) => new BridgeWebsocket(context, options),\n },\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => new UpdateMapStandaloneService(context, options),\n },\n RpgGui,\n RpgClientEngine,\n ];\n}\n"],"names":[],"mappings":";;;;;;AAWA,MAAM,wBAAwB,iBAAkB,CAAA;AAAA,EAG9C,WAAA,CAAsB,SAA0B,OAAwB,EAAA;AACtE,IAAA,KAAA,CAAM,OAAO,CAAA;AADO,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAA0B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA;AAEhD,EAEA,MAAM,UAAa,GAAA;AAAA,IAEjB,MAAM,IAAK,CAAA;AAAA;AAGX,IAAM,MAAA,QAAA,GAAW,IAAI,IAAK,EAAA;AAC1B,IAAA,IAAA,CAAK,MAAS,GAAA,MAAM,cAAe,CAAA,IAAA,CAAK,SAAS,QAAQ,CAAA;AAAA;AAC3D,EAEA,EAAA,CAAG,KAAa,QAA+B,EAAA;AAC7C,IAAK,IAAA,CAAA,MAAA,CAAO,EAAG,CAAA,GAAA,EAAK,QAAQ,CAAA;AAAA;AAC9B,EAEA,GAAA,CAAI,OAAe,QAA+B,EAAA;AAChD,IAAK,IAAA,CAAA,MAAA,CAAO,GAAI,CAAA,KAAA,EAAO,QAAQ,CAAA;AAAA;AACjC,EAEA,IAAA,CAAK,OAAe,IAAW,EAAA;AAC7B,IAAK,IAAA,CAAA,MAAA,CAAO,IAAK,CAAA,KAAA,EAAO,IAAI,CAAA;AAAA;AAEhC;AAEA,MAAM,mCAAmC,gBAAiB,CAAA;AAAA,EACxD,WAAA,CAAsB,SAA0B,OAAwB,EAAA;AACtE,IAAA,KAAA,CAAM,OAAO,CAAA;AADO,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAA0B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA;AAEhD,EAEA,MAAM,OAAO,GAAU,EAAA;AAAA;AAGzB;AAEO,SAAS,cAAc,OAAwB,EAAA;AACpD,EAAO,OAAA;AAAA,IACL;AAAA,MACE,OAAS,EAAA,cAAA;AAAA,MACT,YAAY,CAAC,OAAA,KAAqB,IAAI,eAAA,CAAgB,SAAS,OAAO;AAAA,KACxE;AAAA,IACA;AAAA,MACE,OAAS,EAAA,cAAA;AAAA,MACT,YAAY,CAAC,OAAA,KAAqB,IAAI,0BAAA,CAA2B,SAAS,OAAO;AAAA,KACnF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"index4.js","sources":["../src/services/mmorpg.ts"],"sourcesContent":["import { Context } from \"@signe/di\";\nimport { connectionRoom } from \"@signe/sync/client\";\nimport { RpgGui } from \"../Gui/Gui\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { AbstractWebsocket, WebSocketToken } from \"./AbstractSocket\";\nimport { UpdateMapService, UpdateMapToken } from \"@rpgjs/common\";\n\ninterface MmorpgOptions {\n host?: string;\n}\n\nclass BridgeWebsocket extends AbstractWebsocket {\n private socket: any;\n\n constructor(protected context: Context, private options: MmorpgOptions = {}) {\n super(context);\n }\n\n async connection(listeners?: (data: any) => void) {\n // tmp\n class Room {\n \n }\n const instance = new Room()\n this.socket = await connectionRoom({\n host: this.options.host || window.location.host,\n room: \"lobby-1\",\n }, instance)\n\n listeners?.(this.socket)\n }\n\n on(key: string, callback: (data: any) => void) {\n this.socket.on(key, callback);\n }\n\n off(event: string, callback: (data: any) => void) {\n this.socket.off(event, callback);\n }\n\n emit(event: string, data: any) {\n this.socket.emit(event, data);\n }\n\n updateProperties({ room }: { room: any }) {\n this.socket.conn.updateProperties({\n room: room,\n host: this.options.host\n })\n }\n\n async reconnect(listeners?: (data: any) => void) {\n this.socket.conn.reconnect()\n }\n}\n\nclass UpdateMapStandaloneService extends UpdateMapService {\n constructor(protected context: Context, private options: MmorpgOptions) {\n super(context);\n }\n\n async update(map: any) {\n // nothing\n }\n}\n\nexport function provideMmorpg(options: MmorpgOptions) {\n return [\n {\n provide: WebSocketToken,\n useFactory: (context: Context) => new BridgeWebsocket(context, options),\n },\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => new UpdateMapStandaloneService(context, options),\n },\n RpgGui,\n RpgClientEngine,\n ];\n}\n"],"names":[],"mappings":";;;;;;AAWA,MAAM,wBAAwB,iBAAkB,CAAA;AAAA,EAG9C,WAAsB,CAAA,OAAA,EAA0B,OAAyB,GAAA,EAAI,EAAA;AAC3E,IAAA,KAAA,CAAM,OAAO,CAAA;AADO,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAA0B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA;AAEhD,EAEA,MAAM,WAAW,SAAiC,EAAA;AAAA,IAEhD,MAAM,IAAK,CAAA;AAAA;AAGX,IAAM,MAAA,QAAA,GAAW,IAAI,IAAK,EAAA;AAC1B,IAAK,IAAA,CAAA,MAAA,GAAS,MAAM,cAAe,CAAA;AAAA,MAC/B,IAAM,EAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,IAAQ,OAAO,QAAS,CAAA,IAAA;AAAA,MAC3C,IAAM,EAAA;AAAA,OACP,QAAQ,CAAA;AAEX,IAAA,SAAA,GAAY,KAAK,MAAM,CAAA;AAAA;AACzB,EAEA,EAAA,CAAG,KAAa,QAA+B,EAAA;AAC7C,IAAK,IAAA,CAAA,MAAA,CAAO,EAAG,CAAA,GAAA,EAAK,QAAQ,CAAA;AAAA;AAC9B,EAEA,GAAA,CAAI,OAAe,QAA+B,EAAA;AAChD,IAAK,IAAA,CAAA,MAAA,CAAO,GAAI,CAAA,KAAA,EAAO,QAAQ,CAAA;AAAA;AACjC,EAEA,IAAA,CAAK,OAAe,IAAW,EAAA;AAC7B,IAAK,IAAA,CAAA,MAAA,CAAO,IAAK,CAAA,KAAA,EAAO,IAAI,CAAA;AAAA;AAC9B,EAEA,gBAAA,CAAiB,EAAE,IAAA,EAAuB,EAAA;AACxC,IAAK,IAAA,CAAA,MAAA,CAAO,KAAK,gBAAiB,CAAA;AAAA,MAChC,IAAA;AAAA,MACA,IAAA,EAAM,KAAK,OAAQ,CAAA;AAAA,KACpB,CAAA;AAAA;AACH,EAEA,MAAM,UAAU,SAAiC,EAAA;AAChD,IAAK,IAAA,CAAA,MAAA,CAAO,KAAK,SAAU,EAAA;AAAA;AAE9B;AAEA,MAAM,mCAAmC,gBAAiB,CAAA;AAAA,EACxD,WAAA,CAAsB,SAA0B,OAAwB,EAAA;AACtE,IAAA,KAAA,CAAM,OAAO,CAAA;AADO,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAA0B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA;AAEhD,EAEA,MAAM,OAAO,GAAU,EAAA;AAAA;AAGzB;AAEO,SAAS,cAAc,OAAwB,EAAA;AACpD,EAAO,OAAA;AAAA,IACL;AAAA,MACE,OAAS,EAAA,cAAA;AAAA,MACT,YAAY,CAAC,OAAA,KAAqB,IAAI,eAAA,CAAgB,SAAS,OAAO;AAAA,KACxE;AAAA,IACA;AAAA,MACE,OAAS,EAAA,cAAA;AAAA,MACT,YAAY,CAAC,OAAA,KAAqB,IAAI,0BAAA,CAA2B,SAAS,OAAO;AAAA,KACnF;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
package/dist/index5.js CHANGED
@@ -1,9 +1,10 @@
1
- import { injector, inject, Context } from './index16.js';
1
+ import { Context, injector, inject } from './index16.js';
2
2
  import { RpgClientEngine } from './index2.js';
3
3
  import { setInject } from './index6.js';
4
4
 
5
5
  async function startGame(options) {
6
6
  const context = new Context();
7
+ context["side"] = "client";
7
8
  setInject(context);
8
9
  await injector(context, options.providers);
9
10
  const engine = inject(context, RpgClientEngine);
@@ -1 +1 @@
1
- {"version":3,"file":"index5.js","sources":["../src/core/setup.ts"],"sourcesContent":["import { Context, FactoryProvider, findProvider, findProviders, inject, injector, Providers } from \"@signe/di\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { setInject } from \"./inject\";\n\ninterface SetupOptions {\n providers: Providers;\n}\n\nexport async function startGame(options: SetupOptions) {\n const context = new Context();\n setInject(context);\n\n await injector(context, options.providers);\n\n const engine = inject(context, RpgClientEngine);\n await engine.start();\n return context;\n}"],"names":[],"mappings":";;;;AAQA,eAAsB,UAAU,OAAuB,EAAA;AACrD,EAAM,MAAA,OAAA,GAAU,IAAI,OAAQ,EAAA;AAC5B,EAAA,SAAA,CAAU,OAAO,CAAA;AAEjB,EAAM,MAAA,QAAA,CAAS,OAAS,EAAA,OAAA,CAAQ,SAAS,CAAA;AAEzC,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,OAAA,EAAS,eAAe,CAAA;AAC9C,EAAA,MAAM,OAAO,KAAM,EAAA;AACnB,EAAO,OAAA,OAAA;AACT;;;;"}
1
+ {"version":3,"file":"index5.js","sources":["../src/core/setup.ts"],"sourcesContent":["import { Context, FactoryProvider, findProvider, findProviders, inject, injector, Providers } from \"@signe/di\";\nimport { RpgClientEngine } from \"../RpgClientEngine\";\nimport { setInject } from \"./inject\";\n\ninterface SetupOptions {\n providers: Providers;\n}\n\n\nexport async function startGame(options: SetupOptions) {\n const context = new Context();\n context['side'] = 'client'\n setInject(context);\n\n await injector(context, options.providers);\n\n const engine = inject(context, RpgClientEngine);\n await engine.start();\n return context;\n}"],"names":[],"mappings":";;;;AASA,eAAsB,UAAU,OAAuB,EAAA;AACrD,EAAM,MAAA,OAAA,GAAU,IAAI,OAAQ,EAAA;AAC5B,EAAA,OAAA,CAAQ,MAAM,CAAI,GAAA,QAAA;AAClB,EAAA,SAAA,CAAU,OAAO,CAAA;AAEjB,EAAM,MAAA,QAAA,CAAS,OAAS,EAAA,OAAA,CAAQ,SAAS,CAAA;AAEzC,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,OAAA,EAAS,eAAe,CAAA;AAC9C,EAAA,MAAM,OAAO,KAAM,EAAA;AACnB,EAAO,OAAA,OAAA;AACT;;;;"}
package/dist/index7.js CHANGED
@@ -6,6 +6,9 @@ class LoadMapService {
6
6
  constructor(context, options) {
7
7
  this.context = context;
8
8
  this.options = options;
9
+ if (context["side"] === "server") {
10
+ return;
11
+ }
9
12
  this.updateMapService = inject(context, UpdateMapToken);
10
13
  }
11
14
  async load(mapId) {
@@ -18,7 +21,12 @@ function provideLoadMap(options) {
18
21
  return [
19
22
  {
20
23
  provide: UpdateMapToken,
21
- useFactory: (context) => console.warn("UpdateMapToken is not overridden")
24
+ useFactory: (context) => {
25
+ if (context["side"] === "client") {
26
+ console.warn("UpdateMapToken is not overridden");
27
+ }
28
+ return;
29
+ }
22
30
  },
23
31
  {
24
32
  provide: LoadMapToken,
@@ -1 +1 @@
1
- {"version":3,"file":"index7.js","sources":["../src/services/loadMap.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { UpdateMapToken, UpdateMapService } from \"@rpgjs/common\";\n\nexport const LoadMapToken = 'LoadMapToken'\n\nexport type LoadMapOptions = (mapId: string) => Promise<void>\n\nexport class LoadMapService {\n private updateMapService: UpdateMapService;\n\n constructor(private context: Context, private options: LoadMapOptions) {\n this.updateMapService = inject(context, UpdateMapToken);\n }\n\n async load(mapId: string) {\n const map = await this.options(mapId.replace('map-', ''))\n await this.updateMapService.update(mapId, map);\n return map;\n }\n}\n\nexport function provideLoadMap(options: LoadMapOptions) {\n return [\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => console.warn('UpdateMapToken is not overridden'),\n },\n {\n provide: LoadMapToken,\n useFactory: (context: Context) => new LoadMapService(context, options),\n },\n ];\n}\n"],"names":[],"mappings":";;;AAGO,MAAM,YAAe,GAAA;AAIrB,MAAM,cAAe,CAAA;AAAA,EAG1B,WAAA,CAAoB,SAA0B,OAAyB,EAAA;AAAnD,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAA0B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAC5C,IAAK,IAAA,CAAA,gBAAA,GAAmB,MAAO,CAAA,OAAA,EAAS,cAAc,CAAA;AAAA;AACxD,EAEA,MAAM,KAAK,KAAe,EAAA;AACxB,IAAM,MAAA,GAAA,GAAM,MAAM,IAAK,CAAA,OAAA,CAAQ,MAAM,OAAQ,CAAA,MAAA,EAAQ,EAAE,CAAC,CAAA;AACxD,IAAA,MAAM,IAAK,CAAA,gBAAA,CAAiB,MAAO,CAAA,KAAA,EAAO,GAAG,CAAA;AAC7C,IAAO,OAAA,GAAA;AAAA;AAEX;AAEO,SAAS,eAAe,OAAyB,EAAA;AACtD,EAAO,OAAA;AAAA,IACL;AAAA,MACE,OAAS,EAAA,cAAA;AAAA,MACT,UAAY,EAAA,CAAC,OAAqB,KAAA,OAAA,CAAQ,KAAK,kCAAkC;AAAA,KACnF;AAAA,IACA;AAAA,MACE,OAAS,EAAA,YAAA;AAAA,MACT,YAAY,CAAC,OAAA,KAAqB,IAAI,cAAA,CAAe,SAAS,OAAO;AAAA;AACvE,GACF;AACF;;;;"}
1
+ {"version":3,"file":"index7.js","sources":["../src/services/loadMap.ts"],"sourcesContent":["import { Context, inject } from \"@signe/di\";\nimport { UpdateMapToken, UpdateMapService } from \"@rpgjs/common\";\n\nexport const LoadMapToken = 'LoadMapToken'\n\n/**\n * Represents the structure of map data that should be returned by the load map callback.\n * This interface defines all the properties that can be provided when loading a custom map.\n * \n * @interface MapData\n */\ntype MapData = {\n /** Raw map data that will be passed to the map component */\n data: any;\n /** CanvasEngine component that will render the map */\n component: any;\n /** Optional map width in pixels, used for viewport calculations */\n width?: number;\n /** Optional map height in pixels, used for viewport calculations */\n height?: number;\n /** Optional map events data (NPCs, interactive objects, etc.) */\n events?: any;\n /** Optional map identifier, defaults to the mapId parameter if not provided */\n id?: string;\n}\n\n/**\n * Callback function type for loading map data.\n * This function receives a map ID and should return either a MapData object directly\n * or a Promise that resolves to a MapData object.\n * \n * @callback LoadMapOptions\n * @param {string} mapId - The identifier of the map to load\n * @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it\n */\nexport type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData \n\nexport class LoadMapService {\n private updateMapService: UpdateMapService;\n\n constructor(private context: Context, private options: LoadMapOptions) {\n if (context['side'] === 'server') {\n return\n }\n this.updateMapService = inject(context, UpdateMapToken);\n }\n\n async load(mapId: string) {\n const map = await this.options(mapId.replace('map-', ''))\n await this.updateMapService.update(mapId, map);\n return map;\n }\n}\n\n/**\n * Creates a dependency injection configuration for custom map loading on the client side.\n * \n * This function allows you to customize how maps are loaded and displayed by providing\n * a callback that defines custom map data and rendering components. It's designed to work\n * with the RPG-JS dependency injection system and enables integration of custom map formats\n * like Tiled TMX files or any other map data structure.\n * \n * The function sets up the necessary service providers for map loading, including:\n * - UpdateMapToken: Handles map updates in the client context\n * - LoadMapToken: Provides the LoadMapService with your custom loading logic\n * \n * **Design Concept:**\n * The function follows the provider pattern, creating a modular way to inject custom\n * map loading behavior into the RPG-JS client engine. It separates the concern of\n * map data fetching from map rendering, allowing developers to focus on their specific\n * map format while leveraging the engine's rendering capabilities.\n * \n * @param {LoadMapOptions} options - Callback function that handles map loading logic\n * @returns {Array<Object>} Array of dependency injection provider configurations\n * \n * @example\n * ```typescript\n * import { provideLoadMap } from '@rpgjs/client'\n * import { createModule } from '@rpgjs/common'\n * import MyTiledMapComponent from './MyTiledMapComponent.ce'\n * \n * // Basic usage with JSON map data\n * export function provideCustomMap() {\n * return createModule(\"CustomMap\", [\n * provideLoadMap(async (mapId) => {\n * const response = await fetch(`/maps/${mapId}.json`)\n * const mapData = await response.json()\n * \n * return {\n * data: mapData,\n * component: MyTiledMapComponent,\n * width: mapData.width,\n * height: mapData.height,\n * events: mapData.events\n * }\n * })\n * ])\n * }\n * \n * // Advanced usage with Tiled TMX files\n * export function provideTiledMap() {\n * return createModule(\"TiledMap\", [\n * provideLoadMap(async (mapId) => {\n * // Load TMX file\n * const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)\n * const tmxData = await tmxResponse.text()\n * \n * // Parse TMX data (using a TMX parser)\n * const parsedMap = parseTMX(tmxData)\n * \n * return {\n * data: parsedMap,\n * component: TiledMapRenderer,\n * width: parsedMap.width * parsedMap.tilewidth,\n * height: parsedMap.height * parsedMap.tileheight,\n * events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects\n * }\n * })\n * ])\n * }\n * \n * // Synchronous usage for static maps\n * export function provideStaticMap() {\n * return createModule(\"StaticMap\", [\n * provideLoadMap((mapId) => {\n * const staticMaps = {\n * 'town': { tiles: [...], npcs: [...] },\n * 'dungeon': { tiles: [...], monsters: [...] }\n * }\n * \n * return {\n * data: staticMaps[mapId],\n * component: StaticMapComponent,\n * width: 800,\n * height: 600\n * }\n * })\n * ])\n * }\n * ```\n * \n * @since 4.0.0\n * @see {@link LoadMapOptions} for callback function signature\n * @see {@link MapData} for return data structure\n */\nexport function provideLoadMap(options: LoadMapOptions) {\n return [\n {\n provide: UpdateMapToken,\n useFactory: (context: Context) => {\n if (context['side'] === 'client') {\n console.warn('UpdateMapToken is not overridden')\n }\n return\n },\n },\n {\n provide: LoadMapToken,\n useFactory: (context: Context) => new LoadMapService(context, options),\n },\n ];\n}\n"],"names":[],"mappings":";;;AAGO,MAAM,YAAe,GAAA;AAkCrB,MAAM,cAAe,CAAA;AAAA,EAG1B,WAAA,CAAoB,SAA0B,OAAyB,EAAA;AAAnD,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAA0B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAC5C,IAAI,IAAA,OAAA,CAAQ,MAAM,CAAA,KAAM,QAAU,EAAA;AAChC,MAAA;AAAA;AAEF,IAAK,IAAA,CAAA,gBAAA,GAAmB,MAAO,CAAA,OAAA,EAAS,cAAc,CAAA;AAAA;AACxD,EAEA,MAAM,KAAK,KAAe,EAAA;AACxB,IAAM,MAAA,GAAA,GAAM,MAAM,IAAK,CAAA,OAAA,CAAQ,MAAM,OAAQ,CAAA,MAAA,EAAQ,EAAE,CAAC,CAAA;AACxD,IAAA,MAAM,IAAK,CAAA,gBAAA,CAAiB,MAAO,CAAA,KAAA,EAAO,GAAG,CAAA;AAC7C,IAAO,OAAA,GAAA;AAAA;AAEX;AA6FO,SAAS,eAAe,OAAyB,EAAA;AACtD,EAAO,OAAA;AAAA,IACL;AAAA,MACE,OAAS,EAAA,cAAA;AAAA,MACT,UAAA,EAAY,CAAC,OAAqB,KAAA;AAChC,QAAI,IAAA,OAAA,CAAQ,MAAM,CAAA,KAAM,QAAU,EAAA;AAChC,UAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAAA;AAEjD,QAAA;AAAA;AACF,KACF;AAAA,IACA;AAAA,MACE,OAAS,EAAA,YAAA;AAAA,MACT,YAAY,CAAC,OAAA,KAAqB,IAAI,cAAA,CAAe,SAAS,OAAO;AAAA;AACvE,GACF;AACF;;;;"}
@@ -1,14 +1,135 @@
1
1
  import { Context } from '@signe/di';
2
2
  export declare const LoadMapToken = "LoadMapToken";
3
- export type LoadMapOptions = (mapId: string) => Promise<void>;
3
+ /**
4
+ * Represents the structure of map data that should be returned by the load map callback.
5
+ * This interface defines all the properties that can be provided when loading a custom map.
6
+ *
7
+ * @interface MapData
8
+ */
9
+ type MapData = {
10
+ /** Raw map data that will be passed to the map component */
11
+ data: any;
12
+ /** CanvasEngine component that will render the map */
13
+ component: any;
14
+ /** Optional map width in pixels, used for viewport calculations */
15
+ width?: number;
16
+ /** Optional map height in pixels, used for viewport calculations */
17
+ height?: number;
18
+ /** Optional map events data (NPCs, interactive objects, etc.) */
19
+ events?: any;
20
+ /** Optional map identifier, defaults to the mapId parameter if not provided */
21
+ id?: string;
22
+ };
23
+ /**
24
+ * Callback function type for loading map data.
25
+ * This function receives a map ID and should return either a MapData object directly
26
+ * or a Promise that resolves to a MapData object.
27
+ *
28
+ * @callback LoadMapOptions
29
+ * @param {string} mapId - The identifier of the map to load
30
+ * @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it
31
+ */
32
+ export type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData;
4
33
  export declare class LoadMapService {
5
34
  private context;
6
35
  private options;
7
36
  private updateMapService;
8
37
  constructor(context: Context, options: LoadMapOptions);
9
- load(mapId: string): Promise<void>;
38
+ load(mapId: string): Promise<MapData>;
10
39
  }
40
+ /**
41
+ * Creates a dependency injection configuration for custom map loading on the client side.
42
+ *
43
+ * This function allows you to customize how maps are loaded and displayed by providing
44
+ * a callback that defines custom map data and rendering components. It's designed to work
45
+ * with the RPG-JS dependency injection system and enables integration of custom map formats
46
+ * like Tiled TMX files or any other map data structure.
47
+ *
48
+ * The function sets up the necessary service providers for map loading, including:
49
+ * - UpdateMapToken: Handles map updates in the client context
50
+ * - LoadMapToken: Provides the LoadMapService with your custom loading logic
51
+ *
52
+ * **Design Concept:**
53
+ * The function follows the provider pattern, creating a modular way to inject custom
54
+ * map loading behavior into the RPG-JS client engine. It separates the concern of
55
+ * map data fetching from map rendering, allowing developers to focus on their specific
56
+ * map format while leveraging the engine's rendering capabilities.
57
+ *
58
+ * @param {LoadMapOptions} options - Callback function that handles map loading logic
59
+ * @returns {Array<Object>} Array of dependency injection provider configurations
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * import { provideLoadMap } from '@rpgjs/client'
64
+ * import { createModule } from '@rpgjs/common'
65
+ * import MyTiledMapComponent from './MyTiledMapComponent.ce'
66
+ *
67
+ * // Basic usage with JSON map data
68
+ * export function provideCustomMap() {
69
+ * return createModule("CustomMap", [
70
+ * provideLoadMap(async (mapId) => {
71
+ * const response = await fetch(`/maps/${mapId}.json`)
72
+ * const mapData = await response.json()
73
+ *
74
+ * return {
75
+ * data: mapData,
76
+ * component: MyTiledMapComponent,
77
+ * width: mapData.width,
78
+ * height: mapData.height,
79
+ * events: mapData.events
80
+ * }
81
+ * })
82
+ * ])
83
+ * }
84
+ *
85
+ * // Advanced usage with Tiled TMX files
86
+ * export function provideTiledMap() {
87
+ * return createModule("TiledMap", [
88
+ * provideLoadMap(async (mapId) => {
89
+ * // Load TMX file
90
+ * const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)
91
+ * const tmxData = await tmxResponse.text()
92
+ *
93
+ * // Parse TMX data (using a TMX parser)
94
+ * const parsedMap = parseTMX(tmxData)
95
+ *
96
+ * return {
97
+ * data: parsedMap,
98
+ * component: TiledMapRenderer,
99
+ * width: parsedMap.width * parsedMap.tilewidth,
100
+ * height: parsedMap.height * parsedMap.tileheight,
101
+ * events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects
102
+ * }
103
+ * })
104
+ * ])
105
+ * }
106
+ *
107
+ * // Synchronous usage for static maps
108
+ * export function provideStaticMap() {
109
+ * return createModule("StaticMap", [
110
+ * provideLoadMap((mapId) => {
111
+ * const staticMaps = {
112
+ * 'town': { tiles: [...], npcs: [...] },
113
+ * 'dungeon': { tiles: [...], monsters: [...] }
114
+ * }
115
+ *
116
+ * return {
117
+ * data: staticMaps[mapId],
118
+ * component: StaticMapComponent,
119
+ * width: 800,
120
+ * height: 600
121
+ * }
122
+ * })
123
+ * ])
124
+ * }
125
+ * ```
126
+ *
127
+ * @since 4.0.0
128
+ * @see {@link LoadMapOptions} for callback function signature
129
+ * @see {@link MapData} for return data structure
130
+ */
11
131
  export declare function provideLoadMap(options: LoadMapOptions): {
12
132
  provide: string;
13
133
  useFactory: (context: Context) => void;
14
134
  }[];
135
+ export {};
@@ -4,17 +4,21 @@ import { RpgClientEngine } from '../RpgClientEngine';
4
4
  import { AbstractWebsocket } from './AbstractSocket';
5
5
  import { UpdateMapService } from '@rpgjs/common';
6
6
  interface MmorpgOptions {
7
- host: string;
7
+ host?: string;
8
8
  }
9
9
  declare class BridgeWebsocket extends AbstractWebsocket {
10
10
  protected context: Context;
11
11
  private options;
12
12
  private socket;
13
- constructor(context: Context, options: MmorpgOptions);
14
- connection(): Promise<void>;
13
+ constructor(context: Context, options?: MmorpgOptions);
14
+ connection(listeners?: (data: any) => void): Promise<void>;
15
15
  on(key: string, callback: (data: any) => void): void;
16
16
  off(event: string, callback: (data: any) => void): void;
17
17
  emit(event: string, data: any): void;
18
+ updateProperties({ room }: {
19
+ room: any;
20
+ }): void;
21
+ reconnect(listeners?: (data: any) => void): Promise<void>;
18
22
  }
19
23
  declare class UpdateMapStandaloneService extends UpdateMapService {
20
24
  protected context: Context;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpgjs/client",
3
- "version": "5.0.0-alpha.7",
3
+ "version": "5.0.0-alpha.8",
4
4
  "description": "RPGJS is a framework for creating RPG/MMORPG games",
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "pixi.js": "^8.9.2"
23
23
  },
24
24
  "dependencies": {
25
- "@rpgjs/common": "5.0.0-alpha.7",
25
+ "@rpgjs/common": "5.0.0-alpha.8",
26
26
  "@signe/di": "^2.3.3",
27
27
  "@signe/room": "^2.3.3",
28
28
  "@signe/sync": "^2.3.3",
package/src/RpgClient.ts CHANGED
@@ -12,7 +12,7 @@ export interface RpgClientEngineHooks {
12
12
  * @prop { (engine: RpgClientEngine) => boolean | any } [onStart]
13
13
  * @memberof RpgEngineHooks
14
14
  */
15
- onStart?: (engine: RpgClientEngine) => boolean | void
15
+ onStart?: (engine: RpgClientEngine) => boolean | void | Promise<boolean | void>
16
16
 
17
17
  /**
18
18
  * Each frame
package/src/core/setup.ts CHANGED
@@ -6,8 +6,10 @@ interface SetupOptions {
6
6
  providers: Providers;
7
7
  }
8
8
 
9
+
9
10
  export async function startGame(options: SetupOptions) {
10
11
  const context = new Context();
12
+ context['side'] = 'client'
11
13
  setInject(context);
12
14
 
13
15
  await injector(context, options.providers);
@@ -3,12 +3,45 @@ import { UpdateMapToken, UpdateMapService } from "@rpgjs/common";
3
3
 
4
4
  export const LoadMapToken = 'LoadMapToken'
5
5
 
6
- export type LoadMapOptions = (mapId: string) => Promise<void>
6
+ /**
7
+ * Represents the structure of map data that should be returned by the load map callback.
8
+ * This interface defines all the properties that can be provided when loading a custom map.
9
+ *
10
+ * @interface MapData
11
+ */
12
+ type MapData = {
13
+ /** Raw map data that will be passed to the map component */
14
+ data: any;
15
+ /** CanvasEngine component that will render the map */
16
+ component: any;
17
+ /** Optional map width in pixels, used for viewport calculations */
18
+ width?: number;
19
+ /** Optional map height in pixels, used for viewport calculations */
20
+ height?: number;
21
+ /** Optional map events data (NPCs, interactive objects, etc.) */
22
+ events?: any;
23
+ /** Optional map identifier, defaults to the mapId parameter if not provided */
24
+ id?: string;
25
+ }
26
+
27
+ /**
28
+ * Callback function type for loading map data.
29
+ * This function receives a map ID and should return either a MapData object directly
30
+ * or a Promise that resolves to a MapData object.
31
+ *
32
+ * @callback LoadMapOptions
33
+ * @param {string} mapId - The identifier of the map to load
34
+ * @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it
35
+ */
36
+ export type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData
7
37
 
8
38
  export class LoadMapService {
9
39
  private updateMapService: UpdateMapService;
10
40
 
11
41
  constructor(private context: Context, private options: LoadMapOptions) {
42
+ if (context['side'] === 'server') {
43
+ return
44
+ }
12
45
  this.updateMapService = inject(context, UpdateMapToken);
13
46
  }
14
47
 
@@ -19,11 +52,107 @@ export class LoadMapService {
19
52
  }
20
53
  }
21
54
 
55
+ /**
56
+ * Creates a dependency injection configuration for custom map loading on the client side.
57
+ *
58
+ * This function allows you to customize how maps are loaded and displayed by providing
59
+ * a callback that defines custom map data and rendering components. It's designed to work
60
+ * with the RPG-JS dependency injection system and enables integration of custom map formats
61
+ * like Tiled TMX files or any other map data structure.
62
+ *
63
+ * The function sets up the necessary service providers for map loading, including:
64
+ * - UpdateMapToken: Handles map updates in the client context
65
+ * - LoadMapToken: Provides the LoadMapService with your custom loading logic
66
+ *
67
+ * **Design Concept:**
68
+ * The function follows the provider pattern, creating a modular way to inject custom
69
+ * map loading behavior into the RPG-JS client engine. It separates the concern of
70
+ * map data fetching from map rendering, allowing developers to focus on their specific
71
+ * map format while leveraging the engine's rendering capabilities.
72
+ *
73
+ * @param {LoadMapOptions} options - Callback function that handles map loading logic
74
+ * @returns {Array<Object>} Array of dependency injection provider configurations
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * import { provideLoadMap } from '@rpgjs/client'
79
+ * import { createModule } from '@rpgjs/common'
80
+ * import MyTiledMapComponent from './MyTiledMapComponent.ce'
81
+ *
82
+ * // Basic usage with JSON map data
83
+ * export function provideCustomMap() {
84
+ * return createModule("CustomMap", [
85
+ * provideLoadMap(async (mapId) => {
86
+ * const response = await fetch(`/maps/${mapId}.json`)
87
+ * const mapData = await response.json()
88
+ *
89
+ * return {
90
+ * data: mapData,
91
+ * component: MyTiledMapComponent,
92
+ * width: mapData.width,
93
+ * height: mapData.height,
94
+ * events: mapData.events
95
+ * }
96
+ * })
97
+ * ])
98
+ * }
99
+ *
100
+ * // Advanced usage with Tiled TMX files
101
+ * export function provideTiledMap() {
102
+ * return createModule("TiledMap", [
103
+ * provideLoadMap(async (mapId) => {
104
+ * // Load TMX file
105
+ * const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)
106
+ * const tmxData = await tmxResponse.text()
107
+ *
108
+ * // Parse TMX data (using a TMX parser)
109
+ * const parsedMap = parseTMX(tmxData)
110
+ *
111
+ * return {
112
+ * data: parsedMap,
113
+ * component: TiledMapRenderer,
114
+ * width: parsedMap.width * parsedMap.tilewidth,
115
+ * height: parsedMap.height * parsedMap.tileheight,
116
+ * events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects
117
+ * }
118
+ * })
119
+ * ])
120
+ * }
121
+ *
122
+ * // Synchronous usage for static maps
123
+ * export function provideStaticMap() {
124
+ * return createModule("StaticMap", [
125
+ * provideLoadMap((mapId) => {
126
+ * const staticMaps = {
127
+ * 'town': { tiles: [...], npcs: [...] },
128
+ * 'dungeon': { tiles: [...], monsters: [...] }
129
+ * }
130
+ *
131
+ * return {
132
+ * data: staticMaps[mapId],
133
+ * component: StaticMapComponent,
134
+ * width: 800,
135
+ * height: 600
136
+ * }
137
+ * })
138
+ * ])
139
+ * }
140
+ * ```
141
+ *
142
+ * @since 4.0.0
143
+ * @see {@link LoadMapOptions} for callback function signature
144
+ * @see {@link MapData} for return data structure
145
+ */
22
146
  export function provideLoadMap(options: LoadMapOptions) {
23
147
  return [
24
148
  {
25
149
  provide: UpdateMapToken,
26
- useFactory: (context: Context) => console.warn('UpdateMapToken is not overridden'),
150
+ useFactory: (context: Context) => {
151
+ if (context['side'] === 'client') {
152
+ console.warn('UpdateMapToken is not overridden')
153
+ }
154
+ return
155
+ },
27
156
  },
28
157
  {
29
158
  provide: LoadMapToken,
@@ -6,23 +6,28 @@ import { AbstractWebsocket, WebSocketToken } from "./AbstractSocket";
6
6
  import { UpdateMapService, UpdateMapToken } from "@rpgjs/common";
7
7
 
8
8
  interface MmorpgOptions {
9
- host: string;
9
+ host?: string;
10
10
  }
11
11
 
12
12
  class BridgeWebsocket extends AbstractWebsocket {
13
13
  private socket: any;
14
14
 
15
- constructor(protected context: Context, private options: MmorpgOptions) {
15
+ constructor(protected context: Context, private options: MmorpgOptions = {}) {
16
16
  super(context);
17
17
  }
18
18
 
19
- async connection() {
19
+ async connection(listeners?: (data: any) => void) {
20
20
  // tmp
21
21
  class Room {
22
22
 
23
23
  }
24
24
  const instance = new Room()
25
- this.socket = await connectionRoom(this.options, instance)
25
+ this.socket = await connectionRoom({
26
+ host: this.options.host || window.location.host,
27
+ room: "lobby-1",
28
+ }, instance)
29
+
30
+ listeners?.(this.socket)
26
31
  }
27
32
 
28
33
  on(key: string, callback: (data: any) => void) {
@@ -36,6 +41,17 @@ class BridgeWebsocket extends AbstractWebsocket {
36
41
  emit(event: string, data: any) {
37
42
  this.socket.emit(event, data);
38
43
  }
44
+
45
+ updateProperties({ room }: { room: any }) {
46
+ this.socket.conn.updateProperties({
47
+ room: room,
48
+ host: this.options.host
49
+ })
50
+ }
51
+
52
+ async reconnect(listeners?: (data: any) => void) {
53
+ this.socket.conn.reconnect()
54
+ }
39
55
  }
40
56
 
41
57
  class UpdateMapStandaloneService extends UpdateMapService {