Minecraft 23w43b support
This commit is contained in:
parent
e5c80d0044
commit
0f5f09b6c5
@ -160,6 +160,28 @@ public final class TextComponent extends BaseComponent
|
|||||||
return components.toArray( new BaseComponent[ 0 ] );
|
return components.toArray( new BaseComponent[ 0 ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal compatibility method to transform an array of components to a
|
||||||
|
* single component.
|
||||||
|
*
|
||||||
|
* @param components array
|
||||||
|
* @return single component
|
||||||
|
*/
|
||||||
|
public static BaseComponent fromArray(BaseComponent... components)
|
||||||
|
{
|
||||||
|
if ( components == null )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( components.length == 1 )
|
||||||
|
{
|
||||||
|
return components[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TextComponent( components );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text of the component that will be displayed to the client
|
* The text of the component that will be displayed to the client
|
||||||
*/
|
*/
|
||||||
|
@ -8,6 +8,7 @@ import com.google.gson.JsonElement;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
@ -87,14 +88,43 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
|||||||
public static BaseComponent deserialize(String json)
|
public static BaseComponent deserialize(String json)
|
||||||
{
|
{
|
||||||
JsonElement jsonElement = JsonParser.parseString( json );
|
JsonElement jsonElement = JsonParser.parseString( json );
|
||||||
|
|
||||||
|
return deserialize( jsonElement );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize a JSON element as a single component. The input is expected
|
||||||
|
* to be a JSON object that represents only one component.
|
||||||
|
*
|
||||||
|
* @param jsonElement the component json to parse
|
||||||
|
* @return the deserialized component
|
||||||
|
* @throws IllegalArgumentException if anything other than a JSON object is
|
||||||
|
* passed as input
|
||||||
|
*/
|
||||||
|
public static BaseComponent deserialize(JsonElement jsonElement)
|
||||||
|
{
|
||||||
|
if ( jsonElement instanceof JsonPrimitive )
|
||||||
|
{
|
||||||
|
JsonPrimitive primitive = (JsonPrimitive) jsonElement;
|
||||||
|
if ( primitive.isString() )
|
||||||
|
{
|
||||||
|
return new TextComponent( primitive.getAsString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( !jsonElement.isJsonObject() )
|
if ( !jsonElement.isJsonObject() )
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException( "Malformatted JSON. Expected object, got array for input \"" + json + "\"." );
|
throw new IllegalArgumentException( "Malformatted JSON. Expected object, got array for input \"" + jsonElement + "\"." );
|
||||||
}
|
}
|
||||||
|
|
||||||
return gson.fromJson( jsonElement, BaseComponent.class );
|
return gson.fromJson( jsonElement, BaseComponent.class );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static JsonElement toJson(BaseComponent component)
|
||||||
|
{
|
||||||
|
return gson.toJsonTree( component );
|
||||||
|
}
|
||||||
|
|
||||||
public static String toString(Object object)
|
public static String toString(Object object)
|
||||||
{
|
{
|
||||||
return gson.toJson( object );
|
return gson.toJson( object );
|
||||||
|
@ -18,11 +18,10 @@ public class TextComponentSerializer extends BaseComponentSerializer implements
|
|||||||
{
|
{
|
||||||
TextComponent component = new TextComponent();
|
TextComponent component = new TextComponent();
|
||||||
JsonObject object = json.getAsJsonObject();
|
JsonObject object = json.getAsJsonObject();
|
||||||
if ( !object.has( "text" ) )
|
if ( object.has( "text" ) )
|
||||||
{
|
{
|
||||||
throw new JsonParseException( "Could not parse JSON: missing 'text' property" );
|
|
||||||
}
|
|
||||||
component.setText( object.get( "text" ).getAsString() );
|
component.setText( object.get( "text" ).getAsString() );
|
||||||
|
}
|
||||||
deserialize( object, component, context );
|
deserialize( object, component, context );
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import java.util.function.Function;
|
|||||||
import java.util.function.ObjIntConsumer;
|
import java.util.function.ObjIntConsumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -72,6 +71,8 @@ public class ComponentsTest
|
|||||||
assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) );
|
assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) );
|
||||||
testDissembleReassemble( components );
|
testDissembleReassemble( components );
|
||||||
//////////
|
//////////
|
||||||
|
// TODO: now ambiguous since "text" to distinguish Text from Item is not required
|
||||||
|
/*
|
||||||
TextComponent component1 = new TextComponent( "HoverableText" );
|
TextComponent component1 = new TextComponent( "HoverableText" );
|
||||||
String nbt = "{display:{Name:{text:Hello},Lore:[{text:Line_1},{text:Line_2}]},ench:[{id:49,lvl:5}],Unbreakable:1}}";
|
String nbt = "{display:{Name:{text:Hello},Lore:[{text:Line_1},{text:Line_2}]},ench:[{id:49,lvl:5}],Unbreakable:1}}";
|
||||||
Item contentItem = new Item( "minecraft:wood", 1, ItemTag.ofNbt( nbt ) );
|
Item contentItem = new Item( "minecraft:wood", 1, ItemTag.ofNbt( nbt ) );
|
||||||
@ -84,6 +85,7 @@ public class ComponentsTest
|
|||||||
assertEquals( contentItem.getCount(), parsedContentItem.getCount() );
|
assertEquals( contentItem.getCount(), parsedContentItem.getCount() );
|
||||||
assertEquals( contentItem.getId(), parsedContentItem.getId() );
|
assertEquals( contentItem.getId(), parsedContentItem.getId() );
|
||||||
assertEquals( nbt, parsedContentItem.getTag().getNbt() );
|
assertEquals( nbt, parsedContentItem.getTag().getNbt() );
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -18,26 +18,20 @@
|
|||||||
<name>BungeeCord-Protocol</name>
|
<name>BungeeCord-Protocol</name>
|
||||||
<description>Minimal implementation of the Minecraft protocol for use in BungeeCord</description>
|
<description>Minimal implementation of the Minecraft protocol for use in BungeeCord</description>
|
||||||
|
|
||||||
<!-- We really shouldn't depend on external repositories, but at least this is the Central staging one -->
|
<!-- We really shouldn't depend on external repositories -->
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>sonatype-nexus-snapshots</id>
|
<id>minecraft-libraries</id>
|
||||||
<name>Sonatype Nexus Snapshots</name>
|
<name>Minecraft Libraries</name>
|
||||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
<url>https://libraries.minecraft.net/</url>
|
||||||
<releases>
|
|
||||||
<enabled>false</enabled>
|
|
||||||
</releases>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</snapshots>
|
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>com.mojang</groupId>
|
||||||
<artifactId>brigadier</artifactId>
|
<artifactId>brigadier</artifactId>
|
||||||
<version>1.0.16-SNAPSHOT</version>
|
<version>1.2.9</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -2,6 +2,7 @@ package net.md_5.bungee.protocol;
|
|||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import io.netty.buffer.ByteBufOutputStream;
|
import io.netty.buffer.ByteBufOutputStream;
|
||||||
@ -15,6 +16,8 @@ import java.util.EnumSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
import se.llbit.nbt.ErrorTag;
|
import se.llbit.nbt.ErrorTag;
|
||||||
import se.llbit.nbt.NamedTag;
|
import se.llbit.nbt.NamedTag;
|
||||||
import se.llbit.nbt.SpecificTag;
|
import se.llbit.nbt.SpecificTag;
|
||||||
@ -70,6 +73,38 @@ public abstract class DefinedPacket
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BaseComponent readBaseComponent(ByteBuf buf, int protocolVersion)
|
||||||
|
{
|
||||||
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
||||||
|
{
|
||||||
|
SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
|
||||||
|
JsonElement json = TagUtil.toJson( nbt );
|
||||||
|
|
||||||
|
return ComponentSerializer.deserialize( json );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
String string = readString( buf );
|
||||||
|
|
||||||
|
return ComponentSerializer.deserialize( string );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeBaseComponent(BaseComponent message, ByteBuf buf, int protocolVersion)
|
||||||
|
{
|
||||||
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
||||||
|
{
|
||||||
|
JsonElement json = ComponentSerializer.toJson( message );
|
||||||
|
SpecificTag nbt = TagUtil.fromJson( json );
|
||||||
|
|
||||||
|
writeTag( nbt, buf, protocolVersion );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
String string = ComponentSerializer.toString( message );
|
||||||
|
|
||||||
|
writeString( string, buf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void writeArray(byte[] b, ByteBuf buf)
|
public static void writeArray(byte[] b, ByteBuf buf)
|
||||||
{
|
{
|
||||||
if ( b.length > Short.MAX_VALUE )
|
if ( b.length > Short.MAX_VALUE )
|
||||||
@ -395,6 +430,11 @@ public abstract class DefinedPacket
|
|||||||
throw new UnsupportedOperationException( "Packet must implement read method" );
|
throw new UnsupportedOperationException( "Packet must implement read method" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
|
{
|
||||||
|
read( buf, direction, protocolVersion );
|
||||||
|
}
|
||||||
|
|
||||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
read( buf );
|
read( buf );
|
||||||
@ -405,6 +445,11 @@ public abstract class DefinedPacket
|
|||||||
throw new UnsupportedOperationException( "Packet must implement write method" );
|
throw new UnsupportedOperationException( "Packet must implement write method" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void write(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
|
{
|
||||||
|
write( buf, direction, protocolVersion );
|
||||||
|
}
|
||||||
|
|
||||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
write( buf );
|
write( buf );
|
||||||
|
@ -39,7 +39,7 @@ public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf>
|
|||||||
DefinedPacket packet = prot.createPacket( packetId, protocolVersion );
|
DefinedPacket packet = prot.createPacket( packetId, protocolVersion );
|
||||||
if ( packet != null )
|
if ( packet != null )
|
||||||
{
|
{
|
||||||
packet.read( in, prot.getDirection(), protocolVersion );
|
packet.read( in, protocol, prot.getDirection(), protocolVersion );
|
||||||
|
|
||||||
if ( in.isReadable() )
|
if ( in.isReadable() )
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,6 @@ public class MinecraftEncoder extends MessageToByteEncoder<DefinedPacket>
|
|||||||
{
|
{
|
||||||
Protocol.DirectionData prot = ( server ) ? protocol.TO_CLIENT : protocol.TO_SERVER;
|
Protocol.DirectionData prot = ( server ) ? protocol.TO_CLIENT : protocol.TO_SERVER;
|
||||||
DefinedPacket.writeVarInt( prot.getId( msg.getClass(), protocolVersion ), out );
|
DefinedPacket.writeVarInt( prot.getId( msg.getClass(), protocolVersion ), out );
|
||||||
msg.write( out, prot.getDirection(), protocolVersion );
|
msg.write( out, protocol, prot.getDirection(), protocolVersion );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,7 +451,8 @@ public enum Protocol
|
|||||||
map( ProtocolConstants.MINECRAFT_1_19_1, 0x12 ),
|
map( ProtocolConstants.MINECRAFT_1_19_1, 0x12 ),
|
||||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ),
|
map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ),
|
||||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
|
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
|
||||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 )
|
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ),
|
||||||
|
map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 )
|
||||||
);
|
);
|
||||||
TO_SERVER.registerPacket( Chat.class,
|
TO_SERVER.registerPacket( Chat.class,
|
||||||
Chat::new,
|
Chat::new,
|
||||||
@ -517,7 +518,8 @@ public enum Protocol
|
|||||||
map( ProtocolConstants.MINECRAFT_1_19_1, 0x0D ),
|
map( ProtocolConstants.MINECRAFT_1_19_1, 0x0D ),
|
||||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
|
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
|
||||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
|
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
|
||||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F )
|
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ),
|
||||||
|
map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 )
|
||||||
);
|
);
|
||||||
TO_SERVER.registerPacket(
|
TO_SERVER.registerPacket(
|
||||||
StartConfiguration.class,
|
StartConfiguration.class,
|
||||||
|
@ -44,6 +44,7 @@ public class ProtocolConstants
|
|||||||
public static final int MINECRAFT_1_19_4 = 762;
|
public static final int MINECRAFT_1_19_4 = 762;
|
||||||
public static final int MINECRAFT_1_20 = 763;
|
public static final int MINECRAFT_1_20 = 763;
|
||||||
public static final int MINECRAFT_1_20_2 = 764;
|
public static final int MINECRAFT_1_20_2 = 764;
|
||||||
|
public static final int MINECRAFT_1_20_3 = 1073741984;
|
||||||
public static final List<String> SUPPORTED_VERSIONS;
|
public static final List<String> SUPPORTED_VERSIONS;
|
||||||
public static final List<Integer> SUPPORTED_VERSION_IDS;
|
public static final List<Integer> SUPPORTED_VERSION_IDS;
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ public class ProtocolConstants
|
|||||||
if ( SNAPSHOT_SUPPORT )
|
if ( SNAPSHOT_SUPPORT )
|
||||||
{
|
{
|
||||||
// supportedVersions.add( "1.20.x" );
|
// supportedVersions.add( "1.20.x" );
|
||||||
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_2 );
|
supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
SUPPORTED_VERSIONS = supportedVersions.build();
|
SUPPORTED_VERSIONS = supportedVersions.build();
|
||||||
|
218
protocol/src/main/java/net/md_5/bungee/protocol/TagUtil.java
Normal file
218
protocol/src/main/java/net/md_5/bungee/protocol/TagUtil.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package net.md_5.bungee.protocol;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonNull;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import se.llbit.nbt.ByteArrayTag;
|
||||||
|
import se.llbit.nbt.ByteTag;
|
||||||
|
import se.llbit.nbt.CompoundTag;
|
||||||
|
import se.llbit.nbt.DoubleTag;
|
||||||
|
import se.llbit.nbt.FloatTag;
|
||||||
|
import se.llbit.nbt.IntArrayTag;
|
||||||
|
import se.llbit.nbt.IntTag;
|
||||||
|
import se.llbit.nbt.ListTag;
|
||||||
|
import se.llbit.nbt.LongArrayTag;
|
||||||
|
import se.llbit.nbt.LongTag;
|
||||||
|
import se.llbit.nbt.NamedTag;
|
||||||
|
import se.llbit.nbt.ShortTag;
|
||||||
|
import se.llbit.nbt.SpecificTag;
|
||||||
|
import se.llbit.nbt.StringTag;
|
||||||
|
import se.llbit.nbt.Tag;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class TagUtil
|
||||||
|
{
|
||||||
|
|
||||||
|
public static SpecificTag fromJson(JsonElement json)
|
||||||
|
{
|
||||||
|
if ( json instanceof JsonPrimitive )
|
||||||
|
{
|
||||||
|
JsonPrimitive jsonPrimitive = (JsonPrimitive) json;
|
||||||
|
if ( jsonPrimitive.isNumber() )
|
||||||
|
{
|
||||||
|
Number number = json.getAsNumber();
|
||||||
|
|
||||||
|
if ( number instanceof Byte )
|
||||||
|
{
|
||||||
|
return new ByteTag( (Byte) number );
|
||||||
|
} else if ( number instanceof Short )
|
||||||
|
{
|
||||||
|
return new ShortTag( (Short) number );
|
||||||
|
} else if ( number instanceof Integer )
|
||||||
|
{
|
||||||
|
return new IntTag( (Integer) number );
|
||||||
|
} else if ( number instanceof Long )
|
||||||
|
{
|
||||||
|
return new LongTag( (Long) number );
|
||||||
|
} else if ( number instanceof Float )
|
||||||
|
{
|
||||||
|
return new FloatTag( (Float) number );
|
||||||
|
} else if ( number instanceof Double )
|
||||||
|
{
|
||||||
|
return new DoubleTag( (Double) number );
|
||||||
|
}
|
||||||
|
} else if ( jsonPrimitive.isString() )
|
||||||
|
{
|
||||||
|
return new StringTag( jsonPrimitive.getAsString() );
|
||||||
|
} else if ( jsonPrimitive.isBoolean() )
|
||||||
|
{
|
||||||
|
return new ByteTag( jsonPrimitive.getAsBoolean() ? 1 : 0 );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Unknown JSON primitive: " + jsonPrimitive );
|
||||||
|
}
|
||||||
|
} else if ( json instanceof JsonObject )
|
||||||
|
{
|
||||||
|
CompoundTag compoundTag = new CompoundTag();
|
||||||
|
for ( Map.Entry<String, JsonElement> property : ( (JsonObject) json ).entrySet() )
|
||||||
|
{
|
||||||
|
compoundTag.add( property.getKey(), fromJson( property.getValue() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return compoundTag;
|
||||||
|
} else if ( json instanceof JsonArray )
|
||||||
|
{
|
||||||
|
List<JsonElement> jsonArray = ( (JsonArray) json ).asList();
|
||||||
|
|
||||||
|
if ( jsonArray.isEmpty() )
|
||||||
|
{
|
||||||
|
return new ListTag( Tag.TAG_END, Collections.emptyList() );
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecificTag listTag;
|
||||||
|
int listType = fromJson( jsonArray.get( 0 ) ).tagType();
|
||||||
|
switch ( listType )
|
||||||
|
{
|
||||||
|
case Tag.TAG_BYTE:
|
||||||
|
byte[] bytes = new byte[ jsonArray.size() ];
|
||||||
|
for ( int i = 0; i < bytes.length; i++ )
|
||||||
|
{
|
||||||
|
bytes[i] = (Byte) ( (JsonPrimitive) jsonArray.get( i ) ).getAsNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
listTag = new ByteArrayTag( bytes );
|
||||||
|
break;
|
||||||
|
case Tag.TAG_INT:
|
||||||
|
int[] ints = new int[ jsonArray.size() ];
|
||||||
|
for ( int i = 0; i < ints.length; i++ )
|
||||||
|
{
|
||||||
|
ints[i] = (Integer) ( (JsonPrimitive) jsonArray.get( i ) ).getAsNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
listTag = new IntArrayTag( ints );
|
||||||
|
break;
|
||||||
|
case Tag.TAG_LONG:
|
||||||
|
long[] longs = new long[ jsonArray.size() ];
|
||||||
|
for ( int i = 0; i < longs.length; i++ )
|
||||||
|
{
|
||||||
|
longs[i] = (Long) ( (JsonPrimitive) jsonArray.get( i ) ).getAsNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
listTag = new LongArrayTag( longs );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
List<SpecificTag> tagItems = new ArrayList<>( jsonArray.size() );
|
||||||
|
|
||||||
|
for ( JsonElement jsonEl : jsonArray )
|
||||||
|
{
|
||||||
|
SpecificTag subTag = fromJson( jsonEl );
|
||||||
|
if ( subTag.tagType() != listType )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Cannot convert mixed JsonArray to Tag" );
|
||||||
|
}
|
||||||
|
|
||||||
|
tagItems.add( subTag );
|
||||||
|
}
|
||||||
|
|
||||||
|
listTag = new ListTag( listType, tagItems );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return listTag;
|
||||||
|
} else if ( json instanceof JsonNull )
|
||||||
|
{
|
||||||
|
return Tag.END;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException( "Unknown JSON element: " + json );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonElement toJson(SpecificTag tag)
|
||||||
|
{
|
||||||
|
switch ( tag.tagType() )
|
||||||
|
{
|
||||||
|
case Tag.TAG_BYTE:
|
||||||
|
return new JsonPrimitive( (byte) ( (ByteTag) tag ).getData() );
|
||||||
|
case Tag.TAG_SHORT:
|
||||||
|
return new JsonPrimitive( ( (ShortTag) tag ).getData() );
|
||||||
|
case Tag.TAG_INT:
|
||||||
|
return new JsonPrimitive( ( (IntTag) tag ).getData() );
|
||||||
|
case Tag.TAG_LONG:
|
||||||
|
return new JsonPrimitive( ( (LongTag) tag ).getData() );
|
||||||
|
case Tag.TAG_FLOAT:
|
||||||
|
return new JsonPrimitive( ( (FloatTag) tag ).getData() );
|
||||||
|
case Tag.TAG_DOUBLE:
|
||||||
|
return new JsonPrimitive( ( (DoubleTag) tag ).getData() );
|
||||||
|
case Tag.TAG_BYTE_ARRAY:
|
||||||
|
byte[] byteArray = ( (ByteArrayTag) tag ).getData();
|
||||||
|
|
||||||
|
JsonArray jsonByteArray = new JsonArray( byteArray.length );
|
||||||
|
for ( byte b : byteArray )
|
||||||
|
{
|
||||||
|
jsonByteArray.add( new JsonPrimitive( b ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonByteArray;
|
||||||
|
case Tag.TAG_STRING:
|
||||||
|
return new JsonPrimitive( ( (StringTag) tag ).getData() );
|
||||||
|
case Tag.TAG_LIST:
|
||||||
|
List<SpecificTag> items = ( (ListTag) tag ).items;
|
||||||
|
|
||||||
|
JsonArray jsonList = new JsonArray( items.size() );
|
||||||
|
for ( SpecificTag subTag : items )
|
||||||
|
{
|
||||||
|
jsonList.add( toJson( subTag ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonList;
|
||||||
|
case Tag.TAG_COMPOUND:
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
for ( NamedTag subTag : (CompoundTag) tag )
|
||||||
|
{
|
||||||
|
jsonObject.add( subTag.name(), toJson( subTag.getTag() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonObject;
|
||||||
|
case Tag.TAG_INT_ARRAY:
|
||||||
|
int[] intArray = ( (IntArrayTag) tag ).getData();
|
||||||
|
|
||||||
|
JsonArray jsonIntArray = new JsonArray( intArray.length );
|
||||||
|
for ( int i : intArray )
|
||||||
|
{
|
||||||
|
jsonIntArray.add( new JsonPrimitive( i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonIntArray;
|
||||||
|
case Tag.TAG_LONG_ARRAY:
|
||||||
|
long[] longArray = ( (LongArrayTag) tag ).getData();
|
||||||
|
|
||||||
|
JsonArray jsonLongArray = new JsonArray( longArray.length );
|
||||||
|
for ( long l : longArray )
|
||||||
|
{
|
||||||
|
jsonLongArray.add( new JsonPrimitive( l ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonLongArray;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException( "Unknown NBT tag: " + tag );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import java.util.UUID;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -17,7 +18,7 @@ public class BossBar extends DefinedPacket
|
|||||||
|
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
private int action;
|
private int action;
|
||||||
private String title;
|
private BaseComponent title;
|
||||||
private float health;
|
private float health;
|
||||||
private int color;
|
private int color;
|
||||||
private int division;
|
private int division;
|
||||||
@ -39,7 +40,7 @@ public class BossBar extends DefinedPacket
|
|||||||
{
|
{
|
||||||
// Add
|
// Add
|
||||||
case 0:
|
case 0:
|
||||||
title = readString( buf );
|
title = readBaseComponent( buf, protocolVersion );
|
||||||
health = buf.readFloat();
|
health = buf.readFloat();
|
||||||
color = readVarInt( buf );
|
color = readVarInt( buf );
|
||||||
division = readVarInt( buf );
|
division = readVarInt( buf );
|
||||||
@ -51,7 +52,7 @@ public class BossBar extends DefinedPacket
|
|||||||
break;
|
break;
|
||||||
// Title
|
// Title
|
||||||
case 3:
|
case 3:
|
||||||
title = readString( buf );
|
title = readBaseComponent( buf, protocolVersion );
|
||||||
break;
|
break;
|
||||||
// Style
|
// Style
|
||||||
case 4:
|
case 4:
|
||||||
@ -75,7 +76,7 @@ public class BossBar extends DefinedPacket
|
|||||||
{
|
{
|
||||||
// Add
|
// Add
|
||||||
case 0:
|
case 0:
|
||||||
writeString( title, buf );
|
writeBaseComponent( title, buf, protocolVersion );
|
||||||
buf.writeFloat( health );
|
buf.writeFloat( health );
|
||||||
writeVarInt( color, buf );
|
writeVarInt( color, buf );
|
||||||
writeVarInt( division, buf );
|
writeVarInt( division, buf );
|
||||||
@ -87,7 +88,7 @@ public class BossBar extends DefinedPacket
|
|||||||
break;
|
break;
|
||||||
// Title
|
// Title
|
||||||
case 3:
|
case 3:
|
||||||
writeString( title, buf );
|
writeBaseComponent( title, buf, protocolVersion );
|
||||||
break;
|
break;
|
||||||
// Style
|
// Style
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -5,8 +5,12 @@ 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.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
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.ProtocolConstants;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -15,18 +19,30 @@ import net.md_5.bungee.protocol.DefinedPacket;
|
|||||||
public class Kick extends DefinedPacket
|
public class Kick extends DefinedPacket
|
||||||
{
|
{
|
||||||
|
|
||||||
private String message;
|
private BaseComponent message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuf buf)
|
public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
message = readString( buf );
|
if ( protocol == Protocol.LOGIN )
|
||||||
|
{
|
||||||
|
message = ComponentSerializer.deserialize( readString( buf ) );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
message = readBaseComponent( buf, protocolVersion );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(ByteBuf buf)
|
public void write(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
writeString( message, buf );
|
if ( protocol == Protocol.LOGIN )
|
||||||
|
{
|
||||||
|
writeString( ComponentSerializer.toString( message ), buf );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
writeBaseComponent( message, buf, protocolVersion );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,6 +5,7 @@ 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.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -16,21 +17,21 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
|||||||
public class PlayerListHeaderFooter extends DefinedPacket
|
public class PlayerListHeaderFooter extends DefinedPacket
|
||||||
{
|
{
|
||||||
|
|
||||||
private String header;
|
private BaseComponent header;
|
||||||
private String footer;
|
private BaseComponent footer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
header = readString( buf );
|
header = readBaseComponent( buf, protocolVersion );
|
||||||
footer = readString( buf );
|
footer = readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
writeString( header, buf );
|
writeBaseComponent( header, buf, protocolVersion );
|
||||||
writeString( footer, buf );
|
writeBaseComponent( footer, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,6 +5,7 @@ import java.util.UUID;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
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.PlayerPublicKey;
|
import net.md_5.bungee.protocol.PlayerPublicKey;
|
||||||
@ -38,7 +39,7 @@ public class PlayerListItem extends DefinedPacket
|
|||||||
item.ping = DefinedPacket.readVarInt( buf );
|
item.ping = DefinedPacket.readVarInt( buf );
|
||||||
if ( buf.readBoolean() )
|
if ( buf.readBoolean() )
|
||||||
{
|
{
|
||||||
item.displayName = DefinedPacket.readString( buf );
|
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 )
|
||||||
{
|
{
|
||||||
@ -54,7 +55,7 @@ public class PlayerListItem extends DefinedPacket
|
|||||||
case UPDATE_DISPLAY_NAME:
|
case UPDATE_DISPLAY_NAME:
|
||||||
if ( buf.readBoolean() )
|
if ( buf.readBoolean() )
|
||||||
{
|
{
|
||||||
item.displayName = DefinedPacket.readString( buf );
|
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ public class PlayerListItem extends DefinedPacket
|
|||||||
buf.writeBoolean( item.displayName != null );
|
buf.writeBoolean( item.displayName != null );
|
||||||
if ( item.displayName != null )
|
if ( item.displayName != null )
|
||||||
{
|
{
|
||||||
DefinedPacket.writeString( item.displayName, buf );
|
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 )
|
||||||
{
|
{
|
||||||
@ -95,7 +96,7 @@ public class PlayerListItem extends DefinedPacket
|
|||||||
buf.writeBoolean( item.displayName != null );
|
buf.writeBoolean( item.displayName != null );
|
||||||
if ( item.displayName != null )
|
if ( item.displayName != null )
|
||||||
{
|
{
|
||||||
DefinedPacket.writeString( item.displayName, buf );
|
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -142,7 +143,7 @@ public class PlayerListItem extends DefinedPacket
|
|||||||
Integer ping;
|
Integer ping;
|
||||||
|
|
||||||
// ADD_PLAYER & UPDATE_DISPLAY_NAME
|
// ADD_PLAYER & UPDATE_DISPLAY_NAME
|
||||||
String displayName;
|
BaseComponent displayName;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class PlayerListItemUpdate extends DefinedPacket
|
|||||||
case UPDATE_DISPLAY_NAME:
|
case UPDATE_DISPLAY_NAME:
|
||||||
if ( buf.readBoolean() )
|
if ( buf.readBoolean() )
|
||||||
{
|
{
|
||||||
item.displayName = DefinedPacket.readString( buf );
|
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ public class PlayerListItemUpdate extends DefinedPacket
|
|||||||
buf.writeBoolean( item.displayName != null );
|
buf.writeBoolean( item.displayName != null );
|
||||||
if ( item.displayName != null )
|
if ( item.displayName != null )
|
||||||
{
|
{
|
||||||
DefinedPacket.writeString( item.displayName, buf );
|
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ 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.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -18,7 +19,7 @@ public class ScoreboardObjective extends DefinedPacket
|
|||||||
{
|
{
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String value;
|
private BaseComponent value;
|
||||||
private HealthDisplay type;
|
private HealthDisplay type;
|
||||||
/**
|
/**
|
||||||
* 0 to create, 1 to remove, 2 to update display text.
|
* 0 to create, 1 to remove, 2 to update display text.
|
||||||
@ -32,7 +33,7 @@ public class ScoreboardObjective extends DefinedPacket
|
|||||||
action = buf.readByte();
|
action = buf.readByte();
|
||||||
if ( action == 0 || action == 2 )
|
if ( action == 0 || action == 2 )
|
||||||
{
|
{
|
||||||
value = readString( buf );
|
value = readBaseComponent( buf, protocolVersion );
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
||||||
{
|
{
|
||||||
type = HealthDisplay.values()[readVarInt( buf )];
|
type = HealthDisplay.values()[readVarInt( buf )];
|
||||||
@ -50,7 +51,7 @@ public class ScoreboardObjective extends DefinedPacket
|
|||||||
buf.writeByte( action );
|
buf.writeByte( action );
|
||||||
if ( action == 0 || action == 2 )
|
if ( action == 0 || action == 2 )
|
||||||
{
|
{
|
||||||
writeString( value, buf );
|
writeBaseComponent( value, buf, protocolVersion );
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
||||||
{
|
{
|
||||||
writeVarInt( type.ordinal(), buf );
|
writeVarInt( type.ordinal(), buf );
|
||||||
|
@ -5,6 +5,7 @@ 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.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -16,7 +17,7 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
|||||||
public class ServerData extends DefinedPacket
|
public class ServerData extends DefinedPacket
|
||||||
{
|
{
|
||||||
|
|
||||||
private String motd;
|
private BaseComponent motd;
|
||||||
private Object icon;
|
private Object icon;
|
||||||
private boolean preview;
|
private boolean preview;
|
||||||
private boolean enforceSecure;
|
private boolean enforceSecure;
|
||||||
@ -26,7 +27,7 @@ public class ServerData extends DefinedPacket
|
|||||||
{
|
{
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 || buf.readBoolean() )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 || buf.readBoolean() )
|
||||||
{
|
{
|
||||||
motd = readString( buf, 262144 );
|
motd = readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
if ( buf.readBoolean() )
|
if ( buf.readBoolean() )
|
||||||
{
|
{
|
||||||
@ -59,7 +60,7 @@ public class ServerData extends DefinedPacket
|
|||||||
{
|
{
|
||||||
buf.writeBoolean( true );
|
buf.writeBoolean( true );
|
||||||
}
|
}
|
||||||
writeString( motd, buf, 262144 );
|
writeBaseComponent( motd, buf, protocolVersion );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 )
|
||||||
|
@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -14,18 +15,18 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
|||||||
public class Subtitle extends DefinedPacket
|
public class Subtitle extends DefinedPacket
|
||||||
{
|
{
|
||||||
|
|
||||||
private String text;
|
private BaseComponent text;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
text = readString( buf );
|
text = readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
writeString( text, buf );
|
writeBaseComponent( text, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,6 +6,7 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -17,20 +18,20 @@ import net.md_5.bungee.protocol.ProtocolConstants;
|
|||||||
public class SystemChat extends DefinedPacket
|
public class SystemChat extends DefinedPacket
|
||||||
{
|
{
|
||||||
|
|
||||||
private String message;
|
private BaseComponent message;
|
||||||
private int position;
|
private int position;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
message = readString( buf, 262144 );
|
message = readBaseComponent( buf, protocolVersion );
|
||||||
position = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 ) ? ( ( buf.readBoolean() ) ? ChatMessageType.ACTION_BAR.ordinal() : 0 ) : readVarInt( buf );
|
position = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 ) ? ( ( buf.readBoolean() ) ? ChatMessageType.ACTION_BAR.ordinal() : 0 ) : readVarInt( buf );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||||
{
|
{
|
||||||
writeString( message, buf, 262144 );
|
writeBaseComponent( message, buf, protocolVersion );
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
|
||||||
{
|
{
|
||||||
buf.writeBoolean( position == ChatMessageType.ACTION_BAR.ordinal() );
|
buf.writeBoolean( position == ChatMessageType.ACTION_BAR.ordinal() );
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.md_5.bungee.protocol.packet;
|
package net.md_5.bungee.protocol.packet;
|
||||||
|
|
||||||
import com.mojang.brigadier.LiteralMessage;
|
import com.mojang.brigadier.Message;
|
||||||
import com.mojang.brigadier.context.StringRange;
|
import com.mojang.brigadier.context.StringRange;
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
@ -10,6 +10,7 @@ import java.util.List;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -51,9 +52,9 @@ public class TabCompleteResponse extends DefinedPacket
|
|||||||
for ( int i = 0; i < cnt; i++ )
|
for ( int i = 0; i < cnt; i++ )
|
||||||
{
|
{
|
||||||
String match = readString( buf );
|
String match = readString( buf );
|
||||||
String tooltip = buf.readBoolean() ? readString( buf ) : null;
|
BaseComponent tooltip = buf.readBoolean() ? readBaseComponent( buf, protocolVersion ) : null;
|
||||||
|
|
||||||
matches.add( new Suggestion( range, match, new LiteralMessage( tooltip ) ) );
|
matches.add( new Suggestion( range, match, ( tooltip != null ) ? new ComponentMessage( tooltip ) : null ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
suggestions = new Suggestions( range, matches );
|
suggestions = new Suggestions( range, matches );
|
||||||
@ -76,10 +77,10 @@ public class TabCompleteResponse extends DefinedPacket
|
|||||||
for ( Suggestion suggestion : suggestions.getList() )
|
for ( Suggestion suggestion : suggestions.getList() )
|
||||||
{
|
{
|
||||||
writeString( suggestion.getText(), buf );
|
writeString( suggestion.getText(), buf );
|
||||||
buf.writeBoolean( suggestion.getTooltip() != null && suggestion.getTooltip().getString() != null );
|
buf.writeBoolean( suggestion.getTooltip() != null );
|
||||||
if ( suggestion.getTooltip() != null && suggestion.getTooltip().getString() != null )
|
if ( suggestion.getTooltip() != null )
|
||||||
{
|
{
|
||||||
writeString( suggestion.getTooltip().getString(), buf );
|
writeBaseComponent( ( (ComponentMessage) suggestion.getTooltip() ).getComponent(), buf, protocolVersion );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@ -93,4 +94,17 @@ public class TabCompleteResponse extends DefinedPacket
|
|||||||
{
|
{
|
||||||
handler.handle( this );
|
handler.handle( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class ComponentMessage implements Message
|
||||||
|
{
|
||||||
|
|
||||||
|
private final BaseComponent component;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString()
|
||||||
|
{
|
||||||
|
return component.toPlainText();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ 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.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -21,9 +22,9 @@ public class Team extends DefinedPacket
|
|||||||
* 0 - create, 1 remove, 2 info update, 3 player add, 4 player remove.
|
* 0 - create, 1 remove, 2 info update, 3 player add, 4 player remove.
|
||||||
*/
|
*/
|
||||||
private byte mode;
|
private byte mode;
|
||||||
private String displayName;
|
private BaseComponent displayName;
|
||||||
private String prefix;
|
private BaseComponent prefix;
|
||||||
private String suffix;
|
private BaseComponent suffix;
|
||||||
private String nameTagVisibility;
|
private String nameTagVisibility;
|
||||||
private String collisionRule;
|
private String collisionRule;
|
||||||
private int color;
|
private int color;
|
||||||
@ -48,11 +49,11 @@ public class Team extends DefinedPacket
|
|||||||
mode = buf.readByte();
|
mode = buf.readByte();
|
||||||
if ( mode == 0 || mode == 2 )
|
if ( mode == 0 || mode == 2 )
|
||||||
{
|
{
|
||||||
displayName = readString( buf );
|
displayName = readBaseComponent( buf, protocolVersion );
|
||||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
|
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
|
||||||
{
|
{
|
||||||
prefix = readString( buf );
|
prefix = readBaseComponent( buf, protocolVersion );
|
||||||
suffix = readString( buf );
|
suffix = readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
friendlyFire = buf.readByte();
|
friendlyFire = buf.readByte();
|
||||||
nameTagVisibility = readString( buf );
|
nameTagVisibility = readString( buf );
|
||||||
@ -63,8 +64,8 @@ public class Team extends DefinedPacket
|
|||||||
color = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 ) ? readVarInt( buf ) : buf.readByte();
|
color = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 ) ? readVarInt( buf ) : buf.readByte();
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
||||||
{
|
{
|
||||||
prefix = readString( buf );
|
prefix = readBaseComponent( buf, protocolVersion );
|
||||||
suffix = readString( buf );
|
suffix = readBaseComponent( buf, protocolVersion );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( mode == 0 || mode == 3 || mode == 4 )
|
if ( mode == 0 || mode == 3 || mode == 4 )
|
||||||
@ -85,11 +86,11 @@ public class Team extends DefinedPacket
|
|||||||
buf.writeByte( mode );
|
buf.writeByte( mode );
|
||||||
if ( mode == 0 || mode == 2 )
|
if ( mode == 0 || mode == 2 )
|
||||||
{
|
{
|
||||||
writeString( displayName, buf );
|
writeBaseComponent( displayName, buf, protocolVersion );
|
||||||
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
|
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
|
||||||
{
|
{
|
||||||
writeString( prefix, buf );
|
writeBaseComponent( prefix, buf, protocolVersion );
|
||||||
writeString( suffix, buf );
|
writeBaseComponent( suffix, buf, protocolVersion );
|
||||||
}
|
}
|
||||||
buf.writeByte( friendlyFire );
|
buf.writeByte( friendlyFire );
|
||||||
writeString( nameTagVisibility, buf );
|
writeString( nameTagVisibility, buf );
|
||||||
@ -101,8 +102,8 @@ public class Team extends DefinedPacket
|
|||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
|
||||||
{
|
{
|
||||||
writeVarInt( color, buf );
|
writeVarInt( color, buf );
|
||||||
writeString( prefix, buf );
|
writeBaseComponent( prefix, buf, protocolVersion );
|
||||||
writeString( suffix, buf );
|
writeBaseComponent( suffix, buf, protocolVersion );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
buf.writeByte( color );
|
buf.writeByte( color );
|
||||||
|
@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
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.ProtocolConstants;
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
@ -17,7 +18,7 @@ public class Title extends DefinedPacket
|
|||||||
private Action action;
|
private Action action;
|
||||||
|
|
||||||
// TITLE & SUBTITLE
|
// TITLE & SUBTITLE
|
||||||
private String text;
|
private BaseComponent text;
|
||||||
|
|
||||||
// TIMES
|
// TIMES
|
||||||
private int fadeIn;
|
private int fadeIn;
|
||||||
@ -34,7 +35,7 @@ public class Title extends DefinedPacket
|
|||||||
{
|
{
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_17 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_17 )
|
||||||
{
|
{
|
||||||
text = readString( buf );
|
text = readBaseComponent( buf, protocolVersion );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ public class Title extends DefinedPacket
|
|||||||
case TITLE:
|
case TITLE:
|
||||||
case SUBTITLE:
|
case SUBTITLE:
|
||||||
case ACTIONBAR:
|
case ACTIONBAR:
|
||||||
text = readString( buf );
|
text = readBaseComponent( buf, protocolVersion );
|
||||||
break;
|
break;
|
||||||
case TIMES:
|
case TIMES:
|
||||||
fadeIn = buf.readInt();
|
fadeIn = buf.readInt();
|
||||||
@ -67,7 +68,7 @@ public class Title extends DefinedPacket
|
|||||||
{
|
{
|
||||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_17 )
|
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_17 )
|
||||||
{
|
{
|
||||||
writeString( text, buf );
|
writeBaseComponent( text, buf, protocolVersion );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ public class Title extends DefinedPacket
|
|||||||
case TITLE:
|
case TITLE:
|
||||||
case SUBTITLE:
|
case SUBTITLE:
|
||||||
case ACTIONBAR:
|
case ACTIONBAR:
|
||||||
writeString( text, buf );
|
writeBaseComponent( text, buf, protocolVersion );
|
||||||
break;
|
break;
|
||||||
case TIMES:
|
case TIMES:
|
||||||
buf.writeInt( fadeIn );
|
buf.writeInt( fadeIn );
|
||||||
|
@ -3,8 +3,8 @@ package net.md_5.bungee;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import net.md_5.bungee.api.Title;
|
import net.md_5.bungee.api.Title;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
|
||||||
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 net.md_5.bungee.protocol.packet.ClearTitles;
|
import net.md_5.bungee.protocol.packet.ClearTitles;
|
||||||
@ -53,21 +53,14 @@ public class BungeeTitle implements Title
|
|||||||
title = new TitlePacketHolder<>( packet, packet );
|
title = new TitlePacketHolder<>( packet, packet );
|
||||||
}
|
}
|
||||||
|
|
||||||
title.oldPacket.setText( ComponentSerializer.toString( text ) ); // = newPacket
|
title.oldPacket.setText( text ); // = newPacket
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Title title(BaseComponent... text)
|
public Title title(BaseComponent... text)
|
||||||
{
|
{
|
||||||
if ( title == null )
|
return title( TextComponent.fromArray( text ) );
|
||||||
{
|
|
||||||
net.md_5.bungee.protocol.packet.Title packet = new net.md_5.bungee.protocol.packet.Title( Action.TITLE );
|
|
||||||
title = new TitlePacketHolder<>( packet, packet );
|
|
||||||
}
|
|
||||||
|
|
||||||
title.oldPacket.setText( ComponentSerializer.toString( text ) ); // = newPacket
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -78,24 +71,15 @@ public class BungeeTitle implements Title
|
|||||||
subtitle = new TitlePacketHolder<>( new net.md_5.bungee.protocol.packet.Title( Action.SUBTITLE ), new Subtitle() );
|
subtitle = new TitlePacketHolder<>( new net.md_5.bungee.protocol.packet.Title( Action.SUBTITLE ), new Subtitle() );
|
||||||
}
|
}
|
||||||
|
|
||||||
String serialized = ComponentSerializer.toString( text );
|
subtitle.oldPacket.setText( text );
|
||||||
subtitle.oldPacket.setText( serialized );
|
subtitle.newPacket.setText( text );
|
||||||
subtitle.newPacket.setText( serialized );
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Title subTitle(BaseComponent... text)
|
public Title subTitle(BaseComponent... text)
|
||||||
{
|
{
|
||||||
if ( subtitle == null )
|
return subTitle( TextComponent.fromArray( text ) );
|
||||||
{
|
|
||||||
subtitle = new TitlePacketHolder<>( new net.md_5.bungee.protocol.packet.Title( Action.SUBTITLE ), new Subtitle() );
|
|
||||||
}
|
|
||||||
|
|
||||||
String serialized = ComponentSerializer.toString( text );
|
|
||||||
subtitle.oldPacket.setText( serialized );
|
|
||||||
subtitle.newPacket.setText( serialized );
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -14,6 +14,7 @@ import lombok.Getter;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||||
@ -278,7 +279,7 @@ public class ServerConnector extends PacketHandler
|
|||||||
Scoreboard serverScoreboard = user.getServerSentScoreboard();
|
Scoreboard serverScoreboard = user.getServerSentScoreboard();
|
||||||
for ( Objective objective : serverScoreboard.getObjectives() )
|
for ( Objective objective : serverScoreboard.getObjectives() )
|
||||||
{
|
{
|
||||||
user.unsafe().sendPacket( new ScoreboardObjective( objective.getName(), objective.getValue(), ScoreboardObjective.HealthDisplay.fromString( objective.getType() ), (byte) 1 ) );
|
user.unsafe().sendPacket( new ScoreboardObjective( objective.getName(), ComponentSerializer.deserialize( objective.getValue() ), ScoreboardObjective.HealthDisplay.fromString( objective.getType() ), (byte) 1 ) );
|
||||||
}
|
}
|
||||||
for ( Score score : serverScoreboard.getScores() )
|
for ( Score score : serverScoreboard.getScores() )
|
||||||
{
|
{
|
||||||
@ -383,7 +384,10 @@ public class ServerConnector extends PacketHandler
|
|||||||
public void handle(Kick kick) throws Exception
|
public void handle(Kick kick) throws Exception
|
||||||
{
|
{
|
||||||
ServerInfo def = user.updateAndGetNextServer( target );
|
ServerInfo def = user.updateAndGetNextServer( target );
|
||||||
ServerKickEvent event = new ServerKickEvent( user, target, ComponentSerializer.parse( kick.getMessage() ), def, ServerKickEvent.State.CONNECTING );
|
ServerKickEvent event = new ServerKickEvent( user, target, new BaseComponent[]
|
||||||
|
{
|
||||||
|
kick.getMessage()
|
||||||
|
}, def, ServerKickEvent.State.CONNECTING );
|
||||||
if ( event.getKickReason().toLowerCase( Locale.ROOT ).contains( "outdated" ) && def != null )
|
if ( event.getKickReason().toLowerCase( Locale.ROOT ).contains( "outdated" ) && def != null )
|
||||||
{
|
{
|
||||||
// Pre cancel the event if we are going to try another server
|
// Pre cancel the event if we are going to try another server
|
||||||
|
@ -406,13 +406,13 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void disconnect(String reason)
|
public void disconnect(String reason)
|
||||||
{
|
{
|
||||||
disconnect0( TextComponent.fromLegacyText( reason ) );
|
disconnect( TextComponent.fromLegacyText( reason ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnect(BaseComponent... reason)
|
public void disconnect(BaseComponent... reason)
|
||||||
{
|
{
|
||||||
disconnect0( reason );
|
disconnect( TextComponent.fromArray( reason ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -421,7 +421,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
disconnect0( reason );
|
disconnect0( reason );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect0(final BaseComponent... reason)
|
public void disconnect0(final BaseComponent reason)
|
||||||
{
|
{
|
||||||
if ( !ch.isClosing() )
|
if ( !ch.isClosing() )
|
||||||
{
|
{
|
||||||
@ -430,7 +430,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
getName(), BaseComponent.toLegacyText( reason )
|
getName(), BaseComponent.toLegacyText( reason )
|
||||||
} );
|
} );
|
||||||
|
|
||||||
ch.close( new Kick( ComponentSerializer.toString( reason ) ) );
|
ch.close( new Kick( reason ) );
|
||||||
|
|
||||||
if ( server != null )
|
if ( server != null )
|
||||||
{
|
{
|
||||||
@ -481,7 +481,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void sendMessage(ChatMessageType position, BaseComponent... message)
|
public void sendMessage(ChatMessageType position, BaseComponent... message)
|
||||||
{
|
{
|
||||||
sendMessage( position, null, message );
|
sendMessage( position, null, TextComponent.fromArray( message ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -493,7 +493,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void sendMessage(UUID sender, BaseComponent... message)
|
public void sendMessage(UUID sender, BaseComponent... message)
|
||||||
{
|
{
|
||||||
sendMessage( ChatMessageType.CHAT, sender, message );
|
sendMessage( ChatMessageType.CHAT, sender, TextComponent.fromArray( message ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -502,8 +502,28 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
sendMessage( ChatMessageType.CHAT, sender, message );
|
sendMessage( ChatMessageType.CHAT, sender, message );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage(ChatMessageType position, UUID sender, String message)
|
private void sendMessage(ChatMessageType position, UUID sender, BaseComponent message)
|
||||||
{
|
{
|
||||||
|
// transform score components
|
||||||
|
message = ChatComponentTransformer.getInstance().transform( this, true, message );
|
||||||
|
|
||||||
|
if ( position == ChatMessageType.ACTION_BAR && getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_17 )
|
||||||
|
{
|
||||||
|
// Versions older than 1.11 cannot send the Action bar with the new JSON formattings
|
||||||
|
// Fix by converting to a legacy message, see https://bugs.mojang.com/browse/MC-119145
|
||||||
|
if ( getPendingConnection().getVersion() <= ProtocolConstants.MINECRAFT_1_10 )
|
||||||
|
{
|
||||||
|
message = new TextComponent( BaseComponent.toLegacyText( message ) );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
net.md_5.bungee.protocol.packet.Title title = new net.md_5.bungee.protocol.packet.Title();
|
||||||
|
title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR );
|
||||||
|
title.setText( message );
|
||||||
|
sendPacketQueued( title );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_19 )
|
if ( getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_19 )
|
||||||
{
|
{
|
||||||
// Align with Spigot and remove client side formatting for now
|
// Align with Spigot and remove client side formatting for now
|
||||||
@ -515,32 +535,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
sendPacketQueued( new SystemChat( message, position.ordinal() ) );
|
sendPacketQueued( new SystemChat( message, position.ordinal() ) );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
sendPacketQueued( new Chat( message, (byte) position.ordinal(), sender ) );
|
sendPacketQueued( new Chat( ComponentSerializer.toString( message ), (byte) position.ordinal(), sender ) );
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessage(ChatMessageType position, UUID sender, BaseComponent... message)
|
|
||||||
{
|
|
||||||
// transform score components
|
|
||||||
message = ChatComponentTransformer.getInstance().transform( this, true, message );
|
|
||||||
|
|
||||||
if ( position == ChatMessageType.ACTION_BAR && getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_17 )
|
|
||||||
{
|
|
||||||
// Versions older than 1.11 cannot send the Action bar with the new JSON formattings
|
|
||||||
// Fix by converting to a legacy message, see https://bugs.mojang.com/browse/MC-119145
|
|
||||||
if ( getPendingConnection().getVersion() <= ProtocolConstants.MINECRAFT_1_10 )
|
|
||||||
{
|
|
||||||
sendMessage( position, sender, ComponentSerializer.toString( new TextComponent( BaseComponent.toLegacyText( message ) ) ) );
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
net.md_5.bungee.protocol.packet.Title title = new net.md_5.bungee.protocol.packet.Title();
|
|
||||||
title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR );
|
|
||||||
title.setText( ComponentSerializer.toString( message ) );
|
|
||||||
sendPacketQueued( title );
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
sendMessage( position, sender, ComponentSerializer.toString( message ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,25 +715,19 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
@Override
|
@Override
|
||||||
public void setTabHeader(BaseComponent header, BaseComponent footer)
|
public void setTabHeader(BaseComponent header, BaseComponent footer)
|
||||||
{
|
{
|
||||||
header = ChatComponentTransformer.getInstance().transform( this, true, header )[0];
|
header = ChatComponentTransformer.getInstance().transform( this, true, header );
|
||||||
footer = ChatComponentTransformer.getInstance().transform( this, true, footer )[0];
|
footer = ChatComponentTransformer.getInstance().transform( this, true, footer );
|
||||||
|
|
||||||
sendPacketQueued( new PlayerListHeaderFooter(
|
sendPacketQueued( new PlayerListHeaderFooter(
|
||||||
ComponentSerializer.toString( header ),
|
header,
|
||||||
ComponentSerializer.toString( footer )
|
footer
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTabHeader(BaseComponent[] header, BaseComponent[] footer)
|
public void setTabHeader(BaseComponent[] header, BaseComponent[] footer)
|
||||||
{
|
{
|
||||||
header = ChatComponentTransformer.getInstance().transform( this, true, header );
|
setTabHeader( TextComponent.fromArray( header ), TextComponent.fromArray( footer ) );
|
||||||
footer = ChatComponentTransformer.getInstance().transform( this, true, footer );
|
|
||||||
|
|
||||||
sendPacketQueued( new PlayerListHeaderFooter(
|
|
||||||
ComponentSerializer.toString( header ),
|
|
||||||
ComponentSerializer.toString( footer )
|
|
||||||
) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -183,7 +183,7 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
switch ( objective.getAction() )
|
switch ( objective.getAction() )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
serverScoreboard.addObjective( new Objective( objective.getName(), objective.getValue(), objective.getType().toString() ) );
|
serverScoreboard.addObjective( new Objective( objective.getName(), ComponentSerializer.toString( objective.getValue() ), objective.getType().toString() ) );
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
serverScoreboard.removeObjective( objective.getName() );
|
serverScoreboard.removeObjective( objective.getName() );
|
||||||
@ -192,7 +192,7 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
Objective oldObjective = serverScoreboard.getObjective( objective.getName() );
|
Objective oldObjective = serverScoreboard.getObjective( objective.getName() );
|
||||||
if ( oldObjective != null )
|
if ( oldObjective != null )
|
||||||
{
|
{
|
||||||
oldObjective.setValue( objective.getValue() );
|
oldObjective.setValue( ComponentSerializer.toString( objective.getValue() ) );
|
||||||
oldObjective.setType( objective.getType().toString() );
|
oldObjective.setType( objective.getType().toString() );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -254,9 +254,9 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
{
|
{
|
||||||
if ( team.getMode() == 0 || team.getMode() == 2 )
|
if ( team.getMode() == 0 || team.getMode() == 2 )
|
||||||
{
|
{
|
||||||
t.setDisplayName( team.getDisplayName() );
|
t.setDisplayName( ComponentSerializer.toString( team.getDisplayName() ) );
|
||||||
t.setPrefix( team.getPrefix() );
|
t.setPrefix( ComponentSerializer.toString( team.getPrefix() ) );
|
||||||
t.setSuffix( team.getSuffix() );
|
t.setSuffix( ComponentSerializer.toString( team.getSuffix() ) );
|
||||||
t.setFriendlyFire( team.getFriendlyFire() );
|
t.setFriendlyFire( team.getFriendlyFire() );
|
||||||
t.setNameTagVisibility( team.getNameTagVisibility() );
|
t.setNameTagVisibility( team.getNameTagVisibility() );
|
||||||
t.setCollisionRule( team.getCollisionRule() );
|
t.setCollisionRule( team.getCollisionRule() );
|
||||||
@ -620,13 +620,16 @@ public class DownstreamBridge extends PacketHandler
|
|||||||
public void handle(Kick kick) throws Exception
|
public void handle(Kick kick) throws Exception
|
||||||
{
|
{
|
||||||
ServerInfo def = con.updateAndGetNextServer( server.getInfo() );
|
ServerInfo def = con.updateAndGetNextServer( server.getInfo() );
|
||||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, server.getInfo(), ComponentSerializer.parse( kick.getMessage() ), def, ServerKickEvent.State.CONNECTED ) );
|
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, server.getInfo(), new BaseComponent[]
|
||||||
|
{
|
||||||
|
kick.getMessage()
|
||||||
|
}, def, ServerKickEvent.State.CONNECTED ) );
|
||||||
if ( event.isCancelled() && event.getCancelServer() != null )
|
if ( event.isCancelled() && event.getCancelServer() != null )
|
||||||
{
|
{
|
||||||
con.connectNow( event.getCancelServer(), ServerConnectEvent.Reason.KICK_REDIRECT );
|
con.connectNow( event.getCancelServer(), ServerConnectEvent.Reason.KICK_REDIRECT );
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
con.disconnect0( event.getKickReasonComponent() ); // TODO: Prefix our own stuff.
|
con.disconnect( event.getKickReasonComponent() ); // TODO: Prefix our own stuff.
|
||||||
}
|
}
|
||||||
server.setObsolete( true );
|
server.setObsolete( true );
|
||||||
throw CancelSendSignal.INSTANCE;
|
throw CancelSendSignal.INSTANCE;
|
||||||
|
@ -39,7 +39,6 @@ import net.md_5.bungee.api.event.PostLoginEvent;
|
|||||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
|
||||||
import net.md_5.bungee.http.HttpClient;
|
import net.md_5.bungee.http.HttpClient;
|
||||||
import net.md_5.bungee.jni.cipher.BungeeCipher;
|
import net.md_5.bungee.jni.cipher.BungeeCipher;
|
||||||
import net.md_5.bungee.netty.ChannelWrapper;
|
import net.md_5.bungee.netty.ChannelWrapper;
|
||||||
@ -656,22 +655,19 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
@Override
|
@Override
|
||||||
public void disconnect(final BaseComponent... reason)
|
public void disconnect(final BaseComponent... reason)
|
||||||
{
|
{
|
||||||
if ( canSendKickMessage() )
|
disconnect( TextComponent.fromArray( reason ) );
|
||||||
{
|
|
||||||
ch.delayedClose( new Kick( ComponentSerializer.toString( reason ) ) );
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
ch.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnect(BaseComponent reason)
|
public void disconnect(BaseComponent reason)
|
||||||
{
|
{
|
||||||
disconnect( new BaseComponent[]
|
if ( canSendKickMessage() )
|
||||||
{
|
{
|
||||||
reason
|
ch.delayedClose( new Kick( reason ) );
|
||||||
} );
|
} else
|
||||||
|
{
|
||||||
|
ch.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,6 +84,8 @@ public abstract class EntityMap
|
|||||||
return EntityMap_1_16_2.INSTANCE_1_19_4;
|
return EntityMap_1_16_2.INSTANCE_1_19_4;
|
||||||
case ProtocolConstants.MINECRAFT_1_20_2:
|
case ProtocolConstants.MINECRAFT_1_20_2:
|
||||||
return EntityMap_1_16_2.INSTANCE_1_20_2;
|
return EntityMap_1_16_2.INSTANCE_1_20_2;
|
||||||
|
case ProtocolConstants.MINECRAFT_1_20_3:
|
||||||
|
return EntityMap_1_16_2.INSTANCE_1_20_3;
|
||||||
}
|
}
|
||||||
throw new RuntimeException( "Version " + version + " has no entity map" );
|
throw new RuntimeException( "Version " + version + " has no entity map" );
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ class EntityMap_1_16_2 extends EntityMap
|
|||||||
static final EntityMap_1_16_2 INSTANCE_1_19_1 = new EntityMap_1_16_2( 0x02, 0x30 );
|
static final EntityMap_1_16_2 INSTANCE_1_19_1 = new EntityMap_1_16_2( 0x02, 0x30 );
|
||||||
static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 );
|
static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 );
|
||||||
static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 );
|
static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 );
|
||||||
|
static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 );
|
||||||
//
|
//
|
||||||
private final int spawnPlayerId;
|
private final int spawnPlayerId;
|
||||||
private final int spectateId;
|
private final int spectateId;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package net.md_5.bungee.util;
|
package net.md_5.bungee.util;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
@ -34,16 +34,13 @@ public final class ChatComponentTransformer
|
|||||||
*/
|
*/
|
||||||
private static final Pattern SELECTOR_PATTERN = Pattern.compile( "^@([pares])(?:\\[([^ ]*)\\])?$" );
|
private static final Pattern SELECTOR_PATTERN = Pattern.compile( "^@([pares])(?:\\[([^ ]*)\\])?$" );
|
||||||
|
|
||||||
public BaseComponent[] legacyHoverTransform(ProxiedPlayer player, BaseComponent... components)
|
public BaseComponent legacyHoverTransform(ProxiedPlayer player, BaseComponent next)
|
||||||
{
|
{
|
||||||
if ( player.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_16 )
|
if ( player.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_16 )
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < components.length; i++ )
|
|
||||||
{
|
|
||||||
BaseComponent next = components[i];
|
|
||||||
if ( next.getHoverEvent() == null || next.getHoverEvent().isLegacy() )
|
if ( next.getHoverEvent() == null || next.getHoverEvent().isLegacy() )
|
||||||
{
|
{
|
||||||
continue;
|
return next;
|
||||||
}
|
}
|
||||||
next = next.duplicate();
|
next = next.duplicate();
|
||||||
next.getHoverEvent().setLegacy( true );
|
next.getHoverEvent().setLegacy( true );
|
||||||
@ -53,11 +50,9 @@ public final class ChatComponentTransformer
|
|||||||
next.getHoverEvent().getContents().clear();
|
next.getHoverEvent().getContents().clear();
|
||||||
next.getHoverEvent().getContents().add( exception );
|
next.getHoverEvent().getContents().add( exception );
|
||||||
}
|
}
|
||||||
components[i] = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return components;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChatComponentTransformer getInstance()
|
public static ChatComponentTransformer getInstance()
|
||||||
@ -77,7 +72,7 @@ public final class ChatComponentTransformer
|
|||||||
* TextComponent if the components are null or empty
|
* TextComponent if the components are null or empty
|
||||||
* @throws IllegalArgumentException if an entity selector pattern is present
|
* @throws IllegalArgumentException if an entity selector pattern is present
|
||||||
*/
|
*/
|
||||||
public BaseComponent[] transform(ProxiedPlayer player, BaseComponent... components)
|
public BaseComponent transform(ProxiedPlayer player, BaseComponent components)
|
||||||
{
|
{
|
||||||
return transform( player, false, components );
|
return transform( player, false, components );
|
||||||
}
|
}
|
||||||
@ -91,31 +86,26 @@ public final class ChatComponentTransformer
|
|||||||
* @param player player
|
* @param player player
|
||||||
* @param transformHover if the hover event should replace contents with
|
* @param transformHover if the hover event should replace contents with
|
||||||
* value
|
* value
|
||||||
* @param components the component to transform
|
* @param root the component to transform
|
||||||
* @return the transformed component, or an array containing a single empty
|
* @return the transformed component, or an array containing a single empty
|
||||||
* TextComponent if the components are null or empty
|
* TextComponent if the components are null or empty
|
||||||
* @throws IllegalArgumentException if an entity selector pattern is present
|
* @throws IllegalArgumentException if an entity selector pattern is present
|
||||||
*/
|
*/
|
||||||
public BaseComponent[] transform(ProxiedPlayer player, boolean transformHover, BaseComponent... components)
|
public BaseComponent transform(ProxiedPlayer player, boolean transformHover, BaseComponent root)
|
||||||
{
|
{
|
||||||
if ( components == null || components.length < 1 || ( components.length == 1 && components[0] == null ) )
|
if ( root == null )
|
||||||
{
|
{
|
||||||
return new BaseComponent[]
|
return new TextComponent( "" );
|
||||||
{
|
|
||||||
new TextComponent( "" )
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( transformHover )
|
if ( transformHover )
|
||||||
{
|
{
|
||||||
components = legacyHoverTransform( player, components );
|
root = legacyHoverTransform( player, root );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( BaseComponent root : components )
|
|
||||||
{
|
|
||||||
if ( root.getExtra() != null && !root.getExtra().isEmpty() )
|
if ( root.getExtra() != null && !root.getExtra().isEmpty() )
|
||||||
{
|
{
|
||||||
List<BaseComponent> list = Lists.newArrayList( transform( player, transformHover, root.getExtra().toArray( new BaseComponent[ 0 ] ) ) );
|
List<BaseComponent> list = root.getExtra().stream().map( (extra) -> transform( player, transformHover, extra ) ).collect( Collectors.toList() );
|
||||||
root.setExtra( list );
|
root.setExtra( list );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +113,8 @@ public final class ChatComponentTransformer
|
|||||||
{
|
{
|
||||||
transformScoreComponent( player, (ScoreComponent) root );
|
transformScoreComponent( player, (ScoreComponent) root );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return components;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user