Compare commits

...

44 Commits

Author SHA1 Message Date
93cbdab1f6 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2024-12-11 22:33:44 +01:00
46c233d032 Add CommandsDeclareEvent to declare commands with brigadier API 2024-12-11 22:33:43 +01:00
89053d2254 Server branding now includes the backend server name 2024-12-11 22:33:43 +01:00
5932730744 Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2024-12-11 22:33:43 +01:00
3d89980065 Change projet configuration and POM for Pandacube 2024-12-11 22:33:43 +01:00
21880c668a Remove modules and startup delay
We don’t need them for Pandacube
2024-12-11 22:33:40 +01:00
Outfluencer
7340f1a035
#3765: Fix forgotten boolean write 2024-12-08 07:50:03 +11:00
md_5
8a80435e64
Minecraft 1.21.4 support 2024-12-04 03:20:00 +11:00
md_5
20a71b06a9
Minecraft 1.21.4-rc3 support 2024-11-30 10:11:33 +11:00
md_5
b376f61578
Minecraft 1.21.4-pre2 support 2024-11-26 20:38:03 +11:00
md_5
373dab05ad
Minecraft 1.21.4-pre1 support 2024-11-23 12:27:38 +11:00
Outfluencer
f6b40b1186
#3758: Handle LoginPayloadResponse in UpstreamBridge 2024-11-19 20:20:17 +11:00
Outfluencer
81b118a8ba
#3759: Remove unnecessary protocol version check for UnsignedClientCommand 2024-11-17 11:44:17 +11:00
BoomEaro
7a42f12716
#3760: Fix possible NPE when trying to get encoder/decoder protocol 2024-11-17 11:43:31 +11:00
md_5
4886c4be01
Minecraft 1.21.2 support 2024-10-23 02:15:00 +11:00
md_5
7338d0f444
Minecraft 1.21.2-rc2 support 2024-10-22 07:32:49 +11:00
Outfluencer
8212e10c7c
#3756, #3757: Queue PlayerListItemRemove packets for disconnecting players 2024-10-21 21:05:01 +11:00
md_5
2593130b3e
Minecraft 1.21.2-rc1 support 2024-10-19 08:56:06 +11:00
md_5
6ea49962c5
Minecraft 1.21.2-pre3 support 2024-10-13 09:53:59 +11:00
Outfluencer
672db9fe47
#3753, #3754: Don't disconnect during login if the player is on a server 2024-10-13 09:38:59 +11:00
Outfluencer
2bacf6572b
#3743: Fix infinite encrypting screen on miss configured ip-forwarding 2024-10-06 19:03:45 +11:00
Valentine
9813e46e66
#3746, #3666: Fix potential race conditions when connecting to multiple servers at the same time 2024-10-06 18:55:12 +11:00
Valentine
01a5f36012
#3751: Fix potential overriding of cipher by other libraries 2024-09-29 19:44:15 +10:00
md_5
f0a30c43cd
Minecraft 24w39a support 2024-09-28 08:51:09 +10:00
Outfluencer
acb85e30fa
#3742: Add more checks to InitialHandler 2024-09-21 09:05:50 +10:00
Outfluencer
9437cedc48
#3748: Minecraft 24w38a support 2024-09-21 09:02:28 +10:00
Outfluencer
a89cf5f36d
#3736: Add simple login payload API 2024-09-09 21:06:48 +10:00
Outfluencer
b309e4ac50
#3737: Use composite buffers where possible 2024-09-09 21:01:19 +10:00
md_5
477ea5983c
Remove unused field 2024-09-08 13:15:40 +10:00
Outfluencer
eca6090f1e
#3739: Support aarch64 natives 2024-09-08 09:15:02 +10:00
md_5
8f8c270f3b
Minecraft 24w36a support 2024-09-07 09:13:23 +10:00
md_5
84ac7ab944
Minecraft 24w35a support 2024-09-02 21:06:47 +10:00
Outfluencer
5fbcc6b119
#3732: Fix protocol state issue 2024-08-26 20:06:34 +10:00
Janmm14
79f85a2ce2
#3662: Add deprecation warning to ComponentSerializer.toString(Object)
It taking all objects is error-prone, deprecate it and create overloads
for used acceptable types.
2024-08-25 09:28:49 +10:00
Outfluencer
d32eedd333
#3727: 24w34a snapshot support 2024-08-25 09:15:03 +10:00
Outfluencer
e1d4b6adc7
#3731: Update cookie handling with vanilla limits and don't allow unrequested cookies 2024-08-25 09:10:00 +10:00
Outfluencer
534148763f
#3721: Improve same uuid and name checks
We didn't return so the login event was fired for a disconnected player
2024-08-22 19:25:45 +10:00
lax1dude
cd56fb32c2
#3722: Disable GZIP in native compress library (no longer requires PCLMUL) 2024-08-09 19:07:38 +10:00
lax1dude
6b612302e1
#3718, #3717: Add check for SSE 4.2 and PCLMUL support to native zlib 2024-08-08 18:19:20 +10:00
lax1dude
e49759025f
#3716, #3707: Fix native-cipher segfault when using musl libc 2024-08-08 18:19:20 +10:00
Outfluencer
c310e3339f
#3720: Replace some println calls with proxy logger 2024-08-07 19:57:09 +10:00
Nick
b64615e298
#3715: Fix maximum length for command packets 2024-07-28 21:07:49 +10:00
Raraph84
45d2f44003
#3713: Add default admin permissions for /find and /send 2024-07-28 21:04:41 +10:00
Raraph84
a57adcce00
#3711, #3712: Don't try to reconnect player when it disconnects manually
* Set server obsolete when disconnected by the proxy
2024-07-28 21:02:31 +10:00
116 changed files with 1689 additions and 1775 deletions

View File

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

View File

@ -113,4 +113,18 @@ public interface PendingConnection extends Connection
*/
@ApiStatus.Experimental
CompletableFuture<byte[]> retrieveCookie(String cookie);
/**
* Sends a login payload request to the client.
*
* @param channel the channel to send this data via
* @param data the data to send
* @return a {@link CompletableFuture} that will be completed when the Login
* Payload response is received. If the Vanilla client doesn't know the
* channel, the {@link CompletableFuture} will complete with a null value
* @throws IllegalStateException if the player's version is not at least
* 1.13
*/
@ApiStatus.Experimental
CompletableFuture<byte[]> sendData(String channel, byte[] data);
}

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,13 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
@ -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>
@ -36,7 +33,7 @@
</dependencies>
<build>
<finalName>BungeeCord</finalName>
<finalName>BungeeCord-${project.version}-${build.number}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
@ -22,7 +21,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<version>2.11.0</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.chat;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
@ -129,6 +130,10 @@ public abstract class BaseComponent
{
setColor( component.getColorRaw() );
}
if ( replace || !style.hasShadowColor() )
{
setShadowColor( component.getShadowColorRaw() );
}
if ( replace || !style.hasFont() )
{
setFont( component.getFontRaw() );
@ -175,6 +180,7 @@ public abstract class BaseComponent
if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE )
{
setColor( null );
setShadowColor( null );
setBold( null );
setItalic( null );
setUnderlined( null );
@ -295,6 +301,46 @@ public abstract class BaseComponent
return style.getColor();
}
/**
* Set this component's shadow color.
*
* @param color the component shadow color, or null to use the default
*/
public void setShadowColor(Color color)
{
this.style.setShadowColor( color );
}
/**
* Returns the shadow color of this component. This uses the parent's shadow color if this
* component doesn't have one. null is returned if no shadow color is found.
*
* @return the shadow color of this component
*/
public Color getShadowColor()
{
if ( !style.hasShadowColor() )
{
if ( parent == null )
{
return null;
}
return parent.getShadowColor();
}
return style.getShadowColor();
}
/**
* Returns the shadow color of this component without checking the parents
* shadow color. May return null
*
* @return the shadow color of this component
*/
public Color getShadowColorRaw()
{
return style.getShadowColor();
}
/**
* Set this component's font.
*
@ -536,6 +582,10 @@ public abstract class BaseComponent
{
setColor( style.getColor() );
}
if ( style.hasShadowColor() )
{
setShadowColor( style.getShadowColor() );
}
if ( style.hasFont() )
{
setFont( style.getFont() );

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.chat;
import java.awt.Color;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@ -23,6 +24,10 @@ public final class ComponentStyle implements Cloneable
* {@link ChatColor#color} should not be null).</b>
*/
private ChatColor color;
/**
* The shadow color of this style.
*/
private Color shadowColor;
/**
* The font of this style.
*/
@ -68,6 +73,26 @@ public final class ComponentStyle implements Cloneable
return ( color != null );
}
/**
* Returns the shadow color of this style. May return null.
*
* @return the shadow color of this style, or null if default color
*/
public Color getShadowColor()
{
return shadowColor;
}
/**
* Returns whether or not this style has a shadow color set.
*
* @return whether a shadow color is set
*/
public boolean hasShadowColor()
{
return ( shadowColor != null );
}
/**
* Returns the font of this style. May return null.
*
@ -195,7 +220,7 @@ public final class ComponentStyle implements Cloneable
*/
public boolean isEmpty()
{
return color == null && font == null && bold == null
return color == null && shadowColor == null && font == null && bold == null
&& italic == null && underlined == null
&& strikethrough == null && obfuscated == null;
}
@ -203,7 +228,7 @@ public final class ComponentStyle implements Cloneable
@Override
public ComponentStyle clone()
{
return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated );
}
/**
@ -227,6 +252,7 @@ public final class ComponentStyle implements Cloneable
{
return new ComponentStyleBuilder()
.color( other.color )
.shadowColor( other.shadowColor )
.font( other.font )
.bold( other.bold )
.italic( other.italic )

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.chat;
import java.awt.Color;
import net.md_5.bungee.api.ChatColor;
/**
@ -26,6 +27,7 @@ public final class ComponentStyleBuilder
{
private ChatColor color;
private Color shadowColor;
private String font;
private Boolean bold, italic, underlined, strikethrough, obfuscated;
@ -41,6 +43,18 @@ public final class ComponentStyleBuilder
return this;
}
/**
* Set the style shadow color.
*
* @param shadowColor the shadow color to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder shadowColor(Color shadowColor)
{
this.shadowColor = shadowColor;
return this;
}
/**
* Set the style font.
*
@ -121,6 +135,6 @@ public final class ComponentStyleBuilder
*/
public ComponentStyle build()
{
return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated );
}
}

View File

@ -20,6 +20,7 @@ import net.md_5.bungee.api.chat.ScoreComponent;
import net.md_5.bungee.api.chat.SelectorComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.TranslatableComponent;
import net.md_5.bungee.api.chat.hover.content.Content;
import net.md_5.bungee.api.chat.hover.content.Entity;
import net.md_5.bungee.api.chat.hover.content.EntitySerializer;
import net.md_5.bungee.api.chat.hover.content.Item;
@ -158,11 +159,28 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
return gson.toJsonTree( style );
}
/**
* @param object the object to serialize
* @return the JSON string representation of the object
* @deprecated Error-prone, be careful which object you input here
*/
@Deprecated
public static String toString(Object object)
{
return gson.toJson( object );
}
/**
* @param content the content to serialize
* @return the JSON string representation of the object
* @deprecated for legacy internal use only
*/
@Deprecated
public static String toString(Content content)
{
return gson.toJson( content );
}
public static String toString(BaseComponent component)
{
return gson.toJson( component );

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.chat;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@ -8,6 +9,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.awt.Color;
import java.lang.reflect.Type;
import java.util.Map;
import net.md_5.bungee.api.ChatColor;
@ -67,6 +69,10 @@ public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>,
{
object.addProperty( "color", style.getColor().getName() );
}
if ( style.hasShadowColor() )
{
object.addProperty( "shadow_color", style.getShadowColor().getRGB() );
}
if ( style.hasFont() )
{
object.addProperty( "font", style.getFont() );
@ -102,6 +108,17 @@ public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>,
case "color":
builder.color( ChatColor.of( value.getAsString() ) );
break;
case "shadow_color":
if ( value.isJsonArray() )
{
JsonArray array = value.getAsJsonArray();
builder.shadowColor( new Color( array.get( 0 ).getAsFloat(), array.get( 1 ).getAsFloat(), array.get( 2 ).getAsFloat(), array.get( 3 ).getAsFloat() ) );
} else if ( value.isJsonPrimitive() )
{
builder.shadowColor( new Color( value.getAsNumber().intValue(), true ) );
}
break;
case "font":
builder.font( value.getAsString() );
break;

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
@ -22,7 +21,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<version>2.11.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

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

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-log</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
@ -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.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-alert</artifactId>
<version>1.21-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.fromLegacy( message ) );
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-kick</artifactId>
<version>1.21-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.fromLegacy( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) );
return;
}
if ( args.length == 1 )
{
player.disconnect( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "kick_message" ) ) );
} else
{
String[] reason = new String[ args.length - 1 ];
System.arraycopy( args, 1, reason, 0, reason.length );
player.disconnect( TextComponent.fromLegacy( ChatColor.translateAlternateColorCodes( '&', Joiner.on( ' ' ).join( reason ) ) ) );
}
}
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length == 1 )
{
Set<String> matches = new HashSet<>();
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
return matches;
} else
{
return ImmutableSet.of();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,79 +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.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.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" );
boolean moduleLoaded = ProxyServer.getInstance().getPluginManager().getPlugin( "cmd_server" ) != null;
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 );
BaseComponent baseComponent = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) ).build();
if ( moduleLoaded )
{
baseComponent.setHoverEvent( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new Text( new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() ) )
);
baseComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
}
sender.sendMessage( baseComponent );
}
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) );
}
@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.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-send</artifactId>
<version>1.21-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, Collections.synchronizedList( new ArrayList<>() ) );
}
}
public void lastEntryDone()
{
sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" );
for ( Map.Entry<ServerConnectRequest.Result, List<String>> entry : results.entrySet() )
{
ComponentBuilder builder = new ComponentBuilder( "" );
if ( !entry.getValue().isEmpty() )
{
builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) );
}
builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN );
builder.append( "" + entry.getValue().size() ).bold( true );
sender.sendMessage( builder.create() );
}
}
public static class Entry implements Callback<ServerConnectRequest.Result>
{
private final SendCallback callback;
private final ProxiedPlayer player;
private final ServerInfo target;
public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target)
{
this.callback = callback;
this.player = player;
this.target = target;
this.callback.count++;
}
@Override
public void done(ServerConnectRequest.Result result, Throwable error)
{
callback.results.get( result ).add( player.getName() );
if ( result == ServerConnectRequest.Result.SUCCESS )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) );
}
if ( --callback.count == 0 )
{
callback.lastEntryDone();
}
}
}
}
public CommandSend()
{
super( "send", "bungeecord.command.send" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 2 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) );
return;
}
ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] );
if ( server == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
return;
}
List<ProxiedPlayer> targets;
if ( args[0].equalsIgnoreCase( "all" ) )
{
targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() );
} else if ( args[0].equalsIgnoreCase( "current" ) )
{
if ( !( sender instanceof ProxiedPlayer ) )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) );
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
targets = new ArrayList<>( player.getServer().getInfo().getPlayers() );
} else
{
// If we use a server name, send the entire server. This takes priority over players.
ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] );
if ( serverTarget != null )
{
targets = new ArrayList<>( serverTarget.getPlayers() );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
return;
}
targets = Collections.singletonList( player );
}
}
final SendCallback callback = new SendCallback( sender );
for ( ProxiedPlayer player : targets )
{
ServerConnectRequest request = ServerConnectRequest.builder()
.target( server )
.reason( ServerConnectEvent.Reason.COMMAND )
.callback( new SendCallback.Entry( callback, player, server ) )
.build();
player.connect( request );
}
sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() );
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length > 2 || args.length == 0 )
{
return ImmutableSet.of();
}
Set<String> matches = new HashSet<>();
if ( args.length == 1 )
{
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
if ( "all".startsWith( search ) )
{
matches.add( "all" );
}
if ( "current".startsWith( search ) )
{
matches.add( "current" );
}
} else
{
String search = args[1].toLowerCase( Locale.ROOT );
for ( String server : ProxyServer.getInstance().getServers().keySet() )
{
if ( server.toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( server );
}
}
}
return matches;
}
}

View File

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

View File

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

View File

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

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-server</artifactId>
<version>1.21-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.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.21-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.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
<version>1.21-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}

29
native/compile-native-arm.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
set -eu
CWD=$(pwd)
echo "Compiling mbedtls"
(cd mbedtls && CFLAGS="-fPIC -I$CWD/src/main/c -DMBEDTLS_USER_CONFIG_FILE='<mbedtls_custom_config.h>'" make CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar no_test)
echo "Compiling zlib"
(cd zlib && CFLAGS="-fPIC -DNO_GZIP" CC=aarch64-linux-gnu-gcc CHOST=arm64 ./configure --target="aarch64" --static && make CFLAGS="-fPIC -march=armv8-a+crc" CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar)
CC="aarch64-linux-gnu-gcc"
CFLAGS="-c -fPIC -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"
LDFLAGS="-shared"
echo "Compiling bungee"
$CC $CFLAGS -o shared.o src/main/c/shared.c
$CC $CFLAGS -Imbedtls/include -o NativeCipherImpl.o src/main/c/NativeCipherImpl.c
$CC $CFLAGS -Izlib -o NativeCompressImpl.o src/main/c/NativeCompressImpl.c
echo "Linking native-cipher-arm.so"
$CC $LDFLAGS -o src/main/resources/native-cipher-arm.so shared.o NativeCipherImpl.o mbedtls/library/libmbedcrypto.a
echo "Linking native-compress-arm.so"
$CC $LDFLAGS -o src/main/resources/native-compress-arm.so shared.o NativeCompressImpl.o zlib/libz.a
echo "Cleaning up"
rm shared.o NativeCipherImpl.o NativeCompressImpl.o

View File

@ -2,11 +2,13 @@
set -eu
CWD=$(pwd)
echo "Compiling mbedtls"
(cd mbedtls && make no_test)
(cd mbedtls && CFLAGS="-fPIC -I$CWD/src/main/c -DMBEDTLS_USER_CONFIG_FILE='<mbedtls_custom_config.h>'" make no_test)
echo "Compiling zlib"
(cd zlib && CFLAGS=-fPIC ./configure --static && make)
(cd zlib && CFLAGS="-fPIC -DNO_GZIP" ./configure --static && make)
CC="gcc"
CFLAGS="-c -fPIC -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"

View File

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

View File

@ -5,11 +5,15 @@
#include "shared.h"
#include "net_md_5_bungee_jni_cipher_NativeCipherImpl.h"
// Hack to keep the compiler from optimizing the memset away
static void *(*const volatile memset_func)(void *, int, size_t) = memset;
typedef unsigned char byte;
typedef struct crypto_context {
int mode;
mbedtls_aes_context cipher;
int keyLen;
byte key[];
} crypto_context;
@ -22,6 +26,7 @@ jlong JNICALL Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_init(JNIEnv* env
return 0;
}
crypto->keyLen = (int) keyLen;
(*env)->GetByteArrayRegion(env, key, 0, keyLen, (jbyte*) &crypto->key);
mbedtls_aes_init(&crypto->cipher);
@ -36,6 +41,7 @@ void Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_free(JNIEnv* env, jobject
crypto_context *crypto = (crypto_context*) ctx;
mbedtls_aes_free(&crypto->cipher);
memset_func(crypto->key, 0, (size_t) crypto->keyLen);
free(crypto);
}

View File

@ -3,6 +3,9 @@
#include <zlib.h>
#include "shared.h"
#if !defined(__aarch64__)
#include "cpuid_helper.h"
#endif
#include "net_md_5_bungee_jni_zlib_NativeCompressImpl.h"
typedef unsigned char byte;
@ -26,6 +29,14 @@ jint throwException(JNIEnv *env, const char* message, int err) {
return (*env)->Throw(env, throwable);
}
JNIEXPORT jboolean JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_checkSupported(JNIEnv* env, jobject obj) {
#if !defined(__aarch64__)
return (jboolean) checkCompressionNativesSupport();
#else
return JNI_TRUE;
#endif
}
void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_reset(JNIEnv* env, jobject obj, jlong ctx, jboolean compress) {
z_stream* stream = (z_stream*) ctx;
int ret = (compress) ? deflateReset(stream) : inflateReset(stream);

View File

@ -0,0 +1,19 @@
// Header to check for SSE 2, SSSE 3, and SSE 4.2 support in compression natives
// GCC only!
#ifndef _INCLUDE_CPUID_HELPER_H
#define _INCLUDE_CPUID_HELPER_H
#include <stdbool.h>
#include <cpuid.h>
static inline bool checkCompressionNativesSupport() {
unsigned int eax, ebx, ecx, edx;
if(__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
return (edx & bit_SSE2) != 0 && (ecx & bit_SSSE3) != 0 && (ecx & bit_SSE4_2) != 0;
}else {
return false;
}
}
#endif // _INCLUDE_CPUID_HELPER_H

View File

@ -0,0 +1,31 @@
// This is a hack to deal with a glitch that happens when mbedtls is compiled against glibc
// but then run on a linux distro that uses musl libc. This implementation of the zeroize
// is compatible with both glibc and musl without requiring the library to be recompiled.
// I checked with a disassembler and for BungeeCord's usage of the library, implementing
// this function as a static function only resulted in 2 different subroutines referencing
// different versions of memset_func, so we might as well keep things simple and use a
// static function here instead of requiring the mbedtls makefile to be modified to add
// additional source files.
#ifndef _INCLUDE_MBEDTLS_CUSTOM_CONFIG_H
#define _INCLUDE_MBEDTLS_CUSTOM_CONFIG_H
#include <string.h>
#define MBEDTLS_PLATFORM_ZEROIZE_ALT
#define mbedtls_platform_zeroize mbedtls_platform_zeroize_impl
// hack to prevent compilers from optimizing the memset away
static void *(*const volatile memset_func)(void *, int, size_t) = memset;
static void mbedtls_platform_zeroize_impl(void *buf, size_t len) {
if (len > 0) {
memset_func(buf, 0, len);
}
}
#endif // _INCLUDE_MBEDTLS_CUSTOM_CONFIG_H

View File

@ -15,6 +15,14 @@ extern "C" {
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_initFields
(JNIEnv *, jclass);
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: checkSupported
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_checkSupported
(JNIEnv *, jobject);
/*
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
* Method: end

View File

@ -15,14 +15,23 @@ public final class NativeCode<T>
private final String name;
private final Supplier<? extends T> javaImpl;
private final Supplier<? extends T> nativeImpl;
private final boolean enableNativeFlag;
private final boolean extendedSupportCheck;
//
private boolean loaded;
public NativeCode(String name, Supplier<? extends T> javaImpl, Supplier<? extends T> nativeImpl)
{
this( name, javaImpl, nativeImpl, false );
}
public NativeCode(String name, Supplier<? extends T> javaImpl, Supplier<? extends T> nativeImpl, boolean extendedSupportCheck)
{
this.name = name;
this.javaImpl = javaImpl;
this.nativeImpl = nativeImpl;
this.enableNativeFlag = Boolean.parseBoolean( System.getProperty( "net.md_5.bungee.jni." + name + ".enable", "true" ) );
this.extendedSupportCheck = extendedSupportCheck;
}
public T newInstance()
@ -32,8 +41,9 @@ public final class NativeCode<T>
public boolean load()
{
if ( !loaded && isSupported() )
if ( enableNativeFlag && !loaded && isSupported() )
{
String name = this.name + ( isAarch64() ? "-arm" : "" );
String fullName = "bungeecord-" + name;
try
@ -59,6 +69,13 @@ public final class NativeCode<T>
}
System.load( temp.getPath() );
if ( extendedSupportCheck )
{
// Should throw NativeCodeException if incompatible
nativeImpl.get();
}
loaded = true;
} catch ( IOException ex )
{
@ -66,6 +83,9 @@ public final class NativeCode<T>
} catch ( UnsatisfiedLinkError ex )
{
System.out.println( "Could not load native library: " + ex.getMessage() );
} catch ( NativeCodeException ex )
{
System.out.println( "Native library " + name + " is incompatible: " + ex.getMessage() );
}
}
}
@ -75,6 +95,16 @@ public final class NativeCode<T>
public static boolean isSupported()
{
return "Linux".equals( System.getProperty( "os.name" ) ) && "amd64".equals( System.getProperty( "os.arch" ) );
return "Linux".equals( System.getProperty( "os.name" ) ) && ( isAmd64() || isAarch64() );
}
private static boolean isAmd64()
{
return "amd64".equals( System.getProperty( "os.arch" ) );
}
private static boolean isAarch64()
{
return "aarch64".equals( System.getProperty( "os.arch" ) );
}
}

View File

@ -7,4 +7,10 @@ public class NativeCodeException extends RuntimeException
{
super( message + " : " + reason );
}
public NativeCodeException(String message)
{
super( message );
}
}

View File

@ -18,4 +18,10 @@ public interface BungeeCipher
void cipher(ByteBuf in, ByteBuf out) throws GeneralSecurityException;
ByteBuf cipher(ChannelHandlerContext ctx, ByteBuf in) throws GeneralSecurityException;
/*
* This indicates whether the input ByteBuf is allowed to be a CompositeByteBuf.
* If you need access to a memory address, you should not allow composite buffers.
*/
boolean allowComposite();
}

View File

@ -2,6 +2,7 @@ package net.md_5.bungee.jni.cipher;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.FastThreadLocal;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
@ -12,10 +13,10 @@ public class JavaCipher implements BungeeCipher
{
private final Cipher cipher;
private static final ThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
private static final ThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
private static final FastThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
private static final FastThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
private static class EmptyByteThreadLocal extends ThreadLocal<byte[]>
private static class EmptyByteThreadLocal extends FastThreadLocal<byte[]>
{
@Override
@ -88,4 +89,10 @@ public class JavaCipher implements BungeeCipher
in.readBytes( heapIn, 0, readableBytes );
return heapIn;
}
@Override
public boolean allowComposite()
{
return true;
}
}

View File

@ -71,4 +71,10 @@ public class NativeCipher implements BungeeCipher
return heapOut;
}
@Override
public boolean allowComposite()
{
return false;
}
}

View File

@ -6,9 +6,17 @@ import java.util.zip.DataFormatException;
public interface BungeeZlib
{
public static final int OUTPUT_BUFFER_SIZE = 8192;
void init(boolean compress, int level);
void free();
void process(ByteBuf in, ByteBuf out) throws DataFormatException;
/*
* This indicates whether the input ByteBuf is allowed to be a CompositeByteBuf.
* If you need access to a memory address, you should not allow composite buffers.
*/
boolean allowComposite();
}

View File

@ -73,4 +73,10 @@ public class JavaZlib implements BungeeZlib
inflater.reset();
}
}
@Override
public boolean allowComposite()
{
return true;
}
}

View File

@ -15,6 +15,8 @@ public class NativeCompressImpl
static native void initFields();
native boolean checkSupported();
native void end(long ctx, boolean compress);
native void reset(long ctx, boolean compress);

View File

@ -15,6 +15,14 @@ public class NativeZlib implements BungeeZlib
private boolean compress;
private long ctx;
public NativeZlib()
{
if ( !nativeCompress.checkSupported() )
{
throw new NativeCodeException( "This CPU does not support the required SSE 4.2 and/or PCLMUL extensions!" );
}
}
@Override
public void init(boolean compress, int level)
{
@ -47,7 +55,7 @@ public class NativeZlib implements BungeeZlib
while ( !nativeCompress.finished && ( compress || in.isReadable() ) )
{
out.ensureWritable( 8192 );
out.ensureWritable( OUTPUT_BUFFER_SIZE );
int processed;
try
@ -66,4 +74,10 @@ public class NativeZlib implements BungeeZlib
nativeCompress.consumed = 0;
nativeCompress.finished = false;
}
@Override
public boolean allowComposite()
{
return false;
}
}

Binary file not shown.

Binary file not shown.

View File

@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test;
public class NativeZlibTest
{
private final NativeCode<BungeeZlib> factory = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new );
private final NativeCode<BungeeZlib> factory = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new, true );
@Test
public void doTest() throws DataFormatException

View File

@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<packaging>pom</packaging>
@ -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>
@ -83,7 +82,7 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>4.1.110.Final</version>
<version>4.1.115.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -99,7 +98,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
<version>33.3.1-jre</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -138,7 +137,7 @@
<artifactId>scriptus</artifactId>
<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>

View File

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

@ -499,7 +499,7 @@ public abstract class DefinedPacket
public static BitSet readFixedBitSet(int i, ByteBuf buf)
{
byte[] bits = new byte[ ( i + 8 ) >> 3 ];
byte[] bits = new byte[ ( i + 7 ) >> 3 ];
buf.readBytes( bits );
return BitSet.valueOf( bits );
@ -511,7 +511,7 @@ public abstract class DefinedPacket
{
throw new OverflowPacketException( "BitSet too large (expected " + size + " got " + bits.size() + ")" );
}
buf.writeBytes( Arrays.copyOf( bits.toByteArray(), ( size + 8 ) >> 3 ) );
buf.writeBytes( Arrays.copyOf( bits.toByteArray(), ( size + 7 ) >> 3 ) );
}
public void read(ByteBuf buf)

View File

@ -98,7 +98,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1F ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x24 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x26 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x26 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x27 )
);
TO_CLIENT.registerPacket(
Login.class,
@ -115,7 +116,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x24 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x29 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x2B )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x2B ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x2C )
);
TO_CLIENT.registerPacket( Chat.class,
Chat::new,
@ -146,7 +148,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x45 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x47 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x47 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x4C )
);
TO_CLIENT.registerPacket(
BossBar.class,
@ -206,7 +209,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5C ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x5E )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x5E ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x64 )
);
TO_CLIENT.registerPacket(
ScoreboardScore.class,
@ -224,13 +228,15 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x61 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x68 )
);
TO_CLIENT.registerPacket(
ScoreboardScoreReset.class,
ScoreboardScoreReset::new,
map( ProtocolConstants.MINECRAFT_1_20_3, 0x42 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x44 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x44 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x49 )
);
TO_CLIENT.registerPacket(
ScoreboardDisplay.class,
@ -248,7 +254,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x55 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x57 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x57 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x5C )
);
TO_CLIENT.registerPacket(
Team.class,
@ -266,7 +273,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5E ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x60 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x67 )
);
TO_CLIENT.registerPacket(
PluginMessage.class,
@ -321,7 +329,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x63 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x65 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x6C )
);
TO_CLIENT.registerPacket(
ClearTitles.class,
@ -342,7 +351,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x63 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x63 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x6A )
);
TO_CLIENT.registerPacket(
TitleTimes.class,
@ -354,7 +364,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x64 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x66 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x66 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x6D )
);
TO_CLIENT.registerPacket(
SystemChat.class,
@ -365,7 +376,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x69 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6C )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6C ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x73 )
);
TO_CLIENT.registerPacket(
PlayerListHeaderFooter.class,
@ -387,7 +399,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x6A ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6D )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6D ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x74 )
);
TO_CLIENT.registerPacket(
EntityStatus.class,
@ -432,7 +445,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x20 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x22 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x22 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x23 )
);
TO_CLIENT.registerPacket(
ViewDistance.class,
@ -447,7 +461,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x55 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x55 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x59 )
);
TO_CLIENT.registerPacket(
ServerData.class,
@ -458,7 +473,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x49 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x4B )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x4B ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x50 )
);
TO_CLIENT.registerPacket(
PlayerListItemRemove.class,
@ -466,7 +482,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x35 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3B ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3D )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3D ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x3F )
);
TO_CLIENT.registerPacket(
PlayerListItemUpdate.class,
@ -474,14 +491,16 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x36 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3C ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3E )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3E ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x40 )
);
TO_CLIENT.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x67 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x69 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x69 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x70 )
);
TO_CLIENT.registerPacket(
CookieRequest.class,
@ -491,22 +510,26 @@ public enum Protocol
TO_CLIENT.registerPacket(
StoreCookie.class,
StoreCookie::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6B )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6B ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x72 )
);
TO_CLIENT.registerPacket(
Transfer.class,
Transfer::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x73 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x73 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x7A )
);
TO_CLIENT.registerPacket(
DisconnectReportDetails.class,
DisconnectReportDetails::new,
map( ProtocolConstants.MINECRAFT_1_21, 0x7A )
map( ProtocolConstants.MINECRAFT_1_21, 0x7A ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x81 )
);
TO_CLIENT.registerPacket(
ServerLinks.class,
ServerLinks::new,
map( ProtocolConstants.MINECRAFT_1_21, 0x7B )
map( ProtocolConstants.MINECRAFT_1_21, 0x7B ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x82 )
);
TO_SERVER.registerPacket(
@ -526,7 +549,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x18 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x18 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x1A )
);
TO_SERVER.registerPacket( Chat.class,
Chat::new,
@ -542,19 +566,23 @@ public enum Protocol
ClientCommand::new,
map( ProtocolConstants.MINECRAFT_1_19, 0x03 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x06 )
);
TO_SERVER.registerPacket(
UnsignedClientCommand.class,
UnsignedClientCommand::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x05 )
);
TO_SERVER.registerPacket(
ClientChat.class,
ClientChat::new,
map( ProtocolConstants.MINECRAFT_1_19, 0x04 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x05 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x06 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x06 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x07 )
);
TO_SERVER.registerPacket(
TabCompleteRequest.class,
@ -570,7 +598,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x0D )
);
TO_SERVER.registerPacket(
ClientSettings.class,
@ -585,7 +614,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_3, 0x07 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x0C )
);
TO_SERVER.registerPacket(
PluginMessage.class,
@ -603,18 +633,21 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x12 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x14 )
);
TO_SERVER.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ),
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0C )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x0E )
);
TO_SERVER.registerPacket(
CookieResponse.class,
CookieResponse::new,
map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 )
map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_21_2, 0x13 )
);
}
},

View File

@ -47,6 +47,8 @@ public class ProtocolConstants
public static final int MINECRAFT_1_20_3 = 765;
public static final int MINECRAFT_1_20_5 = 766;
public static final int MINECRAFT_1_21 = 767;
public static final int MINECRAFT_1_21_2 = 768;
public static final int MINECRAFT_1_21_4 = 769;
public static final List<String> SUPPORTED_VERSIONS;
public static final List<Integer> SUPPORTED_VERSION_IDS;
@ -108,13 +110,15 @@ public class ProtocolConstants
ProtocolConstants.MINECRAFT_1_20_2,
ProtocolConstants.MINECRAFT_1_20_3,
ProtocolConstants.MINECRAFT_1_20_5,
ProtocolConstants.MINECRAFT_1_21
ProtocolConstants.MINECRAFT_1_21,
ProtocolConstants.MINECRAFT_1_21_2,
ProtocolConstants.MINECRAFT_1_21_4
);
if ( SNAPSHOT_SUPPORT )
{
// supportedVersions.add( "1.21.x" );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_21 );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_21_4 );
}
SUPPORTED_VERSIONS = supportedVersions.build();

View File

@ -1,27 +1,38 @@
package net.md_5.bungee.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.List;
import lombok.Setter;
/**
* Prepend length of the message as a Varint21 by writing length and data to a
* new buffer
*/
@ChannelHandler.Sharable
public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>
public class Varint21LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf>
{
@Setter
private boolean compose = true;
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> list) throws Exception
{
int bodyLen = msg.readableBytes();
int headerLen = varintSize( bodyLen );
out.ensureWritable( headerLen + bodyLen );
DefinedPacket.writeVarInt( bodyLen, out );
out.writeBytes( msg );
if ( compose )
{
ByteBuf buf = ctx.alloc().directBuffer( headerLen );
DefinedPacket.writeVarInt( bodyLen, buf );
list.add( ctx.alloc().compositeDirectBuffer( 2 ).addComponents( true, buf, msg.retain() ) );
} else
{
ByteBuf buf = ctx.alloc().directBuffer( headerLen + bodyLen );
DefinedPacket.writeVarInt( bodyLen, buf );
buf.writeBytes( msg );
list.add( buf );
}
}
static int varintSize(int paramInt)

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, 256 );
command = readString( buf, ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 ) ? 32767 : 256 );
timestamp = buf.readLong();
salt = buf.readLong();

View File

@ -25,6 +25,7 @@ public class ClientSettings extends DefinedPacket
private int mainHand;
private boolean disableTextFiltering;
private boolean allowServerListing;
private ParticleStatus particleStatus;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
@ -46,6 +47,10 @@ public class ClientSettings extends DefinedPacket
{
allowServerListing = buf.readBoolean();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
{
particleStatus = ParticleStatus.values()[readVarInt( buf )];
}
}
@Override
@ -74,6 +79,10 @@ public class ClientSettings extends DefinedPacket
{
buf.writeBoolean( allowServerListing );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
{
writeVarInt( particleStatus.ordinal(), buf );
}
}
@Override
@ -81,4 +90,11 @@ public class ClientSettings extends DefinedPacket
{
handler.handle( this );
}
public enum ParticleStatus
{
ALL,
DECREASED,
MINIMAL;
}
}

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<>();
@ -327,18 +328,29 @@ public class Commands extends DefinedPacket
{
}
};
private static final ArgumentSerializer<Boolean> BOOLEAN = new ArgumentSerializer<Boolean>()
private static final ProperArgumentSerializer<BoolArgumentType> BOOLEAN = new ProperArgumentSerializer<BoolArgumentType>()
{
@Override
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>()
@ -355,7 +367,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)
@ -383,8 +395,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)
@ -412,8 +436,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)
@ -441,6 +477,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>()
{
@ -456,7 +504,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)
@ -484,6 +532,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>()
{
@ -539,11 +599,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 );
@ -870,6 +939,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;
@ -999,9 +1466,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

@ -23,7 +23,7 @@ public class CookieResponse extends DefinedPacket
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
cookie = readString( buf );
data = readNullable( DefinedPacket::readArray, buf );
data = readNullable( read -> DefinedPacket.readArray( read, 5120 ), buf );
}
@Override

View File

@ -45,6 +45,10 @@ public class EncryptionResponse extends DefinedPacket
writeArray( verifyToken, buf );
} else
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 && protocolVersion <= ProtocolConstants.MINECRAFT_1_19_3 )
{
buf.writeBoolean( false );
}
buf.writeLong( encryptionData.getSalt() );
writeArray( encryptionData.getSignature(), buf );
}

View File

@ -41,6 +41,7 @@ public class Login extends DefinedPacket
private boolean flat;
private Location deathLocation;
private int portalCooldown;
private int seaLevel;
private boolean secureProfile;
@Override
@ -161,7 +162,10 @@ public class Login extends DefinedPacket
{
portalCooldown = readVarInt( buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
{
seaLevel = readVarInt( buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
{
secureProfile = buf.readBoolean();
@ -293,7 +297,10 @@ public class Login extends DefinedPacket
{
writeVarInt( portalCooldown, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
{
writeVarInt( seaLevel, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
{
buf.writeBoolean( secureProfile );

View File

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

View File

@ -145,5 +145,10 @@ public class PlayerListItem extends DefinedPacket
// ADD_PLAYER & UPDATE_DISPLAY_NAME
BaseComponent displayName;
// UPDATE_LIST_ORDER 1.21.2
Integer listOrder;
// UPDATE_HAT 1.21.4
Boolean showHat;
}
}

View File

@ -61,6 +61,12 @@ public class PlayerListItemUpdate extends DefinedPacket
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
}
break;
case UPDATE_LIST_ORDER:
item.listOrder = DefinedPacket.readVarInt( buf );
break;
case UPDATE_HAT:
item.showHat = buf.readBoolean();
break;
}
}
}
@ -109,6 +115,12 @@ public class PlayerListItemUpdate extends DefinedPacket
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
}
break;
case UPDATE_LIST_ORDER:
DefinedPacket.writeVarInt( item.listOrder, buf );
break;
case UPDATE_HAT:
buf.writeBoolean( item.showHat );
break;
}
}
}
@ -128,6 +140,8 @@ public class PlayerListItemUpdate extends DefinedPacket
UPDATE_GAMEMODE,
UPDATE_LISTED,
UPDATE_LATENCY,
UPDATE_DISPLAY_NAME;
UPDATE_DISPLAY_NAME,
UPDATE_LIST_ORDER,
UPDATE_HAT;
}
}

View File

@ -30,6 +30,7 @@ public class Respawn extends DefinedPacket
private byte copyMeta;
private Location deathLocation;
private int portalCooldown;
private int seaLevel;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
@ -84,6 +85,10 @@ public class Respawn extends DefinedPacket
{
portalCooldown = readVarInt( buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
{
seaLevel = readVarInt( buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
copyMeta = buf.readByte();
@ -148,6 +153,10 @@ public class Respawn extends DefinedPacket
{
writeVarInt( portalCooldown, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
{
writeVarInt( seaLevel, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( copyMeta );

View File

@ -21,7 +21,7 @@ public class UnsignedClientCommand extends DefinedPacket
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
command = readString( buf, 256 );
command = readString( buf );
}
@Override

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<packaging>jar</packaging>
@ -64,37 +63,37 @@
<classifier>linux-aarch_64</classifier>
</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>

View File

@ -91,7 +91,6 @@ import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.log.BungeeLogger;
import net.md_5.bungee.log.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;
@ -176,7 +175,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
@ -274,10 +272,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

@ -11,19 +11,18 @@ import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Random;
import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import lombok.Getter;
import net.md_5.bungee.jni.NativeCode;
import net.md_5.bungee.jni.cipher.BungeeCipher;
import net.md_5.bungee.jni.cipher.JavaCipher;
@ -41,8 +40,6 @@ public class EncryptionUtil
private static final Random random = new Random();
private static final Base64.Encoder MIME_ENCODER = Base64.getMimeEncoder( 76, "\n".getBytes( StandardCharsets.UTF_8 ) );
public static final KeyPair keys;
@Getter
private static final SecretKey secret = new SecretKeySpec( new byte[ 16 ], "AES" );
public static final NativeCode<BungeeCipher> nativeFactory = new NativeCode<>( "native-cipher", JavaCipher::new, NativeCipher::new );
private static final PublicKey MOJANG_KEY;
@ -111,17 +108,17 @@ public class EncryptionUtil
return signature.verify( resp.getEncryptionData().getSignature() );
} else
{
Cipher cipher = Cipher.getInstance( "RSA" );
Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
cipher.init( Cipher.DECRYPT_MODE, keys.getPrivate() );
byte[] decrypted = cipher.doFinal( resp.getVerifyToken() );
return Arrays.equals( request.getVerifyToken(), decrypted );
return MessageDigest.isEqual( request.getVerifyToken(), decrypted );
}
}
public static SecretKey getSecret(EncryptionResponse resp, EncryptionRequest request) throws GeneralSecurityException
{
Cipher cipher = Cipher.getInstance( "RSA" );
Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
cipher.init( Cipher.DECRYPT_MODE, keys.getPrivate() );
return new SecretKeySpec( cipher.doFinal( resp.getSharedSecret() ), "AES" );
}
@ -146,7 +143,7 @@ public class EncryptionUtil
public static byte[] encrypt(Key key, byte[] b) throws GeneralSecurityException
{
Cipher hasher = Cipher.getInstance( "RSA" );
Cipher hasher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
hasher.init( Cipher.ENCRYPT_MODE, key );
return hasher.doFinal( b );
}

View File

@ -5,7 +5,6 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@ -32,7 +31,7 @@ public class ServerConnection implements Server
private final boolean forgeServer = false;
@Getter
private final Queue<KeepAliveData> keepAlives = new ArrayDeque<>();
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
private final Queue<DefinedPacket> packetQueue = new ArrayDeque<>();
private final Unsafe unsafe = new Unsafe()
{
@ -45,23 +44,37 @@ public class ServerConnection implements Server
public void sendPacketQueued(DefinedPacket packet)
{
Protocol encodeProtocol = ch.getEncodeProtocol();
if ( !encodeProtocol.TO_SERVER.hasPacket( packet.getClass(), ch.getEncodeVersion() ) )
ch.scheduleIfNecessary( () ->
{
packetQueue.add( packet );
} else
{
unsafe().sendPacket( packet );
}
if ( ch.isClosed() )
{
return;
}
Protocol encodeProtocol = ch.getEncodeProtocol();
if ( !encodeProtocol.TO_SERVER.hasPacket( packet.getClass(), ch.getEncodeVersion() ) )
{
packetQueue.add( packet );
} else
{
unsafe().sendPacket( packet );
}
} );
}
public void sendQueuedPackets()
{
DefinedPacket packet;
while ( ( packet = packetQueue.poll() ) != null )
ch.scheduleIfNecessary( () ->
{
unsafe().sendPacket( packet );
}
if ( ch.isClosed() )
{
return;
}
DefinedPacket packet;
while ( ( packet = packetQueue.poll() ) != null )
{
unsafe().sendPacket( packet );
}
} );
}
@Override
@ -81,6 +94,7 @@ public class ServerConnection implements Server
{
Preconditions.checkArgument( reason.length == 0, "Server cannot have disconnect reason" );
isObsolete = true;
ch.close();
}

View File

@ -137,6 +137,15 @@ public class ServerConnector extends PacketHandler
public void disconnected(ChannelWrapper channel) throws Exception
{
user.getPendingConnects().remove( target );
if ( user.getServer() == null && !obsolete && user.getPendingConnects().isEmpty() && thisState == State.LOGIN_SUCCESS )
{
// this is called if we get disconnected but not have received any response after we send the handshake
// in this case probably an exception was thrown because the handshake could not be read correctly
// because of the extra ip forward data, also we skip the disconnect if another server is also in the
// pendingConnects queue because we don't want to lose the player
user.disconnect( "Unexpected disconnect during server login, did you forget to enable BungeeCord / IP forwarding on your server?" );
}
}
@Override
@ -252,7 +261,7 @@ 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.isLimitedCrafting(), login.isDebug(), login.isFlat(), login.getDeathLocation(),
login.getPortalCooldown(), login.isSecureProfile() );
login.getPortalCooldown(), login.getSeaLevel(), login.isSecureProfile() );
user.unsafe().sendPacket( modLogin );
@ -270,7 +279,7 @@ 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(), (byte) 0, login.getDeathLocation(),
login.getPortalCooldown() ) );
login.getPortalCooldown(), login.getSeaLevel() ) );
} else
{
user.unsafe().sendPacket( BungeeCord.getInstance().registerChannels( user.getPendingConnection().getVersion() ) );
@ -332,12 +341,12 @@ 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(),
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
(byte) 0, login.getDeathLocation(), login.getPortalCooldown(), login.getSeaLevel() ) );
}
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(),
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
(byte) 0, login.getDeathLocation(), login.getPortalCooldown(), login.getSeaLevel() ) );
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_14 )
{
user.unsafe().sendPacket( new ViewDistance( login.getViewDistance() ) );
@ -361,7 +370,10 @@ public class ServerConnector extends PacketHandler
if ( user.getServer() != null )
{
// Begin config mode
user.unsafe().sendPacket( new StartConfiguration() );
if ( user.getCh().getEncodeProtocol() != Protocol.CONFIGURATION )
{
user.unsafe().sendPacket( new StartConfiguration() );
}
} else
{
LoginResult loginProfile = user.getPendingConnection().getLoginProfile();
@ -373,7 +385,6 @@ public class ServerConnector extends PacketHandler
// Remove from old servers
if ( user.getServer() != null )
{
user.getServer().setObsolete( true );
user.getServer().disconnect( "Quitting" );
}

View File

@ -11,6 +11,7 @@ import io.netty.channel.ChannelOption;
import io.netty.util.internal.PlatformDependent;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -21,7 +22,6 @@ import java.util.Objects;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import lombok.Getter;
import lombok.NonNull;
@ -146,7 +146,7 @@ public final class UserConnection implements ProxiedPlayer
@Setter
private ForgeServerHandler forgeServerHandler;
/*========================================================================*/
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
private final Queue<DefinedPacket> packetQueue = new ArrayDeque<>();
private final Unsafe unsafe = new Unsafe()
{
@Override
@ -186,23 +186,37 @@ public final class UserConnection implements ProxiedPlayer
public void sendPacketQueued(DefinedPacket packet)
{
Protocol encodeProtocol = ch.getEncodeProtocol();
if ( !encodeProtocol.TO_CLIENT.hasPacket( packet.getClass(), getPendingConnection().getVersion() ) )
ch.scheduleIfNecessary( () ->
{
packetQueue.add( packet );
} else
{
unsafe().sendPacket( packet );
}
if ( ch.isClosed() )
{
return;
}
Protocol encodeProtocol = ch.getEncodeProtocol();
if ( !encodeProtocol.TO_CLIENT.hasPacket( packet.getClass(), getPendingConnection().getVersion() ) )
{
packetQueue.add( packet );
} else
{
unsafe().sendPacket( packet );
}
} );
}
public void sendQueuedPackets()
{
DefinedPacket packet;
while ( ( packet = packetQueue.poll() ) != null )
ch.scheduleIfNecessary( () ->
{
unsafe().sendPacket( packet );
}
if ( ch.isClosed() )
{
return;
}
DefinedPacket packet;
while ( ( packet = packetQueue.poll() ) != null )
{
unsafe().sendPacket( packet );
}
} );
}
@Deprecated
@ -306,6 +320,11 @@ public final class UserConnection implements ProxiedPlayer
{
Preconditions.checkNotNull( request, "request" );
ch.getHandle().eventLoop().execute( () -> connect0( request ) );
}
private void connect0(final ServerConnectRequest request)
{
final Callback<ServerConnectRequest.Result> callback = request.getCallback();
ServerConnectEvent event = new ServerConnectEvent( this, request.getTarget(), request.getReason(), request );
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
@ -315,10 +334,6 @@ public final class UserConnection implements ProxiedPlayer
callback.done( ServerConnectRequest.Result.EVENT_CANCEL, null );
}
if ( getServer() == null && !ch.isClosing() )
{
throw new IllegalStateException( "Cancelled ServerConnectEvent with no server or disconnect." );
}
return;
}
@ -439,7 +454,6 @@ public final class UserConnection implements ProxiedPlayer
if ( server != null )
{
server.setObsolete( true );
server.disconnect( "Quitting" );
}
}

View File

@ -8,5 +8,5 @@ import net.md_5.bungee.jni.zlib.NativeZlib;
public class CompressFactory
{
public static final NativeCode<BungeeZlib> zlib = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new );
public static final NativeCode<BungeeZlib> zlib = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new, true );
}

View File

@ -2,18 +2,23 @@ package net.md_5.bungee.compress;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.List;
import java.util.zip.Deflater;
import lombok.Getter;
import lombok.Setter;
import net.md_5.bungee.jni.zlib.BungeeZlib;
import net.md_5.bungee.protocol.DefinedPacket;
public class PacketCompressor extends MessageToByteEncoder<ByteBuf>
public class PacketCompressor extends MessageToMessageEncoder<ByteBuf>
{
@Getter
private final BungeeZlib zlib = CompressFactory.zlib.newInstance();
@Setter
private int threshold = 256;
@Setter
private boolean compose = true;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception
@ -28,18 +33,25 @@ public class PacketCompressor extends MessageToByteEncoder<ByteBuf>
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception
{
int origSize = msg.readableBytes();
if ( origSize < threshold )
{
DefinedPacket.writeVarInt( 0, out );
out.writeBytes( msg );
if ( compose )
{
// create a virtual buffer to avoid copying of data
out.add( ctx.alloc().compositeDirectBuffer( 2 ).addComponents( true, ctx.alloc().directBuffer( 1 ).writeByte( 0 ), msg.retain() ) );
} else
{
out.add( ctx.alloc().directBuffer( origSize + 1 ).writeByte( 0 ).writeBytes( msg ) );
}
} else
{
DefinedPacket.writeVarInt( origSize, out );
zlib.process( msg, out );
ByteBuf buf = ctx.alloc().directBuffer( BungeeZlib.OUTPUT_BUFFER_SIZE );
DefinedPacket.writeVarInt( origSize, buf );
zlib.process( msg, buf );
out.add( buf );
}
}
}

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