Optimize BasePacket to directly write to the proto sink

This commit is contained in:
Melledy
2023-12-03 04:00:10 -08:00
parent 773d56bbeb
commit 1d99769d4f
3 changed files with 100 additions and 40 deletions

View File

@@ -16,6 +16,7 @@ import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap;
import kcp.highway.Ukcp; import kcp.highway.Ukcp;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import us.hebi.quickbuf.ProtoMessage;
@Getter @Getter
public class GameSession { public class GameSession {
@@ -176,7 +177,7 @@ public class GameSession {
// Log // Log
if (LunarCore.getConfig().getLogOptions().packets) { if (LunarCore.getConfig().getLogOptions().packets) {
if (!(LunarCore.getConfig().getLogOptions().filterLoopingPackets && CmdIdUtils.LOOP_PACKETS.contains(cmdId))) { if (!(LunarCore.getConfig().getLogOptions().filterLoopingPackets && CmdIdUtils.LOOP_PACKETS.contains(cmdId))) {
logPacket("RECV", cmdId, null); logPacket("RECV", cmdId, Utils.EMPTY_BYTE_ARRAY);
} }
} }
} }
@@ -189,6 +190,10 @@ public class GameSession {
buf.release(); buf.release();
} }
} }
public void logPacket(String sendOrRecv, int opcode, ProtoMessage<?> payload) {
logPacket(sendOrRecv, opcode, payload != null ? payload.toByteArray() : Utils.EMPTY_BYTE_ARRAY);
}
public void logPacket(String sendOrRecv, int opcode, byte[] payload) { public void logPacket(String sendOrRecv, int opcode, byte[] payload) {
LunarCore.getLogger().info(sendOrRecv + ": " + CmdIdUtils.getCmdIdName(opcode) + " (" + opcode + ")" + System.lineSeparator() + Utils.bytesToHex(payload)); LunarCore.getLogger().info(sendOrRecv + ": " + CmdIdUtils.getCmdIdName(opcode) + " (" + opcode + ")" + System.lineSeparator() + Utils.bytesToHex(payload));

View File

@@ -1,10 +1,12 @@
package emu.lunarcore.server.packet; package emu.lunarcore.server.packet;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import emu.lunarcore.util.Utils;
import lombok.Getter; import lombok.Getter;
import us.hebi.quickbuf.ProtoMessage; import us.hebi.quickbuf.ProtoMessage;
import us.hebi.quickbuf.ProtoSink;
import us.hebi.quickbuf.ProtoSource;
@Getter @Getter
public class BasePacket { public class BasePacket {
@@ -12,67 +14,119 @@ public class BasePacket {
public static final int TAIL_CONST = 0xd7a152c8; public static final int TAIL_CONST = 0xd7a152c8;
private int cmdId; private int cmdId;
private byte[] data; private ProtoMessage<?> data;
public BasePacket(int cmdId) { public BasePacket(int cmdId) {
this.cmdId = cmdId; this.cmdId = cmdId;
} }
public BasePacket(int cmdId, byte[] data) {
this.cmdId = cmdId;
this.data = data;
}
public void setCmdId(int cmdId) { public void setCmdId(int cmdId) {
this.cmdId = cmdId; this.cmdId = cmdId;
} }
public void setData(byte[] data) { public void setData(byte[] data) {
this.data = data; this.data = new RawProto(data);
} }
public void setData(ProtoMessage<?> proto) { public void setData(ProtoMessage<?> proto) {
this.data = proto.toByteArray(); this.data = proto;
} }
public byte[] build() { public byte[] build() {
if (getData() == null) { // Setup
this.data = new byte[0]; int protoSize = 0;
// Set proto message size
if (this.data != null) {
protoSize = this.data.getSerializedSize();
}
// Create proto sink
byte[] packet = new byte[16 + protoSize];
ProtoSink output = ProtoSink.newInstance(packet, 0, packet.length);
try {
// Write packet header
this.writeUint32(output, HEADER_CONST);
this.writeUint16(output, cmdId);
this.writeUint16(output, 0);
this.writeUint32(output, protoSize);
// Write protobuf message
if (this.data != null) {
this.data.writeTo(output);
}
// Write packet footer
this.writeUint32(output, TAIL_CONST);
} catch (Exception e) {
// Should never happen
} }
ByteArrayOutputStream baos = new ByteArrayOutputStream(4 + 2 + 4 + getData().length + 4);
this.writeUint32(baos, HEADER_CONST);
this.writeUint16(baos, cmdId);
this.writeUint16(baos, 0); // Empty header
this.writeUint32(baos, data.length);
this.writeBytes(baos, data);
this.writeUint32(baos, TAIL_CONST);
byte[] packet = baos.toByteArray();
return packet; return packet;
} }
private void writeUint16(ByteArrayOutputStream baos, int i) { private void writeUint16(ProtoSink out, int i) throws Exception {
// Unsigned short // Unsigned short
baos.write((byte) ((i >>> 8) & 0xFF)); out.writeRawByte((byte) ((i >>> 8) & 0xFF));
baos.write((byte) (i & 0xFF)); out.writeRawByte((byte) (i & 0xFF));
} }
private void writeUint32(ByteArrayOutputStream baos, int i) { private void writeUint32(ProtoSink out, int i) throws Exception {
// Unsigned int (long) // Unsigned int (long)
baos.write((byte) ((i >>> 24) & 0xFF)); out.writeRawByte((byte) ((i >>> 24) & 0xFF));
baos.write((byte) ((i >>> 16) & 0xFF)); out.writeRawByte((byte) ((i >>> 16) & 0xFF));
baos.write((byte) ((i >>> 8) & 0xFF)); out.writeRawByte((byte) ((i >>> 8) & 0xFF));
baos.write((byte) (i & 0xFF)); out.writeRawByte((byte) (i & 0xFF));
} }
private void writeBytes(ByteArrayOutputStream baos, byte[] bytes) { /**
try { * A byte array wrapped in a ProtoMessage object
baos.write(bytes); */
} catch (IOException e) { @SuppressWarnings("rawtypes")
e.printStackTrace(); private static class RawProto extends ProtoMessage {
private byte[] data;
public RawProto(byte[] data) {
this.data = data;
} }
@Override
public ProtoMessage copyFrom(ProtoMessage other) {
data = other.toByteArray();
return this;
}
@Override
public ProtoMessage clear() {
data = Utils.EMPTY_BYTE_ARRAY;
return this;
}
@Override
protected int computeSerializedSize() {
return data.length;
}
@Override
public void writeTo(ProtoSink output) throws IOException {
output.writeRawBytes(data);
}
@Override
public ProtoMessage mergeFrom(ProtoSource input) throws IOException {
return this; // Skip
}
@Override
public boolean equals(Object obj) {
return false; // Skip
}
@Override
public ProtoMessage clone() {
return null; // Skip
}
} }
} }

View File

@@ -10,13 +10,14 @@ import java.util.concurrent.ThreadLocalRandom;
public class Utils { public class Utils {
private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
public static final Object EMPTY_OBJECT = new Object(); public static final Object EMPTY_OBJECT = new Object();
public static final int[] EMPTY_ARRAY = new int[0]; public static final int[] EMPTY_ARRAY = new int[0];
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
public static final String EMPTY_STRING = ""; public static final String EMPTY_STRING = "";
public static String bytesToHex(byte[] bytes) { public static String bytesToHex(byte[] bytes) {
if (bytes == null) return ""; if (bytes == null || bytes.length == 0) return EMPTY_STRING;
char[] hexChars = new char[bytes.length * 2]; char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) { for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF; int v = bytes[j] & 0xFF;