Plan/Plan/fabric/src/main/java/net/playeranalytics/plan/commands/CommandManager.java

153 lines
6.4 KiB
Java

/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package net.playeranalytics.plan.commands;
import com.djrapitops.plan.commands.use.Arguments;
import com.djrapitops.plan.commands.use.CMDSender;
import com.djrapitops.plan.commands.use.CommandWithSubcommands;
import com.djrapitops.plan.commands.use.Subcommand;
import com.djrapitops.plan.utilities.logging.ErrorContext;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.command.CommandSource;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import net.playeranalytics.plan.PlanFabric;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import java.util.concurrent.CompletableFuture;
public class CommandManager {
private final CommandDispatcher<ServerCommandSource> dispatcher;
private RunnableFactory runnableFactory;
private LiteralArgumentBuilder<ServerCommandSource> root;
private final PlanFabric plugin;
public CommandManager(CommandDispatcher<ServerCommandSource> dispatcher, PlanFabric plugin) {
this.dispatcher = dispatcher;
this.plugin = plugin;
}
public static boolean checkPermission(ServerCommandSource src, String permission) {
if (isPermissionsApiAvailable()) {
return Permissions.check(src, permission, 2);
} else if (src.hasPermissionLevel(2)) {
return true;
} else {
return switch (permission) {
case "plan.player.self", "plan.ingame.self", "plan.register.self", "plan.unregister.self", "plan.json.self" -> true;
default -> false;
};
}
}
public static boolean isPermissionsApiAvailable() {
try {
Class.forName("me.lucko.fabric.api.permissions.v0.Permissions");
return true;
} catch (ClassNotFoundException e) {
return false; // not available
}
}
public CompletableFuture<Suggestions> arguments(final Subcommand subcommand, final CommandContext<ServerCommandSource> ctx, final SuggestionsBuilder builder) {
return CommandSource.suggestMatching(subcommand.getArgumentResolver().apply((CMDSender) ctx.getSource(), new Arguments(new String[0])), builder);
}
private int execute(CommandContext<ServerCommandSource> ctx, Subcommand subcommand) {
runnableFactory.create(() -> {
try {
subcommand.getExecutor().accept((CMDSender) ctx.getSource(), new Arguments(getCommandArguments(ctx)));
} catch (Exception e) {
if (e instanceof IllegalArgumentException) {
ctx.getSource().sendError(Text.literal(e.getMessage()));
} else {
ctx.getSource().sendError(Text.literal("An internal error occurred, see the console for details."));
plugin.getSystem().getErrorLogger().error(e, ErrorContext.builder()
.related(ctx.getSource().getClass())
.related(subcommand.getPrimaryAlias() + " " + getCommandArguments(ctx))
.build());
}
}
}).runTaskAsynchronously();
return 1;
}
private String getCommandArguments(CommandContext<ServerCommandSource> ctx) {
String arguments;
try {
arguments = StringArgumentType.getString(ctx, "arguments");
} catch (IllegalArgumentException e) {
arguments = "";
}
return arguments;
}
private void build() {
dispatcher.register(root);
}
public void registerRoot(Subcommand subcommand, RunnableFactory runnableFactory) {
this.runnableFactory = runnableFactory;
root = buildCommand(subcommand, subcommand.getPrimaryAlias());
if (subcommand instanceof CommandWithSubcommands withSubcommands) {
for (Subcommand cmd : withSubcommands.getSubcommands()) {
registerChild(cmd, root);
}
}
build();
}
public void registerChild(Subcommand subcommand, ArgumentBuilder<ServerCommandSource, ?> parent) {
for (String alias : subcommand.getAliases()) {
LiteralArgumentBuilder<ServerCommandSource> argumentBuilder = buildCommand(subcommand, alias);
if (subcommand instanceof CommandWithSubcommands withSubcommands) {
for (Subcommand cmd : withSubcommands.getSubcommands()) {
registerChild(cmd, argumentBuilder);
}
}
parent.then(argumentBuilder);
}
}
private LiteralArgumentBuilder<ServerCommandSource> buildCommand(Subcommand subcommand, String alias) {
RequiredArgumentBuilder<ServerCommandSource, String> arguments = RequiredArgumentBuilder.argument("arguments", StringArgumentType.greedyString());
arguments.suggests((context, builder) -> arguments(subcommand, context, builder));
arguments.executes(ctx -> execute(ctx, subcommand));
LiteralArgumentBuilder<ServerCommandSource> literal = LiteralArgumentBuilder.literal(alias);
literal.executes(ctx -> execute(ctx, subcommand));
literal.requires(src -> {
for (String permission : subcommand.getRequiredPermissions()) {
if (!checkPermission(src, permission)) return false;
}
return true;
});
literal.then(arguments);
return literal;
}
}