@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
@@ -0,0 +1,302 @@
1
+
2
+ import { HookServer, RpgCommonMap, RpgPlugin, Utils } from '@rpgjs/common'
3
+ import { World } from 'simple-room'
4
+ import { isTiledFormat, TiledMap } from '@rpgjs/tiled'
5
+ import { MapOptions, MapData } from '../decorators/map'
6
+ import { RpgMap } from '../Game/Map'
7
+ import { RpgWorldMaps, WorldMap } from '../Game/WorldMaps'
8
+ import { RpgEvent, RpgPlayer } from '../Player/Player'
9
+ import { RpgServerEngine } from '../server'
10
+
11
+ export interface RpgClassMap<T> {
12
+ id?: string
13
+ file?: string
14
+ new(server: any): T,
15
+ }
16
+
17
+ type SceneMapObject = {
18
+ maps: any[],
19
+ worldMaps: WorldMap[]
20
+ events: RpgEvent[]
21
+ }
22
+
23
+ export class SceneMap {
24
+ static readonly id: string = 'map'
25
+
26
+ private maps: any[] = []
27
+ private mapsById: {
28
+ [mapId: string]: RpgClassMap<RpgMap>
29
+ } = {}
30
+ private worldMaps: Map<string, RpgWorldMaps> = new Map()
31
+
32
+ constructor(sceneMapObject: SceneMapObject, private server: RpgServerEngine) {
33
+ const { maps, worldMaps, events } = sceneMapObject
34
+ this.maps = maps
35
+ this.mapsById = {}
36
+ RpgCommonMap.buffer.clear()
37
+ if (this.maps) {
38
+ for (let map of this.maps) {
39
+ this.createDynamicMap(map)
40
+ }
41
+ }
42
+ if (worldMaps) {
43
+ for (let worldMap of worldMaps) {
44
+ this.createDynamicWorldMaps(worldMap)
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Returns an array of RpgClassMap objects that represent maps with static properties.
51
+ * @returns {RpgClassMap<RpgMap>[]} Array of RpgClassMap objects.
52
+ * @since 4.0.0
53
+ * @example
54
+ * ```typescript
55
+ * const maps = scene.getMaps();
56
+ * console.log(maps);
57
+ * // Output: [
58
+ * // { file: 'maps/level1.tmx', id: 'level1', type: 'map' },
59
+ * // { file: 'maps/level2.tmx', id: 'level1', type: 'map' },
60
+ * // { file: 'maps/level3.tmx', id: 'level1', type: 'map' }
61
+ * // ]
62
+ * ```
63
+ * @memberof SceneMap
64
+ */
65
+ getMaps(): RpgClassMap<RpgMap>[] {
66
+ return Object.values(this.mapsById)
67
+ }
68
+
69
+ getMapBydId(id: string): RpgClassMap<RpgMap> | null {
70
+ let mapClass = this.mapsById[id]
71
+ if (!mapClass) {
72
+ return null
73
+ }
74
+ if (!Utils.isClass(mapClass)) mapClass = Utils.createConstructor<RpgClassMap<RpgMap>>(mapClass)
75
+ return mapClass
76
+ }
77
+
78
+ async loadMap(id: string): Promise<RpgMap | undefined> {
79
+ const mapClass = this.getMapBydId(id)
80
+
81
+ if (!mapClass) {
82
+ console.log(`Map ${id} not exists`)
83
+ return
84
+ }
85
+
86
+ let mapInstance
87
+
88
+ if (mapClass['buffer'].has(id)) {
89
+ return mapClass['buffer'].get(id)
90
+ }
91
+
92
+ if (RpgCommonMap.buffer.has(id)) {
93
+ mapInstance = RpgCommonMap.buffer.get(id)
94
+ }
95
+ else {
96
+ const room = new mapClass(this.server)
97
+ room.$schema.users = [
98
+ {
99
+ ...RpgPlayer.schemas,
100
+ ...this.server['playerProps']
101
+ }
102
+ ]
103
+ mapInstance = World.addRoom(id, room)
104
+ await mapInstance.load()
105
+ }
106
+
107
+ return mapInstance
108
+ }
109
+
110
+ /**
111
+ * Loads the content of a `.world` file from Tiled Map Editor into the map scene
112
+ *
113
+ * > Note, that if the map already exists (i.e. you have already defined an RpgMap), the world will retrieve the already existing map. Otherwise it will create a new map
114
+ *
115
+ * @title Create worlds dynamically
116
+ * @method sceneMap.createDynamicWorldMaps(world)
117
+ * @param {object} world
118
+ * object is
119
+ * ```ts
120
+ * {
121
+ * id?: string
122
+ * maps: {
123
+ * id?: string
124
+ * properties?: object
125
+ * fileName: string;
126
+ height: number;
127
+ width: number;
128
+ x: number;
129
+ y: number;
130
+ * }[],
131
+ onlyShowAdjacentMaps: boolean, // only for Tiled Map Editor
132
+ type: 'world' // only for Tiled Map Editor
133
+ * }
134
+ * ```
135
+ *
136
+ * @since 3.0.0-beta.8
137
+ * @memberof SceneMap
138
+ */
139
+ createDynamicWorldMaps(world: WorldMap): RpgWorldMaps {
140
+ world.id = world.id || Utils.generateUID()
141
+ const worldMap = new RpgWorldMaps(world.id).load(world, this)
142
+ this.worldMaps.set(world.id, worldMap)
143
+ return worldMap
144
+ }
145
+
146
+ /**
147
+ * Recover a world
148
+ *
149
+ * @title Recover a world
150
+ * @method sceneMap.getWorldMaps(id)
151
+ * @param {string} id world id
152
+ * @return { RpgWorldMaps | undefined }
153
+ * @since 3.0.0-beta.8
154
+ * @memberof SceneMap
155
+ */
156
+ getWorldMaps(id: string): RpgWorldMaps | undefined {
157
+ return this.worldMaps.get(id)
158
+ }
159
+
160
+ /**
161
+ * Delete a world
162
+ *
163
+ * @title Delete a world
164
+ * @method sceneMap.deleteWorldMaps(id)
165
+ * @param {string} id world id
166
+ * @since 3.0.0-beta.8
167
+ * @memberof SceneMap
168
+ */
169
+ deleteWorldMaps(id: string): void {
170
+ this.worldMaps.delete(id)
171
+ }
172
+
173
+ /**
174
+ * Create a dynamic map
175
+ *
176
+ * Since version 3.0.0-beta.8, you can just pass the path to the file. The identifier will then be the name of the file
177
+ *
178
+ * @method sceneMap.createDynamicMap(mapData)
179
+ * @title Create a dynamic map
180
+ * @param {object | RpgMap | string} mapData The same property as [@MapData decorator](https://docs.rpgjs.dev/classes/map.html#mapdata-decorator)
181
+ * @returns {RpgMap}
182
+ * @since 3.0.0-beta.4
183
+ * @memberof SceneMap
184
+ * @example
185
+ * ```ts
186
+ * sceneMap.createDynamicMap({
187
+ * id: 'myid',
188
+ * file: require('./tmx/mymap.tmx')
189
+ * })
190
+ * ```
191
+ *
192
+ * And later, on the player:
193
+ *
194
+ * ```ts
195
+ * player.changeMap('myid')
196
+ * ```
197
+ *
198
+ * ---
199
+ *
200
+ * since beta.8
201
+ *
202
+ * ```ts
203
+ * sceneMap.createDynamicMap(require('./tmx/mymap.tmx')) // id is "mymap"
204
+ * ```
205
+ */
206
+ createDynamicMap(mapData: MapOptions | string | RpgClassMap<RpgMap> | TiledMap): RpgClassMap<RpgMap> | never {
207
+ if (Utils.isString(mapData)) {
208
+ const id = Utils.extractId(mapData as string)
209
+ if (!id) {
210
+ throw new Error('Unable to extract the file identifier. Check that the file has only the following characters: [a-zA-Z0-9-_$!]+')
211
+ }
212
+ mapData = {
213
+ id: id[1],
214
+ file: mapData
215
+ } as MapOptions
216
+ }
217
+ if (isTiledFormat(mapData)) {
218
+ const tiledData = (mapData as TiledMap)
219
+ mapData = {
220
+ file: { ...tiledData }
221
+ } as MapOptions
222
+ }
223
+ if (!(mapData as MapOptions).id) (mapData as MapOptions).id = Utils.generateUID()
224
+ if (!Utils.isClass(mapData)) {
225
+ @MapData(mapData as MapOptions)
226
+ class DynamicMap extends RpgMap { }
227
+ mapData = DynamicMap
228
+ }
229
+ const map: RpgClassMap<RpgMap> = mapData as any
230
+ this.mapsById[map.id as string] = map
231
+ return map
232
+ }
233
+
234
+ async changeMap(
235
+ mapId: string,
236
+ player: RpgPlayer,
237
+ positions?: { x: number, y: number, z?: number } | string
238
+ ): Promise<RpgMap | null | boolean> {
239
+
240
+ const boolArray: boolean[] = await RpgPlugin.emit(HookServer.PlayerCanChangeMap, [player, this.getMapBydId(mapId)], true)
241
+
242
+ if (boolArray.some(el => el === false)) {
243
+ return null
244
+ }
245
+
246
+ // if just teleport, not change map
247
+ if (player.map === mapId) {
248
+ await player.teleport(positions || 'start')
249
+ return null
250
+ }
251
+
252
+ player.emit('preLoadScene', mapId)
253
+
254
+ player.prevMap = player.map
255
+
256
+ if (player.prevMap) {
257
+ await player.execMethod('onLeaveMap', <any>[player.getCurrentMap()])
258
+ World.leaveRoom(player.prevMap, player.id)
259
+ }
260
+
261
+ player.map = mapId
262
+ player.events = {}
263
+ player.tmpPositions = positions as any
264
+
265
+ const scalabilityArray: boolean[] = await RpgPlugin.emit(HookServer.ScalabilityChangeServer, player)
266
+
267
+ if (scalabilityArray.some(el => el === true)) {
268
+ return true
269
+ }
270
+
271
+ player.tmpPositions = null
272
+
273
+ const mapInstance = await this.loadMap(mapId)
274
+
275
+ if (!mapInstance) return null
276
+
277
+ if (!player.height) player.height = mapInstance.tileHeight
278
+ if (!player.width) player.width = mapInstance.tileWidth
279
+ if (!player.hitbox.h) player.hitbox.h = mapInstance.tileHeight
280
+ if (!player.hitbox.w) player.hitbox.w = mapInstance.tileWidth
281
+
282
+ player.emitSceneMap()
283
+
284
+ // if room is removed after load map (for unit tests)
285
+ if (!World.getRoom(mapId)) {
286
+ return null
287
+ }
288
+
289
+ player.teleport(positions || 'start')
290
+
291
+ World.joinRoom(mapId, player.id)
292
+
293
+ player = World.getUser(player.id) as RpgPlayer
294
+
295
+ if (player) {
296
+ player.createDynamicEvent(<any>mapInstance._events, false)
297
+ await player.execMethod('onJoinMap', <any>[mapInstance])
298
+ }
299
+
300
+ return mapInstance
301
+ }
302
+ }
@@ -0,0 +1,57 @@
1
+ import { EventMode } from '../Player/Player'
2
+
3
+ export interface EventOptions {
4
+ /**
5
+ * The mode of the event, shared evening or scenario
6
+ *
7
+ * The scenario mode allows you to have events specific to the player. Thus, the graphics, the positions of the event will be different for each player. Beware of performance! The event is duplicated by each player.
8
+ *
9
+ * `shared` mode by default
10
+ *
11
+ * ```ts
12
+ * import { RpgEvent, EventData, RpgPlayer, EventMode } from '@rpgjs/server'
13
+ * @EventData({
14
+ * name: 'EV-1',
15
+ * mode: EventMode.Scenario // or EventMode.Shared
16
+ * })
17
+ * export class CharaEvent extends RpgEvent { }
18
+ * ```
19
+ *
20
+ * @prop {string} [mode] Either "shared" or "scenario".
21
+ * @memberof EventData
22
+ * */
23
+ mode?: EventMode,
24
+
25
+ width?: number,
26
+ height?: number,
27
+
28
+ /**
29
+ * The hitbox of the event. By default, this is the size of the tile of the map
30
+ *
31
+ * @prop { { width: number, height: number }} [hitbox]
32
+ * @memberof EventData
33
+ * */
34
+ hitbox?: {
35
+ width?: number,
36
+ height?: number
37
+ },
38
+
39
+ /**
40
+ * Name of the event. This is its identifier. it allows you to retrieve an event and place it on the map
41
+ *
42
+ * @prop {string} name
43
+ * @memberof EventData
44
+ * */
45
+ name: string
46
+ }
47
+
48
+ export function EventData(options: EventOptions) {
49
+ return (target) => {
50
+ target.mode = options.mode || EventMode.Shared
51
+ target.width = options.width
52
+ target.height = options.height
53
+ target.hitbox = options.hitbox
54
+ target._name = options.name
55
+ target.prototype._name = options.name
56
+ }
57
+ }
@@ -0,0 +1,223 @@
1
+ import { TiledMap } from '@rpgjs/tiled'
2
+ import { componentSchema, RpgPlayer } from '../Player/Player'
3
+
4
+ export interface MapOptions {
5
+ /**
6
+ * Map identifier. Allows to go to the map (for example with player.changeMap())
7
+ *
8
+ * @prop {string} [id]
9
+ * @memberof MapData
10
+ * */
11
+ id?: string,
12
+
13
+ /**
14
+ * the path to the .tmx file (Tiled Map Editor)
15
+ *
16
+ * Remember to use `require()` function
17
+ *
18
+ * ```ts
19
+ * import { MapData, RpgMap } from '@rpgjs/server'
20
+ *
21
+ * @MapData({
22
+ * id: 'town',
23
+ * file: require('./tmx/town.tmx')
24
+ * })
25
+ * class TownMap extends RpgMap { }
26
+ * ```
27
+ * @prop {string} file
28
+ * @memberof MapData
29
+ * */
30
+ file: string | TiledMap,
31
+
32
+ /**
33
+ * The name of the map.
34
+ * @prop {string} [name]
35
+ * @memberof MapData
36
+ * */
37
+ name?: string,
38
+
39
+ /**
40
+ * Map events. This is an array containing `RpgEvent` classes.
41
+ * You can also give an object that will indicate the positions of the event on the map.
42
+ *
43
+ * ```ts
44
+ * import { MapData, RpgMap, EventData, RpgEvent } from '@rpgjs/server'
45
+ *
46
+ * @EventData({
47
+ * name: 'Ev-1'
48
+ * })
49
+ * class NpcEvent extends RpgEvent { }
50
+ *
51
+ * @MapData({
52
+ * id: 'medieval',
53
+ * file: require('./tmx/town.tmx'),
54
+ * events: [NpcEvent]
55
+ * })
56
+ * class TownMap extends RpgMap {}
57
+ * ```
58
+ *
59
+ * If the positions are not defined, the event will be placed on a Tiled Map Editor shape ([/guide/create-event.html#position-the-event-on-the-map](Guide)). Otherwise, it will be placed at `{x:0, y:0 }`
60
+ *
61
+ * You can give positions:
62
+ *
63
+ * ```ts
64
+ * events: [{ event: NpcEvent, x: 10, y: 30 }]
65
+ * ```
66
+ *
67
+ * @prop {Class of RpgEvent[] | { event: Class RpgEvent, x: number, y: number }} [events]
68
+ * @memberof MapData
69
+ * */
70
+ events?: { event: any, x: number, y: number }[] | any[],
71
+
72
+ /**
73
+ * The sounds that will be played when the map is open. Sounds must be defined on the client side. Then, put the name of the sound identifier
74
+ *
75
+ * So, it is possible to play several sounds (in loop or not) on the card. You can put a background music (BGM) and a background noise (BGS) for example
76
+ *
77
+ * ```ts
78
+ * sounds: ['my-bgm', 'my-bgs']
79
+ * ```
80
+ *
81
+ * And client side:
82
+ *
83
+ * ```ts
84
+ * import { Sound } from '@rpgjs/client'
85
+ *
86
+ * @Sound({
87
+ * sounds: {
88
+ * 'my-bgm': require('./assets/bgm.ogg'),
89
+ * 'my-bgs': require('./assets/bgs.ogg')
90
+ * },
91
+ * loop: true
92
+ * })
93
+ * export class Sounds {}
94
+ * ```
95
+ *
96
+ * See [https://docs.rpgjs.dev/classes/sound.html#properties](RpgSound Decorator)
97
+ *
98
+ * @prop {Array<string>} [sounds]
99
+ * @memberof MapData
100
+ * */
101
+ sounds?: string[]
102
+
103
+ /**
104
+ * Specify which properties will be synchronized with the client. On the client side, you can retrieve the values synchronized with the valueChanges property on the scene
105
+ *
106
+ * You must create the schema:
107
+ *
108
+ * ```ts
109
+ * import { MapData, RpgMap } from '@rpgjs/server'
110
+ *
111
+ * @MapData({
112
+ * id: 'medieval',
113
+ * file: require('./tmx/town.tmx'),
114
+ * syncSchema: {
115
+ * count: Number
116
+ * }
117
+ * })
118
+ * export class TownMap extends RpgMap {
119
+ * count: number = 0
120
+ *
121
+ * onEnter() {
122
+ * this.count++
123
+ * }
124
+ *
125
+ * onLeave() {
126
+ * this.count--
127
+ * }
128
+ * }
129
+ *
130
+ * ```
131
+ *
132
+ * If you want to change the scheme of players and events, consider overwriting the existing scheme
133
+ *
134
+ * ```ts
135
+ * import { MapData, RpgMap, RpgPlayer } from '@rpgjs/server'
136
+ *
137
+ *
138
+ * declare module '@rpgjs/server' {
139
+ * export interface RpgPlayer {
140
+ * customProp: string
141
+ * }
142
+ * }
143
+ *
144
+ * @MapData({
145
+ * id: 'medieval',
146
+ * file: require('./tmx/town.tmx'),
147
+ * syncSchema: {
148
+ * users: [
149
+ * {
150
+ * customProp: String,
151
+ * ...RpgPlayer.schemas
152
+ * }
153
+ * ]
154
+ * }
155
+ * })
156
+ * export class TownMap extends RpgMap {}
157
+ * ```
158
+ *
159
+ * The properties are called `users` and `events`. Their scheme is identical and defined in `RpgPlayer.schemas`. To write schematics, refer to the [documentation of the simple-room](https://github.com/RSamaium/simple-room) module
160
+ *
161
+ * @prop {object} [syncSchema]
162
+ * @memberof MapData
163
+ * */
164
+ syncSchema?: any
165
+
166
+ /**
167
+ * Decreases the RAM of the map. In this case, some instructions will be different.
168
+ *
169
+ * `map.getTileByIndex()` will not return all tiles of an index but only the tile of the highest layer
170
+ *
171
+ * > You can also use the `low-memory` property in Tiled maps
172
+ *
173
+ * @prop {boolean} [lowMemory=false]
174
+ * @since 3.1.0
175
+ * @memberof MapData
176
+ * */
177
+ lowMemory?: boolean
178
+ }
179
+
180
+ export function MapData(options: MapOptions) {
181
+ return (target) => {
182
+ target.file = options.file
183
+ target.id = options.id
184
+ target.type = 'map'
185
+ target.prototype.name = options.name
186
+ target.prototype.file = options.file
187
+ target.prototype.id = options.id
188
+ target.prototype.sounds = options.sounds
189
+ target.prototype.lowMemory = options.lowMemory
190
+
191
+ target.prototype.$schema = {}
192
+
193
+ if (options.syncSchema) {
194
+ target.prototype.$schema = options.syncSchema
195
+ }
196
+ if (!target.prototype.$schema.shapes) {
197
+ target.prototype.$schema.shapes = [
198
+ {
199
+ type: String,
200
+ name: String,
201
+ x: Number,
202
+ y: Number,
203
+ width: Number,
204
+ height: Number,
205
+ properties: {
206
+ collision: Boolean
207
+ },
208
+ polygon: [{ x: Number, y: Number }],
209
+ rotation: Number,
210
+ components: [componentSchema]
211
+ }
212
+ ]
213
+ }
214
+ if (!target.prototype.$schema.users) {
215
+ target.prototype.$schema.users = [RpgPlayer.schemas]
216
+ }
217
+ if (!target.prototype.$schema.events) {
218
+ target.prototype.$schema.events = [RpgPlayer.schemas]
219
+ }
220
+
221
+ target.prototype._events = options.events
222
+ }
223
+ }
@@ -0,0 +1,102 @@
1
+ import { RpgCommonGame, HookServer, loadModules, ModuleType, GameSide, RpgPlugin } from '@rpgjs/common'
2
+ import { RpgServerEngine } from './server'
3
+ import { RpgPlayer } from './Player/Player'
4
+ import { RpgMatchMaker } from './MatchMaker'
5
+
6
+ interface RpgServerEntryPointOptions {
7
+ /**
8
+ * Represents socket io but you can put something else (which is of the same scheme as socket io)
9
+ *
10
+ * @prop {SocketIO or other} io
11
+ * @memberof RpgServerEntryPoint
12
+ * */
13
+ io: any,
14
+ /**
15
+ * It allows you to know where the maps are located. Usually put `__dirname` for the current directory.
16
+ *
17
+ * ```ts
18
+ * basePath: __dirname
19
+ * ```
20
+ *
21
+ * @prop {string} basePath
22
+ * @memberof RpgServerEntryPoint
23
+ * */
24
+ basePath: string
25
+
26
+ standalone?: boolean
27
+
28
+ /**
29
+ * The general configurations of the game.
30
+ *
31
+ * @prop {object} [globalConfig]
32
+ * @memberof RpgServerEntryPoint
33
+ * */
34
+ globalConfig?: any
35
+
36
+ workers?: any
37
+ }
38
+
39
+ export default async function (modules: ModuleType[], options: RpgServerEntryPointOptions): Promise<RpgServerEngine> {
40
+ const gameEngine = new RpgCommonGame(GameSide.Server)
41
+
42
+ if (!options.globalConfig) options.globalConfig = {}
43
+
44
+ const relations = {
45
+ onConnected: HookServer.PlayerConnected,
46
+ onInput: HookServer.PlayerInput,
47
+ onJoinMap: HookServer.PlayerJoinMap,
48
+ onLeaveMap: HookServer.PlayerLeaveMap,
49
+ onLevelUp: HookServer.PlayerLevelUp,
50
+ onDead: HookServer.PlayerDead,
51
+ onDisconnected: HookServer.PlayerDisconnected,
52
+ onInShape: HookServer.PlayerInShape,
53
+ onOutShape: HookServer.PlayerOutShape,
54
+ onMove: HookServer.PlayerMove,
55
+ canChangeMap: HookServer.PlayerCanChangeMap
56
+ }
57
+
58
+ const relationsEngine = {
59
+ onStart: HookServer.Start,
60
+ onStep: HookServer.Step
61
+ }
62
+
63
+ const { playerProps } = await loadModules(modules, {
64
+ side: 'server',
65
+ relations: {
66
+ player: relations,
67
+ engine: relationsEngine,
68
+ scalability: {
69
+ onConnected: HookServer.ScalabilityPlayerConnected,
70
+ doChangeServer: HookServer.ScalabilityChangeServer
71
+ }
72
+ }
73
+ }, (mod) => {
74
+ const { scalability } = mod
75
+ if (scalability) {
76
+ const { hooks, stateStore, matchMaker } = scalability
77
+ const matchMakerInstance = new RpgMatchMaker(matchMaker)
78
+ RpgPlugin.on(HookServer.Start, () => {
79
+ return stateStore.connect()
80
+ })
81
+ mod.scalability._hooks = {}
82
+ for (let hookName in hooks) {
83
+ let originalHook = mod.scalability.hooks[hookName]
84
+ mod.scalability._hooks[hookName] = function (player: RpgPlayer) {
85
+ return originalHook(stateStore, matchMakerInstance, player)
86
+ }
87
+ }
88
+ }
89
+ return mod
90
+ })
91
+
92
+ const serverEngine = new RpgServerEngine(options.io, gameEngine, {
93
+ debug: {},
94
+ updateRate: 10,
95
+ stepRate: 60,
96
+ timeoutInterval: 0,
97
+ countConnections: false,
98
+ playerProps,
99
+ ...options
100
+ })
101
+ return serverEngine
102
+ }