Compare commits

...

47 Commits

Author SHA1 Message Date
53b54d300f new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2024-05-08 09:51:37 +02:00
211753cc33 Add CommandsDeclareEvent to declare commands with brigadier API 2024-05-08 09:51:36 +02:00
e1999307b1 Server branding now includes the backend server name 2024-05-08 09:51:36 +02:00
eeca3a5c56 Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2024-05-08 09:51:36 +02:00
55c4157375 Change projet configuration and POM for Pandacube 2024-05-08 09:51:33 +02:00
70ad55b773 Remove modules and startup delay
We don’t need them for Pandacube
2024-05-08 09:46:40 +02:00
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
108 changed files with 1439 additions and 1920 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

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -20,25 +19,25 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-config</artifactId> <artifactId>bungeecord-config</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-event</artifactId> <artifactId>bungeecord-event</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId> <artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -0,0 +1,157 @@
package net.md_5.bungee.api.event;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.ToString;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Event called when a downstream server (on 1.13+) sends the command structure
* to a player, but before BungeeCord adds the dummy command nodes of
* registered commands.
* <p>
* BungeeCord will not overwrite the modifications made by the listeners.
*
* <h2>Usage example</h2>
* Here is a usage example of this event, to declare a command structure.
* This illustrates the commands /server and /send of Bungee.
* <pre>
* event.getRoot().addChild( LiteralArgumentBuilder.&lt;CommandSender&gt;literal( "server" )
* .requires( sender -&gt; sender.hasPermission( "bungeecord.command.server" ) )
* .executes( a -&gt; 0 )
* .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
* .suggests( SuggestionRegistry.ASK_SERVER )
* )
* .build()
* );
* event.getRoot().addChild( LiteralArgumentBuilder.&lt;CommandSender&gt;literal( "send" )
* .requires( sender -&gt; sender.hasPermission( "bungeecord.command.send" ) )
* .then( RequiredArgumentBuilder.argument( "playerName", StringArgumentType.word() )
* .suggests( SuggestionRegistry.ASK_SERVER )
* .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
* .suggests( SuggestionRegistry.ASK_SERVER )
* )
* )
* .build()
* );
* </pre>
*
* <h2>Flag a {@link CommandNode} as executable or not</h2>
* The implementation of a {@link com.mojang.brigadier.Command Command} used in
* {@link ArgumentBuilder#executes(com.mojang.brigadier.Command)} will never be
* executed. This will only tell to the client if the current node is
* executable or not.
* <ul>
* <li>
* {@code builder.executes(null)} (default) to mark the node as not
* executable.
* </li>
* <li>
* {@code builder.executes(a -> 0)}, or any non null argument, to mark
* the node as executable (the child arguments are displayed as
* optional).
* </li>
* </ul>
*
* <h2>{@link CommandNode}s suggestions management</h2>
* The implementation of a SuggestionProvider used in
* {@link RequiredArgumentBuilder#suggests(SuggestionProvider)} will never be
* executed. This will only tell to the client how to deal with the
* auto-completion of the argument.
* <ul>
* <li>
* {@code builder.suggests(null)} (default) to disable auto-completion
* for this argument.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.ALL_RECIPES)} to suggest
* Minecrafts recipes.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.AVAILABLE_SOUNDS)} to
* suggest Minecrafts default sound identifiers.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.SUMMONABLE_ENTITIES)} to
* suggest Minecrafts default summonable entities identifiers.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.ASK_SERVER)}, or any
* other non null argument, to make the Minecraft client ask
* auto-completion to the server. Any specified implementation of
* {@link SuggestionProvider} will never be executed.
* </li>
* </ul>
*
* <h2>Argument types</h2>
* When building a new argument command node using
* {@link RequiredArgumentBuilder#argument(String, ArgumentType)}, you have to
* specify an {@link ArgumentType}. You can use all subclasses of
* {@link ArgumentType} provided with brigadier (for instance,
* {@link StringArgumentType} or {@link IntegerArgumentType}), or call any
* {@code ArgumentRegistry.minecraft*()} methods to use a {@code minecraft:*}
* argument type.
*
* <h2>Limitations with brigadier API</h2>
* This event is only used for the client to show command syntax, suggest
* sub-commands and color the arguments in the chat box. The command execution
* needs to be implemented using {@link PluginManager#registerCommand(Plugin,
* Command)} and the server-side tab-completion using {@link TabCompleteEvent}
* or {@link TabExecutor}.
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CommandsDeclareEvent extends TargetedEvent
{
/**
* Wether or not the command tree is modified by this event.
*
* If this value is set to true, BungeeCord will ensure that the
* modifications made in the command tree, will be sent to the player.
* If this is false, the modifications may not be taken into account.
*
* When calling {@link #getRoot()}, this value is automatically set
* to true.
*/
@Setter(value = AccessLevel.NONE)
private boolean modified = false;
/**
* The root command node of the command structure that will be send to the
* player.
*/
private final RootCommandNode<CommandSender> root;
public CommandsDeclareEvent(Connection sender, Connection receiver, RootCommandNode<CommandSender> root)
{
super( sender, receiver );
this.root = root;
}
/**
* The root command node of the command structure that will be send to the
* player.
* @return The root command node
*/
public RootCommandNode<CommandSender> getRoot()
{
modified = true;
return root;
}
}

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

@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable;
/** /**
* Event called when a player uses tab completion. * Event called when a player uses tab completion.
* @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions.
*/ */
@Deprecated
@Data @Data
@ToString(callSuper = true) @ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -0,0 +1,85 @@
package net.md_5.bungee.api.event;
import com.google.common.base.Preconditions;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.suggestion.Suggestions;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.protocol.ProtocolConstants;
/**
* Event called when a player uses tab completion.
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class TabCompleteRequestEvent extends TargetedEvent implements Cancellable
{
/**
* Cancelled state.
*/
private boolean cancelled;
/**
* The message the player has already entered.
*/
private final String cursor;
/**
* Range corresponding to the last word of {@link #getCursor()}.
* If you want your suggestions to be compatible with 1.12 and older
* clients, you need to {@link #setSuggestions(Suggestions)} with
* a range equals to this one.
* For 1.13 and newer clients, any other range that cover any part of
* {@link #getCursor()} is fine.<br>
* To check if the client supports custom ranges, use
* {@link #supportsCustomRange()}.
*/
private final StringRange legacyCompatibleRange;
/**
* The suggestions that will be sent to the client. If this list is empty,
* the request will be forwarded to the server.
*/
private Suggestions suggestions;
public TabCompleteRequestEvent(Connection sender, Connection receiver, String cursor, StringRange legacyCompatibleRange, Suggestions suggestions)
{
super( sender, receiver );
this.cursor = cursor;
this.legacyCompatibleRange = legacyCompatibleRange;
this.suggestions = suggestions;
}
/**
* Sets the suggestions that will be sent to the client.
* If this list is empty, the request will be forwarded to the server.
* @param suggestions the new Suggestions. Cannot be null.
* @throws IllegalArgumentException if the client is on 1.12 or lower and
* {@code suggestions.getRange()} is not equals to {@link #legacyCompatibleRange}.
*/
public void setSuggestions(Suggestions suggestions)
{
Preconditions.checkNotNull( suggestions );
Preconditions.checkArgument( supportsCustomRange() || legacyCompatibleRange.equals( suggestions.getRange() ),
"Clients on 1.12 or lower versions don't support the provided range for tab-completion: " + suggestions.getRange()
+ ". Please use TabCompleteRequestEvent.getLegacyCompatibleRange() for legacy clients." );
this.suggestions = suggestions;
}
/**
* Convenient method to tell if the client supports custom range for
* suggestions.
* If the client is on 1.13 or above, this methods returns true, and any
* range can be used for {@link #setSuggestions(Suggestions)}. Otherwise,
* it returns false and the defined range must be equals to
* {@link #legacyCompatibleRange}.
* @return true if the client is on 1.13 or newer version, false otherwise.
*/
public boolean supportsCustomRange()
{
return ( (ProxiedPlayer) getSender() ).getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13;
}
}

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

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId> <artifactId>bungeecord-bootstrap</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -21,14 +20,12 @@
<properties> <properties>
<maven.deploy.skip>true</maven.deploy.skip> <maven.deploy.skip>true</maven.deploy.skip>
<maven.javadoc.skip>true</maven.javadoc.skip> <maven.javadoc.skip>true</maven.javadoc.skip>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format> <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-proxy</artifactId> <artifactId>bungeecord-proxy</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
@ -36,12 +33,12 @@
</dependencies> </dependencies>
<build> <build>
<finalName>BungeeCord</finalName> <finalName>BungeeCord-${project.version}-${build.number}</finalName>
<plugins> <plugins>
<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 +52,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

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

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

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId> <artifactId>bungeecord-config</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-event</artifactId> <artifactId>bungeecord-event</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-log</artifactId> <artifactId>bungeecord-log</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -26,7 +25,7 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-alert</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_alert</name>
<description>Provides the alert and alertraw commands</description>
</project>

View File

@ -1,47 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
import java.util.Locale;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.plugin.Command;
public class CommandAlert extends Command
{
public CommandAlert()
{
super( "alert", "bungeecord.command.alert" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length == 0 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
} else
{
StringBuilder builder = new StringBuilder();
if ( args[0].toLowerCase( Locale.ROOT ).startsWith( "&h" ) )
{
// Remove &h
args[0] = args[0].substring( 2 );
} else
{
builder.append( ProxyServer.getInstance().getTranslation( "alert" ) );
}
for ( String s : args )
{
builder.append( ChatColor.translateAlternateColorCodes( '&', s ) );
builder.append( " " );
}
String message = builder.substring( 0, builder.length() - 1 );
ProxyServer.getInstance().broadcast( TextComponent.fromLegacy( message ) );
}
}
}

View File

@ -1,56 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
import com.google.common.base.Joiner;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.chat.ComponentSerializer;
public class CommandAlertRaw extends Command
{
public CommandAlertRaw()
{
super( "alertraw", "bungeecord.command.alert" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length == 0 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
} else
{
String message = Joiner.on( ' ' ).join( args );
try
{
ProxyServer.getInstance().broadcast( ComponentSerializer.parse( message ) );
} catch ( Exception e )
{
Throwable error = e;
while ( error.getCause() != null )
{
error = error.getCause();
}
if ( sender instanceof ProxiedPlayer )
{
sender.sendMessage( new ComponentBuilder( ProxyServer.getInstance().getTranslation( "error_occurred_player" ) )
.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() )
.color( ChatColor.RED )
.create() ) )
.create()
);
} else
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "error_occurred_console", error.getMessage() ) );
}
}
}
}
}

View File

@ -1,14 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginAlert extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandAlert() );
getProxy().getPluginManager().registerCommand( this, new CommandAlertRaw() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.alert.PluginAlert
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-find</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_find</name>
<description>Provides the find command</description>
</project>

View File

@ -1,58 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import java.util.Collections;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
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.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.command.PlayerCommand;
public class CommandFind extends PlayerCommand
{
public CommandFind()
{
super( "find", "bungeecord.command.find" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 1 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null || player.getServer() == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
} else
{
boolean moduleLoaded = ProxyServer.getInstance().getPluginManager().getPlugin( "cmd_server" ) != null;
ServerInfo server = player.getServer().getInfo();
ComponentBuilder componentBuilder = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), server.getName() ) );
if ( moduleLoaded && server.canAccess( sender ) )
{
componentBuilder.event( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() )
);
componentBuilder.event( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
}
sender.sendMessage( componentBuilder.create() );
}
}
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
return args.length == 1 ? super.onTabComplete( sender, args ) : Collections.emptyList();
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginFind extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandFind() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.find.PluginFind
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-kick</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_kick</name>
<description>Provides the gkick command</description>
</project>

View File

@ -1,72 +0,0 @@
package net.md_5.bungee.module.cmd.kick;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class CommandKick extends Command implements TabExecutor
{
public CommandKick()
{
super( "gkick", "bungeecord.command.kick" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length == 0 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null )
{
sender.sendMessage( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) );
return;
}
if ( args.length == 1 )
{
player.disconnect( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "kick_message" ) ) );
} else
{
String[] reason = new String[ args.length - 1 ];
System.arraycopy( args, 1, reason, 0, reason.length );
player.disconnect( TextComponent.fromLegacy( ChatColor.translateAlternateColorCodes( '&', Joiner.on( ' ' ).join( reason ) ) ) );
}
}
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length == 1 )
{
Set<String> matches = new HashSet<>();
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
return matches;
} else
{
return ImmutableSet.of();
}
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.kick;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginKick extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandKick() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.kick.PluginKick
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-list</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_list</name>
<description>Provides the glist command</description>
</project>

View File

@ -1,62 +0,0 @@
package net.md_5.bungee.module.cmd.list;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Command to list all players connected to the proxy.
*/
public class CommandList extends Command implements TabExecutor
{
public CommandList()
{
super( "glist", "bungeecord.command.list" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
boolean hideEmptyServers = ( args.length == 0 ) || !args[0].equalsIgnoreCase( "all" );
for ( ServerInfo server : ProxyServer.getInstance().getServers().values() )
{
if ( !server.canAccess( sender ) )
{
continue;
}
Collection<ProxiedPlayer> serverPlayers = server.getPlayers();
if ( hideEmptyServers && serverPlayers.isEmpty() )
{
continue;
}
List<String> players = new ArrayList<>();
for ( ProxiedPlayer player : serverPlayers )
{
players.add( player.getDisplayName() );
}
Collections.sort( players, String.CASE_INSENSITIVE_ORDER );
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) );
}
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) );
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
return ( args.length > 1 ) ? Collections.emptyList() : Collections.singletonList( "all" );
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.list;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginList extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandList() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.list.PluginList
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-send</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_send</name>
<description>Provides the gsend command</description>
</project>

View File

@ -1,200 +0,0 @@
package net.md_5.bungee.module.cmd.send;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerConnectRequest;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class CommandSend extends Command implements TabExecutor
{
protected static class SendCallback
{
private final Map<ServerConnectRequest.Result, List<String>> results = new HashMap<>();
private final CommandSender sender;
private int count = 0;
public SendCallback(CommandSender sender)
{
this.sender = sender;
for ( ServerConnectRequest.Result result : ServerConnectRequest.Result.values() )
{
results.put( result, Collections.synchronizedList( new ArrayList<>() ) );
}
}
public void lastEntryDone()
{
sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" );
for ( Map.Entry<ServerConnectRequest.Result, List<String>> entry : results.entrySet() )
{
ComponentBuilder builder = new ComponentBuilder( "" );
if ( !entry.getValue().isEmpty() )
{
builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) );
}
builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN );
builder.append( "" + entry.getValue().size() ).bold( true );
sender.sendMessage( builder.create() );
}
}
public static class Entry implements Callback<ServerConnectRequest.Result>
{
private final SendCallback callback;
private final ProxiedPlayer player;
private final ServerInfo target;
public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target)
{
this.callback = callback;
this.player = player;
this.target = target;
this.callback.count++;
}
@Override
public void done(ServerConnectRequest.Result result, Throwable error)
{
callback.results.get( result ).add( player.getName() );
if ( result == ServerConnectRequest.Result.SUCCESS )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) );
}
if ( --callback.count == 0 )
{
callback.lastEntryDone();
}
}
}
}
public CommandSend()
{
super( "send", "bungeecord.command.send" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 2 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) );
return;
}
ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] );
if ( server == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
return;
}
List<ProxiedPlayer> targets;
if ( args[0].equalsIgnoreCase( "all" ) )
{
targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() );
} else if ( args[0].equalsIgnoreCase( "current" ) )
{
if ( !( sender instanceof ProxiedPlayer ) )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) );
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
targets = new ArrayList<>( player.getServer().getInfo().getPlayers() );
} else
{
// If we use a server name, send the entire server. This takes priority over players.
ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] );
if ( serverTarget != null )
{
targets = new ArrayList<>( serverTarget.getPlayers() );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
return;
}
targets = Collections.singletonList( player );
}
}
final SendCallback callback = new SendCallback( sender );
for ( ProxiedPlayer player : targets )
{
ServerConnectRequest request = ServerConnectRequest.builder()
.target( server )
.reason( ServerConnectEvent.Reason.COMMAND )
.callback( new SendCallback.Entry( callback, player, server ) )
.build();
player.connect( request );
}
sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() );
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length > 2 || args.length == 0 )
{
return ImmutableSet.of();
}
Set<String> matches = new HashSet<>();
if ( args.length == 1 )
{
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
if ( "all".startsWith( search ) )
{
matches.add( "all" );
}
if ( "current".startsWith( search ) )
{
matches.add( "current" );
}
} else
{
String search = args[1].toLowerCase( Locale.ROOT );
for ( String server : ProxyServer.getInstance().getServers().keySet() )
{
if ( server.toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( server );
}
}
}
return matches;
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.send;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginSend extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandSend() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.send.PluginSend
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-server</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_server</name>
<description>Provides the server command</description>
</project>

View File

@ -1,104 +0,0 @@
package net.md_5.bungee.module.cmd.server;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
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.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Command to list and switch a player between available servers.
*/
public class CommandServer extends Command implements TabExecutor
{
public CommandServer()
{
super( "server", "bungeecord.command.server" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
Map<String, ServerInfo> servers = ProxyServer.getInstance().getServers();
if ( args.length == 0 )
{
if ( sender instanceof ProxiedPlayer )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) );
}
ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) );
boolean first = true;
for ( ServerInfo server : servers.values() )
{
if ( server.canAccess( sender ) )
{
TextComponent serverTextComponent = new TextComponent( first ? server.getName() : ", " + server.getName() );
int count = server.getPlayers().size();
serverTextComponent.setHoverEvent( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() )
);
serverTextComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
serverList.append( serverTextComponent );
first = false;
}
}
sender.sendMessage( serverList.create() );
} else
{
if ( !( sender instanceof ProxiedPlayer ) )
{
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
ServerInfo server = servers.get( args[0] );
if ( server == null )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
} else if ( !server.canAccess( player ) )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server_permission" ) );
} else
{
player.connect( server, ServerConnectEvent.Reason.COMMAND );
}
}
}
@Override
public Iterable<String> onTabComplete(final CommandSender sender, final String[] args)
{
return ( args.length > 1 ) ? Collections.EMPTY_LIST : Iterables.transform( Iterables.filter( ProxyServer.getInstance().getServers().values(), new Predicate<ServerInfo>()
{
private final String lower = ( args.length == 0 ) ? "" : args[0].toLowerCase( Locale.ROOT );
@Override
public boolean apply(ServerInfo input)
{
return input.getName().toLowerCase( Locale.ROOT ).startsWith( lower ) && input.canAccess( sender );
}
} ), new Function<ServerInfo, String>()
{
@Override
public String apply(ServerInfo input)
{
return input.getName();
}
} );
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.server;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginServer extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandServer() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.server.PluginServer
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,55 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>pom</packaging>
<name>BungeeCord Modules</name>
<description>Parent project for all BungeeCord modules.</description>
<modules>
<module>cmd-alert</module>
<module>cmd-find</module>
<module>cmd-kick</module>
<module>cmd-list</module>
<module>cmd-send</module>
<module>cmd-server</module>
<module>reconnect-yaml</module>
</modules>
<properties>
<module.author>SpigotMC</module.author>
<maven.deploy.skip>true</maven.deploy.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
</properties>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
</project>

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>reconnect_yaml</name>
<description>Provides reconnect location functionality in locations.yml</description>
</project>

View File

@ -1,22 +0,0 @@
package net.md_5.bungee.module.reconnect.yaml;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginYaml extends Plugin
{
@Override
public void onEnable()
{
// TODO: Abstract this for other reconnect modules
for ( ListenerInfo info : getProxy().getConfig().getListeners() )
{
if ( !info.isForceDefault() && getProxy().getReconnectHandler() == null )
{
getProxy().setReconnectHandler( new YamlReconnectHandler() );
break;
}
}
}
}

View File

@ -1,115 +0,0 @@
package net.md_5.bungee.module.reconnect.yaml;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.util.CaseInsensitiveMap;
import org.yaml.snakeyaml.Yaml;
public class YamlReconnectHandler extends AbstractReconnectHandler
{
private final Yaml yaml = new Yaml();
private final File file = new File( "locations.yml" );
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/*========================================================================*/
private CaseInsensitiveMap<String> data;
@SuppressWarnings("unchecked")
public YamlReconnectHandler()
{
try
{
file.createNewFile();
try ( FileReader rd = new FileReader( file ) )
{
Map map = yaml.loadAs( rd, Map.class );
if ( map != null )
{
data = new CaseInsensitiveMap<>( map );
}
}
} catch ( Exception ex )
{
file.renameTo( new File( "locations.yml.old" ) );
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations, resetting them" );
}
if ( data == null )
{
data = new CaseInsensitiveMap<>();
}
}
@Override
protected ServerInfo getStoredServer(ProxiedPlayer player)
{
ServerInfo server = null;
lock.readLock().lock();
try
{
server = ProxyServer.getInstance().getServerInfo( data.get( key( player ) ) );
} finally
{
lock.readLock().unlock();
}
return server;
}
@Override
public void setServer(ProxiedPlayer player)
{
lock.writeLock().lock();
try
{
data.put( key( player ), ( player.getReconnectServer() != null ) ? player.getReconnectServer().getName() : player.getServer().getInfo().getName() );
} finally
{
lock.writeLock().unlock();
}
}
private String key(ProxiedPlayer player)
{
InetSocketAddress host = player.getPendingConnection().getVirtualHost();
return player.getName() + ";" + host.getHostString() + ":" + host.getPort();
}
@Override
public void save()
{
Map<String, String> copy = new HashMap<>();
lock.readLock().lock();
try
{
copy.putAll( data );
} finally
{
lock.readLock().unlock();
}
try ( FileWriter wr = new FileWriter( file ) )
{
yaml.dump( copy, wr );
} catch ( IOException ex )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex );
}
}
@Override
public void close()
{
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.reconnect.yaml.PluginYaml
version: ${describe}
description: ${project.description}
author: ${module.author}

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,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-native</artifactId> <artifactId>bungeecord-native</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

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

15
pom.xml
View File

@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
@ -37,7 +37,6 @@
<module>config</module> <module>config</module>
<module>event</module> <module>event</module>
<module>log</module> <module>log</module>
<module>module</module>
<module>protocol</module> <module>protocol</module>
<module>proxy</module> <module>proxy</module>
<module>query</module> <module>query</module>
@ -72,7 +71,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 +82,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>
@ -138,7 +137,7 @@
<artifactId>scriptus</artifactId> <artifactId>scriptus</artifactId>
<version>0.5.0</version> <version>0.5.0</version>
<configuration> <configuration>
<format>git:${project.name}:${project.version}:%s:${build.number}</format> <format>git:${project.name}-Pandacube:${project.version}:%s:${build.number}</format>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
@ -152,7 +151,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 +281,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 +356,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

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-protocol</artifactId> <artifactId>bungeecord-protocol</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -35,7 +34,7 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

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

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import com.mojang.brigadier.Command; import com.mojang.brigadier.Command;
import com.mojang.brigadier.StringReader; import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.DoubleArgumentType; import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType;
@ -303,7 +304,7 @@ public class Commands extends DefinedPacket
} }
@Data @Data
private static class ArgumentRegistry public static class ArgumentRegistry
{ {
private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>(); private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>();
@ -327,18 +328,29 @@ public class Commands extends DefinedPacket
{ {
} }
}; };
private static final ArgumentSerializer<Boolean> BOOLEAN = new ArgumentSerializer<Boolean>() private static final ProperArgumentSerializer<BoolArgumentType> BOOLEAN = new ProperArgumentSerializer<BoolArgumentType>()
{ {
@Override @Override
protected Boolean read(ByteBuf buf) protected BoolArgumentType read(ByteBuf buf)
{ {
return buf.readBoolean(); return BoolArgumentType.bool();
} }
@Override @Override
protected void write(ByteBuf buf, Boolean t) protected void write(ByteBuf buf, BoolArgumentType t)
{ {
buf.writeBoolean( t ); }
@Override
protected int getIntKey()
{
return 0;
}
@Override
protected String getKey()
{
return "brigadier:bool";
} }
}; };
private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>() private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>()
@ -355,7 +367,7 @@ public class Commands extends DefinedPacket
buf.writeByte( t ); buf.writeByte( t );
} }
}; };
private static final ArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ArgumentSerializer<FloatArgumentType>() private static final ProperArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ProperArgumentSerializer<FloatArgumentType>()
{ {
@Override @Override
protected FloatArgumentType read(ByteBuf buf) protected FloatArgumentType read(ByteBuf buf)
@ -383,8 +395,20 @@ public class Commands extends DefinedPacket
buf.writeFloat( t.getMaximum() ); buf.writeFloat( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 1;
}
@Override
protected String getKey()
{
return "brigadier:float";
}
}; };
private static final ArgumentSerializer<DoubleArgumentType> DOUBLE_RANGE = new ArgumentSerializer<DoubleArgumentType>() private static final ProperArgumentSerializer<DoubleArgumentType> DOUBLE_RANGE = new ProperArgumentSerializer<DoubleArgumentType>()
{ {
@Override @Override
protected DoubleArgumentType read(ByteBuf buf) protected DoubleArgumentType read(ByteBuf buf)
@ -412,8 +436,20 @@ public class Commands extends DefinedPacket
buf.writeDouble( t.getMaximum() ); buf.writeDouble( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 2;
}
@Override
protected String getKey()
{
return "brigadier:double";
}
}; };
private static final ArgumentSerializer<IntegerArgumentType> INTEGER_RANGE = new ArgumentSerializer<IntegerArgumentType>() private static final ProperArgumentSerializer<IntegerArgumentType> INTEGER_RANGE = new ProperArgumentSerializer<IntegerArgumentType>()
{ {
@Override @Override
protected IntegerArgumentType read(ByteBuf buf) protected IntegerArgumentType read(ByteBuf buf)
@ -441,6 +477,18 @@ public class Commands extends DefinedPacket
buf.writeInt( t.getMaximum() ); buf.writeInt( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 3;
}
@Override
protected String getKey()
{
return "brigadier:integer";
}
}; };
private static final ArgumentSerializer<Integer> INTEGER = new ArgumentSerializer<Integer>() private static final ArgumentSerializer<Integer> INTEGER = new ArgumentSerializer<Integer>()
{ {
@ -456,7 +504,7 @@ public class Commands extends DefinedPacket
buf.writeInt( t ); buf.writeInt( t );
} }
}; };
private static final ArgumentSerializer<LongArgumentType> LONG_RANGE = new ArgumentSerializer<LongArgumentType>() private static final ProperArgumentSerializer<LongArgumentType> LONG_RANGE = new ProperArgumentSerializer<LongArgumentType>()
{ {
@Override @Override
protected LongArgumentType read(ByteBuf buf) protected LongArgumentType read(ByteBuf buf)
@ -484,6 +532,18 @@ public class Commands extends DefinedPacket
buf.writeLong( t.getMaximum() ); buf.writeLong( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 4;
}
@Override
protected String getKey()
{
return "brigadier:long";
}
}; };
private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>() private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>()
{ {
@ -539,11 +599,20 @@ public class Commands extends DefinedPacket
static static
{ {
register( "brigadier:bool", VOID ); register( "brigadier:bool", BOOLEAN );
PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN );
register( "brigadier:float", FLOAT_RANGE ); register( "brigadier:float", FLOAT_RANGE );
PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT_RANGE );
register( "brigadier:double", DOUBLE_RANGE ); register( "brigadier:double", DOUBLE_RANGE );
PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE_RANGE );
register( "brigadier:integer", INTEGER_RANGE ); register( "brigadier:integer", INTEGER_RANGE );
register( "brigadier:long", LONG_RANGE ); PROPER_PROVIDERS.put( IntegerArgumentType.class, INTEGER_RANGE );
register( "brigadier:long", LONG_RANGE ); // 1.14+
PROPER_PROVIDERS.put( LongArgumentType.class, LONG_RANGE );
register( "brigadier:string", STRING ); register( "brigadier:string", STRING );
PROPER_PROVIDERS.put( StringArgumentType.class, STRING ); PROPER_PROVIDERS.put( StringArgumentType.class, STRING );
@ -853,7 +922,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 )
}; };
} }
@ -867,6 +939,404 @@ public class Commands extends DefinedPacket
return serializer; return serializer;
} }
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity}.
* @param singleEntity if the argument restrict to only one entity
* @param onlyPlayers if the argument restrict to players only
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntity(boolean singleEntity, boolean onlyPlayers)
{
byte flags = 0;
if ( singleEntity )
{
flags |= 1;
}
if ( onlyPlayers )
{
flags |= 2;
}
return minecraftArgumentType( "minecraft:entity", flags );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:game_profile}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftGameProfile()
{
return minecraftArgumentType( "minecraft:game_profile", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_pos}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockPos()
{
return minecraftArgumentType( "minecraft:block_pos", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:column_pos}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftColumnPos()
{
return minecraftArgumentType( "minecraft:column_pos", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:vec3}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftVec3()
{
return minecraftArgumentType( "minecraft:vec3", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:vec2}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftVec2()
{
return minecraftArgumentType( "minecraft:vec2", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_state}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockState()
{
return minecraftArgumentType( "minecraft:block_state", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_predicate}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockPredicate()
{
return minecraftArgumentType( "minecraft:block_predicate", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_stack}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemStack()
{
return minecraftArgumentType( "minecraft:item_stack", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_predicate}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemPredicate()
{
return minecraftArgumentType( "minecraft:item_predicate", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:color}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftColor()
{
return minecraftArgumentType( "minecraft:color", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:component}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftComponent()
{
return minecraftArgumentType( "minecraft:component", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:message}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftMessage()
{
return minecraftArgumentType( "minecraft:message", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_compound_tag}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTCompoundTag()
{
return minecraftArgumentType( "minecraft:nbt_compound_tag", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_tag}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTTag()
{
return minecraftArgumentType( "minecraft:nbt_tag", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBT()
{
return minecraftArgumentType( "minecraft:nbt", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_path}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTPath()
{
return minecraftArgumentType( "minecraft:nbt_path", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:objective}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftObjective()
{
return minecraftArgumentType( "minecraft:objective", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:objective_criteria}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftObjectiveCriteria()
{
return minecraftArgumentType( "minecraft:objective_criteria", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:operation}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftOperation()
{
return minecraftArgumentType( "minecraft:operation", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:particle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftParticle()
{
return minecraftArgumentType( "minecraft:particle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:rotation}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftRotation()
{
return minecraftArgumentType( "minecraft:rotation", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:scoreboard_slot}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftScoreboardSlot()
{
return minecraftArgumentType( "minecraft:scoreboard_slot", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:score_holder}.
* @param allowMultiple if the argument allows multiple entities
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftScoreHolder(boolean allowMultiple)
{
byte flags = 0;
if ( allowMultiple )
{
flags |= 1;
}
return minecraftArgumentType( "minecraft:score_holder", flags );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:swizzle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftSwizzle()
{
return minecraftArgumentType( "minecraft:swizzle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:team}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftTeam()
{
return minecraftArgumentType( "minecraft:team", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_slot}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemSlot()
{
return minecraftArgumentType( "minecraft:item_slot", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource_location}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResourceLocation()
{
return minecraftArgumentType( "minecraft:resource_location", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:mob_effect}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftMobEffect()
{
return minecraftArgumentType( "minecraft:mob_effect", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:function}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftFunction()
{
return minecraftArgumentType( "minecraft:function", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity_anchor}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntityAnchor()
{
return minecraftArgumentType( "minecraft:entity_anchor", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:int_range}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftIntRange()
{
return minecraftArgumentType( "minecraft:int_range", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:float_range}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftFloatRange()
{
return minecraftArgumentType( "minecraft:float_range", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_enchantment}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemEnchantment()
{
return minecraftArgumentType( "minecraft:item_enchantment", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity_summon}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntitySummon()
{
return minecraftArgumentType( "minecraft:entity_summon", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:dimension}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftDimension()
{
return minecraftArgumentType( "minecraft:dimension", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:time}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftTime()
{
return minecraftArgumentType( "minecraft:time", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:uuid}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftUUID()
{
return minecraftArgumentType( "minecraft:uuid", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:angle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftAngle()
{
return minecraftArgumentType( "minecraft:angle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource}.
* @param rawString the raw string for the argument
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResource(String rawString)
{
return minecraftArgumentType( "minecraft:resource", rawString );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource_or_tag}.
* @param rawString the raw string for the argument
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResourceOrTag(String rawString)
{
return minecraftArgumentType( "minecraft:resource_or_tag", rawString );
}
private static ArgumentType<?> minecraftArgumentType(String key, Object rawValue)
{
ArgumentSerializer reader = PROVIDERS.get( key );
Preconditions.checkArgument( reader != null, "No provider for argument " + key );
return new DummyType( key, reader, rawValue );
}
private static ArgumentType<?> read(ByteBuf buf, int protocolVersion) private static ArgumentType<?> read(ByteBuf buf, int protocolVersion)
{ {
Object key; Object key;
@ -996,11 +1466,15 @@ public class Commands extends DefinedPacket
private static String getKey(SuggestionProvider<DummyProvider> provider) private static String getKey(SuggestionProvider<DummyProvider> provider)
{ {
Preconditions.checkArgument( provider instanceof DummyProvider, "Non dummy provider " + provider ); Preconditions.checkNotNull( provider );
if ( provider instanceof DummyProvider )
{
return ( (DummyProvider) provider ).key; return ( (DummyProvider) provider ).key;
} }
return ( (DummyProvider) ASK_SERVER ).key;
}
@Data @Data
private static final class DummyProvider implements SuggestionProvider<DummyProvider> private static final class DummyProvider implements SuggestionProvider<DummyProvider>
{ {

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

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId> <artifactId>bungeecord-proxy</artifactId>
<version>1.20-R0.3-SNAPSHOT</version> <version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -52,37 +51,49 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <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>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-log</artifactId> <artifactId>bungeecord-log</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-native</artifactId> <artifactId>bungeecord-native</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId> <artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-query</artifactId> <artifactId>bungeecord-query</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-slf4j</artifactId> <artifactId>bungeecord-slf4j</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
@ -96,7 +107,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

@ -91,7 +91,6 @@ import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.log.BungeeLogger; import net.md_5.bungee.log.BungeeLogger;
import net.md_5.bungee.log.LoggingForwardHandler; import net.md_5.bungee.log.LoggingForwardHandler;
import net.md_5.bungee.log.LoggingOutputStream; import net.md_5.bungee.log.LoggingOutputStream;
import net.md_5.bungee.module.ModuleManager;
import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.ProtocolConstants;
@ -176,7 +175,6 @@ public class BungeeCord extends ProxyServer
.registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create();
@Getter @Getter
private ConnectionThrottle connectionThrottle; private ConnectionThrottle connectionThrottle;
private final ModuleManager moduleManager = new ModuleManager();
{ {
// TODO: Proper fallback when we interface the manager // TODO: Proper fallback when we interface the manager
@ -274,10 +272,6 @@ public class BungeeCord extends ProxyServer
eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() ); eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
File moduleDirectory = new File( "modules" );
moduleManager.load( this, moduleDirectory );
pluginManager.detectPlugins( moduleDirectory );
pluginsFolder.mkdir(); pluginsFolder.mkdir();
pluginManager.detectPlugins( pluginsFolder ); pluginManager.detectPlugins( pluginsFolder );

View File

@ -5,7 +5,6 @@ import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit;
import joptsimple.OptionParser; import joptsimple.OptionParser;
import joptsimple.OptionSet; import joptsimple.OptionSet;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
@ -56,8 +55,7 @@ public class BungeeCordLauncher
System.err.println( "*** Warning, this build is outdated ***" ); System.err.println( "*** Warning, this build is outdated ***" );
System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" ); System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" );
System.err.println( "*** You will get NO support regarding this build ***" ); System.err.println( "*** You will get NO support regarding this build ***" );
System.err.println( "*** Server will start in 10 seconds ***" );
Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) );
} }
} }

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

@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.StringRange; import com.mojang.brigadier.context.StringRange;
@ -19,9 +20,12 @@ import io.netty.channel.unix.DomainSocketAddress;
import java.io.DataInput; import java.io.DataInput;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.md_5.bungee.ServerConnection; import net.md_5.bungee.ServerConnection;
@ -35,6 +39,7 @@ import net.md_5.bungee.api.chat.TextComponent;
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.connection.Server; import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.CommandsDeclareEvent;
import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerDisconnectEvent; import net.md_5.bungee.api.event.ServerDisconnectEvent;
@ -312,7 +317,7 @@ public class DownstreamBridge extends PacketHandler
Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" );
brand = ByteBufAllocator.DEFAULT.heapBuffer(); brand = ByteBufAllocator.DEFAULT.heapBuffer();
DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand ); DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + server.getInfo().getName() + " (" + serverBrand + ")", brand );
pluginMessage.setData( DefinedPacket.toArray( brand ) ); pluginMessage.setData( DefinedPacket.toArray( brand ) );
brand.release(); brand.release();
// changes in the packet are ignored so we need to send it manually // changes in the packet are ignored so we need to send it manually
@ -745,6 +750,11 @@ public class DownstreamBridge extends PacketHandler
{ {
boolean modified = false; boolean modified = false;
CommandsDeclareEvent commandsDeclareEvent = new CommandsDeclareEvent( server, con, commands.getRoot() );
bungee.getPluginManager().callEvent( commandsDeclareEvent );
modified = commandsDeclareEvent.isModified();
for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() ) for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() )
{ {
if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) ) if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) )
@ -761,11 +771,65 @@ public class DownstreamBridge extends PacketHandler
if ( modified ) if ( modified )
{ {
commands.setRoot( (com.mojang.brigadier.tree.RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) );
con.unsafe().sendPacket( commands ); con.unsafe().sendPacket( commands );
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }
} }
/*
* Create a deep copy of the provided command node but removes any node that are not accessible by the player
* (using {@link CommandNode#getRequirement()})
*/
private CommandNode filterCommandNode(CommandNode source, IdentityHashMap<CommandNode, CommandNode> commandNodeMapping)
{
CommandNode dest;
if ( source instanceof com.mojang.brigadier.tree.RootCommandNode )
{
dest = new com.mojang.brigadier.tree.RootCommandNode();
} else
{
if ( source.getRequirement() != null )
{
try
{
if ( !source.getRequirement().test( con ) )
{
commandNodeMapping.put( source, null );
return null;
}
} catch ( Throwable t )
{
ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Requirement test for command node " + source + " encountered an exception", t );
}
}
ArgumentBuilder destChildBuilder = source.createBuilder();
destChildBuilder.requires( sender -> true );
if ( destChildBuilder.getRedirect() != null )
{
if ( commandNodeMapping.containsKey( destChildBuilder.getRedirect() ) )
destChildBuilder.redirect( commandNodeMapping.get( destChildBuilder.getRedirect() ) );
else
destChildBuilder.redirect( filterCommandNode( destChildBuilder.getRedirect(), commandNodeMapping ) );
}
dest = destChildBuilder.build();
}
commandNodeMapping.put( source, dest );
for ( CommandNode sourceChild : (Collection<CommandNode>) source.getChildren() )
{
CommandNode destChild = filterCommandNode( sourceChild, commandNodeMapping );
if ( destChild == null )
continue;
dest.addChild( destChild );
}
return dest;
}
@Override @Override
public void handle(ServerData serverData) throws Exception public void handle(ServerData serverData) throws Exception
{ {

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;
@ -135,6 +137,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private boolean transferred; private boolean transferred;
private UserConnection userCon; private UserConnection userCon;
@Getter
private boolean duplication = false;
@Getter
private String realName = null;
@Getter
private UUID realId = null;
@Override @Override
public boolean shouldHandle(PacketWrapper packet) throws Exception public boolean shouldHandle(PacketWrapper packet) throws Exception
{ {
@ -218,7 +229,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 +372,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:
@ -440,6 +457,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
} }
this.loginRequest = loginRequest; this.loginRequest = loginRequest;
setName( realName = loginRequest.getData() );
int limit = BungeeCord.getInstance().config.getPlayerLimit(); int limit = BungeeCord.getInstance().config.getPlayerLimit();
if ( limit > 0 && bungee.getOnlineCount() >= limit ) if ( limit > 0 && bungee.getOnlineCount() >= limit )
@ -448,14 +466,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
return; return;
} }
// If offline mode and they are already on, don't allow connect
// We can just check by UUID here as names are based on UUID
if ( !isOnlineMode() && bungee.getPlayer( getUniqueId() ) != null )
{
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
return;
}
Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>() Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>()
{ {
@ -468,10 +478,20 @@ 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;
} }
if ( !realName.equals( name ) )
{
// Floodgate changes the name attribute with reflexion
setName( realName = name );
}
if ( uniqueId != null )
{
// if plugin called setUniqueId()
realId = uniqueId;
}
if ( onlineMode ) if ( onlineMode )
{ {
thisState = State.ENCRYPT; thisState = State.ENCRYPT;
@ -526,8 +546,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
if ( obj != null && obj.getId() != null ) if ( obj != null && obj.getId() != null )
{ {
loginProfile = obj; loginProfile = obj;
name = obj.getName(); setName( realName = obj.getName() );
uniqueId = Util.getUUID( obj.getId() ); uniqueId = realId = Util.getUUID( obj.getId() );
finish(); finish();
return; return;
} }
@ -545,12 +565,28 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private void finish() private void finish()
{ {
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) ); if ( uniqueId == null ) // offline mode and no plugin used setUniqueId()
if ( uniqueId == null )
{ {
uniqueId = offlineId; uniqueId = realId = offlineId;
} }
/*
* At this point, player is either authenticated by Mojang (online mode),
* by a plugin (Floodgate ?) or the offline id is set.
*/
ProxiedPlayer existingPlayer = bungee.getPlayer( uniqueId );
if ( existingPlayer != null && existingPlayer.hasPermission( "bungeecord.multiple_connect" ) )
{
UUID newId = generateDuplicatedId( uniqueId );
if ( !uniqueId.equals( newId ) )
{
uniqueId = newId;
setName( name + "." + getDuplicationIndex( newId ) );
duplication = true;
}
}
rewriteId = ( bungee.config.isIpForward() ) ? uniqueId : offlineId;
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() ) if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
{ {
if ( getVersion() >= ProtocolConstants.MINECRAFT_1_19_1 && getVersion() < ProtocolConstants.MINECRAFT_1_19_3 ) if ( getVersion() >= ProtocolConstants.MINECRAFT_1_19_1 && getVersion() < ProtocolConstants.MINECRAFT_1_19_3 )
@ -612,7 +648,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 +665,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 +688,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
@ -746,6 +791,59 @@ public class InitialHandler extends PacketHandler implements PendingConnection
return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData(); return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData();
} }
private void setName(String name)
{
this.name = name;
if ( loginRequest != null )
{
loginRequest.setData( name ); // name transmitted to Spigot server
}
updateOfflineId();
}
private UUID generateDuplicatedId(UUID base)
{
// UUID version: offline = 3 ; Java online mode = 4 ; Floodgate xUID = 0 (and must be kept 0)
// UUID variant: offline = 0xx ; Java online mode = 10x ; Floodgate xUID = xxx
if ( base.version() == 0 )
{
/*
* Floodgates xUID converted to UUID are not supported
* because it requires the 64 MSBs to be 0 (or Floodgate API would not
* recognize a Bedrock account) and we cannot modify the 64 LSBs
* without risking a collision with the xUID of another Bedrock account
*/
return base;
}
long MSB = base.getMostSignificantBits();
long LSB = base.getLeastSignificantBits();
MSB &= 0xFFFFFFFF_FFFF_70FFL; // reset bits we need
MSB |= 0x00000000_0000_8000L; // set version to + 8 the current version
for ( int i = 1; i <= 9; i++ )
{
long newMSB = MSB | i << 8;
UUID newUUID = new UUID( newMSB, LSB );
if ( bungee.getPlayer( newUUID ) != null )
{
continue;
}
return newUUID;
}
return base; // there are too many duplicated connections for this player
}
private static int getDuplicationIndex(UUID duplicatedId)
{
return (int) ( duplicatedId.getMostSignificantBits() >> 8 ) & 0xF;
}
private void updateOfflineId()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) );
}
@Override @Override
public int getVersion() public int getVersion()
{ {

View File

@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.Suggestions;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import net.md_5.bungee.BungeeCord; import net.md_5.bungee.BungeeCord;
@ -21,6 +20,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.SettingsChangedEvent; import net.md_5.bungee.api.event.SettingsChangedEvent;
import net.md_5.bungee.api.event.TabCompleteEvent; import net.md_5.bungee.api.event.TabCompleteEvent;
import net.md_5.bungee.api.event.TabCompleteRequestEvent;
import net.md_5.bungee.entitymap.EntityMap; import net.md_5.bungee.entitymap.EntityMap;
import net.md_5.bungee.forge.ForgeConstants; import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.netty.ChannelWrapper;
@ -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++ )
@ -235,32 +242,42 @@ public class UpstreamBridge extends PacketHandler
TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions ); TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions );
bungee.getPluginManager().callEvent( tabCompleteEvent ); bungee.getPluginManager().callEvent( tabCompleteEvent );
if ( tabCompleteEvent.isCancelled() ) List<String> legacyResults = tabCompleteEvent.getSuggestions();
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1;
int end = tabComplete.getCursor().length();
StringRange lastArgumentRange = StringRange.between( start, end );
List<Suggestion> brigadier = new ArrayList<>( legacyResults.size() );
for ( String s : legacyResults )
{
brigadier.add( new Suggestion( lastArgumentRange, s ) );
}
TabCompleteRequestEvent tabCompleteRequestEvent = new TabCompleteRequestEvent( con, con.getServer(), tabComplete.getCursor(), lastArgumentRange, new Suggestions( lastArgumentRange, brigadier ) );
tabCompleteRequestEvent.setCancelled( tabCompleteEvent.isCancelled() );
bungee.getPluginManager().callEvent( tabCompleteRequestEvent );
if ( tabCompleteRequestEvent.isCancelled() )
{ {
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }
List<String> results = tabCompleteEvent.getSuggestions(); Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions();
if ( !results.isEmpty() )
if ( !brigadierResults.isEmpty() )
{ {
// Unclear how to handle 1.13 commands at this point. Because we don't inject into the command packets we are unlikely to get this far unless
// Bungee plugins are adding results for commands they don't own anyway
if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 ) if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 )
{ {
List<String> results = new ArrayList<>( brigadierResults.getList().size() );
for ( Suggestion s : brigadierResults.getList() )
{
results.add( s.getText() );
}
con.unsafe().sendPacket( new TabCompleteResponse( results ) ); con.unsafe().sendPacket( new TabCompleteResponse( results ) );
} else } else
{ {
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1; con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) );
int end = tabComplete.getCursor().length();
StringRange range = StringRange.between( start, end );
List<Suggestion> brigadier = new LinkedList<>();
for ( String s : results )
{
brigadier.add( new Suggestion( range, s ) );
}
con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), new Suggestions( range, brigadier ) ) );
} }
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }

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

@ -1,34 +0,0 @@
package net.md_5.bungee.module;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import lombok.Data;
import net.md_5.bungee.Util;
@Data
public class JenkinsModuleSource implements ModuleSource
{
@Override
public void retrieve(ModuleSpec module, ModuleVersion version)
{
System.out.println( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() );
try
{
URL website = new URL( "https://ci.md-5.net/job/BungeeCord/" + version.getBuild() + "/artifact/module/" + module.getName().replace( '_', '-' ) + "/target/" + module.getName() + ".jar" );
URLConnection con = website.openConnection();
// 15 second timeout at various stages
con.setConnectTimeout( 15000 );
con.setReadTimeout( 15000 );
Files.write( ByteStreams.toByteArray( con.getInputStream() ), module.getFile() );
System.out.println( "Download complete" );
} catch ( IOException ex )
{
System.out.println( "Failed to download: " + Util.exception( ex ) );
}
}
}

View File

@ -1,155 +0,0 @@
package net.md_5.bungee.module;
import com.google.common.base.Preconditions;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.PluginDescription;
import net.md_5.bungee.util.CaseInsensitiveMap;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
public class ModuleManager
{
private final Map<String, ModuleSource> knownSources = new HashMap<>();
public ModuleManager()
{
knownSources.put( "jenkins", new JenkinsModuleSource() );
}
// CHECKSTYLE:OFF
@SuppressFBWarnings(
{
"SF_SWITCH_FALLTHROUGH", "SF_SWITCH_NO_DEFAULT"
})
// CHECKSTYLE:ON
public void load(ProxyServer proxy, File moduleDirectory) throws Exception
{
moduleDirectory.mkdir();
ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() );
if ( bungeeVersion == null )
{
System.out.println( "Couldn't detect bungee version. Custom build?" );
return;
}
List<ModuleSpec> modules = new ArrayList<>();
File configFile = new File( "modules.yml" );
// Start Yaml
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
Yaml yaml = new Yaml( options );
Map<String, Object> config;
configFile.createNewFile();
try ( InputStream is = new FileInputStream( configFile ) )
{
config = (Map) yaml.load( is );
}
if ( config == null )
{
config = new CaseInsensitiveMap<>();
} else
{
config = new CaseInsensitiveMap<>( config );
}
// End yaml
List<String> defaults = new ArrayList<>();
Object readModules = config.get( "modules" );
if ( readModules != null )
{
defaults.addAll( (Collection) readModules );
}
int version = ( config.containsKey( "version" ) ) ? (int) config.get( "version" ) : 0;
switch ( version )
{
case 0:
defaults.add( "jenkins://cmd_alert" );
defaults.add( "jenkins://cmd_find" );
defaults.add( "jenkins://cmd_list" );
defaults.add( "jenkins://cmd_send" );
defaults.add( "jenkins://cmd_server" );
case 1:
defaults.add( "jenkins://reconnect_yaml" );
}
config.put( "modules", defaults );
config.put( "version", 2 );
try ( FileWriter wr = new FileWriter( configFile ) )
{
yaml.dump( config, wr );
}
for ( String s : (List<String>) config.get( "modules" ) )
{
URI uri = new URI( s );
ModuleSource source = knownSources.get( uri.getScheme() );
if ( source == null )
{
System.out.println( "Unknown module source: " + s );
continue;
}
String name = uri.getAuthority();
if ( name == null )
{
System.out.println( "Unknown module host: " + s );
continue;
}
ModuleSpec spec = new ModuleSpec( name, new File( moduleDirectory, name + ".jar" ), source );
modules.add( spec );
System.out.println( "Discovered module: " + spec );
}
for ( ModuleSpec module : modules )
{
ModuleVersion moduleVersion = ( module.getFile().exists() ) ? getVersion( module.getFile() ) : null;
if ( !bungeeVersion.equals( moduleVersion ) )
{
System.out.println( "Attempting to update plugin from " + moduleVersion + " to " + bungeeVersion );
module.getProvider().retrieve( module, bungeeVersion );
}
}
}
@SuppressFBWarnings("REC_CATCH_EXCEPTION")
private ModuleVersion getVersion(File file)
{
try ( JarFile jar = new JarFile( file ) )
{
JarEntry pdf = jar.getJarEntry( "plugin.yml" );
Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" );
try ( InputStream in = jar.getInputStream( pdf ) )
{
PluginDescription desc = new Yaml().loadAs( in, PluginDescription.class );
return ModuleVersion.parse( desc.getVersion() );
}
} catch ( Exception ex )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not check module from file " + file, ex );
}
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More