diff --git a/api/src/main/java/net/md_5/bungee/api/event/ProxyDefineCommandsEvent.java b/api/src/main/java/net/md_5/bungee/api/event/ProxyDefineCommandsEvent.java new file mode 100644 index 00000000000..1eddfaea1d6 --- /dev/null +++ b/api/src/main/java/net/md_5/bungee/api/event/ProxyDefineCommandsEvent.java @@ -0,0 +1,35 @@ +package net.md_5.bungee.api.event; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import net.md_5.bungee.api.connection.Connection; +import net.md_5.bungee.api.plugin.Command; + +/** + * Called when the proxy intercepts the Commands packet, allowing plugins to + * hide commands that clients have permission for without disabling them. + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class ProxyDefineCommandsEvent extends TargetedEvent +{ + /** + * The commands to send to the player + */ + private final Map commands; + + public ProxyDefineCommandsEvent(Connection sender, Connection receiver, Collection> commands) + { + super( sender, receiver ); + this.commands = new HashMap<>( commands.size() ); + for ( Map.Entry command : commands ) + { + this.commands.put( command.getKey(), command.getValue() ); + } + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java index 4684bfd8d4c..f2594793bc4 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java @@ -19,6 +19,7 @@ import java.io.DataInput; import java.net.InetSocketAddress; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; @@ -36,6 +37,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.PluginMessageEvent; +import net.md_5.bungee.api.event.ProxyDefineCommandsEvent; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerDisconnectEvent; import net.md_5.bungee.api.event.ServerKickEvent; @@ -743,13 +745,32 @@ public void handle(Respawn respawn) @Override public void handle(Commands commands) throws Exception { + final Collection> unmodifiedCommandMap = bungee.getPluginManager().getCommands(); + final ProxyDefineCommandsEvent event = new ProxyDefineCommandsEvent( server, con, unmodifiedCommandMap ); + bungee.getPluginManager().callEvent( event ); + boolean modified = false; - for ( Map.Entry command : bungee.getPluginManager().getCommands() ) + // If an event handler REMOVED OR CHANGED a command then set modified. + for ( Map.Entry unmodifiedCommand : unmodifiedCommandMap ) { + if ( event.getCommands().get( unmodifiedCommand.getKey() ) != unmodifiedCommand.getValue() ) + { + modified = true; + } + } + + for ( Map.Entry command : event.getCommands().entrySet() ) + { + // If an event handler ADDED a command then set modified. + if ( !unmodifiedCommandMap.contains( command ) ) + { + modified = true; + } + if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) ) { - CommandNode dummy = LiteralArgumentBuilder.literal( command.getKey() ).executes( DUMMY_COMMAND ) + CommandNode dummy = LiteralArgumentBuilder.literal( command.getKey() ).executes( DUMMY_COMMAND ) .then( RequiredArgumentBuilder.argument( "args", StringArgumentType.greedyString() ) .suggests( Commands.SuggestionRegistry.ASK_SERVER ).executes( DUMMY_COMMAND ) ) .build();