@rpgjs/server 4.1.3 → 4.2.1

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 (45) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/browser/rpg.server.js +768 -366
  3. package/browser/rpg.server.umd.cjs +754 -352
  4. package/lib/Game/EventManager.js +1 -1
  5. package/lib/Game/EventManager.js.map +1 -1
  6. package/lib/Game/Map.d.ts +4 -0
  7. package/lib/Game/Map.js +11 -1
  8. package/lib/Game/Map.js.map +1 -1
  9. package/lib/Gui/Gui.js +1 -0
  10. package/lib/Gui/Gui.js.map +1 -1
  11. package/lib/MatchMaker.js +3 -1
  12. package/lib/MatchMaker.js.map +1 -1
  13. package/lib/Player/Player.d.ts +9 -3
  14. package/lib/Player/Player.js +24 -16
  15. package/lib/Player/Player.js.map +1 -1
  16. package/lib/RpgServer.d.ts +29 -0
  17. package/lib/Scenes/Map.d.ts +2 -3
  18. package/lib/Scenes/Map.js +7 -3
  19. package/lib/Scenes/Map.js.map +1 -1
  20. package/lib/entry-point.js +18 -12
  21. package/lib/entry-point.js.map +1 -1
  22. package/lib/express/server.js +0 -10
  23. package/lib/express/server.js.map +1 -1
  24. package/lib/index.d.ts +1 -0
  25. package/lib/index.js +1 -0
  26. package/lib/index.js.map +1 -1
  27. package/lib/inject.d.ts +22 -0
  28. package/lib/inject.js +29 -0
  29. package/lib/inject.js.map +1 -0
  30. package/lib/server.d.ts +7 -5
  31. package/lib/server.js +82 -38
  32. package/lib/server.js.map +1 -1
  33. package/package.json +7 -8
  34. package/src/Game/EventManager.ts +1 -1
  35. package/src/Game/Map.ts +15 -1
  36. package/src/Gui/Gui.ts +1 -0
  37. package/src/MatchMaker.ts +3 -1
  38. package/src/Player/Player.ts +18 -10
  39. package/src/RpgServer.ts +30 -1
  40. package/src/Scenes/Map.ts +6 -2
  41. package/src/entry-point.ts +19 -12
  42. package/src/express/server.ts +0 -10
  43. package/src/index.ts +1 -0
  44. package/src/inject.ts +33 -0
  45. package/src/server.ts +86 -35
@@ -1,7 +1,8 @@
1
- import { RpgCommonGame, HookServer, loadModules, ModuleType, GameSide, RpgPlugin } from '@rpgjs/common'
1
+ import { RpgCommonGame, HookServer, loadModules, ModuleType, GameSide, RpgPlugin, InjectContext } from '@rpgjs/common'
2
2
  import { RpgServerEngine } from './server'
3
3
  import { RpgPlayer } from './Player/Player'
4
4
  import { RpgMatchMaker } from './MatchMaker'
5
+ import { inject, setInject } from './inject'
5
6
 
6
7
  interface RpgServerEntryPointOptions {
7
8
  /**
@@ -39,7 +40,10 @@ interface RpgServerEntryPointOptions {
39
40
  }
40
41
 
41
42
  export default async function (modules: ModuleType[], options: RpgServerEntryPointOptions): Promise<RpgServerEngine> {
42
- const gameEngine = new RpgCommonGame(GameSide.Server)
43
+ const context = new InjectContext()
44
+ setInject(context)
45
+
46
+ inject(RpgCommonGame, [GameSide.Server])
43
47
 
44
48
  if (!options.globalConfig) options.globalConfig = {}
45
49
 
@@ -59,7 +63,8 @@ export default async function (modules: ModuleType[], options: RpgServerEntryPoi
59
63
 
60
64
  const relationsEngine = {
61
65
  onStart: HookServer.Start,
62
- onStep: HookServer.Step
66
+ onStep: HookServer.Step,
67
+ auth: HookServer.Auth
63
68
  }
64
69
 
65
70
  const { playerProps } = await loadModules(modules, {
@@ -91,14 +96,16 @@ export default async function (modules: ModuleType[], options: RpgServerEntryPoi
91
96
  return mod
92
97
  })
93
98
 
94
- const serverEngine = new RpgServerEngine(options.io, gameEngine, {
95
- debug: {},
96
- updateRate: 10,
97
- stepRate: 60,
98
- timeoutInterval: 0,
99
- countConnections: false,
100
- playerProps,
101
- ...options
102
- })
99
+ const serverEngine = inject(RpgServerEngine, [
100
+ options.io, {
101
+ debug: {},
102
+ updateRate: 10,
103
+ stepRate: 60,
104
+ timeoutInterval: 0,
105
+ countConnections: false,
106
+ playerProps,
107
+ ...options
108
+ }
109
+ ])
103
110
  return serverEngine
104
111
  }
@@ -83,15 +83,5 @@ export function expressServer(modules: ModuleType[], options: ExpressServerOptio
83
83
  process.on('unhandledRejection', function (reason: any) {
84
84
  console.log(pe.render(reason))
85
85
  })
86
-
87
- if (import.meta['hot']) {
88
- import.meta['hot'].on("vite:beforeFullReload", () => {
89
- server.close()
90
- Query.getPlayers().forEach(player => {
91
- player.gameReload()
92
- })
93
- rpgGame.stop()
94
- });
95
- }
96
86
  })
97
87
  }
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')
@@ -237,10 +243,31 @@ export class RpgServerEngine {
237
243
  return Query._getShapesOfMap(map)
238
244
  }
239
245
  })
240
- this.io.on('connection', this.onPlayerConnected.bind(this))
246
+ //this.io.on('connection', this.onPlayerConnected.bind(this))
247
+ this.transport(this.io)
241
248
  await RpgPlugin.emit(HookServer.Start, this)
242
249
  }
243
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
+
244
271
  get tick(): Observable<Tick> {
245
272
  return this.scheduler.tick as any
246
273
  }
@@ -253,8 +280,8 @@ export class RpgServerEngine {
253
280
  * @returns {void}
254
281
  * @memberof RpgServerEngine
255
282
  */
256
- send() {
257
- this.world.send()
283
+ send(): Promise<void> {
284
+ return this.world.send()
258
285
  }
259
286
 
260
287
  private async updatePlayersMove(deltaTimeInt: number) {
@@ -266,7 +293,7 @@ export class RpgServerEngine {
266
293
  if (!playerInstance) continue
267
294
  const player = playerInstance.otherPossessedPlayer ?? playerInstance
268
295
  if (player.pendingMove.length > 0) {
269
- player.moving = true
296
+
270
297
  const lastFrame = player.pendingMove[player.pendingMove.length - 1]
271
298
  if (this.inputOptions.workers) obj.push(player.toObject())
272
299
  else {
@@ -320,8 +347,7 @@ export class RpgServerEngine {
320
347
  maps: this.inputOptions.maps,
321
348
  events: this.inputOptions.events,
322
349
  worldMaps: this.inputOptions.worldMaps
323
- },
324
- this
350
+ }
325
351
  ))
326
352
  }
327
353
 
@@ -351,11 +377,58 @@ export class RpgServerEngine {
351
377
  currentPlayer._socket.emit(eventName, data)
352
378
  }
353
379
 
354
- private onPlayerConnected(socket) {
355
- const { token } = socket.handshake.auth
356
- const playerId = Utils.generateUID()
357
- const player: RpgPlayer = new RpgPlayer(this.gameEngine, playerId)
358
- 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 })
359
432
 
360
433
  socket.on('move', (data: { input: string[], frame: number }) => {
361
434
  if (!data?.input) return
@@ -372,28 +445,6 @@ export class RpgServerEngine {
372
445
  }
373
446
  })
374
447
 
375
- socket.on('disconnect', () => {
376
- this.onPlayerDisconnected(playerId)
377
- })
378
-
379
- this.world.setUser(player, socket)
380
-
381
- player.server = this
382
- player._init()
383
-
384
- if (!token) {
385
- const newToken = Utils.generateUID() + '-' + Utils.generateUID() + '-' + Utils.generateUID()
386
- player.session = newToken
387
- }
388
-
389
- socket.emit('playerJoined', { playerId, session: player.session })
390
-
391
- if (!token) {
392
- player.execMethod('onConnected')
393
- }
394
- else {
395
- RpgPlugin.emit(HookServer.ScalabilityPlayerConnected, player)
396
- }
397
448
  }
398
449
 
399
450
  private onPlayerDisconnected(playerId: string) {