@rpgjs/server 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -28,3 +28,4 @@ export { RpgMatchMaker } from './MatchMaker'
28
28
  export type { IStoreState } from './Interfaces/StateStore'
29
29
  export { Components } from './Player/ComponentManager'
30
30
  export { Gui } from './Gui/Gui'
31
+ export { inject } from './inject'
package/src/inject.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { InjectContext } from "@rpgjs/common";
2
+
3
+ let instanceContext: InjectContext | null = null
4
+
5
+ /**
6
+ * Dependency injection function for RPGJS server side.
7
+ *
8
+ * The server-side `inject` function is designed for retrieving instances of server-related classes in the RPGJS framework.
9
+ * This function is crucial for accessing singleton instances of classes like `RpgServerEngine` on the server. It facilitates
10
+ * a clean and efficient approach to handling dependencies within server modules, contributing to a more organized codebase.
11
+ *
12
+ * @template T The class type that you want to retrieve an instance of, specific to server-side modules.
13
+ * @returns {T} Returns the singleton instance of the specified class, ensuring consistent server-side behavior and state management.
14
+ * @since 4.2.0
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * // Example of injecting the RpgServerEngine
19
+ * import { inject, RpgServerEngine } from '@rpgjs/server'
20
+ * const server = inject(RpgServerEngine)
21
+ * ```
22
+ */
23
+ export function inject<T>(service: new (...args: any[]) => T, args: any[] = []): T {
24
+ return instanceContext!.inject(service, args);
25
+ }
26
+
27
+ export function setInject(context: InjectContext) {
28
+ instanceContext = context;
29
+ }
30
+
31
+ export function clearInject() {
32
+ instanceContext = null
33
+ }
package/src/server.ts CHANGED
@@ -2,11 +2,12 @@ import { SceneMap } from './Scenes/Map';
2
2
  import { RpgPlayer } from './Player/Player'
3
3
  import { Query } from './Query'
4
4
  import { DAMAGE_SKILL, DAMAGE_PHYSIC, DAMAGE_CRITICAL, COEFFICIENT_ELEMENTS } from './presets'
5
- import { World, WorldClass } from 'simple-room'
5
+ import { World, WorldClass, Transport } from 'simple-room'
6
6
  import { Utils, RpgPlugin, Scheduler, HookServer, RpgCommonGame, DefaultInput } from '@rpgjs/common'
7
7
  import { Observable } from 'rxjs';
8
8
  import { Tick } from '@rpgjs/types';
9
9
  import { Actor, Armor, Class, DatabaseTypes, Item, Skill, State, Weapon } from '@rpgjs/database';
10
+ import { inject } from './inject';
10
11
 
11
12
  export class RpgServerEngine {
12
13
 
@@ -49,10 +50,13 @@ export class RpgServerEngine {
49
50
  protected totalConnected: number = 0
50
51
  private scheduler: Scheduler = new Scheduler()
51
52
  private playerProps: any
53
+ public gameEngine: RpgCommonGame = inject(RpgCommonGame)
52
54
 
53
55
  world: WorldClass = World
54
56
  workers: any
55
57
  envs: any = {}
58
+ io: any
59
+ inputOptions: any = {}
56
60
 
57
61
  /**
58
62
  * Combat formulas
@@ -60,7 +64,9 @@ export class RpgServerEngine {
60
64
  * @prop {Socket Io Server} [io]
61
65
  * @memberof RpgServerEngine
62
66
  */
63
- constructor(public io, public gameEngine: RpgCommonGame, public inputOptions) {
67
+ initialize(io, inputOptions) {
68
+ this.io = io
69
+ this.inputOptions = inputOptions
64
70
  this.envs = inputOptions.envs || {}
65
71
  if (this.inputOptions.workers) {
66
72
  console.log('workers enabled')
@@ -107,18 +113,22 @@ export class RpgServerEngine {
107
113
 
108
114
  if (!this.inputOptions.database) this.inputOptions.database = {}
109
115
 
116
+ /**
117
+ * data is array with object or array
118
+ */
110
119
  const datas = await RpgPlugin.emit(HookServer.AddDatabase, this.inputOptions.database) || []
111
120
 
112
- for (let plug of datas) {
113
- this.inputOptions.database = {
114
- ...plug,
115
- ...this.inputOptions.database
121
+ for (let element of datas) {
122
+ if (Array.isArray(element)) {
123
+ for (let data of element) {
124
+ this.addInDatabase(data.id, data)
125
+ }
126
+ }
127
+ else {
128
+ for (let id in element) {
129
+ this.addInDatabase(element[id].id ?? id, element[id])
130
+ }
116
131
  }
117
- }
118
-
119
- for (let key in this.inputOptions.database) {
120
- const data = this.inputOptions.database[key]
121
- this.addInDatabase(data.id, data)
122
132
  }
123
133
 
124
134
  this.loadScenes()
@@ -233,10 +243,31 @@ export class RpgServerEngine {
233
243
  return Query._getShapesOfMap(map)
234
244
  }
235
245
  })
236
- this.io.on('connection', this.onPlayerConnected.bind(this))
246
+ //this.io.on('connection', this.onPlayerConnected.bind(this))
247
+ this.transport(this.io)
237
248
  await RpgPlugin.emit(HookServer.Start, this)
238
249
  }
239
250
 
251
+ private transport(io): Transport {
252
+ const timeoutDisconnect = this.globalConfig.timeoutDisconnect ?? 0
253
+ const auth = this.globalConfig.disableAuth ? () => Utils.generateUID() :
254
+ async (socket) => {
255
+ const val = await RpgPlugin.emit(HookServer.Auth, [this, socket], true)
256
+ if (val.length == 0) {
257
+ return Utils.generateUID()
258
+ }
259
+ return val[val.length - 1]
260
+ }
261
+ const transport = new Transport(io, {
262
+ timeoutDisconnect,
263
+ auth
264
+ })
265
+ this.world.timeoutDisconnect = timeoutDisconnect
266
+ transport.onConnected(this.onPlayerConnected.bind(this))
267
+ transport.onDisconnected(this.onPlayerDisconnected.bind(this))
268
+ return transport
269
+ }
270
+
240
271
  get tick(): Observable<Tick> {
241
272
  return this.scheduler.tick as any
242
273
  }
@@ -249,8 +280,8 @@ export class RpgServerEngine {
249
280
  * @returns {void}
250
281
  * @memberof RpgServerEngine
251
282
  */
252
- send() {
253
- this.world.send()
283
+ send(): Promise<void> {
284
+ return this.world.send()
254
285
  }
255
286
 
256
287
  private async updatePlayersMove(deltaTimeInt: number) {
@@ -316,8 +347,7 @@ export class RpgServerEngine {
316
347
  maps: this.inputOptions.maps,
317
348
  events: this.inputOptions.events,
318
349
  worldMaps: this.inputOptions.worldMaps
319
- },
320
- this
350
+ }
321
351
  ))
322
352
  }
323
353
 
@@ -347,11 +377,58 @@ export class RpgServerEngine {
347
377
  currentPlayer._socket.emit(eventName, data)
348
378
  }
349
379
 
350
- private onPlayerConnected(socket) {
351
- const { token } = socket.handshake.auth
352
- const playerId = Utils.generateUID()
353
- const player: RpgPlayer = new RpgPlayer(this.gameEngine, playerId)
354
- player.session = token
380
+ private getPlayerBySession(session: string): RpgPlayer | null {
381
+ const users = this.world.getUsers<RpgPlayer>()
382
+ for (let userId in users) {
383
+ const user = users[userId]
384
+ if (user.session === session) {
385
+ return user
386
+ }
387
+ }
388
+ return null
389
+ }
390
+
391
+ private onPlayerConnected(socket, playerId: string) {
392
+ const existingUser = this.world.getUser<RpgPlayer>(playerId, false)
393
+
394
+ this.world.connectUser(socket, playerId)
395
+
396
+ let player: RpgPlayer
397
+
398
+ if (!existingUser) {
399
+ const { token } = socket.handshake.auth
400
+ player = new RpgPlayer(playerId)
401
+ player.session = token
402
+
403
+ this.world.setUser(player, socket)
404
+
405
+ player._init()
406
+
407
+ if (!token) {
408
+ const newToken = Utils.generateUID() + '-' + Utils.generateUID() + '-' + Utils.generateUID()
409
+ player.session = newToken
410
+ }
411
+
412
+ if (!token) {
413
+ player.execMethod('onConnected')
414
+ }
415
+ else {
416
+ RpgPlugin.emit(HookServer.ScalabilityPlayerConnected, player)
417
+ }
418
+ }
419
+ else {
420
+ player = existingUser
421
+ if (player.map) {
422
+ player.emit('preLoadScene', {
423
+ reconnect: true,
424
+ id: player.map
425
+ })
426
+ player.emitSceneMap()
427
+ this.world.joinRoom(player.map, playerId)
428
+ }
429
+ }
430
+
431
+ socket.emit('playerJoined', { playerId, session: player.session })
355
432
 
356
433
  socket.on('move', (data: { input: string[], frame: number }) => {
357
434
  if (!data?.input) return
@@ -368,28 +445,6 @@ export class RpgServerEngine {
368
445
  }
369
446
  })
370
447
 
371
- socket.on('disconnect', () => {
372
- this.onPlayerDisconnected(playerId)
373
- })
374
-
375
- this.world.setUser(player, socket)
376
-
377
- player.server = this
378
- player._init()
379
-
380
- if (!token) {
381
- const newToken = Utils.generateUID() + '-' + Utils.generateUID() + '-' + Utils.generateUID()
382
- player.session = newToken
383
- }
384
-
385
- socket.emit('playerJoined', { playerId, session: player.session })
386
-
387
- if (!token) {
388
- player.execMethod('onConnected')
389
- }
390
- else {
391
- RpgPlugin.emit(HookServer.ScalabilityPlayerConnected, player)
392
- }
393
448
  }
394
449
 
395
450
  private onPlayerDisconnected(playerId: string) {