diff --git a/nbt/LICENSE b/nbt/LICENSE
new file mode 100644
index 00000000..f3e916a9
--- /dev/null
+++ b/nbt/LICENSE
@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2025, SpigotMC Pty. Ltd.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/nbt/README.md b/nbt/README.md
new file mode 100644
index 00000000..86305b4a
--- /dev/null
+++ b/nbt/README.md
@@ -0,0 +1,4 @@
+BungeeCord-NBT
+=================
+
+Minimal implementation of NBT for use in BungeeCord
diff --git a/nbt/nb-configuration.xml b/nbt/nb-configuration.xml
new file mode 100644
index 00000000..7e465924
--- /dev/null
+++ b/nbt/nb-configuration.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ project
+ NEW_LINE
+ NEW_LINE
+ NEW_LINE
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
+
diff --git a/nbt/pom.xml b/nbt/pom.xml
new file mode 100644
index 00000000..fd457927
--- /dev/null
+++ b/nbt/pom.xml
@@ -0,0 +1,27 @@
+
+
+ 4.0.0
+
+
+ net.md-5
+ bungeecord-parent
+ 1.21-R0.3-SNAPSHOT
+ ../pom.xml
+
+
+ net.md-5
+ bungeecord-nbt
+ 1.21-R0.3-SNAPSHOT
+ jar
+
+ BungeeCord-NBT
+ Minimal implementation of NBT for use in BungeeCord
+
+
+ BSD-3-Clause
+ https://github.com/SpigotMC/BungeeCord/blob/master/dialog/LICENSE
+ repo
+
+
+
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java
new file mode 100644
index 00000000..c707c157
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java
@@ -0,0 +1,52 @@
+package net.md_5.bungee.nbt;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+import net.md_5.bungee.nbt.type.CompoundTag;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class NamedTag implements Tag
+{
+
+ private String name;
+ private TypedTag tag;
+
+ /**
+ * Reads the data of the {@link DataInput} and parses it into this
+ * {@link NamedTag}.
+ *
+ * @param input input to read from
+ * @param limiter limitation of the read data
+ */
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ byte type = input.readByte();
+ name = CompoundTag.readString( input, limiter );
+ tag = Tag.readById( type, input, limiter );
+ }
+
+ /**
+ * Write this {@link NamedTag} into a {@link DataOutput}.
+ *
+ * @param output the output to write to
+ */
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( name, "name cannot be null" );
+ Preconditions.checkNotNull( tag, "tag cannot be null" );
+
+ output.writeByte( tag.getId() );
+ CompoundTag.writeString( name, output );
+ tag.write( output );
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/Tag.java b/nbt/src/main/java/net/md_5/bungee/nbt/Tag.java
new file mode 100644
index 00000000..d6687c60
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/Tag.java
@@ -0,0 +1,131 @@
+package net.md_5.bungee.nbt;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.function.Supplier;
+import net.md_5.bungee.nbt.exception.NBTFormatException;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+import net.md_5.bungee.nbt.type.ByteArrayTag;
+import net.md_5.bungee.nbt.type.ByteTag;
+import net.md_5.bungee.nbt.type.CompoundTag;
+import net.md_5.bungee.nbt.type.DoubleTag;
+import net.md_5.bungee.nbt.type.EndTag;
+import net.md_5.bungee.nbt.type.FloatTag;
+import net.md_5.bungee.nbt.type.IntArrayTag;
+import net.md_5.bungee.nbt.type.IntTag;
+import net.md_5.bungee.nbt.type.ListTag;
+import net.md_5.bungee.nbt.type.LongArrayTag;
+import net.md_5.bungee.nbt.type.LongTag;
+import net.md_5.bungee.nbt.type.ShortTag;
+import net.md_5.bungee.nbt.type.StringTag;
+
+public interface Tag
+{
+
+ int OBJECT_HEADER = 8;
+ int ARRAY_HEADER = 12;
+ int STRING_SIZE = 28;
+ int OBJECT_REFERENCE = 4;
+
+ Supplier extends TypedTag>[] CONSTRUCTORS = new Supplier[]
+ {
+ EndTag::new,
+ ByteTag::new,
+ ShortTag::new,
+ IntTag::new,
+ LongTag::new,
+ FloatTag::new,
+ DoubleTag::new,
+ ByteArrayTag::new,
+ StringTag::new,
+ ListTag::new,
+ CompoundTag::new,
+ IntArrayTag::new,
+ LongArrayTag::new
+ };
+
+ byte END = 0;
+ byte BYTE = 1;
+ byte SHORT = 2;
+ byte INT = 3;
+ byte LONG = 4;
+ byte FLOAT = 5;
+ byte DOUBLE = 6;
+ byte BYTE_ARRAY = 7;
+ byte STRING = 8;
+ byte LIST = 9;
+ byte COMPOUND = 10;
+ byte INT_ARRAY = 11;
+ byte LONG_ARRAY = 12;
+
+ /**
+ * Reads the data into this tag.
+ *
+ * @param input the input to read from
+ * @param limiter the limiter for this read operation
+ * @throws IOException if an exception occurs during io operations
+ */
+ void read(DataInput input, NBTLimiter limiter) throws IOException;
+
+ /**
+ * Writes this tag into a {@link DataOutput}.
+ *
+ * @param output the output to write to
+ * @throws IOException if an exception occurs during io operations
+ */
+ void write(DataOutput output) throws IOException;
+
+ /**
+ * Reads the data of the {@link DataInput} and parses it into a {@link Tag}.
+ *
+ * @param id the nbt type
+ * @param input input to read from
+ * @param limiter limitation of the read data
+ * @return the initialized {@link Tag}
+ * @throws IOException if an exception occurs during io operations
+ */
+ static TypedTag readById(byte id, DataInput input, NBTLimiter limiter) throws IOException
+ {
+ if ( id < END || id > LONG_ARRAY )
+ {
+ throw new NBTFormatException( "Invalid tag id: " + id );
+ }
+
+ TypedTag tag = CONSTRUCTORS[id].get();
+ tag.read( input, limiter );
+ return tag;
+ }
+
+ static NamedTag readNamedTag(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ NamedTag namedTag = new NamedTag();
+ namedTag.read( input, limiter );
+ return namedTag;
+ }
+
+ static byte[] toByteArray(TypedTag tag) throws IOException
+ {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ DataOutputStream dataOutputStream = new DataOutputStream( byteArrayOutputStream );
+ dataOutputStream.writeByte( tag.getId() );
+ tag.write( dataOutputStream );
+ return byteArrayOutputStream.toByteArray();
+ }
+
+ static TypedTag fromByteArray(byte[] data) throws IOException
+ {
+ return fromByteArray( data, NBTLimiter.unlimitedSize() );
+ }
+
+ static TypedTag fromByteArray(byte[] data, NBTLimiter limiter) throws IOException
+ {
+ DataInputStream stream = new DataInputStream( new ByteArrayInputStream( data ) );
+ byte type = stream.readByte();
+ return readById( type, stream, limiter );
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java
new file mode 100644
index 00000000..1ffdae59
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java
@@ -0,0 +1,12 @@
+package net.md_5.bungee.nbt;
+
+public interface TypedTag extends Tag
+{
+
+ /**
+ * Gets the id of this tag's type.
+ *
+ * @return the id related to this tag's type
+ */
+ byte getId();
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTException.java b/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTException.java
new file mode 100644
index 00000000..d70f7250
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTException.java
@@ -0,0 +1,10 @@
+package net.md_5.bungee.nbt.exception;
+
+public class NBTException extends RuntimeException
+{
+
+ public NBTException(String message)
+ {
+ super( message );
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTFormatException.java b/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTFormatException.java
new file mode 100644
index 00000000..d813dc49
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTFormatException.java
@@ -0,0 +1,10 @@
+package net.md_5.bungee.nbt.exception;
+
+public class NBTFormatException extends NBTException
+{
+
+ public NBTFormatException(String message)
+ {
+ super( message );
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTLimitException.java b/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTLimitException.java
new file mode 100644
index 00000000..7af9dab8
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/exception/NBTLimitException.java
@@ -0,0 +1,10 @@
+package net.md_5.bungee.nbt.exception;
+
+public class NBTLimitException extends NBTException
+{
+
+ public NBTLimitException(String message)
+ {
+ super( message );
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java b/nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java
new file mode 100644
index 00000000..7821f6f6
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java
@@ -0,0 +1,66 @@
+package net.md_5.bungee.nbt.limit;
+
+import lombok.RequiredArgsConstructor;
+import net.md_5.bungee.nbt.exception.NBTLimitException;
+
+@RequiredArgsConstructor
+public class NBTLimiter
+{
+
+ private static final int MAX_STACK_DEPTH = 512;
+ //
+ private final long maxBytes;
+ private final int maxDepth;
+
+ public static NBTLimiter unlimitedSize()
+ {
+ return new NBTLimiter( Long.MAX_VALUE, MAX_STACK_DEPTH );
+ }
+
+ public NBTLimiter(long maxBytes)
+ {
+ this( maxBytes, MAX_STACK_DEPTH );
+ }
+
+ private long usedBytes;
+ private int depth;
+
+ public void countBytes(long amount)
+ {
+ if ( amount < 0 )
+ {
+ throw new NBTLimitException( "NBT limiter tried to count negative byte amount" );
+ }
+
+ if ( ( usedBytes = Math.addExact( usedBytes, amount ) ) > maxBytes )
+ {
+ throw new NBTLimitException( "NBT tag is to big, bytes > " + maxBytes );
+ }
+ }
+
+ public void countBytes(long amount, long factor)
+ {
+ if ( amount < 0 || factor < 0 )
+ {
+ throw new NBTLimitException( "NBT limiter tried to count negative byte amount" );
+ }
+
+ countBytes( Math.multiplyExact( amount, factor ) );
+ }
+
+ public void push()
+ {
+ if ( ( depth = Math.addExact( depth, 1 ) ) > maxDepth )
+ {
+ throw new NBTLimitException( "NBT tag is to complex, depth > " + maxDepth );
+ }
+ }
+
+ public void pop()
+ {
+ if ( --depth < 0 )
+ {
+ throw new NBTLimitException( "NBT limiter tried to pop depth 0" );
+ }
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java
new file mode 100644
index 00000000..e3152412
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java
@@ -0,0 +1,44 @@
+package net.md_5.bungee.nbt.type;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ByteArrayTag implements TypedTag
+{
+
+ private byte[] value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + ARRAY_HEADER + Integer.BYTES );
+ int length = input.readInt();
+ limiter.countBytes( length, Byte.BYTES );
+ input.readFully( value = new byte[ length ] );
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( value, "byte array value cannot be null" );
+ output.writeInt( value.length );
+ output.write( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.BYTE_ARRAY;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java
new file mode 100644
index 00000000..1a707e87
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java
@@ -0,0 +1,39 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ByteTag implements TypedTag
+{
+
+ private byte value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + Byte.BYTES );
+ value = input.readByte();
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ output.write( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.BYTE;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java
new file mode 100644
index 00000000..bdafbed8
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java
@@ -0,0 +1,99 @@
+package net.md_5.bungee.nbt.type;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.exception.NBTFormatException;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CompoundTag implements TypedTag
+{
+
+ private static final int MAP_SIZE_IN_BYTES = 48;
+ private static final int MAP_ENTRY_SIZE_IN_BYTES = 32;
+ //
+ private Map value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.push();
+ limiter.countBytes( MAP_SIZE_IN_BYTES );
+ Map map = new LinkedHashMap<>();
+ for ( byte type; ( type = input.readByte() ) != Tag.END; )
+ {
+ String name = readString( input, limiter );
+ TypedTag tag = Tag.readById( type, input, limiter );
+ if ( map.put( name, tag ) == null )
+ {
+ limiter.countBytes( MAP_ENTRY_SIZE_IN_BYTES + OBJECT_REFERENCE );
+ }
+ }
+ limiter.pop();
+ value = map;
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( value, "compound tag map cannot be null" );
+ for ( Map.Entry entry : value.entrySet() )
+ {
+ String name = entry.getKey();
+ TypedTag tag = entry.getValue();
+ output.writeByte( tag.getId() );
+ if ( tag.getId() == Tag.END )
+ {
+ throw new NBTFormatException( "invalid end tag in compound tag" );
+ }
+ writeString( name, output );
+ tag.write( output );
+ }
+ output.writeByte( 0 );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.COMPOUND;
+ }
+
+ public static String readString(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( STRING_SIZE );
+ String string = input.readUTF();
+ limiter.countBytes( string.length(), Character.BYTES );
+ return string;
+ }
+
+ public static void writeString(String string, DataOutput output) throws IOException
+ {
+ output.writeUTF( string );
+ }
+
+ public TypedTag get(String key)
+ {
+ return value.get( key );
+ }
+
+ public void put(String key, TypedTag tag)
+ {
+ value.put( key, tag );
+ }
+
+ public int size()
+ {
+ return value.size();
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java
new file mode 100644
index 00000000..de527ca3
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java
@@ -0,0 +1,39 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DoubleTag implements TypedTag
+{
+
+ private double value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + Double.BYTES );
+ value = input.readDouble();
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ output.writeDouble( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.DOUBLE;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java
new file mode 100644
index 00000000..7d47c012
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java
@@ -0,0 +1,34 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+public class EndTag implements TypedTag
+{
+
+ public static final EndTag INSTANCE = new EndTag();
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter)
+ {
+ limiter.countBytes( OBJECT_HEADER );
+ }
+
+ @Override
+ public void write(DataOutput output)
+ {
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.END;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java
new file mode 100644
index 00000000..e6077759
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java
@@ -0,0 +1,39 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class FloatTag implements TypedTag
+{
+
+ private float value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + Float.BYTES );
+ value = input.readFloat();
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ output.writeFloat( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.FLOAT;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java
new file mode 100644
index 00000000..f6d900ae
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java
@@ -0,0 +1,52 @@
+package net.md_5.bungee.nbt.type;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class IntArrayTag implements TypedTag
+{
+
+ private int[] value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + ARRAY_HEADER + Integer.BYTES );
+ int length = input.readInt();
+ limiter.countBytes( length, Integer.BYTES );
+ int[] data = new int[ length ];
+ for ( int i = 0; i < length; i++ )
+ {
+ data[i] = input.readInt();
+ }
+ value = data;
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( value, "int array value cannot be null" );
+ output.writeInt( value.length );
+ for ( int i : value )
+ {
+ output.writeInt( i );
+ }
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.INT_ARRAY;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java
new file mode 100644
index 00000000..2462be01
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java
@@ -0,0 +1,39 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class IntTag implements TypedTag
+{
+
+ private int value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + Integer.BYTES );
+ value = input.readInt();
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ output.writeInt( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.INT;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java
new file mode 100644
index 00000000..b1b591b8
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java
@@ -0,0 +1,87 @@
+package net.md_5.bungee.nbt.type;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.exception.NBTFormatException;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ListTag implements TypedTag
+{
+
+ public static final int LIST_HEADER = 12;
+ //
+ private List value;
+ private byte listType;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.push();
+ limiter.countBytes( OBJECT_HEADER + LIST_HEADER + ARRAY_HEADER + Byte.BYTES + Integer.BYTES );
+ listType = input.readByte();
+ int length = input.readInt();
+
+ if ( listType == Tag.END && length > 0 )
+ {
+ throw new NBTFormatException( "Missing type in ListTag" );
+ }
+
+ limiter.countBytes( length, OBJECT_REFERENCE );
+ List tagList = new ArrayList<>( length );
+ for ( int i = 0; i < length; i++ )
+ {
+ tagList.add( Tag.readById( listType, input, limiter ) );
+ }
+ limiter.pop();
+
+ value = tagList;
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( value, "list value cannot be null" );
+ if ( listType == Tag.END && !value.isEmpty() )
+ {
+ throw new NBTFormatException( "Missing type in ListTag" );
+ }
+ output.writeByte( listType );
+ output.writeInt( value.size() );
+ for ( TypedTag tag : value )
+ {
+ if ( tag.getId() != listType )
+ {
+ throw new NBTFormatException( "ListTag type mismatch" );
+ }
+ tag.write( output );
+ }
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.LIST;
+ }
+
+ public TypedTag get(int index)
+ {
+ return value.get( index );
+ }
+
+ public int size()
+ {
+ return value.size();
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java
new file mode 100644
index 00000000..596b3d93
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java
@@ -0,0 +1,53 @@
+package net.md_5.bungee.nbt.type;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LongArrayTag implements TypedTag
+{
+
+ private long[] value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + ARRAY_HEADER + Integer.BYTES );
+ int length = input.readInt();
+ limiter.countBytes( length, Long.BYTES );
+ long[] data = new long[ length ];
+ for ( int i = 0; i < length; i++ )
+ {
+ data[i] = input.readLong();
+ }
+ value = data;
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( value, "long array value cannot be null" );
+
+ output.writeInt( value.length );
+ for ( long i : value )
+ {
+ output.writeLong( i );
+ }
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.LONG_ARRAY;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java
new file mode 100644
index 00000000..9a187f11
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java
@@ -0,0 +1,39 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LongTag implements TypedTag
+{
+
+ private long value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + Long.BYTES );
+ value = input.readLong();
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ output.writeLong( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.LONG;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java
new file mode 100644
index 00000000..4fd87153
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java
@@ -0,0 +1,39 @@
+package net.md_5.bungee.nbt.type;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ShortTag implements TypedTag
+{
+
+ private short value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + Short.BYTES );
+ value = input.readShort();
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ output.writeShort( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.SHORT;
+ }
+}
diff --git a/nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java b/nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java
new file mode 100644
index 00000000..03e3bf08
--- /dev/null
+++ b/nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java
@@ -0,0 +1,44 @@
+package net.md_5.bungee.nbt.type;
+
+import com.google.common.base.Preconditions;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class StringTag implements TypedTag
+{
+
+ private String value;
+
+ @Override
+ public void read(DataInput input, NBTLimiter limiter) throws IOException
+ {
+ limiter.countBytes( OBJECT_HEADER + STRING_SIZE );
+ String string = input.readUTF();
+ limiter.countBytes( string.length(), Character.BYTES );
+ value = string;
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException
+ {
+ Preconditions.checkNotNull( value, "string value cannot be null" );
+
+ output.writeUTF( value );
+ }
+
+ @Override
+ public byte getId()
+ {
+ return Tag.STRING;
+ }
+}
diff --git a/nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java b/nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java
new file mode 100644
index 00000000..46306022
--- /dev/null
+++ b/nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java
@@ -0,0 +1,53 @@
+package net.md_5.bungee.nbt;
+
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.ArrayList;
+import net.md_5.bungee.nbt.exception.NBTLimitException;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+import net.md_5.bungee.nbt.type.ByteArrayTag;
+import net.md_5.bungee.nbt.type.ListTag;
+import org.junit.jupiter.api.Test;
+
+public class NBTLimiterTest
+{
+
+ @Test
+ public void testNbtLimiter()
+ {
+ assertThrows( NBTLimitException.class, () ->
+ {
+ ByteArrayTag byteArrayTag = new ByteArrayTag( new byte[ 1000 ] );
+ byte[] arr = Tag.toByteArray( byteArrayTag );
+ Tag.fromByteArray( arr, new NBTLimiter( 100, 1 ) );
+ } );
+
+ assertDoesNotThrow( () ->
+ {
+ ByteArrayTag byteArrayTag = new ByteArrayTag( new byte[ 1000 ] );
+ byte[] arr = Tag.toByteArray( byteArrayTag );
+ Tag.fromByteArray( arr, new NBTLimiter( 99999999, 1 ) );
+ } );
+ }
+
+ @Test
+ public void testDepth()
+ {
+ assertThrows( NBTLimitException.class, () ->
+ {
+ ListTag root = new ListTag( new ArrayList<>(), Tag.LIST );
+ root.getValue().add( new ListTag( new ArrayList<>(), Tag.LIST ) );
+
+ byte[] arr = Tag.toByteArray( root );
+ Tag.fromByteArray( arr, new NBTLimiter( 100, 1 ) );
+ } );
+
+ assertDoesNotThrow( () ->
+ {
+ ListTag root = new ListTag( new ArrayList<>(), Tag.LIST );
+ root.getValue().add( new ListTag( new ArrayList<>(), Tag.LIST ) );
+
+ byte[] arr = Tag.toByteArray( root );
+ Tag.fromByteArray( arr, new NBTLimiter( 100, 2 ) );
+ } );
+ }
+}
diff --git a/nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java b/nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java
new file mode 100644
index 00000000..52b8cb9e
--- /dev/null
+++ b/nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java
@@ -0,0 +1,247 @@
+package net.md_5.bungee.nbt;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+import net.md_5.bungee.nbt.exception.NBTFormatException;
+import net.md_5.bungee.nbt.type.ByteArrayTag;
+import net.md_5.bungee.nbt.type.ByteTag;
+import net.md_5.bungee.nbt.type.CompoundTag;
+import net.md_5.bungee.nbt.type.DoubleTag;
+import net.md_5.bungee.nbt.type.EndTag;
+import net.md_5.bungee.nbt.type.FloatTag;
+import net.md_5.bungee.nbt.type.IntArrayTag;
+import net.md_5.bungee.nbt.type.IntTag;
+import net.md_5.bungee.nbt.type.ListTag;
+import net.md_5.bungee.nbt.type.LongArrayTag;
+import net.md_5.bungee.nbt.type.LongTag;
+import net.md_5.bungee.nbt.type.ShortTag;
+import net.md_5.bungee.nbt.type.StringTag;
+import org.junit.jupiter.api.Test;
+
+public class NBTTagTest
+{
+
+ @Test
+ public void testByteTag() throws IOException
+ {
+ byte[] tests = new byte[]
+ {
+ 0, Byte.MAX_VALUE, Byte.MIN_VALUE
+ };
+ for ( byte value : tests )
+ {
+ ByteTag byteTag = new ByteTag( value );
+ byte[] deserialized = Tag.toByteArray( byteTag );
+ ByteTag reSerialized = (ByteTag) Tag.fromByteArray( deserialized );
+ assertEquals( byteTag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testShortTag() throws IOException
+ {
+ short[] tests = new short[]
+ {
+ 0, Short.MAX_VALUE, Short.MIN_VALUE
+ };
+ for ( short value : tests )
+ {
+ ShortTag tag = new ShortTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ ShortTag reSerialized = (ShortTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testIntTag() throws IOException
+ {
+ int[] tests = new int[]
+ {
+ 0, Integer.MAX_VALUE, Integer.MIN_VALUE
+ };
+ for ( int value : tests )
+ {
+ IntTag tag = new IntTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ IntTag reSerialized = (IntTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testLongTag() throws IOException
+ {
+ long[] tests = new long[]
+ {
+ 0, Long.MAX_VALUE, Long.MIN_VALUE
+ };
+ for ( long value : tests )
+ {
+ LongTag tag = new LongTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ LongTag reSerialized = (LongTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testDoubleTag() throws IOException
+ {
+ double[] tests = new double[]
+ {
+ 0, Double.MAX_VALUE, Double.MIN_VALUE, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY
+ };
+ for ( double value : tests )
+ {
+ DoubleTag tag = new DoubleTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ DoubleTag reSerialized = (DoubleTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testFloatTag() throws IOException
+ {
+ float[] tests = new float[]
+ {
+ 0, Float.MAX_VALUE, Float.MIN_VALUE, Float.NaN, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY
+ };
+ for ( float value : tests )
+ {
+ FloatTag tag = new FloatTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ FloatTag reSerialized = (FloatTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testStringTag() throws IOException
+ {
+ String[] tests = new String[]
+ {
+ "Outfluencer", "", String.valueOf( System.currentTimeMillis() ), "BungeeCord", new Object().toString()
+ };
+ for ( String value : tests )
+ {
+ StringTag tag = new StringTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ StringTag reSerialized = (StringTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+ }
+
+ @Test
+ public void testByteArrayTag() throws IOException
+ {
+ byte[] value = new byte[ 1024 ];
+ ThreadLocalRandom.current().nextBytes( value );
+ ByteArrayTag tag = new ByteArrayTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ ByteArrayTag reSerialized = (ByteArrayTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+
+ value = new byte[ 0 ];
+ ThreadLocalRandom.current().nextBytes( value );
+ tag = new ByteArrayTag( value );
+ deserialized = Tag.toByteArray( tag );
+ reSerialized = (ByteArrayTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+
+ @Test
+ public void testIntArrayTag() throws IOException
+ {
+ int[] value = new int[ 1024 ];
+ for ( int i = 0; i < value.length; i++ )
+ {
+ value[i] = ThreadLocalRandom.current().nextInt();
+ }
+ IntArrayTag tag = new IntArrayTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ IntArrayTag reSerialized = (IntArrayTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+
+ value = new int[ 0 ];
+ tag = new IntArrayTag( value );
+ deserialized = Tag.toByteArray( tag );
+ reSerialized = (IntArrayTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+ }
+
+ @Test
+ public void testLongArrayTag() throws IOException
+ {
+ long[] value = new long[ 1024 ];
+ for ( int i = 0; i < value.length; i++ )
+ {
+ value[i] = ThreadLocalRandom.current().nextLong();
+ }
+ LongArrayTag tag = new LongArrayTag( value );
+ byte[] deserialized = Tag.toByteArray( tag );
+ LongArrayTag reSerialized = (LongArrayTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+
+ value = new long[ 0 ];
+ tag = new LongArrayTag( value );
+ deserialized = Tag.toByteArray( tag );
+ reSerialized = (LongArrayTag) Tag.fromByteArray( deserialized );
+ assertEquals( tag, reSerialized );
+
+ }
+
+ @Test
+ public void testListTag() throws IOException
+ {
+ List tags = new ArrayList<>();
+ for ( int i = 0; i < 100; i++ )
+ {
+ tags.add( new IntTag( i ) );
+ }
+ ListTag listTag = new ListTag( tags, Tag.INT );
+ byte[] deserialized = Tag.toByteArray( listTag );
+ ListTag reSerialized = (ListTag) Tag.fromByteArray( deserialized );
+ assertEquals( reSerialized.getValue(), tags );
+ List tags2 = new ArrayList<>();
+ for ( int i = 0; i < 100; i++ )
+ {
+ tags2.add( new IntTag( i ) );
+ }
+ tags2.add( new ByteTag( Byte.MIN_VALUE ) );
+ assertThrows( NBTFormatException.class, () -> Tag.toByteArray( new ListTag( tags2, Tag.INT ) ) );
+ assertThrows( NBTFormatException.class, () -> Tag.toByteArray( new ListTag( Collections.singletonList( new EndTag() ), Tag.END ) ) );
+ }
+
+ @Test
+ public void testCompoundTag() throws IOException
+ {
+ Map map = new HashMap<>();
+ for ( int i = 0; i < 100; i++ )
+ {
+ map.put( "" + i, new IntTag( i ) );
+ map.put( "a" + i, new ByteTag( (byte) i ) );
+ map.put( "b" + i, new ShortTag( (short) i ) );
+ map.put( "c" + i, new LongTag( i ) );
+ map.put( "f" + i, new FloatTag( i ) );
+ map.put( "d" + i, new DoubleTag( i ) );
+ }
+ CompoundTag compoundTag = new CompoundTag( map );
+ byte[] deserialized = Tag.toByteArray( compoundTag );
+ CompoundTag reSerialized = (CompoundTag) Tag.fromByteArray( deserialized );
+ assertEquals( reSerialized, compoundTag );
+ Map map2 = new LinkedHashMap<>();
+ map2.put( "", new EndTag() );
+ CompoundTag compoundTag2 = new CompoundTag( map2 );
+ assertThrows( NBTFormatException.class, () -> Tag.toByteArray( compoundTag2 ) );
+ }
+}
diff --git a/nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java b/nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java
new file mode 100644
index 00000000..b7210492
--- /dev/null
+++ b/nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java
@@ -0,0 +1,30 @@
+package net.md_5.bungee.nbt;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Objects;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+import net.md_5.bungee.nbt.type.CompoundTag;
+import org.junit.jupiter.api.Test;
+
+public class PlayerDataTest
+{
+
+ @Test
+ public void testPlayerData() throws URISyntaxException, IOException
+ {
+ ClassLoader classLoader = PlayerDataTest.class.getClassLoader();
+ File file = new File( Objects.requireNonNull( classLoader.getResource( "playerdata.nbt" ) ).toURI() );
+ FileInputStream fileInputStream = new FileInputStream( file );
+ DataInputStream dis = new DataInputStream( fileInputStream );
+ NamedTag namedTag = new NamedTag();
+ namedTag.read( dis, NBTLimiter.unlimitedSize() );
+ assertInstanceOf( CompoundTag.class, namedTag.getTag() );
+ assertEquals( namedTag.getName(), "" );
+ }
+}
diff --git a/nbt/src/test/resources/playerdata.nbt b/nbt/src/test/resources/playerdata.nbt
new file mode 100644
index 00000000..899142fa
Binary files /dev/null and b/nbt/src/test/resources/playerdata.nbt differ
diff --git a/pom.xml b/pom.xml
index dd3e628f..63b12ecc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,7 @@
serializer
slf4j
native
+ nbt
diff --git a/protocol/pom.xml b/protocol/pom.xml
index 77e11507..beb3834f 100644
--- a/protocol/pom.xml
+++ b/protocol/pom.xml
@@ -40,6 +40,12 @@
${project.version}
compile
+
+ net.md-5
+ bungeecord-nbt
+ ${project.version}
+ compile
+
io.netty
netty-codec
@@ -51,11 +57,5 @@
3.1.0
compile
-
- se.llbit
- jo-nbt
- 1.3.0
- compile
-
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java
index b2a4729c..0d484acc 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java
@@ -21,10 +21,11 @@ import java.util.function.BiConsumer;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentStyle;
-import se.llbit.nbt.ErrorTag;
-import se.llbit.nbt.NamedTag;
-import se.llbit.nbt.SpecificTag;
-import se.llbit.nbt.Tag;
+import net.md_5.bungee.nbt.NamedTag;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
+import net.md_5.bungee.nbt.type.EndTag;
@RequiredArgsConstructor
public abstract class DefinedPacket
@@ -116,7 +117,7 @@ public abstract class DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
- SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
+ TypedTag nbt = (TypedTag) readTag( buf, protocolVersion );
JsonElement json = TagUtil.toJson( nbt );
return ChatSerializer.forVersion( protocolVersion ).deserialize( json );
@@ -130,7 +131,7 @@ public abstract class DefinedPacket
public static ComponentStyle readComponentStyle(ByteBuf buf, int protocolVersion)
{
- SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
+ TypedTag nbt = (TypedTag) readTag( buf, protocolVersion );
JsonElement json = TagUtil.toJson( nbt );
return ChatSerializer.forVersion( protocolVersion ).deserializeStyle( json );
@@ -152,8 +153,7 @@ public abstract class DefinedPacket
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( message );
- SpecificTag nbt = TagUtil.fromJson( json );
-
+ TypedTag nbt = TagUtil.fromJson( json );
writeTag( nbt, buf, protocolVersion );
} else
{
@@ -166,8 +166,7 @@ public abstract class DefinedPacket
public static void writeComponentStyle(ComponentStyle style, ByteBuf buf, int protocolVersion)
{
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( style );
- SpecificTag nbt = TagUtil.fromJson( json );
-
+ TypedTag nbt = TagUtil.fromJson( json );
writeTag( nbt, buf, protocolVersion );
}
@@ -456,29 +455,26 @@ public abstract class DefinedPacket
public static Tag readTag(ByteBuf input, int protocolVersion)
{
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
- Tag tag;
- if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
+ try
{
- try
+ if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
byte type = in.readByte();
if ( type == 0 )
{
- return Tag.END;
+ return EndTag.INSTANCE;
} else
{
- tag = SpecificTag.read( type, in );
+ return Tag.readById( type, in, new NBTLimiter( 1 << 21 ) );
}
- } catch ( IOException ex )
- {
- tag = new ErrorTag( "IOException while reading tag type:\n" + ex.getMessage() );
}
- } else
+ NamedTag namedTag = new NamedTag();
+ namedTag.read( in, new NBTLimiter( 1 << 21 ) );
+ return namedTag;
+ } catch ( IOException ex )
{
- tag = NamedTag.read( in );
+ throw new RuntimeException( "Exception reading tag", ex );
}
- Preconditions.checkArgument( !tag.isError(), "Error reading tag: %s", tag.error() );
- return tag;
}
public static void writeTag(Tag tag, ByteBuf output, int protocolVersion)
@@ -486,11 +482,11 @@ public abstract class DefinedPacket
DataOutputStream out = new DataOutputStream( new ByteBufOutputStream( output ) );
try
{
- if ( tag instanceof SpecificTag )
+ if ( tag instanceof TypedTag )
{
- SpecificTag specificTag = (SpecificTag) tag;
- specificTag.writeType( out );
- specificTag.write( out );
+ TypedTag typedTag = (TypedTag) tag;
+ out.writeByte( typedTag.getId() );
+ typedTag.write( out );
} else
{
tag.write( out );
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/TagUtil.java b/protocol/src/main/java/net/md_5/bungee/protocol/TagUtil.java
index 9235a3db..52b9b5cf 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/TagUtil.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/TagUtil.java
@@ -7,31 +7,32 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
-import se.llbit.nbt.ByteArrayTag;
-import se.llbit.nbt.ByteTag;
-import se.llbit.nbt.CompoundTag;
-import se.llbit.nbt.DoubleTag;
-import se.llbit.nbt.FloatTag;
-import se.llbit.nbt.IntArrayTag;
-import se.llbit.nbt.IntTag;
-import se.llbit.nbt.ListTag;
-import se.llbit.nbt.LongArrayTag;
-import se.llbit.nbt.LongTag;
-import se.llbit.nbt.NamedTag;
-import se.llbit.nbt.ShortTag;
-import se.llbit.nbt.SpecificTag;
-import se.llbit.nbt.StringTag;
-import se.llbit.nbt.Tag;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.type.ByteArrayTag;
+import net.md_5.bungee.nbt.type.ByteTag;
+import net.md_5.bungee.nbt.type.CompoundTag;
+import net.md_5.bungee.nbt.type.DoubleTag;
+import net.md_5.bungee.nbt.type.EndTag;
+import net.md_5.bungee.nbt.type.FloatTag;
+import net.md_5.bungee.nbt.type.IntArrayTag;
+import net.md_5.bungee.nbt.type.IntTag;
+import net.md_5.bungee.nbt.type.ListTag;
+import net.md_5.bungee.nbt.type.LongArrayTag;
+import net.md_5.bungee.nbt.type.LongTag;
+import net.md_5.bungee.nbt.type.ShortTag;
+import net.md_5.bungee.nbt.type.StringTag;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class TagUtil
{
- public static SpecificTag fromJson(JsonElement json)
+ public static TypedTag fromJson(JsonElement json)
{
if ( json instanceof JsonPrimitive )
{
@@ -64,17 +65,17 @@ public final class TagUtil
return new StringTag( jsonPrimitive.getAsString() );
} else if ( jsonPrimitive.isBoolean() )
{
- return new ByteTag( jsonPrimitive.getAsBoolean() ? 1 : 0 );
+ return new ByteTag( (byte) ( jsonPrimitive.getAsBoolean() ? 1 : 0 ) );
} else
{
throw new IllegalArgumentException( "Unknown JSON primitive: " + jsonPrimitive );
}
} else if ( json instanceof JsonObject )
{
- CompoundTag compoundTag = new CompoundTag();
+ CompoundTag compoundTag = new CompoundTag( new LinkedHashMap<>() );
for ( Map.Entry property : ( (JsonObject) json ).entrySet() )
{
- compoundTag.add( property.getKey(), fromJson( property.getValue() ) );
+ compoundTag.getValue().put( property.getKey(), fromJson( property.getValue() ) );
}
return compoundTag;
@@ -82,103 +83,103 @@ public final class TagUtil
{
List jsonArray = ( (JsonArray) json ).asList();
- Integer listType = null;
+ Byte listType = null;
for ( JsonElement jsonEl : jsonArray )
{
- int type = fromJson( jsonEl ).tagType();
+ byte type = fromJson( jsonEl ).getId();
if ( listType == null )
{
listType = type;
} else if ( listType != type )
{
- listType = Tag.TAG_COMPOUND;
+ listType = Tag.COMPOUND;
break;
}
}
if ( listType == null )
{
- return new ListTag( Tag.TAG_END, Collections.emptyList() );
+ return new ListTag( Collections.emptyList(), Tag.END );
}
- SpecificTag listTag;
+ TypedTag listTag;
switch ( listType )
{
- case Tag.TAG_BYTE:
+ case Tag.BYTE:
byte[] bytes = new byte[ jsonArray.size() ];
for ( int i = 0; i < bytes.length; i++ )
{
- bytes[i] = (Byte) ( (JsonPrimitive) jsonArray.get( i ) ).getAsNumber();
+ bytes[i] = (Byte) ( jsonArray.get( i ) ).getAsNumber();
}
listTag = new ByteArrayTag( bytes );
break;
- case Tag.TAG_INT:
+ case Tag.INT:
int[] ints = new int[ jsonArray.size() ];
for ( int i = 0; i < ints.length; i++ )
{
- ints[i] = (Integer) ( (JsonPrimitive) jsonArray.get( i ) ).getAsNumber();
+ ints[i] = (Integer) ( jsonArray.get( i ) ).getAsNumber();
}
listTag = new IntArrayTag( ints );
break;
- case Tag.TAG_LONG:
+ case Tag.LONG:
long[] longs = new long[ jsonArray.size() ];
for ( int i = 0; i < longs.length; i++ )
{
- longs[i] = (Long) ( (JsonPrimitive) jsonArray.get( i ) ).getAsNumber();
+ longs[i] = (Long) ( jsonArray.get( i ) ).getAsNumber();
}
listTag = new LongArrayTag( longs );
break;
default:
- List tagItems = new ArrayList<>( jsonArray.size() );
+ List tagItems = new ArrayList<>( jsonArray.size() );
for ( JsonElement jsonEl : jsonArray )
{
- SpecificTag subTag = fromJson( jsonEl );
- if ( listType == Tag.TAG_COMPOUND && !( subTag instanceof CompoundTag ) )
+ TypedTag subTag = fromJson( jsonEl );
+ if ( listType == Tag.COMPOUND && !( subTag instanceof CompoundTag ) )
{
- CompoundTag wrapper = new CompoundTag();
- wrapper.add( "", subTag );
+ CompoundTag wrapper = new CompoundTag( new LinkedHashMap<>() );
+ wrapper.getValue().put( "", subTag );
subTag = wrapper;
}
tagItems.add( subTag );
}
- listTag = new ListTag( listType, tagItems );
+ listTag = new ListTag( tagItems, listType );
break;
}
return listTag;
} else if ( json instanceof JsonNull )
{
- return Tag.END;
+ return EndTag.INSTANCE;
}
throw new IllegalArgumentException( "Unknown JSON element: " + json );
}
- public static JsonElement toJson(SpecificTag tag)
+ public static JsonElement toJson(TypedTag tag)
{
- switch ( tag.tagType() )
+ switch ( tag.getId() )
{
- case Tag.TAG_BYTE:
- return new JsonPrimitive( (byte) ( (ByteTag) tag ).getData() );
- case Tag.TAG_SHORT:
- return new JsonPrimitive( ( (ShortTag) tag ).getData() );
- case Tag.TAG_INT:
- return new JsonPrimitive( ( (IntTag) tag ).getData() );
- case Tag.TAG_LONG:
- return new JsonPrimitive( ( (LongTag) tag ).getData() );
- case Tag.TAG_FLOAT:
- return new JsonPrimitive( ( (FloatTag) tag ).getData() );
- case Tag.TAG_DOUBLE:
- return new JsonPrimitive( ( (DoubleTag) tag ).getData() );
- case Tag.TAG_BYTE_ARRAY:
- byte[] byteArray = ( (ByteArrayTag) tag ).getData();
+ case Tag.BYTE:
+ return new JsonPrimitive( ( (ByteTag) tag ).getValue() );
+ case Tag.SHORT:
+ return new JsonPrimitive( ( (ShortTag) tag ).getValue() );
+ case Tag.INT:
+ return new JsonPrimitive( ( (IntTag) tag ).getValue() );
+ case Tag.LONG:
+ return new JsonPrimitive( ( (LongTag) tag ).getValue() );
+ case Tag.FLOAT:
+ return new JsonPrimitive( ( (FloatTag) tag ).getValue() );
+ case Tag.DOUBLE:
+ return new JsonPrimitive( ( (DoubleTag) tag ).getValue() );
+ case Tag.BYTE_ARRAY:
+ byte[] byteArray = ( (ByteArrayTag) tag ).getValue();
JsonArray jsonByteArray = new JsonArray( byteArray.length );
for ( byte b : byteArray )
@@ -187,21 +188,21 @@ public final class TagUtil
}
return jsonByteArray;
- case Tag.TAG_STRING:
- return new JsonPrimitive( ( (StringTag) tag ).getData() );
- case Tag.TAG_LIST:
- List items = ( (ListTag) tag ).items;
+ case Tag.STRING:
+ return new JsonPrimitive( ( (StringTag) tag ).getValue() );
+ case Tag.LIST:
+ List items = ( (ListTag) tag ).getValue();
JsonArray jsonList = new JsonArray( items.size() );
- for ( SpecificTag subTag : items )
+ for ( TypedTag subTag : items )
{
if ( subTag instanceof CompoundTag )
{
CompoundTag compound = (CompoundTag) subTag;
- if ( compound.size() == 1 )
+ if ( compound.getValue().size() == 1 )
{
- SpecificTag first = (SpecificTag) compound.get( "" );
- if ( !first.isError() )
+ TypedTag first = compound.getValue().get( "" );
+ if ( first != null )
{
jsonList.add( toJson( first ) );
continue;
@@ -213,16 +214,13 @@ public final class TagUtil
}
return jsonList;
- case Tag.TAG_COMPOUND:
+ case Tag.COMPOUND:
JsonObject jsonObject = new JsonObject();
- for ( NamedTag subTag : (CompoundTag) tag )
- {
- jsonObject.add( subTag.name(), toJson( subTag.getTag() ) );
- }
-
+ CompoundTag compoundTag = (CompoundTag) tag;
+ compoundTag.getValue().forEach( (key, value) -> jsonObject.add( key, toJson( value ) ) );
return jsonObject;
- case Tag.TAG_INT_ARRAY:
- int[] intArray = ( (IntArrayTag) tag ).getData();
+ case Tag.INT_ARRAY:
+ int[] intArray = ( (IntArrayTag) tag ).getValue();
JsonArray jsonIntArray = new JsonArray( intArray.length );
for ( int i : intArray )
@@ -231,8 +229,8 @@ public final class TagUtil
}
return jsonIntArray;
- case Tag.TAG_LONG_ARRAY:
- long[] longArray = ( (LongArrayTag) tag ).getData();
+ case Tag.LONG_ARRAY:
+ long[] longArray = ( (LongArrayTag) tag ).getValue();
JsonArray jsonLongArray = new JsonArray( longArray.length );
for ( long l : longArray )
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java
index 4ecc1e0f..6324d50f 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/CustomClickAction.java
@@ -5,11 +5,11 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.TypedTag;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
-import se.llbit.nbt.Tag;
@Data
@NoArgsConstructor
@@ -19,13 +19,13 @@ public class CustomClickAction extends DefinedPacket
{
private String id;
- private Tag data;
+ private TypedTag data;
@Override
public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
{
id = readString( buf );
- data = readNullable( (buf0) -> readTag( buf0, protocolVersion ), buf );
+ data = readNullable( (buf0) -> (TypedTag) readTag( buf0, protocolVersion ), buf );
}
@Override
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Login.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Login.java
index 8314cf4b..cb423644 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Login.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Login.java
@@ -7,11 +7,11 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Location;
import net.md_5.bungee.protocol.ProtocolConstants;
-import se.llbit.nbt.Tag;
@Data
@NoArgsConstructor
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Respawn.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Respawn.java
index e57db1c2..8fb44881 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/Respawn.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/Respawn.java
@@ -5,11 +5,11 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.Tag;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Location;
import net.md_5.bungee.protocol.ProtocolConstants;
-import se.llbit.nbt.Tag;
@Data
@NoArgsConstructor
diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java
index 440020c8..8bdd30dc 100644
--- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java
+++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/ShowDialog.java
@@ -7,13 +7,13 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.dialog.Dialog;
+import net.md_5.bungee.nbt.TypedTag;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.ChatSerializer;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.TagUtil;
-import se.llbit.nbt.SpecificTag;
@Data
@NoArgsConstructor
@@ -39,7 +39,7 @@ public class ShowDialog extends DefinedPacket
protected static Dialog readDialog(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
- SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
+ TypedTag nbt = (TypedTag) readTag( buf, protocolVersion );
JsonElement json = TagUtil.toJson( nbt );
return ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().deserialize( json );
}
@@ -60,7 +60,7 @@ public class ShowDialog extends DefinedPacket
protected static void writeDialog(Dialog dialog, ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
JsonElement json = ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().toJson( dialog );
- SpecificTag nbt = TagUtil.fromJson( json );
+ TypedTag nbt = TagUtil.fromJson( json );
writeTag( nbt, buf, protocolVersion );
}
diff --git a/protocol/src/test/java/net/md_5/bungee/protocol/TagUtilTest.java b/protocol/src/test/java/net/md_5/bungee/protocol/TagUtilTest.java
index f6a8bd31..716827da 100644
--- a/protocol/src/test/java/net/md_5/bungee/protocol/TagUtilTest.java
+++ b/protocol/src/test/java/net/md_5/bungee/protocol/TagUtilTest.java
@@ -6,16 +6,16 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
+import net.md_5.bungee.nbt.Tag;
+import net.md_5.bungee.nbt.TypedTag;
+import net.md_5.bungee.nbt.type.ByteArrayTag;
+import net.md_5.bungee.nbt.type.CompoundTag;
+import net.md_5.bungee.nbt.type.IntArrayTag;
+import net.md_5.bungee.nbt.type.IntTag;
+import net.md_5.bungee.nbt.type.ListTag;
+import net.md_5.bungee.nbt.type.LongArrayTag;
+import net.md_5.bungee.nbt.type.StringTag;
import org.junit.jupiter.api.Test;
-import se.llbit.nbt.ByteArrayTag;
-import se.llbit.nbt.CompoundTag;
-import se.llbit.nbt.IntArrayTag;
-import se.llbit.nbt.IntTag;
-import se.llbit.nbt.ListTag;
-import se.llbit.nbt.LongArrayTag;
-import se.llbit.nbt.SpecificTag;
-import se.llbit.nbt.StringTag;
-import se.llbit.nbt.Tag;
public class TagUtilTest
{
@@ -25,7 +25,7 @@ public class TagUtilTest
private static void testDissembleReassemble(String json)
{
JsonElement parsedJson = GSON.fromJson( json, JsonElement.class );
- SpecificTag nbt = TagUtil.fromJson( parsedJson );
+ TypedTag nbt = TagUtil.fromJson( parsedJson );
JsonElement convertedElement = TagUtil.toJson( nbt );
String convertedJson = GSON.toJson( convertedElement );
@@ -35,18 +35,19 @@ public class TagUtilTest
@Test
public void testStringLiteral()
{
+ // this test only passes if the CompoundTags are backed by a LinkedHashMap
testDissembleReassemble( "{\"text\":\"\",\"extra\":[\"hello\",{\"text\":\"there\",\"color\":\"#ff0000\"},{\"text\":\"friend\",\"font\":\"minecraft:default\"}]}" );
}
public void testCreateMixedList(JsonArray array)
{
- SpecificTag tag = TagUtil.fromJson( array );
+ TypedTag tag = TagUtil.fromJson( array );
assertInstanceOf( ListTag.class, tag );
ListTag list = (ListTag) tag;
- assertEquals( SpecificTag.TAG_COMPOUND, list.getType() );
- assertEquals( array.size(), list.size() );
+ assertEquals( Tag.COMPOUND, list.getListType() );
+ assertEquals( array.size(), list.getValue().size() );
- for ( int i = 0; i < list.size(); i++ )
+ for ( int i = 0; i < list.getValue().size(); i++ )
{
assertTrue( i < array.size() );
@@ -77,7 +78,7 @@ public class TagUtilTest
assertInstanceOf( IntTag.class, value );
IntTag integer = (IntTag) value;
- assertEquals( array.get( i ).getAsInt(), integer.getData() );
+ assertEquals( array.get( i ).getAsInt(), integer.getValue() );
}
} else if ( primitive.isString() )
@@ -85,7 +86,7 @@ public class TagUtilTest
assertInstanceOf( StringTag.class, value );
StringTag string = (StringTag) value;
- assertEquals( array.get( i ).getAsString(), string.getData() );
+ assertEquals( array.get( i ).getAsString(), string.getValue() );
}
}
}
@@ -129,11 +130,11 @@ public class TagUtilTest
public void testCreateEmptyList()
{
JsonArray array = new JsonArray();
- SpecificTag tag = TagUtil.fromJson( array );
+ TypedTag tag = TagUtil.fromJson( array );
assertInstanceOf( ListTag.class, tag );
ListTag list = (ListTag) tag;
assertEquals( 0, list.size() );
- assertEquals( Tag.TAG_END, list.getType() );
+ assertEquals( Tag.END, list.getListType() );
}
@Test
@@ -143,16 +144,16 @@ public class TagUtilTest
array.add( ( (byte) 1 ) );
array.add( ( (byte) 2 ) );
- SpecificTag tag = TagUtil.fromJson( array );
+ TypedTag tag = TagUtil.fromJson( array );
assertInstanceOf( ByteArrayTag.class, tag );
ByteArrayTag byteArray = (ByteArrayTag) tag;
- assertEquals( 2, byteArray.getData().length );
+ assertEquals( 2, byteArray.getValue().length );
- for ( int i = 0; i < byteArray.getData().length; i++ )
+ for ( int i = 0; i < byteArray.getValue().length; i++ )
{
assertTrue( i < array.size() );
- byte item = byteArray.getData()[i];
+ byte item = byteArray.getValue()[i];
assertEquals( array.get( i ).getAsByte(), item );
}
}
@@ -164,16 +165,16 @@ public class TagUtilTest
array.add( 1 );
array.add( 2 );
- SpecificTag tag = TagUtil.fromJson( array );
+ TypedTag tag = TagUtil.fromJson( array );
assertInstanceOf( IntArrayTag.class, tag );
IntArrayTag intArray = (IntArrayTag) tag;
- assertEquals( 2, intArray.getData().length );
+ assertEquals( 2, intArray.getValue().length );
- for ( int i = 0; i < intArray.getData().length; i++ )
+ for ( int i = 0; i < intArray.getValue().length; i++ )
{
assertTrue( i < array.size() );
- int item = intArray.getData()[i];
+ int item = intArray.getValue()[i];
assertEquals( array.get( i ).getAsInt(), item );
}
}
@@ -185,16 +186,16 @@ public class TagUtilTest
array.add( 1L );
array.add( 2L );
- SpecificTag tag = TagUtil.fromJson( array );
+ TypedTag tag = TagUtil.fromJson( array );
assertInstanceOf( LongArrayTag.class, tag );
LongArrayTag intArray = (LongArrayTag) tag;
- assertEquals( 2, intArray.getData().length );
+ assertEquals( 2, intArray.getValue().length );
- for ( int i = 0; i < intArray.getData().length; i++ )
+ for ( int i = 0; i < intArray.getValue().length; i++ )
{
assertTrue( i < array.size() );
- long item = intArray.getData()[i];
+ long item = intArray.getValue()[i];
assertEquals( array.get( i ).getAsLong(), item );
}
}
@@ -206,10 +207,10 @@ public class TagUtilTest
array.add( "a" );
array.add( "b" );
- SpecificTag tag = TagUtil.fromJson( array );
+ TypedTag tag = TagUtil.fromJson( array );
assertInstanceOf( ListTag.class, tag );
ListTag list = (ListTag) tag;
- assertEquals( SpecificTag.TAG_STRING, list.getType() );
+ assertEquals( Tag.STRING, list.getListType() );
assertEquals( 2, list.size() );
for ( int i = 0; i < list.size(); i++ )
@@ -220,7 +221,7 @@ public class TagUtilTest
assertInstanceOf( StringTag.class, item );
StringTag string = (StringTag) item;
- assertEquals( array.get( i ).getAsString(), string.getData() );
+ assertEquals( array.get( i ).getAsString(), string.getValue() );
}
}
}
diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java
index 2f540f0f..dc7b643a 100644
--- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java
+++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java
@@ -47,7 +47,6 @@ import net.md_5.bungee.protocol.packet.TabCompleteRequest;
import net.md_5.bungee.protocol.packet.TabCompleteResponse;
import net.md_5.bungee.protocol.packet.UnsignedClientCommand;
import net.md_5.bungee.util.AllowedCharacters;
-import se.llbit.nbt.SpecificTag;
public class UpstreamBridge extends PacketHandler
{
@@ -385,7 +384,7 @@ public class UpstreamBridge extends PacketHandler
@Override
public void handle(CustomClickAction customClickAction) throws Exception
{
- CustomClickEvent event = new CustomClickEvent( con, customClickAction.getId(), TagUtil.toJson( (SpecificTag) customClickAction.getData() ) );
+ CustomClickEvent event = new CustomClickEvent( con, customClickAction.getId(), TagUtil.toJson( customClickAction.getData() ) );
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
{
throw CancelSendSignal.INSTANCE;
diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java
index eab5a947..873ddd68 100644
--- a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java
+++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java
@@ -4,12 +4,13 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import java.io.DataInputStream;
+import java.io.IOException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import net.md_5.bungee.nbt.NamedTag;
+import net.md_5.bungee.nbt.limit.NBTLimiter;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
-import se.llbit.nbt.NamedTag;
-import se.llbit.nbt.Tag;
/**
* Class to rewrite integers within packets.
@@ -275,10 +276,13 @@ public abstract class EntityMap
DefinedPacket.readVarInt( packet );
break;
case 13:
- Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( packet ) ) );
- if ( tag.isError() )
+ NamedTag tag = new NamedTag();
+ try
{
- throw new RuntimeException( tag.error() );
+ tag.read( new DataInputStream( new ByteBufInputStream( packet ) ), NBTLimiter.unlimitedSize() );
+ } catch ( IOException ioException )
+ {
+ throw new RuntimeException( ioException );
}
break;
case 15:
@@ -321,10 +325,13 @@ public abstract class EntityMap
{
packet.readerIndex( position );
- Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( packet ) ) );
- if ( tag.isError() )
+ NamedTag tag = new NamedTag();
+ try
{
- throw new RuntimeException( tag.error() );
+ tag.read( new DataInputStream( new ByteBufInputStream( packet ) ), NBTLimiter.unlimitedSize() );
+ } catch ( IOException ioException )
+ {
+ throw new RuntimeException( ioException );
}
}
}