All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cloud.commandframework.bukkit.BukkitPluginRegistrationHandler Maven / Gradle / Ivy

There is a newer version: 1.8.4
Show newest version
//
// MIT License
//
// Copyright (c) 2022 Alexander Söderberg & Contributors
//
// 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.
//
package cloud.commandframework.bukkit;

import cloud.commandframework.Command;
import cloud.commandframework.CommandManager;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.StaticArgument;
import cloud.commandframework.internal.CommandRegistrationHandler;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apiguardian.api.API;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandMap;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.entity.Player;
import org.bukkit.help.GenericCommandHelpTopic;
import org.checkerframework.checker.nullness.qual.NonNull;

public class BukkitPluginRegistrationHandler implements CommandRegistrationHandler {

    private final Map, org.bukkit.command.Command> registeredCommands = new HashMap<>();
    private final Set recognizedAliases = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);

    private Map bukkitCommands;
    private BukkitCommandManager bukkitCommandManager;
    private CommandMap commandMap;

    protected BukkitPluginRegistrationHandler() {
    }

    final void initialize(final @NonNull BukkitCommandManager bukkitCommandManager) throws Exception {
        final Method getCommandMap = Bukkit.getServer().getClass().getDeclaredMethod("getCommandMap");
        getCommandMap.setAccessible(true);
        this.commandMap = (CommandMap) getCommandMap.invoke(Bukkit.getServer());
        final Field knownCommands = SimpleCommandMap.class.getDeclaredField("knownCommands");
        knownCommands.setAccessible(true);
        @SuppressWarnings("unchecked") final Map bukkitCommands =
                (Map) knownCommands.get(this.commandMap);
        this.bukkitCommands = bukkitCommands;
        this.bukkitCommandManager = bukkitCommandManager;
        Bukkit.getHelpMap().registerHelpTopicFactory(BukkitCommand.class, GenericCommandHelpTopic::new);
    }

    @Override
    public final boolean registerCommand(final @NonNull Command command) {
        /* We only care about the root command argument */
        final CommandArgument commandArgument = command.getArguments().get(0);
        if (!(this.bukkitCommandManager.commandRegistrationHandler() instanceof CloudCommodoreManager)
                && this.registeredCommands.containsKey(commandArgument)) {
            return false;
        }
        final String label = commandArgument.getName();
        final String namespacedLabel = this.getNamespacedLabel(label);

        @SuppressWarnings("unchecked") final List aliases = new ArrayList<>(
                ((StaticArgument) commandArgument).getAlternativeAliases()
        );

        @SuppressWarnings("unchecked") final BukkitCommand bukkitCommand = new BukkitCommand<>(
                label,
                aliases,
                (Command) command,
                (CommandArgument) commandArgument,
                this.bukkitCommandManager
        );

        if (this.bukkitCommandManager.getSetting(CommandManager.ManagerSettings.OVERRIDE_EXISTING_COMMANDS)) {
            this.bukkitCommands.remove(label);
            aliases.forEach(this.bukkitCommands::remove);
        }

        final Set newAliases = new HashSet<>();

        for (final String alias : aliases) {
            final String namespacedAlias = this.getNamespacedLabel(alias);
            newAliases.add(namespacedAlias);
            if (!this.bukkitCommandOrAliasExists(alias)) {
                newAliases.add(alias);
            }
        }

        if (!this.bukkitCommandExists(label)) {
            newAliases.add(label);
        }
        newAliases.add(namespacedLabel);

        this.commandMap.register(
                label,
                this.bukkitCommandManager.getOwningPlugin().getName().toLowerCase(),
                bukkitCommand
        );

        this.recognizedAliases.addAll(newAliases);
        if (this.bukkitCommandManager.getSplitAliases()) {
            newAliases.forEach(alias -> this.registerExternal(alias, command, bukkitCommand));
        }

        this.registeredCommands.put(commandArgument, bukkitCommand);
        return true;
    }

    @Override
    @SuppressWarnings("unchecked")
    public final void unregisterRootCommand(
            final @NonNull StaticArgument rootCommand
    ) {
        final org.bukkit.command.Command registeredCommand = this.registeredCommands.get(rootCommand);
        if (registeredCommand == null) {
            return;
        }
        ((BukkitCommand) registeredCommand).disable();

        final List aliases = new ArrayList<>(rootCommand.getAlternativeAliases());
        final Set registeredAliases = new HashSet<>();

        for (final String alias : aliases) {
            registeredAliases.add(this.getNamespacedLabel(alias));
            if (this.bukkitCommandOrAliasExists(alias)) {
                registeredAliases.add(alias);
            }
        }

        if (this.bukkitCommandExists(rootCommand.getName())) {
            registeredAliases.add(rootCommand.getName());
        }
        registeredAliases.add(this.getNamespacedLabel(rootCommand.getName()));

        this.bukkitCommands.remove(rootCommand.getName());
        this.bukkitCommands.remove(this.getNamespacedLabel(rootCommand.getName()));

        this.recognizedAliases.removeAll(registeredAliases);
        if (this.bukkitCommandManager.getSplitAliases()) {
            registeredAliases.forEach(this::unregisterExternal);
        }

        this.registeredCommands.remove(rootCommand);

        if (this.bukkitCommandManager.hasCapability(CloudBukkitCapabilities.BRIGADIER)) {
            // Once the command has been unregistered, we need to refresh the command list for all online players.
            Bukkit.getOnlinePlayers().forEach(Player::updateCommands);
        }
    }

    private @NonNull String getNamespacedLabel(final @NonNull String label) {
        return String.format("%s:%s", this.bukkitCommandManager.getOwningPlugin().getName(), label).toLowerCase();
    }

    /**
     * Check if the given alias is recognizable by this registration handler
     *
     * @param alias Alias
     * @return {@code true} if the alias is recognized, else {@code false}
     */
    public boolean isRecognized(final @NonNull String alias) {
        return this.recognizedAliases.contains(alias);
    }

    protected void registerExternal(
            final @NonNull String label,
            final @NonNull Command command,
            final @NonNull BukkitCommand bukkitCommand
    ) {
    }

    @API(status = API.Status.STABLE, since = "1.7.0")
    protected void unregisterExternal(final @NonNull String label) {
    }

    /**
     * Returns true if a command exists in the Bukkit command map, is not an alias, and is not owned by us.
     *
     * @param commandLabel label to check
     * @return whether the command exists and is not an alias
     */
    private boolean bukkitCommandExists(final String commandLabel) {
        final org.bukkit.command.Command existingCommand = this.bukkitCommands.get(commandLabel);
        if (existingCommand == null) {
            return false;
        }
        if (existingCommand instanceof PluginIdentifiableCommand) {
            return existingCommand.getLabel().equals(commandLabel)
                    && !((PluginIdentifiableCommand) existingCommand).getPlugin().getName()
                    .equalsIgnoreCase(this.bukkitCommandManager.getOwningPlugin().getName());
        }
        return existingCommand.getLabel().equals(commandLabel);
    }

    /**
     * Returns true if a command exists in the Bukkit command map, and it is not owned by us, whether or not it is an alias.
     *
     * @param commandLabel label to check
     * @return whether the command exists
     */
    private boolean bukkitCommandOrAliasExists(final String commandLabel) {
        final org.bukkit.command.Command command = this.bukkitCommands.get(commandLabel);
        if (command instanceof PluginIdentifiableCommand) {
            return !((PluginIdentifiableCommand) command).getPlugin().getName()
                    .equalsIgnoreCase(this.bukkitCommandManager.getOwningPlugin().getName());
        }
        return command != null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy