chore: basic nbt reader/writer for protocol while waiting for adventure

This commit is contained in:
mworzala 2024-04-10 08:34:12 -04:00
parent 687968eea0
commit c6b1ded750
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
6 changed files with 111 additions and 41 deletions

View File

@ -12,13 +12,13 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.data.WorldPos;
import net.minestom.server.particle.Particle;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.nbt.BinaryTagReader;
import net.minestom.server.utils.nbt.BinaryTagWriter;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
@ -81,8 +81,8 @@ public final class NetworkBuffer {
int writeIndex;
int readIndex;
DataOutput nbtWriter;
DataInput nbtReader;
BinaryTagWriter nbtWriter;
BinaryTagReader nbtReader;
public NetworkBuffer(@NotNull ByteBuffer buffer, boolean resizable) {
this.nioBuffer = buffer.order(ByteOrder.BIG_ENDIAN);

View File

@ -1,5 +1,8 @@
package net.minestom.server.network;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.EndBinaryTag;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
@ -10,13 +13,12 @@ import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.data.WorldPos;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.data.ParticleData;
import net.minestom.server.utils.nbt.BinaryTagReader;
import net.minestom.server.utils.nbt.BinaryTagWriter;
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.io.*;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@ -283,37 +285,31 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
}
}
record NbtType() implements NetworkBufferTypeImpl<NBT> {
record NbtType() implements NetworkBufferTypeImpl<BinaryTag> {
@Override
public void write(@NotNull NetworkBuffer buffer, org.jglrxavpok.hephaistos.nbt.NBT value) {
NBTWriter nbtWriter = buffer.nbtWriter;
public void write(@NotNull NetworkBuffer buffer, BinaryTag value) {
BinaryTagWriter nbtWriter = buffer.nbtWriter;
if (nbtWriter == null) {
nbtWriter = new NBTWriter(new OutputStream() {
nbtWriter = new BinaryTagWriter(new DataOutputStream(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);
}
nbtWriter.writeNameless(value);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public org.jglrxavpok.hephaistos.nbt.NBT read(@NotNull NetworkBuffer buffer) {
NBTReader nbtReader = buffer.nbtReader;
public BinaryTag read(@NotNull NetworkBuffer buffer) {
BinaryTagReader nbtReader = buffer.nbtReader;
if (nbtReader == null) {
nbtReader = new NBTReader(new InputStream() {
nbtReader = new BinaryTagReader(new DataInputStream(new InputStream() {
@Override
public int read() {
return buffer.read(BYTE) & 0xFF;
@ -323,15 +319,12 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
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) {
return nbtReader.readNameless();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@ -362,13 +355,13 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
record ComponentType() implements NetworkBufferTypeImpl<Component> {
@Override
public void write(@NotNull NetworkBuffer buffer, Component value) {
final NBT nbt = NbtComponentSerializer.nbt().serialize(value);
final BinaryTag nbt = NbtComponentSerializer.nbt().serialize(value);
buffer.write(NBT, nbt);
}
@Override
public Component read(@NotNull NetworkBuffer buffer) {
final NBT nbt = buffer.read(NBT);
final BinaryTag nbt = buffer.read(NBT);
return NbtComponentSerializer.nbt().deserialize(nbt);
}
}
@ -413,8 +406,8 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
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);
CompoundBinaryTag nbt = value.meta().toNBT();
buffer.write(NBT, nbt.size() == 0 ? EndBinaryTag.endBinaryTag() : nbt);
}
@Override
@ -427,8 +420,8 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
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)) {
final BinaryTag nbt = buffer.read(NBT);
if (!(nbt instanceof CompoundBinaryTag compound)) {
return ItemStack.of(material, amount);
}
return ItemStack.fromNBT(material, compound, amount);

View File

@ -1,7 +1,7 @@
package net.minestom.server.tag;
import net.kyori.adventure.nbt.*;
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.nbt.BinaryTagUtil;
import java.util.ArrayList;
import java.util.List;
@ -51,7 +51,7 @@ final class TagNbtSeparator {
var tagFunction = SUPPORTED_TYPES.get(nbt.type());
if (tagFunction != null) {
Tag tag = tagFunction.apply(key);
consumer.accept(makeEntry(path, tag, NBTUtils.nbtValueFromTag(nbt)));
consumer.accept(makeEntry(path, tag, BinaryTagUtil.nbtValueFromTag(nbt)));
} else if (nbt instanceof CompoundBinaryTag nbtCompound) {
for (var ent : nbtCompound) {
var newPath = new ArrayList<>(path);
@ -68,7 +68,7 @@ final class TagNbtSeparator {
var tag = tagFunction.apply(key).list();
Object[] values = new Object[nbtList.size()];
for (int i = 0; i < values.length; i++) {
values[i] = NBTUtils.nbtValueFromTag(nbtList.get(i));
values[i] = BinaryTagUtil.nbtValueFromTag(nbtList.get(i));
}
consumer.accept(makeEntry(path, Tag.class.cast(tag), List.of(values)));
} catch (Exception e) {

View File

@ -0,0 +1,37 @@
package net.minestom.server.utils.nbt;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagType;
import net.kyori.adventure.nbt.BinaryTagTypes;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.IOException;
import java.util.Map;
// Based on net.kyori.adventure.nbt.BinaryTagReaderImpl licensed under the MIT license.
// https://github.com/KyoriPowered/adventure/blob/main/4/nbt/src/main/java/net/kyori/adventure/nbt/BinaryTagReaderImpl.java
public class BinaryTagReader {
static {
BinaryTagTypes.COMPOUND.id(); // Force initialization
}
private final DataInput input;
public BinaryTagReader(@NotNull DataInput input) {
this.input = input;
}
public @NotNull BinaryTag readNameless() throws IOException {
BinaryTagType<? extends BinaryTag> type = BinaryTagUtil.nbtTypeFromId(input.readByte());
return type.read(input);
}
public @NotNull Map.Entry<String, BinaryTag> readNamed() throws IOException {
BinaryTagType<? extends BinaryTag> type = BinaryTagUtil.nbtTypeFromId(input.readByte());
String name = input.readUTF();
return Map.entry(name, type.read(input));
}
}

View File

@ -1,4 +1,4 @@
package net.minestom.server.utils;
package net.minestom.server.utils.nbt;
import net.kyori.adventure.nbt.*;
import net.minestom.server.utils.validate.Check;
@ -6,7 +6,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ApiStatus.Internal
public final class NBTUtils {
public final class BinaryTagUtil {
private static final BinaryTagType<?>[] TYPES = new BinaryTagType[]{
BinaryTagTypes.END,
BinaryTagTypes.BYTE,
@ -54,6 +54,6 @@ public final class NBTUtils {
}
}
private NBTUtils() {
private BinaryTagUtil() {
}
}

View File

@ -0,0 +1,40 @@
package net.minestom.server.utils.nbt;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagType;
import net.kyori.adventure.nbt.BinaryTagTypes;
import org.jetbrains.annotations.NotNull;
import java.io.DataOutput;
import java.io.IOException;
// Based on net.kyori.adventure.nbt.BinaryTagWriterImpl licensed under the MIT license.
// https://github.com/KyoriPowered/adventure/blob/main/4/nbt/src/main/java/net/kyori/adventure/nbt/BinaryTagWriterImpl.java
public class BinaryTagWriter {
static {
BinaryTagTypes.COMPOUND.id(); // Force initialization
}
private final DataOutput output;
public BinaryTagWriter(@NotNull DataOutput output) {
this.output = output;
}
public void writeNameless(@NotNull BinaryTag tag) throws IOException {
//noinspection unchecked
BinaryTagType<BinaryTag> type = (BinaryTagType<BinaryTag>) tag.type();
output.writeByte(type.id());
type.write(tag, output);
}
public void readNamed(@NotNull String name, @NotNull BinaryTag tag) throws IOException {
//noinspection unchecked
BinaryTagType<BinaryTag> type = (BinaryTagType<BinaryTag>) tag.type();
output.writeByte(type.id());
output.writeUTF(name);
type.write(tag, output);
}
}