1
0
Fork 0

Compare commits

...

33 Commits

Author SHA1 Message Date
Marc Baloup ba212a8a61 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2023-09-22 00:03:48 +02:00
Marc Baloup bf44147805 Add CommandsDeclareEvent to declare commands with brigadier API 2023-09-22 00:03:42 +02:00
Marc Baloup e47394e10d Server branding now includes the backend server name 2023-09-21 23:55:32 +02:00
Marc Baloup 3ba71310b8 Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2023-09-21 23:55:32 +02:00
Marc Baloup fe2baa08b5 Change projet configuration and POM for Pandacube 2023-09-21 23:55:32 +02:00
Marc Baloup fb1c808d0e Remove modules and startup delay
We don’t need them for Pandacube
2023-09-21 23:55:29 +02:00
md_5 5a1e342e0d
Minecraft 1.20.2 support 2023-09-22 02:40:00 +10:00
md_5 d9bbdc3281
Add Java 21 compilation support 2023-09-20 18:06:33 +10:00
Parker Hawke cfe00fa47c
#3490: Add ComponentBuilder#build() and ComponentSerializer#deserialize()
Components traditionally use the extra data to represent components as a single BaseComponent object. While BaseComponent typically mirrors this behaviour, somewhere along the development of BungeeChat this practice was made unclear. Because ComponentBuilder#create() returns an array of BaseComponents, it has sort of been silently accepted that all components should be represented as arrays, which is incorrect. This heavily influenced the direction of Spigot's component API (with additions such as CommandSender#sendMessage(BaseComponent[])) which emphasizes this misconception of "all components are arrays".

Adding new methods to ComponentBuilder and ComponentSerializer should steer use of the BungeeChat API to be more oriented towards single component instances, not arrays.
2023-09-19 07:14:18 +10:00
md_5 d68ebd1eaf
Minecraft 1.20.2-rc1 support 2023-09-17 08:10:42 +10:00
dependabot[bot] a7cd79eb41
#3516: Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.6.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-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>
2023-09-16 10:22:07 +10:00
Outfluencer 9e83ee6f0c
#3508: Use same compression threshold checks as Vanilla 2023-09-12 20:29:01 +10:00
dependabot[bot] 7c81d91740
#3513: Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.4.0 to 3.4.1
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.4.0...enforcer-3.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 20:28:08 +10:00
md_5 5b126b7f4d
Fix javadoc plugin version in non-dist builds 2023-09-10 11:41:56 +10:00
dependabot[bot] 9fe7d21f4b
#3510: Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-08 19:33:56 +10:00
dependabot[bot] 94ea0271ba
#3505: Bump io.netty:netty-bom from 4.1.96.Final to 4.1.97.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.96.Final to 4.1.97.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.96.Final...netty-4.1.97.Final)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 20:07:19 +10:00
dependabot[bot] 3af672d2f2
#3504: Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.3.0 to 3.4.0
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.3.0...enforcer-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-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>
2023-08-24 20:07:00 +10:00
md_5 0dd7b98428
Bump version to 1.20-R0.2-SNAPSHOT 2023-08-07 08:01:47 +10:00
md_5 a793692a2c
Release 1.20-R0.1 2023-08-07 07:56:00 +10:00
dependabot[bot] 23fb838227
#3493: Bump io.netty:netty-bom from 4.1.95.Final to 4.1.96.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.95.Final to 4.1.96.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.95.Final...netty-4.1.96.Final)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 20:01:19 +10:00
dependabot[bot] 2d6d89d668
#3492: Bump io.netty:netty-bom from 4.1.94.Final to 4.1.95.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.94.Final to 4.1.95.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.94.Final...netty-4.1.95.Final)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 18:46:54 +10:00
BoomEaro 0199cb90ff
#3489: Add command string length limit when decoding ClientCommand 2023-07-15 10:44:41 +10:00
dependabot[bot] 958cef5084
#3488: Bump scriptus from 0.4.1 to 0.5.0
Bumps [scriptus](https://github.com/SpigotMC/Scriptus) from 0.4.1 to 0.5.0.
- [Commits](https://github.com/SpigotMC/Scriptus/commits)

---
updated-dependencies:
- dependency-name: net.md-5:scriptus
  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>
2023-07-15 10:29:22 +10:00
Outfluencer 9f5ace9025
#3418: Add tab completion for bungee command names in pre-1.13 versions 2023-07-05 19:58:23 +10:00
dependabot[bot] 3a6e2631bf
#3479: Bump netty-bom from 4.1.93.Final to 4.1.94.Final
Bumps [netty-bom](https://github.com/netty/netty) from 4.1.93.Final to 4.1.94.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.93.Final...netty-4.1.94.Final)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-03 18:08:33 +10:00
md_5 c7adcf9fdf
Disable maven enforcer for now 2023-06-18 20:55:47 +10:00
md_5 da3616e636
SPIGOT-7400: Downgrade maven-resolver due to issues resolving certain depends 2023-06-18 20:37:33 +10:00
dependabot[bot] b371fe67a5
#3478: Bump maven-shade-plugin from 3.4.1 to 3.5.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-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>
2023-06-17 07:59:06 +10:00
Outfluencer 6324c7d527
#3401: Only synchronize necessary parts of the BungeeServerInfo#sendData method 2023-06-10 18:06:37 +10:00
Outfluencer 6263fe283b
#3426: Made find command output hover and clickable 2023-06-10 18:03:02 +10:00
Ruan 9a7617f9b8
#3475: Add KickPlayerRaw channel 2023-06-10 18:01:01 +10:00
Janmm14 9a71358dfa
#3439: Add GetPlayerServer bungee plugin message subchannel 2023-06-10 18:00:33 +10:00
Outfluencer a96a2e80a1
#3437: Remove unused enum in ServerConnector and add color to exception message 2023-06-10 17:58:14 +10:00
90 changed files with 2035 additions and 1823 deletions

View File

@ -13,9 +13,10 @@ updates:
- dependency-name: "com.puppycrawl.tools:checkstyle"
# Newer versions have issues, see #1909 and #2050
- dependency-name: "jline:jline"
# Needs to be synchronised with maven-resolver-provider dependencies
# Later versions of these Maven dependencies are incompatible and require careful management - see SPIGOT-7400
- dependency-name: "org.apache.maven.resolver:maven-resolver-connector-basic"
- dependency-name: "org.apache.maven.resolver:maven-resolver-transport-http"
- dependency-name: "org.apache.maven:maven-resolver-provider"
# Used with maven-resolver dependencies; 2.0 update breaks other providers
- dependency-name: "org.slf4j:slf4j-api"
update-types: ["version-update:semver-major"]

View File

@ -9,12 +9,12 @@ jobs:
strategy:
fail-fast: false
matrix:
java: [8, 11, 17]
java: [8, 11, 17, 21]
name: Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: zulu

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-API</name>
@ -20,25 +19,25 @@
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-config</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-event</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
@ -51,28 +50,28 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<version>3.9.2</version>
<version>3.8.5</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-http</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
<version>2.2</version>
<scope>compile</scope>
</dependency>
</dependencies>

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

@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable;
/**
* Event called when a player uses tab completion.
* @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions.
*/
@Deprecated
@Data
@ToString(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

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Bootstrap</name>
@ -21,14 +20,12 @@
<properties>
<maven.deploy.skip>true</maven.deploy.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>
</properties>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
@ -55,7 +52,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Chat</name>
@ -22,7 +21,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -454,9 +454,32 @@ public final class ComponentBuilder
return this;
}
/**
* Returns the component built by this builder. If this builder is
* empty, an empty text component will be returned.
*
* @return the component
*/
public BaseComponent build()
{
TextComponent base = new TextComponent();
if ( !parts.isEmpty() )
{
List<BaseComponent> cloned = new ArrayList<>( parts );
cloned.replaceAll( BaseComponent::duplicate );
base.setExtra( cloned );
}
return base;
}
/**
* Returns the components needed to display the message created by this
* builder.git
* <p>
* <strong>NOTE:</strong> {@link #build()} is preferred as it will
* consolidate all components into a single BaseComponent with extra
* contents as opposed to an array of components which is non-standard
* and may result in unexpected behavior.
*
* @return the created components
*/

View File

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

View File

@ -27,7 +27,6 @@ import net.md_5.bungee.api.chat.hover.content.TextSerializer;
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
{
private static final JsonParser JSON_PARSER = new JsonParser();
private static final Gson gson = new GsonBuilder().
registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ).
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
@ -43,9 +42,25 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
public static final ThreadLocal<Set<BaseComponent>> serializedComponents = new ThreadLocal<Set<BaseComponent>>();
/**
* Parse a JSON-compliant String as an array of base components. The input
* can be one of either an array of components, or a single component object.
* If the input is an array, each component will be parsed individually and
* returned in the order that they were parsed. If the input is a single
* component object, a single-valued array with the component will be returned.
* <p>
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it will
* parse only one component as opposed to an array of components which is non-
* standard behavior. This method is still appropriate for parsing multiple
* components at once, although such use case is rarely (if at all) exhibited
* in vanilla Minecraft.
*
* @param json the component json to parse
* @return an array of all parsed components
*/
public static BaseComponent[] parse(String json)
{
JsonElement jsonElement = JSON_PARSER.parse( json );
JsonElement jsonElement = JsonParser.parseString( json );
if ( jsonElement.isJsonArray() )
{
@ -59,6 +74,26 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
}
}
/**
* Deserialize a JSON-compliant String as a single component. The input is
* expected to be a JSON object that represents only one component.
*
* @param json the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a JSON object is
* passed as input
*/
public static BaseComponent deserialize(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
if ( !jsonElement.isJsonObject() )
{
throw new IllegalArgumentException( "Malformatted JSON. Expected object, got array for input \"" + json + "\"." );
}
return gson.fromJson( jsonElement, BaseComponent.class );
}
public static String toString(Object object)
{
return gson.toJson( object );

View File

@ -1,6 +1,11 @@
package net.md_5.bungee.api.chat;
import java.awt.Color;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ObjIntConsumer;
import java.util.function.Supplier;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Text;
@ -18,10 +23,24 @@ public class ComponentsTest
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) );
}
public static void testDissembleReassemble(String json)
public static void testDissembleReassemble(BaseComponent component)
{
String json = ComponentSerializer.toString( component );
BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( json, ComponentSerializer.toString( parsed ) );
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( component ) );
}
public static void testAssembleDissemble(String json, boolean modern)
{
if ( modern )
{
BaseComponent deserialized = ComponentSerializer.deserialize( json );
Assert.assertEquals( json, ComponentSerializer.toString( deserialized ) );
} else
{
BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( json, ComponentSerializer.toString( parsed ) );
}
}
@Test
@ -41,8 +60,10 @@ public class ComponentsTest
{
textComponent
} );
testDissembleReassemble( textComponent );
json = "{\"hoverEvent\":{\"action\":\"show_item\",\"value\":[{\"text\":\"{id:\\\"minecraft:netherrack\\\",Count:47b}\"}]},\"text\":\"Test\"}";
testDissembleReassemble( json );
testAssembleDissemble( json, false );
testAssembleDissemble( json, true );
//////////
String hoverVal = "{\"text\":\"{id:\\\"minecraft:dirt\\\",Count:1b}\"}";
json = "{\"extra\":[{\"text\":\"[\"},{\"extra\":[{\"translate\":\"block.minecraft.dirt\"}],\"text\":\"\"},{\"text\":\"]\"}],\"hoverEvent\":{\"action\":\"show_item\",\"value\":[" + hoverVal + "]},\"text\":\"\"}";
@ -66,18 +87,37 @@ public class ComponentsTest
}
@Test
public void testEmptyComponentBuilder()
public void testEmptyComponentBuilderCreate()
{
this.testEmptyComponentBuilder(
ComponentBuilder::create,
(components) -> Assert.assertEquals( components.length, 0 ),
(components, size) -> Assert.assertEquals( size, components.length )
);
}
@Test
public void testEmptyComponentBuilderBuild()
{
this.testEmptyComponentBuilder(
ComponentBuilder::build,
(component) -> Assert.assertNull( component.getExtra() ),
(component, size) -> Assert.assertEquals( component.getExtra().size(), size )
);
}
private <T> void testEmptyComponentBuilder(Function<ComponentBuilder, T> componentBuilder, Consumer<T> emptyAssertion, ObjIntConsumer<T> sizedAssertion)
{
ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] parts = builder.create();
Assert.assertEquals( parts.length, 0 );
T component = componentBuilder.apply( builder );
emptyAssertion.accept( component );
for ( int i = 0; i < 3; i++ )
{
builder.append( "part:" + i );
parts = builder.create();
Assert.assertEquals( parts.length, i + 1 );
component = componentBuilder.apply( builder );
sizedAssertion.accept( component, i + 1 );
}
}
@ -213,7 +253,7 @@ public class ComponentsTest
}
@Test
public void testHoverEventContents()
public void testHoverEventContentsCreate()
{
// First do the text using the newer contents system
HoverEvent hoverEvent = new HoverEvent(
@ -222,21 +262,53 @@ public class ComponentsTest
new Text( new ComponentBuilder( "Second" ).create() )
);
this.testHoverEventContents(
hoverEvent,
ComponentSerializer::parse,
(components) -> components[0].getHoverEvent(),
ComponentsTest::testDissembleReassemble // BaseComponent
);
// check the test still works with the value method
hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Sample text" ).create() );
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 1 );
Assert.assertTrue( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
}
@Test
public void testHoverEventContentsBuild()
{
// First do the text using the newer contents system
HoverEvent hoverEvent = new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new Text( new ComponentBuilder( "First" ).build() ),
new Text( new ComponentBuilder( "Second" ).build() )
);
this.testHoverEventContents(
hoverEvent,
ComponentSerializer::deserialize,
BaseComponent::getHoverEvent,
ComponentsTest::testDissembleReassemble // BaseComponent
);
}
private <T> void testHoverEventContents(HoverEvent hoverEvent, Function<String, T> deserializer, Function<T, HoverEvent> hoverEventGetter, Consumer<T> dissembleReassembleTest)
{
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 2 );
Assert.assertFalse( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
// check the test still works with the value method
hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Sample text" ).create() );
Assert.assertEquals( hoverEvent.getContents().size(), 1 );
Assert.assertTrue( hoverEvent.isLegacy() );
serialized = ComponentSerializer.toString( component );
deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
String serialized = ComponentSerializer.toString( component );
T deserialized = deserializer.apply( serialized );
Assert.assertEquals( component.getHoverEvent(), hoverEventGetter.apply( deserialized ) );
// Test single content:
String json = "{\"italic\":true,\"color\":\"gray\",\"translate\":\"chat.type.admin\",\"with\":[{\"text\":\"@\"}"
@ -248,17 +320,28 @@ public class ComponentsTest
+ "\"/tell Name \"},\"hoverEvent\":{\"action\":\"show_entity\",\"contents\":"
+ "{\"type\":\"minecraft:player\",\"id\":\"00000000-0000-0000-0000-00000000000000\",\"name\":"
+ "{\"text\":\"Name\"}}},\"text\":\"Name\"}]}]}";
testDissembleReassemble( ComponentSerializer.parse( json ) );
dissembleReassembleTest.accept( deserializer.apply( json ) );
}
@Test
public void testFormatRetentionCopyFormatting()
public void testFormatRetentionCopyFormattingCreate()
{
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
}
@Test
public void testFormatRetentionCopyFormattingBuild()
{
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Test" ).build() ) ) );
}
private void testFormatRetentionCopyFormatting(Supplier<HoverEvent> hoverEventSupplier)
{
TextComponent first = new TextComponent( "Hello" );
first.setBold( true );
first.setColor( ChatColor.RED );
first.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "test" ) );
first.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
first.setHoverEvent( hoverEventSupplier.get() );
TextComponent second = new TextComponent( " world" );
second.copyFormatting( first, ComponentBuilder.FormatRetention.ALL, true );
@ -269,16 +352,44 @@ public class ComponentsTest
}
@Test
public void testBuilderClone()
public void testBuilderCloneCreate()
{
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.create() ) );
}
@Test
public void testBuilderCloneBuild()
{
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.build() ) );
}
private void testBuilderClone(Function<ComponentBuilder, String> legacyTextFunction)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED );
ComponentBuilder cloned = new ComponentBuilder( builder );
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
Assert.assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) );
}
@Test
public void testBuilderAppendMixedComponents()
public void testBuilderAppendCreateMixedComponents()
{
this.testBuilderAppendMixedComponents(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
@Test
public void testBuilderAppendBuildMixedComponents()
{
this.testBuilderAppendMixedComponents(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
private <T> void testBuilderAppendMixedComponents(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " );
TextComponent textComponent = new TextComponent( "world " );
@ -291,11 +402,11 @@ public class ComponentsTest
} );
ScoreComponent scoreComponent = new ScoreComponent( "myscore", "myobjective" );
builder.append( scoreComponent ); // non array based BaseComponent append
BaseComponent[] components = builder.create();
Assert.assertEquals( "Hello ", components[0].toPlainText() );
Assert.assertEquals( textComponent.toPlainText(), components[1].toPlainText() );
Assert.assertEquals( translatableComponent.toPlainText(), components[2].toPlainText() );
Assert.assertEquals( scoreComponent.toPlainText(), components[3].toPlainText() );
T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello ", extraGetter.apply( component, 0 ).toPlainText() );
Assert.assertEquals( textComponent.toPlainText(), extraGetter.apply( component, 1 ).toPlainText() );
Assert.assertEquals( translatableComponent.toPlainText(), extraGetter.apply( component, 2 ).toPlainText() );
Assert.assertEquals( scoreComponent.toPlainText(), extraGetter.apply( component, 3 ).toPlainText() );
}
@Test
@ -309,32 +420,80 @@ public class ComponentsTest
}
@Test
public void testBuilderAppend()
public void testBuilderAppendCreate()
{
ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " );
HoverEvent hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() );
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() );
BaseComponent[] components = builder.create();
Assert.assertEquals( components[1].getHoverEvent(), hoverEvent );
Assert.assertEquals( components[1].getClickEvent(), clickEvent );
Assert.assertEquals( "Hello world!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", BaseComponent.toLegacyText( components ) );
this.testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() ),
ComponentBuilder::create,
(components, index) -> components[index],
BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderAppendLegacy()
public void testBuilderAppendBuild()
{
this.testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Hello world" ).build() ) ),
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ),
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
(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)
{
ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " );
HoverEvent hoverEvent = hoverEventSupplier.get();
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() ); // Intentionally using create() to append multiple individual components
T component = componentBuilder.apply( builder );
Assert.assertEquals( extraGetter.apply( component, 1 ).getHoverEvent(), hoverEvent );
Assert.assertEquals( extraGetter.apply( component, 1 ).getClickEvent(), clickEvent );
Assert.assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyText, toLegacyTextFunction.apply( component ) );
}
@Test
public void testBuilderAppendLegacyCreate()
{
this.testBuilderAppendLegacy(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderAppendLegacyBuild()
{
this.testBuilderAppendLegacy(
ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <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 );
builder.appendLegacy( "§aworld!" );
BaseComponent[] components = builder.create();
T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello world!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", BaseComponent.toLegacyText( components ) );
Assert.assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
}
@Test
@ -397,57 +556,114 @@ public class ComponentsTest
}
@Test
public void testBuilder()
public void testBuilderCreate()
{
BaseComponent[] components = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).
this.testBuilder(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderBuild()
{
this.testBuilder(
ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <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 ).
append( "World" ).bold( true ).color( ChatColor.BLUE ).
append( "!" ).color( ChatColor.YELLOW ).create();
append( "!" ).color( ChatColor.YELLOW ) );
Assert.assertEquals( "Hello World!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!", BaseComponent.toLegacyText( components ) );
Assert.assertEquals( "Hello World!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
}
@Test
public void testBuilderReset()
public void testBuilderCreateReset()
{
BaseComponent[] components = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset().create();
Assert.assertEquals( components[0].getColor(), ChatColor.RED );
Assert.assertEquals( components[1].getColor(), ChatColor.WHITE );
this.testBuilderReset(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
@Test
public void testBuilderFormatRetention()
public void testBuilderBuildReset()
{
BaseComponent[] noneRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ).create();
this.testBuilderReset(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
Assert.assertEquals( noneRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( noneRetention[1].getColor(), ChatColor.WHITE );
private <T> void testBuilderReset(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "test" ).create() );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( component, 0 ).getColor() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( component, 1 ).getColor() );
}
BaseComponent[] formattingRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ).create();
@Test
public void testBuilderCreateFormatRetention()
{
this.testBuilderFormatRetention(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
Assert.assertEquals( formattingRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( formattingRetention[0].getHoverEvent(), testEvent );
Assert.assertEquals( formattingRetention[1].getColor(), ChatColor.RED );
Assert.assertNull( formattingRetention[1].getHoverEvent() );
@Test
public void testBuilderBuildFormatRetention()
{
this.testBuilderFormatRetention(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
private <T> void testBuilderFormatRetention(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( noneRetention, 0 ).getColor() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( noneRetention, 1 ).getColor() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) );
T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 0 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 1 ).getColor() );
Assert.assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() );
ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" );
BaseComponent[] eventRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ).create();
T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) );
Assert.assertEquals( eventRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( eventRetention[0].getHoverEvent(), testEvent );
Assert.assertEquals( eventRetention[0].getClickEvent(), testClickEvent );
Assert.assertEquals( eventRetention[1].getColor(), ChatColor.WHITE );
Assert.assertEquals( eventRetention[1].getHoverEvent(), testEvent );
Assert.assertEquals( eventRetention[1].getClickEvent(), testClickEvent );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( eventRetention, 0 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() );
Assert.assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( eventRetention, 1 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() );
Assert.assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() );
}
@Test(expected = IllegalArgumentException.class)
@ -572,12 +788,29 @@ public class ComponentsTest
Assert.assertArrayEquals( hexColored, reColored );
}
/**
@Test
public void testLegacyResetInBuilderCreate()
{
this.testLegacyResetInBuilder(
ComponentBuilder::create,
ComponentSerializer::toString
);
}
@Test
public void testLegacyResetInBuilderBuild()
{
this.testLegacyResetInBuilder(
ComponentBuilder::build,
ComponentSerializer::toString
);
}
/*
* In legacy chat, colors and reset both reset all formatting.
* Make sure it works in combination with ComponentBuilder.
*/
@Test
public void testLegacyResetInBuilder()
private <T> void testLegacyResetInBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> componentSerializer)
{
ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] a = TextComponent.fromLegacyText( "§4§n44444§rdd§6§l6666" );
@ -588,13 +821,13 @@ public class ComponentsTest
builder.append( a );
String test1 = ComponentSerializer.toString( builder.create() );
String test1 = componentSerializer.apply( componentBuilder.apply( builder ) );
Assert.assertEquals( expected, test1 );
BaseComponent[] b = TextComponent.fromLegacyText( "§rrrrr" );
builder.append( b );
String test2 = ComponentSerializer.toString( builder.create() );
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );
Assert.assertEquals(
"{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},"
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Config</name>
@ -22,14 +21,14 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
<version>2.10.1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
<version>2.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-event</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Event</name>

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-log</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Log</name>
@ -26,7 +25,7 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version>
<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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-alert</artifactId>
<version>1.20-R0.1-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.fromLegacyText( 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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-find</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_find</name>
<description>Provides the find command</description>
</project>

View File

@ -1,34 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
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
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), player.getServer().getInfo().getName() ) );
}
}
}
}

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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-kick</artifactId>
<version>1.20-R0.1-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.fromLegacyText( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) );
return;
}
if ( args.length == 1 )
{
player.disconnect( TextComponent.fromLegacyText( ProxyServer.getInstance().getTranslation( "kick_message" ) ) );
} else
{
String[] reason = new String[ args.length - 1 ];
System.arraycopy( args, 1, reason, 0, reason.length );
player.disconnect( TextComponent.fromLegacyText( 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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-list</artifactId>
<version>1.20-R0.1-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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-send</artifactId>
<version>1.20-R0.1-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, new ArrayList<String>() );
}
}
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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-server</artifactId>
<version>1.20-R0.1-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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.1-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.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
<version>1.20-R0.1-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

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-native</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Native</name>

29
pom.xml
View File

@ -3,9 +3,9 @@
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>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>BungeeCord-Parent</name>
@ -37,7 +37,6 @@
<module>config</module>
<module>event</module>
<module>log</module>
<module>module</module>
<module>protocol</module>
<module>proxy</module>
<module>query</module>
@ -72,7 +71,7 @@
<properties>
<build.number>unknown</build.number>
<lombok.version>1.18.28</lombok.version>
<lombok.version>1.18.30</lombok.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -83,7 +82,7 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>4.1.93.Final</version>
<version>4.1.97.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -99,7 +98,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<version>32.1.2-jre</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -117,13 +116,22 @@
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>net.md-5</groupId>
<artifactId>scriptus</artifactId>
<version>0.4.1</version>
<version>0.5.0</version>
<configuration>
<format>git:${project.name}:${project.version}:%s:${build.number}</format>
<format>git:${project.name}-Pandacube:${project.version}:%s:${build.number}</format>
</configuration>
<executions>
<execution>
@ -187,7 +195,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce</id>
@ -204,7 +212,7 @@
</rules>
</configuration>
<goals>
<goal>enforce</goal>
<!--<goal>enforce</goal>--> <!-- Disabled until maven-resolver is upgraded again. -->
</goals>
</execution>
</executions>
@ -305,7 +313,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.5.0</version>
<executions>
<!-- Execute Javadoc once normally to catch any warnings -->
<execution>

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Protocol</name>
@ -41,7 +40,7 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version>
<scope>compile</scope>

View File

@ -11,6 +11,7 @@ import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EncryptionResponse;
import net.md_5.bungee.protocol.packet.EntityStatus;
import net.md_5.bungee.protocol.packet.FinishConfiguration;
import net.md_5.bungee.protocol.packet.GameState;
import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.KeepAlive;
@ -18,6 +19,7 @@ import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.LegacyHandshake;
import net.md_5.bungee.protocol.packet.LegacyPing;
import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
import net.md_5.bungee.protocol.packet.LoginRequest;
@ -34,6 +36,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
import net.md_5.bungee.protocol.packet.Subtitle;
@ -223,4 +226,16 @@ public abstract class AbstractPacketHandler
public void handle(ServerData serverData) throws Exception
{
}
public void handle(LoginAcknowledged loginAcknowledged) throws Exception
{
}
public void handle(StartConfiguration startConfiguration) throws Exception
{
}
public void handle(FinishConfiguration finishConfiguration) throws Exception
{
}
}

View File

@ -15,7 +15,9 @@ import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import se.llbit.nbt.ErrorTag;
import se.llbit.nbt.NamedTag;
import se.llbit.nbt.SpecificTag;
import se.llbit.nbt.Tag;
@RequiredArgsConstructor
@ -293,14 +295,35 @@ public abstract class DefinedPacket
return null;
}
public static Tag readTag(ByteBuf input)
public static Tag readTag(ByteBuf input, int protocolVersion)
{
Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( input ) ) );
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
Tag tag;
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
try
{
byte type = in.readByte();
if ( type == 0 )
{
return Tag.END;
} else
{
tag = SpecificTag.read( type, in );
}
} catch ( IOException ex )
{
tag = new ErrorTag( "IOException while reading tag type:\n" + ex.getMessage() );
}
} else
{
tag = NamedTag.read( in );
}
Preconditions.checkArgument( !tag.isError(), "Error reading tag: %s", tag.error() );
return tag;
}
public static void writeTag(Tag tag, ByteBuf output)
public static void writeTag(Tag tag, ByteBuf output, int protocolVersion)
{
try
{
@ -378,6 +401,11 @@ public abstract class DefinedPacket
write( buf );
}
public Protocol nextProtocol()
{
return null;
}
public abstract void handle(AbstractPacketHandler handler) throws Exception;
@Override

View File

@ -5,12 +5,14 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf>
{
@Getter
@Setter
private Protocol protocol;
private final boolean server;

View File

@ -4,12 +4,14 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
public class MinecraftEncoder extends MessageToByteEncoder<DefinedPacket>
{
@Getter
@Setter
private Protocol protocol;
private boolean server;

View File

@ -19,11 +19,13 @@ import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EncryptionResponse;
import net.md_5.bungee.protocol.packet.EntityStatus;
import net.md_5.bungee.protocol.packet.FinishConfiguration;
import net.md_5.bungee.protocol.packet.GameState;
import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
import net.md_5.bungee.protocol.packet.LoginRequest;
@ -40,6 +42,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
import net.md_5.bungee.protocol.packet.Subtitle;
@ -85,7 +88,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x1E ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x20 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1F ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x24 )
);
TO_CLIENT.registerPacket(
Login.class,
@ -100,7 +104,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x23 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x25 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x24 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x29 )
);
TO_CLIENT.registerPacket( Chat.class,
Chat::new,
@ -128,7 +133,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x3B ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x3E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x3D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 )
);
TO_CLIENT.registerPacket(
BossBar.class,
@ -138,7 +144,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_16, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_17, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0A ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0xB )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0B ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A )
);
TO_CLIENT.registerPacket(
PlayerListItem.class, // PlayerInfo
@ -168,7 +175,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0xF )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x10 )
);
TO_CLIENT.registerPacket(
ScoreboardObjective.class,
@ -183,7 +191,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x53 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A )
);
TO_CLIENT.registerPacket(
ScoreboardScore.class,
@ -198,7 +207,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D )
);
TO_CLIENT.registerPacket(
ScoreboardDisplay.class,
@ -213,7 +223,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x4C ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 )
);
TO_CLIENT.registerPacket(
Team.class,
@ -228,7 +239,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x55 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C )
);
TO_CLIENT.registerPacket(
PluginMessage.class,
@ -244,7 +256,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x16 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x17 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x17 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x18 )
);
TO_CLIENT.registerPacket(
Kick.class,
@ -260,7 +273,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x17 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x19 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x17 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1A )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x1B )
);
TO_CLIENT.registerPacket(
Title.class,
@ -276,7 +290,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_18, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 )
);
TO_CLIENT.registerPacket(
ClearTitles.class,
@ -284,7 +299,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0xE )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0E ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F )
);
TO_CLIENT.registerPacket(
Subtitle.class,
@ -293,7 +309,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_18, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F )
);
TO_CLIENT.registerPacket(
TitleTimes.class,
@ -302,7 +319,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_18, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 )
);
TO_CLIENT.registerPacket(
SystemChat.class,
@ -310,7 +328,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x62 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 )
);
TO_CLIENT.registerPacket(
PlayerListHeaderFooter.class,
@ -329,7 +348,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x63 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 )
);
TO_CLIENT.registerPacket(
EntityStatus.class,
@ -345,7 +365,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x18 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x1A ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x19 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1C )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1C ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x1D )
);
TO_CLIENT.registerPacket(
Commands.class,
@ -357,7 +378,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0E ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x10 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x11 )
);
TO_CLIENT.registerPacket(
GameState.class,
@ -369,7 +391,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x1B ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x1D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x20 )
);
TO_CLIENT.registerPacket(
ViewDistance.class,
@ -381,7 +404,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x49 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4C ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 )
);
TO_CLIENT.registerPacket(
ServerData.class,
@ -389,19 +413,27 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x3F ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x42 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 )
);
TO_CLIENT.registerPacket(
PlayerListItemRemove.class,
PlayerListItemRemove::new,
map( ProtocolConstants.MINECRAFT_1_19_3, 0x35 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3B )
);
TO_CLIENT.registerPacket(
PlayerListItemUpdate.class,
PlayerListItemUpdate::new,
map( ProtocolConstants.MINECRAFT_1_19_3, 0x36 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3C )
);
TO_CLIENT.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 )
);
TO_SERVER.registerPacket(
@ -418,7 +450,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 )
);
TO_SERVER.registerPacket( Chat.class,
Chat::new,
@ -453,7 +486,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x09 ),
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 )
);
TO_SERVER.registerPacket(
ClientSettings.class,
@ -466,7 +500,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x07 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x08 ),
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 )
);
TO_SERVER.registerPacket(
PluginMessage.class,
@ -481,7 +516,13 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F )
);
TO_SERVER.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B )
);
}
},
@ -559,6 +600,59 @@ public enum Protocol
LoginPayloadResponse::new,
map( ProtocolConstants.MINECRAFT_1_13, 0x02 )
);
TO_SERVER.registerPacket(
LoginAcknowledged.class,
LoginAcknowledged::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 )
);
}
},
// 3
CONFIGURATION
{
{
TO_CLIENT.registerPacket(
PluginMessage.class,
PluginMessage::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x00 )
);
TO_CLIENT.registerPacket(
Kick.class,
Kick::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 )
);
TO_CLIENT.registerPacket(
FinishConfiguration.class,
FinishConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 )
);
TO_CLIENT.registerPacket(
KeepAlive.class,
KeepAlive::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 )
);
TO_SERVER.registerPacket(
ClientSettings.class,
ClientSettings::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x00 )
);
TO_SERVER.registerPacket(
PluginMessage.class,
PluginMessage::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 )
);
TO_SERVER.registerPacket(
FinishConfiguration.class,
FinishConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 )
);
TO_SERVER.registerPacket(
KeepAlive.class,
KeepAlive::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 )
);
}
};
/*========================================================================*/

View File

@ -43,6 +43,7 @@ public class ProtocolConstants
public static final int MINECRAFT_1_19_3 = 761;
public static final int MINECRAFT_1_19_4 = 762;
public static final int MINECRAFT_1_20 = 763;
public static final int MINECRAFT_1_20_2 = 764;
public static final List<String> SUPPORTED_VERSIONS;
public static final List<Integer> SUPPORTED_VERSION_IDS;
@ -99,13 +100,14 @@ public class ProtocolConstants
ProtocolConstants.MINECRAFT_1_19_1,
ProtocolConstants.MINECRAFT_1_19_3,
ProtocolConstants.MINECRAFT_1_19_4,
ProtocolConstants.MINECRAFT_1_20
ProtocolConstants.MINECRAFT_1_20,
ProtocolConstants.MINECRAFT_1_20_2
);
if ( SNAPSHOT_SUPPORT )
{
// supportedVersions.add( "1.20.x" );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20 );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_2 );
}
SUPPORTED_VERSIONS = supportedVersions.build();

View File

@ -32,7 +32,7 @@ public class ClientCommand extends DefinedPacket
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
command = readString( buf );
command = readString( buf, 256 );
timestamp = buf.readLong();
salt = buf.readLong();

View File

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
@ -303,7 +304,7 @@ public class Commands extends DefinedPacket
}
@Data
private static class ArgumentRegistry
public static class ArgumentRegistry
{
private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>();
@ -325,18 +326,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
protected Boolean read(ByteBuf buf)
protected BoolArgumentType read(ByteBuf buf)
{
return buf.readBoolean();
return BoolArgumentType.bool();
}
@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>()
@ -353,7 +365,7 @@ public class Commands extends DefinedPacket
buf.writeByte( t );
}
};
private static final ArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ArgumentSerializer<FloatArgumentType>()
private static final ProperArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ProperArgumentSerializer<FloatArgumentType>()
{
@Override
protected FloatArgumentType read(ByteBuf buf)
@ -381,8 +393,20 @@ public class Commands extends DefinedPacket
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
protected DoubleArgumentType read(ByteBuf buf)
@ -410,8 +434,20 @@ public class Commands extends DefinedPacket
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
protected IntegerArgumentType read(ByteBuf buf)
@ -439,6 +475,18 @@ public class Commands extends DefinedPacket
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>()
{
@ -454,7 +502,7 @@ public class Commands extends DefinedPacket
buf.writeInt( t );
}
};
private static final ArgumentSerializer<LongArgumentType> LONG_RANGE = new ArgumentSerializer<LongArgumentType>()
private static final ProperArgumentSerializer<LongArgumentType> LONG_RANGE = new ProperArgumentSerializer<LongArgumentType>()
{
@Override
protected LongArgumentType read(ByteBuf buf)
@ -482,6 +530,18 @@ public class Commands extends DefinedPacket
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>()
{
@ -537,11 +597,20 @@ public class Commands extends DefinedPacket
static
{
register( "brigadier:bool", VOID );
register( "brigadier:bool", BOOLEAN );
PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN );
register( "brigadier:float", FLOAT_RANGE );
PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT_RANGE );
register( "brigadier:double", DOUBLE_RANGE );
PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE_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 );
PROPER_PROVIDERS.put( StringArgumentType.class, STRING );
@ -756,6 +825,404 @@ public class Commands extends DefinedPacket
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)
{
Object key;
@ -879,9 +1346,13 @@ public class Commands extends DefinedPacket
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

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@EqualsAndHashCode(callSuper = false)
public class FinishConfiguration extends DefinedPacket
{
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public Protocol nextProtocol()
{
return Protocol.GAME;
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -36,6 +36,7 @@ public class Login extends DefinedPacket
private int simulationDistance;
private boolean reducedDebugInfo;
private boolean normalRespawn;
private boolean limitedCrafting;
private boolean debug;
private boolean flat;
private Location deathLocation;
@ -49,10 +50,16 @@ public class Login extends DefinedPacket
{
hardcore = buf.readBoolean();
}
gameMode = buf.readUnsignedByte();
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
gameMode = buf.readUnsignedByte();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
previousGameMode = buf.readUnsignedByte();
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
previousGameMode = buf.readUnsignedByte();
}
worldNames = new HashSet<>();
int worldCount = readVarInt( buf );
@ -61,19 +68,25 @@ public class Login extends DefinedPacket
worldNames.add( readString( buf ) );
}
dimensions = readTag( buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
dimensions = readTag( buf, protocolVersion );
}
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
dimension = readTag( buf );
} else
dimension = readTag( buf, protocolVersion );
} else if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
dimension = readString( buf );
}
worldName = readString( buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
worldName = readString( buf );
}
} else if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
{
dimension = buf.readInt();
@ -81,7 +94,7 @@ public class Login extends DefinedPacket
{
dimension = (int) buf.readByte();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 && protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
seed = buf.readLong();
}
@ -116,6 +129,15 @@ public class Login extends DefinedPacket
{
normalRespawn = buf.readBoolean();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
limitedCrafting = buf.readBoolean();
dimension = readString( buf );
worldName = readString( buf );
seed = buf.readLong();
gameMode = buf.readUnsignedByte();
previousGameMode = buf.readByte();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
debug = buf.readBoolean();
@ -142,10 +164,16 @@ public class Login extends DefinedPacket
{
buf.writeBoolean( hardcore );
}
buf.writeByte( gameMode );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( gameMode );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
buf.writeByte( previousGameMode );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( previousGameMode );
}
writeVarInt( worldNames.size(), buf );
for ( String world : worldNames )
@ -153,19 +181,25 @@ public class Login extends DefinedPacket
writeString( world, buf );
}
writeTag( dimensions, buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
writeTag( dimensions, buf, protocolVersion );
}
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
writeTag( (Tag) dimension, buf );
} else
writeTag( (Tag) dimension, buf, protocolVersion );
} else if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
writeString( (String) dimension, buf );
}
writeString( worldName, buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
writeString( worldName, buf );
}
} else if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
{
buf.writeInt( (Integer) dimension );
@ -175,7 +209,10 @@ public class Login extends DefinedPacket
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
{
buf.writeLong( seed );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeLong( seed );
}
}
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
{
@ -208,6 +245,15 @@ public class Login extends DefinedPacket
{
buf.writeBoolean( normalRespawn );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeBoolean( limitedCrafting );
writeString( (String) dimension, buf );
writeString( worldName, buf );
buf.writeLong( seed );
buf.writeByte( gameMode );
buf.writeByte( previousGameMode );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
buf.writeBoolean( debug );

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@EqualsAndHashCode(callSuper = false)
public class LoginAcknowledged extends DefinedPacket
{
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public Protocol nextProtocol()
{
return Protocol.CONFIGURATION;
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -32,7 +32,7 @@ public class LoginRequest extends DefinedPacket
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
if ( buf.readBoolean() )
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 || buf.readBoolean() )
{
uuid = readUUID( buf );
}
@ -49,13 +49,19 @@ public class LoginRequest extends DefinedPacket
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
if ( uuid != null )
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeBoolean( true );
writeUUID( uuid, buf );
} else
{
buf.writeBoolean( false );
if ( uuid != null )
{
buf.writeBoolean( true );
writeUUID( uuid, buf );
} else
{
buf.writeBoolean( false );
}
}
}
}

View File

@ -27,7 +27,7 @@ public class Respawn extends DefinedPacket
private String levelType;
private boolean debug;
private boolean flat;
private boolean copyMeta;
private byte copyMeta;
private Location deathLocation;
private int portalCooldown;
@ -38,7 +38,7 @@ public class Respawn extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
dimension = readTag( buf );
dimension = readTag( buf, protocolVersion );
} else
{
dimension = readString( buf );
@ -62,7 +62,10 @@ public class Respawn extends DefinedPacket
previousGameMode = buf.readUnsignedByte();
debug = buf.readBoolean();
flat = buf.readBoolean();
copyMeta = buf.readBoolean();
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
copyMeta = buf.readByte();
}
} else
{
levelType = readString( buf );
@ -78,6 +81,10 @@ public class Respawn extends DefinedPacket
{
portalCooldown = readVarInt( buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
copyMeta = buf.readByte();
}
}
@Override
@ -87,7 +94,7 @@ public class Respawn extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
writeTag( (Tag) dimension, buf );
writeTag( (Tag) dimension, buf, protocolVersion );
} else
{
writeString( (String) dimension, buf );
@ -111,7 +118,10 @@ public class Respawn extends DefinedPacket
buf.writeByte( previousGameMode );
buf.writeBoolean( debug );
buf.writeBoolean( flat );
buf.writeBoolean( copyMeta );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( copyMeta );
}
} else
{
writeString( levelType, buf );
@ -132,6 +142,10 @@ public class Respawn extends DefinedPacket
{
writeVarInt( portalCooldown, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( copyMeta );
}
}
@Override

View File

@ -7,6 +7,7 @@ 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
@ -18,20 +19,32 @@ public class ScoreboardDisplay extends DefinedPacket
/**
* 0 = list, 1 = side, 2 = below.
*/
private byte position;
private int position;
private String name;
@Override
public void read(ByteBuf buf)
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
position = buf.readByte();
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
position = readVarInt( buf );
} else
{
position = buf.readByte();
}
name = readString( buf );
}
@Override
public void write(ByteBuf buf)
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
buf.writeByte( position );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
writeVarInt( position, buf );
} else
{
buf.writeByte( position );
}
writeString( name, buf );
}

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@EqualsAndHashCode(callSuper = false)
public class StartConfiguration extends DefinedPacket
{
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public Protocol nextProtocol()
{
return Protocol.CONFIGURATION;
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Proxy</name>
@ -52,37 +51,37 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-log</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-native</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-query</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-slf4j</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
@ -96,26 +95,26 @@
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
<version>8.1.0</version>
<scope>runtime</scope>
</dependency>
<!-- add these back in as they are not exposed by the API -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<version>3.9.2</version>
<version>3.8.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-http</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>

View File

@ -89,7 +89,6 @@ import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.log.BungeeLogger;
import net.md_5.bungee.log.LoggingForwardHandler;
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.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -173,7 +172,6 @@ public class BungeeCord extends ProxyServer
.registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create();
@Getter
private ConnectionThrottle connectionThrottle;
private final ModuleManager moduleManager = new ModuleManager();
{
// TODO: Proper fallback when we interface the manager
@ -271,10 +269,6 @@ public class BungeeCord extends ProxyServer
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();
pluginManager.detectPlugins( pluginsFolder );

View File

@ -5,7 +5,6 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
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( "*** 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( "*** Server will start in 10 seconds ***" );
Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) );
}
}

View File

@ -103,26 +103,30 @@ public class BungeeServerInfo implements ServerInfo
sendData( channel, data, true );
}
// TODO: Don't like this method
@Override
public boolean sendData(String channel, byte[] data, boolean queue)
{
Preconditions.checkNotNull( channel, "channel" );
Preconditions.checkNotNull( data, "data" );
synchronized ( packetQueue )
Server server;
synchronized ( players )
{
Server server = ( players.isEmpty() ) ? null : players.iterator().next().getServer();
if ( server != null )
{
server.sendData( channel, data );
return true;
} else if ( queue )
server = ( players.isEmpty() ) ? null : players.iterator().next().getServer();
}
if ( server != null )
{
server.sendData( channel, data );
return true;
} else if ( queue )
{
synchronized ( packetQueue )
{
packetQueue.add( new PluginMessage( channel, data, false ) );
}
return false;
}
return false;
}
private long lastPing;

View File

@ -43,6 +43,7 @@ import net.md_5.bungee.protocol.packet.GameState;
import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
import net.md_5.bungee.protocol.packet.LoginRequest;
@ -52,6 +53,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.ViewDistance;
import net.md_5.bungee.util.AddressUtil;
import net.md_5.bungee.util.BufUtil;
@ -73,7 +75,7 @@ public class ServerConnector extends PacketHandler
private enum State
{
LOGIN_SUCCESS, ENCRYPT_RESPONSE, LOGIN, FINISHED;
LOGIN_SUCCESS, LOGIN, FINISHED;
}
@Override
@ -84,13 +86,13 @@ public class ServerConnector extends PacketHandler
return;
}
String message = "Exception Connecting:" + Util.exception( t );
String message = ChatColor.RED + "Exception Connecting: " + Util.exception( t );
if ( user.getServer() == null )
{
user.disconnect( message );
} else
{
user.sendMessage( ChatColor.RED + message );
user.sendMessage( message );
}
}
@ -145,8 +147,15 @@ public class ServerConnector extends PacketHandler
public void handle(LoginSuccess loginSuccess) throws Exception
{
Preconditions.checkState( thisState == State.LOGIN_SUCCESS, "Not expecting LOGIN_SUCCESS" );
ch.setProtocol( Protocol.GAME );
thisState = State.LOGIN;
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 )
{
ServerConnection server = new ServerConnection( ch, target );
cutThrough( server );
} else
{
ch.setProtocol( Protocol.GAME );
thisState = State.LOGIN;
}
// Only reset the Forge client when:
// 1) The user is switching servers (so has a current server)
@ -182,6 +191,12 @@ public class ServerConnector extends PacketHandler
Preconditions.checkState( thisState == State.LOGIN, "Not expecting LOGIN" );
ServerConnection server = new ServerConnection( ch, target );
handleLogin( bungee, ch, user, target, handshakeHandler, server, login );
cutThrough( server );
}
public static void handleLogin(ProxyServer bungee, ChannelWrapper ch, UserConnection user, BungeeServerInfo target, ForgeServerHandler handshakeHandler, ServerConnection server, Login login) throws Exception
{
ServerConnectedEvent event = new ServerConnectedEvent( user, server );
bungee.getPluginManager().callEvent( event );
@ -225,14 +240,13 @@ public class ServerConnector extends PacketHandler
// Set tab list size, TODO: what shall we do about packet mutability
Login modLogin = new Login( login.getEntityId(), login.isHardcore(), login.getGameMode(), login.getPreviousGameMode(), login.getWorldNames(), login.getDimensions(), login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(),
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.getSimulationDistance(), login.isReducedDebugInfo(), login.isNormalRespawn(), login.isDebug(), login.isFlat(), login.getDeathLocation(),
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.getSimulationDistance(), login.isReducedDebugInfo(), login.isNormalRespawn(), login.isLimitedCrafting(), login.isDebug(), login.isFlat(), login.getDeathLocation(),
login.getPortalCooldown() );
user.unsafe().sendPacket( modLogin );
if ( user.getServer() != null )
if ( user.getDimension() != null )
{
user.getServer().setObsolete( true );
user.getTabListHandler().onServerChange();
user.getServerSentScoreboard().clear();
@ -244,14 +258,15 @@ public class ServerConnector extends PacketHandler
}
user.getSentBossBars().clear();
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), false, login.getDeathLocation(),
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), (byte) 0, login.getDeathLocation(),
login.getPortalCooldown() ) );
user.getServer().disconnect( "Quitting" );
} else
{
user.unsafe().sendPacket( BungeeCord.getInstance().registerChannels( user.getPendingConnection().getVersion() ) );
ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer();
DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")", brand );
user.unsafe().sendPacket( new PluginMessage( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13 ? "minecraft:brand" : "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler.isServerForge() ) );
user.unsafe().sendPacket( new PluginMessage( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13 ? "minecraft:brand" : "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler != null && handshakeHandler.isServerForge() ) );
brand.release();
}
@ -295,19 +310,40 @@ public class ServerConnector extends PacketHandler
if ( login.getDimension() == user.getDimension() )
{
user.unsafe().sendPacket( new Respawn( (Integer) login.getDimension() >= 0 ? -1 : 0, login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(),
false, login.getDeathLocation(), login.getPortalCooldown() ) );
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
}
user.setServerEntityId( login.getEntityId() );
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(),
false, login.getDeathLocation(), login.getPortalCooldown() ) );
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_14 )
{
user.unsafe().sendPacket( new ViewDistance( login.getViewDistance() ) );
}
user.setDimension( login.getDimension() );
}
}
// Remove from old servers
private void cutThrough(ServerConnection server)
{
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 )
{
if ( user.getServer() != null )
{
// Begin config mode
user.unsafe().sendPacket( new StartConfiguration() );
} else
{
ch.setDecodeProtocol( Protocol.CONFIGURATION );
ch.write( new LoginAcknowledged() );
ch.setEncodeProtocol( Protocol.CONFIGURATION );
}
}
// Remove from old servers
if ( user.getServer() != null )
{
user.getServer().setObsolete( true );
user.getServer().disconnect( "Quitting" );
}

View File

@ -72,6 +72,7 @@ public final class UserConnection implements ProxiedPlayer
/*========================================================================*/
@NonNull
private final ProxyServer bungee;
@Getter
@NonNull
private final ChannelWrapper ch;
@Getter
@ -124,6 +125,9 @@ public final class UserConnection implements ProxiedPlayer
private final Scoreboard serverSentScoreboard = new Scoreboard();
@Getter
private final Collection<UUID> sentBossBars = new HashSet<>();
@Getter
@Setter
private String lastCommandTabbed;
/*========================================================================*/
@Getter
private String displayName;

View File

@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.StringRange;
@ -19,11 +20,17 @@ import io.netty.channel.unix.DomainSocketAddress;
import java.io.DataInput;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.logging.Level;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.ServerConnection;
import net.md_5.bungee.ServerConnection.KeepAliveData;
import net.md_5.bungee.ServerConnector;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.Util;
import net.md_5.bungee.api.ProxyServer;
@ -31,6 +38,8 @@ import net.md_5.bungee.api.chat.BaseComponent;
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.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.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerDisconnectEvent;
@ -48,11 +57,13 @@ import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.packet.BossBar;
import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.PlayerListItem;
import net.md_5.bungee.protocol.packet.PlayerListItemRemove;
import net.md_5.bungee.protocol.packet.PlayerListItemUpdate;
@ -80,6 +91,7 @@ public class DownstreamBridge extends PacketHandler
private final ProxyServer bungee;
private final UserConnection con;
private final ServerConnection server;
private boolean receivedLogin;
@Override
public void exception(Throwable t) throws Exception
@ -131,7 +143,7 @@ public class DownstreamBridge extends PacketHandler
public void handle(PacketWrapper packet) throws Exception
{
EntityMap rewrite = con.getEntityRewrite();
if ( rewrite != null )
if ( rewrite != null && con.getCh().getEncodeProtocol() == Protocol.GAME )
{
rewrite.rewriteClientbound( packet.buf, con.getServerEntityId(), con.getClientEntityId(), con.getPendingConnection().getVersion() );
}
@ -292,7 +304,7 @@ public class DownstreamBridge extends PacketHandler
Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" );
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 ) );
brand.release();
// changes in the packet are ignored so we need to send it manually
@ -401,6 +413,27 @@ public class DownstreamBridge extends PacketHandler
}
break;
}
case "GetPlayerServer":
{
String name = in.readUTF();
ProxiedPlayer player = bungee.getPlayer( name );
out.writeUTF( "GetPlayerServer" );
out.writeUTF( name );
if ( player == null )
{
out.writeUTF( "" );
break;
}
Server srv = player.getServer();
if ( srv == null )
{
out.writeUTF( "" );
} else
{
out.writeUTF( srv.getInfo().getName() );
}
break;
}
case "IP":
out.writeUTF( "IP" );
if ( con.getSocketAddress() instanceof InetSocketAddress )
@ -562,6 +595,16 @@ public class DownstreamBridge extends PacketHandler
}
break;
}
case "KickPlayerRaw":
{
ProxiedPlayer player = bungee.getPlayer( in.readUTF() );
if ( player != null )
{
BaseComponent[] kickReason = ComponentSerializer.parse( in.readUTF() );
player.disconnect( kickReason );
}
break;
}
}
// Check we haven't set out to null, and we have written data, if so reply back back along the BungeeCord channel
@ -614,6 +657,23 @@ public class DownstreamBridge extends PacketHandler
return input.getText();
}
} );
} else
{
String last = con.getLastCommandTabbed();
if ( last != null )
{
String commandName = last.toLowerCase( Locale.ROOT );
commands.addAll( bungee.getPluginManager().getCommands().stream()
.filter( (entry) ->
{
String lowerCase = entry.getKey().toLowerCase( Locale.ROOT );
return lowerCase.startsWith( commandName ) && entry.getValue().hasPermission( con ) && !bungee.getDisabledCommands().contains( lowerCase );
} )
.map( (stringCommandEntry) -> '/' + stringCommandEntry.getKey() )
.collect( Collectors.toList() ) );
commands.sort( null );
con.setLastCommandTabbed( null );
}
}
TabCompleteResponseEvent tabCompleteResponseEvent = new TabCompleteResponseEvent( server, con, new ArrayList<>( commands ) );
@ -674,6 +734,11 @@ public class DownstreamBridge extends PacketHandler
{
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() )
{
if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) )
@ -690,11 +755,65 @@ public class DownstreamBridge extends PacketHandler
if ( modified )
{
commands.setRoot( (com.mojang.brigadier.tree.RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) );
con.unsafe().sendPacket( commands );
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
public void handle(ServerData serverData) throws Exception
{
@ -705,6 +824,17 @@ public class DownstreamBridge extends PacketHandler
throw CancelSendSignal.INSTANCE;
}
@Override
public void handle(Login login) throws Exception
{
Preconditions.checkState( !receivedLogin, "Not expecting login" );
receivedLogin = true;
ServerConnector.handleLogin( bungee, server.getCh(), con, server.getInfo(), null, server, login );
throw CancelSendSignal.INSTANCE;
}
@Override
public String toString()
{

View File

@ -59,6 +59,7 @@ import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.LegacyHandshake;
import net.md_5.bungee.protocol.packet.LegacyPing;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
import net.md_5.bungee.protocol.packet.LoginRequest;
import net.md_5.bungee.protocol.packet.LoginSuccess;
@ -111,6 +112,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private boolean legacy;
@Getter
private String extraDataInHandshake = "";
private UserConnection userCon;
@Getter
private boolean duplication = false;
@Getter
private String realName = null;
@Getter
private UUID realId = null;
@Override
public boolean shouldHandle(PacketWrapper packet) throws Exception
@ -121,12 +132,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private enum State
{
HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, FINISHING;
HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, FINISHING, CONFIGURING;
}
private boolean canSendKickMessage()
{
return thisState == State.USERNAME || thisState == State.ENCRYPT || thisState == State.FINISHING;
return thisState == State.USERNAME || thisState == State.ENCRYPT || thisState == State.FINISHING || thisState == State.CONFIGURING;
}
@Override
@ -409,6 +420,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
}
this.loginRequest = loginRequest;
setName( realName = loginRequest.getData() );
int limit = BungeeCord.getInstance().config.getPlayerLimit();
if ( limit > 0 && bungee.getOnlineCount() >= limit )
@ -417,14 +429,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
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>()
{
@ -441,6 +445,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
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 )
{
thisState = State.ENCRYPT;
@ -495,8 +509,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
if ( obj != null && obj.getId() != null )
{
loginProfile = obj;
name = obj.getName();
uniqueId = Util.getUUID( obj.getId() );
setName( realName = obj.getName() );
uniqueId = realId = Util.getUUID( obj.getId() );
finish();
return;
}
@ -514,10 +528,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private void finish()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
if ( uniqueId == null )
if ( uniqueId == null ) // offline mode and no plugin used setUniqueId()
{
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;
}
}
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
@ -593,29 +622,18 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
if ( !ch.isClosing() )
{
UserConnection userCon = new UserConnection( bungee, ch, getName(), InitialHandler.this );
userCon = new UserConnection( bungee, ch, getName(), InitialHandler.this );
userCon.setCompressionThreshold( BungeeCord.getInstance().config.getCompressionThreshold() );
userCon.init();
unsafe.sendPacket( new LoginSuccess( getUniqueId(), getName(), ( loginProfile == null ) ? null : loginProfile.getProperties() ) );
ch.setProtocol( Protocol.GAME );
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
ServerInfo server;
if ( bungee.getReconnectHandler() != null )
if ( getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 )
{
server = bungee.getReconnectHandler().getServer( userCon );
thisState = State.CONFIGURING;
} else
{
server = AbstractReconnectHandler.getForcedHost( InitialHandler.this );
ch.setProtocol( Protocol.GAME );
finish2();
}
if ( server == null )
{
server = bungee.getServerInfo( listener.getDefaultServer() );
}
userCon.connect( server, null, true, ServerConnectEvent.Reason.JOIN_PROXY );
}
}
} );
@ -626,6 +644,37 @@ public class InitialHandler extends PacketHandler implements PendingConnection
bungee.getPluginManager().callEvent( new LoginEvent( InitialHandler.this, complete ) );
}
@Override
public void handle(LoginAcknowledged loginAcknowledged) throws Exception
{
Preconditions.checkState( thisState == State.CONFIGURING, "Not expecting CONFIGURING" );
finish2();
ch.setEncodeProtocol( Protocol.CONFIGURATION );
}
private void finish2()
{
userCon.init();
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
ServerInfo server;
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 );
}
@Override
public void handle(LoginPayloadResponse response) throws Exception
{
@ -671,6 +720,54 @@ public class InitialHandler extends PacketHandler implements PendingConnection
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;
}
@Override
public int getVersion()
{
@ -710,6 +807,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
this.uniqueId = uuid;
}
private void updateOfflineId()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
}
@Override
public String getUUID()
{

View File

@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import io.netty.channel.Channel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import net.md_5.bungee.BungeeCord;
@ -20,20 +19,24 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.SettingsChangedEvent;
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.forge.ForgeConstants;
import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.packet.Chat;
import net.md_5.bungee.protocol.packet.ClientChat;
import net.md_5.bungee.protocol.packet.ClientCommand;
import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.PlayerListItem;
import net.md_5.bungee.protocol.packet.PlayerListItemRemove;
import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.TabCompleteRequest;
import net.md_5.bungee.protocol.packet.TabCompleteResponse;
import net.md_5.bungee.util.AllowedCharacters;
@ -51,7 +54,6 @@ public class UpstreamBridge extends PacketHandler
BungeeCord.getInstance().addConnection( con );
con.getTabListHandler().onConnect();
con.unsafe().sendPacket( BungeeCord.getInstance().registerChannels( con.getPendingConnection().getVersion() ) );
}
@Override
@ -134,7 +136,7 @@ public class UpstreamBridge extends PacketHandler
if ( con.getServer() != null )
{
EntityMap rewrite = con.getEntityRewrite();
if ( rewrite != null )
if ( rewrite != null && con.getServer().getCh().getEncodeProtocol() == Protocol.GAME )
{
rewrite.rewriteServerbound( packet.buf, con.getClientEntityId(), con.getServerEntityId(), con.getPendingConnection().getVersion() );
}
@ -213,8 +215,9 @@ public class UpstreamBridge extends PacketHandler
{
List<String> suggestions = new ArrayList<>();
boolean isRegisteredCommand = false;
boolean isCommand = tabComplete.getCursor().startsWith( "/" );
if ( tabComplete.getCursor().startsWith( "/" ) )
if ( isCommand )
{
isRegisteredCommand = bungee.getPluginManager().dispatchCommand( con, tabComplete.getCursor().substring( 1 ), suggestions );
}
@ -222,32 +225,42 @@ public class UpstreamBridge extends PacketHandler
TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions );
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;
}
List<String> results = tabCompleteEvent.getSuggestions();
if ( !results.isEmpty() )
Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions();
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 )
{
List<String> results = new ArrayList<>( brigadierResults.getList().size() );
for ( Suggestion s : brigadierResults.getList() )
{
results.add( s.getText() );
}
con.unsafe().sendPacket( new TabCompleteResponse( results ) );
} else
{
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1;
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 ) ) );
con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) );
}
throw CancelSendSignal.INSTANCE;
}
@ -257,6 +270,15 @@ public class UpstreamBridge extends PacketHandler
{
throw CancelSendSignal.INSTANCE;
}
if ( isCommand && con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 )
{
int lastSpace = tabComplete.getCursor().lastIndexOf( ' ' );
if ( lastSpace == -1 )
{
con.setLastCommandTabbed( tabComplete.getCursor().substring( 1 ) );
}
}
}
@Override
@ -309,6 +331,19 @@ public class UpstreamBridge extends PacketHandler
con.getPendingConnection().relayMessage( pluginMessage );
}
@Override
public void handle(StartConfiguration startConfiguration) throws Exception
{
ChannelWrapper ch = con.getServer().getCh();
if ( ch.getDecodeProtocol() == Protocol.LOGIN )
{
ch.setDecodeProtocol( Protocol.CONFIGURATION );
ch.write( new LoginAcknowledged() );
ch.setEncodeProtocol( Protocol.CONFIGURATION );
throw CancelSendSignal.INSTANCE;
}
}
@Override
public String toString()
{

View File

@ -82,6 +82,8 @@ public abstract class EntityMap
case ProtocolConstants.MINECRAFT_1_19_4:
case ProtocolConstants.MINECRAFT_1_20:
return EntityMap_1_16_2.INSTANCE_1_19_4;
case ProtocolConstants.MINECRAFT_1_20_2:
return EntityMap_1_16_2.INSTANCE_1_20_2;
}
throw new RuntimeException( "Version " + version + " has no entity map" );
}

View File

@ -20,6 +20,7 @@ class EntityMap_1_16_2 extends EntityMap
static final EntityMap_1_16_2 INSTANCE_1_19 = new EntityMap_1_16_2( 0x02, 0x2F );
static final EntityMap_1_16_2 INSTANCE_1_19_1 = new EntityMap_1_16_2( 0x02, 0x30 );
static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 );
static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 );
//
private final int spawnPlayerId;
private final int spectateId;

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

View File

@ -1,7 +0,0 @@
package net.md_5.bungee.module;
interface ModuleSource
{
void retrieve(ModuleSpec module, ModuleVersion version);
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module;
import java.io.File;
import lombok.Data;
@Data
public class ModuleSpec
{
private final String name;
private final File file;
private final ModuleSource provider;
}

View File

@ -1,35 +0,0 @@
package net.md_5.bungee.module;
import lombok.AccessLevel;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class ModuleVersion
{
private final String build;
private final String git;
public static ModuleVersion parse(String version)
{
int lastColon = version.lastIndexOf( ':' );
int secondLastColon = version.lastIndexOf( ':', lastColon - 1 );
if ( lastColon == -1 || secondLastColon == -1 )
{
return null;
}
String buildNumber = version.substring( lastColon + 1, version.length() );
String gitCommit = version.substring( secondLastColon + 1, lastColon ).replaceAll( "\"", "" );
if ( "unknown".equals( buildNumber ) || "unknown".equals( gitCommit ) )
{
return null;
}
return new ModuleVersion( buildNumber, gitCommit );
}
}

View File

@ -11,6 +11,7 @@ import lombok.Getter;
import lombok.Setter;
import net.md_5.bungee.compress.PacketCompressor;
import net.md_5.bungee.compress.PacketDecompressor;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.MinecraftDecoder;
import net.md_5.bungee.protocol.MinecraftEncoder;
import net.md_5.bungee.protocol.PacketWrapper;
@ -35,12 +36,33 @@ public class ChannelWrapper
this.remoteAddress = ( this.ch.remoteAddress() == null ) ? this.ch.parent().localAddress() : this.ch.remoteAddress();
}
public void setProtocol(Protocol protocol)
public Protocol getDecodeProtocol()
{
return ch.pipeline().get( MinecraftDecoder.class ).getProtocol();
}
public void setDecodeProtocol(Protocol protocol)
{
ch.pipeline().get( MinecraftDecoder.class ).setProtocol( protocol );
}
public Protocol getEncodeProtocol()
{
return ch.pipeline().get( MinecraftEncoder.class ).getProtocol();
}
public void setEncodeProtocol(Protocol protocol)
{
ch.pipeline().get( MinecraftEncoder.class ).setProtocol( protocol );
}
public void setProtocol(Protocol protocol)
{
setDecodeProtocol( protocol );
setEncodeProtocol( protocol );
}
public void setVersion(int protocol)
{
ch.pipeline().get( MinecraftDecoder.class ).setProtocolVersion( protocol );
@ -51,13 +73,29 @@ public class ChannelWrapper
{
if ( !closed )
{
DefinedPacket defined = null;
if ( packet instanceof PacketWrapper )
{
( (PacketWrapper) packet ).setReleased( true );
ch.writeAndFlush( ( (PacketWrapper) packet ).buf, ch.voidPromise() );
PacketWrapper wrapper = (PacketWrapper) packet;
wrapper.setReleased( true );
ch.writeAndFlush( wrapper.buf, ch.voidPromise() );
defined = wrapper.packet;
} else
{
ch.writeAndFlush( packet, ch.voidPromise() );
if ( packet instanceof DefinedPacket )
{
defined = (DefinedPacket) packet;
}
}
if ( defined != null )
{
Protocol nextProtocol = defined.nextProtocol();
if ( nextProtocol != null )
{
setEncodeProtocol( nextProtocol );
}
}
}
}
@ -124,11 +162,11 @@ public class ChannelWrapper
public void setCompressionThreshold(int compressionThreshold)
{
if ( ch.pipeline().get( PacketCompressor.class ) == null && compressionThreshold != -1 )
if ( ch.pipeline().get( PacketCompressor.class ) == null && compressionThreshold >= 0 )
{
addBefore( PipelineUtils.PACKET_ENCODER, "compress", new PacketCompressor() );
}
if ( compressionThreshold != -1 )
if ( compressionThreshold >= 0 )
{
ch.pipeline().get( PacketCompressor.class ).setThreshold( compressionThreshold );
} else
@ -136,11 +174,11 @@ public class ChannelWrapper
ch.pipeline().remove( "compress" );
}
if ( ch.pipeline().get( PacketDecompressor.class ) == null && compressionThreshold != -1 )
if ( ch.pipeline().get( PacketDecompressor.class ) == null && compressionThreshold >= 0 )
{
addBefore( PipelineUtils.PACKET_DECODER, "decompress", new PacketDecompressor() );
}
if ( compressionThreshold == -1 )
if ( compressionThreshold < 0 )
{
ch.pipeline().remove( "decompress" );
}

View File

@ -17,6 +17,7 @@ import net.md_5.bungee.connection.PingHandler;
import net.md_5.bungee.protocol.BadPacketException;
import net.md_5.bungee.protocol.OverflowPacketException;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.util.QuietException;
/**
@ -101,9 +102,18 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
return;
}
PacketWrapper packet = (PacketWrapper) msg;
if ( packet.packet != null )
{
Protocol nextProtocol = packet.packet.nextProtocol();
if ( nextProtocol != null )
{
channel.setDecodeProtocol( nextProtocol );
}
}
if ( handler != null )
{
PacketWrapper packet = (PacketWrapper) msg;
boolean sendPacket = handler.shouldHandle( packet );
try
{

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-query</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Query</name>
@ -25,7 +24,7 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>

View File

@ -4,15 +4,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-slf4j</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-SLF4J</name>