diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 12f37b0fa..d05939c05 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -70,12 +70,20 @@ public final class Grasscutter { Crypto.loadKeys(); // Load keys from buffers. // Parse arguments. + boolean exitEarly = false; for (String arg : args) { switch (arg.toLowerCase()) { - case "-handbook" -> Tools.createGmHandbook(); - case "-gachamap" -> Tools.createGachaMapping("./gacha-mapping.js"); + case "-handbook" -> { + Tools.createGmHandbook(); exitEarly = true; + } + case "-gachamap" -> { + Tools.createGachaMapping("./gacha-mapping.js"); exitEarly = true; + } } - } + } + + // Exit early if argument sets it. + if(exitEarly) System.exit(0); // Initialize server. Grasscutter.getLogger().info(translate("messages.status.starting")); @@ -88,14 +96,13 @@ public final class Grasscutter { // Database DatabaseManager.initialize(); - // Create plugin manager instance. - pluginManager = new PluginManager(); - // Create server instances. dispatchServer = new DispatchServer(); gameServer = new GameServer(); // Create a server hook instance with both servers. new ServerHook(gameServer, dispatchServer); + // Create plugin manager instance. + pluginManager = new PluginManager(); // Start servers. if (getConfig().RunMode == ServerRunMode.HYBRID) { diff --git a/src/main/java/emu/grasscutter/game/managers/MovementManager/MovementManager.java b/src/main/java/emu/grasscutter/game/managers/MovementManager/MovementManager.java index ed1645936..18958f355 100644 --- a/src/main/java/emu/grasscutter/game/managers/MovementManager/MovementManager.java +++ b/src/main/java/emu/grasscutter/game/managers/MovementManager/MovementManager.java @@ -268,7 +268,7 @@ public class MovementManager { if (Grasscutter.getConfig().OpenStamina) { boolean moving = isPlayerMoving(); 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; // TODO: refactor these conditions. @@ -306,14 +306,16 @@ public class MovementManager { } else if (MotionStatesCategorized.get("RUN").contains(currentState)) { // RUN, DASH and WALK // DASH - if (currentState == MotionState.MOTION_DASH) { - if (previousState == MotionState.MOTION_DASH) { + if (currentState == MotionState.MOTION_DASH_BEFORE_SHAKE) { + consumption = Consumption.DASH; + if (previousState == MotionState.MOTION_DASH_BEFORE_SHAKE) { + // only charge once consumption = Consumption.SPRINT; - } else { - // cost more to start dashing - consumption = Consumption.DASH; } } + if (currentState == MotionState.MOTION_DASH) { + consumption = Consumption.SPRINT; + } // RUN if (currentState == MotionState.MOTION_RUN) { consumption = Consumption.RUN; @@ -347,14 +349,13 @@ public class MovementManager { staminaRecoverDelay = 0; } if (consumption.amount > 0) { - if (staminaRecoverDelay < 5) { + if (staminaRecoverDelay < 10) { staminaRecoverDelay++; consumption = Consumption.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 + ")"); } } diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 9cb2553b1..7ce8488ef 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -29,6 +29,9 @@ import java.net.InetSocketAddress; import java.time.OffsetDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import static emu.grasscutter.utils.Language.translate; @@ -79,19 +82,6 @@ public final class GameServer extends KcpServer { this.dropManager = new DropManager(this); this.expeditionManager = new ExpeditionManager(this); this.combineManger = new CombineManger(this); - - // Schedule game loop. - Timer gameLoop = new Timer(); - gameLoop.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - try { - onTick(); - } catch (Exception e) { - Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e); - } - } - }, new Date(), 1000L); // Hook into shutdown event. Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown)); @@ -229,6 +219,24 @@ public final class GameServer extends KcpServer { } + @Override + public synchronized void start() { + // Schedule game loop. + Timer gameLoop = new Timer(); + gameLoop.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + onTick(); + } catch (Exception e) { + Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e); + } + } + }, new Date(), 1000L); + + super.start(); + } + @Override public void onStartFinish() { Grasscutter.getLogger().info(translate("messages.status.free_software")); diff --git a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java index 35303b639..88e7fa17f 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java +++ b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java @@ -14,6 +14,7 @@ import emu.grasscutter.server.game.GameSession.SessionState; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +@SuppressWarnings("unchecked") public class GameServerPacketHandler { private final Int2ObjectMap handlers; diff --git a/src/main/java/emu/grasscutter/tools/Tools.java b/src/main/java/emu/grasscutter/tools/Tools.java index 59c264b2b..475649b1f 100644 --- a/src/main/java/emu/grasscutter/tools/Tools.java +++ b/src/main/java/emu/grasscutter/tools/Tools.java @@ -93,7 +93,6 @@ public final class Tools { } Grasscutter.getLogger().info("GM Handbook generated!"); - System.exit(0); } @SuppressWarnings("deprecation") @@ -183,6 +182,5 @@ public final class Tools { } Grasscutter.getLogger().info("Mappings generated!"); - System.exit(0); } } diff --git a/src/main/java/emu/grasscutter/utils/Language.java b/src/main/java/emu/grasscutter/utils/Language.java index c4af257e8..ec56b41d9 100644 --- a/src/main/java/emu/grasscutter/utils/Language.java +++ b/src/main/java/emu/grasscutter/utils/Language.java @@ -40,7 +40,7 @@ public final class Language { @Nullable JsonObject languageData = null; try { - InputStream file = Grasscutter.class.getResourceAsStream("/lang/" + fileName); + InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName); languageData = Grasscutter.getGsonFactory().fromJson(Utils.readFromInputStream(file), JsonObject.class); } catch (Exception exception) { Grasscutter.getLogger().error("Failed to load language file: " + fileName, exception); diff --git a/src/main/java/emu/grasscutter/utils/Utils.java b/src/main/java/emu/grasscutter/utils/Utils.java index 268cc6f40..a72815f58 100644 --- a/src/main/java/emu/grasscutter/utils/Utils.java +++ b/src/main/java/emu/grasscutter/utils/Utils.java @@ -5,6 +5,8 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.time.*; import java.time.temporal.TemporalAdjusters; +import java.util.HashMap; +import java.util.Map; import java.util.Random; import emu.grasscutter.Config; @@ -260,4 +262,41 @@ public final class Utils { Grasscutter.getLogger().warn("Failed to read from input stream."); } return stringBuilder.toString(); } + + /** + * Switch properties from upper case to lower case? + */ + public static Map switchPropertiesUpperLowerCase(Map objMap, Class cls) { + Map map = new HashMap<>(objMap.size()); + for (String key : objMap.keySet()) { + try { + char c = key.charAt(0); + if (c >= 'a' && c <= 'z') { + try { + cls.getDeclaredField(key); + map.put(key, objMap.get(key)); + } catch (NoSuchFieldException e) { + String s1 = String.valueOf(c).toUpperCase(); + String after = key.length() > 1 ? s1 + key.substring(1) : s1; + cls.getDeclaredField(after); + map.put(after, objMap.get(key)); + } + } else if (c >= 'A' && c <= 'Z') { + try { + cls.getDeclaredField(key); + map.put(key, objMap.get(key)); + } catch (NoSuchFieldException e) { + String s1 = String.valueOf(c).toLowerCase(); + String after = key.length() > 1 ? s1 + key.substring(1) : s1; + cls.getDeclaredField(after); + map.put(after, objMap.get(key)); + } + } + } catch (NoSuchFieldException e) { + map.put(key, objMap.get(key)); + } + } + + return map; + } }