/* * 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 . */ 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 dispatcher; private RunnableFactory runnableFactory; private LiteralArgumentBuilder root; private final PlanFabric plugin; public CommandManager(CommandDispatcher 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 arguments(final Subcommand subcommand, final CommandContext ctx, final SuggestionsBuilder builder) { return CommandSource.suggestMatching(subcommand.getArgumentResolver().apply((CMDSender) ctx.getSource(), new Arguments(new String[0])), builder); } private int execute(CommandContext 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 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 parent) { for (String alias : subcommand.getAliases()) { LiteralArgumentBuilder argumentBuilder = buildCommand(subcommand, alias); if (subcommand instanceof CommandWithSubcommands withSubcommands) { for (Subcommand cmd : withSubcommands.getSubcommands()) { registerChild(cmd, argumentBuilder); } } parent.then(argumentBuilder); } } private LiteralArgumentBuilder buildCommand(Subcommand subcommand, String alias) { RequiredArgumentBuilder arguments = RequiredArgumentBuilder.argument("arguments", StringArgumentType.greedyString()); arguments.suggests((context, builder) -> arguments(subcommand, context, builder)); arguments.executes(ctx -> execute(ctx, subcommand)); LiteralArgumentBuilder 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; } }