@rpgjs/server 5.0.0-alpha.4 → 5.0.0-alpha.41
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/dist/Gui/DialogGui.d.ts +5 -0
- package/dist/Gui/GameoverGui.d.ts +23 -0
- package/dist/Gui/Gui.d.ts +6 -0
- package/dist/Gui/MenuGui.d.ts +22 -3
- package/dist/Gui/NotificationGui.d.ts +1 -2
- package/dist/Gui/SaveLoadGui.d.ts +13 -0
- package/dist/Gui/ShopGui.d.ts +28 -3
- package/dist/Gui/TitleGui.d.ts +23 -0
- package/dist/Gui/index.d.ts +10 -1
- package/dist/Player/BattleManager.d.ts +34 -12
- package/dist/Player/ClassManager.d.ts +46 -13
- package/dist/Player/ComponentManager.d.ts +123 -0
- package/dist/Player/Components.d.ts +345 -0
- package/dist/Player/EffectManager.d.ts +86 -0
- package/dist/Player/ElementManager.d.ts +104 -0
- package/dist/Player/GoldManager.d.ts +22 -0
- package/dist/Player/GuiManager.d.ts +259 -0
- package/dist/Player/ItemFixture.d.ts +6 -0
- package/dist/Player/ItemManager.d.ts +450 -9
- package/dist/Player/MoveManager.d.ts +324 -69
- package/dist/Player/ParameterManager.d.ts +344 -14
- package/dist/Player/Player.d.ts +460 -8
- package/dist/Player/SkillManager.d.ts +197 -15
- package/dist/Player/StateManager.d.ts +89 -25
- package/dist/Player/VariableManager.d.ts +74 -0
- package/dist/RpgServer.d.ts +502 -64
- package/dist/RpgServerEngine.d.ts +2 -1
- package/dist/decorators/event.d.ts +46 -0
- package/dist/decorators/map.d.ts +287 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +21653 -20900
- package/dist/index.js.map +1 -1
- package/dist/logs/log.d.ts +2 -3
- package/dist/module.d.ts +43 -1
- package/dist/presets/index.d.ts +0 -9
- package/dist/rooms/BaseRoom.d.ts +132 -0
- package/dist/rooms/lobby.d.ts +10 -2
- package/dist/rooms/map.d.ts +1236 -17
- package/dist/services/save.d.ts +43 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/localStorage.d.ts +23 -0
- package/package.json +14 -10
- package/src/Gui/DialogGui.ts +19 -4
- package/src/Gui/GameoverGui.ts +39 -0
- package/src/Gui/Gui.ts +23 -1
- package/src/Gui/MenuGui.ts +155 -6
- package/src/Gui/NotificationGui.ts +1 -2
- package/src/Gui/SaveLoadGui.ts +60 -0
- package/src/Gui/ShopGui.ts +146 -16
- package/src/Gui/TitleGui.ts +39 -0
- package/src/Gui/index.ts +15 -2
- package/src/Player/BattleManager.ts +91 -49
- package/src/Player/ClassManager.ts +118 -50
- package/src/Player/ComponentManager.ts +425 -19
- package/src/Player/Components.ts +380 -0
- package/src/Player/EffectManager.ts +81 -44
- package/src/Player/ElementManager.ts +109 -86
- package/src/Player/GoldManager.ts +32 -35
- package/src/Player/GuiManager.ts +308 -150
- package/src/Player/ItemFixture.ts +4 -5
- package/src/Player/ItemManager.ts +774 -355
- package/src/Player/MoveManager.ts +1544 -774
- package/src/Player/ParameterManager.ts +546 -104
- package/src/Player/Player.ts +1163 -88
- package/src/Player/SkillManager.ts +520 -195
- package/src/Player/StateManager.ts +170 -182
- package/src/Player/VariableManager.ts +101 -63
- package/src/RpgServer.ts +525 -63
- package/src/core/context.ts +1 -0
- package/src/decorators/event.ts +61 -0
- package/src/decorators/map.ts +327 -0
- package/src/index.ts +11 -1
- package/src/logs/log.ts +10 -3
- package/src/module.ts +126 -3
- package/src/presets/index.ts +1 -10
- package/src/rooms/BaseRoom.ts +232 -0
- package/src/rooms/lobby.ts +25 -7
- package/src/rooms/map.ts +2502 -194
- package/src/services/save.ts +147 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/localStorage.ts +76 -0
- package/tests/battle.spec.ts +375 -0
- package/tests/change-map.spec.ts +72 -0
- package/tests/class.spec.ts +274 -0
- package/tests/effect.spec.ts +219 -0
- package/tests/element.spec.ts +221 -0
- package/tests/event.spec.ts +80 -0
- package/tests/gold.spec.ts +99 -0
- package/tests/item.spec.ts +609 -0
- package/tests/module.spec.ts +38 -0
- package/tests/move.spec.ts +601 -0
- package/tests/player-param.spec.ts +28 -0
- package/tests/prediction-reconciliation.spec.ts +182 -0
- package/tests/random-move.spec.ts +65 -0
- package/tests/skill.spec.ts +658 -0
- package/tests/state.spec.ts +467 -0
- package/tests/variable.spec.ts +185 -0
- package/tests/world-maps.spec.ts +896 -0
- package/vite.config.ts +16 -0
- package/dist/Player/Event.d.ts +0 -0
- package/src/Player/Event.ts +0 -0
package/src/core/context.ts
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export enum EventMode {
|
|
2
|
+
Shared = 'shared',
|
|
3
|
+
Scenario = 'scenario'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface EventOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The mode of the event, shared evening or scenario
|
|
9
|
+
*
|
|
10
|
+
* 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.
|
|
11
|
+
*
|
|
12
|
+
* `shared` mode by default
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { RpgEvent, EventData, RpgPlayer, EventMode } from '@rpgjs/server'
|
|
16
|
+
* @EventData({
|
|
17
|
+
* name: 'EV-1',
|
|
18
|
+
* mode: EventMode.Scenario // or EventMode.Shared
|
|
19
|
+
* })
|
|
20
|
+
* export class CharaEvent extends RpgEvent { }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @prop {string} [mode] Either "shared" or "scenario".
|
|
24
|
+
* @memberof EventData
|
|
25
|
+
* */
|
|
26
|
+
mode?: EventMode,
|
|
27
|
+
|
|
28
|
+
width?: number,
|
|
29
|
+
height?: number,
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The hitbox of the event. By default, this is the size of the tile of the map
|
|
33
|
+
*
|
|
34
|
+
* @prop { { width: number, height: number }} [hitbox]
|
|
35
|
+
* @memberof EventData
|
|
36
|
+
* */
|
|
37
|
+
hitbox?: {
|
|
38
|
+
width?: number,
|
|
39
|
+
height?: number
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Name of the event. This is its identifier. it allows you to retrieve an event and place it on the map
|
|
44
|
+
*
|
|
45
|
+
* @prop {string} name
|
|
46
|
+
* @memberof EventData
|
|
47
|
+
* */
|
|
48
|
+
name: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function EventData(options: EventOptions) {
|
|
52
|
+
return (target) => {
|
|
53
|
+
target.mode = options.mode || EventMode.Shared
|
|
54
|
+
target.width = options.width
|
|
55
|
+
target.height = options.height
|
|
56
|
+
target.hitbox = options.hitbox
|
|
57
|
+
target._name = options.name
|
|
58
|
+
target.prototype._name = options.name
|
|
59
|
+
target.prototype.mode = target.mode
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import type { WeatherState } from "@rpgjs/common";
|
|
2
|
+
|
|
3
|
+
export interface MapOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Map identifier. Allows to go to the map (for example with player.changeMap())
|
|
6
|
+
*
|
|
7
|
+
* @prop {string} [id]
|
|
8
|
+
* @memberof MapData
|
|
9
|
+
* */
|
|
10
|
+
id?: string,
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* the path to the .tmx file (Tiled Map Editor)
|
|
14
|
+
*
|
|
15
|
+
* Remember to use `require()` function
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { MapData, RpgMap } from '@rpgjs/server'
|
|
19
|
+
*
|
|
20
|
+
* @MapData({
|
|
21
|
+
* id: 'town',
|
|
22
|
+
* file: require('./tmx/town.tmx')
|
|
23
|
+
* })
|
|
24
|
+
* class TownMap extends RpgMap { }
|
|
25
|
+
* ```
|
|
26
|
+
* @prop {string} file
|
|
27
|
+
* @memberof MapData
|
|
28
|
+
* */
|
|
29
|
+
file?: any,
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The name of the map.
|
|
33
|
+
* @prop {string} [name]
|
|
34
|
+
* @memberof MapData
|
|
35
|
+
* */
|
|
36
|
+
name?: string,
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Map events. This is an array containing `RpgEvent` classes.
|
|
40
|
+
* You can also give an object that will indicate the positions of the event on the map.
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { MapData, RpgMap, EventData, RpgEvent } from '@rpgjs/server'
|
|
44
|
+
*
|
|
45
|
+
* @EventData({
|
|
46
|
+
* name: 'Ev-1'
|
|
47
|
+
* })
|
|
48
|
+
* class NpcEvent extends RpgEvent { }
|
|
49
|
+
*
|
|
50
|
+
* @MapData({
|
|
51
|
+
* id: 'medieval',
|
|
52
|
+
* file: require('./tmx/town.tmx'),
|
|
53
|
+
* events: [NpcEvent]
|
|
54
|
+
* })
|
|
55
|
+
* class TownMap extends RpgMap {}
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* 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 }`
|
|
59
|
+
*
|
|
60
|
+
* You can give positions:
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
63
|
+
* events: [{ event: NpcEvent, x: 10, y: 30 }]
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @prop {Class of RpgEvent[] | { event: Class RpgEvent, x: number, y: number }} [events]
|
|
67
|
+
* @memberof MapData
|
|
68
|
+
* */
|
|
69
|
+
events?: { event: any, x: number, y: number }[] | any[],
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 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
|
|
73
|
+
*
|
|
74
|
+
* 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
|
|
75
|
+
*
|
|
76
|
+
* ```ts
|
|
77
|
+
* sounds: ['my-bgm', 'my-bgs']
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* And client side:
|
|
81
|
+
*
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { Sound } from '@rpgjs/client'
|
|
84
|
+
*
|
|
85
|
+
* @Sound({
|
|
86
|
+
* sounds: {
|
|
87
|
+
* 'my-bgm': require('./assets/bgm.ogg'),
|
|
88
|
+
* 'my-bgs': require('./assets/bgs.ogg')
|
|
89
|
+
* },
|
|
90
|
+
* loop: true
|
|
91
|
+
* })
|
|
92
|
+
* export class Sounds {}
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* See [https://docs.rpgjs.dev/classes/sound.html#properties](RpgSound Decorator)
|
|
96
|
+
*
|
|
97
|
+
* @prop {Array<string>} [sounds]
|
|
98
|
+
* @memberof MapData
|
|
99
|
+
* */
|
|
100
|
+
sounds?: string[]
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Initial weather state for this map.
|
|
104
|
+
*
|
|
105
|
+
* This value is applied when the map is loaded and can later be updated
|
|
106
|
+
* at runtime with `map.setWeather()` from server logic.
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* @MapData({
|
|
110
|
+
* id: 'forest',
|
|
111
|
+
* file: require('./tmx/forest.tmx'),
|
|
112
|
+
* weather: {
|
|
113
|
+
* effect: 'fog',
|
|
114
|
+
* preset: 'rpgForestFog',
|
|
115
|
+
* params: { density: 1.2, height: 0.75 },
|
|
116
|
+
* transitionMs: 1200
|
|
117
|
+
* }
|
|
118
|
+
* })
|
|
119
|
+
* class ForestMap extends RpgMap {}
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
weather?: WeatherState | null
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Whether to stop all sounds before playing the map sounds when a player joins.
|
|
126
|
+
*
|
|
127
|
+
* If set to `true`, all currently playing sounds will be stopped before playing the new map sounds.
|
|
128
|
+
* This prevents sound overlap when changing maps.
|
|
129
|
+
*
|
|
130
|
+
* By default, this is `false`, meaning sounds from the previous map will continue playing.
|
|
131
|
+
*
|
|
132
|
+
* ```ts
|
|
133
|
+
* @MapData({
|
|
134
|
+
* id: 'battle-map',
|
|
135
|
+
* sounds: ['battle-theme'],
|
|
136
|
+
* stopAllSoundsBeforeJoin: true // Stop all sounds before playing battle theme
|
|
137
|
+
* })
|
|
138
|
+
* class BattleMap extends RpgMap {}
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* @prop {boolean} [stopAllSoundsBeforeJoin=false]
|
|
142
|
+
* @memberof MapData
|
|
143
|
+
* @since 5.0.0
|
|
144
|
+
* */
|
|
145
|
+
stopAllSoundsBeforeJoin?: boolean
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 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
|
|
149
|
+
*
|
|
150
|
+
* You must create the schema:
|
|
151
|
+
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* import { MapData, RpgMap } from '@rpgjs/server'
|
|
154
|
+
*
|
|
155
|
+
* @MapData({
|
|
156
|
+
* id: 'medieval',
|
|
157
|
+
* file: require('./tmx/town.tmx'),
|
|
158
|
+
* syncSchema: {
|
|
159
|
+
* count: Number
|
|
160
|
+
* }
|
|
161
|
+
* })
|
|
162
|
+
* export class TownMap extends RpgMap {
|
|
163
|
+
* count: number = 0
|
|
164
|
+
*
|
|
165
|
+
* onLoad() {}
|
|
166
|
+
*
|
|
167
|
+
* onJoin() {
|
|
168
|
+
* this.count++
|
|
169
|
+
* }
|
|
170
|
+
*
|
|
171
|
+
* onLeave(player) {
|
|
172
|
+
* super.onLeave(player)
|
|
173
|
+
* this.count--
|
|
174
|
+
* }
|
|
175
|
+
* }
|
|
176
|
+
*
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* If you want to change the scheme of players and events, consider overwriting the existing scheme
|
|
180
|
+
*
|
|
181
|
+
* ```ts
|
|
182
|
+
* import { MapData, RpgMap, RpgPlayer } from '@rpgjs/server'
|
|
183
|
+
*
|
|
184
|
+
*
|
|
185
|
+
* declare module '@rpgjs/server' {
|
|
186
|
+
* export interface RpgPlayer {
|
|
187
|
+
* customProp: string
|
|
188
|
+
* }
|
|
189
|
+
* }
|
|
190
|
+
*
|
|
191
|
+
* @MapData({
|
|
192
|
+
* id: 'medieval',
|
|
193
|
+
* file: require('./tmx/town.tmx'),
|
|
194
|
+
* syncSchema: {
|
|
195
|
+
* users: [
|
|
196
|
+
* {
|
|
197
|
+
* customProp: String,
|
|
198
|
+
* ...RpgPlayer.schemas
|
|
199
|
+
* }
|
|
200
|
+
* ]
|
|
201
|
+
* }
|
|
202
|
+
* })
|
|
203
|
+
* export class TownMap extends RpgMap {}
|
|
204
|
+
* ```
|
|
205
|
+
*
|
|
206
|
+
* 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
|
|
207
|
+
*
|
|
208
|
+
* @prop {object} [syncSchema]
|
|
209
|
+
* @memberof MapData
|
|
210
|
+
* */
|
|
211
|
+
syncSchema?: any
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Decreases the RAM of the map. In this case, some instructions will be different.
|
|
215
|
+
*
|
|
216
|
+
* `map.getTileByIndex()` will not return all tiles of an index but only the tile of the highest layer
|
|
217
|
+
*
|
|
218
|
+
* > You can also use the `low-memory` property in Tiled maps
|
|
219
|
+
*
|
|
220
|
+
* @prop {boolean} [lowMemory=false]
|
|
221
|
+
* @since 3.1.0
|
|
222
|
+
* @memberof MapData
|
|
223
|
+
* */
|
|
224
|
+
lowMemory?: boolean
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Called when the map is loaded and initialized
|
|
228
|
+
*
|
|
229
|
+
* This hook is executed once when the map data is loaded and ready.
|
|
230
|
+
* Use this to initialize map-specific properties or setup.
|
|
231
|
+
*
|
|
232
|
+
* @prop { () => any } [onLoad]
|
|
233
|
+
* @memberof MapData
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* @MapData({
|
|
237
|
+
* id: 'town',
|
|
238
|
+
* file: require('./tmx/town.tmx'),
|
|
239
|
+
* onLoad() {
|
|
240
|
+
* console.log('Town map loaded')
|
|
241
|
+
* // Initialize map properties
|
|
242
|
+
* }
|
|
243
|
+
* })
|
|
244
|
+
* class TownMap extends RpgMap {}
|
|
245
|
+
* ```
|
|
246
|
+
* */
|
|
247
|
+
onLoad?: () => any
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Called when a player joins the map
|
|
251
|
+
*
|
|
252
|
+
* This hook is executed each time a player joins the map.
|
|
253
|
+
* Use this to perform actions when a player enters the map.
|
|
254
|
+
*
|
|
255
|
+
* @prop { (player: RpgPlayer) => any } [onJoin]
|
|
256
|
+
* @memberof MapData
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* @MapData({
|
|
260
|
+
* id: 'town',
|
|
261
|
+
* file: require('./tmx/town.tmx'),
|
|
262
|
+
* onJoin(player: RpgPlayer) {
|
|
263
|
+
* console.log(`${player.name} joined the town`)
|
|
264
|
+
* // Perform actions when player joins
|
|
265
|
+
* }
|
|
266
|
+
* })
|
|
267
|
+
* class TownMap extends RpgMap {}
|
|
268
|
+
* ```
|
|
269
|
+
* */
|
|
270
|
+
onJoin?: (player: RpgPlayer) => any
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Called when a player leaves the map
|
|
274
|
+
*
|
|
275
|
+
* This hook is executed each time a player leaves the map.
|
|
276
|
+
* Use this to perform cleanup or actions when a player exits the map.
|
|
277
|
+
*
|
|
278
|
+
* @prop { (player: RpgPlayer) => any } [onLeave]
|
|
279
|
+
* @memberof MapData
|
|
280
|
+
* @example
|
|
281
|
+
* ```ts
|
|
282
|
+
* @MapData({
|
|
283
|
+
* id: 'town',
|
|
284
|
+
* file: require('./tmx/town.tmx'),
|
|
285
|
+
* onLeave(player: RpgPlayer) {
|
|
286
|
+
* console.log(`${player.name} left the town`)
|
|
287
|
+
* // Perform cleanup when player leaves
|
|
288
|
+
* }
|
|
289
|
+
* })
|
|
290
|
+
* class TownMap extends RpgMap {}
|
|
291
|
+
* ```
|
|
292
|
+
* */
|
|
293
|
+
onLeave?: (player: RpgPlayer) => any
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function MapData(options: MapOptions) {
|
|
297
|
+
return (target) => {
|
|
298
|
+
target.file = options.file
|
|
299
|
+
target.id = options.id
|
|
300
|
+
target.type = 'map'
|
|
301
|
+
target.prototype.name = options.name
|
|
302
|
+
target.prototype.file = options.file
|
|
303
|
+
target.prototype.id = options.id
|
|
304
|
+
target.prototype.sounds = options.sounds
|
|
305
|
+
target.prototype.weather = options.weather
|
|
306
|
+
target.prototype.lowMemory = options.lowMemory
|
|
307
|
+
target.prototype.stopAllSoundsBeforeJoin = options.stopAllSoundsBeforeJoin
|
|
308
|
+
|
|
309
|
+
target.prototype.$schema = {}
|
|
310
|
+
|
|
311
|
+
if (options.syncSchema) {
|
|
312
|
+
target.prototype.$schema = options.syncSchema
|
|
313
|
+
}
|
|
314
|
+
target.prototype._events = options.events
|
|
315
|
+
|
|
316
|
+
// Store hooks on prototype
|
|
317
|
+
if (options.onLoad) {
|
|
318
|
+
target.prototype.onLoad = options.onLoad
|
|
319
|
+
}
|
|
320
|
+
if (options.onJoin) {
|
|
321
|
+
target.prototype.onJoin = options.onJoin
|
|
322
|
+
}
|
|
323
|
+
if (options.onLeave) {
|
|
324
|
+
target.prototype.onLeave = options.onLeave
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,16 @@ export * from "./RpgServer";
|
|
|
4
4
|
export * from "./core/setup";
|
|
5
5
|
export * from "./core/inject";
|
|
6
6
|
export * from "./Player/Player";
|
|
7
|
+
export * from "./Player/Components";
|
|
7
8
|
export * from "./module";
|
|
8
9
|
export * from "./rooms/map";
|
|
9
|
-
export * from "./presets";
|
|
10
|
+
export * from "./presets";
|
|
11
|
+
export * from "@signe/reactive";
|
|
12
|
+
export * from "./Gui";
|
|
13
|
+
export * from "./services/save";
|
|
14
|
+
export * from "./storage";
|
|
15
|
+
export { RpgShape, RpgModule, MAXHP, MAXSP, ATK, PDEF, SDEF, STR, AGI, INT, DEX } from "@rpgjs/common";
|
|
16
|
+
export * from "./decorators/event";
|
|
17
|
+
export * from "./decorators/map";
|
|
18
|
+
export * from "./Player/MoveManager";
|
|
19
|
+
export * from "./presets";
|
package/src/logs/log.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
export class Log {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export class Log extends Error {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
|
|
4
|
+
constructor(id: string, msg: string) {
|
|
5
|
+
super(`[${id}] ${msg}`);
|
|
6
|
+
this.name = "RpgLog";
|
|
7
|
+
this.id = id;
|
|
8
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
package/src/module.ts
CHANGED
|
@@ -2,15 +2,80 @@ import { findModules, provideModules } from "@rpgjs/common";
|
|
|
2
2
|
import { FactoryProvider } from "@signe/di";
|
|
3
3
|
import { RpgServerEngine } from "./RpgServerEngine";
|
|
4
4
|
import { RpgMap } from "./rooms/map";
|
|
5
|
+
import { RpgPlayer } from "./Player/Player";
|
|
6
|
+
import { RpgServer } from "./RpgServer";
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Type for server modules that can be either:
|
|
10
|
+
* - An object implementing RpgServer interface
|
|
11
|
+
* - A class decorated with @RpgModule decorator
|
|
12
|
+
*/
|
|
13
|
+
export type RpgServerModule = RpgServer | (new () => any);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Provides server modules configuration to Angular Dependency Injection
|
|
17
|
+
*
|
|
18
|
+
* This function accepts an array of server modules that can be either:
|
|
19
|
+
* - Objects implementing the RpgServer interface
|
|
20
|
+
* - Classes decorated with the @RpgModule decorator (which will be instantiated)
|
|
21
|
+
*
|
|
22
|
+
* @param modules - Array of server modules (objects or classes)
|
|
23
|
+
* @returns FactoryProvider configuration for Angular DI
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* // Using an object
|
|
27
|
+
* provideServerModules([
|
|
28
|
+
* {
|
|
29
|
+
* player: {
|
|
30
|
+
* onConnected(player) {
|
|
31
|
+
* console.log('Player connected')
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* ])
|
|
36
|
+
*
|
|
37
|
+
* // Using a decorated class
|
|
38
|
+
* @RpgModule<RpgServer>({
|
|
39
|
+
* engine: {
|
|
40
|
+
* onStart(server) {
|
|
41
|
+
* console.log('Server started')
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* })
|
|
45
|
+
* class MyServerModule {}
|
|
46
|
+
*
|
|
47
|
+
* provideServerModules([MyServerModule])
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function provideServerModules(modules: RpgServerModule[]): FactoryProvider {
|
|
7
51
|
return provideModules(modules, "server", (modules, context) => {
|
|
8
52
|
const mainModuleServer = findModules(context, 'Server')
|
|
9
53
|
modules = [...mainModuleServer, ...modules]
|
|
10
54
|
modules = modules.map((module) => {
|
|
55
|
+
// If module is a class (constructor function), instantiate it
|
|
56
|
+
// The RpgModule decorator adds properties to the prototype, which will be accessible via the instance
|
|
57
|
+
if (typeof module === 'function') {
|
|
58
|
+
const instance = new module() as any;
|
|
59
|
+
// Copy all enumerable properties (including from prototype) to a plain object
|
|
60
|
+
const moduleObj: any = {};
|
|
61
|
+
for (const key in instance) {
|
|
62
|
+
moduleObj[key] = instance[key];
|
|
63
|
+
}
|
|
64
|
+
module = moduleObj;
|
|
65
|
+
}
|
|
11
66
|
if ('server' in module) {
|
|
12
67
|
module = module.server as any;
|
|
13
68
|
}
|
|
69
|
+
if (module.player?.props) {
|
|
70
|
+
module = {
|
|
71
|
+
...module,
|
|
72
|
+
playerProps: {
|
|
73
|
+
load: (player: RpgPlayer) => {
|
|
74
|
+
player.setSync(module.player.props)
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
14
79
|
if (module.maps && Array.isArray(module.maps)) {
|
|
15
80
|
const maps = [...module.maps];
|
|
16
81
|
module = {
|
|
@@ -18,15 +83,73 @@ export function provideServerModules(modules: any[]): FactoryProvider {
|
|
|
18
83
|
maps: {
|
|
19
84
|
load: (engine: RpgMap) => {
|
|
20
85
|
maps.forEach((map) => {
|
|
21
|
-
|
|
86
|
+
// If map is a class (constructor function), extract properties from class and prototype
|
|
87
|
+
// Otherwise, use the object directly
|
|
88
|
+
let mapInstance: any;
|
|
89
|
+
if (typeof map === 'function') {
|
|
90
|
+
// Extract properties from the class (static properties set by @MapData decorator)
|
|
91
|
+
// and from the prototype (instance properties like _events)
|
|
92
|
+
// The decorator sets properties on both the class and prototype, so we check both
|
|
93
|
+
const MapClass = map as any;
|
|
94
|
+
mapInstance = {
|
|
95
|
+
id: MapClass.prototype?.id ?? MapClass.id,
|
|
96
|
+
file: MapClass.prototype?.file ?? MapClass.file,
|
|
97
|
+
type: MapClass.type,
|
|
98
|
+
name: MapClass.prototype?.name,
|
|
99
|
+
sounds: MapClass.prototype?.sounds,
|
|
100
|
+
weather: MapClass.prototype?.weather,
|
|
101
|
+
lowMemory: MapClass.prototype?.lowMemory,
|
|
102
|
+
stopAllSoundsBeforeJoin: MapClass.prototype?.stopAllSoundsBeforeJoin,
|
|
103
|
+
events: MapClass.prototype?._events,
|
|
104
|
+
syncSchema: MapClass.prototype?.$schema,
|
|
105
|
+
onLoad: MapClass.prototype?.onLoad,
|
|
106
|
+
onJoin: MapClass.prototype?.onJoin,
|
|
107
|
+
onLeave: MapClass.prototype?.onLeave,
|
|
108
|
+
};
|
|
109
|
+
} else {
|
|
110
|
+
mapInstance = map;
|
|
111
|
+
}
|
|
112
|
+
engine.maps.push(mapInstance);
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (module.worldMaps && Array.isArray(module.worldMaps)) {
|
|
119
|
+
const worldMaps = [...module.worldMaps];
|
|
120
|
+
module = {
|
|
121
|
+
...module,
|
|
122
|
+
worldMaps: {
|
|
123
|
+
load: (engine: RpgMap) => {
|
|
124
|
+
worldMaps.forEach((worldMap) => {
|
|
125
|
+
engine.createDynamicWorldMaps(worldMap)
|
|
22
126
|
});
|
|
23
127
|
},
|
|
24
128
|
}
|
|
25
129
|
};
|
|
26
130
|
}
|
|
131
|
+
if (module.database) {
|
|
132
|
+
const database = module.database;
|
|
133
|
+
module = {
|
|
134
|
+
...module,
|
|
135
|
+
databaseHooks: {
|
|
136
|
+
load: async (engine: RpgMap) => {
|
|
137
|
+
const data = typeof database === 'function'
|
|
138
|
+
? await database(engine)
|
|
139
|
+
: database;
|
|
140
|
+
if (!data || typeof data !== 'object') {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
for (const key in data) {
|
|
144
|
+
engine.addInDatabase(key, data[key]);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
27
150
|
return module;
|
|
28
151
|
})
|
|
29
152
|
return modules
|
|
30
153
|
});
|
|
31
154
|
}
|
|
32
|
-
|
|
155
|
+
|
package/src/presets/index.ts
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { random } from "@rpgjs/common"
|
|
2
|
-
|
|
3
|
-
export const MAXHP: string = 'maxHp'
|
|
4
|
-
export const MAXSP: string = 'maxSp'
|
|
5
|
-
export const ATK: string = 'atk'
|
|
6
|
-
export const PDEF: string = 'pdef'
|
|
7
|
-
export const SDEF: string = 'sdef'
|
|
8
|
-
export const STR: string = 'str'
|
|
9
|
-
export const AGI: string = 'agi'
|
|
10
|
-
export const INT: string = 'int'
|
|
11
|
-
export const DEX: string = 'dex'
|
|
2
|
+
import { DEX, AGI, ATK, PDEF, SDEF, STR, INT } from "@rpgjs/common"
|
|
12
3
|
|
|
13
4
|
export const MAXHP_CURVE = {
|
|
14
5
|
start: 741,
|