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 lombok.AccessLevel;
import lombok.Getter;
import us.hebi.quickbuf.ProtoMessage;
@Getter
public class GameSession {
@@ -176,7 +177,7 @@ public class GameSession {
// Log
if (LunarCore.getConfig().getLogOptions().packets) {
if (!(LunarCore.getConfig().getLogOptions().filterLoopingPackets && CmdIdUtils.LOOP_PACKETS.contains(cmdId))) {
logPacket("RECV", cmdId, null);
logPacket("RECV", cmdId, Utils.EMPTY_BYTE_ARRAY);
}
}
}
@@ -190,6 +191,10 @@ public class GameSession {
}
}
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) {
LunarCore.getLogger().info(sendOrRecv + ": " + CmdIdUtils.getCmdIdName(opcode) + " (" + opcode + ")" + System.lineSeparator() + Utils.bytesToHex(payload));
}

View File

@@ -1,10 +1,12 @@
package emu.lunarcore.server.packet;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import emu.lunarcore.util.Utils;
import lombok.Getter;
import us.hebi.quickbuf.ProtoMessage;
import us.hebi.quickbuf.ProtoSink;
import us.hebi.quickbuf.ProtoSource;
@Getter
public class BasePacket {
@@ -12,67 +14,119 @@ public class BasePacket {
public static final int TAIL_CONST = 0xd7a152c8;
private int cmdId;
private byte[] data;
private ProtoMessage<?> data;
public BasePacket(int cmdId) {
this.cmdId = cmdId;
}
public BasePacket(int cmdId, byte[] data) {
this.cmdId = cmdId;
this.data = data;
}
public void setCmdId(int cmdId) {
this.cmdId = cmdId;
}
public void setData(byte[] data) {
this.data = data;
this.data = new RawProto(data);
}
public void setData(ProtoMessage<?> proto) {
this.data = proto.toByteArray();
this.data = proto;
}
public byte[] build() {
if (getData() == null) {
this.data = new byte[0];
// Setup
int protoSize = 0;
// Set proto message size
if (this.data != null) {
protoSize = this.data.getSerializedSize();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(4 + 2 + 4 + getData().length + 4);
// Create proto sink
byte[] packet = new byte[16 + protoSize];
ProtoSink output = ProtoSink.newInstance(packet, 0, packet.length);
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);
try {
// Write packet header
this.writeUint32(output, HEADER_CONST);
this.writeUint16(output, cmdId);
this.writeUint16(output, 0);
this.writeUint32(output, protoSize);
byte[] packet = baos.toByteArray();
// 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
}
return packet;
}
private void writeUint16(ByteArrayOutputStream baos, int i) {
private void writeUint16(ProtoSink out, int i) throws Exception {
// Unsigned short
baos.write((byte) ((i >>> 8) & 0xFF));
baos.write((byte) (i & 0xFF));
out.writeRawByte((byte) ((i >>> 8) & 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)
baos.write((byte) ((i >>> 24) & 0xFF));
baos.write((byte) ((i >>> 16) & 0xFF));
baos.write((byte) ((i >>> 8) & 0xFF));
baos.write((byte) (i & 0xFF));
out.writeRawByte((byte) ((i >>> 24) & 0xFF));
out.writeRawByte((byte) ((i >>> 16) & 0xFF));
out.writeRawByte((byte) ((i >>> 8) & 0xFF));
out.writeRawByte((byte) (i & 0xFF));
}
private void writeBytes(ByteArrayOutputStream baos, byte[] bytes) {
try {
baos.write(bytes);
} catch (IOException e) {
e.printStackTrace();
/**
* A byte array wrapped in a ProtoMessage object
*/
@SuppressWarnings("rawtypes")
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

@@ -13,10 +13,11 @@ public class Utils {
public static final Object EMPTY_OBJECT = new Object();
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 String bytesToHex(byte[] bytes) {
if (bytes == null) return "";
if (bytes == null || bytes.length == 0) return EMPTY_STRING;
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;