@rpgjs/server 3.3.2 → 4.0.0-beta.3

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 (152) hide show
  1. package/LICENSE +19 -0
  2. package/lib/Game/Map.d.ts +58 -5
  3. package/lib/Game/Map.js +185 -80
  4. package/lib/Game/Map.js.map +1 -1
  5. package/lib/Game/WorldMaps.d.ts +3 -2
  6. package/lib/Game/WorldMaps.js +6 -11
  7. package/lib/Game/WorldMaps.js.map +1 -1
  8. package/lib/Gui/DialogGui.d.ts +1 -1
  9. package/lib/Gui/DialogGui.js +12 -13
  10. package/lib/Gui/DialogGui.js.map +1 -1
  11. package/lib/Gui/Gui.js +2 -6
  12. package/lib/Gui/Gui.js.map +1 -1
  13. package/lib/Gui/MenuGui.js +4 -8
  14. package/lib/Gui/MenuGui.js.map +1 -1
  15. package/lib/Gui/NotificationGui.js +4 -8
  16. package/lib/Gui/NotificationGui.js.map +1 -1
  17. package/lib/Gui/ShopGui.js +4 -8
  18. package/lib/Gui/ShopGui.js.map +1 -1
  19. package/lib/Gui/index.js +6 -13
  20. package/lib/Gui/index.js.map +1 -1
  21. package/lib/Interfaces/Gui.js +1 -2
  22. package/lib/Interfaces/StateStore.js +1 -2
  23. package/lib/MatchMaker.js +28 -46
  24. package/lib/MatchMaker.js.map +1 -1
  25. package/lib/Monitor/index.js +3 -5
  26. package/lib/Monitor/index.js.map +1 -1
  27. package/lib/Player/BattleManager.js +17 -16
  28. package/lib/Player/BattleManager.js.map +1 -1
  29. package/lib/Player/ClassManager.js +6 -10
  30. package/lib/Player/ClassManager.js.map +1 -1
  31. package/lib/Player/ComponentManager.d.ts +4 -4
  32. package/lib/Player/ComponentManager.js +37 -24
  33. package/lib/Player/ComponentManager.js.map +1 -1
  34. package/lib/Player/EffectManager.js +8 -12
  35. package/lib/Player/EffectManager.js.map +1 -1
  36. package/lib/Player/ElementManager.js +5 -9
  37. package/lib/Player/ElementManager.js.map +1 -1
  38. package/lib/Player/GoldManager.js +1 -5
  39. package/lib/Player/GoldManager.js.map +1 -1
  40. package/lib/Player/GuiManager.js +17 -15
  41. package/lib/Player/GuiManager.js.map +1 -1
  42. package/lib/Player/ItemFixture.js +1 -5
  43. package/lib/Player/ItemFixture.js.map +1 -1
  44. package/lib/Player/ItemManager.d.ts +3 -3
  45. package/lib/Player/ItemManager.js +29 -31
  46. package/lib/Player/ItemManager.js.map +1 -1
  47. package/lib/Player/MoveManager.d.ts +7 -6
  48. package/lib/Player/MoveManager.js +67 -74
  49. package/lib/Player/MoveManager.js.map +1 -1
  50. package/lib/Player/ParameterManager.js +10 -14
  51. package/lib/Player/ParameterManager.js.map +1 -1
  52. package/lib/Player/Player.d.ts +7 -1
  53. package/lib/Player/Player.js +193 -191
  54. package/lib/Player/Player.js.map +1 -1
  55. package/lib/Player/SkillManager.js +18 -22
  56. package/lib/Player/SkillManager.js.map +1 -1
  57. package/lib/Player/StateManager.js +9 -13
  58. package/lib/Player/StateManager.js.map +1 -1
  59. package/lib/Player/VariableManager.js +1 -5
  60. package/lib/Player/VariableManager.js.map +1 -1
  61. package/lib/Query.d.ts +2 -1
  62. package/lib/Query.js +19 -15
  63. package/lib/Query.js.map +1 -1
  64. package/lib/RpgServer.d.ts +11 -3
  65. package/lib/RpgServer.js +1 -2
  66. package/lib/Scenes/Map.d.ts +27 -4
  67. package/lib/Scenes/Map.js +117 -122
  68. package/lib/Scenes/Map.js.map +1 -1
  69. package/lib/decorators/event.js +4 -7
  70. package/lib/decorators/event.js.map +1 -1
  71. package/lib/decorators/map.d.ts +1 -1
  72. package/lib/decorators/map.js +5 -9
  73. package/lib/decorators/map.js.map +1 -1
  74. package/lib/entry-point.js +59 -65
  75. package/lib/entry-point.js.map +1 -1
  76. package/lib/express/api.d.ts +3 -0
  77. package/lib/express/api.js +105 -0
  78. package/lib/express/api.js.map +1 -0
  79. package/lib/express/errors/NotAuthorized.d.ts +4 -0
  80. package/lib/express/errors/NotAuthorized.js +7 -0
  81. package/lib/express/errors/NotAuthorized.js.map +1 -0
  82. package/lib/express/errors/NotFound.d.ts +4 -0
  83. package/lib/express/errors/NotFound.js +7 -0
  84. package/lib/express/errors/NotFound.js.map +1 -0
  85. package/lib/express/server.js +20 -5
  86. package/lib/express/server.js.map +1 -1
  87. package/lib/index.js +15 -68
  88. package/lib/index.js.map +1 -1
  89. package/lib/logs/index.js +5 -11
  90. package/lib/logs/index.js.map +1 -1
  91. package/lib/logs/item.js +11 -15
  92. package/lib/logs/item.js.map +1 -1
  93. package/lib/logs/log.js +1 -5
  94. package/lib/logs/log.js.map +1 -1
  95. package/lib/logs/skill.js +6 -10
  96. package/lib/logs/skill.js.map +1 -1
  97. package/lib/logs/state.js +5 -9
  98. package/lib/logs/state.js.map +1 -1
  99. package/lib/models/Item.js +1 -2
  100. package/lib/presets/index.js +28 -36
  101. package/lib/presets/index.js.map +1 -1
  102. package/lib/server.d.ts +23 -2
  103. package/lib/server.js +227 -134
  104. package/lib/server.js.map +1 -1
  105. package/package.json +24 -16
  106. package/src/Game/Map.ts +513 -0
  107. package/src/Game/WorldMaps.ts +45 -0
  108. package/src/Gui/DialogGui.ts +67 -0
  109. package/src/Gui/Gui.ts +45 -0
  110. package/src/Gui/MenuGui.ts +26 -0
  111. package/src/Gui/NotificationGui.ts +10 -0
  112. package/src/Gui/ShopGui.ts +43 -0
  113. package/src/Gui/index.ts +13 -0
  114. package/src/Interfaces/Gui.ts +4 -0
  115. package/src/Interfaces/StateStore.ts +5 -0
  116. package/src/MatchMaker.ts +63 -0
  117. package/src/Monitor/index.ts +78 -0
  118. package/src/Player/BattleManager.ts +123 -0
  119. package/src/Player/ClassManager.ts +72 -0
  120. package/src/Player/ComponentManager.ts +538 -0
  121. package/src/Player/EffectManager.ts +94 -0
  122. package/src/Player/ElementManager.ts +142 -0
  123. package/src/Player/GoldManager.ts +26 -0
  124. package/src/Player/GuiManager.ts +308 -0
  125. package/src/Player/ItemFixture.ts +24 -0
  126. package/src/Player/ItemManager.ts +474 -0
  127. package/src/Player/MoveManager.ts +635 -0
  128. package/src/Player/ParameterManager.ts +468 -0
  129. package/src/Player/Player.ts +931 -0
  130. package/src/Player/SkillManager.ts +229 -0
  131. package/src/Player/StateManager.ts +230 -0
  132. package/src/Player/VariableManager.ts +55 -0
  133. package/src/Query.ts +172 -0
  134. package/src/RpgServer.ts +429 -0
  135. package/src/Scenes/Map.ts +302 -0
  136. package/src/decorators/event.ts +57 -0
  137. package/src/decorators/map.ts +223 -0
  138. package/src/entry-point.ts +102 -0
  139. package/src/express/api.ts +118 -0
  140. package/src/express/errors/NotAuthorized.ts +6 -0
  141. package/src/express/errors/NotFound.ts +6 -0
  142. package/src/express/server.ts +93 -0
  143. package/src/index.ts +28 -0
  144. package/src/logs/index.ts +11 -0
  145. package/src/logs/item.ts +31 -0
  146. package/src/logs/log.ts +3 -0
  147. package/src/logs/skill.ts +16 -0
  148. package/src/logs/state.ts +13 -0
  149. package/src/models/Item.ts +11 -0
  150. package/src/presets/index.ts +71 -0
  151. package/src/server.ts +394 -0
  152. package/tsconfig.json +27 -0
package/src/server.ts ADDED
@@ -0,0 +1,394 @@
1
+ import { SceneMap } from './Scenes/Map';
2
+ import { RpgPlayer } from './Player/Player'
3
+ import { Query } from './Query'
4
+ import { DAMAGE_SKILL, DAMAGE_PHYSIC, DAMAGE_CRITICAL, COEFFICIENT_ELEMENTS } from './presets'
5
+ import { World, WorldClass } from 'simple-room'
6
+ import { Utils, RpgPlugin, Scheduler, HookServer, RpgCommonGame, DefaultInput } from '@rpgjs/common'
7
+ import { Observable } from 'rxjs';
8
+ import { Tick } from '@rpgjs/types';
9
+ import { Actor, Armor, Class, DatabaseTypes, Item, Skill, State, Weapon } from '@rpgjs/database';
10
+
11
+ export class RpgServerEngine {
12
+
13
+ /**
14
+ * Express App Instance. If you have assigned this variable before starting the game, you can get the instance of Express
15
+ *
16
+ * @prop {Express App} [app]
17
+ * @memberof RpgServerEngine
18
+ */
19
+ app
20
+
21
+ /**
22
+ * List of the data
23
+ *
24
+ * @prop {object} [database]
25
+ * @memberof RpgServerEngine
26
+ */
27
+ public database: any = {}
28
+
29
+ /**
30
+ * retrieve the global configurations assigned at the entry point
31
+ *
32
+ * @prop {object} [globalConfig]
33
+ * @readonly
34
+ * @memberof RpgServerEngine
35
+ * */
36
+ public globalConfig: any = {}
37
+
38
+ public assetsPath: string = 'assets'
39
+
40
+ /**
41
+ * Combat formulas
42
+ *
43
+ * @prop {object} [damageFormulas]
44
+ * @memberof RpgServerEngine
45
+ */
46
+ public damageFormulas: any = {}
47
+
48
+ public serverId: string = process.env.SERVER_ID || Utils.generateUID()
49
+
50
+ private scenes: Map<string, any> = new Map()
51
+ protected totalConnected: number = 0
52
+ private scheduler: Scheduler = new Scheduler()
53
+ private playerProps: any
54
+
55
+ world: WorldClass = World
56
+ workers: any
57
+
58
+ /**
59
+ * Combat formulas
60
+ *
61
+ * @prop {Socket Io Server} [io]
62
+ * @memberof RpgServerEngine
63
+ */
64
+ constructor(public io, public gameEngine: RpgCommonGame, public inputOptions) {
65
+ if (this.inputOptions.workers) {
66
+ console.log('workers enabled')
67
+ this.workers = this.gameEngine.createWorkers(this.inputOptions.workers).load()
68
+ }
69
+ }
70
+
71
+ private async _init() {
72
+ this.damageFormulas = this.inputOptions.damageFormulas || {}
73
+ this.damageFormulas = {
74
+ damageSkill: DAMAGE_SKILL,
75
+ damagePhysic: DAMAGE_PHYSIC,
76
+ damageCritical: DAMAGE_CRITICAL,
77
+ coefficientElements: COEFFICIENT_ELEMENTS,
78
+ ...this.damageFormulas
79
+ }
80
+
81
+ this.globalConfig = this.inputOptions.globalConfig
82
+ if (this.globalConfig.assetsPath !== undefined) this.assetsPath = this.globalConfig.assetsPath
83
+
84
+ if (!this.inputOptions.maps) this.inputOptions.maps = []
85
+ if (!this.inputOptions.events) this.inputOptions.events = []
86
+ if (!this.inputOptions.worldMaps) this.inputOptions.worldMaps = []
87
+ this.playerProps = this.inputOptions.playerProps
88
+
89
+ this.inputOptions.maps = [
90
+ ...Utils.arrayFlat(await RpgPlugin.emit(HookServer.AddMap, this.inputOptions.maps)) || [],
91
+ ...this.inputOptions.maps
92
+ ]
93
+
94
+ this.inputOptions.events = [
95
+ ...Utils.arrayFlat(await RpgPlugin.emit(HookServer.AddEvent, this.inputOptions.events)) || [],
96
+ ...this.inputOptions.events
97
+ ]
98
+
99
+ this.inputOptions.worldMaps = [
100
+ ...Utils.arrayFlat(await RpgPlugin.emit(HookServer.AddWorldMaps, this.inputOptions.worldMaps)) || [],
101
+ ...this.inputOptions.worldMaps
102
+ ]
103
+
104
+ this.globalConfig.inputs = {
105
+ ...DefaultInput,
106
+ ...(this.globalConfig.inputs || {})
107
+ }
108
+
109
+ if (!this.inputOptions.database) this.inputOptions.database = {}
110
+
111
+ const datas = await RpgPlugin.emit(HookServer.AddDatabase, this.inputOptions.database) || []
112
+
113
+ for (let plug of datas) {
114
+ this.inputOptions.database = {
115
+ ...plug,
116
+ ...this.inputOptions.database
117
+ }
118
+ }
119
+
120
+ for (let key in this.inputOptions.database) {
121
+ const data = this.inputOptions.database[key]
122
+ this.addInDatabase(data.id, data)
123
+ }
124
+
125
+ this.loadScenes()
126
+ }
127
+
128
+ /**
129
+ * Adds data to the server's database (in RAM) for later use
130
+ *
131
+ *
132
+ * @method server.addInDatabase(id,data)
133
+ * @title Add in database
134
+ * @param {number} id resource id
135
+ * @param {class | object} dataClass A class representing the data. You can just add a object if you specify the type
136
+ * @enum {string} [type] The type of data
137
+ *
138
+ * item
139
+ * weapon
140
+ * armor
141
+ * skill
142
+ * class
143
+ * state
144
+ * actor
145
+ *
146
+ * @since 3.0.0-beta.4
147
+ * @example
148
+ * ```ts
149
+ * @Item({
150
+ * name: 'Potion',
151
+ * description: 'Gives 100 HP',
152
+ * })
153
+ * class MyItem() {}
154
+ *
155
+ * server.addInDatabase('dynamic_item', MyItem)
156
+ * ```
157
+ *
158
+ * or with an object
159
+ *
160
+ * ```ts
161
+ * server.addInDatabase('dynamic_item', {
162
+ * name: 'Potion',
163
+ * description: 'Gives 100 HP',
164
+ * }, 'item')
165
+ *
166
+ * @returns {void}
167
+ * @memberof RpgServerEngine
168
+ */
169
+ addInDatabase(id: string, dataClass: any, type?: DatabaseTypes) {
170
+ if (Utils.isClass(dataClass)) {
171
+ this.database[id] = dataClass
172
+ return
173
+ }
174
+ if (!type) {
175
+ throw new Error(`You must specify a type for the database ${id}`)
176
+ }
177
+ switch (type) {
178
+ case 'item':
179
+ @Item(dataClass) class ItemClass { }
180
+ this.database[id] = ItemClass
181
+ break;
182
+ case 'weapon':
183
+ @Weapon(dataClass) class WeaponClass { }
184
+ this.database[id] = WeaponClass
185
+ break;
186
+ case 'armor':
187
+ @Armor(dataClass) class ArmorClass { }
188
+ this.database[id] = ArmorClass
189
+ break;
190
+ case 'skill':
191
+ @Skill(dataClass) class SkillClass { }
192
+ this.database[id] = SkillClass
193
+ break;
194
+ case 'class':
195
+ @Class(dataClass) class ClassClass { }
196
+ this.database[id] = ClassClass
197
+ break;
198
+ case 'state':
199
+ @State(dataClass) class StateClass { }
200
+ this.database[id] = StateClass
201
+ break;
202
+ case 'actor':
203
+ @Actor(dataClass) class ActorClass { }
204
+ this.database[id] = ActorClass
205
+ break;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Start the RPG server
211
+ *
212
+ * @method server.start()
213
+ * @title Start Server
214
+ * @returns {void}
215
+ * @memberof RpgServerEngine
216
+ */
217
+ async start(inputOptions?, scheduler = true) {
218
+ if (inputOptions) this.inputOptions = inputOptions
219
+ await this._init()
220
+ this.tick.subscribe(({ timestamp, deltaTime }) => {
221
+ this.step(timestamp, deltaTime)
222
+ })
223
+ if (scheduler) this.scheduler.start({
224
+ fps: inputOptions?.fps || 60
225
+ })
226
+ this.gameEngine.start({
227
+ getObject(id) {
228
+ return Query.getPlayer(id)
229
+ },
230
+ getObjectsOfGroup(groupId: string, player: RpgPlayer) {
231
+ return Query._getObjectsOfMap(groupId, player)
232
+ },
233
+ getShapesOfGroup(map: string) {
234
+ return Query._getShapesOfMap(map)
235
+ }
236
+ })
237
+ this.io.on('connection', this.onPlayerConnected.bind(this))
238
+ await RpgPlugin.emit(HookServer.Start, this)
239
+ }
240
+
241
+ get tick(): Observable<Tick> {
242
+ return this.scheduler.tick as any
243
+ }
244
+
245
+ /**
246
+ * Sends all packages to clients. The sending is done automatically but you can decide to send yourself by calling this method (for example, for unit tests)
247
+ *
248
+ * @method server.send()
249
+ * @title Send All Packets
250
+ * @returns {void}
251
+ * @memberof RpgServerEngine
252
+ */
253
+ send() {
254
+ this.world.send()
255
+ }
256
+
257
+ private async updatePlayersMove(deltaTimeInt: number) {
258
+ const players = this.world.getUsers()
259
+ const obj: any = []
260
+ let p: Promise<RpgPlayer>[] = []
261
+ for (let playerId in players) {
262
+ const playerInstance = players[playerId]['proxy'] as RpgPlayer
263
+ if (!playerInstance) continue
264
+ const player = playerInstance.otherPossessedPlayer ?? playerInstance
265
+ if (player.pendingMove.length > 0) {
266
+ const lastFrame = player.pendingMove[player.pendingMove.length - 1]
267
+ if (this.inputOptions.workers) obj.push(player.toObject())
268
+ else {
269
+ p.push(this.gameEngine.processInput(player.playerId, this.globalConfig.inputs).then((val) => {
270
+ player.pendingMove = []
271
+ player._lastFramePositions = {
272
+ frame: lastFrame.frame,
273
+ position: { ...player.position }
274
+ }
275
+ return player
276
+ }))
277
+ }
278
+ }
279
+ }
280
+ // TODO
281
+ if (this.inputOptions.workers) {
282
+ this.workers.call('movePlayers', obj).then((players) => {
283
+ for (let playerId in players) {
284
+ const player = this.world.getUser(playerId) as RpgPlayer
285
+ const data = players[playerId]
286
+ if (player) {
287
+ player.position = data.position
288
+ player.direction = data.direction
289
+ }
290
+ RpgPlugin.emit('Server.onInput', [player, {
291
+ input: data.direction,
292
+ moving: true
293
+ }], true)
294
+ }
295
+ })
296
+ }
297
+ return Promise.all(p)
298
+ }
299
+
300
+ nextTick(timestamp: number) {
301
+ this.scheduler.nextTick(timestamp)
302
+ }
303
+
304
+ step(t: number, dt: number) {
305
+ this.updatePlayersMove(1)
306
+ if (this.scheduler.frame % 4 === 0) {
307
+ this.send()
308
+ }
309
+ RpgPlugin.emit(HookServer.Step, this)
310
+ }
311
+
312
+ private loadScenes() {
313
+ this.scenes.set(SceneMap.id, new SceneMap(
314
+ {
315
+ maps: this.inputOptions.maps,
316
+ events: this.inputOptions.events,
317
+ worldMaps: this.inputOptions.worldMaps
318
+ },
319
+ this
320
+ ))
321
+ }
322
+
323
+ getScene<T>(name: string): T {
324
+ return this.scenes.get(name)
325
+ }
326
+
327
+ /**
328
+ * Return the scene that manages the maps of the game
329
+ * @prop {SceneMap} [sceneMap]
330
+ * @since 3.0.0-beta.4
331
+ * @memberof RpgServerEngine
332
+ */
333
+ get sceneMap(): SceneMap {
334
+ return this.getScene<SceneMap>(SceneMap.id)
335
+ }
336
+
337
+ sendToPlayer(currentPlayer, eventName, data) {
338
+ currentPlayer._socket.emit(eventName, data)
339
+ }
340
+
341
+ private onPlayerConnected(socket) {
342
+ const { token } = socket.handshake.auth
343
+ const playerId = Utils.generateUID()
344
+ const player: RpgPlayer = new RpgPlayer(this.gameEngine, playerId)
345
+ player.session = token
346
+
347
+ socket.on('move', (data: { input: string[], frame: number }) => {
348
+ const controlPlayer = player.otherPossessedPlayer ?? player
349
+ if (!controlPlayer.canMove) {
350
+ return
351
+ }
352
+ for (let input of data.input) {
353
+ controlPlayer.pendingMove.push({
354
+ input,
355
+ frame: data.frame
356
+ })
357
+ }
358
+ })
359
+
360
+ socket.on('disconnect', () => {
361
+ this.onPlayerDisconnected(socket.id, playerId)
362
+ })
363
+
364
+ this.world.setUser(player, socket)
365
+
366
+ player.server = this
367
+ player._init()
368
+
369
+ if (!token) {
370
+ const newToken = Utils.generateUID() + '-' + Utils.generateUID() + '-' + Utils.generateUID()
371
+ player.session = newToken
372
+ }
373
+
374
+ socket.emit('playerJoined', { playerId, session: player.session })
375
+
376
+ if (!token) {
377
+ player.execMethod('onConnected')
378
+ }
379
+ else {
380
+ RpgPlugin.emit(HookServer.ScalabilityPlayerConnected, player)
381
+ }
382
+ }
383
+
384
+ /**
385
+ *
386
+ * @param {string} socketId - The socketId of the player that disconnected
387
+ * @param {string} playerId - The playerId of the player that disconnected
388
+ */
389
+ private onPlayerDisconnected(socketId, playerId: string) {
390
+ const player: RpgPlayer = World.getUser(playerId) as RpgPlayer
391
+ player.execMethod('onDisconnected')
392
+ this.world.disconnectUser(playerId)
393
+ }
394
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ES2020",
5
+ "outDir": "./lib",
6
+ "rootDir": "./src",
7
+ "strict": true,
8
+ "sourceMap": true,
9
+ "strictNullChecks": true,
10
+ "strictPropertyInitialization": false,
11
+ "moduleResolution": "node",
12
+ "esModuleInterop": true,
13
+ "removeComments": false,
14
+ "noUnusedParameters": false,
15
+ "noUnusedLocals": false,
16
+ "noImplicitThis": false,
17
+ "noImplicitAny": false,
18
+ "noImplicitReturns": false,
19
+ "declaration": true,
20
+ "experimentalDecorators": true,
21
+ "emitDecoratorMetadata": true,
22
+ "stripInternal": true
23
+ },
24
+ "include": [
25
+ "src"
26
+ ]
27
+ }