Compare commits

..

23 Commits

Author SHA1 Message Date
md_5
231024ba42
Relax chat parsing to treat bytes as booleans to allow formatting read from NBT 2023-12-06 21:55:56 +11:00
md_5
8ce7a7f8b6
Minecraft 1.20.3 support 2023-12-06 03:40:00 +11:00
md_5
e1462ccdd1
Minecraft 1.20.3-rc1 support 2023-12-04 19:02:45 +11:00
md_5
70f346c1dc
Fix extra write in ScoreboardScore packet 2023-11-26 08:12:30 +11:00
md_5
197bf13a28
Minecraft 1.20.3-pre2 support 2023-11-25 17:02:40 +11:00
md_5
0925c06f9b
#3563: Correct max string length for reading SystemChat packets 2023-11-13 20:09:48 +13:00
Parker Hawke
16298a75f2
#3558: Add Translatable interface for fluid creation of TranslatableComponents 2023-11-10 07:03:46 +11:00
md_5
39b10c0b16
Minecraft 23w45a support 2023-11-09 19:33:11 +11:00
dependabot[bot]
bd8d114992
#3561: Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.0 to 3.6.2
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 20:17:54 +11:00
dependabot[bot]
30e12c6fe0
#3560: Bump org.junit.jupiter:junit-jupiter from 5.10.0 to 5.10.1
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 20:17:20 +11:00
md_5
bd009ca52d
#3559: Fix serialisation of certain scoreboard packets < 1.13 2023-11-06 20:14:57 +11:00
md_5
65d8edf62d
Minecraft 23w44a support 2023-11-06 20:14:55 +11:00
BoomEaro
f5157f12a4
#3438: Fix possible race condition in duplicate player check 2023-11-01 21:32:31 +11:00
BoomEaro
df20effacc
#3557: Replace Guava Charsets with Java StandardCharsets 2023-10-31 21:49:17 +11:00
md_5
c92581d0dc
#3556: Deserialize arrays to single components 2023-10-29 11:30:54 +11:00
Outfluencer
e442c3da5c
#3546: Add string length checks to isValidName 2023-10-28 13:11:55 +11:00
dependabot[bot]
f903c54d55
#3554: Bump org.apache.maven.plugins:maven-checkstyle-plugin
Bumps [org.apache.maven.plugins:maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.3.0 to 3.3.1.
- [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.3.0...maven-checkstyle-plugin-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-28 13:06:40 +11:00
Parker Hawke
0d45378986
#3540: Add TextComponent#fromLegacy() as an array-free alternative to #fromLegacyText() 2023-10-28 13:04:18 +11:00
md_5
0f5f09b6c5
Minecraft 23w43b support 2023-10-28 12:57:19 +11:00
md_5
e5c80d0044
Fix code formatting 2023-10-28 12:57:16 +11:00
md_5
9cdb2ba3ea
Deprecate exposed scoreboard API 2023-10-22 09:25:25 +11:00
dependabot[bot]
d0e5cf7ce5
#3549: Bump io.netty:netty-bom from 4.1.99.Final to 4.1.100.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.99.Final to 4.1.100.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.99.Final...netty-4.1.100.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-21 09:16:02 +11:00
md_5
c8568764f6
Fix writing non-compound root NBT tags 2023-10-14 16:38:11 +11:00
63 changed files with 1211 additions and 339 deletions

View File

@ -105,13 +105,13 @@ public class ServerPing
@Deprecated @Deprecated
public ServerPing(Protocol version, Players players, String description, String favicon) public ServerPing(Protocol version, Players players, String description, String favicon)
{ {
this( version, players, new TextComponent( TextComponent.fromLegacyText( description ) ), favicon == null ? null : Favicon.create( favicon ) ); this( version, players, TextComponent.fromLegacy( description ), favicon == null ? null : Favicon.create( favicon ) );
} }
@Deprecated @Deprecated
public ServerPing(Protocol version, Players players, String description, Favicon favicon) public ServerPing(Protocol version, Players players, String description, Favicon favicon)
{ {
this( version, players, new TextComponent( TextComponent.fromLegacyText( description ) ), favicon ); this( version, players, TextComponent.fromLegacy( description ), favicon );
} }
@Deprecated @Deprecated
@ -139,7 +139,7 @@ public class ServerPing
@Deprecated @Deprecated
public void setDescription(String description) public void setDescription(String description)
{ {
this.description = new TextComponent( TextComponent.fromLegacyText( description ) ); this.description = TextComponent.fromLegacy( description );
} }
@Deprecated @Deprecated

View File

@ -334,6 +334,9 @@ public interface ProxiedPlayer extends Connection, CommandSender
* Get the {@link Scoreboard} that belongs to this player. * Get the {@link Scoreboard} that belongs to this player.
* *
* @return this player's {@link Scoreboard} * @return this player's {@link Scoreboard}
* @deprecated for internal use only, setters will not have the expected
* effect, will not update client state, and may corrupt proxy state
*/ */
@Deprecated
Scoreboard getScoreboard(); Scoreboard getScoreboard();
} }

View File

@ -1,9 +1,7 @@
package net.md_5.bungee.api.event; package net.md_5.bungee.api.event;
import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
@ -27,8 +25,7 @@ public class LoginEvent extends AsyncEvent<LoginEvent> implements Cancellable
/** /**
* Message to use when kicking if this event is canceled. * Message to use when kicking if this event is canceled.
*/ */
@Setter(AccessLevel.NONE) private BaseComponent reason;
private BaseComponent[] cancelReasonComponents;
/** /**
* Connection attempting to login. * Connection attempting to login.
*/ */
@ -42,28 +39,44 @@ public class LoginEvent extends AsyncEvent<LoginEvent> implements Cancellable
/** /**
* @return reason to be displayed * @return reason to be displayed
* @deprecated Use component methods instead. * @deprecated use component methods instead
*/ */
@Deprecated @Deprecated
public String getCancelReason() public String getCancelReason()
{ {
return BaseComponent.toLegacyText( getCancelReasonComponents() ); return TextComponent.toLegacyText( getReason() );
} }
/** /**
* @param cancelReason reason to be displayed * @param cancelReason reason to be displayed
* @deprecated Use * @deprecated use component methods instead
* {@link #setCancelReason(net.md_5.bungee.api.chat.BaseComponent...)}
* instead.
*/ */
@Deprecated @Deprecated
public void setCancelReason(String cancelReason) public void setCancelReason(String cancelReason)
{ {
setCancelReason( TextComponent.fromLegacyText( cancelReason ) ); setReason( TextComponent.fromLegacy( cancelReason ) );
} }
/**
* @return reason to be displayed
* @deprecated use single component methods instead
*/
@Deprecated
public BaseComponent[] getCancelReasonComponents()
{
return new BaseComponent[]
{
getReason()
};
}
/**
* @param cancelReason reason to be displayed
* @deprecated use single component methods instead
*/
@Deprecated
public void setCancelReason(BaseComponent... cancelReason) public void setCancelReason(BaseComponent... cancelReason)
{ {
this.cancelReasonComponents = cancelReason; setReason( TextComponent.fromArray( cancelReason ) );
} }
} }

View File

@ -1,9 +1,7 @@
package net.md_5.bungee.api.event; package net.md_5.bungee.api.event;
import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
@ -32,8 +30,7 @@ public class PreLoginEvent extends AsyncEvent<PreLoginEvent> implements Cancella
/** /**
* Message to use when kicking if this event is canceled. * Message to use when kicking if this event is canceled.
*/ */
@Setter(AccessLevel.NONE) private BaseComponent reason;
private BaseComponent[] cancelReasonComponents;
/** /**
* Connection attempting to login. * Connection attempting to login.
*/ */
@ -47,28 +44,44 @@ public class PreLoginEvent extends AsyncEvent<PreLoginEvent> implements Cancella
/** /**
* @return reason to be displayed * @return reason to be displayed
* @deprecated Use component methods instead. * @deprecated use component methods instead
*/ */
@Deprecated @Deprecated
public String getCancelReason() public String getCancelReason()
{ {
return BaseComponent.toLegacyText( getCancelReasonComponents() ); return BaseComponent.toLegacyText( getReason() );
} }
/** /**
* @param cancelReason reason to be displayed * @param cancelReason reason to be displayed
* @deprecated Use * @deprecated Use component methods instead
* {@link #setCancelReason(net.md_5.bungee.api.chat.BaseComponent...)}
* instead.
*/ */
@Deprecated @Deprecated
public void setCancelReason(String cancelReason) public void setCancelReason(String cancelReason)
{ {
setCancelReason( TextComponent.fromLegacyText( cancelReason ) ); setReason( TextComponent.fromLegacy( cancelReason ) );
} }
/**
* @return reason to be displayed
* @deprecated use single component methods instead
*/
@Deprecated
public BaseComponent[] getCancelReasonComponents()
{
return new BaseComponent[]
{
getReason()
};
}
/**
* @param cancelReason reason to be displayed
* @deprecated use single component methods instead
*/
@Deprecated
public void setCancelReason(BaseComponent... cancelReason) public void setCancelReason(BaseComponent... cancelReason)
{ {
this.cancelReasonComponents = cancelReason; setReason( TextComponent.fromArray( cancelReason ) );
} }
} }

View File

@ -35,7 +35,7 @@ public class ServerKickEvent extends Event implements Cancellable
/** /**
* Kick reason. * Kick reason.
*/ */
private BaseComponent[] kickReasonComponent; private BaseComponent reason;
/** /**
* Server to send player to if this event is cancelled. * Server to send player to if this event is cancelled.
*/ */
@ -63,24 +63,61 @@ public class ServerKickEvent extends Event implements Cancellable
this( player, player.getServer().getInfo(), kickReasonComponent, cancelServer, state ); this( player, player.getServer().getInfo(), kickReasonComponent, cancelServer, state );
} }
@Deprecated
public ServerKickEvent(ProxiedPlayer player, ServerInfo kickedFrom, BaseComponent[] kickReasonComponent, ServerInfo cancelServer, State state) public ServerKickEvent(ProxiedPlayer player, ServerInfo kickedFrom, BaseComponent[] kickReasonComponent, ServerInfo cancelServer, State state)
{
this( player, kickedFrom, TextComponent.fromArray( kickReasonComponent ), cancelServer, state );
}
public ServerKickEvent(ProxiedPlayer player, ServerInfo kickedFrom, BaseComponent reason, ServerInfo cancelServer, State state)
{ {
this.player = player; this.player = player;
this.kickedFrom = kickedFrom; this.kickedFrom = kickedFrom;
this.kickReasonComponent = kickReasonComponent; this.reason = reason;
this.cancelServer = cancelServer; this.cancelServer = cancelServer;
this.state = state; this.state = state;
} }
/**
* @return the kick reason
* @deprecated use component methods instead
*/
@Deprecated @Deprecated
public String getKickReason() public String getKickReason()
{ {
return BaseComponent.toLegacyText( kickReasonComponent ); return BaseComponent.toLegacyText( getReason() );
} }
/**
* @param reason the kick reason
* @deprecated use component methods instead
*/
@Deprecated @Deprecated
public void setKickReason(String reason) public void setKickReason(String reason)
{ {
kickReasonComponent = TextComponent.fromLegacyText( reason ); this.setReason( TextComponent.fromLegacy( reason ) );
}
/**
* @return the kick reason
* @deprecated use single component methods instead
*/
@Deprecated
public BaseComponent[] getKickReasonComponent()
{
return new BaseComponent[]
{
getReason()
};
}
/**
* @param kickReasonComponent the kick reason
* @deprecated use single component methods instead
*/
@Deprecated
public void setKickReasonComponent(BaseComponent[] kickReasonComponent)
{
this.setReason( TextComponent.fromArray( kickReasonComponent ) );
} }
} }

View File

@ -204,6 +204,33 @@ public final class ComponentBuilder
return this; return this;
} }
/**
* Appends the {@link TranslationProvider} object to the builder and makes
* the last element the current target for formatting. The components will
* have all the formatting from previous part.
*
* @param translatable the translatable object to append
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(TranslationProvider translatable)
{
return append( translatable, FormatRetention.ALL );
}
/**
* Appends the {@link TranslationProvider} object to the builder and makes
* the last element the current target for formatting. You can specify the
* amount of formatting retained from previous part.
*
* @param translatable the translatable object to append
* @param retention the formatting to retain
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(TranslationProvider translatable, FormatRetention retention)
{
return append( translatable.asTranslatableComponent(), retention );
}
/** /**
* Appends the text to the builder and makes it the current target for * Appends the text to the builder and makes it the current target for
* formatting. The text will have all the formatting from previous part. * formatting. The text will have all the formatting from previous part.
@ -455,8 +482,8 @@ public final class ComponentBuilder
} }
/** /**
* Returns the component built by this builder. If this builder is * Returns the component built by this builder. If this builder is empty, an
* empty, an empty text component will be returned. * empty text component will be returned.
* *
* @return the component * @return the component
*/ */
@ -478,8 +505,8 @@ public final class ComponentBuilder
* <p> * <p>
* <strong>NOTE:</strong> {@link #build()} is preferred as it will * <strong>NOTE:</strong> {@link #build()} is preferred as it will
* consolidate all components into a single BaseComponent with extra * consolidate all components into a single BaseComponent with extra
* contents as opposed to an array of components which is non-standard * contents as opposed to an array of components which is non-standard and
* and may result in unexpected behavior. * may result in unexpected behavior.
* *
* @return the created components * @return the created components
*/ */

View File

@ -43,7 +43,7 @@ public final class ItemTag
private final int level; private final int level;
private final int id; private final int id;
} }
*/ */
private ItemTag(String nbt) private ItemTag(String nbt)
{ {

View File

@ -2,6 +2,7 @@ package net.md_5.bungee.api.chat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Consumer;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -27,6 +28,41 @@ public final class TextComponent extends BaseComponent
* @param message the text to convert * @param message the text to convert
* @return the components needed to print the message to the client * @return the components needed to print the message to the client
*/ */
public static BaseComponent fromLegacy(String message)
{
return fromLegacy( message, ChatColor.WHITE );
}
/**
* Converts the old formatting system that used
* {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based
* system.
*
* @param message the text to convert
* @param defaultColor color to use when no formatting is to be applied
* (i.e. after ChatColor.RESET).
* @return the components needed to print the message to the client
*/
public static BaseComponent fromLegacy(String message, ChatColor defaultColor)
{
ComponentBuilder componentBuilder = new ComponentBuilder();
populateComponentStructure( message, defaultColor, componentBuilder::append );
return componentBuilder.build();
}
/**
* Converts the old formatting system that used
* {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based
* system.
*
* @param message the text to convert
* @return the components needed to print the message to the client
* @deprecated {@link #fromLegacy(String)} is preferred as it will
* consolidate all components into a single BaseComponent with extra
* contents as opposed to an array of components which is non-standard and
* may result in unexpected behavior.
*/
@Deprecated
public static BaseComponent[] fromLegacyText(String message) public static BaseComponent[] fromLegacyText(String message)
{ {
return fromLegacyText( message, ChatColor.WHITE ); return fromLegacyText( message, ChatColor.WHITE );
@ -41,10 +77,21 @@ public final class TextComponent extends BaseComponent
* @param defaultColor color to use when no formatting is to be applied * @param defaultColor color to use when no formatting is to be applied
* (i.e. after ChatColor.RESET). * (i.e. after ChatColor.RESET).
* @return the components needed to print the message to the client * @return the components needed to print the message to the client
* @deprecated {@link #fromLegacy(String, ChatColor)} is preferred as it
* will consolidate all components into a single BaseComponent with extra
* contents as opposed to an array of components which is non-standard and
* may result in unexpected behavior.
*/ */
@Deprecated
public static BaseComponent[] fromLegacyText(String message, ChatColor defaultColor) public static BaseComponent[] fromLegacyText(String message, ChatColor defaultColor)
{ {
ArrayList<BaseComponent> components = new ArrayList<>(); ArrayList<BaseComponent> components = new ArrayList<>();
populateComponentStructure( message, defaultColor, components::add );
return components.toArray( new BaseComponent[ 0 ] );
}
private static void populateComponentStructure(String message, ChatColor defaultColor, Consumer<BaseComponent> appender)
{
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
TextComponent component = new TextComponent(); TextComponent component = new TextComponent();
Matcher matcher = url.matcher( message ); Matcher matcher = url.matcher( message );
@ -94,7 +141,7 @@ public final class TextComponent extends BaseComponent
component = new TextComponent( old ); component = new TextComponent( old );
old.setText( builder.toString() ); old.setText( builder.toString() );
builder = new StringBuilder(); builder = new StringBuilder();
components.add( old ); appender.accept( old );
} }
if ( format == ChatColor.BOLD ) if ( format == ChatColor.BOLD )
{ {
@ -137,7 +184,7 @@ public final class TextComponent extends BaseComponent
component = new TextComponent( old ); component = new TextComponent( old );
old.setText( builder.toString() ); old.setText( builder.toString() );
builder = new StringBuilder(); builder = new StringBuilder();
components.add( old ); appender.accept( old );
} }
TextComponent old = component; TextComponent old = component;
@ -146,7 +193,7 @@ public final class TextComponent extends BaseComponent
component.setText( urlString ); component.setText( urlString );
component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL, component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL,
urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) ); urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) );
components.add( component ); appender.accept( component );
i += pos - i - 1; i += pos - i - 1;
component = old; component = old;
continue; continue;
@ -155,9 +202,29 @@ public final class TextComponent extends BaseComponent
} }
component.setText( builder.toString() ); component.setText( builder.toString() );
components.add( component ); appender.accept( component );
}
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 );
} }
/** /**

View File

@ -86,6 +86,21 @@ public final class TranslatableComponent extends BaseComponent
} }
} }
/**
* Creates a translatable component with the passed substitutions
*
* @param translatable the translatable object
* @param with the {@link java.lang.String}s and
* {@link net.md_5.bungee.api.chat.BaseComponent}s to use into the
* translation
* @see #translate
* @see #setWith(java.util.List)
*/
public TranslatableComponent(TranslationProvider translatable, Object... with)
{
this( translatable.getTranslationKey(), with );
}
/** /**
* Creates a duplicate of this TranslatableComponent. * Creates a duplicate of this TranslatableComponent.
* *

View File

@ -0,0 +1,38 @@
package net.md_5.bungee.api.chat;
/**
* An object capable of being translated by the client in a
* {@link TranslatableComponent}.
*/
public interface TranslationProvider
{
/**
* Get the translation key.
*
* @return the translation key
*/
String getTranslationKey();
/**
* Get this translatable object as a {@link TranslatableComponent}.
*
* @return the translatable component
*/
default TranslatableComponent asTranslatableComponent()
{
return asTranslatableComponent( (Object[]) null );
}
/**
* Get this translatable object as a {@link TranslatableComponent}.
*
* @param with the {@link String Strings} and
* {@link BaseComponent BaseComponents} to use in the translation
* @return the translatable component
*/
default TranslatableComponent asTranslatableComponent(Object... with)
{
return new TranslatableComponent( this, with );
}
}

View File

@ -26,7 +26,10 @@ public class Text extends Content
public Text(BaseComponent value) public Text(BaseComponent value)
{ {
// For legacy serialization reasons, this has to be an array of components // For legacy serialization reasons, this has to be an array of components
this( new BaseComponent[]{value} ); this( new BaseComponent[]
{
value
} );
} }
public Text(String value) public Text(String value)

View File

@ -5,6 +5,7 @@ import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement; 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.JsonPrimitive;
import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializationContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -20,27 +21,51 @@ import net.md_5.bungee.api.chat.hover.content.Content;
public class BaseComponentSerializer public class BaseComponentSerializer
{ {
private static boolean getAsBoolean(JsonElement el)
{
if ( el.isJsonPrimitive() )
{
JsonPrimitive primitive = (JsonPrimitive) el;
if ( primitive.isBoolean() )
{
return primitive.getAsBoolean();
}
if ( primitive.isNumber() )
{
Number number = primitive.getAsNumber();
if ( number instanceof Byte )
{
return number.byteValue() != 0;
}
}
}
return false;
}
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context) protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context)
{ {
if ( object.has( "bold" ) ) if ( object.has( "bold" ) )
{ {
component.setBold( object.get( "bold" ).getAsBoolean() ); component.setBold( getAsBoolean( object.get( "bold" ) ) );
} }
if ( object.has( "italic" ) ) if ( object.has( "italic" ) )
{ {
component.setItalic( object.get( "italic" ).getAsBoolean() ); component.setItalic( getAsBoolean( object.get( "italic" ) ) );
} }
if ( object.has( "underlined" ) ) if ( object.has( "underlined" ) )
{ {
component.setUnderlined( object.get( "underlined" ).getAsBoolean() ); component.setUnderlined( getAsBoolean( object.get( "underlined" ) ) );
} }
if ( object.has( "strikethrough" ) ) if ( object.has( "strikethrough" ) )
{ {
component.setStrikethrough( object.get( "strikethrough" ).getAsBoolean() ); component.setStrikethrough( getAsBoolean( object.get( "strikethrough" ) ) );
} }
if ( object.has( "obfuscated" ) ) if ( object.has( "obfuscated" ) )
{ {
component.setObfuscated( object.get( "obfuscated" ).getAsBoolean() ); component.setObfuscated( getAsBoolean( object.get( "obfuscated" ) ) );
} }
if ( object.has( "color" ) ) if ( object.has( "color" ) )
{ {

View File

@ -2,12 +2,14 @@ package net.md_5.bungee.chat;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement; 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;
@ -44,16 +46,17 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
/** /**
* Parse a JSON-compliant String as an array of base components. The input * Parse a JSON-compliant String as an array of base components. The input
* can be one of either an array of components, or a single component object. * can be one of either an array of components, or a single component
* If the input is an array, each component will be parsed individually and * object. If the input is an array, each component will be parsed
* returned in the order that they were parsed. If the input is a single * individually and returned in the order that they were parsed. If the
* component object, a single-valued array with the component will be returned. * input is a single component object, a single-valued array with the
* component will be returned.
* <p> * <p>
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it will * <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it
* parse only one component as opposed to an array of components which is non- * will parse only one component as opposed to an array of components which
* standard behavior. This method is still appropriate for parsing multiple * is non- standard behavior. This method is still appropriate for parsing
* components at once, although such use case is rarely (if at all) exhibited * multiple components at once, although such use case is rarely (if at all)
* in vanilla Minecraft. * exhibited in vanilla Minecraft.
* *
* @param json the component json to parse * @param json the component json to parse
* @return an array of all parsed components * @return an array of all parsed components
@ -75,25 +78,51 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
} }
/** /**
* Deserialize a JSON-compliant String as a single component. The input is * Deserialize a JSON-compliant String as a single component.
* expected to be a JSON object that represents only one component.
* *
* @param json the component json to parse * @param json the component json to parse
* @return the deserialized component * @return the deserialized component
* @throws IllegalArgumentException if anything other than a JSON object is * @throws IllegalArgumentException if anything other than a valid JSON
* passed as input * component string is passed as input
*/ */
public static BaseComponent deserialize(String json) public static BaseComponent deserialize(String json)
{ {
JsonElement jsonElement = JsonParser.parseString( json ); JsonElement jsonElement = JsonParser.parseString( json );
if ( !jsonElement.isJsonObject() )
return deserialize( jsonElement );
}
/**
* Deserialize a JSON element as a single component.
*
* @param jsonElement the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component is passed as input
*/
public static BaseComponent deserialize(JsonElement jsonElement)
{
if ( jsonElement instanceof JsonPrimitive )
{ {
throw new IllegalArgumentException( "Malformatted JSON. Expected object, got array for input \"" + json + "\"." ); JsonPrimitive primitive = (JsonPrimitive) jsonElement;
if ( primitive.isString() )
{
return new TextComponent( primitive.getAsString() );
}
} else if ( jsonElement instanceof JsonArray )
{
BaseComponent[] array = gson.fromJson( jsonElement, BaseComponent[].class );
return TextComponent.fromArray( array );
} }
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 );

View File

@ -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;
} }

View File

@ -1,11 +1,11 @@
package net.md_5.bungee.chat; package net.md_5.bungee.chat;
import com.google.common.base.Charsets;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -102,7 +102,7 @@ public final class TranslationRegistry
public JsonProvider(String resourcePath) throws IOException public JsonProvider(String resourcePath) throws IOException
{ {
try ( InputStreamReader rd = new InputStreamReader( JsonProvider.class.getResourceAsStream( resourcePath ), Charsets.UTF_8 ) ) try ( InputStreamReader rd = new InputStreamReader( JsonProvider.class.getResourceAsStream( resourcePath ), StandardCharsets.UTF_8 ) )
{ {
JsonObject obj = new Gson().fromJson( rd, JsonObject.class ); JsonObject obj = new Gson().fromJson( rd, JsonObject.class );
for ( Map.Entry<String, JsonElement> entries : obj.entrySet() ) for ( Map.Entry<String, JsonElement> entries : obj.entrySet() )

View File

@ -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
@ -561,8 +563,7 @@ public class ComponentsTest
this.testBuilder( this.testBuilder(
ComponentBuilder::create, ComponentBuilder::create,
BaseComponent::toPlainText, BaseComponent::toPlainText,
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
BaseComponent::toLegacyText BaseComponent::toLegacyText
); );
} }
@ -574,8 +575,7 @@ public class ComponentsTest
ComponentBuilder::build, ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ), (component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component // An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
(component) -> BaseComponent.toLegacyText( component ) (component) -> BaseComponent.toLegacyText( component )
); );
} }
@ -830,8 +830,8 @@ public class ComponentsTest
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) ); String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );
assertEquals( assertEquals(
"{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"}," "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},"
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}," + "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"
+ "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}", + "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}",
test2 ); test2 );
} }

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.config; package net.md_5.bungee.config;
import com.google.common.base.Charsets;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@ -16,6 +15,7 @@ import java.io.OutputStreamWriter;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import lombok.AccessLevel; import lombok.AccessLevel;
@ -37,7 +37,7 @@ public class JsonConfiguration extends ConfigurationProvider
@Override @Override
public void save(Configuration config, File file) throws IOException public void save(Configuration config, File file) throws IOException
{ {
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) ) try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{ {
save( config, writer ); save( config, writer );
} }
@ -91,7 +91,7 @@ public class JsonConfiguration extends ConfigurationProvider
@Override @Override
public Configuration load(InputStream is, Configuration defaults) public Configuration load(InputStream is, Configuration defaults)
{ {
return load( new InputStreamReader( is, Charsets.UTF_8 ), defaults ); return load( new InputStreamReader( is, StandardCharsets.UTF_8 ), defaults );
} }
@Override @Override

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.config; package net.md_5.bungee.config;
import com.google.common.base.Charsets;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -9,6 +8,7 @@ import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import lombok.AccessLevel; import lombok.AccessLevel;
@ -54,7 +54,7 @@ public class YamlConfiguration extends ConfigurationProvider
@Override @Override
public void save(Configuration config, File file) throws IOException public void save(Configuration config, File file) throws IOException
{ {
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) ) try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{ {
save( config, writer ); save( config, writer );
} }

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.log; package net.md_5.bungee.log;
import com.google.common.base.Charsets;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -19,7 +19,7 @@ public class LoggingOutputStream extends ByteArrayOutputStream
@Override @Override
public void flush() throws IOException public void flush() throws IOException
{ {
String contents = toString( Charsets.UTF_8.name() ); String contents = toString( StandardCharsets.UTF_8.name() );
super.reset(); super.reset();
if ( !contents.isEmpty() && !contents.equals( separator ) ) if ( !contents.isEmpty() && !contents.equals( separator ) )
{ {

View File

@ -41,7 +41,7 @@ public class CommandAlert extends Command
String message = builder.substring( 0, builder.length() - 1 ); String message = builder.substring( 0, builder.length() - 1 );
ProxyServer.getInstance().broadcast( TextComponent.fromLegacyText( message ) ); ProxyServer.getInstance().broadcast( TextComponent.fromLegacy( message ) );
} }
} }
} }

View File

@ -33,18 +33,18 @@ public class CommandKick extends Command implements TabExecutor
if ( player == null ) if ( player == null )
{ {
sender.sendMessage( TextComponent.fromLegacyText( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) ); sender.sendMessage( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) );
return; return;
} }
if ( args.length == 1 ) if ( args.length == 1 )
{ {
player.disconnect( TextComponent.fromLegacyText( ProxyServer.getInstance().getTranslation( "kick_message" ) ) ); player.disconnect( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "kick_message" ) ) );
} else } else
{ {
String[] reason = new String[ args.length - 1 ]; String[] reason = new String[ args.length - 1 ];
System.arraycopy( args, 1, reason, 0, reason.length ); System.arraycopy( args, 1, reason, 0, reason.length );
player.disconnect( TextComponent.fromLegacyText( ChatColor.translateAlternateColorCodes( '&', Joiner.on( ' ' ).join( reason ) ) ) ); player.disconnect( TextComponent.fromLegacy( ChatColor.translateAlternateColorCodes( '&', Joiner.on( ' ' ).join( reason ) ) ) );
} }
} }
} }

View File

@ -83,7 +83,7 @@
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId> <artifactId>netty-bom</artifactId>
<version>4.1.99.Final</version> <version>4.1.100.Final</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -93,7 +93,7 @@
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<version>5.10.0</version> <version>5.10.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -122,7 +122,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.0</version> <version>3.6.2</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
@ -151,7 +151,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId> <artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.0</version> <version>3.3.1</version>
<executions> <executions>
<execution> <execution>
<phase>process-classes</phase> <phase>process-classes</phase>

View File

@ -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>

View File

@ -34,6 +34,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay; import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective; import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore; import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.ServerData; import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression; import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration; import net.md_5.bungee.protocol.packet.StartConfiguration;
@ -143,6 +144,10 @@ public abstract class AbstractPacketHandler
{ {
} }
public void handle(ScoreboardScoreReset scoreboardScoreReset) throws Exception
{
}
public void handle(EncryptionRequest encryptionRequest) throws Exception public void handle(EncryptionRequest encryptionRequest) throws Exception
{ {
} }

View File

@ -1,20 +1,25 @@
package net.md_5.bungee.protocol; package net.md_5.bungee.protocol;
import com.google.common.base.Charsets; import com.google.common.base.Function;
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;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiConsumer;
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;
@ -24,6 +29,23 @@ import se.llbit.nbt.Tag;
public abstract class DefinedPacket public abstract class DefinedPacket
{ {
public <T> T readNullable(Function<ByteBuf, T> reader, ByteBuf buf)
{
return buf.readBoolean() ? reader.apply( buf ) : null;
}
public <T> void writeNullable(T t0, BiConsumer<T, ByteBuf> writer, ByteBuf buf)
{
if ( t0 != null )
{
buf.writeBoolean( true );
writer.accept( t0, buf );
} else
{
buf.writeBoolean( false );
}
}
public static void writeString(String s, ByteBuf buf) public static void writeString(String s, ByteBuf buf)
{ {
writeString( s, buf, Short.MAX_VALUE ); writeString( s, buf, Short.MAX_VALUE );
@ -36,7 +58,7 @@ public abstract class DefinedPacket
throw new OverflowPacketException( "Cannot send string longer than " + maxLength + " (got " + s.length() + " characters)" ); throw new OverflowPacketException( "Cannot send string longer than " + maxLength + " (got " + s.length() + " characters)" );
} }
byte[] b = s.getBytes( Charsets.UTF_8 ); byte[] b = s.getBytes( StandardCharsets.UTF_8 );
if ( b.length > maxLength * 3 ) if ( b.length > maxLength * 3 )
{ {
throw new OverflowPacketException( "Cannot send string longer than " + ( maxLength * 3 ) + " (got " + b.length + " bytes)" ); throw new OverflowPacketException( "Cannot send string longer than " + ( maxLength * 3 ) + " (got " + b.length + " bytes)" );
@ -59,7 +81,7 @@ public abstract class DefinedPacket
throw new OverflowPacketException( "Cannot receive string longer than " + maxLen * 3 + " (got " + len + " bytes)" ); throw new OverflowPacketException( "Cannot receive string longer than " + maxLen * 3 + " (got " + len + " bytes)" );
} }
String s = buf.toString( buf.readerIndex(), len, Charsets.UTF_8 ); String s = buf.toString( buf.readerIndex(), len, StandardCharsets.UTF_8 );
buf.readerIndex( buf.readerIndex() + len ); buf.readerIndex( buf.readerIndex() + len );
if ( s.length() > maxLen ) if ( s.length() > maxLen )
@ -70,6 +92,59 @@ public abstract class DefinedPacket
return s; return s;
} }
public static Either<String, BaseComponent> readEitherBaseComponent(ByteBuf buf, int protocolVersion, boolean string)
{
return ( string ) ? Either.left( readString( buf ) ) : Either.right( readBaseComponent( buf, protocolVersion ) );
}
public static BaseComponent readBaseComponent(ByteBuf buf, int protocolVersion)
{
return readBaseComponent( buf, Short.MAX_VALUE, protocolVersion );
}
public static BaseComponent readBaseComponent(ByteBuf buf, int maxStringLength, 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, maxStringLength );
return ComponentSerializer.deserialize( string );
}
}
public static void writeEitherBaseComponent(Either<String, BaseComponent> message, ByteBuf buf, int protocolVersion)
{
if ( message.isLeft() )
{
writeString( message.getLeft(), buf );
} else
{
writeBaseComponent( message.getRight(), buf, protocolVersion );
}
}
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 )
@ -295,6 +370,38 @@ public abstract class DefinedPacket
return null; return null;
} }
public static void writeNumberFormat(NumberFormat format, ByteBuf buf, int protocolVersion)
{
writeVarInt( format.getType().ordinal(), buf );
switch ( format.getType() )
{
case BLANK:
break;
case STYLED:
writeBaseComponent( (BaseComponent) format.getValue(), buf, protocolVersion ); // TODO: style
break;
case FIXED:
writeBaseComponent( (BaseComponent) format.getValue(), buf, protocolVersion );
break;
}
}
public static NumberFormat readNumberFormat(ByteBuf buf, int protocolVersion)
{
int format = readVarInt( buf );
switch ( format )
{
case 0:
return new NumberFormat( NumberFormat.Type.BLANK, null );
case 1:
return new NumberFormat( NumberFormat.Type.STYLED, readBaseComponent( buf, protocolVersion ) ); // TODO: style
case 2:
return new NumberFormat( NumberFormat.Type.FIXED, readBaseComponent( buf, protocolVersion ) );
default:
throw new IllegalArgumentException( "Unknown number format " + format );
}
}
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 ) );
@ -325,9 +432,18 @@ public abstract class DefinedPacket
public static void writeTag(Tag tag, ByteBuf output, int protocolVersion) public static void writeTag(Tag tag, ByteBuf output, int protocolVersion)
{ {
DataOutputStream out = new DataOutputStream( new ByteBufOutputStream( output ) );
try try
{ {
tag.write( new DataOutputStream( new ByteBufOutputStream( output ) ) ); if ( tag instanceof SpecificTag )
{
SpecificTag specificTag = (SpecificTag) tag;
specificTag.writeType( out );
specificTag.write( out );
} else
{
tag.write( out );
}
} catch ( IOException ex ) } catch ( IOException ex )
{ {
throw new RuntimeException( "Exception writing tag", ex ); throw new RuntimeException( "Exception writing tag", ex );
@ -386,6 +502,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 );
@ -396,6 +517,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 );

View File

@ -0,0 +1,34 @@
package net.md_5.bungee.protocol;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public final class Either<L, R>
{
private final L left;
private final R right;
public boolean isLeft()
{
return this.left != null;
}
public boolean isRight()
{
return this.right != null;
}
public static <L, R> Either<L, R> left(L left)
{
return new Either<>( left, null );
}
public static <L, R> Either<L, R> right(R right)
{
return new Either<>( null, right );
}
}

View File

@ -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() )
{ {

View File

@ -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 );
} }
} }

View File

@ -0,0 +1,18 @@
package net.md_5.bungee.protocol;
import lombok.Data;
@Data
public class NumberFormat
{
private final Type type;
private final Object value;
public enum Type
{
BLANK,
STYLED,
FIXED;
}
}

View File

@ -40,6 +40,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay; import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective; import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore; import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.ServerData; import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression; import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration; import net.md_5.bungee.protocol.packet.StartConfiguration;
@ -134,7 +135,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x3E ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x3E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x3D ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x3D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x45 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
BossBar.class, BossBar.class,
@ -192,7 +194,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x56 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5C )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
ScoreboardScore.class, ScoreboardScore.class,
@ -208,7 +211,13 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x59 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5F )
);
TO_CLIENT.registerPacket(
ScoreboardScoreReset.class,
ScoreboardScoreReset::new,
map( ProtocolConstants.MINECRAFT_1_20_3, 0x42 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
ScoreboardDisplay.class, ScoreboardDisplay.class,
@ -224,7 +233,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4F ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x55 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
Team.class, Team.class,
@ -240,7 +250,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x58 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5E )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
PluginMessage.class, PluginMessage.class,
@ -291,7 +302,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5D ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x63 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
ClearTitles.class, ClearTitles.class,
@ -310,7 +322,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5B ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x61 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
TitleTimes.class, TitleTimes.class,
@ -320,7 +333,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5E ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x5E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x64 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
SystemChat.class, SystemChat.class,
@ -329,7 +343,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x62 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x62 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x69 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
PlayerListHeaderFooter.class, PlayerListHeaderFooter.class,
@ -349,7 +364,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x63 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x63 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x6A )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
EntityStatus.class, EntityStatus.class,
@ -405,7 +421,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4C ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x4C ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
ServerData.class, ServerData.class,
@ -414,7 +431,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x42 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x42 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x49 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
PlayerListItemRemove.class, PlayerListItemRemove.class,
@ -433,7 +451,8 @@ public enum Protocol
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
StartConfiguration.class, StartConfiguration.class,
StartConfiguration::new, StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x67 )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
@ -451,7 +470,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 +537,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,

View File

@ -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 = 765;
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;
@ -101,13 +102,14 @@ public class ProtocolConstants
ProtocolConstants.MINECRAFT_1_19_3, ProtocolConstants.MINECRAFT_1_19_3,
ProtocolConstants.MINECRAFT_1_19_4, ProtocolConstants.MINECRAFT_1_19_4,
ProtocolConstants.MINECRAFT_1_20, ProtocolConstants.MINECRAFT_1_20,
ProtocolConstants.MINECRAFT_1_20_2 ProtocolConstants.MINECRAFT_1_20_2,
ProtocolConstants.MINECRAFT_1_20_3
); );
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();

View 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 );
}
}
}

View File

@ -7,7 +7,8 @@ import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.List; import java.util.List;
/** /**
* Prepend length of the message as a Varint21 using an extra buffer for the length, avoiding copying packet data * Prepend length of the message as a Varint21 using an extra buffer for the
* length, avoiding copying packet data
*/ */
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class Varint21LengthFieldExtraBufPrepender extends MessageToMessageEncoder<ByteBuf> public class Varint21LengthFieldExtraBufPrepender extends MessageToMessageEncoder<ByteBuf>

View File

@ -6,7 +6,8 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
/** /**
* Prepend length of the message as a Varint21 by writing length and data to a new buffer * Prepend length of the message as a Varint21 by writing length and data to a
* new buffer
*/ */
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>

View File

@ -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:

View File

@ -310,6 +310,7 @@ public class Commands extends DefinedPacket
private static final ArgumentSerializer[] IDS_1_19; private static final ArgumentSerializer[] IDS_1_19;
private static final ArgumentSerializer[] IDS_1_19_3; private static final ArgumentSerializer[] IDS_1_19_3;
private static final ArgumentSerializer[] IDS_1_19_4; private static final ArgumentSerializer[] IDS_1_19_4;
private static final ArgumentSerializer[] IDS_1_20_3;
private static final Map<Class<?>, ProperArgumentSerializer<?>> PROPER_PROVIDERS = new HashMap<>(); private static final Map<Class<?>, ProperArgumentSerializer<?>> PROPER_PROVIDERS = new HashMap<>();
// //
private static final ArgumentSerializer<Void> VOID = new ArgumentSerializer<Void>() private static final ArgumentSerializer<Void> VOID = new ArgumentSerializer<Void>()
@ -744,6 +745,60 @@ public class Commands extends DefinedPacket
get( "minecraft:uuid", VOID ), get( "minecraft:uuid", VOID ),
get( "minecraft:heightmap", VOID ) get( "minecraft:heightmap", VOID )
}; };
IDS_1_20_3 = new ArgumentSerializer[]
{
get( "brigadier:bool", VOID ),
get( "brigadier:float", FLOAT_RANGE ),
get( "brigadier:double", DOUBLE_RANGE ),
get( "brigadier:integer", INTEGER_RANGE ),
get( "brigadier:long", LONG_RANGE ),
get( "brigadier:string", STRING ),
get( "minecraft:entity", BYTE ),
get( "minecraft:game_profile", VOID ),
get( "minecraft:block_pos", VOID ),
get( "minecraft:column_pos", VOID ),
get( "minecraft:vec3", VOID ),
get( "minecraft:vec2", VOID ),
get( "minecraft:block_state", VOID ),
get( "minecraft:block_predicate", VOID ),
get( "minecraft:item_stack", VOID ),
get( "minecraft:item_predicate", VOID ),
get( "minecraft:color", VOID ),
get( "minecraft:component", VOID ),
get( "minecraft:style", VOID ),
get( "minecraft:message", VOID ),
get( "minecraft:nbt_compound_tag", VOID ),
get( "minecraft:nbt_tag", VOID ),
get( "minecraft:nbt_path", VOID ),
get( "minecraft:objective", VOID ),
get( "minecraft:objective_criteria", VOID ),
get( "minecraft:operation", VOID ),
get( "minecraft:particle", VOID ),
get( "minecraft:angle", VOID ),
get( "minecraft:rotation", VOID ),
get( "minecraft:scoreboard_slot", VOID ),
get( "minecraft:score_holder", BYTE ),
get( "minecraft:swizzle", VOID ),
get( "minecraft:team", VOID ),
get( "minecraft:item_slot", VOID ),
get( "minecraft:resource_location", VOID ),
get( "minecraft:function", VOID ),
get( "minecraft:entity_anchor", VOID ),
get( "minecraft:int_range", VOID ),
get( "minecraft:float_range", VOID ),
get( "minecraft:dimension", VOID ),
get( "minecraft:gamemode", VOID ),
get( "minecraft:time", INTEGER ),
get( "minecraft:resource_or_tag", RAW_STRING ),
get( "minecraft:resource_or_tag_key", RAW_STRING ),
get( "minecraft:resource", RAW_STRING ),
get( "minecraft:resource_key", RAW_STRING ),
get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ),
get( "minecraft:uuid", VOID ),
get( "minecraft:heightmap", VOID )
};
} }
private static void register(String name, ArgumentSerializer serializer) private static void register(String name, ArgumentSerializer serializer)
@ -765,7 +820,10 @@ public class Commands extends DefinedPacket
{ {
key = readVarInt( buf ); key = readVarInt( buf );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 ) if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
reader = IDS_1_20_3[(Integer) key];
} else if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 )
{ {
reader = IDS_1_19_4[(Integer) key]; reader = IDS_1_19_4[(Integer) key];
} else if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_3 ) } else if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_3 )

View File

@ -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

View File

@ -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

View File

@ -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;
} }
} }

View File

@ -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;
} }

View File

@ -6,8 +6,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.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.Either;
import net.md_5.bungee.protocol.NumberFormat;
import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.ProtocolConstants;
@Data @Data
@ -18,12 +21,13 @@ public class ScoreboardObjective extends DefinedPacket
{ {
private String name; private String name;
private String value; private Either<String, 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.
*/ */
private byte action; private byte action;
private NumberFormat numberFormat;
@Override @Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
@ -32,14 +36,19 @@ public class ScoreboardObjective extends DefinedPacket
action = buf.readByte(); action = buf.readByte();
if ( action == 0 || action == 2 ) if ( action == 0 || action == 2 )
{ {
value = readString( buf );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 ) if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{ {
value = readEitherBaseComponent( buf, protocolVersion, false );
type = HealthDisplay.values()[readVarInt( buf )]; type = HealthDisplay.values()[readVarInt( buf )];
} else } else
{ {
value = readEitherBaseComponent( buf, protocolVersion, true );
type = HealthDisplay.fromString( readString( buf ) ); type = HealthDisplay.fromString( readString( buf ) );
} }
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
numberFormat = readNullable( (b) -> readNumberFormat( b, protocolVersion ), buf );
}
} }
} }
@ -50,7 +59,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 ); writeEitherBaseComponent( value, buf, protocolVersion );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 ) if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{ {
writeVarInt( type.ordinal(), buf ); writeVarInt( type.ordinal(), buf );
@ -58,6 +67,10 @@ public class ScoreboardObjective extends DefinedPacket
{ {
writeString( type.toString(), buf ); writeString( type.toString(), buf );
} }
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
writeNullable( numberFormat, (s, b) -> DefinedPacket.writeNumberFormat( s, b, protocolVersion ), buf );
}
} }
} }

View File

@ -5,8 +5,10 @@ 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.NumberFormat;
import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.ProtocolConstants;
@Data @Data
@ -23,29 +25,50 @@ public class ScoreboardScore extends DefinedPacket
private byte action; private byte action;
private String scoreName; private String scoreName;
private int value; private int value;
private BaseComponent displayName;
private NumberFormat numberFormat;
@Override @Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{ {
itemName = readString( buf ); itemName = readString( buf );
action = buf.readByte(); if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
action = 0;
} else
{
action = buf.readByte();
}
scoreName = readString( buf ); scoreName = readString( buf );
if ( action != 1 ) if ( action != 1 )
{ {
value = readVarInt( buf ); value = readVarInt( buf );
} }
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
displayName = readNullable( (b) -> readBaseComponent( b, protocolVersion ), buf );
numberFormat = readNullable( (b) -> readNumberFormat( b, protocolVersion ), buf );
}
} }
@Override @Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{ {
writeString( itemName, buf ); writeString( itemName, buf );
buf.writeByte( action ); if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_3 )
{
buf.writeByte( action );
}
writeString( scoreName, buf ); writeString( scoreName, buf );
if ( action != 1 ) if ( action != 1 || protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{ {
writeVarInt( value, buf ); writeVarInt( value, buf );
} }
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
writeNullable( displayName, (s, b) -> DefinedPacket.writeBaseComponent( s, b, protocolVersion ), buf );
writeNullable( numberFormat, (s, b) -> DefinedPacket.writeNumberFormat( s, b, protocolVersion ), buf );
}
} }
@Override @Override

View File

@ -0,0 +1,41 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class ScoreboardScoreReset extends DefinedPacket
{
private String itemName;
private String scoreName;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
itemName = readString( buf );
scoreName = readNullable( DefinedPacket::readString, buf );
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( itemName, buf );
writeNullable( scoreName, DefinedPacket::writeString, buf );
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -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 )

View File

@ -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

View File

@ -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, 262144, 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() );

View File

@ -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();
}
}
} }

View File

@ -5,8 +5,10 @@ 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.Either;
import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.ProtocolConstants;
@Data @Data
@ -21,9 +23,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 Either<String, BaseComponent> displayName;
private String prefix; private Either<String, BaseComponent> prefix;
private String suffix; private Either<String, BaseComponent> suffix;
private String nameTagVisibility; private String nameTagVisibility;
private String collisionRule; private String collisionRule;
private int color; private int color;
@ -48,11 +50,14 @@ public class Team extends DefinedPacket
mode = buf.readByte(); mode = buf.readByte();
if ( mode == 0 || mode == 2 ) if ( mode == 0 || mode == 2 )
{ {
displayName = readString( buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 ) if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
{ {
prefix = readString( buf ); displayName = readEitherBaseComponent( buf, protocolVersion, true );
suffix = readString( buf ); prefix = readEitherBaseComponent( buf, protocolVersion, true );
suffix = readEitherBaseComponent( buf, protocolVersion, true );
} else
{
displayName = readEitherBaseComponent( buf, protocolVersion, false );
} }
friendlyFire = buf.readByte(); friendlyFire = buf.readByte();
nameTagVisibility = readString( buf ); nameTagVisibility = readString( buf );
@ -63,8 +68,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 = readEitherBaseComponent( buf, protocolVersion, false );
suffix = readString( buf ); suffix = readEitherBaseComponent( buf, protocolVersion, false );
} }
} }
if ( mode == 0 || mode == 3 || mode == 4 ) if ( mode == 0 || mode == 3 || mode == 4 )
@ -85,11 +90,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 ); writeEitherBaseComponent( displayName, buf, protocolVersion );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 ) if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
{ {
writeString( prefix, buf ); writeEitherBaseComponent( prefix, buf, protocolVersion );
writeString( suffix, buf ); writeEitherBaseComponent( suffix, buf, protocolVersion );
} }
buf.writeByte( friendlyFire ); buf.writeByte( friendlyFire );
writeString( nameTagVisibility, buf ); writeString( nameTagVisibility, buf );
@ -101,8 +106,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 ); writeEitherBaseComponent( prefix, buf, protocolVersion );
writeString( suffix, buf ); writeEitherBaseComponent( suffix, buf, protocolVersion );
} else } else
{ {
buf.writeByte( color ); buf.writeByte( color );

View File

@ -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 );

View File

@ -1,6 +1,5 @@
package net.md_5.bungee; package net.md_5.bungee;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -24,6 +23,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.Format; import java.text.Format;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -691,10 +691,10 @@ public class BungeeCord extends ProxyServer
{ {
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 ) if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{ {
return new PluginMessage( "minecraft:register", String.join( "\00", Iterables.transform( pluginChannels, PluginMessage.MODERNISE ) ).getBytes( Charsets.UTF_8 ), false ); return new PluginMessage( "minecraft:register", String.join( "\00", Iterables.transform( pluginChannels, PluginMessage.MODERNISE ) ).getBytes( StandardCharsets.UTF_8 ), false );
} }
return new PluginMessage( "REGISTER", String.join( "\00", pluginChannels ).getBytes( Charsets.UTF_8 ), false ); return new PluginMessage( "REGISTER", String.join( "\00", pluginChannels ).getBytes( StandardCharsets.UTF_8 ), false );
} }
@Override @Override
@ -730,13 +730,13 @@ public class BungeeCord extends ProxyServer
@Override @Override
public void broadcast(String message) public void broadcast(String message)
{ {
broadcast( TextComponent.fromLegacyText( message ) ); broadcast( TextComponent.fromLegacy( message ) );
} }
@Override @Override
public void broadcast(BaseComponent... message) public void broadcast(BaseComponent... message)
{ {
getConsole().sendMessage( BaseComponent.toLegacyText( message ) ); getConsole().sendMessage( message );
for ( ProxiedPlayer player : getPlayers() ) for ( ProxiedPlayer player : getPlayers() )
{ {
player.sendMessage( message ); player.sendMessage( message );
@ -746,14 +746,14 @@ public class BungeeCord extends ProxyServer
@Override @Override
public void broadcast(BaseComponent message) public void broadcast(BaseComponent message)
{ {
getConsole().sendMessage( message.toLegacyText() ); getConsole().sendMessage( message );
for ( ProxiedPlayer player : getPlayers() ) for ( ProxiedPlayer player : getPlayers() )
{ {
player.sendMessage( message ); player.sendMessage( message );
} }
} }
public void addConnection(UserConnection con) public boolean addConnection(UserConnection con)
{ {
UUID offlineId = con.getPendingConnection().getOfflineId(); UUID offlineId = con.getPendingConnection().getOfflineId();
if ( offlineId != null && offlineId.version() != 3 ) if ( offlineId != null && offlineId.version() != 3 )
@ -763,6 +763,10 @@ public class BungeeCord extends ProxyServer
connectionLock.writeLock().lock(); connectionLock.writeLock().lock();
try try
{ {
if ( connections.containsKey( con.getName() ) || connectionsByUUID.containsKey( con.getUniqueId() ) || connectionsByOfflineUUID.containsKey( offlineId ) )
{
return false;
}
connections.put( con.getName(), con ); connections.put( con.getName(), con );
connectionsByUUID.put( con.getUniqueId(), con ); connectionsByUUID.put( con.getUniqueId(), con );
connectionsByOfflineUUID.put( offlineId, con ); connectionsByOfflineUUID.put( offlineId, con );
@ -770,6 +774,7 @@ public class BungeeCord extends ProxyServer
{ {
connectionLock.writeLock().unlock(); connectionLock.writeLock().unlock();
} }
return true;
} }
public void removeConnection(UserConnection con) public void removeConnection(UserConnection con)

View File

@ -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

View File

@ -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;
@ -34,6 +35,7 @@ import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PacketHandler; import net.md_5.bungee.netty.PacketHandler;
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.PacketWrapper; import net.md_5.bungee.protocol.PacketWrapper;
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;
@ -51,6 +53,7 @@ import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.protocol.packet.Respawn; import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardObjective; import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore; import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.SetCompression; import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration; import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.ViewDistance; import net.md_5.bungee.protocol.packet.ViewDistance;
@ -278,11 +281,22 @@ 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(),
( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13 ) ? Either.right( ComponentSerializer.deserialize( objective.getValue() ) ) : Either.left( objective.getValue() ),
ScoreboardObjective.HealthDisplay.fromString( objective.getType() ),
(byte) 1, null )
);
} }
for ( Score score : serverScoreboard.getScores() ) for ( Score score : serverScoreboard.getScores() )
{ {
user.unsafe().sendPacket( new ScoreboardScore( score.getItemName(), (byte) 1, score.getScoreName(), score.getValue() ) ); if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_3 )
{
user.unsafe().sendPacket( new ScoreboardScoreReset( score.getItemName(), null ) );
} else
{
user.unsafe().sendPacket( new ScoreboardScore( score.getItemName(), (byte) 1, score.getScoreName(), score.getValue(), null, null ) );
}
} }
for ( Team team : serverScoreboard.getTeams() ) for ( Team team : serverScoreboard.getTeams() )
{ {
@ -383,7 +397,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

View File

@ -153,7 +153,7 @@ public final class UserConnection implements ProxiedPlayer
} }
}; };
public void init() public boolean init()
{ {
this.entityRewrite = EntityMap.getEntityMap( getPendingConnection().getVersion() ); this.entityRewrite = EntityMap.getEntityMap( getPendingConnection().getVersion() );
@ -172,6 +172,8 @@ public final class UserConnection implements ProxiedPlayer
// Set whether the connection has a 1.8 FML marker in the handshake. // Set whether the connection has a 1.8 FML marker in the handshake.
forgeClientHandler.setFmlTokenInHandshake( this.getPendingConnection().getExtraDataInHandshake().contains( ForgeConstants.FML_HANDSHAKE_TOKEN ) ); forgeClientHandler.setFmlTokenInHandshake( this.getPendingConnection().getExtraDataInHandshake().contains( ForgeConstants.FML_HANDSHAKE_TOKEN ) );
return BungeeCord.getInstance().addConnection( this );
} }
public void sendPacket(PacketWrapper packet) public void sendPacket(PacketWrapper packet)
@ -406,13 +408,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.fromLegacy( reason ) );
} }
@Override @Override
public void disconnect(BaseComponent... reason) public void disconnect(BaseComponent... reason)
{ {
disconnect0( reason ); disconnect( TextComponent.fromArray( reason ) );
} }
@Override @Override
@ -421,7 +423,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 +432,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 )
{ {
@ -454,7 +456,7 @@ public final class UserConnection implements ProxiedPlayer
@Override @Override
public void sendMessage(String message) public void sendMessage(String message)
{ {
sendMessage( TextComponent.fromLegacyText( message ) ); sendMessage( TextComponent.fromLegacy( message ) );
} }
@Override @Override
@ -481,7 +483,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 +495,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 +504,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 +537,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 +717,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

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.conf; package net.md_5.bungee.conf;
import com.google.common.base.Charsets;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -10,6 +9,7 @@ import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -176,7 +176,7 @@ public class YamlConfig implements ConfigurationAdapter
{ {
try try
{ {
try ( Writer wr = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) ) try ( Writer wr = new OutputStreamWriter( new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{ {
yaml.dump( config, wr ); yaml.dump( config, wr );
} }

View File

@ -67,6 +67,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay; import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective; import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore; import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ScoreboardScoreReset;
import net.md_5.bungee.protocol.packet.ServerData; import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression; import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.TabCompleteResponse; import net.md_5.bungee.protocol.packet.TabCompleteResponse;
@ -183,7 +184,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(), ( objective.getValue().isLeft() ) ? objective.getValue().getLeft() : ComponentSerializer.toString( objective.getValue().getRight() ), objective.getType().toString() ) );
break; break;
case 1: case 1:
serverScoreboard.removeObjective( objective.getName() ); serverScoreboard.removeObjective( objective.getName() );
@ -192,7 +193,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( ( objective.getValue().isLeft() ) ? objective.getValue().getLeft() : ComponentSerializer.toString( objective.getValue().getRight() ) );
oldObjective.setType( objective.getType().toString() ); oldObjective.setType( objective.getType().toString() );
} }
break; break;
@ -220,6 +221,18 @@ public class DownstreamBridge extends PacketHandler
} }
} }
@Override
public void handle(ScoreboardScoreReset scoreboardScoreReset) throws Exception
{
Scoreboard serverScoreboard = con.getServerSentScoreboard();
// TODO: Expand score API to handle objective values. Shouldn't matter currently as only used for removing score entries.
if ( scoreboardScoreReset.getScoreName() == null )
{
serverScoreboard.removeScore( scoreboardScoreReset.getItemName() );
}
}
@Override @Override
public void handle(ScoreboardDisplay displayScoreboard) throws Exception public void handle(ScoreboardDisplay displayScoreboard) throws Exception
{ {
@ -254,9 +267,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 +633,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;

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.connection; package net.md_5.bungee.connection;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.gson.Gson; import com.google.gson.Gson;
import java.math.BigInteger; import java.math.BigInteger;
@ -39,7 +38,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;
@ -434,8 +432,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
if ( result.isCancelled() ) if ( result.isCancelled() )
{ {
BaseComponent[] reason = result.getCancelReasonComponents(); BaseComponent reason = result.getReason();
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacyText( bungee.getTranslation( "kick_message" ) ) ); disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) );
return; return;
} }
if ( ch.isClosed() ) if ( ch.isClosed() )
@ -515,7 +513,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private void finish() private void finish()
{ {
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) ); offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) );
if ( uniqueId == null ) if ( uniqueId == null )
{ {
uniqueId = offlineId; uniqueId = offlineId;
@ -578,8 +576,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
if ( result.isCancelled() ) if ( result.isCancelled() )
{ {
BaseComponent[] reason = result.getCancelReasonComponents(); BaseComponent reason = result.getReason();
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacyText( bungee.getTranslation( "kick_message" ) ) ); disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) );
return; return;
} }
if ( ch.isClosed() ) if ( ch.isClosed() )
@ -615,7 +613,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private void finish2() private void finish2()
{ {
userCon.init(); if ( !userCon.init() )
{
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
return;
}
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) ); ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) ); bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
@ -646,7 +648,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
if ( canSendKickMessage() ) if ( canSendKickMessage() )
{ {
disconnect( TextComponent.fromLegacyText( reason ) ); disconnect( TextComponent.fromLegacy( reason ) );
} else } else
{ {
ch.close(); ch.close();
@ -656,22 +658,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

View File

@ -54,7 +54,6 @@ public class UpstreamBridge extends PacketHandler
this.bungee = bungee; this.bungee = bungee;
this.con = con; this.con = con;
BungeeCord.getInstance().addConnection( con );
con.getTabListHandler().onConnect(); con.getTabListHandler().onConnect();
} }

View File

@ -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" );
} }

View File

@ -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;

View File

@ -1,9 +1,9 @@
package net.md_5.bungee.forge; package net.md_5.bungee.forge;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -22,7 +22,7 @@ public class ForgeUtils
*/ */
public static Set<String> readRegisteredChannels(PluginMessage pluginMessage) public static Set<String> readRegisteredChannels(PluginMessage pluginMessage)
{ {
String channels = new String( pluginMessage.getData(), Charsets.UTF_8 ); String channels = new String( pluginMessage.getData(), StandardCharsets.UTF_8 );
String[] split = channels.split( "\0" ); String[] split = channels.split( "\0" );
Set<String> channelSet = ImmutableSet.copyOf( split ); Set<String> channelSet = ImmutableSet.copyOf( split );
return channelSet; return channelSet;

View File

@ -172,10 +172,7 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
} ); } );
} else } else
{ {
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - could not decode packet! {1}", new Object[] ProxyServer.getInstance().getLogger().log( Level.WARNING, handler + " - could not decode packet!", cause );
{
handler, cause
} );
} }
} else if ( cause instanceof IOException || ( cause instanceof IllegalStateException && handler instanceof InitialHandler ) ) } else if ( cause instanceof IOException || ( cause instanceof IllegalStateException && handler instanceof InitialHandler ) )
{ {

View File

@ -27,6 +27,11 @@ public final class AllowedCharacters
public static boolean isValidName(String name, boolean onlineMode) public static boolean isValidName(String name, boolean onlineMode)
{ {
if ( name.isEmpty() || name.length() > 16 )
{
return false;
}
for ( int index = 0, len = name.length(); index < len; index++ ) for ( int index = 0, len = name.length(); index < len; index++ )
{ {
if ( !isNameAllowedCharacter( name.charAt( index ), onlineMode ) ) if ( !isNameAllowedCharacter( name.charAt( index ), onlineMode ) )

View File

@ -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,30 +34,25 @@ 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++ ) if ( next.getHoverEvent() == null || next.getHoverEvent().isLegacy() )
{ {
BaseComponent next = components[i]; return next;
if ( next.getHoverEvent() == null || next.getHoverEvent().isLegacy() ) }
{ next = next.duplicate();
continue; next.getHoverEvent().setLegacy( true );
} if ( next.getHoverEvent().getContents().size() > 1 )
next = next.duplicate(); {
next.getHoverEvent().setLegacy( true ); Content exception = next.getHoverEvent().getContents().get( 0 );
if ( next.getHoverEvent().getContents().size() > 1 ) next.getHoverEvent().getContents().clear();
{ next.getHoverEvent().getContents().add( exception );
Content exception = next.getHoverEvent().getContents().get( 0 );
next.getHoverEvent().getContents().clear();
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,40 +86,35 @@ 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 = root.getExtra().stream().map( (extra) -> transform( player, transformHover, extra ) ).collect( Collectors.toList() );
{ root.setExtra( list );
List<BaseComponent> list = Lists.newArrayList( transform( player, transformHover, root.getExtra().toArray( new BaseComponent[ 0 ] ) ) );
root.setExtra( list );
}
if ( root instanceof ScoreComponent )
{
transformScoreComponent( player, (ScoreComponent) root );
}
} }
return components;
if ( root instanceof ScoreComponent )
{
transformScoreComponent( player, (ScoreComponent) root );
}
return root;
} }
/** /**