@rpgjs/server 5.0.0-beta.3 → 5.0.0-beta.5
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/Player/SkillManager.d.ts +13 -4
- package/dist/RpgServer.d.ts +8 -0
- package/dist/index.js +70 -25
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/Gui/MenuGui.ts +30 -20
- package/src/Player/ParameterManager.ts +4 -1
- package/src/Player/Player.ts +2 -0
- package/src/Player/SkillManager.ts +42 -5
- package/src/RpgServer.ts +9 -0
- package/src/rooms/lobby.ts +6 -1
- package/src/rooms/map.ts +17 -0
- package/tests/gui.spec.ts +76 -0
- package/tests/skill.spec.ts +48 -0
|
@@ -3,9 +3,19 @@ import { RpgPlayer } from './Player';
|
|
|
3
3
|
/**
|
|
4
4
|
* Type for skill class constructor
|
|
5
5
|
*/
|
|
6
|
-
type SkillClass = {
|
|
6
|
+
export type SkillClass = {
|
|
7
7
|
new (...args: any[]): any;
|
|
8
8
|
};
|
|
9
|
+
export type SkillChangeAction = "learn" | "forget";
|
|
10
|
+
export interface SkillChangeOptions {
|
|
11
|
+
source?: "manual" | "level" | "class" | "studio" | string;
|
|
12
|
+
level?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SkillChangePayload extends SkillChangeOptions {
|
|
15
|
+
action: SkillChangeAction;
|
|
16
|
+
skill: SkillClass | SkillObject | string;
|
|
17
|
+
skillId: string;
|
|
18
|
+
}
|
|
9
19
|
/**
|
|
10
20
|
* Interface defining the hooks that can be implemented on skill classes or objects
|
|
11
21
|
*
|
|
@@ -180,7 +190,7 @@ export interface ISkillManager {
|
|
|
180
190
|
* @returns The learned skill data
|
|
181
191
|
* @throws SkillLog.alreadyLearned if the player already knows the skill
|
|
182
192
|
*/
|
|
183
|
-
learnSkill(skillInput: SkillClass | SkillObject | string): any;
|
|
193
|
+
learnSkill(skillInput: SkillClass | SkillObject | string, options?: SkillChangeOptions): any;
|
|
184
194
|
/**
|
|
185
195
|
* Forget a skill
|
|
186
196
|
*
|
|
@@ -188,7 +198,7 @@ export interface ISkillManager {
|
|
|
188
198
|
* @returns The forgotten skill data
|
|
189
199
|
* @throws SkillLog.notLearned if trying to forget a skill not learned
|
|
190
200
|
*/
|
|
191
|
-
forgetSkill(skillInput: SkillClass | SkillObject | string): any;
|
|
201
|
+
forgetSkill(skillInput: SkillClass | SkillObject | string, options?: SkillChangeOptions): any;
|
|
192
202
|
/**
|
|
193
203
|
* Use a skill
|
|
194
204
|
*
|
|
@@ -202,4 +212,3 @@ export interface ISkillManager {
|
|
|
202
212
|
*/
|
|
203
213
|
useSkill(skillInput: SkillClass | SkillObject | string, otherPlayer?: RpgPlayer | RpgPlayer[]): any;
|
|
204
214
|
}
|
|
205
|
-
export {};
|
package/dist/RpgServer.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { RpgPlayer, RpgEvent } from './Player/Player';
|
|
|
3
3
|
import { RpgMap } from './rooms/map';
|
|
4
4
|
import { RpgServerEngine } from './RpgServerEngine';
|
|
5
5
|
import { WorldMapConfig, RpgShape, MapPhysicsInitContext, MapPhysicsEntityContext } from '../../common/src';
|
|
6
|
+
import { SkillChangePayload } from './Player/SkillManager';
|
|
6
7
|
type RpgClassMap<T> = new () => T;
|
|
7
8
|
type RpgClassEvent<T> = RpgEvent;
|
|
8
9
|
type MatchMakerOption = any;
|
|
@@ -196,6 +197,13 @@ export interface RpgPlayerHooks {
|
|
|
196
197
|
*/
|
|
197
198
|
onLevelUp?: (player: RpgPlayer, nbLevel: number) => any;
|
|
198
199
|
/**
|
|
200
|
+
* When a player learns or forgets a skill
|
|
201
|
+
*
|
|
202
|
+
* @prop { (player: RpgPlayer, payload: SkillChangePayload) => any } [onSkillChange]
|
|
203
|
+
* @memberof RpgPlayerHooks
|
|
204
|
+
*/
|
|
205
|
+
onSkillChange?: (player: RpgPlayer, payload: SkillChangePayload) => any;
|
|
206
|
+
/**
|
|
199
207
|
* When the player's HP drops to 0
|
|
200
208
|
*
|
|
201
209
|
* @prop { (player: RpgPlayer) => any } [onDead]
|
package/dist/index.js
CHANGED
|
@@ -7826,6 +7826,13 @@ function provideAutoSave(strategy) {
|
|
|
7826
7826
|
}
|
|
7827
7827
|
//#endregion
|
|
7828
7828
|
//#region src/Gui/MenuGui.ts
|
|
7829
|
+
function readReactiveValue(value, context) {
|
|
7830
|
+
return typeof value === "function" ? value.call(context) : value;
|
|
7831
|
+
}
|
|
7832
|
+
function readField(source, key, fallback) {
|
|
7833
|
+
const value = source?.[key];
|
|
7834
|
+
return readReactiveValue(value, source) ?? fallback;
|
|
7835
|
+
}
|
|
7829
7836
|
var MenuGui = class extends Gui {
|
|
7830
7837
|
constructor(player) {
|
|
7831
7838
|
super(PrebuiltGui.MainMenu, player);
|
|
@@ -7882,7 +7889,7 @@ var MenuGui = class extends Gui {
|
|
|
7882
7889
|
}));
|
|
7883
7890
|
const player = this.player;
|
|
7884
7891
|
const databaseById = player.databaseById?.bind(player);
|
|
7885
|
-
const equippedIds = new Set((player.equipments?.() || []).map((it) => it
|
|
7892
|
+
const equippedIds = new Set((player.equipments?.() || []).map((it) => readField(it, "id", readField(it, "name"))));
|
|
7886
7893
|
const buildStats = () => {
|
|
7887
7894
|
const params = player.param || {};
|
|
7888
7895
|
const statKeys = [
|
|
@@ -7895,29 +7902,29 @@ var MenuGui = class extends Gui {
|
|
|
7895
7902
|
];
|
|
7896
7903
|
const stats = {};
|
|
7897
7904
|
statKeys.forEach((key) => {
|
|
7898
|
-
stats[key] = params[key] ?? 0;
|
|
7905
|
+
stats[key] = readReactiveValue(params[key]) ?? 0;
|
|
7899
7906
|
});
|
|
7900
|
-
stats.pdef = player.pdef ?? params.pdef ?? 0;
|
|
7901
|
-
stats.sdef = player.sdef ?? params.sdef ?? 0;
|
|
7902
|
-
stats.atk = player.atk ?? params.atk ?? 0;
|
|
7907
|
+
stats.pdef = readReactiveValue(player.pdef ?? params.pdef) ?? 0;
|
|
7908
|
+
stats.sdef = readReactiveValue(player.sdef ?? params.sdef) ?? 0;
|
|
7909
|
+
stats.atk = readReactiveValue(player.atk ?? params.atk) ?? 0;
|
|
7903
7910
|
return stats;
|
|
7904
7911
|
};
|
|
7905
7912
|
const items = (player.items?.() || []).map((item) => {
|
|
7906
|
-
const id = item
|
|
7913
|
+
const id = readField(item, "id");
|
|
7907
7914
|
const data = databaseById ? databaseById(id) : {};
|
|
7908
|
-
const type = data
|
|
7909
|
-
const consumable = data
|
|
7915
|
+
const type = readField(data, "_type", "item");
|
|
7916
|
+
const consumable = readField(data, "consumable");
|
|
7910
7917
|
const isConsumable = consumable !== void 0 ? consumable : type === "item";
|
|
7911
7918
|
const usable = isConsumable === false ? false : consumable === void 0 && type !== "item" ? false : true;
|
|
7912
7919
|
return {
|
|
7913
7920
|
id,
|
|
7914
|
-
name: item
|
|
7915
|
-
description: item
|
|
7916
|
-
quantity: item
|
|
7917
|
-
icon: data
|
|
7918
|
-
atk: item
|
|
7919
|
-
pdef: item
|
|
7920
|
-
sdef: item
|
|
7921
|
+
name: readField(item, "name"),
|
|
7922
|
+
description: readField(item, "description"),
|
|
7923
|
+
quantity: readField(item, "quantity"),
|
|
7924
|
+
icon: readField(data, "icon", readField(item, "icon")),
|
|
7925
|
+
atk: readField(item, "atk"),
|
|
7926
|
+
pdef: readField(item, "pdef"),
|
|
7927
|
+
sdef: readField(item, "sdef"),
|
|
7921
7928
|
consumable: isConsumable,
|
|
7922
7929
|
type,
|
|
7923
7930
|
usable,
|
|
@@ -7929,14 +7936,14 @@ var MenuGui = class extends Gui {
|
|
|
7929
7936
|
items,
|
|
7930
7937
|
equips: items.filter((item) => item.type === "weapon" || item.type === "armor"),
|
|
7931
7938
|
skills: (player.skills?.() || []).map((skill) => ({
|
|
7932
|
-
id: skill
|
|
7933
|
-
name: skill
|
|
7934
|
-
description: skill
|
|
7935
|
-
spCost: skill
|
|
7939
|
+
id: readField(skill, "id", readField(skill, "name")),
|
|
7940
|
+
name: readField(skill, "name", readField(skill, "id", "Skill")),
|
|
7941
|
+
description: readField(skill, "description", ""),
|
|
7942
|
+
spCost: readField(skill, "spCost", 0)
|
|
7936
7943
|
})),
|
|
7937
7944
|
saveLoad: this.buildSaveLoad(options),
|
|
7938
7945
|
playerStats: buildStats(),
|
|
7939
|
-
expForNextlevel: player.expForNextlevel
|
|
7946
|
+
expForNextlevel: readReactiveValue(player.expForNextlevel)
|
|
7940
7947
|
};
|
|
7941
7948
|
}
|
|
7942
7949
|
refreshMenu(clientActionId) {
|
|
@@ -8708,7 +8715,10 @@ function WithParameterManager(Base) {
|
|
|
8708
8715
|
if (this.finalLevel && val > this.finalLevel) val = this.finalLevel;
|
|
8709
8716
|
const currentClass = this._class && this._class();
|
|
8710
8717
|
if (currentClass && "skillsToLearn" in currentClass && Array.isArray(currentClass.skillsToLearn)) {
|
|
8711
|
-
for (let i = this._level(); i <= val; i++) for (let skill of currentClass.skillsToLearn) if (skill.level == i) this["learnSkill"](skill.skill
|
|
8718
|
+
for (let i = this._level(); i <= val; i++) for (let skill of currentClass.skillsToLearn) if (skill.level == i) this["learnSkill"](skill.skill, {
|
|
8719
|
+
source: skill.source ?? "level",
|
|
8720
|
+
level: i
|
|
8721
|
+
});
|
|
8712
8722
|
}
|
|
8713
8723
|
const hasNewLevel = val - lastLevel;
|
|
8714
8724
|
if (hasNewLevel > 0) this["execMethod"]("onLevelUp", [hasNewLevel]);
|
|
@@ -9763,7 +9773,7 @@ function WithSkillManager(Base) {
|
|
|
9763
9773
|
* });
|
|
9764
9774
|
* ```
|
|
9765
9775
|
*/
|
|
9766
|
-
learnSkill(skillInput) {
|
|
9776
|
+
learnSkill(skillInput, options = {}) {
|
|
9767
9777
|
const map = this._getSkillMap();
|
|
9768
9778
|
const { skillId, skillData, skillInstance } = this._resolveSkillInput(skillInput, map);
|
|
9769
9779
|
if (this._getLearnedSkillEntry(skillId)) throw SkillLog.alreadyLearned(skillData);
|
|
@@ -9771,6 +9781,13 @@ function WithSkillManager(Base) {
|
|
|
9771
9781
|
this.skills().push(instance);
|
|
9772
9782
|
const hookTarget = instance._skillInstance || instance;
|
|
9773
9783
|
this["execMethod"]("onLearn", [this], hookTarget);
|
|
9784
|
+
this["execMethod"]("onSkillChange", [{
|
|
9785
|
+
action: "learn",
|
|
9786
|
+
skill: skillData,
|
|
9787
|
+
skillId,
|
|
9788
|
+
source: options.source ?? "manual",
|
|
9789
|
+
level: options.level
|
|
9790
|
+
}]);
|
|
9774
9791
|
return skillData;
|
|
9775
9792
|
}
|
|
9776
9793
|
/**
|
|
@@ -9789,7 +9806,7 @@ function WithSkillManager(Base) {
|
|
|
9789
9806
|
* player.forgetSkill(FireSkill);
|
|
9790
9807
|
* ```
|
|
9791
9808
|
*/
|
|
9792
|
-
forgetSkill(skillInput) {
|
|
9809
|
+
forgetSkill(skillInput, options = {}) {
|
|
9793
9810
|
const index = this._getSkillIndex(skillInput);
|
|
9794
9811
|
if (index === -1) {
|
|
9795
9812
|
let skillData = skillInput;
|
|
@@ -9812,6 +9829,13 @@ function WithSkillManager(Base) {
|
|
|
9812
9829
|
this.skills().splice(index, 1);
|
|
9813
9830
|
const hookTarget = skillEntry?._skillInstance || skillEntry?._skillData || skillData;
|
|
9814
9831
|
this["execMethod"]("onForget", [this], hookTarget);
|
|
9832
|
+
this["execMethod"]("onSkillChange", [{
|
|
9833
|
+
action: "forget",
|
|
9834
|
+
skill: skillData,
|
|
9835
|
+
skillId: skillData?.id ?? String(skillInput),
|
|
9836
|
+
source: options.source ?? "manual",
|
|
9837
|
+
level: options.level
|
|
9838
|
+
}]);
|
|
9815
9839
|
return skillData;
|
|
9816
9840
|
}
|
|
9817
9841
|
/**
|
|
@@ -10730,7 +10754,9 @@ var RpgPlayer = class extends BasicPlayerMixins(RpgCommonPlayer) {
|
|
|
10730
10754
|
animationName,
|
|
10731
10755
|
graphic,
|
|
10732
10756
|
nbTimes: finalNbTimes,
|
|
10733
|
-
object: this.id
|
|
10757
|
+
object: this.id,
|
|
10758
|
+
restoreAnimationName: this.animationName(),
|
|
10759
|
+
restoreGraphics: [...this.graphics()]
|
|
10734
10760
|
}
|
|
10735
10761
|
});
|
|
10736
10762
|
}
|
|
@@ -15746,6 +15772,12 @@ var RpgMap = class RpgMap extends RpgCommonMap {
|
|
|
15746
15772
|
* ```
|
|
15747
15773
|
*/
|
|
15748
15774
|
async onInput(player, input) {
|
|
15775
|
+
if (typeof player.canMove === "function" && !player.canMove()) {
|
|
15776
|
+
player.pendingInputs = [];
|
|
15777
|
+
player.lastProcessedInputTs = 0;
|
|
15778
|
+
this.stopMovement(player);
|
|
15779
|
+
return;
|
|
15780
|
+
}
|
|
15749
15781
|
const lastAckedFrame = player._lastFramePositions?.frame ?? 0;
|
|
15750
15782
|
const now = Date.now();
|
|
15751
15783
|
const candidates = [];
|
|
@@ -16048,6 +16080,15 @@ var RpgMap = class RpgMap extends RpgCommonMap {
|
|
|
16048
16080
|
inputs: []
|
|
16049
16081
|
};
|
|
16050
16082
|
}
|
|
16083
|
+
if (typeof player.canMove === "function" && !player.canMove()) {
|
|
16084
|
+
player.pendingInputs = [];
|
|
16085
|
+
player.lastProcessedInputTs = 0;
|
|
16086
|
+
this.stopMovement(player);
|
|
16087
|
+
return {
|
|
16088
|
+
player,
|
|
16089
|
+
inputs: []
|
|
16090
|
+
};
|
|
16091
|
+
}
|
|
16051
16092
|
const processedInputs = [];
|
|
16052
16093
|
const config = {
|
|
16053
16094
|
maxTimeDelta: 1e3,
|
|
@@ -17216,7 +17257,11 @@ var LobbyRoom = class LobbyRoom extends BaseRoom {
|
|
|
17216
17257
|
async guiInteraction(player, value) {
|
|
17217
17258
|
if (value.data.id === "start") {
|
|
17218
17259
|
player.initializeDefaultStats();
|
|
17219
|
-
|
|
17260
|
+
try {
|
|
17261
|
+
await lastValueFrom(this.hooks.callHooks("server-player-onStart", player));
|
|
17262
|
+
} catch (error) {
|
|
17263
|
+
console.error("[RPGJS] Error during player onStart hooks:", error);
|
|
17264
|
+
}
|
|
17220
17265
|
}
|
|
17221
17266
|
}
|
|
17222
17267
|
};
|