geforkt von Mirrors/Velocity
InvocationInfo API (#1467)
* Invocation Source API Allows proxies to detect if a command is executed from an unsigned/signed/api source. This is useful because it allows commands executed from the player manually or by clicking on a chat message to be controlled. * Update api significantly to improve api coverage * javadoc * javadoc * Update api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java Co-authored-by: powercas_gamer <cas@mizule.dev> * Update api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java Co-authored-by: powercas_gamer <cas@mizule.dev> * Fix rename --------- Co-authored-by: powercas_gamer <cas@mizule.dev>
Dieser Commit ist enthalten in:
Ursprung
be5f0ace26
Commit
965db127a9
@ -26,6 +26,7 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
private final CommandSource commandSource;
|
private final CommandSource commandSource;
|
||||||
private final String command;
|
private final String command;
|
||||||
private CommandResult result;
|
private CommandResult result;
|
||||||
|
private InvocationInfo invocationInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a CommandExecuteEvent.
|
* Constructs a CommandExecuteEvent.
|
||||||
@ -34,9 +35,21 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
* @param command the command being executed without first slash
|
* @param command the command being executed without first slash
|
||||||
*/
|
*/
|
||||||
public CommandExecuteEvent(CommandSource commandSource, String command) {
|
public CommandExecuteEvent(CommandSource commandSource, String command) {
|
||||||
|
this(commandSource, command, new InvocationInfo(SignedState.UNSUPPORTED, Source.API));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CommandExecuteEvent.
|
||||||
|
*
|
||||||
|
* @param commandSource the source executing the command
|
||||||
|
* @param command the command being executed without first slash
|
||||||
|
* @param invocationInfo the invocation info of this command
|
||||||
|
*/
|
||||||
|
public CommandExecuteEvent(CommandSource commandSource, String command, InvocationInfo invocationInfo) {
|
||||||
this.commandSource = Preconditions.checkNotNull(commandSource, "commandSource");
|
this.commandSource = Preconditions.checkNotNull(commandSource, "commandSource");
|
||||||
this.command = Preconditions.checkNotNull(command, "command");
|
this.command = Preconditions.checkNotNull(command, "command");
|
||||||
this.result = CommandResult.allowed();
|
this.result = CommandResult.allowed();
|
||||||
|
this.invocationInfo = invocationInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,6 +74,16 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the info of the command invocation.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
* @return invocation info
|
||||||
|
*/
|
||||||
|
public InvocationInfo getInvocationInfo() {
|
||||||
|
return this.invocationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult getResult() {
|
public CommandResult getResult() {
|
||||||
return result;
|
return result;
|
||||||
@ -80,6 +103,75 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents information about a command invocation, including its signed state and source.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public record InvocationInfo(SignedState signedState, Source source) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the signed state of a command invocation.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public enum SignedState {
|
||||||
|
/**
|
||||||
|
* Indicates that the command was executed from a signed source with signed message arguments,
|
||||||
|
* This is currently only possible by typing a command in chat with signed arguments.
|
||||||
|
*
|
||||||
|
* <p><b>Note:</b> Cancelling the {@link CommandExecuteEvent} in this state will result in the player being kicked.</p>
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
SIGNED_WITH_ARGS,
|
||||||
|
/**
|
||||||
|
* Indicates that the command was executed from an signed source with no signed message arguments,
|
||||||
|
* This is currently only possible by typing a command in chat.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
SIGNED_WITHOUT_ARGS,
|
||||||
|
/**
|
||||||
|
* Indicates that the command was executed from an unsigned source,
|
||||||
|
* such as clicking on a component with a {@link net.kyori.adventure.text.event.ClickEvent.Action#RUN_COMMAND}.
|
||||||
|
*
|
||||||
|
* <p>Clients running version 1.20.5 or later will send this state.</p>
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
UNSIGNED,
|
||||||
|
/**
|
||||||
|
* Indicates that the command invocation does not support signing.
|
||||||
|
*
|
||||||
|
* <p>This state is sent by clients running versions prior to 1.19.3.</p>
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
UNSUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the source of a command invocation.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public enum Source {
|
||||||
|
/**
|
||||||
|
* Indicates that the command was invoked by a player.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
PLAYER,
|
||||||
|
/**
|
||||||
|
* Indicates that the command was invoked programmatically through an API call.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
API
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the result of the {@link CommandExecuteEvent}.
|
* Represents the result of the {@link CommandExecuteEvent}.
|
||||||
*/
|
*/
|
||||||
|
@ -218,13 +218,14 @@ public class VelocityCommandManager implements CommandManager {
|
|||||||
*
|
*
|
||||||
* @param source the source to execute the command for
|
* @param source the source to execute the command for
|
||||||
* @param cmdLine the command to execute
|
* @param cmdLine the command to execute
|
||||||
|
* @param invocationInfo the invocation info
|
||||||
* @return the {@link CompletableFuture} of the event
|
* @return the {@link CompletableFuture} of the event
|
||||||
*/
|
*/
|
||||||
public CompletableFuture<CommandExecuteEvent> callCommandEvent(final CommandSource source,
|
public CompletableFuture<CommandExecuteEvent> callCommandEvent(final CommandSource source,
|
||||||
final String cmdLine) {
|
final String cmdLine, final CommandExecuteEvent.InvocationInfo invocationInfo) {
|
||||||
Preconditions.checkNotNull(source, "source");
|
Preconditions.checkNotNull(source, "source");
|
||||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||||
return eventManager.fire(new CommandExecuteEvent(source, cmdLine));
|
return eventManager.fire(new CommandExecuteEvent(source, cmdLine, invocationInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean executeImmediately0(final CommandSource source, final ParseResults<CommandSource> parsed) {
|
private boolean executeImmediately0(final CommandSource source, final ParseResults<CommandSource> parsed) {
|
||||||
@ -266,7 +267,12 @@ public class VelocityCommandManager implements CommandManager {
|
|||||||
Preconditions.checkNotNull(source, "source");
|
Preconditions.checkNotNull(source, "source");
|
||||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||||
|
|
||||||
return callCommandEvent(source, cmdLine).thenComposeAsync(event -> {
|
CommandExecuteEvent.InvocationInfo invocationInfo = new CommandExecuteEvent.InvocationInfo(
|
||||||
|
CommandExecuteEvent.SignedState.UNSUPPORTED,
|
||||||
|
CommandExecuteEvent.Source.API
|
||||||
|
);
|
||||||
|
|
||||||
|
return callCommandEvent(source, cmdLine, invocationInfo).thenComposeAsync(event -> {
|
||||||
CommandExecuteEvent.CommandResult commandResult = event.getResult();
|
CommandExecuteEvent.CommandResult commandResult = event.getResult();
|
||||||
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
|
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
|
||||||
return CompletableFuture.completedFuture(false);
|
return CompletableFuture.completedFuture(false);
|
||||||
|
@ -56,8 +56,10 @@ public interface CommandHandler<T extends MinecraftPacket> {
|
|||||||
|
|
||||||
default void queueCommandResult(VelocityServer server, ConnectedPlayer player,
|
default void queueCommandResult(VelocityServer server, ConnectedPlayer player,
|
||||||
BiFunction<CommandExecuteEvent, LastSeenMessages, CompletableFuture<MinecraftPacket>> futurePacketCreator,
|
BiFunction<CommandExecuteEvent, LastSeenMessages, CompletableFuture<MinecraftPacket>> futurePacketCreator,
|
||||||
String message, Instant timestamp, @Nullable LastSeenMessages lastSeenMessages) {
|
String message, Instant timestamp, @Nullable LastSeenMessages lastSeenMessages,
|
||||||
CompletableFuture<CommandExecuteEvent> eventFuture = server.getCommandManager().callCommandEvent(player, message);
|
CommandExecuteEvent.InvocationInfo invocationInfo) {
|
||||||
|
CompletableFuture<CommandExecuteEvent> eventFuture = server.getCommandManager().callCommandEvent(player, message,
|
||||||
|
invocationInfo);
|
||||||
player.getChatQueue().queuePacket(
|
player.getChatQueue().queuePacket(
|
||||||
newLastSeenMessages -> eventFuture
|
newLastSeenMessages -> eventFuture
|
||||||
.thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages))
|
.thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages))
|
||||||
|
@ -111,6 +111,6 @@ public class KeyedCommandHandler implements CommandHandler<KeyedPlayerCommandPac
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}, packet.getCommand(), packet.getTimestamp(), null);
|
}, packet.getCommand(), packet.getTimestamp(), null, new CommandExecuteEvent.InvocationInfo(CommandExecuteEvent.SignedState.UNSUPPORTED, CommandExecuteEvent.Source.PLAYER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,6 @@ public class LegacyCommandHandler implements CommandHandler<LegacyChatPacket> {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}, command, Instant.now(), null);
|
}, command, Instant.now(), null, new CommandExecuteEvent.InvocationInfo(CommandExecuteEvent.SignedState.UNSUPPORTED, CommandExecuteEvent.Source.PLAYER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,7 @@ public class SessionCommandHandler implements CommandHandler<SessionPlayerComman
|
|||||||
}
|
}
|
||||||
return forwardCommand(fixedPacket, commandToRun);
|
return forwardCommand(fixedPacket, commandToRun);
|
||||||
});
|
});
|
||||||
}, packet.command, packet.timeStamp, packet.lastSeenMessages);
|
}, packet.command, packet.timeStamp, packet.lastSeenMessages,
|
||||||
|
new CommandExecuteEvent.InvocationInfo(packet.getEventSignedState(), CommandExecuteEvent.Source.PLAYER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
@ -68,6 +69,10 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
|||||||
return !argumentSignatures.isEmpty();
|
return !argumentSignatures.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandExecuteEvent.SignedState getEventSignedState() {
|
||||||
|
return !this.argumentSignatures.isEmpty() ? CommandExecuteEvent.SignedState.SIGNED_WITH_ARGS : CommandExecuteEvent.SignedState.SIGNED_WITHOUT_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||||
@ -44,6 +45,11 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandExecuteEvent.SignedState getEventSignedState() {
|
||||||
|
return CommandExecuteEvent.SignedState.UNSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "UnsignedPlayerCommandPacket{" +
|
return "UnsignedPlayerCommandPacket{" +
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren