mirror of https://github.com/GeyserMC/Geyser.git
Stop Bedrock commands from appearing in Java players' brig suggestions
move bedrock-only and player-only checks to the permission check, instead of being a postprocessor
This commit is contained in:
parent
55e50fecb9
commit
3ec2125d3f
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.command;
|
||||
|
||||
import cloud.commandframework.CommandManager;
|
||||
import cloud.commandframework.arguments.CommandArgument;
|
||||
import cloud.commandframework.exceptions.ArgumentParseException;
|
||||
import cloud.commandframework.exceptions.CommandExecutionException;
|
||||
import cloud.commandframework.exceptions.InvalidCommandSenderException;
|
||||
|
@ -33,6 +34,7 @@ import cloud.commandframework.exceptions.InvalidSyntaxException;
|
|||
import cloud.commandframework.exceptions.NoPermissionException;
|
||||
import cloud.commandframework.exceptions.NoSuchCommandException;
|
||||
import cloud.commandframework.execution.CommandExecutionCoordinator;
|
||||
import cloud.commandframework.meta.CommandMeta;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
@ -59,6 +61,7 @@ import org.geysermc.geyser.command.defaults.VersionCommand;
|
|||
import org.geysermc.geyser.event.GeyserEventRegistrar;
|
||||
import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl;
|
||||
import org.geysermc.geyser.extension.command.GeyserExtensionCommand;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -66,6 +69,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
|
@ -86,7 +90,7 @@ public class CommandRegistry {
|
|||
private final List<ExceptionHandler<?>> exceptionHandlers = List.of(
|
||||
new ExceptionHandler<>(InvalidSyntaxException.class, (src, e) -> src.sendLocaleString("geyser.command.invalid_syntax", e.getCorrectSyntax())),
|
||||
new ExceptionHandler<>(InvalidCommandSenderException.class, (src, e) -> src.sendLocaleString("geyser.command.invalid_sender", e.getCommandSender().getClass().getSimpleName(), e.getRequiredSender().getSimpleName())),
|
||||
new ExceptionHandler<>(NoPermissionException.class, (src, e) -> src.sendLocaleString("geyser.command.permission_fail")),
|
||||
new ExceptionHandler<>(NoPermissionException.class, this::handleNoPermission),
|
||||
new ExceptionHandler<>(NoSuchCommandException.class, (src, e) -> src.sendLocaleString("geyser.command.not_found")),
|
||||
new ExceptionHandler<>(ArgumentParseException.class, (src, e) -> src.sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage())),
|
||||
new ExceptionHandler<>(CommandExecutionException.class, (src, e) -> handleUnexpectedThrowable(src, e.getCause()))
|
||||
|
@ -96,8 +100,6 @@ public class CommandRegistry {
|
|||
this.geyser = geyser;
|
||||
this.cloud = cloud;
|
||||
|
||||
// Restricts command source types from executing commands they don't have access to
|
||||
cloud.registerCommandPostProcessor(new SourceTypeProcessor());
|
||||
// Override the default exception handlers that the typical cloud implementations provide so that we can perform localization.
|
||||
// This is kind of meaningless for our Geyser-Standalone implementation since these handlers are the default exception handlers in that case.
|
||||
for (ExceptionHandler<?> handler : exceptionHandlers) {
|
||||
|
@ -242,6 +244,30 @@ public class CommandRegistry {
|
|||
handleUnexpectedThrowable(source, throwable);
|
||||
}
|
||||
|
||||
private void handleNoPermission(GeyserCommandSource source, NoPermissionException exception) {
|
||||
// we basically recheck bedrock-only and player-only to see if they were the cause of this
|
||||
|
||||
// find the Command and its Meta that the source tried executing
|
||||
List<CommandArgument<?, ?>> argumentChain = exception.getCurrentChain();
|
||||
CommandArgument<?, ?> argument = argumentChain.get(argumentChain.size() - 1);
|
||||
CommandMeta meta = Objects.requireNonNull(argument.getOwningCommand()).getCommandMeta();
|
||||
|
||||
// See GeyserCommand#baseBuilder()
|
||||
if (meta.getOrDefault(GeyserCommand.BEDROCK_ONLY, false)) {
|
||||
if (source.connection().isEmpty()) {
|
||||
source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.command.bedrock_only", source.locale()));
|
||||
return;
|
||||
}
|
||||
} else if (meta.getOrDefault(GeyserCommand.PLAYER_ONLY, false)) {
|
||||
if (source.isConsole()) {
|
||||
source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.command.player_only", source.locale()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
source.sendLocaleString("geyser.command.permission_fail");
|
||||
}
|
||||
|
||||
private void handleUnexpectedThrowable(GeyserCommandSource source, Throwable throwable) {
|
||||
source.sendLocaleString("command.failed"); // java edition translation key
|
||||
GeyserImpl.getInstance().getLogger().error("Exception while executing command handler", throwable);
|
||||
|
|
|
@ -162,13 +162,26 @@ public abstract class GeyserCommand implements org.geysermc.geyser.api.command.C
|
|||
|
||||
/**
|
||||
* Creates a new command builder with {@link #rootCommand()}, {@link #name()}, and {@link #aliases()} built on it.
|
||||
* The Applicable from {@link #meta()} is also applied to the builder.
|
||||
* A permission predicate that takes into account {@link #permission()}, {@link #isBedrockOnly()}, and {@link #isExecutableOnConsole()}
|
||||
* is applied. The Applicable from {@link #meta()} is also applied to the builder.
|
||||
*/
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
public final Command.Builder<GeyserCommandSource> baseBuilder(CommandManager<GeyserCommandSource> manager) {
|
||||
return manager.commandBuilder(rootCommand())
|
||||
.literal(name, aliases.toArray(new String[0]))
|
||||
.permission(permission)
|
||||
.permission(source -> {
|
||||
if (bedrockOnly) {
|
||||
if (source.connection().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// connection is present -> it is a player -> executableOnConsole is irrelevant
|
||||
} else if (!executableOnConsole) {
|
||||
if (source.isConsole()) {
|
||||
return false; // not executable on console but is console
|
||||
}
|
||||
}
|
||||
return manager.hasPermission(source, permission);
|
||||
})
|
||||
.apply(meta());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.command;
|
||||
|
||||
import cloud.commandframework.execution.postprocessor.CommandPostprocessingContext;
|
||||
import cloud.commandframework.execution.postprocessor.CommandPostprocessor;
|
||||
import cloud.commandframework.meta.CommandMeta;
|
||||
import cloud.commandframework.services.types.ConsumerService;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
|
||||
public class SourceTypeProcessor implements CommandPostprocessor<GeyserCommandSource> {
|
||||
|
||||
@Override
|
||||
public void accept(@NonNull CommandPostprocessingContext<GeyserCommandSource> processContext) {
|
||||
CommandMeta meta = processContext.getCommand().getCommandMeta();
|
||||
GeyserCommandSource source = processContext.getCommandContext().getSender();
|
||||
|
||||
if (meta.getOrDefault(GeyserCommand.BEDROCK_ONLY, false)) {
|
||||
if (source.connection().isEmpty()) {
|
||||
source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.command.bedrock_only", source.locale()));
|
||||
ConsumerService.interrupt();
|
||||
}
|
||||
} else if (meta.getOrDefault(GeyserCommand.PLAYER_ONLY, false)) {
|
||||
// it should be fine to use else-if here, because if the command is bedrock-only,
|
||||
// performing the bedrock player check is also inherently a player check
|
||||
|
||||
if (source.playerUuid().isEmpty()) {
|
||||
source.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.command.player_only", source.locale()));
|
||||
ConsumerService.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,6 +53,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
|
|||
// if cloud gives a NoSuchCommandException? might be more accurate.
|
||||
CommandRegistry registry = GeyserImpl.getInstance().commandRegistry();
|
||||
if (registry.cloud().rootCommands().contains(root)) {
|
||||
// todo: cloud might not like the trailing whitespace either
|
||||
registry.runCommand(session, strippedCommand);
|
||||
return; // don't pass the command to the java server
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue