diff --git a/build.gradle b/build.gradle index 4e1990b..f4d774a 100644 --- a/build.gradle +++ b/build.gradle @@ -76,6 +76,7 @@ dependencies { implementation group: 'it.unimi.dsi', name: 'fastutil-core', version: '8.5.18' implementation group: 'org.reflections', name: 'reflections', version: '0.10.2' + implementation group: 'com.esotericsoftware', name: 'reflectasm', version: '1.11.9' implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1' implementation group: 'us.hebi.quickbuf', name: 'quickbuf-runtime', version: '1.4' diff --git a/src/main/java/emu/nebula/Nebula.java b/src/main/java/emu/nebula/Nebula.java index 82555b8..c5a73a3 100644 --- a/src/main/java/emu/nebula/Nebula.java +++ b/src/main/java/emu/nebula/Nebula.java @@ -14,6 +14,7 @@ import emu.nebula.command.CommandManager; import emu.nebula.data.ResourceLoader; import emu.nebula.database.DatabaseManager; import emu.nebula.game.GameContext; +import emu.nebula.net.PacketHelper; import emu.nebula.server.HttpServer; import emu.nebula.util.Handbook; import emu.nebula.util.JsonUtils; @@ -78,6 +79,8 @@ public class Nebula { if (generateHandbook) { Handbook.generate(); } + // Cache proto methods + PacketHelper.cacheProtos(); } try { diff --git a/src/main/java/emu/nebula/net/GameSession.java b/src/main/java/emu/nebula/net/GameSession.java index 8356bf6..eb83b34 100644 --- a/src/main/java/emu/nebula/net/GameSession.java +++ b/src/main/java/emu/nebula/net/GameSession.java @@ -11,6 +11,7 @@ import emu.nebula.game.GameContext; import emu.nebula.game.account.Account; import emu.nebula.game.account.AccountHelper; import emu.nebula.game.player.Player; +import emu.nebula.proto.Public.MailState; import emu.nebula.util.AeadHelper; import emu.nebula.util.Utils; import lombok.Getter; @@ -143,10 +144,36 @@ public class GameSession { @SneakyThrows public byte[] encodeMsg(int msgId, ProtoMessage proto) { + // Add any extra data + this.addNextPackage(proto); + + // Encode to message like normal return PacketHelper.encodeMsg(msgId, proto); } public byte[] encodeMsg(int msgId) { return PacketHelper.encodeMsg(msgId); } + + private void addNextPackage(ProtoMessage proto) { + // Sanity check and make sure proto has a "nextPackage" field + if (this.getPlayer() == null || !PacketHelper.hasNextPackageMethod(proto)) { + return; + } + + // Update mail state flag + if (this.getPlayer().getMailbox().isNewState()) { + // Clear + this.getPlayer().getMailbox().clearNewState(); + + // Send mail state notify + byte[] nextPackage = PacketHelper.encodeMsg( + NetMsgId.mail_state_notify, + MailState.newInstance().setNew(true) + ); + + // Set via reflection + PacketHelper.setNextPackage(proto, nextPackage); + } + } } diff --git a/src/main/java/emu/nebula/net/PacketHelper.java b/src/main/java/emu/nebula/net/PacketHelper.java index 3f81c86..1f9ddc0 100644 --- a/src/main/java/emu/nebula/net/PacketHelper.java +++ b/src/main/java/emu/nebula/net/PacketHelper.java @@ -1,10 +1,45 @@ package emu.nebula.net; +import org.reflections.Reflections; + +import com.esotericsoftware.reflectasm.MethodAccess; + +import emu.nebula.Nebula; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.SneakyThrows; import us.hebi.quickbuf.ProtoMessage; import us.hebi.quickbuf.ProtoSink; public class PacketHelper { + private static Object2IntMap> methodIndexCache = new Object2IntOpenHashMap<>(); + + public static void cacheProtos() { + var classes = new Reflections(Nebula.class.getPackage().getName()).getSubTypesOf(ProtoMessage.class); + + for (var cls : classes) { + try { + var access = MethodAccess.get(cls); + int index = access.getIndex("setNextPackage"); + methodIndexCache.put(cls, index); + } catch (Exception e) { + + } + } + + Nebula.getLogger().info("Cached " + methodIndexCache.size() + " proto methods."); + } + + public static boolean hasNextPackageMethod(Object obj) { + return methodIndexCache.containsKey(obj.getClass()); + } + + public static void setNextPackage(ProtoMessage proto, byte[] data) { + int index = methodIndexCache.getInt(proto.getClass()); + MethodAccess.get(proto.getClass()).invoke(proto, index, data); + } + + // Packet encoding public static byte[] encodeMsg(int msgId, byte[] packet) { // Create data array diff --git a/src/main/java/emu/nebula/server/handlers/HandlerPlayerPingReq.java b/src/main/java/emu/nebula/server/handlers/HandlerPlayerPingReq.java index a6b1d47..cd0eea2 100644 --- a/src/main/java/emu/nebula/server/handlers/HandlerPlayerPingReq.java +++ b/src/main/java/emu/nebula/server/handlers/HandlerPlayerPingReq.java @@ -2,9 +2,7 @@ package emu.nebula.server.handlers; import emu.nebula.net.NetHandler; import emu.nebula.net.NetMsgId; -import emu.nebula.net.PacketHelper; import emu.nebula.proto.PlayerPing.Pong; -import emu.nebula.proto.Public.MailState; import emu.nebula.net.HandlerId; import emu.nebula.Nebula; import emu.nebula.net.GameSession; @@ -18,20 +16,6 @@ public class HandlerPlayerPingReq extends NetHandler { var rsp = Pong.newInstance() .setServerTs(Nebula.getCurrentTime()); - // Update mail state flag - if (session.getPlayer().getMailbox().isNewState()) { - // Clear - session.getPlayer().getMailbox().clearNewState(); - - // Send mail state notify - byte[] nextPackage = PacketHelper.encodeMsg( - NetMsgId.mail_state_notify, - MailState.newInstance().setNew(true) - ); - - rsp.setNextPackage(nextPackage); - } - return session.encodeMsg(NetMsgId.player_ping_succeed_ack, rsp); }