@rpgjs/server 5.0.0-alpha.21 → 5.0.0-alpha.23

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.
@@ -2,6 +2,7 @@ import { MockConnection, RoomOnJoin } from '@signe/room';
2
2
  import { Hooks, RpgCommonMap, RpgShape, WorldMapsManager, WorldMapConfig } from '@rpgjs/common';
3
3
  import { RpgPlayer, RpgEvent } from '../Player/Player';
4
4
  import { BehaviorSubject } from 'rxjs';
5
+ import { MapOptions } from '../decorators/map';
5
6
  /**
6
7
  * Interface for input controls configuration
7
8
  *
@@ -35,7 +36,9 @@ export interface EventHooks {
35
36
  onInShape?: (zone: RpgShape, player: RpgPlayer) => void;
36
37
  /** Called when a player exits a shape */
37
38
  onOutShape?: (zone: RpgShape, player: RpgPlayer) => void;
39
+ /** Called when a player is detected entering a shape */
38
40
  onDetectInShape?: (player: RpgPlayer, shape: RpgShape) => void;
41
+ /** Called when a player is detected exiting a shape */
39
42
  onDetectOutShape?: (player: RpgPlayer, shape: RpgShape) => void;
40
43
  }
41
44
  /** Type for event class constructor */
@@ -56,12 +59,104 @@ export type EventPosOption = {
56
59
  event: EventConstructor | (EventHooks & Record<string, any>);
57
60
  };
58
61
  export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoin {
62
+ /**
63
+ * Synchronized signal containing all players currently on the map
64
+ *
65
+ * This signal is automatically synchronized with clients using @signe/sync.
66
+ * Players are indexed by their unique ID.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * // Get all players
71
+ * const allPlayers = map.players();
72
+ *
73
+ * // Get a specific player
74
+ * const player = map.players()['player-id'];
75
+ * ```
76
+ */
59
77
  players: import('@signe/reactive').WritableObjectSignal<{}>;
78
+ /**
79
+ * Synchronized signal containing all events (NPCs, objects) on the map
80
+ *
81
+ * This signal is automatically synchronized with clients using @signe/sync.
82
+ * Events are indexed by their unique ID.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // Get all events
87
+ * const allEvents = map.events();
88
+ *
89
+ * // Get a specific event
90
+ * const event = map.events()['event-id'];
91
+ * ```
92
+ */
60
93
  events: import('@signe/reactive').WritableObjectSignal<{}>;
94
+ /**
95
+ * Signal containing the map's database of items, classes, and other game data
96
+ *
97
+ * This database can be dynamically populated using `addInDatabase()` and
98
+ * `removeInDatabase()` methods. It's used to store game entities like items,
99
+ * classes, skills, etc. that are specific to this map.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * // Add data to database
104
+ * map.addInDatabase('Potion', PotionClass);
105
+ *
106
+ * // Access database
107
+ * const potion = map.database()['Potion'];
108
+ * ```
109
+ */
61
110
  database: import('@signe/reactive').WritableObjectSignal<{}>;
62
- maps: any[];
111
+ /**
112
+ * Array of map configurations - can contain MapOptions objects or instances of map classes
113
+ *
114
+ * This array stores the configuration for this map and any related maps.
115
+ * It's populated when the map is loaded via `updateMap()`.
116
+ */
117
+ maps: (MapOptions | any)[];
118
+ /**
119
+ * Array of sound IDs to play when players join the map
120
+ *
121
+ * These sounds are automatically played for each player when they join the map.
122
+ * Sounds must be defined on the client side.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * // Set sounds for the map
127
+ * map.sounds = ['background-music', 'ambient-forest'];
128
+ * ```
129
+ */
130
+ sounds: string[];
131
+ /**
132
+ * BehaviorSubject that completes when the map data is ready
133
+ *
134
+ * This subject is used to signal when the map has finished loading all its data.
135
+ * Players wait for this to complete before the map is fully initialized.
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * // Wait for map data to be ready
140
+ * map.dataIsReady$.subscribe(() => {
141
+ * console.log('Map is ready!');
142
+ * });
143
+ * ```
144
+ */
63
145
  dataIsReady$: BehaviorSubject<void>;
146
+ /**
147
+ * Global configuration object for the map
148
+ *
149
+ * This object contains configuration settings that apply to the entire map.
150
+ * It's populated from the map data when `updateMap()` is called.
151
+ */
64
152
  globalConfig: any;
153
+ /**
154
+ * Damage formulas configuration for the map
155
+ *
156
+ * Contains formulas for calculating damage from skills, physical attacks,
157
+ * critical hits, and element coefficients. Default formulas are merged
158
+ * with custom formulas when the map is loaded.
159
+ */
65
160
  damageFormulas: any;
66
161
  /** Internal: Map of shapes by name */
67
162
  private _shapes;
@@ -108,32 +203,301 @@ export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoi
108
203
  * ```
109
204
  */
110
205
  private setupCollisionDetection;
206
+ /**
207
+ * Intercepts and modifies packets before they are sent to clients
208
+ *
209
+ * This method is automatically called by @signe/room for each packet sent to clients.
210
+ * It adds timestamp and acknowledgment information to sync packets for client-side
211
+ * prediction reconciliation. This helps with network synchronization and reduces
212
+ * perceived latency.
213
+ *
214
+ * ## Architecture
215
+ *
216
+ * Adds metadata to packets:
217
+ * - `timestamp`: Current server time for client-side prediction
218
+ * - `ack`: Acknowledgment info with last processed frame and authoritative position
219
+ *
220
+ * @param player - The player receiving the packet
221
+ * @param packet - The packet data to intercept
222
+ * @param conn - The connection object
223
+ * @returns Modified packet with timestamp and ack info, or null if player is invalid
224
+ *
225
+ * @example
226
+ * ```ts
227
+ * // This method is called automatically by the framework
228
+ * // You typically don't call it directly
229
+ * ```
230
+ */
111
231
  interceptorPacket(player: RpgPlayer, packet: any, conn: MockConnection): any;
232
+ /**
233
+ * Called when a player joins the map
234
+ *
235
+ * This method is automatically called by @signe/room when a player connects to the map.
236
+ * It initializes the player's connection, sets up the map context, and waits for
237
+ * the map data to be ready before playing sounds and triggering hooks.
238
+ *
239
+ * ## Architecture
240
+ *
241
+ * 1. Sets player's map reference and context
242
+ * 2. Initializes the player
243
+ * 3. Waits for map data to be ready
244
+ * 4. Plays map sounds for the player
245
+ * 5. Triggers `server-player-onJoinMap` hook
246
+ *
247
+ * @param player - The player joining the map
248
+ * @param conn - The connection object for the player
249
+ *
250
+ * @example
251
+ * ```ts
252
+ * // This method is called automatically by the framework
253
+ * // You can listen to the hook to perform custom logic
254
+ * server.addHook('server-player-onJoinMap', (player, map) => {
255
+ * console.log(`Player ${player.id} joined map ${map.id}`);
256
+ * });
257
+ * ```
258
+ */
112
259
  onJoin(player: RpgPlayer, conn: MockConnection): void;
113
- onLeave(player: RpgPlayer, conn: MockConnection): void;
260
+ /**
261
+ * Called when a player leaves the map
262
+ *
263
+ * This method is automatically called by @signe/room when a player disconnects from the map.
264
+ * It cleans up the player's pending inputs and triggers the appropriate hooks.
265
+ *
266
+ * ## Architecture
267
+ *
268
+ * 1. Triggers `server-player-onLeaveMap` hook
269
+ * 2. Clears pending inputs to prevent processing after disconnection
270
+ *
271
+ * @param player - The player leaving the map
272
+ * @param conn - The connection object for the player
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * // This method is called automatically by the framework
277
+ * // You can listen to the hook to perform custom cleanup
278
+ * server.addHook('server-player-onLeaveMap', (player, map) => {
279
+ * console.log(`Player ${player.id} left map ${map.id}`);
280
+ * });
281
+ * ```
282
+ */
283
+ onLeave(player: RpgPlayer, conn: MockConnection): Promise<void>;
284
+ /**
285
+ * Get the hooks system for this map
286
+ *
287
+ * Returns the dependency-injected Hooks instance that allows you to trigger
288
+ * and listen to various game events.
289
+ *
290
+ * @returns The Hooks instance for this map
291
+ *
292
+ * @example
293
+ * ```ts
294
+ * // Trigger a custom hook
295
+ * map.hooks.callHooks('custom-event', data).subscribe();
296
+ * ```
297
+ */
114
298
  get hooks(): Hooks;
299
+ /**
300
+ * Get the width of the map in pixels
301
+ *
302
+ * @returns The width of the map in pixels, or 0 if not loaded
303
+ *
304
+ * @example
305
+ * ```ts
306
+ * const width = map.widthPx;
307
+ * console.log(`Map width: ${width}px`);
308
+ * ```
309
+ */
115
310
  get widthPx(): number;
311
+ /**
312
+ * Get the height of the map in pixels
313
+ *
314
+ * @returns The height of the map in pixels, or 0 if not loaded
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * const height = map.heightPx;
319
+ * console.log(`Map height: ${height}px`);
320
+ * ```
321
+ */
116
322
  get heightPx(): number;
323
+ /**
324
+ * Get the unique identifier of the map
325
+ *
326
+ * @returns The map ID, or empty string if not loaded
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * const mapId = map.id;
331
+ * console.log(`Current map: ${mapId}`);
332
+ * ```
333
+ */
117
334
  get id(): string;
335
+ /**
336
+ * Get the X position of this map in the world coordinate system
337
+ *
338
+ * This is used when maps are part of a larger world map. The world position
339
+ * indicates where this map is located relative to other maps.
340
+ *
341
+ * @returns The X position in world coordinates, or 0 if not in a world
342
+ *
343
+ * @example
344
+ * ```ts
345
+ * const worldX = map.worldX;
346
+ * console.log(`Map is at world position (${worldX}, ${map.worldY})`);
347
+ * ```
348
+ */
118
349
  get worldX(): number;
350
+ /**
351
+ * Get the Y position of this map in the world coordinate system
352
+ *
353
+ * This is used when maps are part of a larger world map. The world position
354
+ * indicates where this map is located relative to other maps.
355
+ *
356
+ * @returns The Y position in world coordinates, or 0 if not in a world
357
+ *
358
+ * @example
359
+ * ```ts
360
+ * const worldY = map.worldY;
361
+ * console.log(`Map is at world position (${map.worldX}, ${worldY})`);
362
+ * ```
363
+ */
119
364
  get worldY(): number;
365
+ /**
366
+ * Handle GUI interaction from a player
367
+ *
368
+ * This method is called when a player interacts with a GUI element.
369
+ * It synchronizes the player's changes to ensure the client state is up to date.
370
+ *
371
+ * @param player - The player performing the interaction
372
+ * @param value - The interaction data from the client
373
+ *
374
+ * @example
375
+ * ```ts
376
+ * // This method is called automatically when a player interacts with a GUI
377
+ * // The interaction data is sent from the client
378
+ * ```
379
+ */
120
380
  guiInteraction(player: RpgPlayer, value: any): void;
381
+ /**
382
+ * Handle GUI exit from a player
383
+ *
384
+ * This method is called when a player closes or exits a GUI.
385
+ * It removes the GUI from the player's active GUIs.
386
+ *
387
+ * @param player - The player exiting the GUI
388
+ * @param guiId - The ID of the GUI being exited
389
+ * @param data - Optional data associated with the GUI exit
390
+ *
391
+ * @example
392
+ * ```ts
393
+ * // This method is called automatically when a player closes a GUI
394
+ * // The GUI is removed from the player's active GUIs
395
+ * ```
396
+ */
121
397
  guiExit(player: RpgPlayer, { guiId, data }: {
122
398
  guiId: any;
123
399
  data: any;
124
400
  }): void;
401
+ /**
402
+ * Handle action input from a player
403
+ *
404
+ * This method is called when a player performs an action (like pressing a button).
405
+ * It checks for collisions with events and triggers the appropriate hooks.
406
+ *
407
+ * ## Architecture
408
+ *
409
+ * 1. Gets all entities colliding with the player
410
+ * 2. Triggers `onAction` hook on colliding events
411
+ * 3. Triggers `onInput` hook on the player
412
+ *
413
+ * @param player - The player performing the action
414
+ * @param action - The action data (button pressed, etc.)
415
+ *
416
+ * @example
417
+ * ```ts
418
+ * // This method is called automatically when a player presses an action button
419
+ * // Events near the player will have their onAction hook triggered
420
+ * ```
421
+ */
125
422
  onAction(player: RpgPlayer, action: any): void;
423
+ /**
424
+ * Handle movement input from a player
425
+ *
426
+ * This method is called when a player sends movement input from the client.
427
+ * It queues the input for processing by the game loop. Inputs are processed
428
+ * with frame numbers to ensure proper ordering and client-side prediction.
429
+ *
430
+ * ## Architecture
431
+ *
432
+ * - Inputs are queued in `player.pendingInputs`
433
+ * - Duplicate frames are skipped to prevent processing the same input twice
434
+ * - Inputs are processed asynchronously by the game loop
435
+ *
436
+ * @param player - The player sending the movement input
437
+ * @param input - The input data containing frame number, input direction, and timestamp
438
+ *
439
+ * @example
440
+ * ```ts
441
+ * // This method is called automatically when a player moves
442
+ * // The input is queued and processed by processInput()
443
+ * ```
444
+ */
126
445
  onInput(player: RpgPlayer, input: any): Promise<void>;
446
+ /**
447
+ * Update the map configuration and data
448
+ *
449
+ * This endpoint receives map data from the client and initializes the map.
450
+ * It loads the map configuration, damage formulas, events, and physics.
451
+ *
452
+ * ## Architecture
453
+ *
454
+ * 1. Validates the request body using MapUpdateSchema
455
+ * 2. Updates map data, global config, and damage formulas
456
+ * 3. Merges events and sounds from map configuration
457
+ * 4. Triggers hooks for map loading
458
+ * 5. Loads physics engine
459
+ * 6. Creates all events on the map
460
+ * 7. Completes the dataIsReady$ subject
461
+ *
462
+ * @param request - HTTP request containing map data
463
+ * @returns Promise that resolves when the map is fully loaded
464
+ *
465
+ * @example
466
+ * ```ts
467
+ * // This endpoint is called automatically when a map is loaded
468
+ * // POST /map/update
469
+ * // Body: { id: string, width: number, height: number, config?: any, damageFormulas?: any }
470
+ * ```
471
+ */
127
472
  updateMap(request: Request): Promise<void>;
128
473
  /**
129
474
  * Update (or create) a world configuration and propagate to all maps in that world
130
475
  *
131
- * Body must contain the world config as defined by Tiled world import or an array of maps.
132
- * If the world does not exist yet for this scene, it is created (auto-create).
476
+ * This endpoint receives world map configuration data (typically from Tiled world import)
477
+ * and creates or updates the world manager. The world ID is extracted from the URL path.
478
+ *
479
+ * ## Architecture
480
+ *
481
+ * 1. Extracts world ID from URL path parameter
482
+ * 2. Normalizes input to array of WorldMapConfig
483
+ * 3. Ensures all required map properties are present (width, height, tile sizes)
484
+ * 4. Creates or updates the world manager
133
485
  *
134
486
  * Expected payload examples:
135
- * - { id: string, maps: WorldMapConfig[] }
136
- * - WorldMapConfig[]
487
+ * - `{ id: string, maps: WorldMapConfig[] }`
488
+ * - `WorldMapConfig[]`
489
+ *
490
+ * @param request - HTTP request containing world configuration
491
+ * @returns Promise resolving to `{ ok: true }` when complete
492
+ *
493
+ * @example
494
+ * ```ts
495
+ * // POST /world/my-world/update
496
+ * // Body: [{ id: 'map1', worldX: 0, worldY: 0, width: 800, height: 600 }]
497
+ *
498
+ * // Or with nested structure
499
+ * // Body: { id: 'my-world', maps: [{ id: 'map1', ... }] }
500
+ * ```
137
501
  */
138
502
  updateWorld(request: Request): Promise<any>;
139
503
  /**
@@ -176,17 +540,85 @@ export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoi
176
540
  player: RpgPlayer;
177
541
  inputs: string[];
178
542
  }>;
543
+ /**
544
+ * Main game loop that processes player inputs
545
+ *
546
+ * This private method runs continuously every 50ms to process pending inputs
547
+ * for all players on the map. It ensures inputs are processed in order and
548
+ * prevents concurrent processing for the same player.
549
+ *
550
+ * ## Architecture
551
+ *
552
+ * - Runs every 50ms for responsive input processing
553
+ * - Processes inputs for each player with pending inputs
554
+ * - Uses a flag to prevent concurrent processing for the same player
555
+ * - Calls `processInput()` to handle anti-cheat validation and movement
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * // This method is called automatically in the constructor
560
+ * // You typically don't call it directly
561
+ * ```
562
+ */
179
563
  private loop;
180
564
  /**
181
- * Get a world manager by id (if multiple supported in future)
565
+ * Get a world manager by id
566
+ *
567
+ * Returns the world maps manager for the given world ID. Currently, only
568
+ * one world manager is supported per map instance.
569
+ *
570
+ * @param id - The world ID (currently unused, returns the single manager)
571
+ * @returns The WorldMapsManager instance, or null if not initialized
572
+ *
573
+ * @example
574
+ * ```ts
575
+ * const worldManager = map.getWorldMaps('my-world');
576
+ * if (worldManager) {
577
+ * const mapInfo = worldManager.getMapInfo('map1');
578
+ * }
579
+ * ```
182
580
  */
183
581
  getWorldMaps(id: string): WorldMapsManager | null;
184
582
  /**
185
583
  * Delete a world manager by id
584
+ *
585
+ * Removes the world maps manager from this map instance. Currently, only
586
+ * one world manager is supported, so this clears the single manager.
587
+ *
588
+ * @param id - The world ID (currently unused)
589
+ * @returns true if the manager was deleted, false if it didn't exist
590
+ *
591
+ * @example
592
+ * ```ts
593
+ * const deleted = map.deleteWorldMaps('my-world');
594
+ * if (deleted) {
595
+ * console.log('World manager removed');
596
+ * }
597
+ * ```
186
598
  */
187
599
  deleteWorldMaps(id: string): boolean;
188
600
  /**
189
601
  * Create a world manager dynamically
602
+ *
603
+ * Creates a new WorldMapsManager instance and configures it with the provided
604
+ * map configurations. This is used when loading world data from Tiled or
605
+ * other map editors.
606
+ *
607
+ * @param world - World configuration object
608
+ * @param world.id - Optional world identifier
609
+ * @param world.maps - Array of map configurations for the world
610
+ * @returns The newly created WorldMapsManager instance
611
+ *
612
+ * @example
613
+ * ```ts
614
+ * const manager = map.createDynamicWorldMaps({
615
+ * id: 'my-world',
616
+ * maps: [
617
+ * { id: 'map1', worldX: 0, worldY: 0, width: 800, height: 600 },
618
+ * { id: 'map2', worldX: 800, worldY: 0, width: 800, height: 600 }
619
+ * ]
620
+ * });
621
+ * ```
190
622
  */
191
623
  createDynamicWorldMaps(world: {
192
624
  id?: string;
@@ -194,6 +626,22 @@ export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoi
194
626
  }): WorldMapsManager;
195
627
  /**
196
628
  * Update world maps by id. Auto-create when missing.
629
+ *
630
+ * Updates the world maps configuration. If the world manager doesn't exist,
631
+ * it is automatically created. This is useful for dynamically loading world
632
+ * data or updating map positions.
633
+ *
634
+ * @param id - The world ID
635
+ * @param maps - Array of map configurations to update
636
+ * @returns Promise that resolves when the update is complete
637
+ *
638
+ * @example
639
+ * ```ts
640
+ * await map.updateWorldMaps('my-world', [
641
+ * { id: 'map1', worldX: 0, worldY: 0, width: 800, height: 600 },
642
+ * { id: 'map2', worldX: 800, worldY: 0, width: 800, height: 600 }
643
+ * ]);
644
+ * ```
197
645
  */
198
646
  updateWorldMaps(id: string, maps: WorldMapConfig[]): Promise<void>;
199
647
  /**
@@ -286,12 +734,147 @@ export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoi
286
734
  * });
287
735
  */
288
736
  createDynamicEvent(eventObj: EventPosOption): Promise<void>;
737
+ /**
738
+ * Get an event by its ID
739
+ *
740
+ * Returns the event with the specified ID, or undefined if not found.
741
+ * The return type can be narrowed using TypeScript generics.
742
+ *
743
+ * @param eventId - The unique identifier of the event
744
+ * @returns The event instance, or undefined if not found
745
+ *
746
+ * @example
747
+ * ```ts
748
+ * // Get any event
749
+ * const event = map.getEvent('npc-1');
750
+ *
751
+ * // Get event with type narrowing
752
+ * const npc = map.getEvent<MyNPC>('npc-1');
753
+ * if (npc) {
754
+ * npc.speak('Hello!');
755
+ * }
756
+ * ```
757
+ */
289
758
  getEvent<T extends RpgPlayer>(eventId: string): T | undefined;
759
+ /**
760
+ * Get a player by their ID
761
+ *
762
+ * Returns the player with the specified ID, or undefined if not found.
763
+ *
764
+ * @param playerId - The unique identifier of the player
765
+ * @returns The player instance, or undefined if not found
766
+ *
767
+ * @example
768
+ * ```ts
769
+ * const player = map.getPlayer('player-123');
770
+ * if (player) {
771
+ * console.log(`Player ${player.name} is on the map`);
772
+ * }
773
+ * ```
774
+ */
290
775
  getPlayer(playerId: string): RpgPlayer | undefined;
776
+ /**
777
+ * Get all players currently on the map
778
+ *
779
+ * Returns an array of all players that are currently connected to this map.
780
+ *
781
+ * @returns Array of all RpgPlayer instances on the map
782
+ *
783
+ * @example
784
+ * ```ts
785
+ * const players = map.getPlayers();
786
+ * console.log(`There are ${players.length} players on the map`);
787
+ *
788
+ * players.forEach(player => {
789
+ * console.log(`- ${player.name}`);
790
+ * });
791
+ * ```
792
+ */
291
793
  getPlayers(): RpgPlayer[];
794
+ /**
795
+ * Get all events on the map
796
+ *
797
+ * Returns an array of all events (NPCs, objects, etc.) that are currently
798
+ * on this map.
799
+ *
800
+ * @returns Array of all RpgEvent instances on the map
801
+ *
802
+ * @example
803
+ * ```ts
804
+ * const events = map.getEvents();
805
+ * console.log(`There are ${events.length} events on the map`);
806
+ *
807
+ * events.forEach(event => {
808
+ * console.log(`- ${event.name} at (${event.x}, ${event.y})`);
809
+ * });
810
+ * ```
811
+ */
292
812
  getEvents(): RpgEvent[];
813
+ /**
814
+ * Get the first event that matches a condition
815
+ *
816
+ * Searches through all events on the map and returns the first one that
817
+ * matches the provided callback function.
818
+ *
819
+ * @param cb - Callback function that returns true for the desired event
820
+ * @returns The first matching event, or undefined if none found
821
+ *
822
+ * @example
823
+ * ```ts
824
+ * // Find an event by name
825
+ * const npc = map.getEventBy(event => event.name === 'Merchant');
826
+ *
827
+ * // Find an event at a specific position
828
+ * const chest = map.getEventBy(event =>
829
+ * event.x === 100 && event.y === 200
830
+ * );
831
+ * ```
832
+ */
293
833
  getEventBy(cb: (event: RpgEvent) => boolean): RpgEvent | undefined;
834
+ /**
835
+ * Get all events that match a condition
836
+ *
837
+ * Searches through all events on the map and returns all events that
838
+ * match the provided callback function.
839
+ *
840
+ * @param cb - Callback function that returns true for desired events
841
+ * @returns Array of all matching events
842
+ *
843
+ * @example
844
+ * ```ts
845
+ * // Find all NPCs
846
+ * const npcs = map.getEventsBy(event => event.name.startsWith('NPC-'));
847
+ *
848
+ * // Find all events in a specific area
849
+ * const nearbyEvents = map.getEventsBy(event =>
850
+ * event.x >= 0 && event.x <= 100 &&
851
+ * event.y >= 0 && event.y <= 100
852
+ * );
853
+ * ```
854
+ */
294
855
  getEventsBy(cb: (event: RpgEvent) => boolean): RpgEvent[];
856
+ /**
857
+ * Remove an event from the map
858
+ *
859
+ * Removes the event with the specified ID from the map. The event will
860
+ * be removed from the synchronized events signal, causing it to disappear
861
+ * on all clients.
862
+ *
863
+ * @param eventId - The unique identifier of the event to remove
864
+ *
865
+ * @example
866
+ * ```ts
867
+ * // Remove an event
868
+ * map.removeEvent('npc-1');
869
+ *
870
+ * // Remove event after interaction
871
+ * const chest = map.getEvent('chest-1');
872
+ * if (chest) {
873
+ * // ... do something with chest ...
874
+ * map.removeEvent('chest-1');
875
+ * }
876
+ * ```
877
+ */
295
878
  removeEvent(eventId: string): void;
296
879
  /**
297
880
  * Display a component animation at a specific position on the map
@@ -363,16 +946,44 @@ export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoi
363
946
  x: number;
364
947
  y: number;
365
948
  }, graphic: string, animationName?: string): void;
366
- /**
367
- * Set the sync schema for the map
368
- * @param schema - The schema to set
369
- */
370
949
  /**
371
950
  * Configure runtime synchronized properties on the map
372
951
  *
373
- * Design
952
+ * This method allows you to dynamically add synchronized properties to the map
953
+ * that will be automatically synced with clients. The schema follows the same
954
+ * structure as module properties with `$initial`, `$syncWithClient`, and `$permanent` options.
955
+ *
956
+ * ## Architecture
957
+ *
374
958
  * - Reads a schema object shaped like module props
375
959
  * - Creates typed sync signals with @signe/sync
960
+ * - Properties are accessible as `map.propertyName`
961
+ *
962
+ * @param schema - Schema object defining the properties to sync
963
+ * @param schema[key].$initial - Initial value for the property
964
+ * @param schema[key].$syncWithClient - Whether to sync this property to clients
965
+ * @param schema[key].$permanent - Whether to persist this property
966
+ *
967
+ * @example
968
+ * ```ts
969
+ * // Add synchronized properties to the map
970
+ * map.setSync({
971
+ * weather: {
972
+ * $initial: 'sunny',
973
+ * $syncWithClient: true,
974
+ * $permanent: false
975
+ * },
976
+ * timeOfDay: {
977
+ * $initial: 12,
978
+ * $syncWithClient: true,
979
+ * $permanent: false
980
+ * }
981
+ * });
982
+ *
983
+ * // Use the properties
984
+ * map.weather.set('rainy');
985
+ * const currentWeather = map.weather();
986
+ * ```
376
987
  */
377
988
  setSync(schema: Record<string, any>): void;
378
989
  /**
@@ -580,6 +1191,59 @@ export declare class RpgMap extends RpgCommonMap<RpgPlayer> implements RoomOnJoi
580
1191
  * ```
581
1192
  */
582
1193
  stopSound(soundId: string): void;
1194
+ /**
1195
+ * Shake the map for all players
1196
+ *
1197
+ * This method triggers a shake animation on the map for all players currently on the map.
1198
+ * The shake effect creates a visual feedback that can be used for earthquakes, explosions,
1199
+ * impacts, or any dramatic event that should affect the entire map visually.
1200
+ *
1201
+ * ## Architecture
1202
+ *
1203
+ * Broadcasts a shake event to all clients connected to the map. Each client receives
1204
+ * the shake configuration and triggers the shake animation on the map container using
1205
+ * Canvas Engine's shake directive.
1206
+ *
1207
+ * @param options - Optional shake configuration
1208
+ * @param options.intensity - Shake intensity in pixels (default: 10)
1209
+ * @param options.duration - Duration of the shake animation in milliseconds (default: 500)
1210
+ * @param options.frequency - Number of shake oscillations during the animation (default: 10)
1211
+ * @param options.direction - Direction of the shake - 'x', 'y', or 'both' (default: 'both')
1212
+ *
1213
+ * @example
1214
+ * ```ts
1215
+ * // Basic shake with default settings
1216
+ * map.shakeMap();
1217
+ *
1218
+ * // Intense earthquake effect
1219
+ * map.shakeMap({
1220
+ * intensity: 25,
1221
+ * duration: 1000,
1222
+ * frequency: 15,
1223
+ * direction: 'both'
1224
+ * });
1225
+ *
1226
+ * // Horizontal shake for side impact
1227
+ * map.shakeMap({
1228
+ * intensity: 15,
1229
+ * duration: 400,
1230
+ * direction: 'x'
1231
+ * });
1232
+ *
1233
+ * // Vertical shake for ground impact
1234
+ * map.shakeMap({
1235
+ * intensity: 20,
1236
+ * duration: 600,
1237
+ * direction: 'y'
1238
+ * });
1239
+ * ```
1240
+ */
1241
+ shakeMap(options?: {
1242
+ intensity?: number;
1243
+ duration?: number;
1244
+ frequency?: number;
1245
+ direction?: 'x' | 'y' | 'both';
1246
+ }): void;
583
1247
  }
584
1248
  export interface RpgMap {
585
1249
  $send: (conn: MockConnection, data: any) => void;