#3803: Add NBT module
This commit is contained in:
parent
bec329352d
commit
41e49dad6b
28
nbt/LICENSE
Normal file
28
nbt/LICENSE
Normal file
@ -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.
|
4
nbt/README.md
Normal file
4
nbt/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
BungeeCord-NBT
|
||||||
|
=================
|
||||||
|
|
||||||
|
Minimal implementation of NBT for use in BungeeCord
|
31
nbt/nb-configuration.xml
Normal file
31
nbt/nb-configuration.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
27
nbt/pom.xml
Normal file
27
nbt/pom.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
|
<version>1.21-R0.3-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-nbt</artifactId>
|
||||||
|
<version>1.21-R0.3-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>BungeeCord-NBT</name>
|
||||||
|
<description>Minimal implementation of NBT for use in BungeeCord</description>
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>BSD-3-Clause</name>
|
||||||
|
<url>https://github.com/SpigotMC/BungeeCord/blob/master/dialog/LICENSE</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
</project>
|
52
nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java
Normal file
52
nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java
Normal file
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
131
nbt/src/main/java/net/md_5/bungee/nbt/Tag.java
Normal file
131
nbt/src/main/java/net/md_5/bungee/nbt/Tag.java
Normal file
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
12
nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java
Normal file
12
nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java
Normal file
@ -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();
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package net.md_5.bungee.nbt.exception;
|
||||||
|
|
||||||
|
public class NBTException extends RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
public NBTException(String message)
|
||||||
|
{
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package net.md_5.bungee.nbt.exception;
|
||||||
|
|
||||||
|
public class NBTFormatException extends NBTException
|
||||||
|
{
|
||||||
|
|
||||||
|
public NBTFormatException(String message)
|
||||||
|
{
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package net.md_5.bungee.nbt.exception;
|
||||||
|
|
||||||
|
public class NBTLimitException extends NBTException
|
||||||
|
{
|
||||||
|
|
||||||
|
public NBTLimitException(String message)
|
||||||
|
{
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
66
nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java
Normal file
66
nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java
Normal file
@ -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" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java
Normal file
44
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
99
nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java
Normal file
99
nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java
Normal file
@ -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<String, TypedTag> value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||||
|
{
|
||||||
|
limiter.push();
|
||||||
|
limiter.countBytes( MAP_SIZE_IN_BYTES );
|
||||||
|
Map<String, TypedTag> 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<String, TypedTag> 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();
|
||||||
|
}
|
||||||
|
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
34
nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java
Normal file
34
nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
52
nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java
Normal file
52
nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
87
nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java
Normal file
87
nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java
Normal file
@ -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<TypedTag> 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<TypedTag> 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();
|
||||||
|
}
|
||||||
|
}
|
53
nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java
Normal file
53
nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
44
nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java
Normal file
44
nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
53
nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java
Normal file
53
nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java
Normal file
@ -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 ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
247
nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java
Normal file
247
nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java
Normal file
@ -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<TypedTag> 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<TypedTag> 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<String, TypedTag> 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<String, TypedTag> map2 = new LinkedHashMap<>();
|
||||||
|
map2.put( "", new EndTag() );
|
||||||
|
CompoundTag compoundTag2 = new CompoundTag( map2 );
|
||||||
|
assertThrows( NBTFormatException.class, () -> Tag.toByteArray( compoundTag2 ) );
|
||||||
|
}
|
||||||
|
}
|
30
nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java
Normal file
30
nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java
Normal file
@ -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(), "" );
|
||||||
|
}
|
||||||
|
}
|
BIN
nbt/src/test/resources/playerdata.nbt
Normal file
BIN
nbt/src/test/resources/playerdata.nbt
Normal file
Binary file not shown.
1
pom.xml
1
pom.xml
@ -45,6 +45,7 @@
|
|||||||
<module>serializer</module>
|
<module>serializer</module>
|
||||||
<module>slf4j</module>
|
<module>slf4j</module>
|
||||||
<module>native</module>
|
<module>native</module>
|
||||||
|
<module>nbt</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
|
@ -40,6 +40,12 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-nbt</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-codec</artifactId>
|
<artifactId>netty-codec</artifactId>
|
||||||
@ -51,11 +57,5 @@
|
|||||||
<version>3.1.0</version>
|
<version>3.1.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>se.llbit</groupId>
|
|
||||||
<artifactId>jo-nbt</artifactId>
|
|
||||||
<version>1.3.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -21,10 +21,11 @@ import java.util.function.BiConsumer;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.ComponentStyle;
|
import net.md_5.bungee.api.chat.ComponentStyle;
|
||||||
import se.llbit.nbt.ErrorTag;
|
import net.md_5.bungee.nbt.NamedTag;
|
||||||
import se.llbit.nbt.NamedTag;
|
import net.md_5.bungee.nbt.Tag;
|
||||||
import se.llbit.nbt.SpecificTag;
|
import net.md_5.bungee.nbt.TypedTag;
|
||||||
import se.llbit.nbt.Tag;
|
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||||
|
import net.md_5.bungee.nbt.type.EndTag;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public abstract class DefinedPacket
|
public abstract class DefinedPacket
|
||||||
@ -116,7 +117,7 @@ public abstract class DefinedPacket
|
|||||||
{
|
{
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
||||||
{
|
{
|
||||||
SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
|
TypedTag nbt = (TypedTag) readTag( buf, protocolVersion );
|
||||||
JsonElement json = TagUtil.toJson( nbt );
|
JsonElement json = TagUtil.toJson( nbt );
|
||||||
|
|
||||||
return ChatSerializer.forVersion( protocolVersion ).deserialize( json );
|
return ChatSerializer.forVersion( protocolVersion ).deserialize( json );
|
||||||
@ -130,7 +131,7 @@ public abstract class DefinedPacket
|
|||||||
|
|
||||||
public static ComponentStyle readComponentStyle(ByteBuf buf, int protocolVersion)
|
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 );
|
JsonElement json = TagUtil.toJson( nbt );
|
||||||
|
|
||||||
return ChatSerializer.forVersion( protocolVersion ).deserializeStyle( json );
|
return ChatSerializer.forVersion( protocolVersion ).deserializeStyle( json );
|
||||||
@ -152,8 +153,7 @@ public abstract class DefinedPacket
|
|||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
||||||
{
|
{
|
||||||
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( message );
|
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( message );
|
||||||
SpecificTag nbt = TagUtil.fromJson( json );
|
TypedTag nbt = TagUtil.fromJson( json );
|
||||||
|
|
||||||
writeTag( nbt, buf, protocolVersion );
|
writeTag( nbt, buf, protocolVersion );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
@ -166,8 +166,7 @@ public abstract class DefinedPacket
|
|||||||
public static void writeComponentStyle(ComponentStyle style, ByteBuf buf, int protocolVersion)
|
public static void writeComponentStyle(ComponentStyle style, ByteBuf buf, int protocolVersion)
|
||||||
{
|
{
|
||||||
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( style );
|
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( style );
|
||||||
SpecificTag nbt = TagUtil.fromJson( json );
|
TypedTag nbt = TagUtil.fromJson( json );
|
||||||
|
|
||||||
writeTag( nbt, buf, protocolVersion );
|
writeTag( nbt, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,29 +455,26 @@ public abstract class DefinedPacket
|
|||||||
public static Tag readTag(ByteBuf input, int protocolVersion)
|
public static Tag readTag(ByteBuf input, int protocolVersion)
|
||||||
{
|
{
|
||||||
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
|
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
|
||||||
Tag tag;
|
try
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
|
|
||||||
{
|
{
|
||||||
try
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
|
||||||
{
|
{
|
||||||
byte type = in.readByte();
|
byte type = in.readByte();
|
||||||
if ( type == 0 )
|
if ( type == 0 )
|
||||||
{
|
{
|
||||||
return Tag.END;
|
return EndTag.INSTANCE;
|
||||||
} else
|
} 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)
|
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 ) );
|
DataOutputStream out = new DataOutputStream( new ByteBufOutputStream( output ) );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ( tag instanceof SpecificTag )
|
if ( tag instanceof TypedTag )
|
||||||
{
|
{
|
||||||
SpecificTag specificTag = (SpecificTag) tag;
|
TypedTag typedTag = (TypedTag) tag;
|
||||||
specificTag.writeType( out );
|
out.writeByte( typedTag.getId() );
|
||||||
specificTag.write( out );
|
typedTag.write( out );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
tag.write( out );
|
tag.write( out );
|
||||||
|
@ -7,31 +7,32 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import se.llbit.nbt.ByteArrayTag;
|
import net.md_5.bungee.nbt.Tag;
|
||||||
import se.llbit.nbt.ByteTag;
|
import net.md_5.bungee.nbt.TypedTag;
|
||||||
import se.llbit.nbt.CompoundTag;
|
import net.md_5.bungee.nbt.type.ByteArrayTag;
|
||||||
import se.llbit.nbt.DoubleTag;
|
import net.md_5.bungee.nbt.type.ByteTag;
|
||||||
import se.llbit.nbt.FloatTag;
|
import net.md_5.bungee.nbt.type.CompoundTag;
|
||||||
import se.llbit.nbt.IntArrayTag;
|
import net.md_5.bungee.nbt.type.DoubleTag;
|
||||||
import se.llbit.nbt.IntTag;
|
import net.md_5.bungee.nbt.type.EndTag;
|
||||||
import se.llbit.nbt.ListTag;
|
import net.md_5.bungee.nbt.type.FloatTag;
|
||||||
import se.llbit.nbt.LongArrayTag;
|
import net.md_5.bungee.nbt.type.IntArrayTag;
|
||||||
import se.llbit.nbt.LongTag;
|
import net.md_5.bungee.nbt.type.IntTag;
|
||||||
import se.llbit.nbt.NamedTag;
|
import net.md_5.bungee.nbt.type.ListTag;
|
||||||
import se.llbit.nbt.ShortTag;
|
import net.md_5.bungee.nbt.type.LongArrayTag;
|
||||||
import se.llbit.nbt.SpecificTag;
|
import net.md_5.bungee.nbt.type.LongTag;
|
||||||
import se.llbit.nbt.StringTag;
|
import net.md_5.bungee.nbt.type.ShortTag;
|
||||||
import se.llbit.nbt.Tag;
|
import net.md_5.bungee.nbt.type.StringTag;
|
||||||
|
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public final class TagUtil
|
public final class TagUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
public static SpecificTag fromJson(JsonElement json)
|
public static TypedTag fromJson(JsonElement json)
|
||||||
{
|
{
|
||||||
if ( json instanceof JsonPrimitive )
|
if ( json instanceof JsonPrimitive )
|
||||||
{
|
{
|
||||||
@ -64,17 +65,17 @@ public final class TagUtil
|
|||||||
return new StringTag( jsonPrimitive.getAsString() );
|
return new StringTag( jsonPrimitive.getAsString() );
|
||||||
} else if ( jsonPrimitive.isBoolean() )
|
} else if ( jsonPrimitive.isBoolean() )
|
||||||
{
|
{
|
||||||
return new ByteTag( jsonPrimitive.getAsBoolean() ? 1 : 0 );
|
return new ByteTag( (byte) ( jsonPrimitive.getAsBoolean() ? 1 : 0 ) );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException( "Unknown JSON primitive: " + jsonPrimitive );
|
throw new IllegalArgumentException( "Unknown JSON primitive: " + jsonPrimitive );
|
||||||
}
|
}
|
||||||
} else if ( json instanceof JsonObject )
|
} else if ( json instanceof JsonObject )
|
||||||
{
|
{
|
||||||
CompoundTag compoundTag = new CompoundTag();
|
CompoundTag compoundTag = new CompoundTag( new LinkedHashMap<>() );
|
||||||
for ( Map.Entry<String, JsonElement> property : ( (JsonObject) json ).entrySet() )
|
for ( Map.Entry<String, JsonElement> property : ( (JsonObject) json ).entrySet() )
|
||||||
{
|
{
|
||||||
compoundTag.add( property.getKey(), fromJson( property.getValue() ) );
|
compoundTag.getValue().put( property.getKey(), fromJson( property.getValue() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return compoundTag;
|
return compoundTag;
|
||||||
@ -82,103 +83,103 @@ public final class TagUtil
|
|||||||
{
|
{
|
||||||
List<JsonElement> jsonArray = ( (JsonArray) json ).asList();
|
List<JsonElement> jsonArray = ( (JsonArray) json ).asList();
|
||||||
|
|
||||||
Integer listType = null;
|
Byte listType = null;
|
||||||
|
|
||||||
for ( JsonElement jsonEl : jsonArray )
|
for ( JsonElement jsonEl : jsonArray )
|
||||||
{
|
{
|
||||||
int type = fromJson( jsonEl ).tagType();
|
byte type = fromJson( jsonEl ).getId();
|
||||||
if ( listType == null )
|
if ( listType == null )
|
||||||
{
|
{
|
||||||
listType = type;
|
listType = type;
|
||||||
} else if ( listType != type )
|
} else if ( listType != type )
|
||||||
{
|
{
|
||||||
listType = Tag.TAG_COMPOUND;
|
listType = Tag.COMPOUND;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( listType == null )
|
if ( listType == null )
|
||||||
{
|
{
|
||||||
return new ListTag( Tag.TAG_END, Collections.emptyList() );
|
return new ListTag( Collections.emptyList(), Tag.END );
|
||||||
}
|
}
|
||||||
|
|
||||||
SpecificTag listTag;
|
TypedTag listTag;
|
||||||
switch ( listType )
|
switch ( listType )
|
||||||
{
|
{
|
||||||
case Tag.TAG_BYTE:
|
case Tag.BYTE:
|
||||||
byte[] bytes = new byte[ jsonArray.size() ];
|
byte[] bytes = new byte[ jsonArray.size() ];
|
||||||
for ( int i = 0; i < bytes.length; i++ )
|
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 );
|
listTag = new ByteArrayTag( bytes );
|
||||||
break;
|
break;
|
||||||
case Tag.TAG_INT:
|
case Tag.INT:
|
||||||
int[] ints = new int[ jsonArray.size() ];
|
int[] ints = new int[ jsonArray.size() ];
|
||||||
for ( int i = 0; i < ints.length; i++ )
|
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 );
|
listTag = new IntArrayTag( ints );
|
||||||
break;
|
break;
|
||||||
case Tag.TAG_LONG:
|
case Tag.LONG:
|
||||||
long[] longs = new long[ jsonArray.size() ];
|
long[] longs = new long[ jsonArray.size() ];
|
||||||
for ( int i = 0; i < longs.length; i++ )
|
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 );
|
listTag = new LongArrayTag( longs );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
List<SpecificTag> tagItems = new ArrayList<>( jsonArray.size() );
|
List<TypedTag> tagItems = new ArrayList<>( jsonArray.size() );
|
||||||
|
|
||||||
for ( JsonElement jsonEl : jsonArray )
|
for ( JsonElement jsonEl : jsonArray )
|
||||||
{
|
{
|
||||||
SpecificTag subTag = fromJson( jsonEl );
|
TypedTag subTag = fromJson( jsonEl );
|
||||||
if ( listType == Tag.TAG_COMPOUND && !( subTag instanceof CompoundTag ) )
|
if ( listType == Tag.COMPOUND && !( subTag instanceof CompoundTag ) )
|
||||||
{
|
{
|
||||||
CompoundTag wrapper = new CompoundTag();
|
CompoundTag wrapper = new CompoundTag( new LinkedHashMap<>() );
|
||||||
wrapper.add( "", subTag );
|
wrapper.getValue().put( "", subTag );
|
||||||
subTag = wrapper;
|
subTag = wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
tagItems.add( subTag );
|
tagItems.add( subTag );
|
||||||
}
|
}
|
||||||
|
|
||||||
listTag = new ListTag( listType, tagItems );
|
listTag = new ListTag( tagItems, listType );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return listTag;
|
return listTag;
|
||||||
} else if ( json instanceof JsonNull )
|
} else if ( json instanceof JsonNull )
|
||||||
{
|
{
|
||||||
return Tag.END;
|
return EndTag.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException( "Unknown JSON element: " + json );
|
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:
|
case Tag.BYTE:
|
||||||
return new JsonPrimitive( (byte) ( (ByteTag) tag ).getData() );
|
return new JsonPrimitive( ( (ByteTag) tag ).getValue() );
|
||||||
case Tag.TAG_SHORT:
|
case Tag.SHORT:
|
||||||
return new JsonPrimitive( ( (ShortTag) tag ).getData() );
|
return new JsonPrimitive( ( (ShortTag) tag ).getValue() );
|
||||||
case Tag.TAG_INT:
|
case Tag.INT:
|
||||||
return new JsonPrimitive( ( (IntTag) tag ).getData() );
|
return new JsonPrimitive( ( (IntTag) tag ).getValue() );
|
||||||
case Tag.TAG_LONG:
|
case Tag.LONG:
|
||||||
return new JsonPrimitive( ( (LongTag) tag ).getData() );
|
return new JsonPrimitive( ( (LongTag) tag ).getValue() );
|
||||||
case Tag.TAG_FLOAT:
|
case Tag.FLOAT:
|
||||||
return new JsonPrimitive( ( (FloatTag) tag ).getData() );
|
return new JsonPrimitive( ( (FloatTag) tag ).getValue() );
|
||||||
case Tag.TAG_DOUBLE:
|
case Tag.DOUBLE:
|
||||||
return new JsonPrimitive( ( (DoubleTag) tag ).getData() );
|
return new JsonPrimitive( ( (DoubleTag) tag ).getValue() );
|
||||||
case Tag.TAG_BYTE_ARRAY:
|
case Tag.BYTE_ARRAY:
|
||||||
byte[] byteArray = ( (ByteArrayTag) tag ).getData();
|
byte[] byteArray = ( (ByteArrayTag) tag ).getValue();
|
||||||
|
|
||||||
JsonArray jsonByteArray = new JsonArray( byteArray.length );
|
JsonArray jsonByteArray = new JsonArray( byteArray.length );
|
||||||
for ( byte b : byteArray )
|
for ( byte b : byteArray )
|
||||||
@ -187,21 +188,21 @@ public final class TagUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
return jsonByteArray;
|
return jsonByteArray;
|
||||||
case Tag.TAG_STRING:
|
case Tag.STRING:
|
||||||
return new JsonPrimitive( ( (StringTag) tag ).getData() );
|
return new JsonPrimitive( ( (StringTag) tag ).getValue() );
|
||||||
case Tag.TAG_LIST:
|
case Tag.LIST:
|
||||||
List<SpecificTag> items = ( (ListTag) tag ).items;
|
List<TypedTag> items = ( (ListTag) tag ).getValue();
|
||||||
|
|
||||||
JsonArray jsonList = new JsonArray( items.size() );
|
JsonArray jsonList = new JsonArray( items.size() );
|
||||||
for ( SpecificTag subTag : items )
|
for ( TypedTag subTag : items )
|
||||||
{
|
{
|
||||||
if ( subTag instanceof CompoundTag )
|
if ( subTag instanceof CompoundTag )
|
||||||
{
|
{
|
||||||
CompoundTag compound = (CompoundTag) subTag;
|
CompoundTag compound = (CompoundTag) subTag;
|
||||||
if ( compound.size() == 1 )
|
if ( compound.getValue().size() == 1 )
|
||||||
{
|
{
|
||||||
SpecificTag first = (SpecificTag) compound.get( "" );
|
TypedTag first = compound.getValue().get( "" );
|
||||||
if ( !first.isError() )
|
if ( first != null )
|
||||||
{
|
{
|
||||||
jsonList.add( toJson( first ) );
|
jsonList.add( toJson( first ) );
|
||||||
continue;
|
continue;
|
||||||
@ -213,16 +214,13 @@ public final class TagUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
return jsonList;
|
return jsonList;
|
||||||
case Tag.TAG_COMPOUND:
|
case Tag.COMPOUND:
|
||||||
JsonObject jsonObject = new JsonObject();
|
JsonObject jsonObject = new JsonObject();
|
||||||
for ( NamedTag subTag : (CompoundTag) tag )
|
CompoundTag compoundTag = (CompoundTag) tag;
|
||||||
{
|
compoundTag.getValue().forEach( (key, value) -> jsonObject.add( key, toJson( value ) ) );
|
||||||
jsonObject.add( subTag.name(), toJson( subTag.getTag() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
case Tag.TAG_INT_ARRAY:
|
case Tag.INT_ARRAY:
|
||||||
int[] intArray = ( (IntArrayTag) tag ).getData();
|
int[] intArray = ( (IntArrayTag) tag ).getValue();
|
||||||
|
|
||||||
JsonArray jsonIntArray = new JsonArray( intArray.length );
|
JsonArray jsonIntArray = new JsonArray( intArray.length );
|
||||||
for ( int i : intArray )
|
for ( int i : intArray )
|
||||||
@ -231,8 +229,8 @@ public final class TagUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
return jsonIntArray;
|
return jsonIntArray;
|
||||||
case Tag.TAG_LONG_ARRAY:
|
case Tag.LONG_ARRAY:
|
||||||
long[] longArray = ( (LongArrayTag) tag ).getData();
|
long[] longArray = ( (LongArrayTag) tag ).getValue();
|
||||||
|
|
||||||
JsonArray jsonLongArray = new JsonArray( longArray.length );
|
JsonArray jsonLongArray = new JsonArray( longArray.length );
|
||||||
for ( long l : longArray )
|
for ( long l : longArray )
|
||||||
|
@ -5,11 +5,11 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.nbt.TypedTag;
|
||||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||||
import net.md_5.bungee.protocol.DefinedPacket;
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.Protocol;
|
import net.md_5.bungee.protocol.Protocol;
|
||||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import se.llbit.nbt.Tag;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -19,13 +19,13 @@ public class CustomClickAction extends DefinedPacket
|
|||||||
{
|
{
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private Tag data;
|
private TypedTag data;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
|
public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
id = readString( buf );
|
id = readString( buf );
|
||||||
data = readNullable( (buf0) -> readTag( buf0, protocolVersion ), buf );
|
data = readNullable( (buf0) -> (TypedTag) readTag( buf0, protocolVersion ), buf );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -7,11 +7,11 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.nbt.Tag;
|
||||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||||
import net.md_5.bungee.protocol.DefinedPacket;
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.Location;
|
import net.md_5.bungee.protocol.Location;
|
||||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import se.llbit.nbt.Tag;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
@ -5,11 +5,11 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.nbt.Tag;
|
||||||
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
import net.md_5.bungee.protocol.AbstractPacketHandler;
|
||||||
import net.md_5.bungee.protocol.DefinedPacket;
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.Location;
|
import net.md_5.bungee.protocol.Location;
|
||||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import se.llbit.nbt.Tag;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
@ -7,13 +7,13 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.api.dialog.Dialog;
|
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.AbstractPacketHandler;
|
||||||
import net.md_5.bungee.protocol.ChatSerializer;
|
import net.md_5.bungee.protocol.ChatSerializer;
|
||||||
import net.md_5.bungee.protocol.DefinedPacket;
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.Either;
|
import net.md_5.bungee.protocol.Either;
|
||||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import net.md_5.bungee.protocol.TagUtil;
|
import net.md_5.bungee.protocol.TagUtil;
|
||||||
import se.llbit.nbt.SpecificTag;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -39,7 +39,7 @@ public class ShowDialog extends DefinedPacket
|
|||||||
|
|
||||||
protected static Dialog readDialog(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
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 );
|
JsonElement json = TagUtil.toJson( nbt );
|
||||||
return ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().deserialize( json );
|
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)
|
protected static void writeDialog(Dialog dialog, ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
JsonElement json = ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().toJson( dialog );
|
JsonElement json = ChatSerializer.forVersion( protocolVersion ).getDialogSerializer().toJson( dialog );
|
||||||
SpecificTag nbt = TagUtil.fromJson( json );
|
TypedTag nbt = TagUtil.fromJson( json );
|
||||||
|
|
||||||
writeTag( nbt, buf, protocolVersion );
|
writeTag( nbt, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,16 @@ import com.google.gson.JsonArray;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonPrimitive;
|
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 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
|
public class TagUtilTest
|
||||||
{
|
{
|
||||||
@ -25,7 +25,7 @@ public class TagUtilTest
|
|||||||
private static void testDissembleReassemble(String json)
|
private static void testDissembleReassemble(String json)
|
||||||
{
|
{
|
||||||
JsonElement parsedJson = GSON.fromJson( json, JsonElement.class );
|
JsonElement parsedJson = GSON.fromJson( json, JsonElement.class );
|
||||||
SpecificTag nbt = TagUtil.fromJson( parsedJson );
|
TypedTag nbt = TagUtil.fromJson( parsedJson );
|
||||||
JsonElement convertedElement = TagUtil.toJson( nbt );
|
JsonElement convertedElement = TagUtil.toJson( nbt );
|
||||||
|
|
||||||
String convertedJson = GSON.toJson( convertedElement );
|
String convertedJson = GSON.toJson( convertedElement );
|
||||||
@ -35,18 +35,19 @@ public class TagUtilTest
|
|||||||
@Test
|
@Test
|
||||||
public void testStringLiteral()
|
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\"}]}" );
|
testDissembleReassemble( "{\"text\":\"\",\"extra\":[\"hello\",{\"text\":\"there\",\"color\":\"#ff0000\"},{\"text\":\"friend\",\"font\":\"minecraft:default\"}]}" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCreateMixedList(JsonArray array)
|
public void testCreateMixedList(JsonArray array)
|
||||||
{
|
{
|
||||||
SpecificTag tag = TagUtil.fromJson( array );
|
TypedTag tag = TagUtil.fromJson( array );
|
||||||
assertInstanceOf( ListTag.class, tag );
|
assertInstanceOf( ListTag.class, tag );
|
||||||
ListTag list = (ListTag) tag;
|
ListTag list = (ListTag) tag;
|
||||||
assertEquals( SpecificTag.TAG_COMPOUND, list.getType() );
|
assertEquals( Tag.COMPOUND, list.getListType() );
|
||||||
assertEquals( array.size(), list.size() );
|
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() );
|
assertTrue( i < array.size() );
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ public class TagUtilTest
|
|||||||
assertInstanceOf( IntTag.class, value );
|
assertInstanceOf( IntTag.class, value );
|
||||||
|
|
||||||
IntTag integer = (IntTag) value;
|
IntTag integer = (IntTag) value;
|
||||||
assertEquals( array.get( i ).getAsInt(), integer.getData() );
|
assertEquals( array.get( i ).getAsInt(), integer.getValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ( primitive.isString() )
|
} else if ( primitive.isString() )
|
||||||
@ -85,7 +86,7 @@ public class TagUtilTest
|
|||||||
assertInstanceOf( StringTag.class, value );
|
assertInstanceOf( StringTag.class, value );
|
||||||
|
|
||||||
StringTag string = (StringTag) 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()
|
public void testCreateEmptyList()
|
||||||
{
|
{
|
||||||
JsonArray array = new JsonArray();
|
JsonArray array = new JsonArray();
|
||||||
SpecificTag tag = TagUtil.fromJson( array );
|
TypedTag tag = TagUtil.fromJson( array );
|
||||||
assertInstanceOf( ListTag.class, tag );
|
assertInstanceOf( ListTag.class, tag );
|
||||||
ListTag list = (ListTag) tag;
|
ListTag list = (ListTag) tag;
|
||||||
assertEquals( 0, list.size() );
|
assertEquals( 0, list.size() );
|
||||||
assertEquals( Tag.TAG_END, list.getType() );
|
assertEquals( Tag.END, list.getListType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -143,16 +144,16 @@ public class TagUtilTest
|
|||||||
array.add( ( (byte) 1 ) );
|
array.add( ( (byte) 1 ) );
|
||||||
array.add( ( (byte) 2 ) );
|
array.add( ( (byte) 2 ) );
|
||||||
|
|
||||||
SpecificTag tag = TagUtil.fromJson( array );
|
TypedTag tag = TagUtil.fromJson( array );
|
||||||
assertInstanceOf( ByteArrayTag.class, tag );
|
assertInstanceOf( ByteArrayTag.class, tag );
|
||||||
ByteArrayTag byteArray = (ByteArrayTag) 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() );
|
assertTrue( i < array.size() );
|
||||||
|
|
||||||
byte item = byteArray.getData()[i];
|
byte item = byteArray.getValue()[i];
|
||||||
assertEquals( array.get( i ).getAsByte(), item );
|
assertEquals( array.get( i ).getAsByte(), item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,16 +165,16 @@ public class TagUtilTest
|
|||||||
array.add( 1 );
|
array.add( 1 );
|
||||||
array.add( 2 );
|
array.add( 2 );
|
||||||
|
|
||||||
SpecificTag tag = TagUtil.fromJson( array );
|
TypedTag tag = TagUtil.fromJson( array );
|
||||||
assertInstanceOf( IntArrayTag.class, tag );
|
assertInstanceOf( IntArrayTag.class, tag );
|
||||||
IntArrayTag intArray = (IntArrayTag) 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() );
|
assertTrue( i < array.size() );
|
||||||
|
|
||||||
int item = intArray.getData()[i];
|
int item = intArray.getValue()[i];
|
||||||
assertEquals( array.get( i ).getAsInt(), item );
|
assertEquals( array.get( i ).getAsInt(), item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,16 +186,16 @@ public class TagUtilTest
|
|||||||
array.add( 1L );
|
array.add( 1L );
|
||||||
array.add( 2L );
|
array.add( 2L );
|
||||||
|
|
||||||
SpecificTag tag = TagUtil.fromJson( array );
|
TypedTag tag = TagUtil.fromJson( array );
|
||||||
assertInstanceOf( LongArrayTag.class, tag );
|
assertInstanceOf( LongArrayTag.class, tag );
|
||||||
LongArrayTag intArray = (LongArrayTag) 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() );
|
assertTrue( i < array.size() );
|
||||||
|
|
||||||
long item = intArray.getData()[i];
|
long item = intArray.getValue()[i];
|
||||||
assertEquals( array.get( i ).getAsLong(), item );
|
assertEquals( array.get( i ).getAsLong(), item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,10 +207,10 @@ public class TagUtilTest
|
|||||||
array.add( "a" );
|
array.add( "a" );
|
||||||
array.add( "b" );
|
array.add( "b" );
|
||||||
|
|
||||||
SpecificTag tag = TagUtil.fromJson( array );
|
TypedTag tag = TagUtil.fromJson( array );
|
||||||
assertInstanceOf( ListTag.class, tag );
|
assertInstanceOf( ListTag.class, tag );
|
||||||
ListTag list = (ListTag) tag;
|
ListTag list = (ListTag) tag;
|
||||||
assertEquals( SpecificTag.TAG_STRING, list.getType() );
|
assertEquals( Tag.STRING, list.getListType() );
|
||||||
assertEquals( 2, list.size() );
|
assertEquals( 2, list.size() );
|
||||||
|
|
||||||
for ( int i = 0; i < list.size(); i++ )
|
for ( int i = 0; i < list.size(); i++ )
|
||||||
@ -220,7 +221,7 @@ public class TagUtilTest
|
|||||||
assertInstanceOf( StringTag.class, item );
|
assertInstanceOf( StringTag.class, item );
|
||||||
|
|
||||||
StringTag string = (StringTag) item;
|
StringTag string = (StringTag) item;
|
||||||
assertEquals( array.get( i ).getAsString(), string.getData() );
|
assertEquals( array.get( i ).getAsString(), string.getValue() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.TabCompleteResponse;
|
||||||
import net.md_5.bungee.protocol.packet.UnsignedClientCommand;
|
import net.md_5.bungee.protocol.packet.UnsignedClientCommand;
|
||||||
import net.md_5.bungee.util.AllowedCharacters;
|
import net.md_5.bungee.util.AllowedCharacters;
|
||||||
import se.llbit.nbt.SpecificTag;
|
|
||||||
|
|
||||||
public class UpstreamBridge extends PacketHandler
|
public class UpstreamBridge extends PacketHandler
|
||||||
{
|
{
|
||||||
@ -385,7 +384,7 @@ public class UpstreamBridge extends PacketHandler
|
|||||||
@Override
|
@Override
|
||||||
public void handle(CustomClickAction customClickAction) throws Exception
|
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() )
|
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||||
{
|
{
|
||||||
throw CancelSendSignal.INSTANCE;
|
throw CancelSendSignal.INSTANCE;
|
||||||
|
@ -4,12 +4,13 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
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.DefinedPacket;
|
||||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import se.llbit.nbt.NamedTag;
|
|
||||||
import se.llbit.nbt.Tag;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to rewrite integers within packets.
|
* Class to rewrite integers within packets.
|
||||||
@ -275,10 +276,13 @@ public abstract class EntityMap
|
|||||||
DefinedPacket.readVarInt( packet );
|
DefinedPacket.readVarInt( packet );
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( packet ) ) );
|
NamedTag tag = new NamedTag();
|
||||||
if ( tag.isError() )
|
try
|
||||||
{
|
{
|
||||||
throw new RuntimeException( tag.error() );
|
tag.read( new DataInputStream( new ByteBufInputStream( packet ) ), NBTLimiter.unlimitedSize() );
|
||||||
|
} catch ( IOException ioException )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( ioException );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 15:
|
case 15:
|
||||||
@ -321,10 +325,13 @@ public abstract class EntityMap
|
|||||||
{
|
{
|
||||||
packet.readerIndex( position );
|
packet.readerIndex( position );
|
||||||
|
|
||||||
Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( packet ) ) );
|
NamedTag tag = new NamedTag();
|
||||||
if ( tag.isError() )
|
try
|
||||||
{
|
{
|
||||||
throw new RuntimeException( tag.error() );
|
tag.read( new DataInputStream( new ByteBufInputStream( packet ) ), NBTLimiter.unlimitedSize() );
|
||||||
|
} catch ( IOException ioException )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( ioException );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user