Cleanup/command dispatching (#12713)

This commit is contained in:
Owen
2025-06-21 21:44:07 -04:00
committed by GitHub
parent 186e9e331b
commit 5edcf6ddf6
10 changed files with 97 additions and 124 deletions

View File

@@ -1,5 +1,6 @@
package io.papermc.paper; package io.papermc.paper;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.world.damagesource.CombatEntry; import io.papermc.paper.world.damagesource.CombatEntry;
import io.papermc.paper.world.damagesource.FallLocationType; import io.papermc.paper.world.damagesource.FallLocationType;
import net.kyori.adventure.util.Services; import net.kyori.adventure.util.Services;
@@ -11,6 +12,8 @@ import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.function.Predicate;
/** /**
* Static bridge to the server internals. * Static bridge to the server internals.
* <p> * <p>
@@ -73,5 +76,15 @@ public interface InternalAPIBridge {
* @return combat entry * @return combat entry
*/ */
CombatEntry createCombatEntry(DamageSource damageSource, float damage, @Nullable FallLocationType fallLocationType, float fallDistance); CombatEntry createCombatEntry(DamageSource damageSource, float damage, @Nullable FallLocationType fallLocationType, float fallDistance);
/**
* Causes this predicate to be considered restricted.
* Applying this to a command node prevents this command from being executed from an
* unattended context, such as click events.
*
* @param predicate wrapped predicate
* @return wrapped predicate
*/
Predicate<CommandSourceStack> restricted(Predicate<CommandSourceStack> predicate);
} }

View File

@@ -5,6 +5,7 @@ import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.LiteralCommandNode;
import io.papermc.paper.InternalAPIBridge;
import io.papermc.paper.plugin.bootstrap.BootstrapContext; import io.papermc.paper.plugin.bootstrap.BootstrapContext;
import io.papermc.paper.plugin.bootstrap.PluginBootstrap; import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
import io.papermc.paper.plugin.configuration.PluginMeta; import io.papermc.paper.plugin.configuration.PluginMeta;
@@ -13,6 +14,7 @@ import io.papermc.paper.plugin.lifecycle.event.registrar.Registrar;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;
import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullMarked;
@@ -85,6 +87,22 @@ public interface Commands extends Registrar {
return RequiredArgumentBuilder.argument(name, argumentType); return RequiredArgumentBuilder.argument(name, argumentType);
} }
/**
* Creates a restricted {@link Predicate} that wraps the given predicate.
* <p>
* A restricted predicate prevents execution in unattended contexts, such as from
* chat click events. A warning is shown on the client before executing the command.
* <p>
* This is used by vanilla to prevent invocation of sensitive commands (like op) from
* players without their knowledge.
*
* @param predicate the original predicate to wrap
* @return a new predicate with restricted execution behavior
*/
static Predicate<CommandSourceStack> restricted(final Predicate<CommandSourceStack> predicate) {
return InternalAPIBridge.get().restricted(predicate);
}
/** /**
* Gets the underlying {@link CommandDispatcher}. * Gets the underlying {@link CommandDispatcher}.
* *

View File

@@ -1,6 +1,13 @@
--- a/net/minecraft/commands/Commands.java --- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java +++ b/net/minecraft/commands/Commands.java
@@ -176,6 +_,11 @@ @@ -170,12 +_,18 @@
@Override
public boolean isRestricted(CommandNode<CommandSourceStack> node) {
+ if (node.getRequirement() instanceof PermissionSource.RestrictedMarker) return true; // Paper - restricted api
return node.getRequirement() instanceof PermissionCheck<?> permissionCheck && permissionCheck.requiredLevel() > 0;
}
};
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>(); private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
public Commands(Commands.CommandSelection selection, CommandBuildContext context) { public Commands(Commands.CommandSelection selection, CommandBuildContext context) {
@@ -55,71 +62,20 @@
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer()); this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
} }
@@ -289,9 +_,41 @@ @@ -299,6 +_,13 @@
return new ParseResults<>(commandContextBuilder, parseResults.getReader(), parseResults.getExceptions());
}
+ // CraftBukkit start
+ public void dispatchServerCommand(CommandSourceStack sender, String command) {
+ com.google.common.base.Joiner joiner = com.google.common.base.Joiner.on(" ");
+ if (command.startsWith("/")) {
+ command = command.substring(1);
+ }
+
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(sender.getBukkitSender(), command);
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ command = event.getCommand();
+
+ String[] args = command.split(" ");
+ if (args.length == 0) return; // Paper - empty commands shall not be dispatched
+
+ // Paper - Fix permission levels for command blocks
+
+ // Handle vanilla commands; // Paper - handled in CommandNode/CommandDispatcher
+
+ String newCommand = joiner.join(args);
+ this.performPrefixedCommand(sender, newCommand, newCommand);
+ }
+ // CraftBukkit end
+
public void performPrefixedCommand(CommandSourceStack source, String command) {
+ // CraftBukkit start
+ this.performPrefixedCommand(source, command, command);
+ }
+
+ public void performPrefixedCommand(CommandSourceStack source, String command, String label) {
command = trimOptionalPrefix(command);
- this.performCommand(this.dispatcher.parse(command, source), command);
+ this.performCommand(this.dispatcher.parse(command, source), command, label);
+ // CraftBukkit end
}
public static String trimOptionalPrefix(String command) {
@@ -299,9 +_,20 @@
} }
public void performCommand(ParseResults<CommandSourceStack> parseResults, String command) { public void performCommand(ParseResults<CommandSourceStack> parseResults, String command) {
+ // CraftBukkit start + // Paper start
+ this.performCommand(parseResults, command, command); + this.performCommand(parseResults, command, false);
+ } + }
+ +
+ public void performCommand(ParseResults<CommandSourceStack> parseResults, String command, String label) { + public void performCommand(ParseResults<CommandSourceStack> parseResults, String command, boolean throwCommandError) {
+ // CraftBukkit end + org.spigotmc.AsyncCatcher.catchOp("Cannot perform command async");
+ // Paper start
+ this.performCommand(parseResults, command, label, false);
+ }
+ public void performCommand(ParseResults<CommandSourceStack> parseResults, String command, String label, boolean throwCommandError) {
+ // Paper end + // Paper end
CommandSourceStack commandSourceStack = parseResults.getContext().getSource(); CommandSourceStack commandSourceStack = parseResults.getContext().getSource();
Profiler.get().push(() -> "/" + command); Profiler.get().push(() -> "/" + command);
- ContextChain<CommandSourceStack> contextChain = finishParsing(parseResults, command, commandSourceStack); ContextChain<CommandSourceStack> contextChain = finishParsing(parseResults, command, commandSourceStack);
+ ContextChain contextChain = this.finishParsing(parseResults, command, commandSourceStack, label); // CraftBukkit // Paper - Add UnknownCommandEvent
try {
if (contextChain != null) {
@@ -313,9 +_,10 @@ @@ -313,9 +_,10 @@
); );
} }
@@ -133,12 +89,12 @@
StackTraceElement[] stackTrace = var12.getStackTrace(); StackTraceElement[] stackTrace = var12.getStackTrace();
for (int i = 0; i < Math.min(stackTrace.length, 3); i++) { for (int i = 0; i < Math.min(stackTrace.length, 3); i++) {
@@ -341,18 +_,22 @@ @@ -341,13 +_,17 @@
} }
@Nullable @Nullable
- private static ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source) { - private static ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source) {
+ private ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source, String label) { // CraftBukkit // Paper - Add UnknownCommandEvent + private ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseResults, String command, CommandSourceStack source) {
try { try {
validateParseResults(parseResults); validateParseResults(parseResults);
return ContextChain.tryFlatten(parseResults.getContext().build(command)) return ContextChain.tryFlatten(parseResults.getContext().build(command))
@@ -153,12 +109,6 @@
if (var7.getInput() != null && var7.getCursor() >= 0) { if (var7.getInput() != null && var7.getCursor() >= 0) {
int min = Math.min(var7.getInput().length(), var7.getCursor()); int min = Math.min(var7.getInput().length(), var7.getCursor());
MutableComponent mutableComponent = Component.empty() MutableComponent mutableComponent = Component.empty()
.withStyle(ChatFormatting.GRAY)
- .withStyle(style -> style.withClickEvent(new ClickEvent.SuggestCommand("/" + command)));
+ .withStyle(style -> style.withClickEvent(new ClickEvent.SuggestCommand("/" + label))); // CraftBukkit // Paper
if (min > 10) {
mutableComponent.append(CommonComponents.ELLIPSIS);
}
@@ -364,7 +_,17 @@ @@ -364,7 +_,17 @@
} }

View File

@@ -1,16 +1,18 @@
--- a/net/minecraft/commands/PermissionSource.java --- a/net/minecraft/commands/PermissionSource.java
+++ b/net/minecraft/commands/PermissionSource.java +++ b/net/minecraft/commands/PermissionSource.java
@@ -9,9 +_,20 @@ @@ -9,9 +_,22 @@
return this.hasPermission(2); return this.hasPermission(2);
} }
- public record Check<T extends PermissionSource>(@Override int requiredLevel) implements PermissionCheck<T> { - public record Check<T extends PermissionSource>(@Override int requiredLevel) implements PermissionCheck<T> {
+ public record Check<T extends PermissionSource>(@Override int requiredLevel, java.util.concurrent.atomic.AtomicReference<com.mojang.brigadier.tree.CommandNode<CommandSourceStack>> vanillaNode) implements PermissionCheck<T> { // Paper + // Paper start - Vanilla Command permission checking & expose restricted API
+ // Paper start - Vanilla Command permission checking + interface RestrictedMarker { }
+
+ public record Check<T extends PermissionSource>(@Override int requiredLevel, java.util.concurrent.atomic.AtomicReference<com.mojang.brigadier.tree.CommandNode<CommandSourceStack>> vanillaNode) implements PermissionCheck<T> {
+ public Check(int requiredLevel) { + public Check(int requiredLevel) {
+ this(requiredLevel, new java.util.concurrent.atomic.AtomicReference<>()); + this(requiredLevel, new java.util.concurrent.atomic.AtomicReference<>());
+ } + }
+ // Paper end - Vanilla Command permission checking + // Paper end - Vanilla Command permission checking & expose restricted API
@Override @Override
public boolean test(T source) { public boolean test(T source) {
+ // Paper start - Vanilla Command permission checking + // Paper start - Vanilla Command permission checking

View File

@@ -273,7 +273,7 @@
} }
@Override @Override
@@ -291,13 +_,23 @@ @@ -291,12 +_,20 @@
} }
public void handleConsoleInput(String msg, CommandSourceStack source) { public void handleConsoleInput(String msg, CommandSourceStack source) {
@@ -284,23 +284,19 @@
public void handleConsoleInputs() { public void handleConsoleInputs() {
- while (!this.consoleInput.isEmpty()) { - while (!this.consoleInput.isEmpty()) {
- ConsoleInput consoleInput = this.consoleInput.remove(0); - ConsoleInput consoleInput = this.consoleInput.remove(0);
- this.getCommands().performPrefixedCommand(consoleInput.source, consoleInput.msg);
+ // Paper start - Perf: use proper queue + // Paper start - Perf: use proper queue
+ ConsoleInput servercommand; + ConsoleInput consoleInput;
+ while ((servercommand = this.serverCommandQueue.poll()) != null) { + while ((consoleInput = this.serverCommandQueue.poll()) != null) {
+ // Paper end - Perf: use proper queue + // Paper end - Perf: use proper queue
+ // CraftBukkit start - ServerCommand for preprocessing + // CraftBukkit start - ServerCommand for preprocessing
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(this.console, servercommand.msg); + org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(this.console, consoleInput.msg);
+ this.server.getPluginManager().callEvent(event); + this.server.getPluginManager().callEvent(event);
+ if (event.isCancelled()) continue; + if (event.isCancelled()) continue;
+ servercommand = new ConsoleInput(event.getCommand(), servercommand.source); + consoleInput = new ConsoleInput(event.getCommand(), consoleInput.source);
+
+ // this.getCommands().performPrefixedCommand(servercommand.source, servercommand.msg); // Called in dispatchServerCommand
+ this.server.dispatchServerCommand(this.console, servercommand);
+ // CraftBukkit end + // CraftBukkit end
this.getCommands().performPrefixedCommand(consoleInput.source, consoleInput.msg);
} }
} }
@@ -430,7 +_,11 @@ @@ -430,7 +_,11 @@
@Override @Override
public boolean enforceSecureProfile() { public boolean enforceSecureProfile() {
@@ -314,7 +310,7 @@
} }
@Override @Override
@@ -515,14 +_,54 @@ @@ -515,14 +_,53 @@
@Override @Override
public String getPluginNames() { public String getPluginNames() {
@@ -365,8 +361,7 @@
+ if (event.isCancelled()) { + if (event.isCancelled()) {
+ return; + return;
+ } + }
+ ConsoleInput serverCommand = new ConsoleInput(event.getCommand(), wrapper); + this.getCommands().performPrefixedCommand(wrapper, event.getCommand());
+ this.server.dispatchServerCommand(event.getSender(), serverCommand);
+ }); + });
+ return rconConsoleSource.getCommandResponse(); + return rconConsoleSource.getCommandResponse();
+ // CraftBukkit end + // CraftBukkit end

View File

@@ -12,12 +12,18 @@
public int getSuccessCount() { public int getSuccessCount() {
return this.successCount; return this.successCount;
@@ -108,7 +_,7 @@ @@ -108,7 +_,13 @@
this.successCount++; this.successCount++;
} }
}); });
- server.getCommands().performPrefixedCommand(commandSourceStack, this.command); - server.getCommands().performPrefixedCommand(commandSourceStack, this.command);
+ server.getCommands().dispatchServerCommand(commandSourceStack, this.command); // CraftBukkit + // Paper start - ServerCommandEvent
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command));
+ if (!event.callEvent()) {
+ return true;
+ }
+ server.getCommands().performPrefixedCommand(commandSourceStack, event.getCommand());
+ // Paper end - ServerCommandEvent
} catch (Throwable var6) { } catch (Throwable var6) {
CrashReport crashReport = CrashReport.forThrowable(var6, "Executing command block"); CrashReport crashReport = CrashReport.forThrowable(var6, "Executing command block");
CrashReportCategory crashReportCategory = crashReport.addCategory("Command to be executed"); CrashReportCategory crashReportCategory = crashReport.addCategory("Command to be executed");

View File

@@ -1,10 +1,12 @@
package io.papermc.paper; package io.papermc.paper;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.world.damagesource.CombatEntry; import io.papermc.paper.world.damagesource.CombatEntry;
import io.papermc.paper.world.damagesource.FallLocationType; import io.papermc.paper.world.damagesource.FallLocationType;
import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper; import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper;
import io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper; import io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper;
import net.minecraft.Optionull; import net.minecraft.Optionull;
import net.minecraft.commands.PermissionSource;
import net.minecraft.world.damagesource.FallLocation; import net.minecraft.world.damagesource.FallLocation;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBiome;
@@ -16,6 +18,7 @@ import org.bukkit.damage.DamageSource;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.function.Predicate;
@NullMarked @NullMarked
public class PaperServerInternalAPIBridge implements InternalAPIBridge { public class PaperServerInternalAPIBridge implements InternalAPIBridge {
@@ -71,4 +74,16 @@ public class PaperServerInternalAPIBridge implements InternalAPIBridge {
damageSource, damage, fallLocation, fallDistance damageSource, damage, fallLocation, fallDistance
)); ));
} }
@Override
public Predicate<CommandSourceStack> restricted(final Predicate<CommandSourceStack> predicate) {
record RestrictedPredicate(Predicate<CommandSourceStack> predicate) implements Predicate<CommandSourceStack>, PermissionSource.RestrictedMarker {
@Override
public boolean test(final CommandSourceStack commandSourceStack) {
return this.predicate.test(commandSourceStack);
}
}
return new RestrictedPredicate(predicate);
}
} }

View File

@@ -20,6 +20,7 @@ import java.util.Spliterator;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -96,7 +97,7 @@ public class BukkitBrigForwardingMap extends HashMap<String, Command> {
public Command put(String key, Command value) { public Command put(String key, Command value) {
Command old = this.get(key); Command old = this.get(key);
this.getDispatcher().getRoot().removeCommand(key); // Override previous command this.getDispatcher().getRoot().removeCommand(key); // Override previous command
if (value instanceof PluginVanillaCommandWrapper wrapper && wrapper.getName().equals(key)) { if (value instanceof VanillaCommandWrapper wrapper && wrapper.getName().equals(key)) {
// Don't break when some plugin tries to remove and add back a plugin command registered with modern API... // Don't break when some plugin tries to remove and add back a plugin command registered with modern API...
this.getDispatcher().getRoot().addChild((CommandNode) wrapper.vanillaCommand); this.getDispatcher().getRoot().addChild((CommandNode) wrapper.vanillaCommand);
} else { } else {

View File

@@ -302,7 +302,6 @@ public final class CraftServer implements Server {
public CraftDataPackManager dataPackManager; public CraftDataPackManager dataPackManager;
private final CraftServerTickManager serverTickManager; private final CraftServerTickManager serverTickManager;
private final CraftServerLinks serverLinks; private final CraftServerLinks serverLinks;
public boolean playerCommandState;
private boolean printSaveWarning; private boolean printSaveWarning;
private CraftIconCache icon; private CraftIconCache icon;
private boolean overrideAllCommandBlockCommands = false; private boolean overrideAllCommandBlockCommands = false;
@@ -973,41 +972,13 @@ public final class CraftServer implements Server {
return this.playerList; return this.playerList;
} }
// NOTE: Should only be called from DedicatedServer.ah()
public boolean dispatchServerCommand(CommandSender sender, ConsoleInput serverCommand) {
if (sender instanceof Conversable) {
Conversable conversable = (Conversable) sender;
if (conversable.isConversing()) {
conversable.acceptConversationInput(serverCommand.msg);
return true;
}
}
try {
this.playerCommandState = true;
return this.dispatchCommand(sender, serverCommand.msg);
} catch (Exception ex) {
this.getLogger().log(Level.WARNING, "Unexpected exception while parsing console command \"" + serverCommand.msg + '"', ex);
return false;
} finally {
this.playerCommandState = false;
}
}
@Override @Override
public boolean dispatchCommand(CommandSender sender, String commandLine) { public boolean dispatchCommand(CommandSender rawSender, String commandLine) {
Preconditions.checkArgument(sender != null, "sender cannot be null"); Preconditions.checkArgument(rawSender != null, "sender cannot be null");
Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); Preconditions.checkArgument(commandLine != null, "commandLine cannot be null");
org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message
CommandSourceStack sourceStack = VanillaCommandWrapper.getListener(rawSender);
if (this.commandMap.dispatch(sender, commandLine)) {
return true;
}
return this.dispatchCommand(VanillaCommandWrapper.getListener(sender), commandLine);
}
public boolean dispatchCommand(CommandSourceStack sourceStack, String commandLine) {
net.minecraft.commands.Commands commands = this.getHandle().getServer().getCommands(); net.minecraft.commands.Commands commands = this.getHandle().getServer().getCommands();
com.mojang.brigadier.CommandDispatcher<CommandSourceStack> dispatcher = commands.getDispatcher(); com.mojang.brigadier.CommandDispatcher<CommandSourceStack> dispatcher = commands.getDispatcher();
com.mojang.brigadier.ParseResults<CommandSourceStack> results = dispatcher.parse(commandLine, sourceStack); com.mojang.brigadier.ParseResults<CommandSourceStack> results = dispatcher.parse(commandLine, sourceStack);
@@ -1017,7 +988,12 @@ public final class CraftServer implements Server {
Command target = this.commandMap.getCommand(args[0].toLowerCase(java.util.Locale.ENGLISH)); Command target = this.commandMap.getCommand(args[0].toLowerCase(java.util.Locale.ENGLISH));
try { try {
commands.performCommand(results, commandLine, commandLine, true); if (results.getContext().getNodes().isEmpty()) {
return false;
}
Commands.validateParseResults(results);
commands.performCommand(results, commandLine, true);
return true;
} catch (CommandException ex) { } catch (CommandException ex) {
new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args)).callEvent(); // Paper new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args)).callEvent(); // Paper
throw ex; throw ex;
@@ -1026,9 +1002,6 @@ public final class CraftServer implements Server {
new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args)).callEvent(); // Paper new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args)).callEvent(); // Paper
throw new CommandException(msg, ex); throw new CommandException(msg, ex);
} }
// Paper end
return false;
} }
@Override @Override
@@ -2608,7 +2581,7 @@ public final class CraftServer implements Server {
} }
public void checkSaveState() { public void checkSaveState() {
if (this.playerCommandState || this.printSaveWarning || this.console.autosavePeriod <= 0) { if (this.printSaveWarning || this.console.autosavePeriod <= 0) {
return; return;
} }
this.printSaveWarning = true; this.printSaveWarning = true;

View File

@@ -50,7 +50,7 @@ public class VanillaCommandWrapper extends BukkitCommand { // Paper
if (!this.testPermission(sender)) return true; if (!this.testPermission(sender)) return true;
CommandSourceStack source = VanillaCommandWrapper.getListener(sender); CommandSourceStack source = VanillaCommandWrapper.getListener(sender);
this.commands().performPrefixedCommand(source, this.toDispatcher(args, this.getName()), this.toDispatcher(args, commandLabel)); // Paper this.commands().performPrefixedCommand(source, this.toDispatcher(args, this.getName()));
return true; return true;
} }