Compare commits

...

41 Commits

Author SHA1 Message Date
Janmm14
18eae8a1a6
#3664: Improve chat test code quality 2024-05-05 10:48:01 +10:00
Outfluencer
6e1751733f
#3608, #3676: Close connection if HAProxy 2.0 message is a health check 2024-04-29 06:56:18 +10:00
DerFrZocker
6335af840b
SPIGOT-7638: Library loader does not seem to resolve every dependency 2024-04-27 09:25:29 +10:00
Janmm14
336333acb1
#3665: Small improvements to TranslatableComponent
* Make TranslatableComponent format Pattern static
* Fix TranslatableComponent copy constructor not copying fallback
2024-04-25 07:58:27 +10:00
dependabot[bot]
d110f6629b
#3669: Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.2 to 3.5.3
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.2...maven-shade-plugin-3.5.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-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>
2024-04-25 07:57:50 +10:00
md_5
6f70b15e2e
Minecraft 1.20.5 support 2024-04-24 01:15:00 +10:00
dependabot[bot]
b30499e2b6
#3667: Bump org.apache.maven.plugins:maven-jar-plugin from 3.4.0 to 3.4.1
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.0...maven-jar-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-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>
2024-04-23 08:19:33 +10:00
md_5
5079181c28
Minecraft 1.20.5-rc3 support 2024-04-23 06:16:02 +10:00
md_5
ee02d98cb2
Minecraft 1.20.5-rc2 support 2024-04-20 08:53:11 +10:00
Outfluencer
c7ff3b8a14
#3654: Update year in README.md 2024-04-20 08:46:24 +10:00
Outfluencer
de60af0d7b
#3659: Cleanup command packets for 1.20.5 2024-04-20 08:45:46 +10:00
dependabot[bot]
a9218a7aa7
#3660: Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.3 to 3.2.4
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.3...maven-gpg-plugin-3.2.4)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-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>
2024-04-20 08:44:38 +10:00
Outfluencer
67c65e0464
#3658: Minecraft 1.20.5-rc1 support 2024-04-19 06:58:16 +10:00
Outfluencer
1be25b6c74
#3656: Improve online mode support where IP forwarding is disabled 2024-04-17 21:05:26 +10:00
md_5
8525b44961
Minecraft 1.20.5-pre3 support 2024-04-17 07:55:07 +10:00
Jared Tiala
1fca510a08
#3655: Fix 1.20.5-pre1 view distance packet ID 2024-04-17 06:38:26 +10:00
dependabot[bot]
3384185285
#3652: Bump org.apache.maven.plugins:maven-jar-plugin from 3.3.0 to 3.4.0
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-16 21:33:01 +10:00
dependabot[bot]
3075d2c19d
#3651: Bump io.netty:netty-bom from 4.1.108.Final to 4.1.109.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.108.Final to 4.1.109.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.108.Final...netty-4.1.109.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>
2024-04-16 21:32:48 +10:00
md_5
bc528d5d98
Update native libraries 2024-04-14 09:15:51 +10:00
Outfluencer
25cf8d682b
#3617: Don't go further if connection is disconnected during handshake event
Also replace all isClosed with isClosing as it is more accurate for
disconnect calls in events.
2024-04-13 17:22:31 +10:00
ignPurple
17e23d5c3f
#3628: Convert PostLoginEvent to AsyncEvent and expose target server 2024-04-13 17:10:24 +10:00
dependabot[bot]
d6c5197cb9
#3599: Bump com.mysql:mysql-connector-j from 8.2.0 to 8.3.0
Bumps [com.mysql:mysql-connector-j](https://github.com/mysql/mysql-connector-j) from 8.2.0 to 8.3.0.
- [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.x/CHANGES)
- [Commits](https://github.com/mysql/mysql-connector-j/compare/8.2.0...8.3.0)

---
updated-dependencies:
- dependency-name: com.mysql:mysql-connector-j
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-13 15:52:04 +10:00
dependabot[bot]
dd96f0f878
#3647: Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.2 to 3.2.3
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.2...maven-gpg-plugin-3.2.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-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>
2024-04-13 15:49:42 +10:00
md_5
8a9501ffe4
Minecraft 1.20.5-pre1 support 2024-04-13 10:50:38 +10:00
Outfluencer
5e25c63c5a
#3646: Add experimental io_uring support 2024-04-09 21:39:06 +10:00
dependabot[bot]
bd963501ec
#3644: Bump org.apache.maven.plugins:maven-source-plugin from 3.3.0 to 3.3.1
Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.0 to 3.3.1.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.0...maven-source-plugin-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-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>
2024-04-09 21:22:35 +10:00
md_5
da795a7094
Minecraft 24w14a support 2024-04-07 08:18:48 +10:00
md_5
84d0ea73fa
Minor formatting fixes 2024-03-31 10:09:20 +11:00
Outfluencer
0851e39197
#3614: Make glist command output hover and clickable 2024-03-31 10:09:16 +11:00
md_5
86e6fdf8a2
Fix lombok induced JavaDoc error 2024-03-31 10:02:23 +11:00
md_5
6ab0f5eba7
#3621: Warn about use of valid chat colors and add test 2024-03-31 09:53:03 +11:00
Rothes
f224787222
#3621: Only serialize valid chat colors to "color" component 2024-03-31 09:51:04 +11:00
Janmm14
82684c7b6b
#3634: Improve chat test code style.
Stop use of subclass for static method call.
Make test helper methods static.
2024-03-31 09:38:18 +11:00
Janmm14
c2f73d32b8
#3634: Micro-optimize chat deserialization 2024-03-31 09:38:17 +11:00
md_5
e642b9dde1
Minecraft 24w13a support 2024-03-29 15:03:59 +11:00
dependabot[bot]
db623d10c5
#3640: Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.1 to 3.2.2
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.1...maven-gpg-plugin-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-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>
2024-03-27 08:22:21 +11:00
dependabot[bot]
61bb9f5b93
#3637: Bump org.projectlombok:lombok from 1.18.30 to 1.18.32
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.30 to 1.18.32.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.30...v1.18.32)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  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>
2024-03-23 15:58:33 +11:00
dependabot[bot]
9551b45328
#3639: Bump io.netty:netty-bom from 4.1.107.Final to 4.1.108.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.107.Final to 4.1.108.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.107.Final...netty-4.1.108.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>
2024-03-23 15:58:14 +11:00
dependabot[bot]
dc680b87eb
#3636: Bump org.apache.maven.plugins:maven-gpg-plugin from 3.1.0 to 3.2.1
Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.1.0 to 3.2.1.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.1.0...maven-gpg-plugin-3.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-23 15:57:59 +11:00
dependabot[bot]
156eda78c6
#3635: Bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.12.1 to 3.13.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.1...maven-compiler-plugin-3.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-23 15:57:46 +11:00
md_5
31be68af51
Minecraft 24w12a support 2024-03-23 15:57:06 +11:00
52 changed files with 514 additions and 319 deletions

View File

@ -23,4 +23,4 @@ Binaries
-------- --------
Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl). Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl).
(c) 2012-2023 SpigotMC Pty. Ltd. (c) 2012-2024 SpigotMC Pty. Ltd.

View File

@ -3,8 +3,9 @@ package net.md_5.bungee.api.event;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Event;
/** /**
* Event called as soon as a connection has a {@link ProxiedPlayer} and is ready * Event called as soon as a connection has a {@link ProxiedPlayer} and is ready
@ -13,11 +14,22 @@ import net.md_5.bungee.api.plugin.Event;
@Data @Data
@ToString(callSuper = false) @ToString(callSuper = false)
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class PostLoginEvent extends Event public class PostLoginEvent extends AsyncEvent<PostLoginEvent>
{ {
/** /**
* The player involved with this event. * The player involved with this event.
*/ */
private final ProxiedPlayer player; private final ProxiedPlayer player;
/**
* The server to which the player will initially be connected.
*/
private ServerInfo target;
public PostLoginEvent(ProxiedPlayer player, ServerInfo target, Callback<PostLoginEvent> done)
{
super( done );
this.player = player;
this.target = target;
}
} }

View File

@ -61,6 +61,11 @@ class LibraryLoader
logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() ); logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
} }
} ); } );
// SPIGOT-7638: Add system properties,
// since JdkVersionProfileActivator needs 'java.version' when a profile has the 'jdk' element
// otherwise it will silently fail and not resolves the dependencies in the affected pom.
session.setSystemProperties( System.getProperties() );
session.setReadOnly(); session.setReadOnly();
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) ); this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) );

View File

@ -41,7 +41,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version> <version>3.4.1</version>
<configuration> <configuration>
<archive> <archive>
<manifestEntries> <manifestEntries>
@ -55,7 +55,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version> <version>3.5.3</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>

View File

@ -244,7 +244,7 @@ public final class ChatColor
public static ChatColor of(String string) public static ChatColor of(String string)
{ {
Preconditions.checkArgument( string != null, "string cannot be null" ); Preconditions.checkArgument( string != null, "string cannot be null" );
if ( string.startsWith( "#" ) && string.length() == 7 ) if ( string.length() == 7 && string.charAt( 0 ) == '#' )
{ {
int rgb; int rgb;
try try

View File

@ -253,6 +253,9 @@ public abstract class BaseComponent
/** /**
* Set this component's color. * Set this component's color.
* <p>
* <b>Warning: This should be a color, not formatting code (ie,
* {@link ChatColor#color} should not be null).</b>
* *
* @param color the component color, or null to use the default * @param color the component color, or null to use the default
*/ */

View File

@ -18,6 +18,9 @@ public final class ComponentStyle implements Cloneable
/** /**
* The color of this style. * The color of this style.
* <p>
* <b>Warning: This should be a color, not formatting code (ie,
* {@link ChatColor#color} should not be null).</b>
*/ */
private ChatColor color; private ChatColor color;
/** /**

View File

@ -19,7 +19,7 @@ import net.md_5.bungee.chat.TranslationRegistry;
public final class TranslatableComponent extends BaseComponent public final class TranslatableComponent extends BaseComponent
{ {
private final Pattern format = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" ); private static final Pattern FORMAT = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" );
/** /**
* The key into the Minecraft locale files to use for the translation. The * The key into the Minecraft locale files to use for the translation. The
@ -44,10 +44,11 @@ public final class TranslatableComponent extends BaseComponent
{ {
super( original ); super( original );
setTranslate( original.getTranslate() ); setTranslate( original.getTranslate() );
setFallback( original.getFallback() );
if ( original.getWith() != null ) if ( original.getWith() != null )
{ {
List<BaseComponent> temp = new ArrayList<BaseComponent>(); List<BaseComponent> temp = new ArrayList<>();
for ( BaseComponent baseComponent : original.getWith() ) for ( BaseComponent baseComponent : original.getWith() )
{ {
temp.add( baseComponent.duplicate() ); temp.add( baseComponent.duplicate() );
@ -177,7 +178,7 @@ public final class TranslatableComponent extends BaseComponent
trans = fallback; trans = fallback;
} }
Matcher matcher = format.matcher( trans ); Matcher matcher = FORMAT.matcher( trans );
int position = 0; int position = 0;
int i = 0; int i = 0;
while ( matcher.find( position ) ) while ( matcher.find( position ) )

View File

@ -23,47 +23,49 @@ public class BaseComponentSerializer
{ {
component.applyStyle( context.deserialize( object, ComponentStyle.class ) ); component.applyStyle( context.deserialize( object, ComponentStyle.class ) );
if ( object.has( "insertion" ) ) JsonElement insertion = object.get( "insertion" );
if ( insertion != null )
{ {
component.setInsertion( object.get( "insertion" ).getAsString() ); component.setInsertion( insertion.getAsString() );
} }
//Events //Events
if ( object.has( "clickEvent" ) ) JsonObject clickEvent = object.getAsJsonObject( "clickEvent" );
if ( clickEvent != null )
{ {
JsonObject event = object.getAsJsonObject( "clickEvent" );
component.setClickEvent( new ClickEvent( component.setClickEvent( new ClickEvent(
ClickEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ), ClickEvent.Action.valueOf( clickEvent.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ),
( event.has( "value" ) ) ? event.get( "value" ).getAsString() : "" ) ); ( clickEvent.has( "value" ) ) ? clickEvent.get( "value" ).getAsString() : "" ) );
} }
if ( object.has( "hoverEvent" ) ) JsonObject hoverEventJson = object.getAsJsonObject( "hoverEvent" );
if ( hoverEventJson != null )
{ {
JsonObject event = object.getAsJsonObject( "hoverEvent" );
HoverEvent hoverEvent = null; HoverEvent hoverEvent = null;
HoverEvent.Action action = HoverEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ); HoverEvent.Action action = HoverEvent.Action.valueOf( hoverEventJson.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) );
if ( event.has( "value" ) ) JsonElement value = hoverEventJson.get( "value" );
if ( value != null )
{ {
JsonElement contents = event.get( "value" );
// Plugins previously had support to pass BaseComponent[] into any action. // Plugins previously had support to pass BaseComponent[] into any action.
// If the GSON is possible to be parsed as BaseComponent, attempt to parse as so. // If the GSON is possible to be parsed as BaseComponent, attempt to parse as so.
BaseComponent[] components; BaseComponent[] components;
if ( contents.isJsonArray() ) if ( value.isJsonArray() )
{ {
components = context.deserialize( contents, BaseComponent[].class ); components = context.deserialize( value, BaseComponent[].class );
} else } else
{ {
components = new BaseComponent[] components = new BaseComponent[]
{ {
context.deserialize( contents, BaseComponent.class ) context.deserialize( value, BaseComponent.class )
}; };
} }
hoverEvent = new HoverEvent( action, components ); hoverEvent = new HoverEvent( action, components );
} else if ( event.has( "contents" ) ) } else
{
JsonElement contents = hoverEventJson.get( "contents" );
if ( contents != null )
{ {
JsonElement contents = event.get( "contents" );
Content[] list; Content[] list;
if ( contents.isJsonArray() ) if ( contents.isJsonArray() )
{ {
@ -77,6 +79,7 @@ public class BaseComponentSerializer
} }
hoverEvent = new HoverEvent( action, new ArrayList<>( Arrays.asList( list ) ) ); hoverEvent = new HoverEvent( action, new ArrayList<>( Arrays.asList( list ) ) );
} }
}
if ( hoverEvent != null ) if ( hoverEvent != null )
{ {
@ -84,9 +87,10 @@ public class BaseComponentSerializer
} }
} }
if ( object.has( "extra" ) ) JsonElement extra = object.get( "extra" );
if ( extra != null )
{ {
component.setExtra( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "extra" ), BaseComponent[].class ) ) ); component.setExtra( Arrays.asList( context.deserialize( extra, BaseComponent[].class ) ) );
} }
} }

View File

@ -9,6 +9,7 @@ import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Map;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ComponentStyle; import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.ComponentStyleBuilder; import net.md_5.bungee.api.chat.ComponentStyleBuilder;
@ -62,7 +63,7 @@ public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>,
{ {
object.addProperty( "obfuscated", style.isObfuscatedRaw() ); object.addProperty( "obfuscated", style.isObfuscatedRaw() );
} }
if ( style.hasColor() ) if ( style.hasColor() && style.getColor().getColor() != null )
{ {
object.addProperty( "color", style.getColor().getName() ); object.addProperty( "color", style.getColor().getName() );
} }
@ -77,33 +78,34 @@ public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>,
{ {
ComponentStyleBuilder builder = ComponentStyle.builder(); ComponentStyleBuilder builder = ComponentStyle.builder();
JsonObject object = json.getAsJsonObject(); JsonObject object = json.getAsJsonObject();
if ( object.has( "bold" ) ) for ( Map.Entry<String, JsonElement> entry : object.entrySet() )
{ {
builder.bold( getAsBoolean( object.get( "bold" ) ) ); String name = entry.getKey();
JsonElement value = entry.getValue();
switch ( name )
{
case "bold":
builder.bold( getAsBoolean( value ) );
break;
case "italic":
builder.italic( getAsBoolean( value ) );
break;
case "underlined":
builder.underlined( getAsBoolean( value ) );
break;
case "strikethrough":
builder.strikethrough( getAsBoolean( value ) );
break;
case "obfuscated":
builder.obfuscated( getAsBoolean( value ) );
break;
case "color":
builder.color( ChatColor.of( value.getAsString() ) );
break;
case "font":
builder.font( value.getAsString() );
break;
} }
if ( object.has( "italic" ) )
{
builder.italic( getAsBoolean( object.get( "italic" ) ) );
}
if ( object.has( "underlined" ) )
{
builder.underlined( getAsBoolean( object.get( "underlined" ) ) );
}
if ( object.has( "strikethrough" ) )
{
builder.strikethrough( getAsBoolean( object.get( "strikethrough" ) ) );
}
if ( object.has( "obfuscated" ) )
{
builder.obfuscated( getAsBoolean( object.get( "obfuscated" ) ) );
}
if ( object.has( "color" ) )
{
builder.color( ChatColor.of( object.get( "color" ).getAsString() ) );
}
if ( object.has( "font" ) )
{
builder.font( object.get( "font" ).getAsString() );
} }
return builder.build(); return builder.build();
} }

View File

@ -17,13 +17,14 @@ public class KeybindComponentSerializer extends BaseComponentSerializer implemen
public KeybindComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException public KeybindComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{ {
JsonObject object = json.getAsJsonObject(); JsonObject object = json.getAsJsonObject();
if ( !object.has( "keybind" ) ) JsonElement keybind = object.get( "keybind" );
if ( keybind == null )
{ {
throw new JsonParseException( "Could not parse JSON: missing 'keybind' property" ); throw new JsonParseException( "Could not parse JSON: missing 'keybind' property" );
} }
KeybindComponent component = new KeybindComponent(); KeybindComponent component = new KeybindComponent();
deserialize( object, component, context ); deserialize( object, component, context );
component.setKeybind( object.get( "keybind" ).getAsString() ); component.setKeybind( keybind.getAsString() );
return component; return component;
} }

View File

@ -17,22 +17,29 @@ public class ScoreComponentSerializer extends BaseComponentSerializer implements
public ScoreComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException public ScoreComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{ {
JsonObject json = element.getAsJsonObject(); JsonObject json = element.getAsJsonObject();
if ( !json.has( "score" ) ) JsonObject score = json.getAsJsonObject( "score" );
if ( score == null )
{ {
throw new JsonParseException( "Could not parse JSON: missing 'score' property" ); throw new JsonParseException( "Could not parse JSON: missing 'score' property" );
} }
JsonObject score = json.get( "score" ).getAsJsonObject(); JsonElement nameJson = score.get( "name" );
if ( !score.has( "name" ) || !score.has( "objective" ) ) if ( nameJson == null )
{
throw new JsonParseException( "A score component needs at least a name (and an objective)" );
}
JsonElement objectiveJson = score.get( "objective" );
if ( objectiveJson == null )
{ {
throw new JsonParseException( "A score component needs at least a name and an objective" ); throw new JsonParseException( "A score component needs at least a name and an objective" );
} }
String name = score.get( "name" ).getAsString(); String name = nameJson.getAsString();
String objective = score.get( "objective" ).getAsString(); String objective = objectiveJson.getAsString();
ScoreComponent component = new ScoreComponent( name, objective ); ScoreComponent component = new ScoreComponent( name, objective );
if ( score.has( "value" ) && !score.get( "value" ).getAsString().isEmpty() ) JsonElement value = score.get( "value" );
if ( value != null && !value.getAsString().isEmpty() )
{ {
component.setValue( score.get( "value" ).getAsString() ); component.setValue( value.getAsString() );
} }
deserialize( json, component, context ); deserialize( json, component, context );

View File

@ -17,15 +17,17 @@ public class SelectorComponentSerializer extends BaseComponentSerializer impleme
public SelectorComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException public SelectorComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{ {
JsonObject object = element.getAsJsonObject(); JsonObject object = element.getAsJsonObject();
if ( !object.has( "selector" ) ) JsonElement selector = object.get( "selector" );
if ( selector == null )
{ {
throw new JsonParseException( "Could not parse JSON: missing 'selector' property" ); throw new JsonParseException( "Could not parse JSON: missing 'selector' property" );
} }
SelectorComponent component = new SelectorComponent( object.get( "selector" ).getAsString() ); SelectorComponent component = new SelectorComponent( selector.getAsString() );
if ( object.has( "separator" ) ) JsonElement separator = object.get( "separator" );
if ( separator != null )
{ {
component.setSeparator( ComponentSerializer.deserialize( object.get( "separator" ).getAsString() ) ); component.setSeparator( ComponentSerializer.deserialize( separator.getAsString() ) );
} }
deserialize( object, component, context ); deserialize( object, component, context );

View File

@ -18,9 +18,10 @@ public class TextComponentSerializer extends BaseComponentSerializer implements
{ {
TextComponent component = new TextComponent(); TextComponent component = new TextComponent();
JsonObject object = json.getAsJsonObject(); JsonObject object = json.getAsJsonObject();
if ( object.has( "text" ) ) JsonElement text = object.get( "text" );
if ( text != null )
{ {
component.setText( object.get( "text" ).getAsString() ); component.setText( text.getAsString() );
} }
deserialize( object, component, context ); deserialize( object, component, context );
return component; return component;

View File

@ -21,18 +21,21 @@ public class TranslatableComponentSerializer extends BaseComponentSerializer imp
TranslatableComponent component = new TranslatableComponent(); TranslatableComponent component = new TranslatableComponent();
JsonObject object = json.getAsJsonObject(); JsonObject object = json.getAsJsonObject();
deserialize( object, component, context ); deserialize( object, component, context );
if ( !object.has( "translate" ) ) JsonElement translate = object.get( "translate" );
if ( translate == null )
{ {
throw new JsonParseException( "Could not parse JSON: missing 'translate' property" ); throw new JsonParseException( "Could not parse JSON: missing 'translate' property" );
} }
component.setTranslate( object.get( "translate" ).getAsString() ); component.setTranslate( translate.getAsString() );
if ( object.has( "with" ) ) JsonElement with = object.get( "with" );
if ( with != null )
{ {
component.setWith( Arrays.asList( context.deserialize( object.get( "with" ), BaseComponent[].class ) ) ); component.setWith( Arrays.asList( context.deserialize( with, BaseComponent[].class ) ) );
} }
if ( object.has( "fallback" ) ) JsonElement fallback = object.get( "fallback" );
if ( fallback != null )
{ {
component.setFallback( object.get( "fallback" ).getAsString() ); component.setFallback( fallback.getAsString() );
} }
return component; return component;
} }

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.chat; package net.md_5.bungee.api.chat;
import static net.md_5.bungee.api.ChatColor.*;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import java.awt.Color; import java.awt.Color;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@ -7,7 +8,6 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.ObjIntConsumer; import java.util.function.ObjIntConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.hover.content.Entity; import net.md_5.bungee.api.chat.hover.content.Entity;
import net.md_5.bungee.api.chat.hover.content.Text; import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.ComponentSerializer;
@ -20,14 +20,14 @@ public class ComponentsTest
{ {
String json = ComponentSerializer.toString( components ); String json = ComponentSerializer.toString( components );
BaseComponent[] parsed = ComponentSerializer.parse( json ); BaseComponent[] parsed = ComponentSerializer.parse( json );
assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) ); assertEquals( BaseComponent.toLegacyText( parsed ), BaseComponent.toLegacyText( components ) );
} }
public static void testDissembleReassemble(BaseComponent component) public static void testDissembleReassemble(BaseComponent component)
{ {
String json = ComponentSerializer.toString( component ); String json = ComponentSerializer.toString( component );
BaseComponent[] parsed = ComponentSerializer.parse( json ); BaseComponent[] parsed = ComponentSerializer.parse( json );
assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( component ) ); assertEquals( BaseComponent.toLegacyText( parsed ), BaseComponent.toLegacyText( component ) );
} }
public static void testAssembleDissemble(String json, boolean modern) public static void testAssembleDissemble(String json, boolean modern)
@ -100,7 +100,7 @@ public class ComponentsTest
@Test @Test
public void testEmptyComponentBuilderCreate() public void testEmptyComponentBuilderCreate()
{ {
this.testEmptyComponentBuilder( testEmptyComponentBuilder(
ComponentBuilder::create, ComponentBuilder::create,
(components) -> assertEquals( components.length, 0 ), (components) -> assertEquals( components.length, 0 ),
(components, size) -> assertEquals( size, components.length ) (components, size) -> assertEquals( size, components.length )
@ -110,14 +110,14 @@ public class ComponentsTest
@Test @Test
public void testEmptyComponentBuilderBuild() public void testEmptyComponentBuilderBuild()
{ {
this.testEmptyComponentBuilder( testEmptyComponentBuilder(
ComponentBuilder::build, ComponentBuilder::build,
(component) -> assertNull( component.getExtra() ), (component) -> assertNull( component.getExtra() ),
(component, size) -> assertEquals( component.getExtra().size(), size ) (component, size) -> assertEquals( component.getExtra().size(), size )
); );
} }
private <T> void testEmptyComponentBuilder(Function<ComponentBuilder, T> componentBuilder, Consumer<T> emptyAssertion, ObjIntConsumer<T> sizedAssertion) private static <T> void testEmptyComponentBuilder(Function<ComponentBuilder, T> componentBuilder, Consumer<T> emptyAssertion, ObjIntConsumer<T> sizedAssertion)
{ {
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
@ -137,9 +137,9 @@ public class ComponentsTest
{ {
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
assertNotNull( builder.getCurrentComponent() ); assertNotNull( builder.getCurrentComponent() );
builder.color( ChatColor.GREEN ); builder.color( GREEN );
builder.append( "test ", ComponentBuilder.FormatRetention.ALL ); builder.append( "test ", ComponentBuilder.FormatRetention.ALL );
assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN ); assertEquals( builder.getCurrentComponent().getColor(), GREEN );
} }
@Test @Test
@ -155,6 +155,17 @@ public class ComponentsTest
assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 1 ) ); assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 1 ) );
} }
@Test
public void testFormatNotColor()
{
BaseComponent[] component = new ComponentBuilder().color( BOLD ).append( "Test" ).create();
String json = ComponentSerializer.toString( component );
BaseComponent[] parsed = ComponentSerializer.parse( json );
assertNull( parsed[0].getColorRaw(), "Format should not be preserved as color" );
}
@Test @Test
public void testComponentParting() public void testComponentParting()
{ {
@ -176,8 +187,8 @@ public class ComponentsTest
@Test @Test
public void testToLegacyFromLegacy() public void testToLegacyFromLegacy()
{ {
String text = "§a§lHello §f§kworld§7!"; String text = "" + GREEN + BOLD + "Hello " + WHITE + MAGIC + "world" + GRAY + "!";
assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) ); assertEquals( text, BaseComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) );
} }
@Test @Test
@ -218,7 +229,7 @@ public class ComponentsTest
@Test @Test
public void testLegacyComponentBuilderAppend() public void testLegacyComponentBuilderAppend()
{ {
String text = "§a§lHello §r§kworld§7!"; String text = "" + GREEN + BOLD + "Hello " + RESET + MAGIC + "world" + GRAY + "!";
BaseComponent[] components = TextComponent.fromLegacyText( text ); BaseComponent[] components = TextComponent.fromLegacyText( text );
BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create(); BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create();
assertArrayEquals( components, builderComponents ); assertArrayEquals( components, builderComponents );
@ -337,20 +348,20 @@ public class ComponentsTest
@Test @Test
public void testFormatRetentionCopyFormattingCreate() public void testFormatRetentionCopyFormattingCreate()
{ {
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) ); testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
} }
@Test @Test
public void testFormatRetentionCopyFormattingBuild() public void testFormatRetentionCopyFormattingBuild()
{ {
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Test" ).build() ) ) ); testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Test" ).build() ) ) );
} }
private void testFormatRetentionCopyFormatting(Supplier<HoverEvent> hoverEventSupplier) private static void testFormatRetentionCopyFormatting(Supplier<HoverEvent> hoverEventSupplier)
{ {
TextComponent first = new TextComponent( "Hello" ); TextComponent first = new TextComponent( "Hello" );
first.setBold( true ); first.setBold( true );
first.setColor( ChatColor.RED ); first.setColor( RED );
first.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "test" ) ); first.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "test" ) );
first.setHoverEvent( hoverEventSupplier.get() ); first.setHoverEvent( hoverEventSupplier.get() );
@ -365,18 +376,18 @@ public class ComponentsTest
@Test @Test
public void testBuilderCloneCreate() public void testBuilderCloneCreate()
{ {
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.create() ) ); testBuilderClone( (builder) -> BaseComponent.toLegacyText( builder.create() ) );
} }
@Test @Test
public void testBuilderCloneBuild() public void testBuilderCloneBuild()
{ {
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.build() ) ); testBuilderClone( (builder) -> BaseComponent.toLegacyText( builder.build() ) );
} }
private void testBuilderClone(Function<ComponentBuilder, String> legacyTextFunction) private static void testBuilderClone(Function<ComponentBuilder, String> legacyTextFunction)
{ {
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED ); ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( RED ).append( "world" ).color( DARK_RED );
ComponentBuilder cloned = new ComponentBuilder( builder ); ComponentBuilder cloned = new ComponentBuilder( builder );
assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) ); assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) );
@ -385,7 +396,7 @@ public class ComponentsTest
@Test @Test
public void testBuilderAppendCreateMixedComponents() public void testBuilderAppendCreateMixedComponents()
{ {
this.testBuilderAppendMixedComponents( testBuilderAppendMixedComponents(
ComponentBuilder::create, ComponentBuilder::create,
(components, index) -> components[index] (components, index) -> components[index]
); );
@ -394,13 +405,13 @@ public class ComponentsTest
@Test @Test
public void testBuilderAppendBuildMixedComponents() public void testBuilderAppendBuildMixedComponents()
{ {
this.testBuilderAppendMixedComponents( testBuilderAppendMixedComponents(
ComponentBuilder::build, ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ) (component, index) -> component.getExtra().get( index )
); );
} }
private <T> void testBuilderAppendMixedComponents(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter) private static <T> void testBuilderAppendMixedComponents(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{ {
ComponentBuilder builder = new ComponentBuilder( "Hello " ); ComponentBuilder builder = new ComponentBuilder( "Hello " );
TextComponent textComponent = new TextComponent( "world " ); TextComponent textComponent = new TextComponent( "world " );
@ -443,12 +454,12 @@ public class ComponentsTest
@Test @Test
public void testBuilderAppendCreate() public void testBuilderAppendCreate()
{ {
this.testBuilderAppend( testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() ), () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() ),
ComponentBuilder::create, ComponentBuilder::create,
(components, index) -> components[index], (components, index) -> components[index],
BaseComponent::toPlainText, BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", YELLOW + "Hello " + GREEN + "world!",
BaseComponent::toLegacyText BaseComponent::toLegacyText
); );
} }
@ -456,24 +467,24 @@ public class ComponentsTest
@Test @Test
public void testBuilderAppendBuild() public void testBuilderAppendBuild()
{ {
this.testBuilderAppend( testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Hello world" ).build() ) ), () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Hello world" ).build() ) ),
ComponentBuilder::build, ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ), (component, index) -> component.getExtra().get( index ),
(component) -> BaseComponent.toPlainText( component ), (component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component // An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", WHITE.toString() + YELLOW + "Hello " + GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component ) (component) -> BaseComponent.toLegacyText( component )
); );
} }
private <T> void testBuilderAppend(Supplier<HoverEvent> hoverEventSupplier, Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter, Function<T, String> toPlainTextFunction, String expectedLegacyText, Function<T, String> toLegacyTextFunction) private static <T> void testBuilderAppend(Supplier<HoverEvent> hoverEventSupplier, Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter, Function<T, String> toPlainTextFunction, String expectedLegacyText, Function<T, String> toLegacyTextFunction)
{ {
ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " ); ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " );
HoverEvent hoverEvent = hoverEventSupplier.get(); HoverEvent hoverEvent = hoverEventSupplier.get();
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW ); ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( YELLOW );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() ); // Intentionally using create() to append multiple individual components builder.append( new ComponentBuilder( "world!" ).color( GREEN ).event( hoverEvent ).event( clickEvent ).create() ); // Intentionally using create() to append multiple individual components
T component = componentBuilder.apply( builder ); T component = componentBuilder.apply( builder );
@ -486,10 +497,10 @@ public class ComponentsTest
@Test @Test
public void testBuilderAppendLegacyCreate() public void testBuilderAppendLegacyCreate()
{ {
this.testBuilderAppendLegacy( testBuilderAppendLegacy(
ComponentBuilder::create, ComponentBuilder::create,
BaseComponent::toPlainText, BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", YELLOW + "Hello " + GREEN + "world!",
BaseComponent::toLegacyText BaseComponent::toLegacyText
); );
} }
@ -497,19 +508,19 @@ public class ComponentsTest
@Test @Test
public void testBuilderAppendLegacyBuild() public void testBuilderAppendLegacyBuild()
{ {
this.testBuilderAppendLegacy( testBuilderAppendLegacy(
ComponentBuilder::build, ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ), (component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component // An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", WHITE.toString() + YELLOW + "Hello " + GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component ) (component) -> BaseComponent.toLegacyText( component )
); );
} }
private <T> void testBuilderAppendLegacy(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction) private static <T> void testBuilderAppendLegacy(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction)
{ {
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW ); ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( YELLOW );
builder.appendLegacy( "§aworld!" ); builder.appendLegacy( GREEN + "world!" );
T component = componentBuilder.apply( builder ); T component = componentBuilder.apply( builder );
@ -521,26 +532,26 @@ public class ComponentsTest
public void testBasicComponent() public void testBasicComponent()
{ {
TextComponent textComponent = new TextComponent( "Hello world" ); TextComponent textComponent = new TextComponent( "Hello world" );
textComponent.setColor( ChatColor.RED ); textComponent.setColor( RED );
assertEquals( "Hello world", textComponent.toPlainText() ); assertEquals( "Hello world", textComponent.toPlainText() );
assertEquals( ChatColor.RED + "Hello world", textComponent.toLegacyText() ); assertEquals( RED + "Hello world", textComponent.toLegacyText() );
} }
@Test @Test
public void testLegacyConverter() public void testLegacyConverter()
{ {
BaseComponent[] test1 = TextComponent.fromLegacyText( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold" ); BaseComponent[] test1 = TextComponent.fromLegacyText( AQUA + "Aqua " + RED + BOLD + "RedBold" );
assertEquals( "Aqua RedBold", BaseComponent.toPlainText( test1 ) ); assertEquals( "Aqua RedBold", BaseComponent.toPlainText( test1 ) );
assertEquals( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold", BaseComponent.toLegacyText( test1 ) ); assertEquals( AQUA + "Aqua " + RED + BOLD + "RedBold", BaseComponent.toLegacyText( test1 ) );
BaseComponent[] test2 = TextComponent.fromLegacyText( "Text http://spigotmc.org " + ChatColor.GREEN + "google.com/test" ); BaseComponent[] test2 = TextComponent.fromLegacyText( "Text http://spigotmc.org " + GREEN + "google.com/test" );
assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) ); assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) );
//The extra ChatColor instances are sometimes inserted when not needed but it doesn't change the result //The extra ChatColor instances are sometimes inserted when not needed but it doesn't change the result
assertEquals( ChatColor.WHITE + "Text " + ChatColor.WHITE + "http://spigotmc.org" + ChatColor.WHITE assertEquals( WHITE + "Text " + WHITE + "http://spigotmc.org" + WHITE
+ " " + ChatColor.GREEN + "google.com/test" + ChatColor.GREEN, BaseComponent.toLegacyText( test2 ) ); + " " + GREEN + "google.com/test" + GREEN, BaseComponent.toLegacyText( test2 ) );
ClickEvent url1 = test2[1].getClickEvent(); ClickEvent url1 = test2[1].getClickEvent();
assertNotNull( url1 ); assertNotNull( url1 );
@ -553,36 +564,13 @@ public class ComponentsTest
assertEquals( "http://google.com/test", url2.getValue() ); assertEquals( "http://google.com/test", url2.getValue() );
} }
@Test
public void testTranslateComponent()
{
TranslatableComponent item = new TranslatableComponent( "item.swordGold.name" );
item.setColor( ChatColor.AQUA );
TranslatableComponent translatableComponent = new TranslatableComponent( "commands.give.success",
item, "5",
"thinkofdeath" );
assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() );
assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE
+ " * " + ChatColor.WHITE + "5" + ChatColor.WHITE + " to " + ChatColor.WHITE + "thinkofdeath",
translatableComponent.toLegacyText() );
TranslatableComponent positional = new TranslatableComponent( "book.pageIndicator", "5", "50" );
assertEquals( "Page 5 of 50", positional.toPlainText() );
assertEquals( ChatColor.WHITE + "Page " + ChatColor.WHITE + "5" + ChatColor.WHITE + " of " + ChatColor.WHITE + "50", positional.toLegacyText() );
TranslatableComponent one_four_two = new TranslatableComponent( "filled_map.buried_treasure" );
assertEquals( "Buried Treasure Map", one_four_two.toPlainText() );
}
@Test @Test
public void testBuilderCreate() public void testBuilderCreate()
{ {
this.testBuilder( testBuilder(
ComponentBuilder::create, ComponentBuilder::create,
BaseComponent::toPlainText, BaseComponent::toPlainText,
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!", RED + "Hello " + BLUE + BOLD + "World" + YELLOW + BOLD + "!",
BaseComponent::toLegacyText BaseComponent::toLegacyText
); );
} }
@ -590,20 +578,20 @@ public class ComponentsTest
@Test @Test
public void testBuilderBuild() public void testBuilderBuild()
{ {
this.testBuilder( testBuilder(
ComponentBuilder::build, ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ), (component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component // An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!", WHITE.toString() + RED + "Hello " + BLUE + BOLD + "World" + YELLOW + BOLD + "!",
(component) -> BaseComponent.toLegacyText( component ) (component) -> BaseComponent.toLegacyText( component )
); );
} }
private <T> void testBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction) private static <T> void testBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction)
{ {
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ). T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( RED ).
append( "World" ).bold( true ).color( ChatColor.BLUE ). append( "World" ).bold( true ).color( BLUE ).
append( "!" ).color( ChatColor.YELLOW ) ); append( "!" ).color( YELLOW ) );
assertEquals( "Hello World!", toPlainTextFunction.apply( component ) ); assertEquals( "Hello World!", toPlainTextFunction.apply( component ) );
assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) ); assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
@ -612,7 +600,7 @@ public class ComponentsTest
@Test @Test
public void testBuilderCreateReset() public void testBuilderCreateReset()
{ {
this.testBuilderReset( testBuilderReset(
ComponentBuilder::create, ComponentBuilder::create,
(components, index) -> components[index] (components, index) -> components[index]
); );
@ -621,25 +609,25 @@ public class ComponentsTest
@Test @Test
public void testBuilderBuildReset() public void testBuilderBuildReset()
{ {
this.testBuilderReset( testBuilderReset(
ComponentBuilder::build, ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ) (component, index) -> component.getExtra().get( index )
); );
} }
private <T> void testBuilderReset(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter) private static <T> void testBuilderReset(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{ {
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( RED )
.append( "World" ).reset() ); .append( "World" ).reset() );
assertEquals( ChatColor.RED, extraGetter.apply( component, 0 ).getColor() ); assertEquals( RED, extraGetter.apply( component, 0 ).getColor() );
assertEquals( ChatColor.WHITE, extraGetter.apply( component, 1 ).getColor() ); assertEquals( WHITE, extraGetter.apply( component, 1 ).getColor() );
} }
@Test @Test
public void testBuilderCreateFormatRetention() public void testBuilderCreateFormatRetention()
{ {
this.testBuilderFormatRetention( testBuilderFormatRetention(
ComponentBuilder::create, ComponentBuilder::create,
(components, index) -> components[index] (components, index) -> components[index]
); );
@ -648,39 +636,39 @@ public class ComponentsTest
@Test @Test
public void testBuilderBuildFormatRetention() public void testBuilderBuildFormatRetention()
{ {
this.testBuilderFormatRetention( testBuilderFormatRetention(
ComponentBuilder::build, ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ) (component, index) -> component.getExtra().get( index )
); );
} }
private <T> void testBuilderFormatRetention(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter) private static <T> void testBuilderFormatRetention(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{ {
T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ) ); .append( "World", ComponentBuilder.FormatRetention.NONE ) );
assertEquals( ChatColor.RED, extraGetter.apply( noneRetention, 0 ).getColor() ); assertEquals( RED, extraGetter.apply( noneRetention, 0 ).getColor() );
assertEquals( ChatColor.WHITE, extraGetter.apply( noneRetention, 1 ).getColor() ); assertEquals( WHITE, extraGetter.apply( noneRetention, 1 ).getColor() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) ); HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) );
T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) ); .event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) );
assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 0 ).getColor() ); assertEquals( RED, extraGetter.apply( formattingRetention, 0 ).getColor() );
assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() ); assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() );
assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 1 ).getColor() ); assertEquals( RED, extraGetter.apply( formattingRetention, 1 ).getColor() );
assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() ); assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() );
ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" ); ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" );
T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) ); .event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) );
assertEquals( ChatColor.RED, extraGetter.apply( eventRetention, 0 ).getColor() ); assertEquals( RED, extraGetter.apply( eventRetention, 0 ).getColor() );
assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() ); assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() );
assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() ); assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() );
assertEquals( ChatColor.WHITE, extraGetter.apply( eventRetention, 1 ).getColor() ); assertEquals( WHITE, extraGetter.apply( eventRetention, 1 ).getColor() );
assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() ); assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() );
assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() ); assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() );
} }
@ -698,9 +686,9 @@ public class ComponentsTest
{ {
TextComponent a = new TextComponent( "A" ); TextComponent a = new TextComponent( "A" );
TextComponent b = new TextComponent( "B" ); TextComponent b = new TextComponent( "B" );
b.setColor( ChatColor.AQUA ); b.setColor( AQUA );
TextComponent c = new TextComponent( "C" ); TextComponent c = new TextComponent( "C" );
c.setColor( ChatColor.RED ); c.setColor( RED );
a.addExtra( b ); a.addExtra( b );
b.addExtra( c ); b.addExtra( c );
c.addExtra( a ); c.addExtra( a );
@ -712,7 +700,7 @@ public class ComponentsTest
{ {
TextComponent a = new TextComponent( "A" ); TextComponent a = new TextComponent( "A" );
TextComponent b = new TextComponent( "B" ); TextComponent b = new TextComponent( "B" );
b.setColor( ChatColor.AQUA ); b.setColor( AQUA );
a.addExtra( b ); a.addExtra( b );
a.addExtra( b ); a.addExtra( b );
ComponentSerializer.toString( a ); ComponentSerializer.toString( a );
@ -723,9 +711,9 @@ public class ComponentsTest
{ {
TextComponent a = new TextComponent( "A" ); TextComponent a = new TextComponent( "A" );
TextComponent b = new TextComponent( "B" ); TextComponent b = new TextComponent( "B" );
b.setColor( ChatColor.AQUA ); b.setColor( AQUA );
TextComponent c = new TextComponent( "C" ); TextComponent c = new TextComponent( "C" );
c.setColor( ChatColor.RED ); c.setColor( RED );
a.addExtra( b ); a.addExtra( b );
a.addExtra( c ); a.addExtra( c );
c.addExtra( a ); c.addExtra( a );
@ -741,15 +729,15 @@ public class ComponentsTest
// collect all invalid color codes (e.g. §z, §g, ...) // collect all invalid color codes (e.g. §z, §g, ...)
for ( char alphChar : "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray() ) for ( char alphChar : "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray() )
{ {
if ( ChatColor.ALL_CODES.indexOf( alphChar ) == -1 ) if ( ALL_CODES.indexOf( alphChar ) == -1 )
{ {
allInvalidColorCodes.append( ChatColor.COLOR_CHAR ); allInvalidColorCodes.append( COLOR_CHAR );
allInvalidColorCodes.append( alphChar ); allInvalidColorCodes.append( alphChar );
} }
} }
// last char is a single '§' // last char is a single '§'
allInvalidColorCodes.append( ChatColor.COLOR_CHAR ); allInvalidColorCodes.append( COLOR_CHAR );
String invalidColorCodesLegacyText = fromAndToLegacyText( allInvalidColorCodes.toString() ); String invalidColorCodesLegacyText = fromAndToLegacyText( allInvalidColorCodes.toString() );
String emptyLegacyText = fromAndToLegacyText( "" ); String emptyLegacyText = fromAndToLegacyText( "" );
@ -761,10 +749,10 @@ public class ComponentsTest
@Test @Test
public void testFormattingOnlyTextConversion() public void testFormattingOnlyTextConversion()
{ {
String text = "§a"; String text = "" + GREEN;
BaseComponent[] converted = TextComponent.fromLegacyText( text ); BaseComponent[] converted = TextComponent.fromLegacyText( text );
assertEquals( ChatColor.GREEN, converted[0].getColor() ); assertEquals( GREEN, converted[0].getColor() );
String roundtripLegacyText = BaseComponent.toLegacyText( converted ); String roundtripLegacyText = BaseComponent.toLegacyText( converted );
@ -799,8 +787,8 @@ public class ComponentsTest
@Test @Test
public void testLegacyHack() public void testLegacyHack()
{ {
BaseComponent[] hexColored = new ComponentBuilder().color( ChatColor.of( Color.GRAY ) ).append( "Test" ).create(); BaseComponent[] hexColored = new ComponentBuilder().color( of( Color.GRAY ) ).append( "Test" ).create();
String legacy = TextComponent.toLegacyText( hexColored ); String legacy = BaseComponent.toLegacyText( hexColored );
BaseComponent[] reColored = TextComponent.fromLegacyText( legacy ); BaseComponent[] reColored = TextComponent.fromLegacyText( legacy );
@ -810,7 +798,7 @@ public class ComponentsTest
@Test @Test
public void testLegacyResetInBuilderCreate() public void testLegacyResetInBuilderCreate()
{ {
this.testLegacyResetInBuilder( testLegacyResetInBuilder(
ComponentBuilder::create, ComponentBuilder::create,
ComponentSerializer::toString ComponentSerializer::toString
); );
@ -819,7 +807,7 @@ public class ComponentsTest
@Test @Test
public void testLegacyResetInBuilderBuild() public void testLegacyResetInBuilderBuild()
{ {
this.testLegacyResetInBuilder( testLegacyResetInBuilder(
ComponentBuilder::build, ComponentBuilder::build,
ComponentSerializer::toString ComponentSerializer::toString
); );
@ -851,10 +839,10 @@ public class ComponentsTest
* In legacy chat, colors and reset both reset all formatting. * In legacy chat, colors and reset both reset all formatting.
* Make sure it works in combination with ComponentBuilder. * Make sure it works in combination with ComponentBuilder.
*/ */
private <T> void testLegacyResetInBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> componentSerializer) private static <T> void testLegacyResetInBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> componentSerializer)
{ {
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] a = TextComponent.fromLegacyText( "§4§n44444§rdd§6§l6666" ); BaseComponent[] a = TextComponent.fromLegacyText( "" + DARK_RED + UNDERLINE + "44444" + RESET + "dd" + GOLD + BOLD + "6666" );
String expected = "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},{\"color\":" String expected = "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},{\"color\":"
+ "\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}],\"text\":\"\"}"; + "\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}],\"text\":\"\"}";
@ -865,7 +853,7 @@ public class ComponentsTest
String test1 = componentSerializer.apply( componentBuilder.apply( builder ) ); String test1 = componentSerializer.apply( componentBuilder.apply( builder ) );
assertEquals( expected, test1 ); assertEquals( expected, test1 );
BaseComponent[] b = TextComponent.fromLegacyText( "§rrrrr" ); BaseComponent[] b = TextComponent.fromLegacyText( RESET + "rrrr" );
builder.append( b ); builder.append( b );
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) ); String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.chat; package net.md_5.bungee.api.chat;
import static net.md_5.bungee.api.ChatColor.*;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.ComponentSerializer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -12,7 +13,7 @@ public class TranslatableComponentTest
{ {
TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", 2, "aoeu" ); TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", 2, "aoeu" );
assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() ); assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() );
assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() ); assertEquals( WHITE + "Test string with " + WHITE + "2" + WHITE + " placeholders: " + WHITE + "aoeu", testComponent.toLegacyText() );
} }
@Test @Test
@ -22,7 +23,29 @@ public class TranslatableComponentTest
String jsonString = ComponentSerializer.toString( testComponent ); String jsonString = ComponentSerializer.toString( testComponent );
BaseComponent[] baseComponents = ComponentSerializer.parse( jsonString ); BaseComponent[] baseComponents = ComponentSerializer.parse( jsonString );
assertEquals( "Test string with a placeholder", TextComponent.toPlainText( baseComponents ) ); assertEquals( "Test string with a placeholder", BaseComponent.toPlainText( baseComponents ) );
assertEquals( "§fTest string with §fa§f placeholder", TextComponent.toLegacyText( baseComponents ) ); assertEquals( WHITE + "Test string with " + WHITE + "a" + WHITE + " placeholder", BaseComponent.toLegacyText( baseComponents ) );
} }
@Test
public void testTranslateComponent()
{
TranslatableComponent item = new TranslatableComponent( "item.swordGold.name" );
item.setColor( AQUA );
TranslatableComponent translatableComponent = new TranslatableComponent( "commands.give.success",
item, "5", "thinkofdeath" );
assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() );
assertEquals( WHITE + "Given " + AQUA + "Golden Sword" + WHITE + " * " + WHITE + "5" + WHITE + " to " + WHITE + "thinkofdeath",
translatableComponent.toLegacyText() );
TranslatableComponent positional = new TranslatableComponent( "book.pageIndicator", "5", "50" );
assertEquals( "Page 5 of 50", positional.toPlainText() );
assertEquals( WHITE + "Page " + WHITE + "5" + WHITE + " of " + WHITE + "50", positional.toLegacyText() );
TranslatableComponent one_four_two = new TranslatableComponent( "filled_map.buried_treasure" );
assertEquals( "Buried Treasure Map", one_four_two.toPlainText() );
}
} }

View File

@ -7,6 +7,11 @@ import java.util.List;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
@ -27,6 +32,7 @@ public class CommandList extends Command implements TabExecutor
public void execute(CommandSender sender, String[] args) public void execute(CommandSender sender, String[] args)
{ {
boolean hideEmptyServers = ( args.length == 0 ) || !args[0].equalsIgnoreCase( "all" ); boolean hideEmptyServers = ( args.length == 0 ) || !args[0].equalsIgnoreCase( "all" );
boolean moduleLoaded = ProxyServer.getInstance().getPluginManager().getPlugin( "cmd_server" ) != null;
for ( ServerInfo server : ProxyServer.getInstance().getServers().values() ) for ( ServerInfo server : ProxyServer.getInstance().getServers().values() )
{ {
@ -48,7 +54,18 @@ public class CommandList extends Command implements TabExecutor
} }
Collections.sort( players, String.CASE_INSENSITIVE_ORDER ); Collections.sort( players, String.CASE_INSENSITIVE_ORDER );
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) ); BaseComponent baseComponent = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) ).build();
if ( moduleLoaded )
{
baseComponent.setHoverEvent( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new Text( new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() ) )
);
baseComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
}
sender.sendMessage( baseComponent );
} }
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) ); sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) );

View File

@ -8,7 +8,7 @@ echo "Compiling mbedtls"
echo "Compiling zlib" echo "Compiling zlib"
(cd zlib && CFLAGS=-fPIC ./configure --static && make) (cd zlib && CFLAGS=-fPIC ./configure --static && make)
CXX="g++ -shared -fPIC -Wl,--wrap=memcpy -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/" CXX="g++ -shared -fPIC -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"
$CXX -Imbedtls/include src/main/c/NativeCipherImpl.cpp -o src/main/resources/native-cipher.so mbedtls/library/libmbedcrypto.a $CXX -Imbedtls/include src/main/c/NativeCipherImpl.cpp -o src/main/resources/native-cipher.so mbedtls/library/libmbedcrypto.a
$CXX -Izlib src/main/c/NativeCompressImpl.cpp -o src/main/resources/native-compress.so zlib/libz.a $CXX -Izlib src/main/c/NativeCompressImpl.cpp -o src/main/resources/native-compress.so zlib/libz.a

@ -1 +1 @@
Subproject commit 8c89224991adff88d53cd380f42a2baa36f91454 Subproject commit 2ca6c285a0dd3f33982dd57299012dacab1ff206

View File

@ -4,12 +4,6 @@
#include <mbedtls/aes.h> #include <mbedtls/aes.h>
#include "net_md_5_bungee_jni_cipher_NativeCipherImpl.h" #include "net_md_5_bungee_jni_cipher_NativeCipherImpl.h"
// Support for CentOS 6
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
extern "C" void *__wrap_memcpy(void *dest, const void *src, size_t n) {
return memcpy(dest, src, n);
}
typedef unsigned char byte; typedef unsigned char byte;
struct crypto_context { struct crypto_context {

View File

@ -4,12 +4,6 @@
#include <zlib.h> #include <zlib.h>
#include "net_md_5_bungee_jni_zlib_NativeCompressImpl.h" #include "net_md_5_bungee_jni_zlib_NativeCompressImpl.h"
// Support for CentOS 6
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
extern "C" void *__wrap_memcpy(void *dest, const void *src, size_t n) {
return memcpy(dest, src, n);
}
typedef unsigned char byte; typedef unsigned char byte;
static jfieldID consumedID; static jfieldID consumedID;

@ -1 +1 @@
Subproject commit 4e4e4c4fbdad9dd034d8f05e2312bf845f0d4d15 Subproject commit 92530568d2c128b4432467b76a3b54d93d6350bd

10
pom.xml
View File

@ -72,7 +72,7 @@
<properties> <properties>
<build.number>unknown</build.number> <build.number>unknown</build.number>
<lombok.version>1.18.30</lombok.version> <lombok.version>1.18.32</lombok.version>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -83,7 +83,7 @@
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId> <artifactId>netty-bom</artifactId>
<version>4.1.107.Final</version> <version>4.1.109.Final</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -152,7 +152,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version> <version>3.13.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -282,7 +282,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version> <version>3.3.1</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@ -357,7 +357,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-gpg-plugin</artifactId>
<version>3.1.0</version> <version>3.2.4</version>
<executions> <executions>
<execution> <execution>
<phase>verify</phase> <phase>verify</phase>

View File

@ -51,6 +51,7 @@ import net.md_5.bungee.protocol.packet.Team;
import net.md_5.bungee.protocol.packet.Title; import net.md_5.bungee.protocol.packet.Title;
import net.md_5.bungee.protocol.packet.TitleTimes; import net.md_5.bungee.protocol.packet.TitleTimes;
import net.md_5.bungee.protocol.packet.Transfer; import net.md_5.bungee.protocol.packet.Transfer;
import net.md_5.bungee.protocol.packet.UnsignedClientCommand;
import net.md_5.bungee.protocol.packet.ViewDistance; import net.md_5.bungee.protocol.packet.ViewDistance;
public abstract class AbstractPacketHandler public abstract class AbstractPacketHandler
@ -104,6 +105,10 @@ public abstract class AbstractPacketHandler
{ {
} }
public void handle(UnsignedClientCommand command) throws Exception
{
}
public void handle(Respawn respawn) throws Exception public void handle(Respawn respawn) throws Exception
{ {
} }

View File

@ -57,6 +57,7 @@ import net.md_5.bungee.protocol.packet.Team;
import net.md_5.bungee.protocol.packet.Title; import net.md_5.bungee.protocol.packet.Title;
import net.md_5.bungee.protocol.packet.TitleTimes; import net.md_5.bungee.protocol.packet.TitleTimes;
import net.md_5.bungee.protocol.packet.Transfer; import net.md_5.bungee.protocol.packet.Transfer;
import net.md_5.bungee.protocol.packet.UnsignedClientCommand;
import net.md_5.bungee.protocol.packet.ViewDistance; import net.md_5.bungee.protocol.packet.ViewDistance;
public enum Protocol public enum Protocol
@ -444,7 +445,7 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ), map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 ), map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x62 ) map( ProtocolConstants.MINECRAFT_1_20_5, 0x55 )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
ServerData.class, ServerData.class,
@ -513,7 +514,7 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ), map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ), map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x17 ) map( ProtocolConstants.MINECRAFT_1_20_5, 0x18 )
); );
TO_SERVER.registerPacket( Chat.class, TO_SERVER.registerPacket( Chat.class,
Chat::new, Chat::new,
@ -528,13 +529,20 @@ public enum Protocol
ClientCommand.class, ClientCommand.class,
ClientCommand::new, ClientCommand::new,
map( ProtocolConstants.MINECRAFT_1_19, 0x03 ), map( ProtocolConstants.MINECRAFT_1_19, 0x03 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x04 ) map( ProtocolConstants.MINECRAFT_1_19_1, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 )
);
TO_SERVER.registerPacket(
UnsignedClientCommand.class,
UnsignedClientCommand::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
ClientChat.class, ClientChat.class,
ClientChat::new, ClientChat::new,
map( ProtocolConstants.MINECRAFT_1_19, 0x04 ), map( ProtocolConstants.MINECRAFT_1_19, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x05 ) map( ProtocolConstants.MINECRAFT_1_19_1, 0x05 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x06 )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
TabCompleteRequest.class, TabCompleteRequest.class,
@ -549,7 +557,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x09 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x08 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
ClientSettings.class, ClientSettings.class,
@ -563,7 +572,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_1, 0x08 ), map( ProtocolConstants.MINECRAFT_1_19_1, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x07 ), map( ProtocolConstants.MINECRAFT_1_19_3, 0x07 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x09 ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
PluginMessage.class, PluginMessage.class,
@ -581,17 +591,18 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ), map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ), map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ), map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 ) map( ProtocolConstants.MINECRAFT_1_20_5, 0x12 )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
StartConfiguration.class, StartConfiguration.class,
StartConfiguration::new, StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ) map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0C )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(
CookieResponse.class, CookieResponse.class,
CookieResponse::new, CookieResponse::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x10 ) map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 )
); );
} }
}, },
@ -724,12 +735,12 @@ public enum Protocol
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
StoreCookie.class, StoreCookie.class,
StoreCookie::new, StoreCookie::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x09 ) map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A )
); );
TO_CLIENT.registerPacket( TO_CLIENT.registerPacket(
Transfer.class, Transfer.class,
Transfer::new, Transfer::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A ) map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B )
); );
TO_SERVER.registerPacket( TO_SERVER.registerPacket(

View File

@ -45,7 +45,7 @@ public class ProtocolConstants
public static final int MINECRAFT_1_20 = 763; public static final int MINECRAFT_1_20 = 763;
public static final int MINECRAFT_1_20_2 = 764; public static final int MINECRAFT_1_20_2 = 764;
public static final int MINECRAFT_1_20_3 = 765; public static final int MINECRAFT_1_20_3 = 765;
public static final int MINECRAFT_1_20_5 = 1073742003; public static final int MINECRAFT_1_20_5 = 766;
public static final List<String> SUPPORTED_VERSIONS; public static final List<String> SUPPORTED_VERSIONS;
public static final List<Integer> SUPPORTED_VERSION_IDS; public static final List<Integer> SUPPORTED_VERSION_IDS;
@ -104,13 +104,14 @@ public class ProtocolConstants
ProtocolConstants.MINECRAFT_1_19_4, ProtocolConstants.MINECRAFT_1_19_4,
ProtocolConstants.MINECRAFT_1_20, ProtocolConstants.MINECRAFT_1_20,
ProtocolConstants.MINECRAFT_1_20_2, ProtocolConstants.MINECRAFT_1_20_2,
ProtocolConstants.MINECRAFT_1_20_3 ProtocolConstants.MINECRAFT_1_20_3,
ProtocolConstants.MINECRAFT_1_20_5
); );
if ( SNAPSHOT_SUPPORT ) if ( SNAPSHOT_SUPPORT )
{ {
// supportedVersions.add( "1.20.x" ); // supportedVersions.add( "1.20.x" );
supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_5 ); // supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_5 );
} }
SUPPORTED_VERSIONS = supportedVersions.build(); SUPPORTED_VERSIONS = supportedVersions.build();

View File

@ -853,7 +853,10 @@ public class Commands extends DefinedPacket
get( "minecraft:template_mirror", VOID ), get( "minecraft:template_mirror", VOID ),
get( "minecraft:template_rotation", VOID ), get( "minecraft:template_rotation", VOID ),
get( "minecraft:uuid", VOID ), get( "minecraft:uuid", VOID ),
get( "minecraft:heightmap", VOID ) get( "minecraft:heightmap", VOID ),
get( "minecraft:loot_table", VOID ),
get( "minecraft:loot_predicate", VOID ),
get( "minecraft:loot_modifier", VOID )
}; };
} }

View File

@ -37,6 +37,11 @@ public class LoginSuccess extends DefinedPacket
{ {
properties = readProperties( buf ); properties = readProperties( buf );
} }
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
{
// Whether the client should disconnect on its own if it receives invalid data from the server
buf.readBoolean();
}
} }
@Override @Override
@ -54,6 +59,12 @@ public class LoginSuccess extends DefinedPacket
{ {
writeProperties( properties, buf ); writeProperties( properties, buf );
} }
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
{
// Whether the client should disconnect on its own if it receives invalid data from the server
// Vanilla sends true so we also send true
buf.writeBoolean( true );
}
} }
@Override @Override

View File

@ -0,0 +1,38 @@
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 UnsignedClientCommand extends DefinedPacket
{
private String command;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
command = readString( buf, 256 );
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( command, buf );
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -51,6 +51,18 @@
<classifier>linux-aarch_64</classifier> <classifier>linux-aarch_64</classifier>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-transport-native-io_uring</artifactId>
<version>0.0.25.Final</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-transport-native-io_uring</artifactId>
<version>0.0.25.Final</version>
<classifier>linux-aarch_64</classifier>
</dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
@ -96,7 +108,7 @@
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version> <version>8.3.0</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<!-- add these back in as they are not exposed by the API --> <!-- add these back in as they are not exposed by the API -->

View File

@ -130,7 +130,7 @@ public class ServerConnector extends PacketHandler
channel.write( copiedHandshake ); channel.write( copiedHandshake );
channel.setProtocol( Protocol.LOGIN ); channel.setProtocol( Protocol.LOGIN );
channel.write( new LoginRequest( user.getName(), null, user.getUniqueId() ) ); channel.write( new LoginRequest( user.getName(), null, user.getRewriteId() ) );
} }
@Override @Override
@ -365,7 +365,7 @@ public class ServerConnector extends PacketHandler
} else } else
{ {
LoginResult loginProfile = user.getPendingConnection().getLoginProfile(); LoginResult loginProfile = user.getPendingConnection().getLoginProfile();
user.unsafe().sendPacket( new LoginSuccess( user.getUniqueId(), user.getName(), ( loginProfile == null ) ? null : loginProfile.getProperties() ) ); user.unsafe().sendPacket( new LoginSuccess( user.getRewriteId(), user.getName(), ( loginProfile == null ) ? null : loginProfile.getProperties() ) );
user.getCh().setEncodeProtocol( Protocol.CONFIGURATION ); user.getCh().setEncodeProtocol( Protocol.CONFIGURATION );
} }
} }

View File

@ -642,6 +642,11 @@ public final class UserConnection implements ProxiedPlayer
return getPendingConnection().getUniqueId(); return getPendingConnection().getUniqueId();
} }
public UUID getRewriteId()
{
return getPendingConnection().getRewriteId();
}
public void setSettings(ClientSettings settings) public void setSettings(ClientSettings settings)
{ {
this.settings = settings; this.settings = settings;

View File

@ -126,6 +126,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
@Getter @Getter
private UUID offlineId; private UUID offlineId;
@Getter @Getter
private UUID rewriteId;
@Getter
private LoginResult loginProfile; private LoginResult loginProfile;
@Getter @Getter
private boolean legacy; private boolean legacy;
@ -218,7 +220,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
@Override @Override
public void done(ProxyPingEvent result, Throwable error) public void done(ProxyPingEvent result, Throwable error)
{ {
if ( ch.isClosed() ) if ( ch.isClosing() )
{ {
return; return;
} }
@ -361,6 +363,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection
bungee.getPluginManager().callEvent( new PlayerHandshakeEvent( InitialHandler.this, handshake ) ); bungee.getPluginManager().callEvent( new PlayerHandshakeEvent( InitialHandler.this, handshake ) );
// return if the connection was closed during the event
if ( ch.isClosing() )
{
return;
}
switch ( handshake.getRequestedProtocol() ) switch ( handshake.getRequestedProtocol() )
{ {
case 1: case 1:
@ -468,7 +476,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) ); disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) );
return; return;
} }
if ( ch.isClosed() ) if ( ch.isClosing() )
{ {
return; return;
} }
@ -550,6 +558,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
uniqueId = offlineId; uniqueId = offlineId;
} }
rewriteId = ( bungee.config.isIpForward() ) ? uniqueId : offlineId;
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() ) if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
{ {
@ -612,7 +621,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) ); disconnect( ( reason != null ) ? reason : TextComponent.fromLegacy( bungee.getTranslation( "kick_message" ) ) );
return; return;
} }
if ( ch.isClosed() ) if ( ch.isClosing() )
{ {
return; return;
} }
@ -629,7 +638,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
if ( getVersion() < ProtocolConstants.MINECRAFT_1_20_2 ) if ( getVersion() < ProtocolConstants.MINECRAFT_1_20_2 )
{ {
unsafe.sendPacket( new LoginSuccess( getUniqueId(), getName(), ( loginProfile == null ) ? null : loginProfile.getProperties() ) ); unsafe.sendPacket( new LoginSuccess( getRewriteId(), getName(), ( loginProfile == null ) ? null : loginProfile.getProperties() ) );
ch.setProtocol( Protocol.GAME ); ch.setProtocol( Protocol.GAME );
} }
finish2(); finish2();
@ -652,28 +661,37 @@ public class InitialHandler extends PacketHandler implements PendingConnection
} }
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) ); ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
ServerInfo initialServer;
if ( bungee.getReconnectHandler() != null )
{
initialServer = bungee.getReconnectHandler().getServer( userCon );
} else
{
initialServer = AbstractReconnectHandler.getForcedHost( InitialHandler.this );
}
if ( initialServer == null )
{
initialServer = bungee.getServerInfo( listener.getDefaultServer() );
}
Callback<PostLoginEvent> complete = new Callback<PostLoginEvent>()
{
@Override
public void done(PostLoginEvent result, Throwable error)
{
// #3612: Don't progress further if disconnected during event // #3612: Don't progress further if disconnected during event
if ( ch.isClosed() ) if ( ch.isClosing() )
{ {
return; return;
} }
ServerInfo server; userCon.connect( result.getTarget(), null, true, ServerConnectEvent.Reason.JOIN_PROXY );
if ( bungee.getReconnectHandler() != null )
{
server = bungee.getReconnectHandler().getServer( userCon );
} else
{
server = AbstractReconnectHandler.getForcedHost( InitialHandler.this );
}
if ( server == null )
{
server = bungee.getServerInfo( listener.getDefaultServer() );
} }
};
userCon.connect( server, null, true, ServerConnectEvent.Reason.JOIN_PROXY ); // fire post-login event
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon, initialServer, complete ) );
} }
@Override @Override

View File

@ -42,6 +42,7 @@ import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.protocol.packet.StartConfiguration; import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.TabCompleteRequest; import net.md_5.bungee.protocol.packet.TabCompleteRequest;
import net.md_5.bungee.protocol.packet.TabCompleteResponse; import net.md_5.bungee.protocol.packet.TabCompleteResponse;
import net.md_5.bungee.protocol.packet.UnsignedClientCommand;
import net.md_5.bungee.util.AllowedCharacters; import net.md_5.bungee.util.AllowedCharacters;
public class UpstreamBridge extends PacketHandler public class UpstreamBridge extends PacketHandler
@ -84,7 +85,7 @@ public class UpstreamBridge extends PacketHandler
PlayerListItem oldPacket = new PlayerListItem(); PlayerListItem oldPacket = new PlayerListItem();
oldPacket.setAction( PlayerListItem.Action.REMOVE_PLAYER ); oldPacket.setAction( PlayerListItem.Action.REMOVE_PLAYER );
PlayerListItem.Item item = new PlayerListItem.Item(); PlayerListItem.Item item = new PlayerListItem.Item();
item.setUuid( con.getUniqueId() ); item.setUuid( con.getRewriteId() );
oldPacket.setItems( new PlayerListItem.Item[] oldPacket.setItems( new PlayerListItem.Item[]
{ {
item item
@ -93,7 +94,7 @@ public class UpstreamBridge extends PacketHandler
PlayerListItemRemove newPacket = new PlayerListItemRemove(); PlayerListItemRemove newPacket = new PlayerListItemRemove();
newPacket.setUuids( new UUID[] newPacket.setUuids( new UUID[]
{ {
con.getUniqueId() con.getRewriteId()
} ); } );
for ( ProxiedPlayer player : con.getServer().getInfo().getPlayers() ) for ( ProxiedPlayer player : con.getServer().getInfo().getPlayers() )
@ -196,6 +197,12 @@ public class UpstreamBridge extends PacketHandler
handleChat( "/" + command.getCommand() ); handleChat( "/" + command.getCommand() );
} }
@Override
public void handle(UnsignedClientCommand command) throws Exception
{
handleChat( "/" + command.getCommand() );
}
private String handleChat(String message) private String handleChat(String message)
{ {
for ( int index = 0, length = message.length(); index < length; index++ ) for ( int index = 0, length = message.length(); index < length; index++ )

View File

@ -121,13 +121,13 @@ class EntityMap_1_10 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -164,7 +164,7 @@ class EntityMap_1_10 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -173,7 +173,7 @@ class EntityMap_1_10 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_11 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -165,7 +165,7 @@ class EntityMap_1_11 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -174,7 +174,7 @@ class EntityMap_1_11 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_12 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -165,7 +165,7 @@ class EntityMap_1_12 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x1E /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x1E /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -174,7 +174,7 @@ class EntityMap_1_12 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_12_1 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -165,7 +165,7 @@ class EntityMap_1_12_1 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x1E /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x1E /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -174,7 +174,7 @@ class EntityMap_1_12_1 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_13 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -165,7 +165,7 @@ class EntityMap_1_13 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x28 /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x28 /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -174,7 +174,7 @@ class EntityMap_1_13 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -120,13 +120,13 @@ class EntityMap_1_14 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -169,7 +169,7 @@ class EntityMap_1_14 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x2B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x2B /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -178,7 +178,7 @@ class EntityMap_1_14 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -120,13 +120,13 @@ class EntityMap_1_15 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -169,7 +169,7 @@ class EntityMap_1_15 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x2B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x2B /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -178,7 +178,7 @@ class EntityMap_1_15 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -120,13 +120,13 @@ class EntityMap_1_16 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -169,7 +169,7 @@ class EntityMap_1_16 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x2C /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x2C /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -178,7 +178,7 @@ class EntityMap_1_16 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -22,7 +22,7 @@ class EntityMap_1_16_2 extends EntityMap
static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 ); static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 );
static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 ); static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 );
static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 ); static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 );
static final EntityMap_1_16_2 INSTANCE_1_20_5 = new EntityMap_1_16_2( -1, 0x36 ); static final EntityMap_1_16_2 INSTANCE_1_20_5 = new EntityMap_1_16_2( -1, 0x37 );
// //
private final int spawnPlayerId; private final int spawnPlayerId;
private final int spectateId; private final int spectateId;
@ -41,13 +41,13 @@ class EntityMap_1_16_2 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }
@ -62,7 +62,7 @@ class EntityMap_1_16_2 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == spectateId && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == spectateId )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -71,7 +71,7 @@ class EntityMap_1_16_2 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_8 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} else if ( packetId == 0x42 /* Combat Event */ ) } else if ( packetId == 0x42 /* Combat Event */ )
@ -158,7 +158,7 @@ class EntityMap_1_8 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x18 /* Spectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x18 /* Spectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -167,7 +167,7 @@ class EntityMap_1_8 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_9 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -164,7 +164,7 @@ class EntityMap_1_9 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -173,7 +173,7 @@ class EntityMap_1_9 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -121,13 +121,13 @@ class EntityMap_1_9_4 extends EntityMap
DefinedPacket.readVarInt( packet ); // Entity ID DefinedPacket.readVarInt( packet ); // Entity ID
int idLength = packet.readerIndex() - readerIndex - packetIdLength; int idLength = packet.readerIndex() - readerIndex - packetIdLength;
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; UserConnection player;
if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null ) if ( ( player = BungeeCord.getInstance().getPlayerByOfflineUUID( uuid ) ) != null )
{ {
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength + idLength ); packet.writerIndex( readerIndex + packetIdLength + idLength );
DefinedPacket.writeUUID( player.getUniqueId(), packet ); DefinedPacket.writeUUID( player.getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
break; break;
@ -164,7 +164,7 @@ class EntityMap_1_9_4 extends EntityMap
int packetId = DefinedPacket.readVarInt( packet ); int packetId = DefinedPacket.readVarInt( packet );
int packetIdLength = packet.readerIndex() - readerIndex; int packetIdLength = packet.readerIndex() - readerIndex;
if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ && !BungeeCord.getInstance().getConfig().isIpForward() ) if ( packetId == 0x1B /* Spectate : PacketPlayInSpectate */ )
{ {
UUID uuid = DefinedPacket.readUUID( packet ); UUID uuid = DefinedPacket.readUUID( packet );
ProxiedPlayer player; ProxiedPlayer player;
@ -173,7 +173,7 @@ class EntityMap_1_9_4 extends EntityMap
int previous = packet.writerIndex(); int previous = packet.writerIndex();
packet.readerIndex( readerIndex ); packet.readerIndex( readerIndex );
packet.writerIndex( readerIndex + packetIdLength ); packet.writerIndex( readerIndex + packetIdLength );
DefinedPacket.writeUUID( ( (UserConnection) player ).getPendingConnection().getOfflineId(), packet ); DefinedPacket.writeUUID( ( (UserConnection) player ).getRewriteId(), packet );
packet.writerIndex( previous ); packet.writerIndex( previous );
} }
} }

View File

@ -94,6 +94,9 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
} ); } );
channel.setRemoteAddress( newAddress ); channel.setRemoteAddress( newAddress );
} else
{
channel.close();
} }
} finally } finally
{ {

View File

@ -24,6 +24,11 @@ import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.unix.DomainSocketAddress; import io.netty.channel.unix.DomainSocketAddress;
import io.netty.handler.codec.haproxy.HAProxyMessageDecoder; import io.netty.handler.codec.haproxy.HAProxyMessageDecoder;
import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.incubator.channel.uring.IOUring;
import io.netty.incubator.channel.uring.IOUringDatagramChannel;
import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
import io.netty.incubator.channel.uring.IOUringServerSocketChannel;
import io.netty.incubator.channel.uring.IOUringSocketChannel;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -102,13 +107,28 @@ public class PipelineUtils
public static final String LEGACY_KICKER = "legacy-kick"; public static final String LEGACY_KICKER = "legacy-kick";
private static boolean epoll; private static boolean epoll;
private static boolean io_uring;
static static
{ {
if ( !PlatformDependent.isWindows() && Boolean.parseBoolean( System.getProperty( "bungee.epoll", "true" ) ) ) if ( !PlatformDependent.isWindows() )
{
// disable by default (experimental)
if ( Boolean.parseBoolean( System.getProperty( "bungee.io_uring", "false" ) ) )
{
ProxyServer.getInstance().getLogger().info( "Not on Windows, attempting to use enhanced IOUringEventLoopGroup" );
if ( io_uring = IOUring.isAvailable() )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "io_uring is enabled and working, utilising it! (experimental feature)" );
} else
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "io_uring is not working: {0}", Util.exception( IOUring.unavailabilityCause() ) );
}
}
if ( !io_uring && Boolean.parseBoolean( System.getProperty( "bungee.epoll", "true" ) ) )
{ {
ProxyServer.getInstance().getLogger().info( "Not on Windows, attempting to use enhanced EpollEventLoop" ); ProxyServer.getInstance().getLogger().info( "Not on Windows, attempting to use enhanced EpollEventLoop" );
if ( epoll = Epoll.isAvailable() ) if ( epoll = Epoll.isAvailable() )
{ {
ProxyServer.getInstance().getLogger().info( "Epoll is working, utilising it!" ); ProxyServer.getInstance().getLogger().info( "Epoll is working, utilising it!" );
@ -118,10 +138,11 @@ public class PipelineUtils
} }
} }
} }
}
public static EventLoopGroup newEventLoopGroup(int threads, ThreadFactory factory) public static EventLoopGroup newEventLoopGroup(int threads, ThreadFactory factory)
{ {
return epoll ? new EpollEventLoopGroup( threads, factory ) : new NioEventLoopGroup( threads, factory ); return io_uring ? new IOUringEventLoopGroup( threads, factory ) : epoll ? new EpollEventLoopGroup( threads, factory ) : new NioEventLoopGroup( threads, factory );
} }
public static Class<? extends ServerChannel> getServerChannel(SocketAddress address) public static Class<? extends ServerChannel> getServerChannel(SocketAddress address)
@ -133,7 +154,7 @@ public class PipelineUtils
return EpollServerDomainSocketChannel.class; return EpollServerDomainSocketChannel.class;
} }
return epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class; return io_uring ? IOUringServerSocketChannel.class : epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class;
} }
public static Class<? extends Channel> getChannel(SocketAddress address) public static Class<? extends Channel> getChannel(SocketAddress address)
@ -145,12 +166,12 @@ public class PipelineUtils
return EpollDomainSocketChannel.class; return EpollDomainSocketChannel.class;
} }
return epoll ? EpollSocketChannel.class : NioSocketChannel.class; return io_uring ? IOUringSocketChannel.class : epoll ? EpollSocketChannel.class : NioSocketChannel.class;
} }
public static Class<? extends DatagramChannel> getDatagramChannel() public static Class<? extends DatagramChannel> getDatagramChannel()
{ {
return epoll ? EpollDatagramChannel.class : NioDatagramChannel.class; return io_uring ? IOUringDatagramChannel.class : epoll ? EpollDatagramChannel.class : NioDatagramChannel.class;
} }
private static final int LOW_MARK = Integer.getInteger( "net.md_5.bungee.low_mark", 2 << 18 ); // 0.5 mb private static final int LOW_MARK = Integer.getInteger( "net.md_5.bungee.low_mark", 2 << 18 ); // 0.5 mb

View File

@ -46,7 +46,7 @@ public abstract class TabList
UserConnection player = BungeeCord.getInstance().getPlayerByOfflineUUID( playerListItem.getUuids()[i] ); UserConnection player = BungeeCord.getInstance().getPlayerByOfflineUUID( playerListItem.getUuids()[i] );
if ( player != null ) if ( player != null )
{ {
playerListItem.getUuids()[i] = player.getUniqueId(); playerListItem.getUuids()[i] = player.getRewriteId();
} }
} }
@ -72,7 +72,7 @@ public abstract class TabList
UserConnection player = BungeeCord.getInstance().getPlayerByOfflineUUID( item.getUuid() ); UserConnection player = BungeeCord.getInstance().getPlayerByOfflineUUID( item.getUuid() );
if ( player != null ) if ( player != null )
{ {
item.setUuid( player.getUniqueId() ); item.setUuid( player.getRewriteId() );
if ( item.getProperties() != null ) if ( item.getProperties() != null )
{ {