From c79ca3028f7dd80cf14a192c6b2680a127444895 Mon Sep 17 00:00:00 2001 From: akatatsu27 <43857160+akatatsu27@users.noreply.github.com> Date: Fri, 8 Jul 2022 20:31:29 +0300 Subject: [PATCH] Added more server debug options (#1444) Original commits: * Added more server debug options * made server debug code prettier * fixed initialization bug * Enables logging of packets contained in UnionCmdNotify, when debug level is WHITELIST or BLACKLIST --- .../java/emu/grasscutter/Grasscutter.java | 4 +- .../grasscutter/server/game/GameSession.java | 60 ++++++++++++------- .../packet/recv/HandlerUnionCmdNotify.java | 18 +++++- .../grasscutter/utils/ConfigContainer.java | 21 ++++--- 4 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 45b234f6e..881a1d2ac 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -4,6 +4,8 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + +import emu.grasscutter.Grasscutter.ServerDebugMode; import emu.grasscutter.auth.AuthenticationSystem; import emu.grasscutter.auth.DefaultAuthentication; import emu.grasscutter.command.CommandMap; @@ -412,6 +414,6 @@ public final class Grasscutter { } public enum ServerDebugMode { - ALL, MISSING, NONE + ALL, MISSING, WHITELIST, BLACKLIST, NONE } } diff --git a/src/main/java/emu/grasscutter/server/game/GameSession.java b/src/main/java/emu/grasscutter/server/game/GameSession.java index fdec9d2ca..e2d726941 100644 --- a/src/main/java/emu/grasscutter/server/game/GameSession.java +++ b/src/main/java/emu/grasscutter/server/game/GameSession.java @@ -26,10 +26,10 @@ public class GameSession implements GameSessionManager.KcpChannel { private Account account; private Player player; - + private boolean useSecretKey; private SessionState state; - + private int clientTime; private long lastPingTime; private int lastClientSeq = 10; @@ -39,11 +39,11 @@ public class GameSession implements GameSessionManager.KcpChannel { this.state = SessionState.WAITING_FOR_TOKEN; this.lastPingTime = System.currentTimeMillis(); } - + public GameServer getServer() { return server; } - + public InetSocketAddress getAddress() { try{ return tunnel.getAddress(); @@ -55,7 +55,7 @@ public class GameSession implements GameSessionManager.KcpChannel { public boolean useSecretKey() { return useSecretKey; } - + public Account getAccount() { return account; } @@ -63,7 +63,7 @@ public class GameSession implements GameSessionManager.KcpChannel { public void setAccount(Account account) { this.account = account; } - + public String getAccountId() { return this.getAccount().getId(); } @@ -93,7 +93,7 @@ public class GameSession implements GameSessionManager.KcpChannel { public void setUseSecretKey(boolean useSecretKey) { this.useSecretKey = useSecretKey; } - + public int getClientTime() { return this.clientTime; } @@ -101,12 +101,12 @@ public class GameSession implements GameSessionManager.KcpChannel { public long getLastPingTime() { return lastPingTime; } - + public void updateLastPingTime(int clientTime) { this.clientTime = clientTime; this.lastPingTime = System.currentTimeMillis(); } - + public int getNextClientSequence() { return ++lastClientSeq; } @@ -114,17 +114,21 @@ public class GameSession implements GameSessionManager.KcpChannel { public void replayPacket(int opcode, String name) { String filePath = PACKET(name); File p = new File(filePath); - + if (!p.exists()) return; byte[] packet = FileUtils.read(p); - + BasePacket basePacket = new BasePacket(opcode); basePacket.setData(packet); - + send(basePacket); } - + + public void logPacket( String sendOrRecv, int opcode, byte[] payload) { + Grasscutter.getLogger().info(sendOrRecv + ": " + PacketOpcodesUtil.getOpcodeName(opcode) + " (" + opcode + ")"); + System.out.println(Utils.bytesToHex(payload)); + } public void send(BasePacket packet) { // Test if (packet.getOpcode() <= 0) { @@ -137,26 +141,34 @@ public class GameSession implements GameSessionManager.KcpChannel { if(PacketOpcodes.BANNED_PACKETS.contains(packet.getOpcode())) { return; } - + // Header if (packet.shouldBuildHeader()) { packet.buildHeader(this.getNextClientSequence()); } - + // Log if (SERVER.debugLevel == ServerDebugMode.ALL) { if (!loopPacket.contains(packet.getOpcode())) { - Grasscutter.getLogger().info("SEND: " + PacketOpcodesUtil.getOpcodeName(packet.getOpcode()) + " (" + packet.getOpcode() + ")"); - System.out.println(Utils.bytesToHex(packet.getData())); + logPacket("SEND",packet.getOpcode(), packet.getData()); } } + + if (SERVER.debugLevel == ServerDebugMode.WHITELIST && SERVER.DebugWhitelist.contains(packet.getOpcode())) { + logPacket("SEND",packet.getOpcode(), packet.getData()); + } + + if (SERVER.debugLevel == ServerDebugMode.BLACKLIST && !(SERVER.DebugBlacklist.contains(packet.getOpcode()))) { + logPacket("SEND",packet.getOpcode(), packet.getData()); + } + // Invoke event. SendPacketEvent event = new SendPacketEvent(this, packet); event.call(); if(!event.isCanceled()) { // If event is not cancelled, continue. tunnel.writeData(event.getPacket().build()); } } - + private static final Set loopPacket = Set.of( PacketOpcodes.PingReq, PacketOpcodes.PingRsp, @@ -216,10 +228,18 @@ public class GameSession implements GameSessionManager.KcpChannel { // Log packet if (allDebug) { if (!loopPacket.contains(opcode)) { - Grasscutter.getLogger().info("RECV: " + PacketOpcodesUtil.getOpcodeName(opcode) + " (" + opcode + ")"); - System.out.println(Utils.bytesToHex(payload)); + logPacket("RECV",opcode, payload); } } + + if (SERVER.debugLevel == ServerDebugMode.WHITELIST && SERVER.DebugWhitelist.contains(opcode)) { + logPacket("RECV",opcode, payload); + } + + if (SERVER.debugLevel == ServerDebugMode.BLACKLIST && !(SERVER.DebugBlacklist.contains(opcode))) { + logPacket("RECV",opcode, payload); + } + // Handle getServer().getPacketHandler().handle(this, opcode, header, payload); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java index 2468f675f..a86ffb084 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java @@ -1,11 +1,15 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.Grasscutter; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.UnionCmdNotifyOuterClass.UnionCmdNotify; import emu.grasscutter.net.proto.UnionCmdOuterClass.UnionCmd; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.Grasscutter.ServerDebugMode; + +import static emu.grasscutter.Configuration.SERVER; @Opcodes(PacketOpcodes.UnionCmdNotify) public class HandlerUnionCmdNotify extends PacketHandler { @@ -13,13 +17,21 @@ public class HandlerUnionCmdNotify extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { UnionCmdNotify req = UnionCmdNotify.parseFrom(payload); for (UnionCmd cmd : req.getCmdListList()) { - session.getServer().getPacketHandler().handle(session, cmd.getMessageId(), EMPTY_BYTE_ARRAY, cmd.getBody().toByteArray()); + int cmdOpcode = cmd.getMessageId(); + byte[] cmdPayload = cmd.getBody().toByteArray(); + if(Grasscutter.config.server.debugLevel == ServerDebugMode.WHITELIST && SERVER.DebugWhitelist.contains(cmd.getMessageId())) { + session.logPacket("RECV in Union", cmdOpcode, cmdPayload); + } else if (Grasscutter.config.server.debugLevel == ServerDebugMode.BLACKLIST && !SERVER.DebugBlacklist.contains(cmd.getMessageId())) { + session.logPacket("RECV in Union", cmdOpcode, cmdPayload); + } + //debugLevel ALL ignores UnionCmdNotify, so we will also ignore the contained opcodes + session.getServer().getPacketHandler().handle(session, cmd.getMessageId(), EMPTY_BYTE_ARRAY, cmd.getBody().toByteArray()); } - + // Update session.getPlayer().getCombatInvokeHandler().update(session.getPlayer()); session.getPlayer().getAbilityInvokeHandler().update(session.getPlayer()); - + // Handle attack results last while (!session.getPlayer().getAttackResults().isEmpty()) { session.getPlayer().getScene().handleAttack(session.getPlayer().getAttackResults().poll()); diff --git a/src/main/java/emu/grasscutter/utils/ConfigContainer.java b/src/main/java/emu/grasscutter/utils/ConfigContainer.java index fb2af55e2..8c031c7a6 100644 --- a/src/main/java/emu/grasscutter/utils/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/utils/ConfigContainer.java @@ -5,6 +5,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter.ServerDebugMode; import emu.grasscutter.Grasscutter.ServerRunMode; +import java.util.Set; import java.io.FileReader; import java.lang.reflect.Field; import java.util.Arrays; @@ -21,7 +22,7 @@ public class ConfigContainer { } /** - * Attempts to update the server's existing configuration to the latest + * Attempts to update the server's existing configuration to the latest */ public static void updateConfig() { try { // Check if the server is using a legacy config. @@ -58,7 +59,7 @@ public class ConfigContainer { Grasscutter.getLogger().warn("Failed to inject the updated ", exception); } } - + public Structure folderStructure = new Structure(); public Database databaseInfo = new Database(); public Language language = new Language(); @@ -73,7 +74,7 @@ public class ConfigContainer { public static class Database { public DataStore server = new DataStore(); public DataStore game = new DataStore(); - + public static class DataStore { public String connectionUri = "mongodb://localhost:27017"; public String collection = "grasscutter"; @@ -93,11 +94,13 @@ public class ConfigContainer { public static class Server { public ServerDebugMode debugLevel = ServerDebugMode.NONE; + public Set DebugWhitelist = Set.of(); + public Set DebugBlacklist = Set.of(); public ServerRunMode runMode = ServerRunMode.HYBRID; public HTTP http = new HTTP(); public Game game = new Game(); - + public Dispatch dispatch = new Dispatch(); } @@ -114,7 +117,7 @@ public class ConfigContainer { } /* Server options. */ - + public static class HTTP { public String bindAddress = "0.0.0.0"; /* This is the address used in URLs. */ @@ -123,7 +126,7 @@ public class ConfigContainer { public int bindPort = 443; /* This is the port used in URLs. */ public int accessPort = 0; - + public Encryption encryption = new Encryption(); public Policies policies = new Policies(); public Files files = new Files(); @@ -240,7 +243,7 @@ public class ConfigContainer { public String nickName = "Server"; public String signature = "Welcome to Grasscutter!"; } - + public static class Files { public String indexFile = "./index.html"; public String errorFile = "./404.html"; @@ -250,7 +253,7 @@ public class ConfigContainer { public static class Region { public Region() { } - + public Region( String name, String title, String address, int port @@ -260,7 +263,7 @@ public class ConfigContainer { this.Ip = address; this.Port = port; } - + public String Name = "os_usa"; public String Title = "Grasscutter"; public String Ip = "127.0.0.1";