@rpgjs/server 5.0.0-alpha.10 → 5.0.0-alpha.12

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.
@@ -14,8 +14,8 @@ import { MockConnection } from "@signe/room";
14
14
  import { IMoveManager, WithMoveManager } from "./MoveManager";
15
15
  import { IGoldManager, WithGoldManager } from "./GoldManager";
16
16
  import { WithVariableManager, type IVariableManager } from "./VariableManager";
17
- import { sync } from "@signe/sync";
18
- import { signal } from "@signe/reactive";
17
+ import { createStatesSnapshot, load, sync, type } from "@signe/sync";
18
+ import { computed, signal } from "@signe/reactive";
19
19
  import {
20
20
  IParameterManager,
21
21
  WithParameterManager,
@@ -117,6 +117,14 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
117
117
  (this as any).addParameter(AGI, AGI_CURVE);
118
118
  (this as any).allRecovery();
119
119
  }
120
+
121
+ _onInit() {
122
+ this.hooks.callHooks("server-playerProps-load", this).subscribe();
123
+ }
124
+
125
+ get hooks() {
126
+ return inject<Hooks>(this.context as any, ModulesToken);
127
+ }
120
128
 
121
129
  async execMethod(method: string, methodData: any[] = [], target?: any) {
122
130
  let ret: any;
@@ -124,8 +132,7 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
124
132
  ret = await target[method](...methodData);
125
133
  }
126
134
  else {
127
- const hooks = inject<Hooks>(this.context as any, ModulesToken);
128
- ret = await lastValueFrom(hooks
135
+ ret = await lastValueFrom(this.hooks
129
136
  .callHooks(`server-player-${method}`, target ?? this, ...methodData));
130
137
  }
131
138
  this.syncChanges()
@@ -152,6 +159,7 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
152
159
  mapId: string,
153
160
  positions?: { x: number; y: number; z?: number } | string
154
161
  ): Promise<any | null | boolean> {
162
+ const room = this.getCurrentMap();
155
163
  this.emit("changeMap", {
156
164
  mapId: 'map-' + mapId,
157
165
  positions,
@@ -178,6 +186,19 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
178
186
  });
179
187
  }
180
188
 
189
+ async save() {
190
+ const snapshot = createStatesSnapshot(this)
191
+ await lastValueFrom(this.hooks.callHooks("server-player-onSave", this, snapshot))
192
+ return JSON.stringify(snapshot)
193
+ }
194
+
195
+ async load(snapshot: string) {
196
+ const data = JSON.parse(snapshot)
197
+ const dataLoaded = load(this, data)
198
+ await lastValueFrom(this.hooks.callHooks("server-player-onLoad", this, dataLoaded))
199
+ return dataLoaded
200
+ }
201
+
181
202
  /**
182
203
  * Set the current animation of the player's sprite
183
204
  *
@@ -322,7 +343,7 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
322
343
  * });
323
344
  * ```
324
345
  */
325
- showComponentAnimation(id: string, params: any) {
346
+ showComponentAnimation(id: string, params: any = {}) {
326
347
  const map = this.getCurrentMap();
327
348
  if (!map) return;
328
349
  map.$broadcast({
@@ -335,56 +356,30 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
335
356
  });
336
357
  }
337
358
 
338
- /**
339
- * Display a spritesheet animation on the player
340
- *
341
- * This method displays a temporary visual animation using a spritesheet.
342
- * The animation can either be displayed as an overlay on the player or replace
343
- * the player's current graphic temporarily. This is useful for spell effects,
344
- * transformations, or other visual feedback that uses predefined spritesheets.
345
- *
346
- * @param graphic - The ID of the spritesheet to use for the animation
347
- * @param animationName - The name of the animation within the spritesheet (default: 'default')
348
- * @param replaceGraphic - Whether to replace the player's sprite with the animation (default: false)
349
- *
350
- * @example
351
- * ```ts
352
- * // Show explosion animation as overlay on player
353
- * player.showAnimation("explosion");
354
- *
355
- * // Show specific spell effect animation
356
- * player.showAnimation("spell-effects", "fireball");
357
- *
358
- * // Transform player graphic temporarily with animation
359
- * player.showAnimation("transformation", "werewolf", true);
360
- *
361
- * // Show healing effect on player
362
- * player.showAnimation("healing-effects", "holy-light");
363
- * ```
364
- */
365
- showAnimation(graphic: string, animationName: string = 'default', replaceGraphic: boolean = false) {
366
- if (replaceGraphic) {
367
- this.setAnimation(animationName, 1);
368
- return
369
- }
370
- this.showComponentAnimation("animation", {
371
- graphic,
372
- animationName,
373
- });
374
- }
375
-
376
359
  showHit(text: string) {
377
360
  this.showComponentAnimation("hit", {
378
361
  text,
379
362
  direction: this.direction(),
380
363
  });
381
364
  }
365
+
366
+ /**
367
+ * Set the sync schema for the map
368
+ * @param schema - The schema to set
369
+ */
370
+ setSync(schema: any) {
371
+ for (let key in schema) {
372
+ this[key] = type(signal(null), key, {
373
+ syncWithClient: schema[key]?.$syncWithClient,
374
+ persist: schema[key]?.$permanent,
375
+ }, this)
376
+ }
377
+ }
382
378
  }
383
379
 
384
380
  export class RpgEvent extends RpgPlayer {
385
381
  override async execMethod(methodName: string, methodData: any[] = [], instance = this) {
386
- const hooks = inject<Hooks>(this.context as any, ModulesToken);
387
- await lastValueFrom(hooks
382
+ await lastValueFrom(this.hooks
388
383
  .callHooks(`server-event-${methodName}`, instance, ...methodData));
389
384
  if (!instance[methodName]) {
390
385
  return;
package/src/index.ts CHANGED
@@ -6,4 +6,6 @@ export * from "./core/inject";
6
6
  export * from "./Player/Player";
7
7
  export * from "./module";
8
8
  export * from "./rooms/map";
9
- export * from "./presets";
9
+ export * from "./presets";
10
+ export * from "@signe/reactive";
11
+ export * from "./Gui";
package/src/module.ts CHANGED
@@ -2,6 +2,7 @@ import { findModules, provideModules } from "@rpgjs/common";
2
2
  import { FactoryProvider } from "@signe/di";
3
3
  import { RpgServerEngine } from "./RpgServerEngine";
4
4
  import { RpgMap } from "./rooms/map";
5
+ import { RpgPlayer } from "./Player/Player";
5
6
 
6
7
  export function provideServerModules(modules: any[]): FactoryProvider {
7
8
  return provideModules(modules, "server", (modules, context) => {
@@ -11,6 +12,16 @@ export function provideServerModules(modules: any[]): FactoryProvider {
11
12
  if ('server' in module) {
12
13
  module = module.server as any;
13
14
  }
15
+ if (module.player?.props) {
16
+ module = {
17
+ ...module,
18
+ playerProps: {
19
+ load: (player: RpgPlayer) => {
20
+ player.setSync(module.player.props)
21
+ },
22
+ }
23
+ };
24
+ }
14
25
  if (module.maps && Array.isArray(module.maps)) {
15
26
  const maps = [...module.maps];
16
27
  module = {
package/src/rooms/map.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Action, MockConnection, Request, Room, RoomOnJoin } from "@signe/room";
2
2
  import { Hooks, IceMovement, ModulesToken, ProjectileMovement, ProjectileType, RpgCommonMap, ZoneData } from "@rpgjs/common";
3
3
  import { RpgPlayer, RpgEvent } from "../Player/Player";
4
- import { generateShortUUID, sync, users } from "@signe/sync";
4
+ import { generateShortUUID, sync, type, users } from "@signe/sync";
5
5
  import { signal } from "@signe/reactive";
6
6
  import { inject } from "@signe/di";
7
7
  import { context } from "../core/context";;
@@ -80,6 +80,7 @@ export class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoin {
80
80
  }, () => {
81
81
  player.animationName.set('stand')
82
82
  })
83
+ player._onInit()
83
84
  this.dataIsReady$.pipe(
84
85
  finalize(() => {
85
86
  this.hooks
@@ -270,6 +271,7 @@ export class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoin {
270
271
 
271
272
  eventInstance.x.set(x);
272
273
  eventInstance.y.set(y);
274
+ if (event.name) eventInstance.name.set(event.name);
273
275
 
274
276
  this.events()[id] = eventInstance;
275
277
 
@@ -288,6 +290,14 @@ export class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoin {
288
290
  return Object.values(this.events())
289
291
  }
290
292
 
293
+ getEventBy(cb: (event: RpgEvent) => boolean): RpgEvent | undefined {
294
+ return this.getEventsBy(cb)[0]
295
+ }
296
+
297
+ getEventsBy(cb: (event: RpgEvent) => boolean): RpgEvent[] {
298
+ return this.getEvents().filter(cb)
299
+ }
300
+
291
301
  removeEvent(eventId: string) {
292
302
  delete this.events()[eventId]
293
303
  }
@@ -371,9 +381,23 @@ export class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoin {
371
381
  animationName,
372
382
  })
373
383
  }
384
+
385
+ /**
386
+ * Set the sync schema for the map
387
+ * @param schema - The schema to set
388
+ */
389
+ setSync(schema: any) {
390
+ for (let key in schema) {
391
+ this[key] = type(signal(null), key, {
392
+ syncWithClient: schema[key]?.$syncWithClient,
393
+ persist: schema[key]?.$permanent,
394
+ }, this)
395
+ }
396
+ }
374
397
  }
375
398
 
376
399
  export interface RpgMap {
377
400
  $send: (conn: MockConnection, data: any) => void;
378
401
  $broadcast: (data: any) => void;
402
+ $sessionTransfer: (userOrPublicId: any | string, targetRoomId: string) => void;
379
403
  }