Compare commits
5 Commits
6bb83c4e61
...
f948b287f5
Author | SHA1 | Date | |
---|---|---|---|
f948b287f5 | |||
85d372ae7e | |||
f38c4a6e94 | |||
aefd61943b | |||
f08fb3cdfe |
11
api/pom.xml
11
api/pom.xml
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.3-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>
|
||||
|
@ -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.<CommandSender>literal( "server" )
|
||||
* .requires( sender -> sender.hasPermission( "bungeecord.command.server" ) )
|
||||
* .executes( a -> 0 )
|
||||
* .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
|
||||
* .suggests( SuggestionRegistry.ASK_SERVER )
|
||||
* )
|
||||
* .build()
|
||||
* );
|
||||
* event.getRoot().addChild( LiteralArgumentBuilder.<CommandSender>literal( "send" )
|
||||
* .requires( sender -> 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
|
||||
* Minecraft’s recipes.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@code builder.suggests(SuggestionRegistry.AVAILABLE_SOUNDS)} to
|
||||
* suggest Minecraft’s default sound identifiers.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@code builder.suggests(SuggestionRegistry.SUMMONABLE_ENTITIES)} to
|
||||
* suggest Minecraft’s 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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-bootstrap</artifactId>
|
||||
<version>1.20-R0.3-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>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-config</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-log</artifactId>
|
||||
<version>1.20-R0.3-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>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-native</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
4
pom.xml
4
pom.xml
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
@ -137,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>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>1.20-R0.3-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>
|
||||
|
@ -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<>();
|
||||
@ -326,18 +327,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>()
|
||||
@ -354,7 +366,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)
|
||||
@ -382,8 +394,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)
|
||||
@ -411,8 +435,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)
|
||||
@ -440,6 +476,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>()
|
||||
{
|
||||
@ -455,7 +503,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)
|
||||
@ -483,6 +531,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>()
|
||||
{
|
||||
@ -538,11 +598,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 );
|
||||
@ -811,6 +880,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;
|
||||
@ -937,11 +1404,15 @@ 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) ASK_SERVER ).key;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static final class DummyProvider implements SuggestionProvider<DummyProvider>
|
||||
{
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-proxy</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
@ -52,37 +51,37 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-log</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-native</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-query</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-slf4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
|
@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.StringRange;
|
||||
@ -19,9 +20,12 @@ import io.netty.channel.unix.DomainSocketAddress;
|
||||
import java.io.DataInput;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.ServerConnection;
|
||||
@ -35,6 +39,7 @@ import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.event.CommandsDeclareEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.api.event.ServerDisconnectEvent;
|
||||
@ -312,7 +317,7 @@ public class DownstreamBridge extends PacketHandler
|
||||
Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" );
|
||||
|
||||
brand = ByteBufAllocator.DEFAULT.heapBuffer();
|
||||
DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand );
|
||||
DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + server.getInfo().getName() + " (" + serverBrand + ")", brand );
|
||||
pluginMessage.setData( DefinedPacket.toArray( brand ) );
|
||||
brand.release();
|
||||
// changes in the packet are ignored so we need to send it manually
|
||||
@ -745,6 +750,11 @@ public class DownstreamBridge extends PacketHandler
|
||||
{
|
||||
boolean modified = false;
|
||||
|
||||
CommandsDeclareEvent commandsDeclareEvent = new CommandsDeclareEvent( server, con, commands.getRoot() );
|
||||
bungee.getPluginManager().callEvent( commandsDeclareEvent );
|
||||
|
||||
modified = commandsDeclareEvent.isModified();
|
||||
|
||||
for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() )
|
||||
{
|
||||
if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) )
|
||||
@ -761,11 +771,65 @@ public class DownstreamBridge extends PacketHandler
|
||||
|
||||
if ( modified )
|
||||
{
|
||||
commands.setRoot( (com.mojang.brigadier.tree.RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) );
|
||||
con.unsafe().sendPacket( commands );
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a deep copy of the provided command node but removes any node that are not accessible by the player
|
||||
* (using {@link CommandNode#getRequirement()})
|
||||
*/
|
||||
private CommandNode filterCommandNode(CommandNode source, IdentityHashMap<CommandNode, CommandNode> commandNodeMapping)
|
||||
{
|
||||
CommandNode dest;
|
||||
if ( source instanceof com.mojang.brigadier.tree.RootCommandNode )
|
||||
{
|
||||
dest = new com.mojang.brigadier.tree.RootCommandNode();
|
||||
} else
|
||||
{
|
||||
if ( source.getRequirement() != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( !source.getRequirement().test( con ) )
|
||||
{
|
||||
commandNodeMapping.put( source, null );
|
||||
return null;
|
||||
}
|
||||
} catch ( Throwable t )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Requirement test for command node " + source + " encountered an exception", t );
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentBuilder destChildBuilder = source.createBuilder();
|
||||
destChildBuilder.requires( sender -> true );
|
||||
if ( destChildBuilder.getRedirect() != null )
|
||||
{
|
||||
if ( commandNodeMapping.containsKey( destChildBuilder.getRedirect() ) )
|
||||
destChildBuilder.redirect( commandNodeMapping.get( destChildBuilder.getRedirect() ) );
|
||||
else
|
||||
destChildBuilder.redirect( filterCommandNode( destChildBuilder.getRedirect(), commandNodeMapping ) );
|
||||
}
|
||||
|
||||
dest = destChildBuilder.build();
|
||||
}
|
||||
|
||||
commandNodeMapping.put( source, dest );
|
||||
|
||||
for ( CommandNode sourceChild : (Collection<CommandNode>) source.getChildren() )
|
||||
{
|
||||
CommandNode destChild = filterCommandNode( sourceChild, commandNodeMapping );
|
||||
if ( destChild == null )
|
||||
continue;
|
||||
dest.addChild( destChild );
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ServerData serverData) throws Exception
|
||||
{
|
||||
|
@ -135,6 +135,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
private boolean transferred;
|
||||
private UserConnection userCon;
|
||||
|
||||
@Getter
|
||||
private boolean duplication = false;
|
||||
|
||||
@Getter
|
||||
private String realName = null;
|
||||
|
||||
@Getter
|
||||
private UUID realId = null;
|
||||
|
||||
@Override
|
||||
public boolean shouldHandle(PacketWrapper packet) throws Exception
|
||||
{
|
||||
@ -440,6 +449,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
}
|
||||
|
||||
this.loginRequest = loginRequest;
|
||||
setName( realName = loginRequest.getData() );
|
||||
|
||||
int limit = BungeeCord.getInstance().config.getPlayerLimit();
|
||||
if ( limit > 0 && bungee.getOnlineCount() >= limit )
|
||||
@ -448,14 +458,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
return;
|
||||
}
|
||||
|
||||
// If offline mode and they are already on, don't allow connect
|
||||
// We can just check by UUID here as names are based on UUID
|
||||
if ( !isOnlineMode() && bungee.getPlayer( getUniqueId() ) != null )
|
||||
{
|
||||
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>()
|
||||
{
|
||||
|
||||
@ -472,6 +474,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ( !realName.equals( name ) )
|
||||
{
|
||||
// Floodgate changes the name attribute with reflexion
|
||||
setName( realName = name );
|
||||
}
|
||||
if ( uniqueId != null )
|
||||
{
|
||||
// if plugin called setUniqueId()
|
||||
realId = uniqueId;
|
||||
}
|
||||
if ( onlineMode )
|
||||
{
|
||||
thisState = State.ENCRYPT;
|
||||
@ -526,8 +538,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
if ( obj != null && obj.getId() != null )
|
||||
{
|
||||
loginProfile = obj;
|
||||
name = obj.getName();
|
||||
uniqueId = Util.getUUID( obj.getId() );
|
||||
setName( realName = obj.getName() );
|
||||
uniqueId = realId = Util.getUUID( obj.getId() );
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
@ -545,10 +557,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
|
||||
private void finish()
|
||||
{
|
||||
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) );
|
||||
if ( uniqueId == null )
|
||||
if ( uniqueId == null ) // offline mode and no plugin used setUniqueId()
|
||||
{
|
||||
uniqueId = offlineId;
|
||||
uniqueId = realId = offlineId;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, player is either authenticated by Mojang (online mode),
|
||||
* by a plugin (Floodgate ?) or the offline id is set.
|
||||
*/
|
||||
ProxiedPlayer existingPlayer = bungee.getPlayer( uniqueId );
|
||||
if ( existingPlayer != null && existingPlayer.hasPermission( "bungeecord.multiple_connect" ) )
|
||||
{
|
||||
UUID newId = generateDuplicatedId( uniqueId );
|
||||
if ( !uniqueId.equals( newId ) )
|
||||
{
|
||||
uniqueId = newId;
|
||||
setName( name + "." + getDuplicationIndex( newId ) );
|
||||
duplication = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
|
||||
@ -746,6 +773,59 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData();
|
||||
}
|
||||
|
||||
private void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
if ( loginRequest != null )
|
||||
{
|
||||
loginRequest.setData( name ); // name transmitted to Spigot server
|
||||
}
|
||||
updateOfflineId();
|
||||
}
|
||||
|
||||
private UUID generateDuplicatedId(UUID base)
|
||||
{
|
||||
// UUID version: offline = 3 ; Java online mode = 4 ; Floodgate xUID = 0 (and must be kept 0)
|
||||
// UUID variant: offline = 0xx ; Java online mode = 10x ; Floodgate xUID = xxx
|
||||
if ( base.version() == 0 )
|
||||
{
|
||||
/*
|
||||
* Floodgate’s xUID converted to UUID are not supported
|
||||
* because it requires the 64 MSBs to be 0 (or Floodgate API would not
|
||||
* recognize a Bedrock account) and we cannot modify the 64 LSBs
|
||||
* without risking a collision with the xUID of another Bedrock account
|
||||
*/
|
||||
return base;
|
||||
}
|
||||
long MSB = base.getMostSignificantBits();
|
||||
long LSB = base.getLeastSignificantBits();
|
||||
|
||||
MSB &= 0xFFFFFFFF_FFFF_70FFL; // reset bits we need
|
||||
MSB |= 0x00000000_0000_8000L; // set version to + 8 the current version
|
||||
|
||||
for ( int i = 1; i <= 9; i++ )
|
||||
{
|
||||
long newMSB = MSB | i << 8;
|
||||
UUID newUUID = new UUID( newMSB, LSB );
|
||||
if ( bungee.getPlayer( newUUID ) != null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return newUUID;
|
||||
}
|
||||
return base; // there are too many duplicated connections for this player
|
||||
}
|
||||
|
||||
private static int getDuplicationIndex(UUID duplicatedId)
|
||||
{
|
||||
return (int) ( duplicatedId.getMostSignificantBits() >> 8 ) & 0xF;
|
||||
}
|
||||
|
||||
private void updateOfflineId()
|
||||
{
|
||||
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion()
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import io.netty.channel.Channel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
@ -21,6 +20,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.SettingsChangedEvent;
|
||||
import net.md_5.bungee.api.event.TabCompleteEvent;
|
||||
import net.md_5.bungee.api.event.TabCompleteRequestEvent;
|
||||
import net.md_5.bungee.entitymap.EntityMap;
|
||||
import net.md_5.bungee.forge.ForgeConstants;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
@ -235,32 +235,42 @@ public class UpstreamBridge extends PacketHandler
|
||||
TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions );
|
||||
bungee.getPluginManager().callEvent( tabCompleteEvent );
|
||||
|
||||
if ( tabCompleteEvent.isCancelled() )
|
||||
List<String> legacyResults = tabCompleteEvent.getSuggestions();
|
||||
|
||||
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1;
|
||||
int end = tabComplete.getCursor().length();
|
||||
StringRange lastArgumentRange = StringRange.between( start, end );
|
||||
|
||||
List<Suggestion> brigadier = new ArrayList<>( legacyResults.size() );
|
||||
for ( String s : legacyResults )
|
||||
{
|
||||
brigadier.add( new Suggestion( lastArgumentRange, s ) );
|
||||
}
|
||||
|
||||
TabCompleteRequestEvent tabCompleteRequestEvent = new TabCompleteRequestEvent( con, con.getServer(), tabComplete.getCursor(), lastArgumentRange, new Suggestions( lastArgumentRange, brigadier ) );
|
||||
tabCompleteRequestEvent.setCancelled( tabCompleteEvent.isCancelled() );
|
||||
bungee.getPluginManager().callEvent( tabCompleteRequestEvent );
|
||||
|
||||
if ( tabCompleteRequestEvent.isCancelled() )
|
||||
{
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
|
||||
List<String> results = tabCompleteEvent.getSuggestions();
|
||||
if ( !results.isEmpty() )
|
||||
Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions();
|
||||
|
||||
if ( !brigadierResults.isEmpty() )
|
||||
{
|
||||
// Unclear how to handle 1.13 commands at this point. Because we don't inject into the command packets we are unlikely to get this far unless
|
||||
// Bungee plugins are adding results for commands they don't own anyway
|
||||
if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 )
|
||||
{
|
||||
List<String> results = new ArrayList<>( brigadierResults.getList().size() );
|
||||
for ( Suggestion s : brigadierResults.getList() )
|
||||
{
|
||||
results.add( s.getText() );
|
||||
}
|
||||
con.unsafe().sendPacket( new TabCompleteResponse( results ) );
|
||||
} else
|
||||
{
|
||||
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1;
|
||||
int end = tabComplete.getCursor().length();
|
||||
StringRange range = StringRange.between( start, end );
|
||||
|
||||
List<Suggestion> brigadier = new LinkedList<>();
|
||||
for ( String s : results )
|
||||
{
|
||||
brigadier.add( new Suggestion( range, s ) );
|
||||
}
|
||||
|
||||
con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), new Suggestions( range, brigadier ) ) );
|
||||
con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) );
|
||||
}
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-query</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
@ -25,7 +24,7 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
|
@ -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.20-R0.3-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-slf4j</artifactId>
|
||||
<version>1.20-R0.3-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
Loading…
Reference in New Issue
Block a user