mirror of https://github.com/Minestom/Minestom.git
NetworkBuffer.Type refactor (#2078)
* Refactor network buffer types * Remove magical -1 return * Style * Type doesnt need to be sealed
This commit is contained in:
parent
2442f14b3d
commit
b5c35e0144
|
@ -62,7 +62,7 @@ public final class Metadata {
|
|||
}
|
||||
|
||||
public static Entry<Point> Rotation(@NotNull Point value) {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_ROTATION, value, NetworkBuffer.ROTATION);
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_ROTATION, value, NetworkBuffer.VECTOR3);
|
||||
}
|
||||
|
||||
public static Entry<Point> Position(@NotNull Point value) {
|
||||
|
@ -128,7 +128,7 @@ public final class Metadata {
|
|||
return new MetadataImpl.EntryImpl<>(TYPE_VECTOR3, value, NetworkBuffer.VECTOR3);
|
||||
}
|
||||
|
||||
public static Entry<float[]> Quaternion(float @NotNull[] value) {
|
||||
public static Entry<float[]> Quaternion(float @NotNull [] value) {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_QUATERNION, value, NetworkBuffer.QUATERNION);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import net.minestom.server.item.ItemStack;
|
|||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.Either;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -29,50 +28,53 @@ import java.util.function.Function;
|
|||
|
||||
@ApiStatus.Experimental
|
||||
public final class NetworkBuffer {
|
||||
public static final Type<Boolean> BOOLEAN = NetworkBufferTypes.BOOLEAN;
|
||||
public static final Type<Byte> BYTE = NetworkBufferTypes.BYTE;
|
||||
public static final Type<Short> SHORT = NetworkBufferTypes.SHORT;
|
||||
public static final Type<Integer> UNSIGNED_SHORT = NetworkBufferTypes.UNSIGNED_SHORT;
|
||||
public static final Type<Integer> INT = NetworkBufferTypes.INT;
|
||||
public static final Type<Long> LONG = NetworkBufferTypes.LONG;
|
||||
public static final Type<Float> FLOAT = NetworkBufferTypes.FLOAT;
|
||||
public static final Type<Double> DOUBLE = NetworkBufferTypes.DOUBLE;
|
||||
public static final Type<Integer> VAR_INT = NetworkBufferTypes.VAR_INT;
|
||||
public static final Type<Long> VAR_LONG = NetworkBufferTypes.VAR_LONG;
|
||||
public static final Type<byte[]> RAW_BYTES = NetworkBufferTypes.RAW_BYTES;
|
||||
public static final Type<String> STRING = NetworkBufferTypes.STRING;
|
||||
public static final Type<NBT> NBT = NetworkBufferTypes.NBT;
|
||||
public static final Type<Point> BLOCK_POSITION = NetworkBufferTypes.BLOCK_POSITION;
|
||||
public static final Type<Component> COMPONENT = NetworkBufferTypes.COMPONENT;
|
||||
public static final Type<Component> JSON_COMPONENT = NetworkBufferTypes.JSON_COMPONENT;
|
||||
public static final Type<UUID> UUID = NetworkBufferTypes.UUID;
|
||||
public static final Type<@Nullable ItemStack> ITEM = NetworkBufferTypes.ITEM;
|
||||
public static final Type<Boolean> BOOLEAN = new NetworkBufferTypeImpl.BooleanType();
|
||||
public static final Type<Byte> BYTE = new NetworkBufferTypeImpl.ByteType();
|
||||
public static final Type<Short> SHORT = new NetworkBufferTypeImpl.ShortType();
|
||||
public static final Type<Integer> UNSIGNED_SHORT = new NetworkBufferTypeImpl.UnsignedShortType();
|
||||
public static final Type<Integer> INT = new NetworkBufferTypeImpl.IntType();
|
||||
public static final Type<Long> LONG = new NetworkBufferTypeImpl.LongType();
|
||||
public static final Type<Float> FLOAT = new NetworkBufferTypeImpl.FloatType();
|
||||
public static final Type<Double> DOUBLE = new NetworkBufferTypeImpl.DoubleType();
|
||||
public static final Type<Integer> VAR_INT = new NetworkBufferTypeImpl.VarIntType();
|
||||
public static final Type<Long> VAR_LONG = new NetworkBufferTypeImpl.VarLongType();
|
||||
public static final Type<byte[]> RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType();
|
||||
public static final Type<String> STRING = new NetworkBufferTypeImpl.StringType();
|
||||
public static final Type<NBT> NBT = new NetworkBufferTypeImpl.NbtType();
|
||||
public static final Type<Point> BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType();
|
||||
public static final Type<Component> COMPONENT = new NetworkBufferTypeImpl.ComponentType();
|
||||
public static final Type<Component> JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType();
|
||||
public static final Type<UUID> UUID = new NetworkBufferTypeImpl.UUIDType();
|
||||
public static final Type<ItemStack> ITEM = new NetworkBufferTypeImpl.ItemType();
|
||||
|
||||
public static final Type<byte[]> BYTE_ARRAY = NetworkBufferTypes.BYTE_ARRAY;
|
||||
public static final Type<long[]> LONG_ARRAY = NetworkBufferTypes.LONG_ARRAY;
|
||||
public static final Type<int[]> VAR_INT_ARRAY = NetworkBufferTypes.VAR_INT_ARRAY;
|
||||
public static final Type<long[]> VAR_LONG_ARRAY = NetworkBufferTypes.VAR_LONG_ARRAY;
|
||||
public static final Type<byte[]> BYTE_ARRAY = new NetworkBufferTypeImpl.ByteArrayType();
|
||||
public static final Type<long[]> LONG_ARRAY = new NetworkBufferTypeImpl.LongArrayType();
|
||||
public static final Type<int[]> VAR_INT_ARRAY = new NetworkBufferTypeImpl.VarIntArrayType();
|
||||
public static final Type<long[]> VAR_LONG_ARRAY = new NetworkBufferTypeImpl.VarLongArrayType();
|
||||
|
||||
// METADATA
|
||||
public static final Type<Component> OPT_CHAT = NetworkBufferTypes.OPT_CHAT;
|
||||
public static final Type<Point> ROTATION = NetworkBufferTypes.ROTATION;
|
||||
public static final Type<Point> OPT_BLOCK_POSITION = NetworkBufferTypes.OPT_BLOCK_POSITION;
|
||||
public static final Type<Direction> DIRECTION = NetworkBufferTypes.DIRECTION;
|
||||
public static final Type<UUID> OPT_UUID = NetworkBufferTypes.OPT_UUID;
|
||||
public static final Type<Integer> BLOCK_STATE = NetworkBufferTypes.BLOCK_STATE;
|
||||
public static final Type<Integer> OPT_BLOCK_STATE = NetworkBufferTypes.OPT_BLOCK_STATE;
|
||||
public static final Type<int[]> VILLAGER_DATA = NetworkBufferTypes.VILLAGER_DATA;
|
||||
public static final Type<Integer> OPT_VAR_INT = NetworkBufferTypes.OPT_VAR_INT;
|
||||
public static final Type<Entity.Pose> POSE = NetworkBufferTypes.POSE;
|
||||
public static final Type<DeathLocation> DEATH_LOCATION = NetworkBufferTypes.DEATH_LOCATION;
|
||||
public static final Type<CatMeta.Variant> CAT_VARIANT = NetworkBufferTypes.CAT_VARIANT;
|
||||
public static final Type<FrogMeta.Variant> FROG_VARIANT = NetworkBufferTypes.FROG_VARIANT;
|
||||
public static final Type<PaintingMeta.Variant> PAINTING_VARIANT = NetworkBufferTypes.PAINTING_VARIANT;
|
||||
public static final Type<SnifferMeta.State> SNIFFER_STATE = NetworkBufferTypes.SNIFFER_STATE;
|
||||
public static final Type<Point> VECTOR3 = NetworkBufferTypes.VECTOR3;
|
||||
public static final Type<Point> VECTOR3D = NetworkBufferTypes.VECTOR3D;
|
||||
public static final Type<float[]> QUATERNION = NetworkBufferTypes.QUATERNION;
|
||||
public static final Type<Particle> PARTICLE = NetworkBufferTypes.PARTICLE;
|
||||
public static final Type<Integer> BLOCK_STATE = new NetworkBufferTypeImpl.BlockStateType();
|
||||
public static final Type<int[]> VILLAGER_DATA = new NetworkBufferTypeImpl.VillagerDataType();
|
||||
public static final Type<DeathLocation> DEATH_LOCATION = new NetworkBufferTypeImpl.DeathLocationType();
|
||||
public static final Type<Point> VECTOR3 = new NetworkBufferTypeImpl.Vector3Type();
|
||||
public static final Type<Point> VECTOR3D = new NetworkBufferTypeImpl.Vector3DType();
|
||||
public static final Type<float[]> QUATERNION = new NetworkBufferTypeImpl.QuaternionType();
|
||||
public static final Type<Particle> PARTICLE = new NetworkBufferTypeImpl.ParticleType();
|
||||
|
||||
public static final Type<Component> OPT_CHAT = NetworkBufferTypeImpl.fromOptional(COMPONENT);
|
||||
public static final Type<Point> OPT_BLOCK_POSITION = NetworkBufferTypeImpl.fromOptional(BLOCK_POSITION);
|
||||
public static final Type<UUID> OPT_UUID = NetworkBufferTypeImpl.fromOptional(UUID);
|
||||
public static final Type<Integer> OPT_BLOCK_STATE = NetworkBufferTypeImpl.fromOptional(BLOCK_STATE);
|
||||
public static final Type<Integer> OPT_VAR_INT = NetworkBufferTypeImpl.fromOptional(VAR_INT);
|
||||
|
||||
public static final Type<Direction> DIRECTION = NetworkBufferTypeImpl.fromEnum(Direction.class);
|
||||
public static final Type<Entity.Pose> POSE = NetworkBufferTypeImpl.fromEnum(Entity.Pose.class);
|
||||
|
||||
public static final Type<CatMeta.Variant> CAT_VARIANT = NetworkBufferTypeImpl.fromEnum(CatMeta.Variant.class);
|
||||
public static final Type<FrogMeta.Variant> FROG_VARIANT = NetworkBufferTypeImpl.fromEnum(FrogMeta.Variant.class);
|
||||
public static final Type<PaintingMeta.Variant> PAINTING_VARIANT = NetworkBufferTypeImpl.fromEnum(PaintingMeta.Variant.class);
|
||||
public static final Type<SnifferMeta.State> SNIFFER_STATE = NetworkBufferTypeImpl.fromEnum(SnifferMeta.State.class);
|
||||
|
||||
|
||||
ByteBuffer nioBuffer;
|
||||
final boolean resizable;
|
||||
|
@ -103,9 +105,7 @@ public final class NetworkBuffer {
|
|||
}
|
||||
|
||||
public <T> void write(@NotNull Type<T> type, @NotNull T value) {
|
||||
var impl = (NetworkBufferTypes.TypeImpl<T>) type;
|
||||
final long length = impl.writer().write(this, value);
|
||||
if (length != -1) this.writeIndex += length;
|
||||
type.write(this, value);
|
||||
}
|
||||
|
||||
public <T> void write(@NotNull Writer writer) {
|
||||
|
@ -113,8 +113,7 @@ public final class NetworkBuffer {
|
|||
}
|
||||
|
||||
public <T> @NotNull T read(@NotNull Type<T> type) {
|
||||
var impl = (NetworkBufferTypes.TypeImpl<T>) type;
|
||||
return impl.reader().read(this);
|
||||
return type.read(this);
|
||||
}
|
||||
|
||||
public <T> void writeOptional(@NotNull Type<T> type, @Nullable T value) {
|
||||
|
@ -141,9 +140,7 @@ public final class NetworkBuffer {
|
|||
return;
|
||||
}
|
||||
write(VAR_INT, values.size());
|
||||
for (T value : values) {
|
||||
write(type, value);
|
||||
}
|
||||
for (T value : values) write(type, value);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
|
@ -157,9 +154,7 @@ public final class NetworkBuffer {
|
|||
return;
|
||||
}
|
||||
write(VAR_INT, values.size());
|
||||
for (T value : values) {
|
||||
write(value);
|
||||
}
|
||||
for (T value : values) write(value);
|
||||
}
|
||||
|
||||
public <T> void writeCollection(@Nullable Collection<@NotNull T> values,
|
||||
|
@ -169,18 +164,14 @@ public final class NetworkBuffer {
|
|||
return;
|
||||
}
|
||||
write(VAR_INT, values.size());
|
||||
for (T value : values) {
|
||||
consumer.accept(this, value);
|
||||
}
|
||||
for (T value : values) consumer.accept(this, value);
|
||||
}
|
||||
|
||||
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Type<T> type, int maxSize) {
|
||||
final int size = read(VAR_INT);
|
||||
Check.argCondition(size > maxSize, "Collection size ({0}) is higher than the maximum allowed size ({1})", size, maxSize);
|
||||
final List<T> values = new java.util.ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
values.add(read(type));
|
||||
}
|
||||
for (int i = 0; i < size; i++) values.add(read(type));
|
||||
return values;
|
||||
}
|
||||
|
||||
|
@ -188,30 +179,10 @@ public final class NetworkBuffer {
|
|||
final int size = read(VAR_INT);
|
||||
Check.argCondition(size > maxSize, "Collection size ({0}) is higher than the maximum allowed size ({1})", size, maxSize);
|
||||
final List<T> values = new java.util.ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
values.add(function.apply(this));
|
||||
}
|
||||
for (int i = 0; i < size; i++) values.add(function.apply(this));
|
||||
return values;
|
||||
}
|
||||
|
||||
public <L, R> void writeEither(Either<L, R> either, BiConsumer<NetworkBuffer, L> leftWriter, BiConsumer<NetworkBuffer, R> rightWriter) {
|
||||
if (either.isLeft()) {
|
||||
write(BOOLEAN, true);
|
||||
leftWriter.accept(this, either.left());
|
||||
} else {
|
||||
write(BOOLEAN, false);
|
||||
rightWriter.accept(this, either.right());
|
||||
}
|
||||
}
|
||||
|
||||
public <L, R> @NotNull Either<L, R> readEither(@NotNull Function<NetworkBuffer, L> leftReader, Function<NetworkBuffer, R> rightReader) {
|
||||
if (read(BOOLEAN)) {
|
||||
return Either.left(leftReader.apply(this));
|
||||
} else {
|
||||
return Either.right(rightReader.apply(this));
|
||||
}
|
||||
}
|
||||
|
||||
public <E extends Enum<?>> void writeEnum(@NotNull Class<E> enumClass, @NotNull E value) {
|
||||
write(VAR_INT, value.ordinal());
|
||||
}
|
||||
|
@ -320,7 +291,10 @@ public final class NetworkBuffer {
|
|||
}
|
||||
|
||||
|
||||
public sealed interface Type<T> permits NetworkBufferTypes.TypeImpl {
|
||||
public interface Type<T> {
|
||||
void write(@NotNull NetworkBuffer buffer, T value);
|
||||
|
||||
T read(@NotNull NetworkBuffer buffer);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
|
|
@ -0,0 +1,649 @@
|
|||
package net.minestom.server.network;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
|
||||
int SEGMENT_BITS = 0x7F;
|
||||
int CONTINUE_BIT = 0x80;
|
||||
|
||||
record BooleanType() implements NetworkBufferTypeImpl<Boolean> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Boolean value) {
|
||||
buffer.ensureSize(1);
|
||||
buffer.nioBuffer.put(buffer.writeIndex(), value ? (byte) 1 : (byte) 0);
|
||||
buffer.writeIndex += 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean read(@NotNull NetworkBuffer buffer) {
|
||||
final byte value = buffer.nioBuffer.get(buffer.readIndex());
|
||||
buffer.readIndex += 1;
|
||||
return value == 1;
|
||||
}
|
||||
}
|
||||
|
||||
record ByteType() implements NetworkBufferTypeImpl<Byte> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Byte value) {
|
||||
buffer.ensureSize(1);
|
||||
buffer.nioBuffer.put(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte read(@NotNull NetworkBuffer buffer) {
|
||||
final byte value = buffer.nioBuffer.get(buffer.readIndex());
|
||||
buffer.readIndex += 1;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record ShortType() implements NetworkBufferTypeImpl<Short> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Short value) {
|
||||
buffer.ensureSize(2);
|
||||
buffer.nioBuffer.putShort(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short read(@NotNull NetworkBuffer buffer) {
|
||||
final short value = buffer.nioBuffer.getShort(buffer.readIndex());
|
||||
buffer.readIndex += 2;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record UnsignedShortType() implements NetworkBufferTypeImpl<Integer> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Integer value) {
|
||||
buffer.ensureSize(2);
|
||||
buffer.nioBuffer.putShort(buffer.writeIndex(), (short) (value & 0xFFFF));
|
||||
buffer.writeIndex += 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer read(@NotNull NetworkBuffer buffer) {
|
||||
final short value = buffer.nioBuffer.getShort(buffer.readIndex());
|
||||
buffer.readIndex += 2;
|
||||
return value & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
record IntType() implements NetworkBufferTypeImpl<Integer> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Integer value) {
|
||||
buffer.ensureSize(4);
|
||||
buffer.nioBuffer.putInt(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer read(@NotNull NetworkBuffer buffer) {
|
||||
final int value = buffer.nioBuffer.getInt(buffer.readIndex());
|
||||
buffer.readIndex += 4;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record LongType() implements NetworkBufferTypeImpl<Long> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Long value) {
|
||||
buffer.ensureSize(8);
|
||||
buffer.nioBuffer.putLong(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long read(@NotNull NetworkBuffer buffer) {
|
||||
final long value = buffer.nioBuffer.getLong(buffer.readIndex());
|
||||
buffer.readIndex += 8;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record FloatType() implements NetworkBufferTypeImpl<Float> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Float value) {
|
||||
buffer.ensureSize(4);
|
||||
buffer.nioBuffer.putFloat(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float read(@NotNull NetworkBuffer buffer) {
|
||||
final float value = buffer.nioBuffer.getFloat(buffer.readIndex());
|
||||
buffer.readIndex += 4;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record DoubleType() implements NetworkBufferTypeImpl<Double> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Double value) {
|
||||
buffer.ensureSize(8);
|
||||
buffer.nioBuffer.putDouble(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double read(@NotNull NetworkBuffer buffer) {
|
||||
final double value = buffer.nioBuffer.getDouble(buffer.readIndex());
|
||||
buffer.readIndex += 8;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record VarIntType() implements NetworkBufferTypeImpl<Integer> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Integer boxed) {
|
||||
final int value = boxed;
|
||||
final int index = buffer.writeIndex();
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
buffer.ensureSize(1);
|
||||
buffer.nioBuffer.put(index, (byte) value);
|
||||
buffer.writeIndex += 1;
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
buffer.ensureSize(2);
|
||||
buffer.nioBuffer.putShort(index, (short) ((value & 0x7F | 0x80) << 8 | (value >>> 7)));
|
||||
buffer.writeIndex += 2;
|
||||
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
|
||||
buffer.ensureSize(3);
|
||||
var nio = buffer.nioBuffer;
|
||||
nio.put(index, (byte) (value & 0x7F | 0x80));
|
||||
nio.put(index + 1, (byte) ((value >>> 7) & 0x7F | 0x80));
|
||||
nio.put(index + 2, (byte) (value >>> 14));
|
||||
buffer.writeIndex += 3;
|
||||
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
|
||||
buffer.ensureSize(4);
|
||||
var nio = buffer.nioBuffer;
|
||||
nio.putInt(index, (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21));
|
||||
buffer.writeIndex += 4;
|
||||
} else {
|
||||
buffer.ensureSize(5);
|
||||
var nio = buffer.nioBuffer;
|
||||
nio.putInt(index, (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80));
|
||||
nio.put(index + 4, (byte) (value >>> 28));
|
||||
buffer.writeIndex += 5;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer read(@NotNull NetworkBuffer buffer) {
|
||||
int index = buffer.readIndex();
|
||||
// https://github.com/jvm-profiling-tools/async-profiler/blob/a38a375dc62b31a8109f3af97366a307abb0fe6f/src/converter/one/jfr/JfrReader.java#L393
|
||||
int result = 0;
|
||||
for (int shift = 0; ; shift += 7) {
|
||||
byte b = buffer.nioBuffer.get(index++);
|
||||
result |= (b & 0x7f) << shift;
|
||||
if (b >= 0) {
|
||||
buffer.readIndex += index - buffer.readIndex();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record VarLongType() implements NetworkBufferTypeImpl<Long> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Long value) {
|
||||
buffer.ensureSize(10);
|
||||
int size = 0;
|
||||
while (true) {
|
||||
if ((value & ~((long) SEGMENT_BITS)) == 0) {
|
||||
buffer.nioBuffer.put(buffer.writeIndex() + size, (byte) value.intValue());
|
||||
buffer.writeIndex += size + 1;
|
||||
return;
|
||||
}
|
||||
buffer.nioBuffer.put(buffer.writeIndex() + size, (byte) (value & SEGMENT_BITS | CONTINUE_BIT));
|
||||
size++;
|
||||
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||
value >>>= 7;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long read(@NotNull NetworkBuffer buffer) {
|
||||
int length = 0;
|
||||
long value = 0;
|
||||
int position = 0;
|
||||
byte currentByte;
|
||||
while (true) {
|
||||
currentByte = buffer.nioBuffer.get(buffer.readIndex() + length);
|
||||
length++;
|
||||
value |= (long) (currentByte & SEGMENT_BITS) << position;
|
||||
if ((currentByte & CONTINUE_BIT) == 0) break;
|
||||
position += 7;
|
||||
if (position >= 64) throw new RuntimeException("VarLong is too big");
|
||||
}
|
||||
buffer.readIndex += length;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record RawBytesType() implements NetworkBufferTypeImpl<byte[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, byte[] value) {
|
||||
buffer.ensureSize(value.length);
|
||||
buffer.nioBuffer.put(buffer.writeIndex(), value);
|
||||
buffer.writeIndex += value.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read(@NotNull NetworkBuffer buffer) {
|
||||
final int limit = buffer.nioBuffer.limit();
|
||||
final int length = limit - buffer.readIndex();
|
||||
assert length > 0 : "Invalid remaining: " + length;
|
||||
final byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
record StringType() implements NetworkBufferTypeImpl<String> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, String value) {
|
||||
final byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
buffer.write(VAR_INT, bytes.length);
|
||||
buffer.write(RAW_BYTES, bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(@NotNull NetworkBuffer buffer) {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final int remaining = buffer.nioBuffer.limit() - buffer.readIndex();
|
||||
Check.argCondition(length > remaining, "String is too long (length: {0}, readable: {1})", length, remaining);
|
||||
byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
record NbtType() implements NetworkBufferTypeImpl<NBT> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, org.jglrxavpok.hephaistos.nbt.NBT value) {
|
||||
NBTWriter nbtWriter = buffer.nbtWriter;
|
||||
if (nbtWriter == null) {
|
||||
nbtWriter = new NBTWriter(new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) {
|
||||
buffer.write(BYTE, (byte) b);
|
||||
}
|
||||
}, CompressedProcesser.NONE);
|
||||
buffer.nbtWriter = nbtWriter;
|
||||
}
|
||||
try {
|
||||
if (value == NBTEnd.INSTANCE) {
|
||||
// Kotlin - https://discord.com/channels/706185253441634317/706186227493109860/1163703658341478462
|
||||
buffer.write(BYTE, (byte) NBTType.TAG_End.getOrdinal());
|
||||
} else {
|
||||
buffer.write(BYTE, (byte) value.getID().getOrdinal());
|
||||
nbtWriter.writeRaw(value);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.jglrxavpok.hephaistos.nbt.NBT read(@NotNull NetworkBuffer buffer) {
|
||||
NBTReader nbtReader = buffer.nbtReader;
|
||||
if (nbtReader == null) {
|
||||
nbtReader = new NBTReader(new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
return buffer.read(BYTE) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return buffer.readableBytes();
|
||||
}
|
||||
}, CompressedProcesser.NONE);
|
||||
buffer.nbtReader = nbtReader;
|
||||
}
|
||||
try {
|
||||
byte tagId = buffer.read(BYTE);
|
||||
if (tagId == NBTType.TAG_End.getOrdinal())
|
||||
return NBTEnd.INSTANCE;
|
||||
return nbtReader.readRaw(tagId);
|
||||
} catch (IOException | NBTException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record BlockPositionType() implements NetworkBufferTypeImpl<Point> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Point value) {
|
||||
final int blockX = value.blockX();
|
||||
final int blockY = value.blockY();
|
||||
final int blockZ = value.blockZ();
|
||||
final long longPos = (((long) blockX & 0x3FFFFFF) << 38) |
|
||||
(((long) blockZ & 0x3FFFFFF) << 12) |
|
||||
((long) blockY & 0xFFF);
|
||||
buffer.write(LONG, longPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point read(@NotNull NetworkBuffer buffer) {
|
||||
final long value = buffer.read(LONG);
|
||||
final int x = (int) (value >> 38);
|
||||
final int y = (int) (value << 52 >> 52);
|
||||
final int z = (int) (value << 26 >> 38);
|
||||
return new Vec(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
record ComponentType() implements NetworkBufferTypeImpl<Component> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Component value) {
|
||||
final NBT nbt = NbtComponentSerializer.nbt().serialize(value);
|
||||
buffer.write(NBT, nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component read(@NotNull NetworkBuffer buffer) {
|
||||
final NBT nbt = buffer.read(NBT);
|
||||
return NbtComponentSerializer.nbt().deserialize(nbt);
|
||||
}
|
||||
}
|
||||
|
||||
record JsonComponentType() implements NetworkBufferTypeImpl<Component> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Component value) {
|
||||
final String json = GsonComponentSerializer.gson().serialize(value);
|
||||
buffer.write(STRING, json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component read(@NotNull NetworkBuffer buffer) {
|
||||
final String json = buffer.read(STRING);
|
||||
return GsonComponentSerializer.gson().deserialize(json);
|
||||
}
|
||||
}
|
||||
|
||||
record UUIDType() implements NetworkBufferTypeImpl<UUID> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, java.util.UUID value) {
|
||||
buffer.write(LONG, value.getMostSignificantBits());
|
||||
buffer.write(LONG, value.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.UUID read(@NotNull NetworkBuffer buffer) {
|
||||
final long mostSignificantBits = buffer.read(LONG);
|
||||
final long leastSignificantBits = buffer.read(LONG);
|
||||
return new UUID(mostSignificantBits, leastSignificantBits);
|
||||
}
|
||||
}
|
||||
|
||||
record ItemType() implements NetworkBufferTypeImpl<ItemStack> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, ItemStack value) {
|
||||
if (value.isAir()) {
|
||||
buffer.write(BOOLEAN, false);
|
||||
return;
|
||||
}
|
||||
buffer.write(BOOLEAN, true);
|
||||
buffer.write(VAR_INT, value.material().id());
|
||||
buffer.write(BYTE, (byte) value.amount());
|
||||
// Vanilla does not write an empty object, just an end tag.
|
||||
NBTCompound nbt = value.meta().toNBT();
|
||||
buffer.write(NBT, nbt.isEmpty() ? NBTEnd.INSTANCE : nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack read(@NotNull NetworkBuffer buffer) {
|
||||
final boolean present = buffer.read(BOOLEAN);
|
||||
if (!present) return ItemStack.AIR;
|
||||
|
||||
final int id = buffer.read(VAR_INT);
|
||||
final Material material = Material.fromId(id);
|
||||
if (material == null) throw new RuntimeException("Unknown material id: " + id);
|
||||
|
||||
final int amount = buffer.read(BYTE);
|
||||
final NBT nbt = buffer.read(NBT);
|
||||
if (!(nbt instanceof NBTCompound compound)) {
|
||||
return ItemStack.of(material, amount);
|
||||
}
|
||||
return ItemStack.fromNBT(material, compound, amount);
|
||||
}
|
||||
}
|
||||
|
||||
record ByteArrayType() implements NetworkBufferTypeImpl<byte[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, byte[] value) {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
buffer.write(RAW_BYTES, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read(@NotNull NetworkBuffer buffer) {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
record LongArrayType() implements NetworkBufferTypeImpl<long[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, long[] value) {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
for (long l : value) buffer.write(LONG, l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] read(@NotNull NetworkBuffer buffer) {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final long[] longs = new long[length];
|
||||
for (int i = 0; i < length; i++) longs[i] = buffer.read(LONG);
|
||||
return longs;
|
||||
}
|
||||
}
|
||||
|
||||
record VarIntArrayType() implements NetworkBufferTypeImpl<int[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, int[] value) {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
for (int i : value) buffer.write(VAR_INT, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] read(@NotNull NetworkBuffer buffer) {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final int[] ints = new int[length];
|
||||
for (int i = 0; i < length; i++) ints[i] = buffer.read(VAR_INT);
|
||||
return ints;
|
||||
}
|
||||
}
|
||||
|
||||
record VarLongArrayType() implements NetworkBufferTypeImpl<long[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, long[] value) {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
for (long l : value) buffer.write(VAR_LONG, l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] read(@NotNull NetworkBuffer buffer) {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final long[] longs = new long[length];
|
||||
for (int i = 0; i < length; i++) longs[i] = buffer.read(VAR_LONG);
|
||||
return longs;
|
||||
}
|
||||
}
|
||||
|
||||
// METADATA
|
||||
|
||||
record BlockStateType() implements NetworkBufferTypeImpl<Integer> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Integer value) {
|
||||
buffer.write(VAR_INT, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer read(@NotNull NetworkBuffer buffer) {
|
||||
return buffer.read(VAR_INT);
|
||||
}
|
||||
}
|
||||
|
||||
record VillagerDataType() implements NetworkBufferTypeImpl<int[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, int[] value) {
|
||||
buffer.write(VAR_INT, value[0]);
|
||||
buffer.write(VAR_INT, value[1]);
|
||||
buffer.write(VAR_INT, value[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] read(@NotNull NetworkBuffer buffer) {
|
||||
final int[] value = new int[3];
|
||||
value[0] = buffer.read(VAR_INT);
|
||||
value[1] = buffer.read(VAR_INT);
|
||||
value[2] = buffer.read(VAR_INT);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
record DeathLocationType() implements NetworkBufferTypeImpl<DeathLocation> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, DeathLocation value) {
|
||||
buffer.writeOptional(writer -> {
|
||||
writer.write(STRING, value.dimension());
|
||||
writer.write(BLOCK_POSITION, value.position());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeathLocation read(@NotNull NetworkBuffer buffer) {
|
||||
return buffer.readOptional(networkBuffer -> {
|
||||
final String dimension = networkBuffer.read(STRING);
|
||||
final Point position = networkBuffer.read(BLOCK_POSITION);
|
||||
return new DeathLocation(dimension, position);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
record Vector3Type() implements NetworkBufferTypeImpl<Point> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Point value) {
|
||||
buffer.write(FLOAT, (float) value.x());
|
||||
buffer.write(FLOAT, (float) value.y());
|
||||
buffer.write(FLOAT, (float) value.z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point read(@NotNull NetworkBuffer buffer) {
|
||||
final float x = buffer.read(FLOAT);
|
||||
final float y = buffer.read(FLOAT);
|
||||
final float z = buffer.read(FLOAT);
|
||||
return new Vec(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
record Vector3DType() implements NetworkBufferTypeImpl<Point> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Point value) {
|
||||
buffer.write(DOUBLE, value.x());
|
||||
buffer.write(DOUBLE, value.y());
|
||||
buffer.write(DOUBLE, value.z());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point read(@NotNull NetworkBuffer buffer) {
|
||||
final double x = buffer.read(DOUBLE);
|
||||
final double y = buffer.read(DOUBLE);
|
||||
final double z = buffer.read(DOUBLE);
|
||||
return new Vec(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
record QuaternionType() implements NetworkBufferTypeImpl<float[]> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, float[] value) {
|
||||
buffer.write(FLOAT, value[0]);
|
||||
buffer.write(FLOAT, value[1]);
|
||||
buffer.write(FLOAT, value[2]);
|
||||
buffer.write(FLOAT, value[3]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] read(@NotNull NetworkBuffer buffer) {
|
||||
final float x = buffer.read(FLOAT);
|
||||
final float y = buffer.read(FLOAT);
|
||||
final float z = buffer.read(FLOAT);
|
||||
final float w = buffer.read(FLOAT);
|
||||
return new float[]{x, y, z, w};
|
||||
}
|
||||
}
|
||||
|
||||
record ParticleType() implements NetworkBufferTypeImpl<Particle> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Particle value) {
|
||||
Check.stateCondition(value.data() != null && !value.data().validate(value.id()), "Particle data {0} is not valid for this particle type {1}", value.data(), value.namespace());
|
||||
Check.stateCondition(value.data() == null && ParticleData.requiresData(value.id()), "Particle data is required for this particle type {0}", value.namespace());
|
||||
buffer.write(VAR_INT, value.id());
|
||||
if (value.data() != null) value.data().write(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Particle read(@NotNull NetworkBuffer buffer) {
|
||||
throw new UnsupportedOperationException("Cannot read a particle from the network buffer");
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends Enum<?>> NetworkBufferTypeImpl<T> fromEnum(Class<T> enumClass) {
|
||||
return new NetworkBufferTypeImpl<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, T value) {
|
||||
buffer.writeEnum(enumClass, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(@NotNull NetworkBuffer buffer) {
|
||||
return buffer.readEnum(enumClass);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static <T> NetworkBufferTypeImpl<T> fromOptional(Type<T> optionalType) {
|
||||
return new NetworkBufferTypeImpl<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, T value) {
|
||||
buffer.writeOptional(optionalType, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(@NotNull NetworkBuffer buffer) {
|
||||
return buffer.readOptional(optionalType);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,665 +0,0 @@
|
|||
package net.minestom.server.network;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.metadata.animal.FrogMeta;
|
||||
import net.minestom.server.entity.metadata.animal.SnifferMeta;
|
||||
import net.minestom.server.entity.metadata.animal.tameable.CatMeta;
|
||||
import net.minestom.server.entity.metadata.other.PaintingMeta;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
final class NetworkBufferTypes {
|
||||
private static final int SEGMENT_BITS = 0x7F;
|
||||
private static final int CONTINUE_BIT = 0x80;
|
||||
|
||||
static final TypeImpl<Boolean> BOOLEAN = new TypeImpl<>(Boolean.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(1);
|
||||
buffer.nioBuffer.put(buffer.writeIndex(), value ? (byte) 1 : (byte) 0);
|
||||
return 1;
|
||||
},
|
||||
buffer -> {
|
||||
final byte value = buffer.nioBuffer.get(buffer.readIndex());
|
||||
buffer.readIndex += 1;
|
||||
return value == 1;
|
||||
});
|
||||
static final TypeImpl<Byte> BYTE = new TypeImpl<>(Byte.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(1);
|
||||
buffer.nioBuffer.put(buffer.writeIndex(), value);
|
||||
return 1;
|
||||
},
|
||||
buffer -> {
|
||||
final byte value = buffer.nioBuffer.get(buffer.readIndex());
|
||||
buffer.readIndex += 1;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Short> SHORT = new TypeImpl<>(Short.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(2);
|
||||
buffer.nioBuffer.putShort(buffer.writeIndex(), value);
|
||||
return 2;
|
||||
},
|
||||
buffer -> {
|
||||
final short value = buffer.nioBuffer.getShort(buffer.readIndex());
|
||||
buffer.readIndex += 2;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Integer> UNSIGNED_SHORT = new TypeImpl<>(Integer.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(2);
|
||||
buffer.nioBuffer.putShort(buffer.writeIndex(), (short) (value & 0xFFFF));
|
||||
return 2;
|
||||
},
|
||||
buffer -> {
|
||||
final short value = buffer.nioBuffer.getShort(buffer.readIndex());
|
||||
buffer.readIndex += 2;
|
||||
return value & 0xFFFF;
|
||||
});
|
||||
static final TypeImpl<Integer> INT = new TypeImpl<>(Integer.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(4);
|
||||
buffer.nioBuffer.putInt(buffer.writeIndex(), value);
|
||||
return 4;
|
||||
},
|
||||
buffer -> {
|
||||
final int value = buffer.nioBuffer.getInt(buffer.readIndex());
|
||||
buffer.readIndex += 4;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Long> LONG = new TypeImpl<>(Long.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(8);
|
||||
buffer.nioBuffer.putLong(buffer.writeIndex(), value);
|
||||
return 8;
|
||||
},
|
||||
buffer -> {
|
||||
final long value = buffer.nioBuffer.getLong(buffer.readIndex());
|
||||
buffer.readIndex += 8;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Float> FLOAT = new TypeImpl<>(Float.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(4);
|
||||
buffer.nioBuffer.putFloat(buffer.writeIndex(), value);
|
||||
return 4;
|
||||
},
|
||||
buffer -> {
|
||||
final float value = buffer.nioBuffer.getFloat(buffer.readIndex());
|
||||
buffer.readIndex += 4;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Double> DOUBLE = new TypeImpl<>(Double.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(8);
|
||||
buffer.nioBuffer.putDouble(buffer.writeIndex(), value);
|
||||
return 8;
|
||||
},
|
||||
buffer -> {
|
||||
final double value = buffer.nioBuffer.getDouble(buffer.readIndex());
|
||||
buffer.readIndex += 8;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Integer> VAR_INT = new TypeImpl<>(Integer.class,
|
||||
(buffer, boxed) -> {
|
||||
final int value = boxed;
|
||||
final int index = buffer.writeIndex();
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
buffer.ensureSize(1);
|
||||
buffer.nioBuffer.put(index, (byte) value);
|
||||
return 1;
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
buffer.ensureSize(2);
|
||||
buffer.nioBuffer.putShort(index, (short) ((value & 0x7F | 0x80) << 8 | (value >>> 7)));
|
||||
return 2;
|
||||
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
|
||||
buffer.ensureSize(3);
|
||||
var nio = buffer.nioBuffer;
|
||||
nio.put(index, (byte) (value & 0x7F | 0x80));
|
||||
nio.put(index + 1, (byte) ((value >>> 7) & 0x7F | 0x80));
|
||||
nio.put(index + 2, (byte) (value >>> 14));
|
||||
return 3;
|
||||
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
|
||||
buffer.ensureSize(4);
|
||||
var nio = buffer.nioBuffer;
|
||||
nio.putInt(index, (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21));
|
||||
return 4;
|
||||
} else {
|
||||
buffer.ensureSize(5);
|
||||
var nio = buffer.nioBuffer;
|
||||
nio.putInt(index, (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80));
|
||||
nio.put(index + 4, (byte) (value >>> 28));
|
||||
return 5;
|
||||
}
|
||||
},
|
||||
buffer -> {
|
||||
int index = buffer.readIndex();
|
||||
// https://github.com/jvm-profiling-tools/async-profiler/blob/a38a375dc62b31a8109f3af97366a307abb0fe6f/src/converter/one/jfr/JfrReader.java#L393
|
||||
int result = 0;
|
||||
for (int shift = 0; ; shift += 7) {
|
||||
byte b = buffer.nioBuffer.get(index++);
|
||||
result |= (b & 0x7f) << shift;
|
||||
if (b >= 0) {
|
||||
buffer.readIndex += index - buffer.readIndex();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
});
|
||||
static final TypeImpl<Long> VAR_LONG = new TypeImpl<>(Long.class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(10);
|
||||
int size = 0;
|
||||
while (true) {
|
||||
if ((value & ~((long) SEGMENT_BITS)) == 0) {
|
||||
buffer.nioBuffer.put(buffer.writeIndex() + size, (byte) value.intValue());
|
||||
return size + 1;
|
||||
}
|
||||
buffer.nioBuffer.put(buffer.writeIndex() + size, (byte) (value & SEGMENT_BITS | CONTINUE_BIT));
|
||||
size++;
|
||||
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||
value >>>= 7;
|
||||
}
|
||||
},
|
||||
buffer -> {
|
||||
int length = 0;
|
||||
|
||||
long value = 0;
|
||||
int position = 0;
|
||||
byte currentByte;
|
||||
|
||||
while (true) {
|
||||
currentByte = buffer.nioBuffer.get(buffer.readIndex() + length);
|
||||
length++;
|
||||
value |= (long) (currentByte & SEGMENT_BITS) << position;
|
||||
if ((currentByte & CONTINUE_BIT) == 0) break;
|
||||
position += 7;
|
||||
if (position >= 64) throw new RuntimeException("VarLong is too big");
|
||||
}
|
||||
buffer.readIndex += length;
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<byte[]> RAW_BYTES = new TypeImpl<>(byte[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.ensureSize(value.length);
|
||||
buffer.nioBuffer.put(buffer.writeIndex(), value);
|
||||
return value.length;
|
||||
},
|
||||
buffer -> {
|
||||
final int limit = buffer.nioBuffer.limit();
|
||||
final int length = limit - buffer.readIndex();
|
||||
assert length > 0 : "Invalid remaining: " + length;
|
||||
final byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
return bytes;
|
||||
});
|
||||
static final TypeImpl<String> STRING = new TypeImpl<>(String.class,
|
||||
(buffer, value) -> {
|
||||
final byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
buffer.write(VAR_INT, bytes.length);
|
||||
buffer.write(RAW_BYTES, bytes);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final int remaining = buffer.nioBuffer.limit() - buffer.readIndex();
|
||||
Check.argCondition(length > remaining, "String is too long (length: {0}, readable: {1})", length, remaining);
|
||||
byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
});
|
||||
static final TypeImpl<NBT> NBT = new TypeImpl<>(NBT.class,
|
||||
(buffer, value) -> {
|
||||
NBTWriter nbtWriter = buffer.nbtWriter;
|
||||
if (nbtWriter == null) {
|
||||
nbtWriter = new NBTWriter(new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) {
|
||||
buffer.write(BYTE, (byte) b);
|
||||
}
|
||||
}, CompressedProcesser.NONE);
|
||||
buffer.nbtWriter = nbtWriter;
|
||||
}
|
||||
try {
|
||||
if (value == NBTEnd.INSTANCE) {
|
||||
// Kotlin - https://discord.com/channels/706185253441634317/706186227493109860/1163703658341478462
|
||||
buffer.write(BYTE, (byte) NBTType.TAG_End.getOrdinal());
|
||||
} else {
|
||||
buffer.write(BYTE, (byte) value.getID().getOrdinal());
|
||||
nbtWriter.writeRaw(value);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
NBTReader nbtReader = buffer.nbtReader;
|
||||
if (nbtReader == null) {
|
||||
nbtReader = new NBTReader(new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
return buffer.read(BYTE) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return buffer.readableBytes();
|
||||
}
|
||||
}, CompressedProcesser.NONE);
|
||||
buffer.nbtReader = nbtReader;
|
||||
}
|
||||
try {
|
||||
byte tagId = buffer.read(BYTE);
|
||||
if (tagId == NBTType.TAG_End.getOrdinal())
|
||||
return NBTEnd.INSTANCE;
|
||||
return nbtReader.readRaw(tagId);
|
||||
} catch (IOException | NBTException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
static final TypeImpl<Point> BLOCK_POSITION = new TypeImpl<>(Point.class,
|
||||
(buffer, value) -> {
|
||||
final int blockX = value.blockX();
|
||||
final int blockY = value.blockY();
|
||||
final int blockZ = value.blockZ();
|
||||
final long longPos = (((long) blockX & 0x3FFFFFF) << 38) |
|
||||
(((long) blockZ & 0x3FFFFFF) << 12) |
|
||||
((long) blockY & 0xFFF);
|
||||
buffer.write(LONG, longPos);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final long value = buffer.read(LONG);
|
||||
final int x = (int) (value >> 38);
|
||||
final int y = (int) (value << 52 >> 52);
|
||||
final int z = (int) (value << 26 >> 38);
|
||||
return new Vec(x, y, z);
|
||||
});
|
||||
static final TypeImpl<Component> COMPONENT = new TypeImpl<>(Component.class,
|
||||
(buffer, value) -> {
|
||||
final NBT nbt = NbtComponentSerializer.nbt().serialize(value);
|
||||
buffer.write(NBT, nbt);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final NBT nbt = buffer.read(NBT);
|
||||
return NbtComponentSerializer.nbt().deserialize(nbt);
|
||||
});
|
||||
static final TypeImpl<Component> JSON_COMPONENT = new TypeImpl<>(Component.class,
|
||||
(buffer, value) -> {
|
||||
final String json = GsonComponentSerializer.gson().serialize(value);
|
||||
buffer.write(STRING, json);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final String json = buffer.read(STRING);
|
||||
return GsonComponentSerializer.gson().deserialize(json);
|
||||
});
|
||||
static final TypeImpl<UUID> UUID = new TypeImpl<>(UUID.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(LONG, value.getMostSignificantBits());
|
||||
buffer.write(LONG, value.getLeastSignificantBits());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final long mostSignificantBits = buffer.read(LONG);
|
||||
final long leastSignificantBits = buffer.read(LONG);
|
||||
return new UUID(mostSignificantBits, leastSignificantBits);
|
||||
});
|
||||
static final TypeImpl<ItemStack> ITEM = new TypeImpl<>(ItemStack.class,
|
||||
(buffer, value) -> {
|
||||
if (value.isAir()) {
|
||||
buffer.write(BOOLEAN, false);
|
||||
return -1;
|
||||
}
|
||||
buffer.write(BOOLEAN, true);
|
||||
buffer.write(VAR_INT, value.material().id());
|
||||
buffer.write(BYTE, (byte) value.amount());
|
||||
|
||||
// Vanilla does not write an empty object, just an end tag.
|
||||
NBTCompound nbt = value.meta().toNBT();
|
||||
buffer.write(NBT, nbt.isEmpty() ? NBTEnd.INSTANCE : nbt);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final boolean present = buffer.read(BOOLEAN);
|
||||
if (!present) return ItemStack.AIR;
|
||||
|
||||
final int id = buffer.read(VAR_INT);
|
||||
final Material material = Material.fromId(id);
|
||||
if (material == null) throw new RuntimeException("Unknown material id: " + id);
|
||||
|
||||
final int amount = buffer.read(BYTE);
|
||||
final NBT nbt = buffer.read(NBT);
|
||||
if (!(nbt instanceof NBTCompound compound)) {
|
||||
return ItemStack.of(material, amount);
|
||||
}
|
||||
|
||||
return ItemStack.fromNBT(material, compound, amount);
|
||||
});
|
||||
static final TypeImpl<byte[]> BYTE_ARRAY = new TypeImpl<>(byte[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
buffer.write(RAW_BYTES, value);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
return bytes;
|
||||
});
|
||||
static final TypeImpl<long[]> LONG_ARRAY = new TypeImpl<>(long[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
for (long l : value) {
|
||||
buffer.write(LONG, l);
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final long[] longs = new long[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
longs[i] = buffer.read(LONG);
|
||||
}
|
||||
return longs;
|
||||
});
|
||||
static final TypeImpl<int[]> VAR_INT_ARRAY = new TypeImpl<>(int[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
for (int i : value) {
|
||||
buffer.write(VAR_INT, i);
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final int[] ints = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
ints[i] = buffer.read(VAR_INT);
|
||||
}
|
||||
return ints;
|
||||
});
|
||||
static final TypeImpl<long[]> VAR_LONG_ARRAY = new TypeImpl<>(long[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.length);
|
||||
for (long l : value) {
|
||||
buffer.write(VAR_LONG, l);
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final long[] longs = new long[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
longs[i] = buffer.read(VAR_LONG);
|
||||
}
|
||||
return longs;
|
||||
});
|
||||
// METADATA
|
||||
static final TypeImpl<Component> OPT_CHAT = new TypeImpl<>(Component.class,
|
||||
(buffer, value) -> {
|
||||
if (value == null) {
|
||||
buffer.write(BOOLEAN, false);
|
||||
return -1;
|
||||
}
|
||||
buffer.write(BOOLEAN, true);
|
||||
buffer.write(COMPONENT, value);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final boolean present = buffer.read(BOOLEAN);
|
||||
if (!present) return null;
|
||||
return buffer.read(COMPONENT);
|
||||
});
|
||||
static final TypeImpl<Point> ROTATION = new TypeImpl<>(Point.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(FLOAT, (float) value.x());
|
||||
buffer.write(FLOAT, (float) value.y());
|
||||
buffer.write(FLOAT, (float) value.z());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final float x = buffer.read(FLOAT);
|
||||
final float y = buffer.read(FLOAT);
|
||||
final float z = buffer.read(FLOAT);
|
||||
return new Vec(x, y, z);
|
||||
});
|
||||
static final TypeImpl<Point> OPT_BLOCK_POSITION = new TypeImpl<>(Point.class,
|
||||
(buffer, value) -> {
|
||||
if (value == null) {
|
||||
buffer.write(BOOLEAN, false);
|
||||
return -1;
|
||||
}
|
||||
buffer.write(BOOLEAN, true);
|
||||
buffer.write(BLOCK_POSITION, value);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final boolean present = buffer.read(BOOLEAN);
|
||||
if (!present) return null;
|
||||
return buffer.read(BLOCK_POSITION);
|
||||
});
|
||||
static final TypeImpl<Direction> DIRECTION = new TypeImpl<>(Direction.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.ordinal());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int ordinal = buffer.read(VAR_INT);
|
||||
return Direction.values()[ordinal];
|
||||
});
|
||||
static final TypeImpl<UUID> OPT_UUID = new TypeImpl<>(UUID.class,
|
||||
(buffer, value) -> {
|
||||
if (value == null) {
|
||||
buffer.write(BOOLEAN, false);
|
||||
return -1;
|
||||
}
|
||||
buffer.write(BOOLEAN, true);
|
||||
buffer.write(UUID, value);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final boolean present = buffer.read(BOOLEAN);
|
||||
if (!present) return null;
|
||||
return buffer.read(UUID);
|
||||
});
|
||||
static final TypeImpl<Integer> BLOCK_STATE = new TypeImpl<>(Integer.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(NetworkBuffer.VAR_INT, value);
|
||||
return -1;
|
||||
},
|
||||
buffer -> buffer.read(VAR_INT));
|
||||
static final TypeImpl<Integer> OPT_BLOCK_STATE = new TypeImpl<>(Integer.class,
|
||||
(buffer, value) -> {
|
||||
if (value == null) {
|
||||
buffer.write(NetworkBuffer.VAR_INT, 0);
|
||||
return -1;
|
||||
}
|
||||
buffer.write(VAR_INT, value);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int value = buffer.read(VAR_INT);
|
||||
return value == 0 ? null : value;
|
||||
});
|
||||
static final TypeImpl<int[]> VILLAGER_DATA = new TypeImpl<>(int[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value[0]);
|
||||
buffer.write(VAR_INT, value[1]);
|
||||
buffer.write(VAR_INT, value[2]);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int[] value = new int[3];
|
||||
value[0] = buffer.read(VAR_INT);
|
||||
value[1] = buffer.read(VAR_INT);
|
||||
value[2] = buffer.read(VAR_INT);
|
||||
return value;
|
||||
});
|
||||
static final TypeImpl<Integer> OPT_VAR_INT = new TypeImpl<>(int.class,
|
||||
(buffer, value) -> {
|
||||
if (value == null) {
|
||||
buffer.write(VAR_INT, 0);
|
||||
return -1;
|
||||
}
|
||||
buffer.write(VAR_INT, value + 1);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int value = buffer.read(VAR_INT);
|
||||
return value == 0 ? null : value - 1;
|
||||
});
|
||||
static final TypeImpl<Entity.Pose> POSE = new TypeImpl<>(Entity.Pose.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.ordinal());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int ordinal = buffer.read(VAR_INT);
|
||||
return Entity.Pose.values()[ordinal];
|
||||
});
|
||||
static final TypeImpl<DeathLocation> DEATH_LOCATION = new TypeImpl<>(DeathLocation.class,
|
||||
(buffer, value) -> {
|
||||
if (value == null) {
|
||||
buffer.write(BOOLEAN, false);
|
||||
} else {
|
||||
buffer.write(BOOLEAN, true);
|
||||
buffer.write(STRING, value.dimension());
|
||||
buffer.write(BLOCK_POSITION, value.position());
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
if (buffer.read(BOOLEAN)) {
|
||||
return new DeathLocation(buffer.read(STRING), buffer.read(BLOCK_POSITION));
|
||||
}
|
||||
return null;
|
||||
});
|
||||
static final TypeImpl<CatMeta.Variant> CAT_VARIANT = new TypeImpl<>(CatMeta.Variant.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.ordinal());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int ordinal = buffer.read(VAR_INT);
|
||||
return CatMeta.Variant.values()[ordinal];
|
||||
});
|
||||
static final TypeImpl<FrogMeta.Variant> FROG_VARIANT = new TypeImpl<>(FrogMeta.Variant.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.ordinal());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int ordinal = buffer.read(VAR_INT);
|
||||
return FrogMeta.Variant.values()[ordinal];
|
||||
});
|
||||
static final TypeImpl<PaintingMeta.Variant> PAINTING_VARIANT = new TypeImpl<>(PaintingMeta.Variant.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.ordinal());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int ordinal = buffer.read(VAR_INT);
|
||||
return PaintingMeta.Variant.values()[ordinal];
|
||||
});
|
||||
static final TypeImpl<SnifferMeta.State> SNIFFER_STATE = new TypeImpl<>(SnifferMeta.State.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(VAR_INT, value.ordinal());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final int ordinal = buffer.read(VAR_INT);
|
||||
return SnifferMeta.State.values()[ordinal];
|
||||
});
|
||||
static final TypeImpl<Point> VECTOR3 = new TypeImpl<>(Point.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(FLOAT, (float) value.x());
|
||||
buffer.write(FLOAT, (float) value.y());
|
||||
buffer.write(FLOAT, (float) value.z());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final float x = buffer.read(FLOAT);
|
||||
final float y = buffer.read(FLOAT);
|
||||
final float z = buffer.read(FLOAT);
|
||||
return new Vec(x, y, z);
|
||||
});
|
||||
static final TypeImpl<Point> VECTOR3D = new TypeImpl<>(Point.class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(DOUBLE, value.x());
|
||||
buffer.write(DOUBLE, value.y());
|
||||
buffer.write(DOUBLE, value.z());
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final double x = buffer.read(DOUBLE);
|
||||
final double y = buffer.read(DOUBLE);
|
||||
final double z = buffer.read(DOUBLE);
|
||||
return new Vec(x, y, z);
|
||||
});
|
||||
static final TypeImpl<float[]> QUATERNION = new TypeImpl<>(float[].class,
|
||||
(buffer, value) -> {
|
||||
buffer.write(FLOAT, value[0]);
|
||||
buffer.write(FLOAT, value[1]);
|
||||
buffer.write(FLOAT, value[2]);
|
||||
buffer.write(FLOAT, value[3]);
|
||||
return -1;
|
||||
},
|
||||
buffer -> {
|
||||
final float x = buffer.read(FLOAT);
|
||||
final float y = buffer.read(FLOAT);
|
||||
final float z = buffer.read(FLOAT);
|
||||
final float w = buffer.read(FLOAT);
|
||||
return new float[]{x, y, z, w};
|
||||
});
|
||||
static final TypeImpl<Particle> PARTICLE = new TypeImpl<>(Particle.class,
|
||||
(buffer, value) -> {
|
||||
Check.stateCondition(value.data() != null && !value.data().validate(value.id()), "Particle data {0} is not valid for this particle type {1}", value.data(), value.namespace());
|
||||
Check.stateCondition(value.data() == null && ParticleData.requiresData(value.id()), "Particle data is required for this particle type {0}", value.namespace());
|
||||
|
||||
buffer.write(VAR_INT, value.id());
|
||||
|
||||
if (value.data() != null) value.data().write(buffer);
|
||||
return -1;
|
||||
},
|
||||
buffer -> null);
|
||||
|
||||
record TypeImpl<T>(@NotNull Class<T> type,
|
||||
@NotNull TypeWriter<T> writer,
|
||||
@NotNull TypeReader<T> reader) implements NetworkBuffer.Type<T> {
|
||||
}
|
||||
|
||||
interface TypeWriter<T> {
|
||||
long write(@NotNull NetworkBuffer buffer, @UnknownNullability T value);
|
||||
}
|
||||
|
||||
interface TypeReader<T> {
|
||||
@UnknownNullability T read(@NotNull NetworkBuffer buffer);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue