mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-29 03:39:22 +00:00
Feature: Forward commands with no permission to the backend server on Standalone/ViaProxy (#5566)
* Feature: Forward commands with no permission to the backend server on Standalone/ViaProxy * Address review
This commit is contained in:
@@ -97,6 +97,9 @@ public class CommandRegistry implements EventRegistrar {
|
||||
|
||||
private static final String GEYSER_ROOT_PERMISSION = "geyser.command";
|
||||
|
||||
public final static boolean STANDALONE_COMMAND_MANAGER = GeyserImpl.getInstance().getPlatformType() == PlatformType.STANDALONE ||
|
||||
GeyserImpl.getInstance().getPlatformType() == PlatformType.VIAPROXY;
|
||||
|
||||
protected final GeyserImpl geyser;
|
||||
private final CommandManager<GeyserCommandSource> cloud;
|
||||
private final boolean applyRootPermission;
|
||||
@@ -274,12 +277,15 @@ public class CommandRegistry implements EventRegistrar {
|
||||
|
||||
cloud.command(builder.handler(context -> {
|
||||
GeyserCommandSource source = context.sender();
|
||||
if (!source.hasPermission(help.permission())) {
|
||||
// delegate if possible - otherwise we have nothing else to offer the user.
|
||||
if (source.hasPermission(help.permission())) {
|
||||
// Delegate to help if possible
|
||||
help.execute(source);
|
||||
} else if (STANDALONE_COMMAND_MANAGER && source instanceof GeyserSession session) {
|
||||
// If we are on an appropriate platform, forward the command to the backend
|
||||
session.sendCommand(context.rawInput().input());
|
||||
} else {
|
||||
source.sendLocaleString(ExceptionHandlers.PERMISSION_FAIL_LANG_KEY);
|
||||
return;
|
||||
}
|
||||
help.execute(source);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,12 @@ package org.geysermc.geyser.command;
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.text.MinecraftLocale;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.exception.ArgumentParseException;
|
||||
import org.incendo.cloud.exception.CommandExecutionException;
|
||||
import org.incendo.cloud.exception.InvalidCommandSenderException;
|
||||
@@ -71,36 +73,51 @@ final class ExceptionHandlers {
|
||||
controller.clearHandlers();
|
||||
|
||||
registerExceptionHandler(InvalidSyntaxException.class,
|
||||
(src, e) -> src.sendLocaleString("geyser.command.invalid_syntax", e.correctSyntax()));
|
||||
(ctx, e) -> ctx.sender().sendLocaleString("geyser.command.invalid_syntax", e.correctSyntax()));
|
||||
|
||||
registerExceptionHandler(InvalidCommandSenderException.class, (src, e) -> {
|
||||
registerExceptionHandler(InvalidCommandSenderException.class, (ctx, e) -> {
|
||||
// We currently don't use cloud sender type requirements anywhere.
|
||||
// This can be implemented better in the future if necessary.
|
||||
Type type = e.requiredSenderTypes().iterator().next(); // just grab the first
|
||||
String typeString = GenericTypeReflector.getTypeName(type);
|
||||
src.sendLocaleString("geyser.command.invalid_sender", e.commandSender().getClass().getSimpleName(), typeString);
|
||||
ctx.sender().sendLocaleString("geyser.command.invalid_sender", e.commandSender().getClass().getSimpleName(), typeString);
|
||||
});
|
||||
|
||||
registerExceptionHandler(NoPermissionException.class, ExceptionHandlers::handleNoPermission);
|
||||
|
||||
registerExceptionHandler(NoSuchCommandException.class,
|
||||
(src, e) -> src.sendLocaleString("geyser.command.not_found"));
|
||||
(ctx, e) -> {
|
||||
// Let backend server receive & handle the command
|
||||
if (CommandRegistry.STANDALONE_COMMAND_MANAGER && ctx.sender() instanceof GeyserSession session) {
|
||||
session.sendCommand(ctx.rawInput().input());
|
||||
} else {
|
||||
ctx.sender().sendLocaleString("geyser.command.not_found");
|
||||
}
|
||||
});
|
||||
|
||||
registerExceptionHandler(ArgumentParseException.class,
|
||||
(src, e) -> src.sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage()));
|
||||
(ctx, e) -> ctx.sender().sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage()));
|
||||
|
||||
registerExceptionHandler(CommandExecutionException.class,
|
||||
(src, e) -> handleUnexpectedThrowable(src, e.getCause()));
|
||||
(ctx, e) -> handleUnexpectedThrowable(ctx.sender(), e.getCause()));
|
||||
|
||||
registerExceptionHandler(Throwable.class,
|
||||
(src, e) -> handleUnexpectedThrowable(src, e.getCause()));
|
||||
(ctx, e) -> handleUnexpectedThrowable(ctx.sender(), e.getCause()));
|
||||
}
|
||||
|
||||
private <E extends Throwable> void registerExceptionHandler(Class<E> type, BiConsumer<GeyserCommandSource, E> handler) {
|
||||
controller.registerHandler(type, context -> handler.accept(context.context().sender(), context.exception()));
|
||||
private <E extends Throwable> void registerExceptionHandler(Class<E> type, BiConsumer<CommandContext<GeyserCommandSource>, E> handler) {
|
||||
controller.registerHandler(type, context -> handler.accept(context.context(), context.exception()));
|
||||
}
|
||||
|
||||
private static void handleNoPermission(GeyserCommandSource source, NoPermissionException exception) {
|
||||
private static void handleNoPermission(CommandContext<GeyserCommandSource> context, NoPermissionException exception) {
|
||||
GeyserCommandSource source = context.sender();
|
||||
|
||||
// Let backend server receive & handle the command
|
||||
if (CommandRegistry.STANDALONE_COMMAND_MANAGER && source instanceof GeyserSession session) {
|
||||
session.sendCommand(context.rawInput().input());
|
||||
return;
|
||||
}
|
||||
|
||||
// custom handling if the source can't use the command because of additional requirements
|
||||
if (exception.permissionResult() instanceof GeyserPermission.Result result) {
|
||||
if (result.meta() == GeyserPermission.Result.Meta.NOT_BEDROCK) {
|
||||
|
||||
@@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
@@ -44,10 +43,12 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
|
||||
}
|
||||
|
||||
static void handleCommand(GeyserSession session, String command) {
|
||||
if (session.getGeyser().getPlatformType() == PlatformType.STANDALONE ||
|
||||
session.getGeyser().getPlatformType() == PlatformType.VIAPROXY) {
|
||||
// try to handle the command within the standalone/viaproxy command manager
|
||||
if (MessageTranslator.isTooLong(command, session)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CommandRegistry.STANDALONE_COMMAND_MANAGER) {
|
||||
// try to handle the command within the standalone/viaproxy command manager
|
||||
String[] args = command.split(" ");
|
||||
if (args.length > 0) {
|
||||
String root = args[0];
|
||||
@@ -55,15 +56,13 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
|
||||
CommandRegistry registry = GeyserImpl.getInstance().commandRegistry();
|
||||
if (registry.rootCommands().contains(root)) {
|
||||
registry.runCommand(session, command);
|
||||
return; // don't pass the command to the java server
|
||||
// don't pass the command to the java server here
|
||||
// will pass it through later if the user lacks permission
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MessageTranslator.isTooLong(command, session)) {
|
||||
return;
|
||||
}
|
||||
|
||||
session.sendCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user