From 9bdb642a8b826cad558739a6c8ad71d5fae35026 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Fri, 28 Jun 2024 23:39:51 +0400 Subject: [PATCH 01/10] Example impls --- .../packetevents/binary/BinaryBuffer.java | 67 ++++++++++ .../packetevents/binary/BinaryBufferType.java | 30 +++++ .../binary/BinaryBufferTypes.java | 123 ++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java create mode 100644 api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferType.java create mode 100644 api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java new file mode 100644 index 0000000000..5ec507948c --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -0,0 +1,67 @@ +package com.github.retrooper.packetevents.binary; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.protocol.player.ClientVersion; + +public final class BinaryBuffer { + + public static final BinaryBufferType BYTE = new BinaryBufferTypes.Byte(); + public static final BinaryBufferType BOOLEAN = new BinaryBufferTypes.Bool(); + public static final BinaryBufferType INT = new BinaryBufferTypes.Int(); + public static final BinaryBufferType FLOAT = new BinaryBufferTypes.Float(); + public static final BinaryBufferType DOUBLE = new BinaryBufferTypes.Double(); + public static final BinaryBufferType LONG = new BinaryBufferTypes.Long(); + public static final BinaryBufferType SHORT = new BinaryBufferTypes.Short(); + public static final BinaryBufferType VAR_INT = new BinaryBufferTypes.VarInt(); + + private Object buffer; + + public BinaryBuffer(Object buffer) { + this.buffer = buffer; + } + + public BinaryBuffer(int capacity, boolean io) { + if (io) { + this.buffer = PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().buffer(capacity); + } + else { + this.buffer = PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().directBuffer(capacity); + } + } + + public BinaryBuffer(int capacity) { + this(capacity, true); + } + + public BinaryBuffer(byte[] wrappedData) { + this.buffer = PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().wrappedBuffer(wrappedData); + } + + public T read(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { + return type.read(this, serverVersion, clientVersion); + } + + public T read(BinaryBufferType type, ClientVersion clientVersion) { + return type.read(this, clientVersion); + } + + public T read(BinaryBufferType type) { + return type.read(this); + } + + public void write(BinaryBufferType type, T value, ServerVersion serverVersion, ClientVersion clientVersion) { + type.write(this, value, serverVersion, clientVersion); + } + + public void write(BinaryBufferType type, T value, ClientVersion clientVersion) { + type.write(this, value, clientVersion); + } + + public void write(BinaryBufferType type, T value) { + type.write(this, value); + } + + + +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferType.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferType.java new file mode 100644 index 0000000000..4b11ccc0a0 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferType.java @@ -0,0 +1,30 @@ +package com.github.retrooper.packetevents.binary; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.protocol.player.ClientVersion; + +public interface BinaryBufferType { + + T read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion); + + void write(BinaryBuffer buffer, T value, ServerVersion serverVersion, ClientVersion clientVersion); + + default T read(BinaryBuffer buffer, ClientVersion clientVersion) { + return read(buffer, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + + default void write(BinaryBuffer buffer, T value, ClientVersion clientVersion) { + write(buffer, value, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + + default T read(BinaryBuffer buffer) { + ServerVersion v = PacketEvents.getAPI().getServerManager().getVersion(); + return read(buffer, v, v.toClientVersion()); + } + + default void write(BinaryBuffer buffer, T value) { + write(buffer, value, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java new file mode 100644 index 0000000000..857cb50e62 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -0,0 +1,123 @@ +package com.github.retrooper.packetevents.binary; + +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.player.ClientVersion; + +final class BinaryBufferTypes { + + private BinaryBufferTypes() {} + + static final class Float implements BinaryBufferType { + @Override + public java.lang.Float read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readFloat(buffer); + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Float value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeFloat(buffer, value); + } + } + static final class Double implements BinaryBufferType { + @Override + public java.lang.Double read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readDouble(buffer); + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Double value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeDouble(buffer, value); + } + } + static final class Bool implements BinaryBufferType { + + @Override + public Boolean read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readBoolean(buffer); + } + + @Override + public void write(BinaryBuffer buffer, Boolean value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeBoolean(buffer, value); + } + } + static final class Byte implements BinaryBufferType { + + @Override + public java.lang.Byte read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readByte(buffer); + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Byte value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeByte(buffer, value); + } + } + static final class Int implements BinaryBufferType { + + @Override + public Integer read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readInt(buffer); + } + + @Override + public void write(BinaryBuffer buffer, Integer value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeInt(buffer, value); + } + } + static final class Long implements BinaryBufferType { + + @Override + public java.lang.Long read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readLong(buffer); + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Long value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeLong(buffer, value); + } + } + static final class Short implements BinaryBufferType { + + @Override + public java.lang.Short read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readShort(buffer); + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Short value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeShort(buffer, value); + } + } + static final class VarInt implements BinaryBufferType { + + @Override + public Integer read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + int value = 0; + int length = 0; + byte currentByte; + do { + currentByte = ByteBufHelper.readByte(buffer); + value |= (currentByte & 0x7F) << (length * 7); + length++; + if (length > 5) { + throw new RuntimeException("VarInt is too large. Must be smaller than 5 bytes."); + } + } while ((currentByte & 0x80) == 0x80); + return value; + } + + @Override + public void write(BinaryBuffer buffer, Integer value, ServerVersion serverVersion, ClientVersion clientVersion) { + while (true) { + if ((value & ~0x7F) == 0) { + ByteBufHelper.writeByte(buffer, value); + break; + } + ByteBufHelper.writeByte(buffer, (value & 0x7F) | 0x80); + value >>>= 7; + } + } + } +} From 4861de256893239b5a37a2ab71de6a837f37d56f Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Fri, 28 Jun 2024 23:54:03 +0400 Subject: [PATCH 02/10] More methods in BinaryBuffer --- .../packetevents/binary/BinaryBuffer.java | 105 +++++++++++++++++- .../binary/BinaryBufferTypes.java | 22 ++++ 2 files changed, 122 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index 5ec507948c..9e264b2326 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -2,7 +2,11 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; + +import java.util.*; public final class BinaryBuffer { @@ -38,30 +42,121 @@ public BinaryBuffer(byte[] wrappedData) { this.buffer = PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().wrappedBuffer(wrappedData); } + /** Buffer Operations **/ + public void resetReaderIndex() { + ByteBufHelper.resetReaderIndex(buffer); + } + public void resetWriterIndex() { + ByteBufHelper.resetWriterIndex(buffer); + } + public void reset() { + ByteBufHelper.clear(buffer); + } + + + /** Primitive Read/Write Methods **/ public T read(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { return type.read(this, serverVersion, clientVersion); } - public T read(BinaryBufferType type, ClientVersion clientVersion) { return type.read(this, clientVersion); } - public T read(BinaryBufferType type) { return type.read(this); } - public void write(BinaryBufferType type, T value, ServerVersion serverVersion, ClientVersion clientVersion) { type.write(this, value, serverVersion, clientVersion); } - public void write(BinaryBufferType type, T value, ClientVersion clientVersion) { type.write(this, value, clientVersion); } - public void write(BinaryBufferType type, T value) { type.write(this, value); } + /** Collection Read/Write Methods **/ + public Collection readCollection(int maxSize, BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { + int size = read(VAR_INT, serverVersion, clientVersion); + if (size > maxSize) { + throw new IllegalArgumentException("Size of collection is too big: " + size); + } + List list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(read(type, serverVersion, clientVersion)); + } + return list; + } + public Collection readCollection(int maxSize, BinaryBufferType type, ClientVersion clientVersion) { + return readCollection(maxSize, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + public Collection readCollection(int maxSize, BinaryBufferType type) { + return readCollection(maxSize, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + public Collection readCollection(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { + return readCollection(Short.MAX_VALUE, type, serverVersion, clientVersion); + } + public Collection readCollection(BinaryBufferType type, ClientVersion clientVersion) { + return readCollection(Short.MAX_VALUE, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + public Collection readCollection(BinaryBufferType type) { + return readCollection(Short.MAX_VALUE, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + + public void writeCollection(Collection collection, BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { + write(VAR_INT, collection.size(), serverVersion, clientVersion); + for (T t : collection) { + write(type, t, serverVersion, clientVersion); + } + } + public void writeCollection(Collection collection, BinaryBufferType type, ClientVersion clientVersion) { + writeCollection(collection, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + public void writeCollection(Collection collection, BinaryBufferType type) { + writeCollection(collection, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + + /** Map Read/Write Methods **/ + public Map readMap(BinaryBufferType keyType, BinaryBufferType valueType, ServerVersion serverVersion, ClientVersion clientVersion) { + int size = read(VAR_INT, serverVersion, clientVersion); + Map map = new HashMap<>(size); + for (int i = 0; i < size; i++) { + K key = read(keyType, serverVersion, clientVersion); + V value = read(valueType, serverVersion, clientVersion); + map.put(key, value); + } + return map; + } + public Map readMap(BinaryBufferType keyType, BinaryBufferType valueType, ClientVersion clientVersion) { + return readMap(keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + public Map readMap(BinaryBufferType keyType, BinaryBufferType valueType) { + return readMap(keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + public void writeMap(Map map, BinaryBufferType keyType, BinaryBufferType valueType, ServerVersion serverVersion, ClientVersion clientVersion) { + write(VAR_INT, map.size(), serverVersion, clientVersion); + for (Map.Entry entry : map.entrySet()) { + write(keyType, entry.getKey(), serverVersion, clientVersion); + write(valueType, entry.getValue(), serverVersion, clientVersion); + } + } + public void writeMap(Map map, BinaryBufferType keyType, BinaryBufferType valueType, ClientVersion clientVersion) { + writeMap(map, keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + public void writeMap(Map map, BinaryBufferType keyType, BinaryBufferType valueType) { + writeMap(map, keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + /** Enums Read/Write Methods **/ + public > T readEnum(Class enumClass) { + T[] constants = enumClass.getEnumConstants(); + int ordinal = read(VAR_INT); + if (ordinal < 0 || ordinal >= constants.length) { + throw new IllegalArgumentException("Invalid ordinal for enum " + enumClass.getName() + ": " + ordinal); + } + return constants[ordinal]; + } + public > void writeEnum(T value) { + write(VAR_INT, value.ordinal()); + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index 857cb50e62..b8038c8147 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -120,4 +120,26 @@ public void write(BinaryBuffer buffer, Integer value, ServerVersion serverVersio } } } + static final class VarLong implements BinaryBufferType { + + @Override + public java.lang.Long read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + long value = 0; + int size = 0; + int b; + while (((b = ByteBufHelper.readByte(buffer)) & 0x80) == 0x80) { + value |= (long) (b & 0x7F) << (size++ * 7); + } + return value | ((long) (b & 0x7F) << (size * 7)); } + + @Override + public void write(BinaryBuffer buffer, java.lang.Long value, ServerVersion serverVersion, ClientVersion clientVersion) { + while ((value & ~0x7F) != 0) { + ByteBufHelper.writeByte(buffer, (int) (value & 0x7F) | 0x80); + value >>>= 7; + } + + ByteBufHelper.writeByte(buffer, value.intValue()); + } + } } From f140fc9c466dc6b9fa5ad8bb58a89a73eae6c4b1 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Sat, 24 May 2025 18:09:45 +0400 Subject: [PATCH 03/10] Bring this alive + String conversion --- .../packetevents/binary/BinaryBuffer.java | 19 ++- .../binary/BinaryBufferTypes.java | 132 ++++++++++++++---- .../packetevents/wrapper/PacketWrapper.java | 3 + 3 files changed, 127 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index 9e264b2326..406dbb2d6d 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -11,13 +11,24 @@ public final class BinaryBuffer { public static final BinaryBufferType BYTE = new BinaryBufferTypes.Byte(); + public static final BinaryBufferType UBYTE = new BinaryBufferTypes.UByte(); public static final BinaryBufferType BOOLEAN = new BinaryBufferTypes.Bool(); - public static final BinaryBufferType INT = new BinaryBufferTypes.Int(); + public static final BinaryBufferType FLOAT = new BinaryBufferTypes.Float(); public static final BinaryBufferType DOUBLE = new BinaryBufferTypes.Double(); - public static final BinaryBufferType LONG = new BinaryBufferTypes.Long(); + public static final BinaryBufferType SHORT = new BinaryBufferTypes.Short(); + public static final BinaryBufferType INT = new BinaryBufferTypes.Int(); + public static final BinaryBufferType LONG = new BinaryBufferTypes.Long(); + public static final BinaryBufferType MEDIUM = new BinaryBufferTypes.Medium(); + public static final BinaryBufferType VAR_INT = new BinaryBufferTypes.VarInt(); + public static final BinaryBufferType VAR_LONG = new BinaryBufferTypes.VarLong(); + + public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); + public static BinaryBufferType SizedString(int maxSize) { + return new BinaryBufferTypes.String(maxSize); + } private Object buffer; @@ -159,4 +170,8 @@ public > T readEnum(Class enumClass) { public > void writeEnum(T value) { write(VAR_INT, value.ordinal()); } + + public Object getBuffer() { + return buffer; + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index b8038c8147..62d7e4df51 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -4,6 +4,8 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import java.nio.charset.StandardCharsets; + final class BinaryBufferTypes { private BinaryBufferTypes() {} @@ -11,83 +13,96 @@ private BinaryBufferTypes() {} static final class Float implements BinaryBufferType { @Override public java.lang.Float read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readFloat(buffer); + return ByteBufHelper.readFloat(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, java.lang.Float value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeFloat(buffer, value); + ByteBufHelper.writeFloat(buffer.getBuffer(), value); } } static final class Double implements BinaryBufferType { @Override public java.lang.Double read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readDouble(buffer); + return ByteBufHelper.readDouble(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, java.lang.Double value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeDouble(buffer, value); + ByteBufHelper.writeDouble(buffer.getBuffer(), value); } } static final class Bool implements BinaryBufferType { @Override public Boolean read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readBoolean(buffer); + return ByteBufHelper.readBoolean(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, Boolean value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeBoolean(buffer, value); + ByteBufHelper.writeBoolean(buffer.getBuffer(), value); } } static final class Byte implements BinaryBufferType { @Override public java.lang.Byte read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readByte(buffer); + return ByteBufHelper.readByte(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, java.lang.Byte value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeByte(buffer, value); + ByteBufHelper.writeByte(buffer.getBuffer(), value); + } + } + static final class UByte implements BinaryBufferType { + + @Override + public java.lang.Short read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readUnsignedByte(buffer.getBuffer()); + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Short value, ServerVersion serverVersion, ClientVersion clientVersion) { + int s = value & 0xFF; + ByteBufHelper.writeByte(buffer.getBuffer(), s); } } static final class Int implements BinaryBufferType { @Override public Integer read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readInt(buffer); + return ByteBufHelper.readInt(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, Integer value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeInt(buffer, value); + ByteBufHelper.writeInt(buffer.getBuffer(), value); } } static final class Long implements BinaryBufferType { @Override public java.lang.Long read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readLong(buffer); + return ByteBufHelper.readLong(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, java.lang.Long value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeLong(buffer, value); + ByteBufHelper.writeLong(buffer.getBuffer(), value); } } static final class Short implements BinaryBufferType { @Override public java.lang.Short read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { - return ByteBufHelper.readShort(buffer); + return ByteBufHelper.readShort(buffer.getBuffer()); } @Override public void write(BinaryBuffer buffer, java.lang.Short value, ServerVersion serverVersion, ClientVersion clientVersion) { - ByteBufHelper.writeShort(buffer, value); + ByteBufHelper.writeShort(buffer.getBuffer(), value); } } static final class VarInt implements BinaryBufferType { @@ -98,7 +113,7 @@ public Integer read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVers int length = 0; byte currentByte; do { - currentByte = ByteBufHelper.readByte(buffer); + currentByte = ByteBufHelper.readByte(buffer.getBuffer()); value |= (currentByte & 0x7F) << (length * 7); length++; if (length > 5) { @@ -110,16 +125,42 @@ public Integer read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVers @Override public void write(BinaryBuffer buffer, Integer value, ServerVersion serverVersion, ClientVersion clientVersion) { - while (true) { - if ((value & ~0x7F) == 0) { - ByteBufHelper.writeByte(buffer, value); - break; - } - ByteBufHelper.writeByte(buffer, (value & 0x7F) | 0x80); - value >>>= 7; + /* Got this code/optimization from https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/ + * Copyright and permission notice above (above the class). + * Steinborn's post says that the code is under the MIT, last accessed 29.06.2024. + */ + if ((value & (0xFFFFFFFF << 7)) == 0) { + ByteBufHelper.writeByte(buffer.getBuffer(), value); + } else if ((value & (0xFFFFFFFF << 14)) == 0) { + int w = (value & 0x7F | 0x80) << 8 | (value >>> 7); + ByteBufHelper.writeShort(buffer.getBuffer(), w); + } else if ((value & (0xFFFFFFFF << 21)) == 0) { + int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14); + ByteBufHelper.writeMedium(buffer.getBuffer(), w); + } else if ((value & (0xFFFFFFFF << 28)) == 0) { + int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) + | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); + ByteBufHelper.writeInt(buffer.getBuffer(), w); + } else { + int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 + | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); + ByteBufHelper.writeInt(buffer.getBuffer(), w); + ByteBufHelper.writeByte(buffer.getBuffer(), value >>> 28); } } } + static final class Medium implements BinaryBufferType { + + @Override + public Integer read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return ByteBufHelper.readMedium(buffer.getBuffer()); + } + + @Override + public void write(BinaryBuffer buffer, Integer value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeMedium(buffer.getBuffer(), value); + } + } static final class VarLong implements BinaryBufferType { @Override @@ -127,7 +168,7 @@ public java.lang.Long read(BinaryBuffer buffer, ServerVersion serverVersion, Cli long value = 0; int size = 0; int b; - while (((b = ByteBufHelper.readByte(buffer)) & 0x80) == 0x80) { + while (((b = ByteBufHelper.readByte(buffer.getBuffer())) & 0x80) == 0x80) { value |= (long) (b & 0x7F) << (size++ * 7); } return value | ((long) (b & 0x7F) << (size * 7)); } @@ -135,11 +176,52 @@ public java.lang.Long read(BinaryBuffer buffer, ServerVersion serverVersion, Cli @Override public void write(BinaryBuffer buffer, java.lang.Long value, ServerVersion serverVersion, ClientVersion clientVersion) { while ((value & ~0x7F) != 0) { - ByteBufHelper.writeByte(buffer, (int) (value & 0x7F) | 0x80); + ByteBufHelper.writeByte(buffer.getBuffer(), (int) (value & 0x7F) | 0x80); value >>>= 7; } - ByteBufHelper.writeByte(buffer, value.intValue()); + ByteBufHelper.writeByte(buffer.getBuffer(), value.intValue()); + } + } + + static final class String implements BinaryBufferType { + + static final int MAX_LENGTH = java.lang.Short.MAX_VALUE; + + private int maxLength = MAX_LENGTH; + + String(int length) { + if (length < 0 || length > MAX_LENGTH) { + throw new IllegalArgumentException("String length must be between 0 and " + MAX_LENGTH + ", but was " + length); + } + this.maxLength = length; + } + + String() {} + + @Override + public java.lang.String read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + int j = buffer.read(BinaryBuffer.VAR_INT); + // TODO: Don't throw an exception if the string is too long (but still cut it off and probably kick the player) + if (j > maxLength * 4) { + throw new RuntimeException("The received encoded string buffer length is longer than maximum allowed (" + j + " > " + maxLength * 4 + ")"); + } else if (j < 0) { + throw new RuntimeException("The received encoded string buffer length is less than zero! Weird string!"); + } else { + java.lang.String s = ByteBufHelper.toString(buffer, ByteBufHelper.readerIndex(buffer), j, StandardCharsets.UTF_8); + ByteBufHelper.readerIndex(buffer, ByteBufHelper.readerIndex(buffer) + j); + if (s.length() > maxLength) { + throw new RuntimeException("The received string length is longer than maximum allowed (" + j + " > " + maxLength + ")"); + } else { + return s; + } + } + } + + @Override + public void write(BinaryBuffer buffer, java.lang.String value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.VAR_INT, value.length()); + ByteBufHelper.writeBytes(buffer.getBuffer(), value.getBytes(StandardCharsets.UTF_8)); } } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index e83c0c36a4..723642df62 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -43,6 +43,7 @@ package com.github.retrooper.packetevents.wrapper; import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.binary.BinaryBuffer; import com.github.retrooper.packetevents.event.PacketReceiveEvent; import com.github.retrooper.packetevents.event.PacketSendEvent; import com.github.retrooper.packetevents.event.ProtocolPacketEvent; @@ -130,6 +131,8 @@ public class PacketWrapper> { @Nullable public Object buffer; + @Nullable + public BinaryBuffer binaryBuffer; @ApiStatus.Internal public final Object bufferLock = new Object(); From a3faaf96e576368855603e6e1359dc59ffa715e9 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 11:10:23 +0400 Subject: [PATCH 04/10] Start porting packet wrapper --- .../packetevents/binary/BinaryBuffer.java | 2 + .../binary/BinaryBufferTypes.java | 16 +++- .../packetevents/wrapper/PacketWrapper.java | 76 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index 406dbb2d6d..bb467dbe48 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -25,6 +25,8 @@ public final class BinaryBuffer { public static final BinaryBufferType VAR_INT = new BinaryBufferTypes.VarInt(); public static final BinaryBufferType VAR_LONG = new BinaryBufferTypes.VarLong(); + public static final BinaryBufferType UUID = new BinaryBufferTypes.Uuid(); + public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); public static BinaryBufferType SizedString(int maxSize) { return new BinaryBufferTypes.String(maxSize); diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index 62d7e4df51..5bfb5f07c1 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -183,7 +183,6 @@ public void write(BinaryBuffer buffer, java.lang.Long value, ServerVersion serve ByteBufHelper.writeByte(buffer.getBuffer(), value.intValue()); } } - static final class String implements BinaryBufferType { static final int MAX_LENGTH = java.lang.Short.MAX_VALUE; @@ -224,4 +223,19 @@ public void write(BinaryBuffer buffer, java.lang.String value, ServerVersion ser ByteBufHelper.writeBytes(buffer.getBuffer(), value.getBytes(StandardCharsets.UTF_8)); } } + static final class Uuid implements BinaryBufferType { + + @Override + public java.util.UUID read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + long mostSigBits = ByteBufHelper.readLong(buffer.getBuffer()); + long leastSigBits = ByteBufHelper.readLong(buffer.getBuffer()); + return new java.util.UUID(mostSigBits, leastSigBits); + } + + @Override + public void write(BinaryBuffer buffer, java.util.UUID value, ServerVersion serverVersion, ClientVersion clientVersion) { + ByteBufHelper.writeLong(buffer.getBuffer(), value.getMostSignificantBits()); + ByteBufHelper.writeLong(buffer.getBuffer(), value.getLeastSignificantBits()); + } + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 723642df62..6242a4eec0 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -44,6 +44,7 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.binary.BinaryBuffer; +import com.github.retrooper.packetevents.binary.BinaryBufferType; import com.github.retrooper.packetevents.event.PacketReceiveEvent; import com.github.retrooper.packetevents.event.PacketSendEvent; import com.github.retrooper.packetevents.event.ProtocolPacketEvent; @@ -154,6 +155,7 @@ public PacketWrapper(ClientVersion clientVersion, ServerVersion serverVersion, i this.clientVersion = clientVersion; this.serverVersion = serverVersion; this.buffer = null; + this.binaryBuffer = null; this.packetTypeData = new PacketTypeData(null, packetID); } @@ -166,6 +168,7 @@ public PacketWrapper(PacketReceiveEvent event, boolean readData) { this.serverVersion = event.getServerVersion(); this.user = event.getUser(); this.buffer = event.getByteBuf(); + this.binaryBuffer = new BinaryBuffer(this.buffer); this.packetTypeData = new PacketTypeData(event.getPacketType(), event.getPacketId()); if (readData) { readEvent(event); @@ -180,6 +183,7 @@ public PacketWrapper(PacketSendEvent event, boolean readData) { this.clientVersion = event.getUser().getClientVersion(); this.serverVersion = event.getServerVersion(); this.buffer = event.getByteBuf(); + this.binaryBuffer = new BinaryBuffer(this.buffer); this.packetTypeData = new PacketTypeData(event.getPacketType(), event.getPacketId()); this.user = event.getUser(); if (readData) { @@ -309,6 +313,7 @@ public Object getBuffer() { public void setBuffer(Object buffer) { this.buffer = buffer; + this.binaryBuffer = new BinaryBuffer(buffer); } /** @@ -356,45 +361,80 @@ public void resetByteBuf() { public void resetBuffer() { ByteBufHelper.clear(buffer); + // TODO: Potentially use {@link BinaryBuffer#reset()} instead? } public byte readByte() { + if (true) { + return binaryBuffer.read(BinaryBuffer.BYTE); + } return ByteBufHelper.readByte(buffer); } public void writeByte(int value) { + if (true) { + binaryBuffer.write(BinaryBuffer.BYTE, (byte) value); + return; + } ByteBufHelper.writeByte(buffer, value); } public short readUnsignedByte() { + if (true) { + return binaryBuffer.read(BinaryBuffer.UBYTE); + } return ByteBufHelper.readUnsignedByte(buffer); } public boolean readBoolean() { + if (true) { + return binaryBuffer.read(BinaryBuffer.BOOLEAN); + } return readByte() != 0; } public void writeBoolean(boolean value) { + if (true) { + binaryBuffer.write(BinaryBuffer.BOOLEAN, value); + return; + } writeByte(value ? 1 : 0); } public int readInt() { + if (true) { + return binaryBuffer.read(BinaryBuffer.INT); + } return ByteBufHelper.readInt(buffer); } public void writeInt(int value) { + if (true) { + binaryBuffer.write(BinaryBuffer.INT, value); + return; + } ByteBufHelper.writeInt(buffer, value); } public int readMedium() { + if (true) { + return binaryBuffer.read(BinaryBuffer.MEDIUM); + } return ByteBufHelper.readMedium(buffer); } public void writeMedium(int value) { + if (true) { + binaryBuffer.write(BinaryBuffer.MEDIUM, value); + return; + } ByteBufHelper.writeMedium(buffer, value); } public int readVarInt() { + if (true) { + return binaryBuffer.read(BinaryBuffer.VAR_INT); + } int value = 0; int length = 0; byte currentByte; @@ -410,6 +450,10 @@ public int readVarInt() { } public void writeVarInt(int value) { + if (true) { + binaryBuffer.write(BinaryBuffer.VAR_INT, value); + return; + } /* Got this code/optimization from https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/ * Copyright and permission notice above (above the class). * Steinborn's post says that the code is under the MIT, last accessed 29.06.2024. @@ -434,10 +478,13 @@ public void writeVarInt(int value) { } } + + // TODO: Map types need to be checked further if Reader instances are required for serialization public Map readMap(Reader keyFunction, Reader valueFunction) { return this.readMap(keyFunction, valueFunction, Integer.MAX_VALUE); } + // TODO: Map types need to be checked further if Reader instances are required for serialization public Map readMap(Reader keyFunction, Reader valueFunction, int maxSize) { int size = this.readVarInt(); if (size > maxSize) { @@ -453,6 +500,7 @@ public Map readMap(Reader keyFunction, Reader valueFunction, return map; } + // TODO: Map types need to be checked further if Writer instances are required for serialization public void writeMap(Map map, Writer keyConsumer, Writer valueConsumer) { writeVarInt(map.size()); for (Map.Entry entry : map.entrySet()) { @@ -689,6 +737,9 @@ public void writeLong(long value) { } public long readVarLong() { + if (true) { + return binaryBuffer.read(BinaryBuffer.VAR_LONG); + } long value = 0; int size = 0; int b; @@ -699,6 +750,10 @@ public long readVarLong() { } public void writeVarLong(long l) { + if (true) { + binaryBuffer.write(BinaryBuffer.VAR_LONG, l); + return; + } while ((l & ~0x7F) != 0) { this.writeByte((int) (l & 0x7F) | 0x80); l >>>= 7; @@ -708,18 +763,32 @@ public void writeVarLong(long l) { } public float readFloat() { + if (true) { + return binaryBuffer.read(BinaryBuffer.FLOAT); + } return ByteBufHelper.readFloat(buffer); } public void writeFloat(float value) { + if (true) { + binaryBuffer.write(BinaryBuffer.FLOAT, value); + return; + } ByteBufHelper.writeFloat(buffer, value); } public double readDouble() { + if (true) { + return binaryBuffer.read(BinaryBuffer.DOUBLE); + } return ByteBufHelper.readDouble(buffer); } public void writeDouble(double value) { + if (true) { + binaryBuffer.write(BinaryBuffer.DOUBLE, value); + return; + } ByteBufHelper.writeDouble(buffer, value); } @@ -830,12 +899,19 @@ public void writeLongArray(long[] array) { } public UUID readUUID() { + if (true) { + return binaryBuffer.read(BinaryBuffer.UUID); + } long mostSigBits = readLong(); long leastSigBits = readLong(); return new UUID(mostSigBits, leastSigBits); } public void writeUUID(UUID uuid) { + if (true) { + binaryBuffer.write(BinaryBuffer.UUID, uuid); + return; + } writeLong(uuid.getMostSignificantBits()); writeLong(uuid.getLeastSignificantBits()); } From d079edf166ba4cae1bbab260bce3496b3be2850c Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 11:14:19 +0400 Subject: [PATCH 05/10] block pos, gamemode, and others --- .../packetevents/binary/BinaryBuffer.java | 4 +++ .../binary/BinaryBufferTypes.java | 30 +++++++++++++++++++ .../packetevents/wrapper/PacketWrapper.java | 14 +++++++++ 3 files changed, 48 insertions(+) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index bb467dbe48..46bd4a304c 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -4,6 +4,8 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import java.util.*; @@ -26,6 +28,8 @@ public final class BinaryBuffer { public static final BinaryBufferType VAR_LONG = new BinaryBufferTypes.VarLong(); public static final BinaryBufferType UUID = new BinaryBufferTypes.Uuid(); + public static final BinaryBufferType BLOCK_POSITION = new BinaryBufferTypes.BlockPos(); + public static final BinaryBufferType GAME_MODE = new BinaryBufferTypes.GameMode(); public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); public static BinaryBufferType SizedString(int maxSize) { diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index 5bfb5f07c1..f3fca94bd8 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -3,6 +3,8 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.util.Vector3i; import java.nio.charset.StandardCharsets; @@ -238,4 +240,32 @@ public void write(BinaryBuffer buffer, java.util.UUID value, ServerVersion serve ByteBufHelper.writeLong(buffer.getBuffer(), value.getLeastSignificantBits()); } } + static final class BlockPos implements BinaryBufferType { + + @Override + public Vector3i read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + long l = ByteBufHelper.readLong(buffer.getBuffer()); + return new Vector3i(l, serverVersion); + } + + @Override + public void write(BinaryBuffer buffer, Vector3i value, ServerVersion serverVersion, ClientVersion clientVersion) { + long val = value.getSerializedPosition(serverVersion); + ByteBufHelper.writeLong(buffer.getBuffer(), val); + } + } + static final class GameMode implements BinaryBufferType { + + @Override + public com.github.retrooper.packetevents.protocol.player.GameMode read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + byte b = ByteBufHelper.readByte(buffer.getBuffer()); + return com.github.retrooper.packetevents.protocol.player.GameMode.getById(b); + } + + @Override + public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.protocol.player.GameMode value, ServerVersion serverVersion, ClientVersion clientVersion) { + int id = value == null ? -1 : value.getId(); + ByteBufHelper.writeByte(buffer.getBuffer(), id); + } + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 6242a4eec0..14fa37b6bc 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -917,20 +917,34 @@ public void writeUUID(UUID uuid) { } public Vector3i readBlockPosition() { + if (true) { + return binaryBuffer.read(BinaryBuffer.BLOCK_POSITION); + } long val = readLong(); return new Vector3i(val, serverVersion); } public void writeBlockPosition(Vector3i pos) { + if (true) { + binaryBuffer.write(BinaryBuffer.BLOCK_POSITION, pos); + return; + } long val = pos.getSerializedPosition(serverVersion); writeLong(val); } public GameMode readGameMode() { + if (true) { + return binaryBuffer.read(BinaryBuffer.GAME_MODE); + } return GameMode.getById(readByte()); } public void writeGameMode(@Nullable GameMode mode) { + if (true) { + binaryBuffer.write(BinaryBuffer.GAME_MODE, mode); + return; + } int id = mode == null ? -1 : mode.getId(); writeByte(id); } From 8dc104dc15a8b8b4f7e77781efff85736b48b199 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 11:31:18 +0400 Subject: [PATCH 06/10] nbt, dimensions, resourcelocation, etc --- .../packetevents/binary/BinaryBuffer.java | 15 +++ .../binary/BinaryBufferTypes.java | 102 ++++++++++++++++++ .../packetevents/wrapper/PacketWrapper.java | 7 ++ 3 files changed, 124 insertions(+) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index 46bd4a304c..cb90a8992c 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -3,8 +3,12 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.nbt.NBT; +import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.player.ClientVersion; import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.world.Dimension; +import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.wrapper.PacketWrapper; @@ -30,6 +34,17 @@ public final class BinaryBuffer { public static final BinaryBufferType UUID = new BinaryBufferTypes.Uuid(); public static final BinaryBufferType BLOCK_POSITION = new BinaryBufferTypes.BlockPos(); public static final BinaryBufferType GAME_MODE = new BinaryBufferTypes.GameMode(); + public static final BinaryBufferType IDENTIFIER = new BinaryBufferTypes.Identifier(); + + public static final BinaryBufferType NBT_RAW = new BinaryBufferTypes.NbtRaw(); + public static final BinaryBufferType NBT = new BinaryBufferTypes.Nbt(); + + public static final BinaryBufferType NBT_RAW_UNLIMITED = new BinaryBufferTypes.NbtRawUnlimited(); + public static final BinaryBufferType NBT_UNLIMITED = new BinaryBufferTypes.NbtUnlimited(); + + @Deprecated() + /** Use {@link BinaryBuffer#DIMENSION_TYPE} instead */ + public static final BinaryBufferType DIMENSION = new BinaryBufferTypes.Dimension(); public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); public static BinaryBufferType SizedString(int maxSize) { diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index f3fca94bd8..72e82416b7 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -2,8 +2,14 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.nbt.NBT; +import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; +import com.github.retrooper.packetevents.protocol.nbt.NBTLimiter; +import com.github.retrooper.packetevents.protocol.nbt.codec.NBTCodec; import com.github.retrooper.packetevents.protocol.player.ClientVersion; import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.world.Dimension; +import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Vector3i; import java.nio.charset.StandardCharsets; @@ -254,6 +260,66 @@ public void write(BinaryBuffer buffer, Vector3i value, ServerVersion serverVersi ByteBufHelper.writeLong(buffer.getBuffer(), val); } } + static final class Identifier implements BinaryBufferType { + + @Override + public ResourceLocation read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return new ResourceLocation(buffer.read(BinaryBuffer.STRING)); + } + + @Override + public void write(BinaryBuffer buffer, ResourceLocation value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.STRING, value.toString()); + } + } + static final class Nbt implements BinaryBufferType { + + @Override + public NBTCompound read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return (NBTCompound) buffer.read(BinaryBuffer.NBT_RAW); + } + + @Override + public void write(BinaryBuffer buffer, NBTCompound value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.NBT_RAW, value, serverVersion, clientVersion); + } + } + static final class NbtRaw implements BinaryBufferType { + + @Override + public NBT read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return NBTCodec.readNBTFromBuffer(buffer.getBuffer(), serverVersion); + } + + @Override + public void write(BinaryBuffer buffer, NBT value, ServerVersion serverVersion, ClientVersion clientVersion) { + NBTCodec.writeNBTToBuffer(buffer.getBuffer(), serverVersion, value); + } + } + static final class NbtUnlimited implements BinaryBufferType { + + @Override + public NBTCompound read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return (NBTCompound) buffer.read(BinaryBuffer.NBT_RAW_UNLIMITED); + } + + @Override + public void write(BinaryBuffer buffer, NBTCompound value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.NBT_RAW, value, serverVersion, clientVersion); + } + } + static final class NbtRawUnlimited implements BinaryBufferType { + + @Override + public NBT read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return NBTCodec.readNBTFromBuffer(buffer.getBuffer(), serverVersion, NBTLimiter.noop()); + } + + @Override + public void write(BinaryBuffer buffer, NBT value, ServerVersion serverVersion, ClientVersion clientVersion) { + NBTCodec.writeNBTToBuffer(buffer.getBuffer(), serverVersion, value); + } + } static final class GameMode implements BinaryBufferType { @Override @@ -268,4 +334,40 @@ public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.protoco ByteBufHelper.writeByte(buffer.getBuffer(), id); } } + static final class Dimension implements BinaryBufferType { + + @Override + public com.github.retrooper.packetevents.protocol.world.Dimension read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_20_5)) { + return new com.github.retrooper.packetevents.protocol.world.Dimension( + buffer.read(BinaryBuffer.VAR_INT)); + } + if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_19) + || serverVersion.isOlderThan(ServerVersion.V_1_16_2)) { + com.github.retrooper.packetevents.protocol.world.Dimension dimension = new com.github.retrooper.packetevents.protocol.world.Dimension(new NBTCompound()); + dimension.setDimensionName(buffer.read(BinaryBuffer.IDENTIFIER).toString()); + return dimension; + } else { + NBTCompound attrib = buffer.read(BinaryBuffer.NBT); + return new com.github.retrooper.packetevents.protocol.world.Dimension(attrib); + } + } + + @Override + public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.protocol.world.Dimension value, ServerVersion serverVersion, ClientVersion clientVersion) { + if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_20_5)) { + buffer.write(BinaryBuffer.VAR_INT, value.getId()); + return; + } + if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_19) + || serverVersion.isOlderThan(ServerVersion.V_1_16_2)) { + buffer.write(BinaryBuffer.STRING, value.getDimensionName()); + } else { + buffer.write(BinaryBuffer.NBT, value.getAttributes()); + } + } + } + + + } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 14fa37b6bc..516844df01 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -1010,6 +1010,9 @@ public void writeEntityMetadata(EntityMetadataProvider metadata) { @Deprecated public Dimension readDimension() { + if (true) { + return binaryBuffer.read(BinaryBuffer.DIMENSION); + } if (this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_20_5)) { return new Dimension(this.readVarInt()); } @@ -1025,6 +1028,10 @@ public Dimension readDimension() { @Deprecated public void writeDimension(Dimension dimension) { + if (true) { + binaryBuffer.write(BinaryBuffer.DIMENSION, dimension); + return; + } if (this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_20_5)) { this.writeVarInt(dimension.getId()); return; From 0a8c2e0b9b63793eda3f7fea13fc6a1323f6b8bf Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 11:59:05 +0400 Subject: [PATCH 07/10] add javadocs to BinaryBuffer --- .../packetevents/binary/BinaryBuffer.java | 252 +++++++++++++++++- .../binary/BinaryBufferTypes.java | 36 +++ .../packetevents/wrapper/PacketWrapper.java | 7 + 3 files changed, 289 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index cb90a8992c..1a6de188e3 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -10,6 +10,7 @@ import com.github.retrooper.packetevents.protocol.world.Dimension; import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Vector3i; +import com.github.retrooper.packetevents.util.crypto.SaltSignature; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import java.util.*; @@ -35,15 +36,16 @@ public final class BinaryBuffer { public static final BinaryBufferType BLOCK_POSITION = new BinaryBufferTypes.BlockPos(); public static final BinaryBufferType GAME_MODE = new BinaryBufferTypes.GameMode(); public static final BinaryBufferType IDENTIFIER = new BinaryBufferTypes.Identifier(); + public static final BinaryBufferType SALT_SIGNATURE = new BinaryBufferTypes.Salt(); public static final BinaryBufferType NBT_RAW = new BinaryBufferTypes.NbtRaw(); public static final BinaryBufferType NBT = new BinaryBufferTypes.Nbt(); - public static final BinaryBufferType NBT_RAW_UNLIMITED = new BinaryBufferTypes.NbtRawUnlimited(); public static final BinaryBufferType NBT_UNLIMITED = new BinaryBufferTypes.NbtUnlimited(); @Deprecated() /** Use {@link BinaryBuffer#DIMENSION_TYPE} instead */ + // TODO: Make DIMENSION_TYPE public static final BinaryBufferType DIMENSION = new BinaryBufferTypes.Dimension(); public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); @@ -53,10 +55,19 @@ public static BinaryBufferType SizedString(int maxSize) { private Object buffer; + /** + * Creates a new BinaryBuffer instance with the specified buffer object. This object is specified by the platform's netty ByteBuf + * @param buffer the underlying buffer object, typically a ByteBuf or similar. + */ public BinaryBuffer(Object buffer) { this.buffer = buffer; } + /** + * Creates a new BinaryBuffer instance with the specified capacity and whether it should be IO or direct. + * @param capacity the initial capacity of the buffer + * @param io whether the buffer should be an IO buffer (true) or a direct buffer (false) + */ public BinaryBuffer(int capacity, boolean io) { if (io) { this.buffer = PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().buffer(capacity); @@ -66,47 +77,137 @@ public BinaryBuffer(int capacity, boolean io) { } } + /** + * Creates a new BinaryBuffer instance with the specified capacity, using an IO buffer by default. + * @param capacity the initial capacity of the buffer + */ public BinaryBuffer(int capacity) { this(capacity, true); } + /** + * Creates a new BinaryBuffer instance that wraps the provided byte array. + * @param wrappedData the byte array to wrap in the buffer + */ public BinaryBuffer(byte[] wrappedData) { this.buffer = PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().wrappedBuffer(wrappedData); } - /** Buffer Operations **/ + /** + * Resets the reader index of the underlying buffer. + */ public void resetReaderIndex() { ByteBufHelper.resetReaderIndex(buffer); } + + /** + * Resets the writer index of the underlying buffer. + */ public void resetWriterIndex() { ByteBufHelper.resetWriterIndex(buffer); } + + /** + * Clears the underlying buffer, resetting both reader and writer indices. + */ public void reset() { ByteBufHelper.clear(buffer); } + /** + * Reads a raw byte array from the underlying buffer. + * @param length the length of the byte array to read + * @return the byte array read from the buffer, or an empty array if a read is unsuccessful. + */ + public byte[] readBytes(int length) { + byte[] bytes = new byte[length]; + ByteBufHelper.readBytes(buffer, bytes); + return bytes; + } - /** Primitive Read/Write Methods **/ + /** + * Writes a raw byte array to the underlying buffer. + * @param array the byte array to write to the buffer + */ + public void writeBytes(byte[] array) { + ByteBufHelper.writeBytes(buffer, array); + } + + /** + * Reads a {@link BinaryBufferType} + * @param type the type to read + * @param serverVersion the server version to read the type for, these are important in specific cases. + * @param clientVersion the client version to read the type for, these are important in specific cases. + * @return The value read from the buffer. Will always return an instance of the type specified's generic, or throw an exception if the read fails. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public T read(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { return type.read(this, serverVersion, clientVersion); } + + /** + * Reads a {@link BinaryBufferType} while automatically determining the server version based on the current server manager. + * @param type the type to read + * @param clientVersion the client version to read the type for, these are important in specific cases. + * @return The value read from the buffer. Will always return an instance of the type specified's generic, or throw an exception if the read fails. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public T read(BinaryBufferType type, ClientVersion clientVersion) { return type.read(this, clientVersion); } + + /** + * Reads a {@link BinaryBufferType} while automatically determining the server and client versions based on the current server manager. + * @param type the type to read + * @return The value read from the buffer. Will always return an instance of the type specified's generic, or throw an exception if the read fails. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public T read(BinaryBufferType type) { return type.read(this); } + + /** + * Writes a value to the underlying buffer using the specified {@link BinaryBufferType}. + * @param type the type to write + * @param value the value to write to the buffer + * @param serverVersion the server version to write the type for, these are important in specific cases. + * @param clientVersion the client version to write the type for, these are important in specific cases. + * @param the type to write, this is the generic of the {@link BinaryBufferType} specified. + */ public void write(BinaryBufferType type, T value, ServerVersion serverVersion, ClientVersion clientVersion) { type.write(this, value, serverVersion, clientVersion); } + + /** + * Writes a value to the underlying buffer using the specified {@link BinaryBufferType} while automatically determining the server version based on the current server manager. + * @param type the type to write + * @param value the value to write to the buffer + * @param clientVersion the client version to write the type for, these are important in specific cases. + * @param the type to write, this is the generic of the {@link BinaryBufferType} specified. + */ public void write(BinaryBufferType type, T value, ClientVersion clientVersion) { type.write(this, value, clientVersion); } + + /** + * Writes a value to the underlying buffer using the specified {@link BinaryBufferType} while automatically determining the server and client versions based on the current server manager. + * @param type the type to write + * @param value the value to write to the buffer + * @param the type to write, this is the generic of the {@link BinaryBufferType} specified. + */ public void write(BinaryBufferType type, T value) { type.write(this, value); } - /** Collection Read/Write Methods **/ + /** + * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification. + * @param maxSize the maximum size of the collection to read, if the size exceeds this value an {@link IllegalArgumentException} will be thrown. + * @param type the type to read from the buffer + * @param serverVersion the server version to read the type for, these are important in specific cases These get passed into the type. + * @param clientVersion the client version to read the type for, these are important in specific cases These get passed into the type. + * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public Collection readCollection(int maxSize, BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { int size = read(VAR_INT, serverVersion, clientVersion); if (size > maxSize) { @@ -118,36 +219,111 @@ public Collection readCollection(int maxSize, BinaryBufferType type, Se } return list; } + + + /** + * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server version based on the current server manager. + * @param maxSize the maximum size of the collection to read, if the size exceeds this value an {@link IllegalArgumentException} will be thrown. + * @param type the type to read from the buffer + * @param clientVersion the client version to read the type for, these are important in specific cases These get passed into the type. + * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public Collection readCollection(int maxSize, BinaryBufferType type, ClientVersion clientVersion) { return readCollection(maxSize, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); } + + /** + * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server and client versions based on the current server manager. + * @param maxSize the maximum size of the collection to read, if the size exceeds this value an {@link IllegalArgumentException} will be thrown. + * @param type the type to read from the buffer + * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public Collection readCollection(int maxSize, BinaryBufferType type) { return readCollection(maxSize, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); } + + /** + * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification with a maximum size of {@link Short#MAX_VALUE}. + * @param type the type to read from the buffer + * @param serverVersion the server version to read the type for, these are important in specific cases These get passed into the type. + * @param clientVersion the client version to read the type for, these are important in specific cases These get passed into the type. + * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public Collection readCollection(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { return readCollection(Short.MAX_VALUE, type, serverVersion, clientVersion); } + + /** + * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification with a maximum size of {@link Short#MAX_VALUE} while automatically determining the server version based on the current server manager. + * @param type the type to read from the buffer + * @param clientVersion the client version to read the type for, these are important in specific cases These get passed into the type. + * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public Collection readCollection(BinaryBufferType type, ClientVersion clientVersion) { return readCollection(Short.MAX_VALUE, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); } + + /** + * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification with a maximum size of {@link Short#MAX_VALUE} while automatically determining the server and client versions based on the current server manager. + * @param type the type to read from the buffer + * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. + * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. + */ public Collection readCollection(BinaryBufferType type) { return readCollection(Short.MAX_VALUE, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); } + /** + * Writes a collection using {@link BinaryBuffer#VAR_INT} for the size specification. + * @param collection the collection to write to the buffer + * @param type the type to write to the buffer + * @param serverVersion the server version to write the type for, these are important in specific cases These get passed into the type. + * @param clientVersion the client version to write the type for, these are important in specific cases These get passed into the type. + * @param the type to write, this is the generic of the {@link BinaryBufferType} specified. + */ public void writeCollection(Collection collection, BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { write(VAR_INT, collection.size(), serverVersion, clientVersion); for (T t : collection) { write(type, t, serverVersion, clientVersion); } } + + /** + * Writes a collection using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server version based on the current server manager. + * @param collection the collection to write to the buffer + * @param type the type to write to the buffer + * @param clientVersion the client version to write the type for, these are important in specific cases These get passed into the type. + * @param the type to write, this is the generic of the {@link BinaryBufferType} specified. + */ public void writeCollection(Collection collection, BinaryBufferType type, ClientVersion clientVersion) { writeCollection(collection, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); } + + /** + * Writes a collection using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server and client versions based on the current server manager. + * @param collection the collection to write to the buffer + * @param type the type to write to the buffer + * @param the type to write, this is the generic of the {@link BinaryBufferType} specified. + */ public void writeCollection(Collection collection, BinaryBufferType type) { writeCollection(collection, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); } - /** Map Read/Write Methods **/ + + /** + * Writes a map to the underlying buffer using {@link BinaryBuffer#VAR_INT} for the size specification. Every iteration it reads the keyType, and then the valueType + * @param keyType the type to read the keys from the buffer + * @param valueType the type to read the values from the buffer + * @param serverVersion the server version to read the type for, these are important in specific cases These get passed into the type. + * @param clientVersion the client version to read the type for, these are important in specific cases These get passed into the type. + * @return a map of the specified types read from the buffer, or an empty map if the read is unsuccessful. {@link Map} + * @param the type to read the keys, this is the generic of the {@link BinaryBufferType} specified for keys. + * @param the type to read the values, this is the generic of the {@link BinaryBufferType} specified for values. + */ public Map readMap(BinaryBufferType keyType, BinaryBufferType valueType, ServerVersion serverVersion, ClientVersion clientVersion) { int size = read(VAR_INT, serverVersion, clientVersion); Map map = new HashMap<>(size); @@ -158,13 +334,42 @@ public Map readMap(BinaryBufferType keyType, BinaryBufferType } return map; } + + /** + * Reads a map from the underlying buffer using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server version based on the current server manager. + * @param keyType the type to read the keys from the buffer + * @param valueType the type to read the values from the buffer + * @param clientVersion the client version to read the type for, these are important in specific cases These get passed into the type. + * @return a map of the specified types read from the buffer, or an empty map if the read is unsuccessful. {@link Map} + * @param the type to read the keys, this is the generic of the {@link BinaryBufferType} specified for keys. + * @param the type to read the values, this is the generic of the {@link BinaryBufferType} specified for values. + */ public Map readMap(BinaryBufferType keyType, BinaryBufferType valueType, ClientVersion clientVersion) { return readMap(keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); } + + /** + * Reads a map from the underlying buffer using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server and client versions based on the current server manager. + * @param keyType the type to read the keys from the buffer + * @param valueType the type to read the values from the buffer + * @return a map of the specified types read from the buffer, or an empty map if the read is unsuccessful. {@link Map} + * @param the type to read the keys, this is the generic of the {@link BinaryBufferType} specified for keys. + * @param the type to read the values, this is the generic of the {@link BinaryBufferType} specified for values. + */ public Map readMap(BinaryBufferType keyType, BinaryBufferType valueType) { return readMap(keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); } + /** + * Writes a map to the underlying buffer using {@link BinaryBuffer#VAR_INT} for the size specification. Every iteration it writes the keyType, and then the valueType + * @param map the map to write to the buffer + * @param keyType the type to write the keys to the buffer + * @param valueType the type to write the values to the buffer + * @param serverVersion the server version to write the type for, these are important in specific cases These get passed into the type. + * @param clientVersion the client version to write the type for, these are important in specific cases These get passed into the type. + * @param the type to write the keys, this is the generic of the {@link BinaryBufferType} specified for keys. + * @param the type to write the values, this is the generic of the {@link BinaryBufferType} specified for values. + */ public void writeMap(Map map, BinaryBufferType keyType, BinaryBufferType valueType, ServerVersion serverVersion, ClientVersion clientVersion) { write(VAR_INT, map.size(), serverVersion, clientVersion); for (Map.Entry entry : map.entrySet()) { @@ -172,14 +377,39 @@ public void writeMap(Map map, BinaryBufferType keyType, BinaryBu write(valueType, entry.getValue(), serverVersion, clientVersion); } } + + /** + * Writes a map to the underlying buffer using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server version based on the current server manager. + * @param map the map to write to the buffer + * @param keyType the type to write the keys to the buffer + * @param valueType the type to write the values to the buffer + * @param clientVersion the client version to write the type for, these are important in specific cases These get passed into the type. + * @param the type to write the keys, this is the generic of the {@link BinaryBufferType} specified for keys. + * @param the type to write the values, this is the generic of the {@link BinaryBufferType} specified for values. + */ public void writeMap(Map map, BinaryBufferType keyType, BinaryBufferType valueType, ClientVersion clientVersion) { writeMap(map, keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); } + + /** + * Writes a map to the underlying buffer using {@link BinaryBuffer#VAR_INT} for the size specification while automatically determining the server and client versions based on the current server manager. + * @param map the map to write to the buffer + * @param keyType the type to write the keys to the buffer + * @param valueType the type to write the values to the buffer + * @param the type to write the keys, this is the generic of the {@link BinaryBufferType} specified for keys. + * @param the type to write the values, this is the generic of the {@link BinaryBufferType} specified for values. + */ public void writeMap(Map map, BinaryBufferType keyType, BinaryBufferType valueType) { writeMap(map, keyType, valueType, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); } - /** Enums Read/Write Methods **/ + + /** + * Reads an enum value from the underlying buffer using its ordinal. The ordinal is read using {@link BinaryBuffer#VAR_INT}. + * @param enumClass the class of the enum to read + * @return the enum value read from the buffer, or throws an {@link IllegalArgumentException} if the ordinal is invalid. + * @param the type of the enum to read, this is the generic of the enum class specified. + */ public > T readEnum(Class enumClass) { T[] constants = enumClass.getEnumConstants(); int ordinal = read(VAR_INT); @@ -188,10 +418,20 @@ public > T readEnum(Class enumClass) { } return constants[ordinal]; } + + /** + * Writes an enum value to the underlying buffer using its ordinal. The ordinal is written using {@link BinaryBuffer#VAR_INT}. + * @param value the enum value to write to the buffer + * @param the type of the enum to write, this is the generic of the enum class specified. + */ public > void writeEnum(T value) { write(VAR_INT, value.ordinal()); } + /** + * Returns the underlying buffer object. These should rarely be used outside packetevents internals. + * @return the underlying buffer object, typically a ByteBuf or similar. + */ public Object getBuffer() { return buffer; } diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index 72e82416b7..eed922d1c9 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -11,6 +11,7 @@ import com.github.retrooper.packetevents.protocol.world.Dimension; import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Vector3i; +import com.github.retrooper.packetevents.util.crypto.SaltSignature; import java.nio.charset.StandardCharsets; @@ -368,6 +369,41 @@ public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.protoco } } + static final class Salt implements BinaryBufferType { + + @Override + public SaltSignature read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + long salt = buffer.read(BinaryBuffer.LONG); + byte[] signature; + //1.19.3+ + if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_19_3)) { + //Read optional signature + if (buffer.read(BinaryBuffer.BOOLEAN)) { + signature = buffer.readBytes(256); + } else { + signature = new byte[0]; + } + } else { + signature = readByteArray(256); + } + return new SaltSignature(salt, signature); } + + @Override + public void write(BinaryBuffer buffer, SaltSignature signature, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.LONG, signature.getSalt()); + if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_19_3)) { + boolean present = signature.getSignature().length != 0; + buffer.write(BinaryBuffer.BOOLEAN, present); + if (present) { + + writeBytes(signature.getSignature()); + } + + } else { + writeByteArray(signature.getSignature()); + } + } + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 516844df01..6c9a2217f0 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -1045,6 +1045,9 @@ public void writeDimension(Dimension dimension) { } public SaltSignature readSaltSignature() { + if (true) { + return binaryBuffer.read(BinaryBuffer.SALT_SIGNATURE); + } long salt = readLong(); byte[] signature; //1.19.3+ @@ -1062,6 +1065,10 @@ public SaltSignature readSaltSignature() { } public void writeSaltSignature(SaltSignature signature) { + if (true) { + binaryBuffer.write(BinaryBuffer.SALT_SIGNATURE, signature); + return; + } writeLong(signature.getSalt()); if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_19_3)) { boolean present = signature.getSignature().length != 0; From 1ea4c337ff1b6ff366b2395c3c23467c7506053f Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 13:30:14 +0400 Subject: [PATCH 08/10] keys, timestamps, profile keys --- .../packetevents/binary/BinaryBuffer.java | 71 +++++++++++++-- .../binary/BinaryBufferTypes.java | 86 ++++++++++++++++++- .../packetevents/wrapper/PacketWrapper.java | 21 +++++ 3 files changed, 170 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index 1a6de188e3..d0cc653e6d 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -7,16 +7,73 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.player.ClientVersion; import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.PublicProfileKey; import com.github.retrooper.packetevents.protocol.world.Dimension; import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.util.crypto.SaltSignature; import com.github.retrooper.packetevents.wrapper.PacketWrapper; +import java.security.PublicKey; +import java.time.Instant; import java.util.*; +/** + * BinaryBuffer is a utility class for reading and writing protocol data from the underlying buffer + * This class was created to replace heavy usage of {@link PacketWrapper} for reading and writing data. + * {@link BinaryBufferType} is the format used to read and write data from the buffer. + * It provides methods to read and write various data types, including primitive types, collections, maps, and custom types. + * Custom classes that are not defined in the {@link BinaryBufferTypes} class can be added by creating a new class that extends {@link BinaryBufferType}. + * This is the encouraged way to add new types to the buffer. + * Example usage: + *
+ *     class Person {
+ *         public static final BinaryBufferType TYPE = new Serializer();
+ *
+ *          public static Person read({@link BinaryBuffer} buffer, {@link ServerVersion} serverVersion, {@link ClientVersion} clientVersion) {
+ *              return buffer.read(TYPE, serverVersion, clientVersion);
+ *          }
+ *
+ *        private int id;
+ *         private String name;
+ *
+ *         public Person(int id, String name) {
+ *              this.id = id;
+ *              this.name = name;
+ *         }
+ *
+ *
+ *
+ *         class Serializer implements {@link BinaryBufferType} {
+ *
+ *           {@literal @}Override
+ *           public Person read({@link BinaryBuffer} buffer, {@link ServerVersion} serverVersion, {@link ClientVersion} clientVersion) {
+ *              int id = buffer.read(BinaryBuffer.INT, serverVersion, clientVersion);
+ *              String name = buffer.read(BinaryBuffer.STRING, serverVersion, clientVersion);
+ *              return new Person(id, name);
+ *         }
+ *
+ *         {@literal @}Override
+ *         public void write({@link BinaryBuffer} buffer, Person value, {@link ServerVersion} serverVersion, {@link ClientVersion} clientVersion) {
+ *              buffer.write(BinaryBuffer.INT, value.getId(), serverVersion, clientVersion);
+ *              buffer.write(BinaryBuffer.STRING, value.getName(), serverVersion, clientVersion);
+ *         }
+ *
+ *     }
+ *
+ * 
+ * + * TODO's: + * - Add more types to the {@link BinaryBufferTypes} class. + * - Convert the types like BYTE_ARRAY, INT_ARRAY, etc to a more reusable method, same with collections + */ public final class BinaryBuffer { + public static final BinaryBufferType BYTE_ARRAY = new BinaryBufferTypes.ByteArray(); + public static BinaryBufferType SizedByteArray(int maxSize) { + return new BinaryBufferTypes.ByteArray(maxSize); + } + public static final BinaryBufferType BYTE = new BinaryBufferTypes.Byte(); public static final BinaryBufferType UBYTE = new BinaryBufferTypes.UByte(); public static final BinaryBufferType BOOLEAN = new BinaryBufferTypes.Bool(); @@ -37,17 +94,21 @@ public final class BinaryBuffer { public static final BinaryBufferType GAME_MODE = new BinaryBufferTypes.GameMode(); public static final BinaryBufferType IDENTIFIER = new BinaryBufferTypes.Identifier(); public static final BinaryBufferType SALT_SIGNATURE = new BinaryBufferTypes.Salt(); + public static final BinaryBufferType PUBLIC_KEY = new BinaryBufferTypes.Publickey(); + public static final BinaryBufferType TIMESTAMP = new BinaryBufferTypes.Timestamp(); + public static final BinaryBufferType PUBLIC_PROFILE_KEY = new BinaryBufferTypes.ProfileKey(); + + /** + * Use {@link BinaryBuffer#DIMENSION_TYPE} instead + */ + @Deprecated() + public static final BinaryBufferType DIMENSION = new BinaryBufferTypes.Dimension(); public static final BinaryBufferType NBT_RAW = new BinaryBufferTypes.NbtRaw(); public static final BinaryBufferType NBT = new BinaryBufferTypes.Nbt(); public static final BinaryBufferType NBT_RAW_UNLIMITED = new BinaryBufferTypes.NbtRawUnlimited(); public static final BinaryBufferType NBT_UNLIMITED = new BinaryBufferTypes.NbtUnlimited(); - @Deprecated() - /** Use {@link BinaryBuffer#DIMENSION_TYPE} instead */ - // TODO: Make DIMENSION_TYPE - public static final BinaryBufferType DIMENSION = new BinaryBufferTypes.Dimension(); - public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); public static BinaryBufferType SizedString(int maxSize) { return new BinaryBufferTypes.String(maxSize); diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index eed922d1c9..a42ec0e63e 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -8,12 +8,16 @@ import com.github.retrooper.packetevents.protocol.nbt.codec.NBTCodec; import com.github.retrooper.packetevents.protocol.player.ClientVersion; import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.PublicProfileKey; import com.github.retrooper.packetevents.protocol.world.Dimension; import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Vector3i; +import com.github.retrooper.packetevents.util.crypto.MinecraftEncryptionUtil; import com.github.retrooper.packetevents.util.crypto.SaltSignature; import java.nio.charset.StandardCharsets; +import java.security.PublicKey; +import java.time.Instant; final class BinaryBufferTypes { @@ -368,9 +372,40 @@ public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.protoco } } } + static final class ByteArray implements BinaryBufferType { + private static final int MAX_LENGTH = 32767; // 2^15 - 1 + private final int maxLength; + public ByteArray(int maxLength) { + if (maxLength < 0 || maxLength > MAX_LENGTH) { + throw new IllegalArgumentException("ByteArray length must be between 0 and " + MAX_LENGTH + ", but was " + maxLength); + } + this.maxLength = maxLength; + } + + public ByteArray() { + this(MAX_LENGTH); + } + + @Override + public byte[] read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + int len = buffer.read(BinaryBuffer.VAR_INT, serverVersion, clientVersion); + if (len < 0 || len > maxLength) { + throw new RuntimeException("The received byte array length is invalid (" + len + " > " + maxLength + ")"); + } + return buffer.readBytes(len); + } + + @Override + public void write(BinaryBuffer buffer, byte[] value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.VAR_INT, value.length, serverVersion, clientVersion); + buffer.writeBytes(value); + } + } static final class Salt implements BinaryBufferType { + private static final BinaryBufferType BYTE_ARRAY = new ByteArray(256); + @Override public SaltSignature read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { long salt = buffer.read(BinaryBuffer.LONG); @@ -384,7 +419,7 @@ public SaltSignature read(BinaryBuffer buffer, ServerVersion serverVersion, Clie signature = new byte[0]; } } else { - signature = readByteArray(256); + signature = buffer.read(BYTE_ARRAY); } return new SaltSignature(salt, signature); } @@ -396,14 +431,59 @@ public void write(BinaryBuffer buffer, SaltSignature signature, ServerVersion se buffer.write(BinaryBuffer.BOOLEAN, present); if (present) { - writeBytes(signature.getSignature()); + buffer.writeBytes(signature.getSignature()); } } else { - writeByteArray(signature.getSignature()); + buffer.write(BYTE_ARRAY, signature.getSignature(), serverVersion, clientVersion); } } } + static final class Publickey implements BinaryBufferType { + + private static final BinaryBufferType BYTE_ARRAY = new ByteArray(512); + + @Override + public PublicKey read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return MinecraftEncryptionUtil.publicKey( + buffer.read(BinaryBuffer.BYTE_ARRAY, serverVersion, clientVersion) + ); + } + + @Override + public void write(BinaryBuffer buffer, PublicKey value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BYTE_ARRAY, value.getEncoded()); + } + } + static final class Timestamp implements BinaryBufferType { + @Override + public Instant read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return Instant.ofEpochMilli(buffer.read(BinaryBuffer.LONG, serverVersion, clientVersion)); + } + @Override + public void write(BinaryBuffer buffer, Instant value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.LONG, value.toEpochMilli(), serverVersion, clientVersion); + } + } + static final class ProfileKey implements BinaryBufferType { + + private static final BinaryBufferType BYTE_ARRAY = new ByteArray(4096); + + @Override + public PublicProfileKey read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + Instant expiresAt = buffer.read(BinaryBuffer.TIMESTAMP, serverVersion, clientVersion); + PublicKey publicKey = buffer.read(BinaryBuffer.PUBLIC_KEY, serverVersion, clientVersion); + byte[] signature = buffer.read(BYTE_ARRAY, serverVersion, clientVersion); + return new PublicProfileKey(expiresAt, publicKey, signature); + } + + @Override + public void write(BinaryBuffer buffer, PublicProfileKey value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.TIMESTAMP, value.getExpiresAt(), serverVersion, clientVersion); + buffer.write(BinaryBuffer.PUBLIC_KEY, value.getKey(), serverVersion, clientVersion); + buffer.write(BYTE_ARRAY, value.getKeySignature(), serverVersion, clientVersion); + } + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 6c9a2217f0..6237aed1ad 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -1083,14 +1083,24 @@ public void writeSaltSignature(SaltSignature signature) { } public PublicKey readPublicKey() { + if (true) { + return binaryBuffer.read(BinaryBuffer.PUBLIC_KEY); + } return MinecraftEncryptionUtil.publicKey(readByteArray(512)); } public void writePublicKey(PublicKey publicKey) { + if (true) { + binaryBuffer.write(BinaryBuffer.PUBLIC_KEY, publicKey); + return; + } writeByteArray(publicKey.getEncoded()); } public PublicProfileKey readPublicProfileKey() { + if (true) { + return binaryBuffer.read(BinaryBuffer.PUBLIC_PROFILE_KEY); + } Instant expiresAt = readTimestamp(); PublicKey key = readPublicKey(); byte[] keySignature = readByteArray(4096); @@ -1098,6 +1108,10 @@ public PublicProfileKey readPublicProfileKey() { } public void writePublicProfileKey(PublicProfileKey key) { + if (true) { + binaryBuffer.write(BinaryBuffer.PUBLIC_PROFILE_KEY, key); + return; + } writeTimestamp(key.getExpiresAt()); writePublicKey(key.getKey()); writeByteArray(key.getKeySignature()); @@ -1113,10 +1127,17 @@ public void writeRemoteChatSession(RemoteChatSession chatSession) { } public Instant readTimestamp() { + if (true) { + return binaryBuffer.read(BinaryBuffer.TIMESTAMP); + } return Instant.ofEpochMilli(readLong()); } public void writeTimestamp(Instant timestamp) { + if (true) { + binaryBuffer.write(BinaryBuffer.TIMESTAMP, timestamp); + return; + } writeLong(timestamp.toEpochMilli()); } From b0a5de9a8828c2865c9bdf61ecc95fca7e4dde51 Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 16:22:43 +0400 Subject: [PATCH 09/10] either conversion --- .../packetevents/binary/BinaryBuffer.java | 114 +++++++++++++++++- .../binary/BinaryBufferTypes.java | 61 ++++++++++ .../settings/PacketEventsSettings.java | 21 ++++ .../packetevents/wrapper/PacketWrapper.java | 106 +++++++++++----- 4 files changed, 264 insertions(+), 38 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index d0cc653e6d..d1df0ba161 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -3,6 +3,7 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.mapper.MappedEntity; import com.github.retrooper.packetevents.protocol.nbt.NBT; import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.player.ClientVersion; @@ -10,8 +11,11 @@ import com.github.retrooper.packetevents.protocol.player.PublicProfileKey; import com.github.retrooper.packetevents.protocol.world.Dimension; import com.github.retrooper.packetevents.resources.ResourceLocation; +import com.github.retrooper.packetevents.util.Either; import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.util.crypto.SaltSignature; +import com.github.retrooper.packetevents.util.crypto.SignatureData; +import com.github.retrooper.packetevents.util.mappings.IRegistry; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import java.security.PublicKey; @@ -70,7 +74,7 @@ public final class BinaryBuffer { public static final BinaryBufferType BYTE_ARRAY = new BinaryBufferTypes.ByteArray(); - public static BinaryBufferType SizedByteArray(int maxSize) { + public static BinaryBufferType BYTE_ARRAY(int maxSize) { return new BinaryBufferTypes.ByteArray(maxSize); } @@ -97,6 +101,11 @@ public static BinaryBufferType SizedByteArray(int maxSize) { public static final BinaryBufferType PUBLIC_KEY = new BinaryBufferTypes.Publickey(); public static final BinaryBufferType TIMESTAMP = new BinaryBufferTypes.Timestamp(); public static final BinaryBufferType PUBLIC_PROFILE_KEY = new BinaryBufferTypes.ProfileKey(); + public static final BinaryBufferType SIGNATURE_DATA = new BinaryBufferTypes.SignatureData(); + + public static BinaryBufferType MAPPED_ENTITY(IRegistry registry) { + return new BinaryBufferTypes.MappedEntity<>(registry); + } /** * Use {@link BinaryBuffer#DIMENSION_TYPE} instead @@ -110,7 +119,7 @@ public static BinaryBufferType SizedByteArray(int maxSize) { public static final BinaryBufferType NBT_UNLIMITED = new BinaryBufferTypes.NbtUnlimited(); public static final BinaryBufferType STRING = new BinaryBufferTypes.String(); - public static BinaryBufferType SizedString(int maxSize) { + public static BinaryBufferType STRING(int maxSize) { return new BinaryBufferTypes.String(maxSize); } @@ -227,6 +236,53 @@ public T read(BinaryBufferType type) { return type.read(this); } + + /** Reads an {@link Either} from the underlying buffer, where the first value is read as a boolean to determine if it is a left or right value. + * If the boolean is true, the left value is read using the specified leftType, otherwise the right value is read using the specified rightType. + * @param leftType the type to read the left value from the buffer + * @param rightType the type to read the right value from the buffer + * @param serverVersion the server version to read the type for, these are important in specific cases. + * @param clientVersion the client version to read the type for, these are important in specific cases. + * @return an Either containing a left or right value based on the boolean read from the buffer. + * @param the type of the left value, this is the generic of the {@link BinaryBufferType} specified for left values. + * @param the type of the right value, this is the generic of the {@link BinaryBufferType} specified for right values. + */ + public Either readEither(BinaryBufferType leftType, BinaryBufferType rightType, ServerVersion serverVersion, ClientVersion clientVersion) { + boolean isLeft = read(BOOLEAN, serverVersion, clientVersion); + if (isLeft) { + return Either.createLeft(read(leftType, serverVersion, clientVersion)); + } else { + return Either.createRight(read(rightType, serverVersion, clientVersion)); + } + } + + /** Reads an {@link Either} from the underlying buffer, where the first value is read as a boolean to determine if it is a left or right value. + * If the boolean is true, the left value is read using the specified leftType, otherwise the right value is read using the specified rightType. + * while automatically determining the server version based on the current server manager. + * @param leftType the type to read the left value from the buffer + * @param rightType the type to read the right value from the buffer + * @param clientVersion the client version to read the type for, these are important in specific cases. + * @return an Either containing a left or right value based on the boolean read from the buffer. + * @param the type of the left value, this is the generic of the {@link BinaryBufferType} specified for left values. + * @param the type of the right value, this is the generic of the {@link BinaryBufferType} specified for right values. + */ + public Either readEither(BinaryBufferType leftType, BinaryBufferType rightType, ClientVersion clientVersion) { + return readEither(leftType, rightType, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + + /** Reads an {@link Either} from the underlying buffer, where the first value is read as a boolean to determine if it is a left or right value. + * If the boolean is true, the left value is read using the specified leftType, otherwise the right value is read using the specified rightType. + * while automatically determining the server and client versions based on the current server manager. + * @param leftType the type to read the left value from the buffer + * @param rightType the type to read the right value from the buffer + * @return an Either containing a left or right value based on the boolean read from the buffer. + * @param the type of the left value, this is the generic of the {@link BinaryBufferType} specified for left values. + * @param the type of the right value, this is the generic of the {@link BinaryBufferType} specified for right values. + */ + public Either readEither(BinaryBufferType leftType, BinaryBufferType rightType) { + return readEither(leftType, rightType, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + /** * Writes a value to the underlying buffer using the specified {@link BinaryBufferType}. * @param type the type to write @@ -260,6 +316,54 @@ public void write(BinaryBufferType type, T value) { type.write(this, value); } + /** Writes an {@link Either} to the underlying buffer, where the first value is written as a boolean to determine if it is a left or right value. + * If the boolean is true, the left value is written using the specified leftType, otherwise the right value is written using the specified rightType. + * @param either the Either to write to the buffer + * @param leftType the type to write the left value to the buffer + * @param rightType the type to write the right value to the buffer + * @param serverVersion the server version to write the type for, these are important in specific cases. + * @param clientVersion the client version to write the type for, these are important in specific cases. + * @param the type of the left value, this is the generic of the {@link BinaryBufferType} specified for left values. + * @param the type of the right value, this is the generic of the {@link BinaryBufferType} specified for right values. + */ + public void writeEither(Either either, BinaryBufferType leftType, BinaryBufferType rightType, ServerVersion serverVersion, ClientVersion clientVersion) { + if (either.isLeft()) { + write(BOOLEAN, true, serverVersion, clientVersion); + write(leftType, either.getLeft(), serverVersion, clientVersion); + } else { + write(BOOLEAN, false, serverVersion, clientVersion); + write(rightType, either.getRight(), serverVersion, clientVersion); + } + } + + /** Writes an {@link Either} to the underlying buffer, where the first value is written as a boolean to determine if it is a left or right value. + * If the boolean is true, the left value is written using the specified leftType, otherwise the right value is written using the specified rightType. + * while automatically determining the server version based on the current server manager. + * @param either the Either to write to the buffer + * @param leftType the type to write the left value to the buffer + * @param rightType the type to write the right value to the buffer + * @param clientVersion the client version to write the type for, these are important in specific cases. + * @param the type of the left value, this is the generic of the {@link BinaryBufferType} specified for left values. + * @param the type of the right value, this is the generic of the {@link BinaryBufferType} specified for right values. + */ + public void writeEither(Either either, BinaryBufferType leftType, BinaryBufferType rightType, ClientVersion clientVersion) { + writeEither(either, leftType, rightType, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); + } + + /** Writes an {@link Either} to the underlying buffer, where the first value is written as a boolean to determine if it is a left or right value. + * If the boolean is true, the left value is written using the specified leftType, otherwise the right value is written using the specified rightType. + * while automatically determining the server and client versions based on the current server manager. + * @param either the Either to write to the buffer + * @param leftType the type to write the left value to the buffer + * @param rightType the type to write the right value to the buffer + * @param the type of the left value, this is the generic of the {@link BinaryBufferType} specified for left values. + * @param the type of the right value, this is the generic of the {@link BinaryBufferType} specified for right values. + */ + public void writeEither(Either either, BinaryBufferType leftType, BinaryBufferType rightType) { + writeEither(either, leftType, rightType, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); + } + + /** * Reads a collection using {@link BinaryBuffer#VAR_INT} for the size specification. * @param maxSize the maximum size of the collection to read, if the size exceeds this value an {@link IllegalArgumentException} will be thrown. @@ -313,7 +417,7 @@ public Collection readCollection(int maxSize, BinaryBufferType type) { * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. */ - public Collection readCollection(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { + public Collection readCollection(BinaryBufferType type, ServerVersion serverVersion, ClientVersion clientVersion) { return readCollection(Short.MAX_VALUE, type, serverVersion, clientVersion); } @@ -324,7 +428,7 @@ public Collection readCollection(BinaryBufferType type, ServerVersion s * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. */ - public Collection readCollection(BinaryBufferType type, ClientVersion clientVersion) { + public Collection readCollection(BinaryBufferType type, ClientVersion clientVersion) { return readCollection(Short.MAX_VALUE, type, PacketEvents.getAPI().getServerManager().getVersion(), clientVersion); } @@ -334,7 +438,7 @@ public Collection readCollection(BinaryBufferType type, ClientVersion c * @return a collection of the specified type read from the buffer, or an empty collection if the read is unsuccessful. * @param the type to read, this is the generic of the {@link BinaryBufferType} specified. */ - public Collection readCollection(BinaryBufferType type) { + public Collection readCollection(BinaryBufferType type) { return readCollection(Short.MAX_VALUE, type, PacketEvents.getAPI().getServerManager().getVersion(), PacketEvents.getAPI().getServerManager().getVersion().toClientVersion()); } diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index a42ec0e63e..6b0c040d9d 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -2,6 +2,8 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; +import com.github.retrooper.packetevents.protocol.chat.filter.FilterMaskType; +import com.github.retrooper.packetevents.protocol.mapper.MappedEntity; import com.github.retrooper.packetevents.protocol.nbt.NBT; import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.nbt.NBTLimiter; @@ -14,6 +16,9 @@ import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.util.crypto.MinecraftEncryptionUtil; import com.github.retrooper.packetevents.util.crypto.SaltSignature; +import com.github.retrooper.packetevents.util.crypto.SignatureData; +import com.github.retrooper.packetevents.util.mappings.IRegistry; +import com.github.retrooper.packetevents.util.mappings.IRegistryHolder; import java.nio.charset.StandardCharsets; import java.security.PublicKey; @@ -486,4 +491,60 @@ public void write(BinaryBuffer buffer, PublicProfileKey value, ServerVersion ser buffer.write(BYTE_ARRAY, value.getKeySignature(), serverVersion, clientVersion); } } + static final class SignatureData implements BinaryBufferType { + private static final BinaryBufferType BYTE_ARRAY = new ByteArray(4096); + + @Override + public com.github.retrooper.packetevents.util.crypto.SignatureData read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return new com.github.retrooper.packetevents.util.crypto.SignatureData( + buffer.read(BinaryBuffer.TIMESTAMP, serverVersion, clientVersion), + buffer.read(BinaryBuffer.PUBLIC_KEY, serverVersion, clientVersion), + buffer.read(BYTE_ARRAY, serverVersion, clientVersion) + ); + } + + @Override + public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.util.crypto.SignatureData value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.TIMESTAMP, value.getTimestamp(), serverVersion, clientVersion); + buffer.write(BinaryBuffer.PUBLIC_KEY, value.getPublicKey(), serverVersion, clientVersion); + buffer.write(BYTE_ARRAY, value.getSignature(), serverVersion, clientVersion); + } + } + + static final class MappedEntityDirect implements BinaryBufferType { + + @Override + public T read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return null; + } + + @Override + public void write(BinaryBuffer buffer, T value, ServerVersion serverVersion, ClientVersion clientVersion) { + + } + } + static final class MappedEntity implements BinaryBufferType { + + private final IRegistry registry; + private final IRegistryHolder registryHolder; + + MappedEntity(IRegistry registry, IRegistryHolder registryHolder) { + this.registry = registry; + this.registryHolder = registryHolder; + } + + @Override + public T read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + IRegistry replacedRegistry = registryHolder.getRegistryOr( + registry, serverVersion.toClientVersion() + ); + + } + + @Override + public void write(BinaryBuffer buffer, T value, ServerVersion serverVersion, ClientVersion clientVersion) { + + } + } + } diff --git a/api/src/main/java/com/github/retrooper/packetevents/settings/PacketEventsSettings.java b/api/src/main/java/com/github/retrooper/packetevents/settings/PacketEventsSettings.java index f01ba5f5e0..255d13e6fc 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/settings/PacketEventsSettings.java +++ b/api/src/main/java/com/github/retrooper/packetevents/settings/PacketEventsSettings.java @@ -40,6 +40,7 @@ public class PacketEventsSettings { private boolean fullStackTraceEnabled = false; private boolean kickOnPacketExceptionEnabled = true; private boolean kickIfTerminated = true; + private boolean useBinaryBuffer = false; private Function resourceProvider = path -> PacketEventsSettings.class .getClassLoader() .getResourceAsStream(path); @@ -56,6 +57,18 @@ public PacketEventsSettings timeStampMode(TimeStampMode timeStampMode) { return this; } + /** + * NOTE TO TOFAA: Delete this after testing phase. TODO + * Should we use the new binary buffer system in {@link com.github.retrooper.packetevents.wrapper.PacketWrapper} + * @param useBinaryBuffer True if we should use the binary buffer system, false otherwise. + * @return Settings instance + */ + @ApiStatus.Internal + public PacketEventsSettings useBinaryBuffer(boolean useBinaryBuffer) { + this.useBinaryBuffer = useBinaryBuffer; + return this; + } + /** * Do we re-encode all packets by default? * @@ -193,6 +206,14 @@ public boolean shouldDownsampleColors() { } + /** + * Should we use the new binary buffer system in {@link com.github.retrooper.packetevents.wrapper.PacketWrapper}? + * @return Getter for {@link #useBinaryBuffer} + */ + public boolean shouldUseBinaryBuffer() { + return useBinaryBuffer; + } + /** * Should we collect server data anonymously and report to bStats? * diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 6237aed1ad..95e6c5ba21 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -365,14 +365,16 @@ public void resetBuffer() { } public byte readByte() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.BYTE); } return ByteBufHelper.readByte(buffer); } public void writeByte(int value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.BYTE, (byte) value); return; } @@ -380,21 +382,24 @@ public void writeByte(int value) { } public short readUnsignedByte() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.UBYTE); } return ByteBufHelper.readUnsignedByte(buffer); } public boolean readBoolean() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.BOOLEAN); } return readByte() != 0; } public void writeBoolean(boolean value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.BOOLEAN, value); return; } @@ -402,14 +407,16 @@ public void writeBoolean(boolean value) { } public int readInt() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.INT); } return ByteBufHelper.readInt(buffer); } public void writeInt(int value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.INT, value); return; } @@ -417,14 +424,16 @@ public void writeInt(int value) { } public int readMedium() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.MEDIUM); } return ByteBufHelper.readMedium(buffer); } public void writeMedium(int value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.MEDIUM, value); return; } @@ -432,7 +441,8 @@ public void writeMedium(int value) { } public int readVarInt() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.VAR_INT); } int value = 0; @@ -450,7 +460,8 @@ public int readVarInt() { } public void writeVarInt(int value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.VAR_INT, value); return; } @@ -737,7 +748,8 @@ public void writeLong(long value) { } public long readVarLong() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.VAR_LONG); } long value = 0; @@ -750,7 +762,8 @@ public long readVarLong() { } public void writeVarLong(long l) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.VAR_LONG, l); return; } @@ -763,14 +776,16 @@ public void writeVarLong(long l) { } public float readFloat() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.FLOAT); } return ByteBufHelper.readFloat(buffer); } public void writeFloat(float value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.FLOAT, value); return; } @@ -778,14 +793,16 @@ public void writeFloat(float value) { } public double readDouble() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.DOUBLE); } return ByteBufHelper.readDouble(buffer); } public void writeDouble(double value) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.DOUBLE, value); return; } @@ -899,7 +916,7 @@ public void writeLongArray(long[] array) { } public UUID readUUID() { - if (true) { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.UUID); } long mostSigBits = readLong(); @@ -908,7 +925,8 @@ public UUID readUUID() { } public void writeUUID(UUID uuid) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.UUID, uuid); return; } @@ -917,7 +935,8 @@ public void writeUUID(UUID uuid) { } public Vector3i readBlockPosition() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.BLOCK_POSITION); } long val = readLong(); @@ -925,7 +944,8 @@ public Vector3i readBlockPosition() { } public void writeBlockPosition(Vector3i pos) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.BLOCK_POSITION, pos); return; } @@ -934,14 +954,16 @@ public void writeBlockPosition(Vector3i pos) { } public GameMode readGameMode() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.GAME_MODE); } return GameMode.getById(readByte()); } public void writeGameMode(@Nullable GameMode mode) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.GAME_MODE, mode); return; } @@ -1010,7 +1032,8 @@ public void writeEntityMetadata(EntityMetadataProvider metadata) { @Deprecated public Dimension readDimension() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.DIMENSION); } if (this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_20_5)) { @@ -1028,7 +1051,8 @@ public Dimension readDimension() { @Deprecated public void writeDimension(Dimension dimension) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.DIMENSION, dimension); return; } @@ -1045,7 +1069,8 @@ public void writeDimension(Dimension dimension) { } public SaltSignature readSaltSignature() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.SALT_SIGNATURE); } long salt = readLong(); @@ -1065,7 +1090,8 @@ public SaltSignature readSaltSignature() { } public void writeSaltSignature(SaltSignature signature) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.SALT_SIGNATURE, signature); return; } @@ -1083,14 +1109,16 @@ public void writeSaltSignature(SaltSignature signature) { } public PublicKey readPublicKey() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.PUBLIC_KEY); } return MinecraftEncryptionUtil.publicKey(readByteArray(512)); } public void writePublicKey(PublicKey publicKey) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.PUBLIC_KEY, publicKey); return; } @@ -1098,7 +1126,8 @@ public void writePublicKey(PublicKey publicKey) { } public PublicProfileKey readPublicProfileKey() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.PUBLIC_PROFILE_KEY); } Instant expiresAt = readTimestamp(); @@ -1108,7 +1137,8 @@ public PublicProfileKey readPublicProfileKey() { } public void writePublicProfileKey(PublicProfileKey key) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.PUBLIC_PROFILE_KEY, key); return; } @@ -1127,14 +1157,16 @@ public void writeRemoteChatSession(RemoteChatSession chatSession) { } public Instant readTimestamp() { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { return binaryBuffer.read(BinaryBuffer.TIMESTAMP); } return Instant.ofEpochMilli(readLong()); } public void writeTimestamp(Instant timestamp) { - if (true) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { binaryBuffer.write(BinaryBuffer.TIMESTAMP, timestamp); return; } @@ -1142,10 +1174,18 @@ public void writeTimestamp(Instant timestamp) { } public SignatureData readSignatureData() { + if (true) { + return binaryBuffer.read(BinaryBuffer.SIGNATURE_DATA); + } return new SignatureData(readTimestamp(), readPublicKey(), readByteArray(4096)); } public void writeSignatureData(SignatureData signatureData) { + + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + binaryBuffer.write(BinaryBuffer.SIGNATURE_DATA, signatureData); + return; + } writeTimestamp(signatureData.getTimestamp()); writePublicKey(signatureData.getPublicKey()); writeByteArray(signatureData.getSignature()); From 22e91451580e4c7915ae96815cdd9124945946ea Mon Sep 17 00:00:00 2001 From: Tofaa2 Date: Mon, 26 May 2025 17:44:49 +0400 Subject: [PATCH 10/10] world block pos --- .../packetevents/binary/BinaryBuffer.java | 9 ++-- .../binary/BinaryBufferTypes.java | 52 ++++++++++++++++++- .../protocol/item/ItemStackSerialization.java | 31 +++++++++++ .../packetevents/wrapper/PacketWrapper.java | 22 ++++++++ 4 files changed, 108 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java index d1df0ba161..c01c7c0515 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBuffer.java @@ -10,8 +10,10 @@ import com.github.retrooper.packetevents.protocol.player.GameMode; import com.github.retrooper.packetevents.protocol.player.PublicProfileKey; import com.github.retrooper.packetevents.protocol.world.Dimension; +import com.github.retrooper.packetevents.protocol.world.WorldBlockPosition; import com.github.retrooper.packetevents.resources.ResourceLocation; import com.github.retrooper.packetevents.util.Either; +import com.github.retrooper.packetevents.util.KnownPack; import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.util.crypto.SaltSignature; import com.github.retrooper.packetevents.util.crypto.SignatureData; @@ -95,6 +97,7 @@ public static BinaryBufferType BYTE_ARRAY(int maxSize) { public static final BinaryBufferType UUID = new BinaryBufferTypes.Uuid(); public static final BinaryBufferType BLOCK_POSITION = new BinaryBufferTypes.BlockPos(); + public static final BinaryBufferType WORLD_BLOCK_POSITION = new BinaryBufferTypes.WorldBlockPos(); public static final BinaryBufferType GAME_MODE = new BinaryBufferTypes.GameMode(); public static final BinaryBufferType IDENTIFIER = new BinaryBufferTypes.Identifier(); public static final BinaryBufferType SALT_SIGNATURE = new BinaryBufferTypes.Salt(); @@ -102,10 +105,8 @@ public static BinaryBufferType BYTE_ARRAY(int maxSize) { public static final BinaryBufferType TIMESTAMP = new BinaryBufferTypes.Timestamp(); public static final BinaryBufferType PUBLIC_PROFILE_KEY = new BinaryBufferTypes.ProfileKey(); public static final BinaryBufferType SIGNATURE_DATA = new BinaryBufferTypes.SignatureData(); - - public static BinaryBufferType MAPPED_ENTITY(IRegistry registry) { - return new BinaryBufferTypes.MappedEntity<>(registry); - } + public static final BinaryBufferType ROTATION = new BinaryBufferTypes.Rotation(); + public static final BinaryBufferType KNOWN_PACK = new BinaryBufferTypes.KnownPack(); /** * Use {@link BinaryBuffer#DIMENSION_TYPE} instead diff --git a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java index 6b0c040d9d..503d430125 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/binary/BinaryBufferTypes.java @@ -12,7 +12,10 @@ import com.github.retrooper.packetevents.protocol.player.GameMode; import com.github.retrooper.packetevents.protocol.player.PublicProfileKey; import com.github.retrooper.packetevents.protocol.world.Dimension; +import com.github.retrooper.packetevents.protocol.world.WorldBlockPosition; import com.github.retrooper.packetevents.resources.ResourceLocation; +import com.github.retrooper.packetevents.util.KnownPack; +import com.github.retrooper.packetevents.util.MathUtil; import com.github.retrooper.packetevents.util.Vector3i; import com.github.retrooper.packetevents.util.crypto.MinecraftEncryptionUtil; import com.github.retrooper.packetevents.util.crypto.SaltSignature; @@ -510,7 +513,6 @@ public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.util.cr buffer.write(BYTE_ARRAY, value.getSignature(), serverVersion, clientVersion); } } - static final class MappedEntityDirect implements BinaryBufferType { @Override @@ -538,7 +540,7 @@ public T read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion cl IRegistry replacedRegistry = registryHolder.getRegistryOr( registry, serverVersion.toClientVersion() ); - + return null; // TODO: } @Override @@ -546,5 +548,51 @@ public void write(BinaryBuffer buffer, T value, ServerVersion serverVersion, Cli } } + static final class Rotation implements BinaryBufferType { + + @Override + public java.lang.Float read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return (float) (buffer.read(BinaryBuffer.BYTE) * 360) / 256f; + } + + @Override + public void write(BinaryBuffer buffer, java.lang.Float value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.BYTE, (byte) MathUtil.floor(value * 256f / 360f)); + } + } + static final class KnownPack implements BinaryBufferType { + + @Override + public com.github.retrooper.packetevents.util.KnownPack read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return new com.github.retrooper.packetevents.util.KnownPack( + buffer.read(BinaryBuffer.STRING, serverVersion, clientVersion), + buffer.read(BinaryBuffer.STRING, serverVersion, clientVersion), + buffer.read(BinaryBuffer.STRING, serverVersion, clientVersion) + ); + } + + @Override + public void write(BinaryBuffer buffer, com.github.retrooper.packetevents.util.KnownPack value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.STRING, value.getNamespace(), serverVersion, clientVersion); + buffer.write(BinaryBuffer.STRING, value.getId(), serverVersion, clientVersion); + buffer.write(BinaryBuffer.STRING, value.getVersion(), serverVersion, clientVersion); + } + } + static final class WorldBlockPos implements BinaryBufferType { + + @Override + public WorldBlockPosition read(BinaryBuffer buffer, ServerVersion serverVersion, ClientVersion clientVersion) { + return new WorldBlockPosition( + buffer.read(BinaryBuffer.IDENTIFIER, serverVersion, clientVersion), + buffer.read(BinaryBuffer.BLOCK_POSITION, serverVersion, clientVersion) + ); + } + + @Override + public void write(BinaryBuffer buffer, WorldBlockPosition value, ServerVersion serverVersion, ClientVersion clientVersion) { + buffer.write(BinaryBuffer.IDENTIFIER, value.getWorld(), serverVersion, clientVersion); + buffer.write(BinaryBuffer.BLOCK_POSITION, value.getBlockPosition(), serverVersion, clientVersion); + } + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/item/ItemStackSerialization.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/item/ItemStackSerialization.java index 1cff37d680..7b1cdbc666 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/item/ItemStackSerialization.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/item/ItemStackSerialization.java @@ -18,6 +18,7 @@ package com.github.retrooper.packetevents.protocol.item; +import com.github.retrooper.packetevents.binary.BinaryBuffer; import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper; import com.github.retrooper.packetevents.protocol.component.ComponentType; @@ -27,6 +28,7 @@ import com.github.retrooper.packetevents.protocol.item.type.ItemTypes; import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.util.mappings.IRegistryHolder; import com.github.retrooper.packetevents.wrapper.PacketWrapper; import org.jetbrains.annotations.Nullable; @@ -76,6 +78,35 @@ private static ItemStack readLegacy(PacketWrapper wrapper) { .wrapper(wrapper).build(); } + /** + * Migration of {@link ItemStackSerialization#readLegacy} + */ + private static ItemStack readLegacyBinary( + BinaryBuffer buffer, + ServerVersion serverVersion, + IRegistryHolder registryHolder + ) { + boolean v1_13_2 = serverVersion.isNewerThanOrEquals(ServerVersion.V_1_13_2); + if (v1_13_2 && !buffer.read(BinaryBuffer.BOOLEAN)) { + return ItemStack.EMPTY; + } + int typeId = v1_13_2 ? buffer.read(BinaryBuffer.VAR_INT) : buffer.read(BinaryBuffer.SHORT); + if (typeId < 0 && !v1_13_2) { // 1.13.2 doesn't have this logic + return ItemStack.EMPTY; + } + + ClientVersion version = serverVersion.toClientVersion(); + ItemType type = ItemTypes.getRegistry().getByIdOrThrow(version, typeId); + int amount = buffer.read(BinaryBuffer.BYTE); + int legacyData = v1_13_2 ? -1 : buffer.read(BinaryBuffer.SHORT); + NBTCompound nbt = buffer.read(BinaryBuffer.NBT); + return ItemStack.builder().type(type).amount(amount) + .nbt(nbt).legacyData(legacyData) + .version(version) + .registryHolder(registryHolder) + .build(); + } + /** * Removed with 1.20.5 */ diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 95e6c5ba21..b8b6819643 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -1201,10 +1201,17 @@ public static IntFunction limitValue(IntFunction function, int limit) } public WorldBlockPosition readWorldBlockPosition() { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + return binaryBuffer.read(BinaryBuffer.WORLD_BLOCK_POSITION); + } return new WorldBlockPosition(readIdentifier(), readBlockPosition()); } public void writeWorldBlockPosition(WorldBlockPosition pos) { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + binaryBuffer.write(BinaryBuffer.WORLD_BLOCK_POSITION, pos); + return; + } writeIdentifier(pos.getWorld()); writeBlockPosition(pos.getBlockPosition()); } @@ -1437,6 +1444,9 @@ public void writeNode(Node node) { } public KnownPack readKnownPack() { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + return binaryBuffer.read(BinaryBuffer.KNOWN_PACK); + } String namespace = this.readString(); String id = this.readString(); String version = this.readString(); @@ -1444,6 +1454,10 @@ public KnownPack readKnownPack() { } public void writeKnownPack(KnownPack knownPack) { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + binaryBuffer.write(BinaryBuffer.KNOWN_PACK, knownPack); + return; + } this.writeString(knownPack.getNamespace()); this.writeString(knownPack.getId()); this.writeString(knownPack.getVersion()); @@ -1567,6 +1581,7 @@ public > Z readEnum(Class clazz) { } public > Z readEnum(Z[] values) { + return values[this.readVarInt()]; } @@ -1663,10 +1678,17 @@ public void writeEither(Either either, Writer leftWriter, Writer } public void writeRotation(float rotation) { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + this.binaryBuffer.write(BinaryBuffer.ROTATION, rotation); + return; + } this.writeByte((byte) MathUtil.floor(rotation * 256f / 360f)); } public float readRotation() { + if (PacketEvents.getAPI().getSettings().shouldUseBinaryBuffer()) { + return this.binaryBuffer.read(BinaryBuffer.ROTATION); + } return (float) (this.readByte() * 360) / 256f; }