mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-30 06:13:52 +00:00
commit
39e8f810d2
@ -77,7 +77,7 @@ public final class Grasscutter {
|
|||||||
Tools.createGmHandbook(); exitEarly = true;
|
Tools.createGmHandbook(); exitEarly = true;
|
||||||
}
|
}
|
||||||
case "-gachamap" -> {
|
case "-gachamap" -> {
|
||||||
Tools.createGachaMapping("./gacha-mapping.js"); exitEarly = true;
|
Tools.createGachaMapping(Grasscutter.getConfig().DATA_FOLDER + "/gacha_mappings.js"); exitEarly = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public class MovementManager {
|
|||||||
|
|
||||||
public HashMap<String, HashSet<MotionState>> MotionStatesCategorized = new HashMap<>();
|
public HashMap<String, HashSet<MotionState>> MotionStatesCategorized = new HashMap<>();
|
||||||
|
|
||||||
private enum Consumption {
|
private enum ConsumptionType {
|
||||||
None(0),
|
None(0),
|
||||||
|
|
||||||
// consume
|
// consume
|
||||||
@ -37,6 +37,7 @@ public class MovementManager {
|
|||||||
SWIM_DASH_START(-200),
|
SWIM_DASH_START(-200),
|
||||||
SWIM_DASH(-200),
|
SWIM_DASH(-200),
|
||||||
SWIMMING(-80),
|
SWIMMING(-80),
|
||||||
|
FIGHT(0),
|
||||||
|
|
||||||
// restore
|
// restore
|
||||||
STANDBY(500),
|
STANDBY(500),
|
||||||
@ -46,11 +47,22 @@ public class MovementManager {
|
|||||||
POWERED_FLY(500);
|
POWERED_FLY(500);
|
||||||
|
|
||||||
public final int amount;
|
public final int amount;
|
||||||
Consumption(int amount) {
|
ConsumptionType(int amount) {
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class Consumption {
|
||||||
|
public ConsumptionType consumptionType;
|
||||||
|
public int amount;
|
||||||
|
public Consumption(ConsumptionType ct, int a) {
|
||||||
|
consumptionType = ct;
|
||||||
|
amount = a;
|
||||||
|
}
|
||||||
|
public Consumption(ConsumptionType ct) {
|
||||||
|
this(ct, ct.amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private MotionState previousState = MotionState.MOTION_STANDBY;
|
private MotionState previousState = MotionState.MOTION_STANDBY;
|
||||||
private MotionState currentState = MotionState.MOTION_STANDBY;
|
private MotionState currentState = MotionState.MOTION_STANDBY;
|
||||||
@ -64,8 +76,9 @@ public class MovementManager {
|
|||||||
private Timer movementManagerTickTimer;
|
private Timer movementManagerTickTimer;
|
||||||
private GameSession cachedSession = null;
|
private GameSession cachedSession = null;
|
||||||
private GameEntity cachedEntity = null;
|
private GameEntity cachedEntity = null;
|
||||||
|
|
||||||
private int staminaRecoverDelay = 0;
|
private int staminaRecoverDelay = 0;
|
||||||
|
private int skillCaster = 0;
|
||||||
|
private int skillCasting = 0;
|
||||||
|
|
||||||
public MovementManager(Player player) {
|
public MovementManager(Player player) {
|
||||||
previousCoordinates.add(new Position(0,0,0));
|
previousCoordinates.add(new Position(0,0,0));
|
||||||
@ -114,6 +127,12 @@ public class MovementManager {
|
|||||||
MotionState.MOTION_WALK,
|
MotionState.MOTION_WALK,
|
||||||
MotionState.MOTION_DANGER_WALK
|
MotionState.MOTION_DANGER_WALK
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
MotionStatesCategorized.put("FIGHT", new HashSet<>(Arrays.asList(
|
||||||
|
MotionState.MOTION_FIGHT
|
||||||
|
)));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(GameSession session, EntityMoveInfoOuterClass.EntityMoveInfo moveInfo, GameEntity entity) {
|
public void handle(GameSession session, EntityMoveInfoOuterClass.EntityMoveInfo moveInfo, GameEntity entity) {
|
||||||
@ -134,11 +153,12 @@ public class MovementManager {
|
|||||||
currentCoordinates = newPos;
|
currentCoordinates = newPos;
|
||||||
}
|
}
|
||||||
currentState = motionInfo.getState();
|
currentState = motionInfo.getState();
|
||||||
Grasscutter.getLogger().debug("" + currentState);
|
Grasscutter.getLogger().debug("" + currentState + "\t" + (moveInfo.getIsReliable() ? "reliable" : ""));
|
||||||
handleFallOnGround(motionInfo);
|
handleFallOnGround(motionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetTimer() {
|
public void resetTimer() {
|
||||||
|
Grasscutter.getLogger().debug("MovementManager ticker stopped");
|
||||||
movementManagerTickTimer.cancel();
|
movementManagerTickTimer.cancel();
|
||||||
movementManagerTickTimer = null;
|
movementManagerTickTimer = null;
|
||||||
}
|
}
|
||||||
@ -167,8 +187,6 @@ public class MovementManager {
|
|||||||
return player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
return player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Returns new stamina
|
// Returns new stamina
|
||||||
public int updateStamina(GameSession session, int amount) {
|
public int updateStamina(GameSession session, int amount) {
|
||||||
int currentStamina = session.getPlayer().getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
int currentStamina = session.getPlayer().getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
||||||
@ -184,6 +202,7 @@ public class MovementManager {
|
|||||||
newStamina = playerMaxStamina;
|
newStamina = playerMaxStamina;
|
||||||
}
|
}
|
||||||
session.getPlayer().setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
session.getPlayer().setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
||||||
|
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||||
return newStamina;
|
return newStamina;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,95 +288,40 @@ public class MovementManager {
|
|||||||
boolean moving = isPlayerMoving();
|
boolean moving = isPlayerMoving();
|
||||||
if (moving || (getCurrentStamina() < getMaximumStamina())) {
|
if (moving || (getCurrentStamina() < getMaximumStamina())) {
|
||||||
// Grasscutter.getLogger().debug("Player moving: " + moving + ", stamina full: " + (getCurrentStamina() >= getMaximumStamina()) + ", recalculate stamina");
|
// Grasscutter.getLogger().debug("Player moving: " + moving + ", stamina full: " + (getCurrentStamina() >= getMaximumStamina()) + ", recalculate stamina");
|
||||||
Consumption consumption = Consumption.None;
|
Consumption consumption = new Consumption(ConsumptionType.None);
|
||||||
|
|
||||||
// TODO: refactor these conditions.
|
// TODO: refactor these conditions.
|
||||||
if (MotionStatesCategorized.get("CLIMB").contains(currentState)) {
|
if (MotionStatesCategorized.get("CLIMB").contains(currentState)) {
|
||||||
if (currentState == MotionState.MOTION_CLIMB) {
|
consumption = getClimbConsumption();
|
||||||
// CLIMB
|
|
||||||
if (previousState != MotionState.MOTION_CLIMB && previousState != MotionState.MOTION_CLIMB_JUMP) {
|
|
||||||
consumption = Consumption.CLIMB_START;
|
|
||||||
} else {
|
|
||||||
consumption = Consumption.CLIMBING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentState == MotionState.MOTION_CLIMB_JUMP) {
|
|
||||||
if (previousState != MotionState.MOTION_CLIMB_JUMP) {
|
|
||||||
consumption = Consumption.CLIMB_JUMP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentState == MotionState.MOTION_JUMP) {
|
|
||||||
if (previousState == MotionState.MOTION_CLIMB) {
|
|
||||||
consumption = Consumption.CLIMB_JUMP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (MotionStatesCategorized.get("SWIM").contains((currentState))) {
|
} else if (MotionStatesCategorized.get("SWIM").contains((currentState))) {
|
||||||
// SWIM
|
consumption = getSwimConsumptions();
|
||||||
if (currentState == MotionState.MOTION_SWIM_MOVE) {
|
|
||||||
consumption = Consumption.SWIMMING;
|
|
||||||
}
|
|
||||||
if (currentState == MotionState.MOTION_SWIM_DASH) {
|
|
||||||
if (previousState != MotionState.MOTION_SWIM_DASH) {
|
|
||||||
consumption = Consumption.SWIM_DASH_START;
|
|
||||||
} else {
|
|
||||||
consumption = Consumption.SWIM_DASH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (MotionStatesCategorized.get("RUN").contains(currentState)) {
|
} else if (MotionStatesCategorized.get("RUN").contains(currentState)) {
|
||||||
// RUN, DASH and WALK
|
consumption = getRunWalkDashConsumption();
|
||||||
// DASH
|
|
||||||
if (currentState == MotionState.MOTION_DASH_BEFORE_SHAKE) {
|
|
||||||
consumption = Consumption.DASH;
|
|
||||||
if (previousState == MotionState.MOTION_DASH_BEFORE_SHAKE) {
|
|
||||||
// only charge once
|
|
||||||
consumption = Consumption.SPRINT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentState == MotionState.MOTION_DASH) {
|
|
||||||
consumption = Consumption.SPRINT;
|
|
||||||
}
|
|
||||||
// RUN
|
|
||||||
if (currentState == MotionState.MOTION_RUN) {
|
|
||||||
consumption = Consumption.RUN;
|
|
||||||
}
|
|
||||||
// WALK
|
|
||||||
if (currentState == MotionState.MOTION_WALK) {
|
|
||||||
consumption = Consumption.WALK;
|
|
||||||
}
|
|
||||||
} else if (MotionStatesCategorized.get("FLY").contains(currentState)) {
|
} else if (MotionStatesCategorized.get("FLY").contains(currentState)) {
|
||||||
// FLY
|
consumption = getFlyConsumption();
|
||||||
consumption = Consumption.FLY;
|
|
||||||
// POWERED_FLY, e.g. wind tunnel
|
|
||||||
if (currentState == MotionState.MOTION_POWERED_FLY) {
|
|
||||||
consumption = Consumption.POWERED_FLY;
|
|
||||||
}
|
|
||||||
} else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) {
|
} else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) {
|
||||||
// STAND
|
consumption = getStandConsumption();
|
||||||
if (currentState == MotionState.MOTION_STANDBY) {
|
} else if (MotionStatesCategorized.get("FIGHT").contains(currentState)) {
|
||||||
consumption = Consumption.STANDBY;
|
consumption = getFightConsumption();
|
||||||
}
|
|
||||||
if (currentState == MotionState.MOTION_STANDBY_MOVE) {
|
|
||||||
consumption = Consumption.STANDBY_MOVE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tick triggered
|
// delay 2 seconds before start recovering - as official server does.
|
||||||
handleDrowning();
|
|
||||||
|
|
||||||
if (cachedSession != null) {
|
if (cachedSession != null) {
|
||||||
if (consumption.amount < 0) {
|
if (consumption.amount < 0) {
|
||||||
staminaRecoverDelay = 0;
|
staminaRecoverDelay = 0;
|
||||||
}
|
}
|
||||||
if (consumption.amount > 0) {
|
if (consumption.amount > 0 && consumption.consumptionType != ConsumptionType.POWERED_FLY) {
|
||||||
if (staminaRecoverDelay < 10) {
|
if (staminaRecoverDelay < 10) {
|
||||||
staminaRecoverDelay++;
|
staminaRecoverDelay++;
|
||||||
consumption = Consumption.None;
|
consumption = new Consumption(ConsumptionType.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int newStamina = updateStamina(cachedSession, consumption.amount);
|
// Grasscutter.getLogger().debug(getCurrentStamina() + "/" + getMaximumStamina() + "\t" + currentState + "\t" + "isMoving: " + isPlayerMoving() + "\t(" + consumption.consumptionType + "," + consumption.amount + ")");
|
||||||
cachedSession.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
updateStamina(cachedSession, consumption.amount);
|
||||||
Grasscutter.getLogger().debug(player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) + "/" + player.getProperty(PlayerProperty.PROP_MAX_STAMINA) + "\t" + currentState + "\t" + "isMoving: " + isPlayerMoving() + "\t" + consumption + "(" + consumption.amount + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tick triggered
|
||||||
|
handleDrowning();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,4 +330,113 @@ public class MovementManager {
|
|||||||
currentCoordinates.getY(), currentCoordinates.getZ());;
|
currentCoordinates.getY(), currentCoordinates.getZ());;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Consumption getClimbConsumption() {
|
||||||
|
Consumption consumption = new Consumption(ConsumptionType.None);
|
||||||
|
if (currentState == MotionState.MOTION_CLIMB) {
|
||||||
|
consumption = new Consumption(ConsumptionType.CLIMBING);
|
||||||
|
if (previousState != MotionState.MOTION_CLIMB && previousState != MotionState.MOTION_CLIMB_JUMP) {
|
||||||
|
consumption = new Consumption(ConsumptionType.CLIMB_START);
|
||||||
|
}
|
||||||
|
if (!isPlayerMoving()) {
|
||||||
|
consumption = new Consumption(ConsumptionType.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentState == MotionState.MOTION_CLIMB_JUMP) {
|
||||||
|
if (previousState != MotionState.MOTION_CLIMB_JUMP) {
|
||||||
|
consumption = new Consumption(ConsumptionType.CLIMB_JUMP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumption getSwimConsumptions() {
|
||||||
|
Consumption consumption = new Consumption(ConsumptionType.None);
|
||||||
|
if (currentState == MotionState.MOTION_SWIM_MOVE) {
|
||||||
|
consumption = new Consumption(ConsumptionType.SWIMMING);
|
||||||
|
}
|
||||||
|
if (currentState == MotionState.MOTION_SWIM_DASH) {
|
||||||
|
consumption = new Consumption(ConsumptionType.SWIM_DASH_START);
|
||||||
|
if (previousState == MotionState.MOTION_SWIM_DASH) {
|
||||||
|
consumption = new Consumption(ConsumptionType.SWIM_DASH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumption getRunWalkDashConsumption() {
|
||||||
|
Consumption consumption = new Consumption(ConsumptionType.None);
|
||||||
|
if (currentState == MotionState.MOTION_DASH_BEFORE_SHAKE) {
|
||||||
|
consumption = new Consumption(ConsumptionType.DASH);
|
||||||
|
if (previousState == MotionState.MOTION_DASH_BEFORE_SHAKE) {
|
||||||
|
// only charge once
|
||||||
|
consumption = new Consumption(ConsumptionType.SPRINT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentState == MotionState.MOTION_DASH) {
|
||||||
|
consumption = new Consumption(ConsumptionType.SPRINT);
|
||||||
|
}
|
||||||
|
if (currentState == MotionState.MOTION_RUN) {
|
||||||
|
consumption = new Consumption(ConsumptionType.RUN);
|
||||||
|
}
|
||||||
|
if (currentState == MotionState.MOTION_WALK) {
|
||||||
|
consumption = new Consumption(ConsumptionType.WALK);
|
||||||
|
}
|
||||||
|
return consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumption getFlyConsumption() {
|
||||||
|
Consumption consumption = new Consumption(ConsumptionType.FLY);
|
||||||
|
HashMap<Integer, Float> glidingCostReduction = new HashMap<>() {{
|
||||||
|
put(212301, 0.8f); // Amber
|
||||||
|
put(222301, 0.8f); // Venti
|
||||||
|
}};
|
||||||
|
float reduction = 1;
|
||||||
|
for (EntityAvatar entity: cachedSession.getPlayer().getTeamManager().getActiveTeam()) {
|
||||||
|
for (int skillId: entity.getAvatar().getProudSkillList()) {
|
||||||
|
if (glidingCostReduction.containsKey(skillId)) {
|
||||||
|
reduction = glidingCostReduction.get(skillId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
consumption.amount *= reduction;
|
||||||
|
|
||||||
|
// POWERED_FLY, e.g. wind tunnel
|
||||||
|
if (currentState == MotionState.MOTION_POWERED_FLY) {
|
||||||
|
consumption = new Consumption(ConsumptionType.POWERED_FLY);
|
||||||
|
}
|
||||||
|
return consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumption getStandConsumption() {
|
||||||
|
Consumption consumption = new Consumption(ConsumptionType.None);
|
||||||
|
if (currentState == MotionState.MOTION_STANDBY) {
|
||||||
|
consumption = new Consumption(ConsumptionType.STANDBY);
|
||||||
|
}
|
||||||
|
if (currentState == MotionState.MOTION_STANDBY_MOVE) {
|
||||||
|
consumption = new Consumption(ConsumptionType.STANDBY_MOVE);
|
||||||
|
}
|
||||||
|
return consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumption getFightConsumption() {
|
||||||
|
Consumption consumption = new Consumption(ConsumptionType.None);
|
||||||
|
HashMap<Integer, Integer> fightingCost = new HashMap<>() {{
|
||||||
|
put(10013, -1000); // Kamisato Ayaka
|
||||||
|
put(10413, -1000); // Mona
|
||||||
|
}};
|
||||||
|
if (fightingCost.containsKey(skillCasting)) {
|
||||||
|
consumption = new Consumption(ConsumptionType.FIGHT, fightingCost.get(skillCasting));
|
||||||
|
// only handle once, so reset.
|
||||||
|
skillCasting = 0;
|
||||||
|
skillCaster = 0;
|
||||||
|
}
|
||||||
|
return consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifySkill(int caster, int skillId) {
|
||||||
|
skillCaster = caster;
|
||||||
|
skillCasting = skillId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1151,8 +1151,11 @@ public class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLogout() {
|
public void onLogout() {
|
||||||
|
// stop stamina calculation
|
||||||
|
getMovementManager().resetTimer();
|
||||||
|
|
||||||
// force to leave the dungeon
|
// force to leave the dungeon
|
||||||
if(getScene().getSceneType() == SceneType.SCENE_DUNGEON){
|
if (getScene().getSceneType() == SceneType.SCENE_DUNGEON) {
|
||||||
this.getServer().getDungeonManager().exitDungeon(this);
|
this.getServer().getDungeonManager().exitDungeon(this);
|
||||||
}
|
}
|
||||||
// Leave world
|
// Leave world
|
||||||
|
@ -16,11 +16,9 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
|||||||
// TODO: Will be used for deducting stamina for charged skills.
|
// TODO: Will be used for deducting stamina for charged skills.
|
||||||
|
|
||||||
int caster = notify.getCasterId();
|
int caster = notify.getCasterId();
|
||||||
int skill = notify.getSkillId();
|
int skillId = notify.getSkillId();
|
||||||
|
|
||||||
// Grasscutter.getLogger().warn(caster + "\t" + skill);
|
session.getPlayer().getMovementManager().notifySkill(caster, skillId);
|
||||||
|
|
||||||
// session.getPlayer().getScene().broadcastPacket(new PacketEvtAvatarStandUpNotify(notify));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,25 +64,26 @@ public final class Tools {
|
|||||||
if (availableLangList.size() == 1) {
|
if (availableLangList.size() == 1) {
|
||||||
return availableLangList.get(0).toUpperCase();
|
return availableLangList.get(0).toUpperCase();
|
||||||
}
|
}
|
||||||
System.out.println("The following languages mappings are available, please select one: [default: EN]");
|
String stagedMessage = "";
|
||||||
String groupedLangList = "> ";
|
stagedMessage += "The following languages mappings are available, please select one: [default: EN]\n";
|
||||||
|
String groupedLangList = ">\t";
|
||||||
int groupedLangCount = 0;
|
int groupedLangCount = 0;
|
||||||
String input = "";
|
String input = "";
|
||||||
for (String availableLanguage: availableLangList){
|
for (String availableLanguage: availableLangList){
|
||||||
groupedLangCount++;
|
groupedLangCount++;
|
||||||
groupedLangList = groupedLangList + "" + availableLanguage + "\t";
|
groupedLangList = groupedLangList + "" + availableLanguage + "\t";
|
||||||
if (groupedLangCount == 6) {
|
if (groupedLangCount == 6) {
|
||||||
System.out.println(groupedLangList);
|
stagedMessage += groupedLangList + "\n";
|
||||||
groupedLangCount = 0;
|
groupedLangCount = 0;
|
||||||
groupedLangList = "> ";
|
groupedLangList = ">\t";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (groupedLangCount > 0) {
|
if (groupedLangCount > 0) {
|
||||||
System.out.println(groupedLangList);
|
stagedMessage += groupedLangList + "\n";
|
||||||
}
|
}
|
||||||
System.out.print("\nYour choice:[EN] ");
|
stagedMessage += "\nYour choice:[EN] ";
|
||||||
|
|
||||||
input = new BufferedReader(new InputStreamReader(System.in)).readLine();
|
input = Grasscutter.getConsole().readLine(stagedMessage);
|
||||||
if (availableLangList.contains(input.toLowerCase())) {
|
if (availableLangList.contains(input.toLowerCase())) {
|
||||||
return input.toUpperCase();
|
return input.toUpperCase();
|
||||||
}
|
}
|
||||||
@ -249,6 +250,6 @@ final class ToolsWithLanguageOption {
|
|||||||
writer.println("}\n}");
|
writer.println("}\n}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grasscutter.getLogger().info("Mappings generated!");
|
Grasscutter.getLogger().info("Mappings generated to " + location + " !");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
298
src/main/resources/languages/zh-CN.json
Normal file
298
src/main/resources/languages/zh-CN.json
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
{
|
||||||
|
"messages": {
|
||||||
|
"game": {
|
||||||
|
"port_bind": "游戏服务器已在端口 %s 上启动",
|
||||||
|
"connect": "客户端已连接至 %s",
|
||||||
|
"disconnect": "客户端 %s 已断开连接",
|
||||||
|
"game_update_error": "游戏更新时发生错误",
|
||||||
|
"command_error": "命令发生错误:"
|
||||||
|
},
|
||||||
|
"dispatch": {
|
||||||
|
"port_bind": "[Dispatch] 服务器已在端口 %s 上启动",
|
||||||
|
"request": "[Dispatch] 客户端 %s 请求: %s %s",
|
||||||
|
"keystore": {
|
||||||
|
"general_error": "[Dispatch] 加载 keystore 文件时发生错误!",
|
||||||
|
"password_error": "[Dispatch] 加载 keystore 失败。正在尝试使用预设的 keystore 密码...",
|
||||||
|
"no_keystore_error": "[Dispatch] 未找到 SSL 证书!已降级到 HTTP 服务器",
|
||||||
|
"default_password": "[Dispatch] 默认的 keystore 密码加载成功。请考虑将 config.json 的默认密码设置为 123456"
|
||||||
|
},
|
||||||
|
"no_commands_error": "此命令不适用于 Dispatch-only 模式",
|
||||||
|
"unhandled_request_error": "[Dispatch] 潜在的未处理请求 %s 请求:%s",
|
||||||
|
"account": {
|
||||||
|
"login_attempt": "[Dispatch] 客户端 %s 正在尝试登录",
|
||||||
|
"login_success": "[Dispatch] 客户端 %s 已登录,UID为 %s",
|
||||||
|
"login_token_attempt": "[Dispatch] 客户端 %s 正在尝试使用令牌登录",
|
||||||
|
"login_token_error": "[Dispatch] 客户端 %s 使用令牌登录失败",
|
||||||
|
"login_token_success": "[Dispatch] 客户端 %s 已通过令牌登录,UID为 %s",
|
||||||
|
"combo_token_success": "[Dispatch] 客户端 %s 交换令牌成功",
|
||||||
|
"combo_token_error": "[Dispatch] 客户端 %s 交换令牌失败",
|
||||||
|
"account_login_create_success": "[Dispatch] 客户端 %s 登录失败: 已注册UID为 %s 的账号",
|
||||||
|
"account_login_create_error": "[Dispatch] 客户端 %s 登录失败:账号创建失败。",
|
||||||
|
"account_login_exist_error": "[Dispatch] 客户端 %s 登录失败:账号不存在",
|
||||||
|
"account_cache_error": "游戏账号缓存信息错误",
|
||||||
|
"session_key_error": "交换秘钥不符。",
|
||||||
|
"username_error": "未找到此用户名。",
|
||||||
|
"username_create_error": "未找到用户名,建立连接失败。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"free_software": "Grasscutter 是免费开源软件。如果你是付费购买的,那已经被骗了。Github:https://github.com/Grasscutters/Grasscutter",
|
||||||
|
"starting": "正在启动 Grasscutter...",
|
||||||
|
"shutdown": "正在关闭...",
|
||||||
|
"done": "加載完成!输入 \"help\" 查看命令列表",
|
||||||
|
"error": "发生了一个错误。",
|
||||||
|
"welcome": "欢迎使用 Grasscutter",
|
||||||
|
"run_mode_error": "无效的服务器运行模式: %s。",
|
||||||
|
"run_mode_help": "服务器运行模式必须为 HYBRID、DISPATCH_ONLY 或 GAME_ONLY。Grasscutter 启动失败...",
|
||||||
|
"create_resources": "正在创建 resources 目录...",
|
||||||
|
"resources_error": "请将 BinOutput 和 ExcelBinOutput 复制到 resources 目录。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"commands": {
|
||||||
|
"generic": {
|
||||||
|
"not_specified": "没有指定命令。",
|
||||||
|
"unknown_command": "未知的命令:%s",
|
||||||
|
"permission_error": "您没有执行此命令的权限。",
|
||||||
|
"console_execute_error": "此命令只能在服务器控制台执行。",
|
||||||
|
"player_execute_error": "此命令只能在游戏内执行。",
|
||||||
|
"command_exist_error": "找不到命令。",
|
||||||
|
"invalid": {
|
||||||
|
"amount": "无效的 数量.",
|
||||||
|
"artifactId": "无效的圣遗物ID。",
|
||||||
|
"avatarId": "无效的角色ID。",
|
||||||
|
"avatarLevel": "无效的角色等級。",
|
||||||
|
"entityId": "无效的实体ID。",
|
||||||
|
"itemId": "无效的物品ID。",
|
||||||
|
"itemLevel": "无效的物品等級。",
|
||||||
|
"itemRefinement": "无效的物品精炼等级。",
|
||||||
|
"playerId": "无效的玩家ID。",
|
||||||
|
"uid": "无效的UID。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"execution": {
|
||||||
|
"uid_error": "无效的UID。",
|
||||||
|
"player_exist_error": "用户不存在。",
|
||||||
|
"player_offline_error": "玩家已离线。",
|
||||||
|
"item_id_error": "无效的物品ID。.",
|
||||||
|
"item_player_exist_error": "无效的物品/玩家UID。",
|
||||||
|
"entity_id_error": "无效的实体ID。",
|
||||||
|
"player_exist_offline_error": "玩家不存在或已离线。",
|
||||||
|
"argument_error": "无效的参数。",
|
||||||
|
"clear_target": "目标已清除.",
|
||||||
|
"set_target": "随后的的命令都会以@%s为预设。",
|
||||||
|
"need_target": "此命令需要一个目标 UID。添加 <@UID> 参数或使用 /target @UID 来设定持久目标。"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"enabled": "已启用",
|
||||||
|
"disabled": "未启用",
|
||||||
|
"help": "帮助",
|
||||||
|
"success": "成功"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"modify": "修改使用者账号",
|
||||||
|
"invalid": "无效的UID。",
|
||||||
|
"exists": "账号已存在。",
|
||||||
|
"create": "已建立账号,UID 为 %s 。",
|
||||||
|
"delete": "账号已刪除。",
|
||||||
|
"no_account": "账号不存在。",
|
||||||
|
"command_usage": "用法:account <create|delete> <username> [uid]"
|
||||||
|
},
|
||||||
|
"broadcast": {
|
||||||
|
"command_usage": "用法:broadcast <消息>",
|
||||||
|
"message_sent": "公告已发送。"
|
||||||
|
},
|
||||||
|
"changescene": {
|
||||||
|
"usage": "用法:changescene <scene id>",
|
||||||
|
"already_in_scene": "你已经在这个秘境中了。",
|
||||||
|
"success": "已切换至秘境 %s.",
|
||||||
|
"exists_error": "此秘境不存在。"
|
||||||
|
},
|
||||||
|
"clear": {
|
||||||
|
"command_usage": "用法: clear <all|wp|art|mat>",
|
||||||
|
"weapons": "已将 %s 的武器清空。",
|
||||||
|
"artifacts": "已将 %s 的圣遗物清空。",
|
||||||
|
"materials": "已将 %s 的材料清空。",
|
||||||
|
"furniture": "已将 %s 的尘歌壶家具清空。",
|
||||||
|
"displays": "已清除 %s 的显示。",
|
||||||
|
"virtuals": "已将 %s 的所有货币和经验值清空。",
|
||||||
|
"everything": "已将 %s 的所有物品清空。"
|
||||||
|
},
|
||||||
|
"coop": {
|
||||||
|
"usage": "用法:coop <playerId> <target playerId>",
|
||||||
|
"success": "已召唤 %s 到 %s的世界"
|
||||||
|
},
|
||||||
|
"enter_dungeon": {
|
||||||
|
"usage": "用法:enterdungeon <dungeon id>",
|
||||||
|
"changed": "已进入秘境 %s",
|
||||||
|
"not_found_error": "此秘境不存在。",
|
||||||
|
"in_dungeon_error": "你已经在秘境中了。"
|
||||||
|
},
|
||||||
|
"giveAll": {
|
||||||
|
"usage": "用法:giveall [player] [amount]",
|
||||||
|
"started": "正在给予全部物品...",
|
||||||
|
"success": "已给予全部物品。",
|
||||||
|
"invalid_amount_or_playerId": "无效的数量/玩家ID。"
|
||||||
|
},
|
||||||
|
"giveArtifact": {
|
||||||
|
"usage": "用法:giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]",
|
||||||
|
"id_error": "无效的圣遗物ID。",
|
||||||
|
"success": "已将 %s 给予 %s。"
|
||||||
|
},
|
||||||
|
"giveChar": {
|
||||||
|
"usage": "用法:givechar <player> <itemId|itemName> [amount]",
|
||||||
|
"given": "Given %s with level %s to %s.",
|
||||||
|
"invalid_avatar_id": "无效的角色ID。",
|
||||||
|
"invalid_avatar_level": "无效的角色等級。.",
|
||||||
|
"invalid_avatar_or_player_id": "无效的角色ID/玩家ID。"
|
||||||
|
},
|
||||||
|
"give": {
|
||||||
|
"usage": "用法:give <player> <itemId|itemName> [amount] [level] [refinement]",
|
||||||
|
"refinement_only_applicable_weapons": "精炼等级参数仅在武器上可用",
|
||||||
|
"refinement_must_between_1_and_5": "精炼等级必须在 1 到 5 之间。",
|
||||||
|
"given": "已将 %s 个 %s 给予 %s。",
|
||||||
|
"given_with_level_and_refinement": "已将 %s [等級%s, 精炼%s] %s个给予 %s",
|
||||||
|
"given_level": "已将 %s 等级 %s %s 个给予 %s"
|
||||||
|
},
|
||||||
|
"godmode": {
|
||||||
|
"success": "上帝模式被设置为 %s 。 [用户:%s]"
|
||||||
|
},
|
||||||
|
"heal": {
|
||||||
|
"success": "所有角色已被治疗。"
|
||||||
|
},
|
||||||
|
"kick": {
|
||||||
|
"player_kick_player": "玩家 [%s:%s] 已将 [%s:%s] 踢出",
|
||||||
|
"server_kick_player": "正在踢出玩家 [%s:%s]"
|
||||||
|
},
|
||||||
|
"kill": {
|
||||||
|
"usage": "用法:killall [playerUid] [sceneId]",
|
||||||
|
"scene_not_found_in_player_world": "未在玩家世界中找到此场景",
|
||||||
|
"kill_monsters_in_scene": "已杀死 %s 个怪物。 [场景ID: %s]"
|
||||||
|
},
|
||||||
|
"killCharacter": {
|
||||||
|
"usage": "用法:/killcharacter [playerId]",
|
||||||
|
"success": "已杀死 %s 目前使用的角色。"
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"message": "目前在线人数:%s"
|
||||||
|
},
|
||||||
|
"permission": {
|
||||||
|
"usage": "用法:permission <add|remove> <username> <permission>",
|
||||||
|
"add": "已设置权限。",
|
||||||
|
"has_error": "此玩家已拥有此权限!",
|
||||||
|
"remove": "权限已移除。",
|
||||||
|
"not_have_error": "此玩家未拥有权限!",
|
||||||
|
"account_error": "账号不存在!"
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"success": "坐标:%.3f, %.3f, %.3f\n场景ID:%d"
|
||||||
|
},
|
||||||
|
"reload": {
|
||||||
|
"reload_start": "正在重载配置文件和数据。",
|
||||||
|
"reload_done": "重装完毕。"
|
||||||
|
},
|
||||||
|
"resetConst": {
|
||||||
|
"reset_all": "重置所有角色的命座。",
|
||||||
|
"success": "已重置 %s 的命座,重新登录后将会生效。"
|
||||||
|
},
|
||||||
|
"resetShopLimit": {
|
||||||
|
"usage": "用法:/resetshop <player id>"
|
||||||
|
},
|
||||||
|
"sendMail": {
|
||||||
|
"usage": "用法:give [player] <itemId|itemName> [amount]",
|
||||||
|
"user_not_exist": "ID '%s' 的使用者不存在。",
|
||||||
|
"start_composition": "发送邮件流程。\n请使用`/send <标题>`前进到下一步。\n你可以在任何时间使用`/sendmail stop`来停止发送。",
|
||||||
|
"templates": "邮件模板尚未实装...",
|
||||||
|
"invalid_arguments": "无效的参数。\n指令使用方法 `/sendmail <userId|all|help> [templateId]`",
|
||||||
|
"send_cancel": "取消发送邮件",
|
||||||
|
"send_done": "已将邮件给 %s!",
|
||||||
|
"send_all_done": "邮件已发送给所有人!",
|
||||||
|
"not_composition_end": "现在邮件发送未到最后阶段。\n请使用 `/sendmail %s` 继续发送邮件,或使用 `/sendmail stop` 来停止发送邮件。",
|
||||||
|
"please_use": "请使用 `/sendmail %s`",
|
||||||
|
"set_title": "成功将邮件标题设置为 '%s'。\n使用 '/sendmail <content>' 来设置邮件内容。",
|
||||||
|
"set_contents": "成功将'%s'设置为邮件内容。\n使用 '/sendmail <发件人>' 来设置发件人。",
|
||||||
|
"set_message_sender": "发件人已设置为 '%s'。\n使用 '/sendmail <itemId|itemName|finish> [amount] [level]' 来添加附件。",
|
||||||
|
"send": "已添加 %s 个 %s (等級为 %s) 邮件附件。\n如果没有要继续添加的道具请使用 `/sendmail finish` 来完成邮件发送。",
|
||||||
|
"invalid_arguments_please_use": "错误的参数 \n请使用 `/sendmail %s`",
|
||||||
|
"title": "<标题>",
|
||||||
|
"message": "<正文>",
|
||||||
|
"sender": "<发件人>",
|
||||||
|
"arguments": "<itemId|itemName|finish> [数量] [等级]",
|
||||||
|
"error": "错误:无效的编写阶段 %s。需要 StackTrace 请查看服务器控制台。"
|
||||||
|
},
|
||||||
|
"sendMessage": {
|
||||||
|
"usage": "用法:sendmessage <player> <message>",
|
||||||
|
"success": "消息已发送。"
|
||||||
|
},
|
||||||
|
"setFetterLevel": {
|
||||||
|
"usage": "用法:setfetterlevel <level>",
|
||||||
|
"range_error": "好感度等级必须在 0 到 10 之间。",
|
||||||
|
"fetter_set_level": "好感度已设置为 %s 级",
|
||||||
|
"level_error": "无效的好感度等级。"
|
||||||
|
},
|
||||||
|
"setStats": {
|
||||||
|
"usage_console": "用法:setstats|stats @<UID> <stat> <value>",
|
||||||
|
"usage_ingame": "用法:setstats|stats [@UID] <stat> <value>",
|
||||||
|
"help_message": "\n\t可使用的数据类型:hp (生命值)| maxhp (最大生命值) | def(防御力) | atk (攻击力)| em (元素精通) | er (元素充能效率) | crate(暴击率) | cdmg (暴击伤害)| cdr (冷却缩减) | heal(治疗加成)| heali (受治疗加成)| shield (护盾强效)| defi (无视防御)\n\t(cont.) 元素伤害:epyro (火) | ecryo (冰) | ehydro (水) | egeo (岩) | edendro (草) | eelectro (雷) | ephys (物理)(cont.) 元素抗性:respyro (火) | rescryo (冰) | reshydro (水) | resgeo (岩) | resdendro (草) | reselectro (雷) | resphys (物理)\n",
|
||||||
|
"value_error": "无效的数据值。",
|
||||||
|
"uid_error": "无效的UID。",
|
||||||
|
"player_error": "玩家不存在或已离线。",
|
||||||
|
"set_self": "%s 已经设置为 %s。",
|
||||||
|
"set_for_uid": "%s 的使用者 %s 更改为 %s。",
|
||||||
|
"set_max_hp": "最大生命值更改为 %s。"
|
||||||
|
},
|
||||||
|
"setWorldLevel": {
|
||||||
|
"usage": "用法:setworldlevel <level>",
|
||||||
|
"value_error": "世界等级必须设置在0-8之间。",
|
||||||
|
"success": "已将世界等级设为%s。",
|
||||||
|
"invalid_world_level": "无效的世界等级。"
|
||||||
|
},
|
||||||
|
"spawn": {
|
||||||
|
"usage": "用法:spawn <entityId> [amount] [level(仅限怪物]",
|
||||||
|
"success": "已生成 %s 个 %s。"
|
||||||
|
},
|
||||||
|
"stop": {
|
||||||
|
"success": "正在关闭服务器..."
|
||||||
|
},
|
||||||
|
"talent": {
|
||||||
|
"usage_1": "设置天赋等级:/talent set <talentID> <value>",
|
||||||
|
"usage_2": "另一种设置天赋等级的命令使用方法:/talent <n or e or q> <value>",
|
||||||
|
"usage_3": "获取天赋ID指令用法:/talent getid",
|
||||||
|
"lower_16": "无效的天赋等级,天赋等级应低于16。",
|
||||||
|
"set_id": "将天赋等级设为 %s。",
|
||||||
|
"set_atk": "将普通攻击等级设为 %s。",
|
||||||
|
"set_e": "设定天赋E等级为 %s。",
|
||||||
|
"set_q": "设定天赋Q等级为 %s。",
|
||||||
|
"invalid_skill_id": "无效的技能ID。",
|
||||||
|
"set_this": "将天赋等级设为 %s。",
|
||||||
|
"invalid_level": "无效的天赋等级。",
|
||||||
|
"normal_attack_id": "普通攻击的 ID 为 %s。",
|
||||||
|
"e_skill_id": "E技能ID %s。",
|
||||||
|
"q_skill_id": "Q技能ID %s。"
|
||||||
|
},
|
||||||
|
"teleportAll": {
|
||||||
|
"success": "已将全部玩家传送到你的位置",
|
||||||
|
"error": "命令仅限多人游戏使用。"
|
||||||
|
},
|
||||||
|
"teleport": {
|
||||||
|
"usage_server": "用法:/tp @<player id> <x> <y> <z> [scene id]",
|
||||||
|
"usage": "用法:/tp [@<player id>] <x> <y> <z> [scene id]",
|
||||||
|
"specify_player_id": "你必须指定一个玩家ID。",
|
||||||
|
"invalid_position": "无效的位置。",
|
||||||
|
"success": "传送 %s 到坐标 %s,%s,%s,场景为 %s"
|
||||||
|
},
|
||||||
|
"weather": {
|
||||||
|
"usage": "用法:weather <weatherId> [climateId]",
|
||||||
|
"success": "已将当前天气设定为 %s,气候则为 %s。",
|
||||||
|
"invalid_id": "无效的ID。"
|
||||||
|
},
|
||||||
|
"drop": {
|
||||||
|
"command_usage": "用法:drop <itemId|itemName> [amount]",
|
||||||
|
"success": "已將 %s x %s 丟在附近。"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"usage": "用法:",
|
||||||
|
"aliases": "別名:",
|
||||||
|
"available_commands": "可用指令:"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user