Compare commits

..

29 Commits

Author SHA1 Message Date
adaebb32f5 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2023-12-07 23:41:36 +01:00
525403b004 Add CommandsDeclareEvent to declare commands with brigadier API 2023-12-07 23:41:36 +01:00
4e5410fe30 Server branding now includes the backend server name 2023-12-07 23:41:36 +01:00
6707a3731f Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2023-12-07 23:41:32 +01:00
f0a7644d5b Change projet configuration and POM for Pandacube 2023-12-07 23:16:32 +01:00
45b1d1e41c Remove modules and startup delay
We don’t need them for Pandacube
2023-12-07 23:16:27 +01:00
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
61 changed files with 1211 additions and 339 deletions

View File

@ -105,13 +105,13 @@ public class ServerPing
@Deprecated
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
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
@ -139,7 +139,7 @@ public class ServerPing
@Deprecated
public void setDescription(String description)
{
this.description = new TextComponent( TextComponent.fromLegacyText( description ) );
this.description = TextComponent.fromLegacy( description );
}
@Deprecated

View File

@ -334,6 +334,9 @@ public interface ProxiedPlayer extends Connection, CommandSender
* Get the {@link Scoreboard} that belongs to this player.
*
* @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();
}

View File

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

View File

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

View File

@ -35,7 +35,7 @@ public class ServerKickEvent extends Event implements Cancellable
/**
* Kick reason.
*/
private BaseComponent[] kickReasonComponent;
private BaseComponent reason;
/**
* 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 );
}
@Deprecated
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.kickedFrom = kickedFrom;
this.kickReasonComponent = kickReasonComponent;
this.reason = reason;
this.cancelServer = cancelServer;
this.state = state;
}
/**
* @return the kick reason
* @deprecated use component methods instead
*/
@Deprecated
public String getKickReason()
{
return BaseComponent.toLegacyText( kickReasonComponent );
return BaseComponent.toLegacyText( getReason() );
}
/**
* @param reason the kick reason
* @deprecated use component methods instead
*/
@Deprecated
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;
}
/**
* 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
* 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
* empty, an empty text component will be returned.
* Returns the component built by this builder. If this builder is empty, an
* empty text component will be returned.
*
* @return the component
*/
@ -478,8 +505,8 @@ public final class ComponentBuilder
* <p>
* <strong>NOTE:</strong> {@link #build()} 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.
* contents as opposed to an array of components which is non-standard and
* may result in unexpected behavior.
*
* @return the created components
*/

View File

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

View File

@ -2,6 +2,7 @@ package net.md_5.bungee.api.chat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AllArgsConstructor;
@ -27,6 +28,41 @@ public final class TextComponent extends BaseComponent
* @param message the text to convert
* @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)
{
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
* (i.e. after ChatColor.RESET).
* @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)
{
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();
TextComponent component = new TextComponent();
Matcher matcher = url.matcher( message );
@ -94,7 +141,7 @@ public final class TextComponent extends BaseComponent
component = new TextComponent( old );
old.setText( builder.toString() );
builder = new StringBuilder();
components.add( old );
appender.accept( old );
}
if ( format == ChatColor.BOLD )
{
@ -137,7 +184,7 @@ public final class TextComponent extends BaseComponent
component = new TextComponent( old );
old.setText( builder.toString() );
builder = new StringBuilder();
components.add( old );
appender.accept( old );
}
TextComponent old = component;
@ -146,7 +193,7 @@ public final class TextComponent extends BaseComponent
component.setText( urlString );
component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL,
urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) );
components.add( component );
appender.accept( component );
i += pos - i - 1;
component = old;
continue;
@ -155,9 +202,29 @@ public final class TextComponent extends BaseComponent
}
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.
*

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)
{
// For legacy serialization reasons, this has to be an array of components
this( new BaseComponent[]{value} );
this( new BaseComponent[]
{
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.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import java.util.ArrayList;
import java.util.Arrays;
@ -20,27 +21,51 @@ import net.md_5.bungee.api.chat.hover.content.Content;
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)
{
if ( object.has( "bold" ) )
{
component.setBold( object.get( "bold" ).getAsBoolean() );
component.setBold( getAsBoolean( object.get( "bold" ) ) );
}
if ( object.has( "italic" ) )
{
component.setItalic( object.get( "italic" ).getAsBoolean() );
component.setItalic( getAsBoolean( object.get( "italic" ) ) );
}
if ( object.has( "underlined" ) )
{
component.setUnderlined( object.get( "underlined" ).getAsBoolean() );
component.setUnderlined( getAsBoolean( object.get( "underlined" ) ) );
}
if ( object.has( "strikethrough" ) )
{
component.setStrikethrough( object.get( "strikethrough" ).getAsBoolean() );
component.setStrikethrough( getAsBoolean( object.get( "strikethrough" ) ) );
}
if ( object.has( "obfuscated" ) )
{
component.setObfuscated( object.get( "obfuscated" ).getAsBoolean() );
component.setObfuscated( getAsBoolean( object.get( "obfuscated" ) ) );
}
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.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import java.lang.reflect.Type;
import java.util.Set;
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
* can be one of either an array of components, or a single component object.
* If the input is an array, each component will be parsed individually and
* returned in the order that they were parsed. If the input is a single
* component object, a single-valued array with the component will be returned.
* can be one of either an array of components, or a single component
* object. If the input is an array, each component will be parsed
* individually and returned in the order that they were parsed. If the
* input is a single component object, a single-valued array with the
* component will be returned.
* <p>
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it will
* parse only one component as opposed to an array of components which is non-
* standard behavior. This method is still appropriate for parsing multiple
* components at once, although such use case is rarely (if at all) exhibited
* in vanilla Minecraft.
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it
* will parse only one component as opposed to an array of components which
* is non- standard behavior. This method is still appropriate for parsing
* multiple components at once, although such use case is rarely (if at all)
* exhibited in vanilla Minecraft.
*
* @param json the component json to parse
* @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
* expected to be a JSON object that represents only one component.
* Deserialize a JSON-compliant String as a single component.
*
* @param json the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a JSON object is
* passed as input
* @throws IllegalArgumentException if anything other than a valid JSON
* component string is passed as input
*/
public static BaseComponent deserialize(String 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 );
}
public static JsonElement toJson(BaseComponent component)
{
return gson.toJsonTree( component );
}
public static String toString(Object object)
{
return gson.toJson( object );

View File

@ -18,11 +18,10 @@ public class TextComponentSerializer extends BaseComponentSerializer implements
{
TextComponent component = new TextComponent();
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 );
return component;
}

View File

@ -1,11 +1,11 @@
package net.md_5.bungee.chat;
import com.google.common.base.Charsets;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -102,7 +102,7 @@ public final class TranslationRegistry
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 );
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.Supplier;
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.chat.ComponentSerializer;
import org.junit.jupiter.api.Test;
@ -72,6 +71,8 @@ public class ComponentsTest
assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) );
testDissembleReassemble( components );
//////////
// TODO: now ambiguous since "text" to distinguish Text from Item is not required
/*
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}}";
Item contentItem = new Item( "minecraft:wood", 1, ItemTag.ofNbt( nbt ) );
@ -84,6 +85,7 @@ public class ComponentsTest
assertEquals( contentItem.getCount(), parsedContentItem.getCount() );
assertEquals( contentItem.getId(), parsedContentItem.getId() );
assertEquals( nbt, parsedContentItem.getTag().getNbt() );
*/
}
@Test
@ -561,8 +563,7 @@ public class ComponentsTest
this.testBuilder(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
BaseComponent::toLegacyText
);
}
@ -574,8 +575,7 @@ public class ComponentsTest
ComponentBuilder::build,
(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
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
(component) -> BaseComponent.toLegacyText( component )
);
}
@ -830,8 +830,8 @@ public class ComponentsTest
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );
assertEquals(
"{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},"
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"
+ "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}",
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"
+ "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}",
test2 );
}

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.config;
import com.google.common.base.Charsets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
@ -16,6 +15,7 @@ import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.AccessLevel;
@ -37,7 +37,7 @@ public class JsonConfiguration extends ConfigurationProvider
@Override
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 );
}
@ -91,7 +91,7 @@ public class JsonConfiguration extends ConfigurationProvider
@Override
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

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.config;
import com.google.common.base.Charsets;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -9,6 +8,7 @@ import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.AccessLevel;
@ -54,7 +54,7 @@ public class YamlConfiguration extends ConfigurationProvider
@Override
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 );
}

View File

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

View File

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

View File

@ -17,26 +17,20 @@
<name>BungeeCord-Protocol</name>
<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>
<repository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>minecraft-libraries</id>
<name>Minecraft Libraries</name>
<url>https://libraries.minecraft.net/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<groupId>com.mojang</groupId>
<artifactId>brigadier</artifactId>
<version>1.0.16-SNAPSHOT</version>
<version>1.2.9</version>
<scope>compile</scope>
</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.ScoreboardObjective;
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.SetCompression;
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
{
}

View File

@ -1,20 +1,25 @@
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.gson.JsonElement;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
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.NamedTag;
import se.llbit.nbt.SpecificTag;
@ -24,6 +29,23 @@ import se.llbit.nbt.Tag;
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)
{
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)" );
}
byte[] b = s.getBytes( Charsets.UTF_8 );
byte[] b = s.getBytes( StandardCharsets.UTF_8 );
if ( b.length > maxLength * 3 )
{
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)" );
}
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 );
if ( s.length() > maxLen )
@ -70,6 +92,59 @@ public abstract class DefinedPacket
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)
{
if ( b.length > Short.MAX_VALUE )
@ -295,6 +370,38 @@ public abstract class DefinedPacket
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)
{
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)
{
DataOutputStream out = new DataOutputStream( new ByteBufOutputStream( output ) );
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 )
{
throw new RuntimeException( "Exception writing tag", ex );
@ -386,6 +502,11 @@ public abstract class DefinedPacket
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)
{
read( buf );
@ -396,6 +517,11 @@ public abstract class DefinedPacket
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)
{
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 );
if ( packet != null )
{
packet.read( in, prot.getDirection(), protocolVersion );
packet.read( in, protocol, prot.getDirection(), protocolVersion );
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;
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.ScoreboardObjective;
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.SetCompression;
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_3, 0x3D ),
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(
BossBar.class,
@ -192,7 +194,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ),
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(
ScoreboardScore.class,
@ -208,7 +211,13 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ),
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(
ScoreboardDisplay.class,
@ -224,7 +233,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ),
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(
Team.class,
@ -240,7 +250,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ),
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(
PluginMessage.class,
@ -291,7 +302,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ),
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(
ClearTitles.class,
@ -310,7 +322,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ),
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(
TitleTimes.class,
@ -320,7 +333,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ),
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(
SystemChat.class,
@ -329,7 +343,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x62 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ),
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(
PlayerListHeaderFooter.class,
@ -349,7 +364,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x63 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ),
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(
EntityStatus.class,
@ -405,7 +421,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4C ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ),
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(
ServerData.class,
@ -414,7 +431,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x42 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ),
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(
PlayerListItemRemove.class,
@ -433,7 +451,8 @@ public enum Protocol
TO_CLIENT.registerPacket(
StartConfiguration.class,
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(
@ -451,7 +470,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ),
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,
Chat::new,
@ -517,7 +537,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
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(
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_20 = 763;
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<Integer> SUPPORTED_VERSION_IDS;
@ -101,13 +102,14 @@ public class ProtocolConstants
ProtocolConstants.MINECRAFT_1_19_3,
ProtocolConstants.MINECRAFT_1_19_4,
ProtocolConstants.MINECRAFT_1_20,
ProtocolConstants.MINECRAFT_1_20_2
ProtocolConstants.MINECRAFT_1_20_2,
ProtocolConstants.MINECRAFT_1_20_3
);
if ( SNAPSHOT_SUPPORT )
{
// supportedVersions.add( "1.20.x" );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_2 );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_3 );
}
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;
/**
* 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
public class Varint21LengthFieldExtraBufPrepender extends MessageToMessageEncoder<ByteBuf>

View File

@ -6,7 +6,8 @@ import io.netty.channel.ChannelHandlerContext;
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
public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>

View File

@ -5,6 +5,7 @@ import java.util.UUID;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -17,7 +18,7 @@ public class BossBar extends DefinedPacket
private UUID uuid;
private int action;
private String title;
private BaseComponent title;
private float health;
private int color;
private int division;
@ -39,7 +40,7 @@ public class BossBar extends DefinedPacket
{
// Add
case 0:
title = readString( buf );
title = readBaseComponent( buf, protocolVersion );
health = buf.readFloat();
color = readVarInt( buf );
division = readVarInt( buf );
@ -51,7 +52,7 @@ public class BossBar extends DefinedPacket
break;
// Title
case 3:
title = readString( buf );
title = readBaseComponent( buf, protocolVersion );
break;
// Style
case 4:
@ -75,7 +76,7 @@ public class BossBar extends DefinedPacket
{
// Add
case 0:
writeString( title, buf );
writeBaseComponent( title, buf, protocolVersion );
buf.writeFloat( health );
writeVarInt( color, buf );
writeVarInt( division, buf );
@ -87,7 +88,7 @@ public class BossBar extends DefinedPacket
break;
// Title
case 3:
writeString( title, buf );
writeBaseComponent( title, buf, protocolVersion );
break;
// Style
case 4:

View File

@ -311,6 +311,7 @@ public class Commands extends DefinedPacket
private static final ArgumentSerializer[] IDS_1_19;
private static final ArgumentSerializer[] IDS_1_19_3;
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 ArgumentSerializer<Void> VOID = new ArgumentSerializer<Void>()
@ -813,6 +814,60 @@ public class Commands extends DefinedPacket
get( "minecraft:uuid", 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)
@ -1232,7 +1287,10 @@ public class Commands extends DefinedPacket
{
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];
} else if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_3 )

View File

@ -5,8 +5,12 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
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.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@NoArgsConstructor
@ -15,18 +19,30 @@ import net.md_5.bungee.protocol.DefinedPacket;
public class Kick extends DefinedPacket
{
private String message;
private BaseComponent message;
@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
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

View File

@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -16,21 +17,21 @@ import net.md_5.bungee.protocol.ProtocolConstants;
public class PlayerListHeaderFooter extends DefinedPacket
{
private String header;
private String footer;
private BaseComponent header;
private BaseComponent footer;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
header = readString( buf );
footer = readString( buf );
header = readBaseComponent( buf, protocolVersion );
footer = readBaseComponent( buf, protocolVersion );
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( header, buf );
writeString( footer, buf );
writeBaseComponent( header, buf, protocolVersion );
writeBaseComponent( footer, buf, protocolVersion );
}
@Override

View File

@ -5,6 +5,7 @@ import java.util.UUID;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.PlayerPublicKey;
@ -38,7 +39,7 @@ public class PlayerListItem extends DefinedPacket
item.ping = DefinedPacket.readVarInt( buf );
if ( buf.readBoolean() )
{
item.displayName = DefinedPacket.readString( buf );
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 )
{
@ -54,7 +55,7 @@ public class PlayerListItem extends DefinedPacket
case UPDATE_DISPLAY_NAME:
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 );
if ( item.displayName != null )
{
DefinedPacket.writeString( item.displayName, buf );
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 )
{
@ -95,7 +96,7 @@ public class PlayerListItem extends DefinedPacket
buf.writeBoolean( item.displayName != null );
if ( item.displayName != null )
{
DefinedPacket.writeString( item.displayName, buf );
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
}
break;
}
@ -142,7 +143,7 @@ public class PlayerListItem extends DefinedPacket
Integer ping;
// ADD_PLAYER & UPDATE_DISPLAY_NAME
String displayName;
BaseComponent displayName;
}
}

View File

@ -58,7 +58,7 @@ public class PlayerListItemUpdate extends DefinedPacket
case UPDATE_DISPLAY_NAME:
if ( buf.readBoolean() )
{
item.displayName = DefinedPacket.readString( buf );
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
}
break;
}
@ -106,7 +106,7 @@ public class PlayerListItemUpdate extends DefinedPacket
buf.writeBoolean( item.displayName != null );
if ( item.displayName != null )
{
DefinedPacket.writeString( item.displayName, buf );
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
}
break;
}

View File

@ -6,8 +6,11 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
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;
@Data
@ -18,12 +21,13 @@ public class ScoreboardObjective extends DefinedPacket
{
private String name;
private String value;
private Either<String, BaseComponent> value;
private HealthDisplay type;
/**
* 0 to create, 1 to remove, 2 to update display text.
*/
private byte action;
private NumberFormat numberFormat;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
@ -32,14 +36,19 @@ public class ScoreboardObjective extends DefinedPacket
action = buf.readByte();
if ( action == 0 || action == 2 )
{
value = readString( buf );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{
value = readEitherBaseComponent( buf, protocolVersion, false );
type = HealthDisplay.values()[readVarInt( buf )];
} else
{
value = readEitherBaseComponent( buf, protocolVersion, true );
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 );
if ( action == 0 || action == 2 )
{
writeString( value, buf );
writeEitherBaseComponent( value, buf, protocolVersion );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{
writeVarInt( type.ordinal(), buf );
@ -58,6 +67,10 @@ public class ScoreboardObjective extends DefinedPacket
{
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.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.NumberFormat;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@ -23,29 +25,50 @@ public class ScoreboardScore extends DefinedPacket
private byte action;
private String scoreName;
private int value;
private BaseComponent displayName;
private NumberFormat numberFormat;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
itemName = readString( buf );
action = buf.readByte();
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
action = 0;
} else
{
action = buf.readByte();
}
scoreName = readString( buf );
if ( action != 1 )
{
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
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( itemName, buf );
buf.writeByte( action );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_3 )
{
buf.writeByte( action );
}
writeString( scoreName, buf );
if ( action != 1 )
if ( action != 1 || protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
{
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

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.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -16,7 +17,7 @@ import net.md_5.bungee.protocol.ProtocolConstants;
public class ServerData extends DefinedPacket
{
private String motd;
private BaseComponent motd;
private Object icon;
private boolean preview;
private boolean enforceSecure;
@ -26,7 +27,7 @@ public class ServerData extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 || buf.readBoolean() )
{
motd = readString( buf, 262144 );
motd = readBaseComponent( buf, protocolVersion );
}
if ( buf.readBoolean() )
{
@ -59,7 +60,7 @@ public class ServerData extends DefinedPacket
{
buf.writeBoolean( true );
}
writeString( motd, buf, 262144 );
writeBaseComponent( motd, buf, protocolVersion );
} else
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 )

View File

@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -14,18 +15,18 @@ import net.md_5.bungee.protocol.ProtocolConstants;
public class Subtitle extends DefinedPacket
{
private String text;
private BaseComponent text;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
text = readString( buf );
text = readBaseComponent( buf, protocolVersion );
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( text, buf );
writeBaseComponent( text, buf, protocolVersion );
}
@Override

View File

@ -6,6 +6,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
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.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -17,20 +18,20 @@ import net.md_5.bungee.protocol.ProtocolConstants;
public class SystemChat extends DefinedPacket
{
private String message;
private BaseComponent message;
private int position;
@Override
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 );
}
@Override
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 )
{
buf.writeBoolean( position == ChatMessageType.ACTION_BAR.ordinal() );

View File

@ -1,6 +1,6 @@
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.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
@ -10,6 +10,7 @@ import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -51,9 +52,9 @@ public class TabCompleteResponse extends DefinedPacket
for ( int i = 0; i < cnt; i++ )
{
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 );
@ -76,10 +77,10 @@ public class TabCompleteResponse extends DefinedPacket
for ( Suggestion suggestion : suggestions.getList() )
{
writeString( suggestion.getText(), buf );
buf.writeBoolean( suggestion.getTooltip() != null && suggestion.getTooltip().getString() != null );
if ( suggestion.getTooltip() != null && suggestion.getTooltip().getString() != null )
buf.writeBoolean( suggestion.getTooltip() != null );
if ( suggestion.getTooltip() != null )
{
writeString( suggestion.getTooltip().getString(), buf );
writeBaseComponent( ( (ComponentMessage) suggestion.getTooltip() ).getComponent(), buf, protocolVersion );
}
}
} else
@ -93,4 +94,17 @@ public class TabCompleteResponse extends DefinedPacket
{
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.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Either;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@ -21,9 +23,9 @@ public class Team extends DefinedPacket
* 0 - create, 1 remove, 2 info update, 3 player add, 4 player remove.
*/
private byte mode;
private String displayName;
private String prefix;
private String suffix;
private Either<String, BaseComponent> displayName;
private Either<String, BaseComponent> prefix;
private Either<String, BaseComponent> suffix;
private String nameTagVisibility;
private String collisionRule;
private int color;
@ -48,11 +50,14 @@ public class Team extends DefinedPacket
mode = buf.readByte();
if ( mode == 0 || mode == 2 )
{
displayName = readString( buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
{
prefix = readString( buf );
suffix = readString( buf );
displayName = readEitherBaseComponent( buf, protocolVersion, true );
prefix = readEitherBaseComponent( buf, protocolVersion, true );
suffix = readEitherBaseComponent( buf, protocolVersion, true );
} else
{
displayName = readEitherBaseComponent( buf, protocolVersion, false );
}
friendlyFire = buf.readByte();
nameTagVisibility = readString( buf );
@ -63,8 +68,8 @@ public class Team extends DefinedPacket
color = ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 ) ? readVarInt( buf ) : buf.readByte();
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{
prefix = readString( buf );
suffix = readString( buf );
prefix = readEitherBaseComponent( buf, protocolVersion, false );
suffix = readEitherBaseComponent( buf, protocolVersion, false );
}
}
if ( mode == 0 || mode == 3 || mode == 4 )
@ -85,11 +90,11 @@ public class Team extends DefinedPacket
buf.writeByte( mode );
if ( mode == 0 || mode == 2 )
{
writeString( displayName, buf );
writeEitherBaseComponent( displayName, buf, protocolVersion );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_13 )
{
writeString( prefix, buf );
writeString( suffix, buf );
writeEitherBaseComponent( prefix, buf, protocolVersion );
writeEitherBaseComponent( suffix, buf, protocolVersion );
}
buf.writeByte( friendlyFire );
writeString( nameTagVisibility, buf );
@ -101,8 +106,8 @@ public class Team extends DefinedPacket
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_13 )
{
writeVarInt( color, buf );
writeString( prefix, buf );
writeString( suffix, buf );
writeEitherBaseComponent( prefix, buf, protocolVersion );
writeEitherBaseComponent( suffix, buf, protocolVersion );
} else
{
buf.writeByte( color );

View File

@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -17,7 +18,7 @@ public class Title extends DefinedPacket
private Action action;
// TITLE & SUBTITLE
private String text;
private BaseComponent text;
// TIMES
private int fadeIn;
@ -34,7 +35,7 @@ public class Title extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_17 )
{
text = readString( buf );
text = readBaseComponent( buf, protocolVersion );
return;
}
@ -52,7 +53,7 @@ public class Title extends DefinedPacket
case TITLE:
case SUBTITLE:
case ACTIONBAR:
text = readString( buf );
text = readBaseComponent( buf, protocolVersion );
break;
case TIMES:
fadeIn = buf.readInt();
@ -67,7 +68,7 @@ public class Title extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_17 )
{
writeString( text, buf );
writeBaseComponent( text, buf, protocolVersion );
return;
}
@ -85,7 +86,7 @@ public class Title extends DefinedPacket
case TITLE:
case SUBTITLE:
case ACTIONBAR:
writeString( text, buf );
writeBaseComponent( text, buf, protocolVersion );
break;
case TIMES:
buf.writeInt( fadeIn );

View File

@ -1,6 +1,5 @@
package net.md_5.bungee;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@ -24,6 +23,7 @@ import java.io.IOException;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.Format;
import java.text.MessageFormat;
import java.util.ArrayList;
@ -685,10 +685,10 @@ public class BungeeCord extends ProxyServer
{
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
@ -724,13 +724,13 @@ public class BungeeCord extends ProxyServer
@Override
public void broadcast(String message)
{
broadcast( TextComponent.fromLegacyText( message ) );
broadcast( TextComponent.fromLegacy( message ) );
}
@Override
public void broadcast(BaseComponent... message)
{
getConsole().sendMessage( BaseComponent.toLegacyText( message ) );
getConsole().sendMessage( message );
for ( ProxiedPlayer player : getPlayers() )
{
player.sendMessage( message );
@ -740,14 +740,14 @@ public class BungeeCord extends ProxyServer
@Override
public void broadcast(BaseComponent message)
{
getConsole().sendMessage( message.toLegacyText() );
getConsole().sendMessage( message );
for ( ProxiedPlayer player : getPlayers() )
{
player.sendMessage( message );
}
}
public void addConnection(UserConnection con)
public boolean addConnection(UserConnection con)
{
UUID offlineId = con.getPendingConnection().getOfflineId();
if ( offlineId != null && offlineId.version() != 3 )
@ -757,6 +757,10 @@ public class BungeeCord extends ProxyServer
connectionLock.writeLock().lock();
try
{
if ( connections.containsKey( con.getName() ) || connectionsByUUID.containsKey( con.getUniqueId() ) || connectionsByOfflineUUID.containsKey( offlineId ) )
{
return false;
}
connections.put( con.getName(), con );
connectionsByUUID.put( con.getUniqueId(), con );
connectionsByOfflineUUID.put( offlineId, con );
@ -764,6 +768,7 @@ public class BungeeCord extends ProxyServer
{
connectionLock.writeLock().unlock();
}
return true;
}
public void removeConnection(UserConnection con)

View File

@ -3,8 +3,8 @@ package net.md_5.bungee;
import lombok.Data;
import net.md_5.bungee.api.Title;
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.chat.ComponentSerializer;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.packet.ClearTitles;
@ -53,21 +53,14 @@ public class BungeeTitle implements Title
title = new TitlePacketHolder<>( packet, packet );
}
title.oldPacket.setText( ComponentSerializer.toString( text ) ); // = newPacket
title.oldPacket.setText( text ); // = newPacket
return this;
}
@Override
public Title title(BaseComponent... text)
{
if ( title == null )
{
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;
return title( TextComponent.fromArray( text ) );
}
@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() );
}
String serialized = ComponentSerializer.toString( text );
subtitle.oldPacket.setText( serialized );
subtitle.newPacket.setText( serialized );
subtitle.oldPacket.setText( text );
subtitle.newPacket.setText( text );
return this;
}
@Override
public Title subTitle(BaseComponent... text)
{
if ( subtitle == null )
{
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;
return subTitle( TextComponent.fromArray( text ) );
}
@Override

View File

@ -14,6 +14,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.ChatColor;
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.event.ServerConnectEvent;
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.PacketHandler;
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.Protocol;
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.ScoreboardObjective;
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.StartConfiguration;
import net.md_5.bungee.protocol.packet.ViewDistance;
@ -278,11 +281,22 @@ public class ServerConnector extends PacketHandler
Scoreboard serverScoreboard = user.getServerSentScoreboard();
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() )
{
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() )
{
@ -383,7 +397,10 @@ public class ServerConnector extends PacketHandler
public void handle(Kick kick) throws Exception
{
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 )
{
// 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() );
@ -172,6 +172,8 @@ public final class UserConnection implements ProxiedPlayer
// Set whether the connection has a 1.8 FML marker in the handshake.
forgeClientHandler.setFmlTokenInHandshake( this.getPendingConnection().getExtraDataInHandshake().contains( ForgeConstants.FML_HANDSHAKE_TOKEN ) );
return BungeeCord.getInstance().addConnection( this );
}
public void sendPacket(PacketWrapper packet)
@ -406,13 +408,13 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void disconnect(String reason)
{
disconnect0( TextComponent.fromLegacyText( reason ) );
disconnect( TextComponent.fromLegacy( reason ) );
}
@Override
public void disconnect(BaseComponent... reason)
{
disconnect0( reason );
disconnect( TextComponent.fromArray( reason ) );
}
@Override
@ -421,7 +423,7 @@ public final class UserConnection implements ProxiedPlayer
disconnect0( reason );
}
public void disconnect0(final BaseComponent... reason)
public void disconnect0(final BaseComponent reason)
{
if ( !ch.isClosing() )
{
@ -430,7 +432,7 @@ public final class UserConnection implements ProxiedPlayer
getName(), BaseComponent.toLegacyText( reason )
} );
ch.close( new Kick( ComponentSerializer.toString( reason ) ) );
ch.close( new Kick( reason ) );
if ( server != null )
{
@ -454,7 +456,7 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void sendMessage(String message)
{
sendMessage( TextComponent.fromLegacyText( message ) );
sendMessage( TextComponent.fromLegacy( message ) );
}
@Override
@ -481,7 +483,7 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void sendMessage(ChatMessageType position, BaseComponent... message)
{
sendMessage( position, null, message );
sendMessage( position, null, TextComponent.fromArray( message ) );
}
@Override
@ -493,7 +495,7 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void sendMessage(UUID sender, BaseComponent... message)
{
sendMessage( ChatMessageType.CHAT, sender, message );
sendMessage( ChatMessageType.CHAT, sender, TextComponent.fromArray( message ) );
}
@Override
@ -502,8 +504,28 @@ public final class UserConnection implements ProxiedPlayer
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 )
{
// 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() ) );
} else
{
sendPacketQueued( new Chat( 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 ) );
sendPacketQueued( new Chat( ComponentSerializer.toString( message ), (byte) position.ordinal(), sender ) );
}
}
@ -720,25 +717,19 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void setTabHeader(BaseComponent header, BaseComponent footer)
{
header = ChatComponentTransformer.getInstance().transform( this, true, header )[0];
footer = ChatComponentTransformer.getInstance().transform( this, true, footer )[0];
header = ChatComponentTransformer.getInstance().transform( this, true, header );
footer = ChatComponentTransformer.getInstance().transform( this, true, footer );
sendPacketQueued( new PlayerListHeaderFooter(
ComponentSerializer.toString( header ),
ComponentSerializer.toString( footer )
header,
footer
) );
}
@Override
public void setTabHeader(BaseComponent[] header, BaseComponent[] footer)
{
header = ChatComponentTransformer.getInstance().transform( this, true, header );
footer = ChatComponentTransformer.getInstance().transform( this, true, footer );
sendPacketQueued( new PlayerListHeaderFooter(
ComponentSerializer.toString( header ),
ComponentSerializer.toString( footer )
) );
setTabHeader( TextComponent.fromArray( header ), TextComponent.fromArray( footer ) );
}
@Override

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.conf;
import com.google.common.base.Charsets;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileInputStream;
@ -10,6 +9,7 @@ import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -176,7 +176,7 @@ public class YamlConfig implements ConfigurationAdapter
{
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 );
}

View File

@ -72,6 +72,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
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.SetCompression;
import net.md_5.bungee.protocol.packet.TabCompleteResponse;
@ -188,7 +189,7 @@ public class DownstreamBridge extends PacketHandler
switch ( objective.getAction() )
{
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;
case 1:
serverScoreboard.removeObjective( objective.getName() );
@ -197,7 +198,7 @@ public class DownstreamBridge extends PacketHandler
Objective oldObjective = serverScoreboard.getObjective( objective.getName() );
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() );
}
break;
@ -225,6 +226,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
public void handle(ScoreboardDisplay displayScoreboard) throws Exception
{
@ -259,9 +272,9 @@ public class DownstreamBridge extends PacketHandler
{
if ( team.getMode() == 0 || team.getMode() == 2 )
{
t.setDisplayName( team.getDisplayName() );
t.setPrefix( team.getPrefix() );
t.setSuffix( team.getSuffix() );
t.setDisplayName( ComponentSerializer.toString( team.getDisplayName() ) );
t.setPrefix( ComponentSerializer.toString( team.getPrefix() ) );
t.setSuffix( ComponentSerializer.toString( team.getSuffix() ) );
t.setFriendlyFire( team.getFriendlyFire() );
t.setNameTagVisibility( team.getNameTagVisibility() );
t.setCollisionRule( team.getCollisionRule() );
@ -625,13 +638,16 @@ public class DownstreamBridge extends PacketHandler
public void handle(Kick kick) throws Exception
{
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 )
{
con.connectNow( event.getCancelServer(), ServerConnectEvent.Reason.KICK_REDIRECT );
} else
{
con.disconnect0( event.getKickReasonComponent() ); // TODO: Prefix our own stuff.
con.disconnect( event.getKickReasonComponent() ); // TODO: Prefix our own stuff.
}
server.setObsolete( true );
throw CancelSendSignal.INSTANCE;

View File

@ -1,6 +1,5 @@
package net.md_5.bungee.connection;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.gson.Gson;
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.ProxyPingEvent;
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.jni.cipher.BungeeCipher;
import net.md_5.bungee.netty.ChannelWrapper;
@ -436,8 +434,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
if ( result.isCancelled() )
{
BaseComponent[] reason = result.getCancelReasonComponents();
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacyText( bungee.getTranslation( "kick_message" ) ) );
BaseComponent reason = result.getReason();
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) );
return;
}
if ( ch.isClosed() )
@ -605,8 +603,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
if ( result.isCancelled() )
{
BaseComponent[] reason = result.getCancelReasonComponents();
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacyText( bungee.getTranslation( "kick_message" ) ) );
BaseComponent reason = result.getReason();
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) );
return;
}
if ( ch.isClosed() )
@ -642,7 +640,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
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 ) );
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
@ -673,7 +675,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
if ( canSendKickMessage() )
{
disconnect( TextComponent.fromLegacyText( reason ) );
disconnect( TextComponent.fromLegacy( reason ) );
} else
{
ch.close();
@ -683,22 +685,19 @@ public class InitialHandler extends PacketHandler implements PendingConnection
@Override
public void disconnect(final BaseComponent... reason)
{
if ( canSendKickMessage() )
{
ch.delayedClose( new Kick( ComponentSerializer.toString( reason ) ) );
} else
{
ch.close();
}
disconnect( TextComponent.fromArray( reason ) );
}
@Override
public void disconnect(BaseComponent reason)
{
disconnect( new BaseComponent[]
if ( canSendKickMessage() )
{
reason
} );
ch.delayedClose( new Kick( reason ) );
} else
{
ch.close();
}
}
@Override
@ -755,6 +754,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
return (int) ( duplicatedId.getMostSignificantBits() >> 8 ) & 0xF;
}
private void updateOfflineId()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) );
}
@Override
public int getVersion()
{
@ -794,11 +798,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
this.uniqueId = uuid;
}
private void updateOfflineId()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
}
@Override
public String getUUID()
{

View File

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

View File

@ -84,6 +84,8 @@ public abstract class EntityMap
return EntityMap_1_16_2.INSTANCE_1_19_4;
case ProtocolConstants.MINECRAFT_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" );
}

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_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_3 = new EntityMap_1_16_2( -1, 0x34 );
//
private final int spawnPlayerId;
private final int spectateId;

View File

@ -1,9 +1,9 @@
package net.md_5.bungee.forge;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@ -22,7 +22,7 @@ public class ForgeUtils
*/
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" );
Set<String> channelSet = ImmutableSet.copyOf( split );
return channelSet;

View File

@ -172,10 +172,7 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
} );
} else
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} - could not decode packet! {1}", new Object[]
{
handler, cause
} );
ProxyServer.getInstance().getLogger().log( Level.WARNING, handler + " - could not decode packet!", cause );
}
} 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)
{
if ( name.isEmpty() || name.length() > 16 )
{
return false;
}
for ( int index = 0, len = name.length(); index < len; index++ )
{
if ( !isNameAllowedCharacter( name.charAt( index ), onlineMode ) )

View File

@ -1,9 +1,9 @@
package net.md_5.bungee.util;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
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])(?:\\[([^ ]*)\\])?$" );
public BaseComponent[] legacyHoverTransform(ProxiedPlayer player, BaseComponent... components)
public BaseComponent legacyHoverTransform(ProxiedPlayer player, BaseComponent next)
{
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];
if ( next.getHoverEvent() == null || next.getHoverEvent().isLegacy() )
{
continue;
}
next = next.duplicate();
next.getHoverEvent().setLegacy( true );
if ( next.getHoverEvent().getContents().size() > 1 )
{
Content exception = next.getHoverEvent().getContents().get( 0 );
next.getHoverEvent().getContents().clear();
next.getHoverEvent().getContents().add( exception );
}
components[i] = next;
return next;
}
next = next.duplicate();
next.getHoverEvent().setLegacy( true );
if ( next.getHoverEvent().getContents().size() > 1 )
{
Content exception = next.getHoverEvent().getContents().get( 0 );
next.getHoverEvent().getContents().clear();
next.getHoverEvent().getContents().add( exception );
}
}
return components;
return next;
}
public static ChatComponentTransformer getInstance()
@ -77,7 +72,7 @@ public final class ChatComponentTransformer
* TextComponent if the components are null or empty
* @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 );
}
@ -91,40 +86,35 @@ public final class ChatComponentTransformer
* @param player player
* @param transformHover if the hover event should replace contents with
* value
* @param components the component to transform
* @param root the component to transform
* @return the transformed component, or an array containing a single empty
* TextComponent if the components are null or empty
* @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[]
{
new TextComponent( "" )
};
return new TextComponent( "" );
}
if ( transformHover )
{
components = legacyHoverTransform( player, components );
root = legacyHoverTransform( player, root );
}
for ( BaseComponent root : components )
if ( root.getExtra() != null && !root.getExtra().isEmpty() )
{
if ( root.getExtra() != null && !root.getExtra().isEmpty() )
{
List<BaseComponent> list = Lists.newArrayList( transform( player, transformHover, root.getExtra().toArray( new BaseComponent[ 0 ] ) ) );
root.setExtra( list );
}
if ( root instanceof ScoreComponent )
{
transformScoreComponent( player, (ScoreComponent) root );
}
List<BaseComponent> list = root.getExtra().stream().map( (extra) -> transform( player, transformHover, extra ) ).collect( Collectors.toList() );
root.setExtra( list );
}
return components;
if ( root instanceof ScoreComponent )
{
transformScoreComponent( player, (ScoreComponent) root );
}
return root;
}
/**