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[] 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 ); } } }