mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-17 09:25:06 +01:00
@@ -77,7 +77,7 @@ public final class Grasscutter {
|
||||
Tools.createGmHandbook(); exitEarly = true;
|
||||
}
|
||||
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<>();
|
||||
|
||||
private enum Consumption {
|
||||
private enum ConsumptionType {
|
||||
None(0),
|
||||
|
||||
// consume
|
||||
@@ -37,6 +37,7 @@ public class MovementManager {
|
||||
SWIM_DASH_START(-200),
|
||||
SWIM_DASH(-200),
|
||||
SWIMMING(-80),
|
||||
FIGHT(0),
|
||||
|
||||
// restore
|
||||
STANDBY(500),
|
||||
@@ -46,11 +47,22 @@ public class MovementManager {
|
||||
POWERED_FLY(500);
|
||||
|
||||
public final int amount;
|
||||
Consumption(int amount) {
|
||||
ConsumptionType(int 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 currentState = MotionState.MOTION_STANDBY;
|
||||
@@ -64,8 +76,9 @@ public class MovementManager {
|
||||
private Timer movementManagerTickTimer;
|
||||
private GameSession cachedSession = null;
|
||||
private GameEntity cachedEntity = null;
|
||||
|
||||
private int staminaRecoverDelay = 0;
|
||||
private int skillCaster = 0;
|
||||
private int skillCasting = 0;
|
||||
|
||||
public MovementManager(Player player) {
|
||||
previousCoordinates.add(new Position(0,0,0));
|
||||
@@ -114,6 +127,12 @@ public class MovementManager {
|
||||
MotionState.MOTION_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) {
|
||||
@@ -134,11 +153,12 @@ public class MovementManager {
|
||||
currentCoordinates = newPos;
|
||||
}
|
||||
currentState = motionInfo.getState();
|
||||
Grasscutter.getLogger().debug("" + currentState);
|
||||
Grasscutter.getLogger().debug("" + currentState + "\t" + (moveInfo.getIsReliable() ? "reliable" : ""));
|
||||
handleFallOnGround(motionInfo);
|
||||
}
|
||||
|
||||
public void resetTimer() {
|
||||
Grasscutter.getLogger().debug("MovementManager ticker stopped");
|
||||
movementManagerTickTimer.cancel();
|
||||
movementManagerTickTimer = null;
|
||||
}
|
||||
@@ -167,8 +187,6 @@ public class MovementManager {
|
||||
return player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Returns new stamina
|
||||
public int updateStamina(GameSession session, int amount) {
|
||||
int currentStamina = session.getPlayer().getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
|
||||
@@ -184,6 +202,7 @@ public class MovementManager {
|
||||
newStamina = playerMaxStamina;
|
||||
}
|
||||
session.getPlayer().setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
||||
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||
return newStamina;
|
||||
}
|
||||
|
||||
@@ -269,95 +288,40 @@ public class MovementManager {
|
||||
boolean moving = isPlayerMoving();
|
||||
if (moving || (getCurrentStamina() < getMaximumStamina())) {
|
||||
// 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.
|
||||
if (MotionStatesCategorized.get("CLIMB").contains(currentState)) {
|
||||
if (currentState == MotionState.MOTION_CLIMB) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
consumption = getClimbConsumption();
|
||||
} else if (MotionStatesCategorized.get("SWIM").contains((currentState))) {
|
||||
// SWIM
|
||||
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;
|
||||
}
|
||||
}
|
||||
consumption = getSwimConsumptions();
|
||||
} else if (MotionStatesCategorized.get("RUN").contains(currentState)) {
|
||||
// RUN, DASH and WALK
|
||||
// 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;
|
||||
}
|
||||
consumption = getRunWalkDashConsumption();
|
||||
} else if (MotionStatesCategorized.get("FLY").contains(currentState)) {
|
||||
// FLY
|
||||
consumption = Consumption.FLY;
|
||||
// POWERED_FLY, e.g. wind tunnel
|
||||
if (currentState == MotionState.MOTION_POWERED_FLY) {
|
||||
consumption = Consumption.POWERED_FLY;
|
||||
}
|
||||
consumption = getFlyConsumption();
|
||||
} else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) {
|
||||
// STAND
|
||||
if (currentState == MotionState.MOTION_STANDBY) {
|
||||
consumption = Consumption.STANDBY;
|
||||
}
|
||||
if (currentState == MotionState.MOTION_STANDBY_MOVE) {
|
||||
consumption = Consumption.STANDBY_MOVE;
|
||||
}
|
||||
consumption = getStandConsumption();
|
||||
} else if (MotionStatesCategorized.get("FIGHT").contains(currentState)) {
|
||||
consumption = getFightConsumption();
|
||||
}
|
||||
|
||||
// tick triggered
|
||||
handleDrowning();
|
||||
|
||||
// delay 2 seconds before start recovering - as official server does.
|
||||
if (cachedSession != null) {
|
||||
if (consumption.amount < 0) {
|
||||
staminaRecoverDelay = 0;
|
||||
}
|
||||
if (consumption.amount > 0) {
|
||||
if (consumption.amount > 0 && consumption.consumptionType != ConsumptionType.POWERED_FLY) {
|
||||
if (staminaRecoverDelay < 10) {
|
||||
staminaRecoverDelay++;
|
||||
consumption = Consumption.None;
|
||||
consumption = new Consumption(ConsumptionType.None);
|
||||
}
|
||||
}
|
||||
int newStamina = updateStamina(cachedSession, consumption.amount);
|
||||
cachedSession.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||
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 + ")");
|
||||
// Grasscutter.getLogger().debug(getCurrentStamina() + "/" + getMaximumStamina() + "\t" + currentState + "\t" + "isMoving: " + isPlayerMoving() + "\t(" + consumption.consumptionType + "," + consumption.amount + ")");
|
||||
updateStamina(cachedSession, consumption.amount);
|
||||
}
|
||||
|
||||
// tick triggered
|
||||
handleDrowning();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,4 +330,113 @@ public class MovementManager {
|
||||
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() {
|
||||
// stop stamina calculation
|
||||
getMovementManager().resetTimer();
|
||||
|
||||
// force to leave the dungeon
|
||||
if(getScene().getSceneType() == SceneType.SCENE_DUNGEON){
|
||||
if (getScene().getSceneType() == SceneType.SCENE_DUNGEON) {
|
||||
this.getServer().getDungeonManager().exitDungeon(this);
|
||||
}
|
||||
// Leave world
|
||||
|
||||
@@ -16,11 +16,9 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
||||
// TODO: Will be used for deducting stamina for charged skills.
|
||||
|
||||
int caster = notify.getCasterId();
|
||||
int skill = notify.getSkillId();
|
||||
int skillId = notify.getSkillId();
|
||||
|
||||
// Grasscutter.getLogger().warn(caster + "\t" + skill);
|
||||
|
||||
// session.getPlayer().getScene().broadcastPacket(new PacketEvtAvatarStandUpNotify(notify));
|
||||
session.getPlayer().getMovementManager().notifySkill(caster, skillId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,25 +64,26 @@ public final class Tools {
|
||||
if (availableLangList.size() == 1) {
|
||||
return availableLangList.get(0).toUpperCase();
|
||||
}
|
||||
System.out.println("The following languages mappings are available, please select one: [default: EN]");
|
||||
String groupedLangList = "> ";
|
||||
String stagedMessage = "";
|
||||
stagedMessage += "The following languages mappings are available, please select one: [default: EN]\n";
|
||||
String groupedLangList = ">\t";
|
||||
int groupedLangCount = 0;
|
||||
String input = "";
|
||||
for (String availableLanguage: availableLangList){
|
||||
groupedLangCount++;
|
||||
groupedLangList = groupedLangList + "" + availableLanguage + "\t";
|
||||
if (groupedLangCount == 6) {
|
||||
System.out.println(groupedLangList);
|
||||
stagedMessage += groupedLangList + "\n";
|
||||
groupedLangCount = 0;
|
||||
groupedLangList = "> ";
|
||||
groupedLangList = ">\t";
|
||||
}
|
||||
}
|
||||
if (groupedLangCount > 0) {
|
||||
System.out.println(groupedLangList);
|
||||
stagedMessage += groupedLangList + "\n";
|
||||
}
|
||||
System.out.print("\nYour choice:[EN] ");
|
||||
|
||||
input = new BufferedReader(new InputStreamReader(System.in)).readLine();
|
||||
stagedMessage += "\nYour choice:[EN] ";
|
||||
|
||||
input = Grasscutter.getConsole().readLine(stagedMessage);
|
||||
if (availableLangList.contains(input.toLowerCase())) {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
@@ -249,6 +250,6 @@ final class ToolsWithLanguageOption {
|
||||
writer.println("}\n}");
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info("Mappings generated!");
|
||||
Grasscutter.getLogger().info("Mappings generated to " + location + " !");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user