From d5461d104f4aef366b1e837895f362ee94eeb442 Mon Sep 17 00:00:00 2001 From: jmp Date: Tue, 6 Oct 2020 10:17:32 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Move=20Brig=20mappings=20to=20a?= =?UTF-8?q?=20common=20class=20for=20Paper=20and=20Commodore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/BukkitBrigadierMapper.java | 171 ++++++++++++++++++ .../bukkit/CloudCommodoreManager.java | 1 + .../paper/PaperBrigadierListener.java | 117 +----------- 3 files changed, 174 insertions(+), 115 deletions(-) create mode 100644 cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java new file mode 100644 index 00000000..8baa6c29 --- /dev/null +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/BukkitBrigadierMapper.java @@ -0,0 +1,171 @@ +// +// MIT License +// +// Copyright (c) 2020 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.brigadier.CloudBrigadierManager; +import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector; +import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector; +import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; +import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; +import com.mojang.brigadier.arguments.ArgumentType; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.UUID; +import java.util.function.Supplier; +import java.util.logging.Level; + +/** + * Class which handles mapping argument types to their NMS Brigadier counterpart on Bukkit platforms. + * + * @param Command sender type + */ +public final class BukkitBrigadierMapper { + + private static final int UUID_ARGUMENT_VERSION = 16; + + private final BukkitCommandManager commandManager; + private final CloudBrigadierManager brigadierManager; + private final String nmsVersion; + + + /** + * Class that handles mapping argument types to Brigadier for Bukkit (Commodore) and Paper. + * + * @param commandManager The {@link BukkitCommandManager} to use for mapping + * @param brigadierManager The {@link CloudBrigadierManager} to use for mapping + */ + public BukkitBrigadierMapper(final @NonNull BukkitCommandManager commandManager, + final @NonNull CloudBrigadierManager brigadierManager) { + this.commandManager = commandManager; + this.brigadierManager = brigadierManager; + + /* Detect Minecraft Version Metadata */ + final String version = Bukkit.getServer().getClass().getPackage().getName(); + this.nmsVersion = version.substring(version.lastIndexOf(".") + 1); + final int majorMinecraftVersion = Integer.parseInt(nmsVersion.split("_")[1]); + + try { + /* UUID nms argument is a 1.16+ feature */ + if (majorMinecraftVersion >= UUID_ARGUMENT_VERSION) { + /* Map UUID */ + this.mapSimpleNMS(UUID.class, this.getNMSArgument("UUID").getConstructor()); + } + /* Map Enchantment */ + this.mapSimpleNMS(Enchantment.class, this.getNMSArgument("Enchantment").getConstructor()); + /* Map EntityType */ + this.mapSimpleNMS(EntityType.class, this.getNMSArgument("EntitySummon").getConstructor()); + /* Map Material */ + this.mapSimpleNMS(Material.class, this.getNMSArgument("ItemStack").getConstructor()); + /* Map Entity Selectors */ + this.mapComplexNMS(SingleEntitySelector.class, this.getEntitySelectorArgument(true, false)); + this.mapComplexNMS(SinglePlayerSelector.class, this.getEntitySelectorArgument(true, true)); + this.mapComplexNMS(MultipleEntitySelector.class, this.getEntitySelectorArgument(false, false)); + this.mapComplexNMS(MultiplePlayerSelector.class, this.getEntitySelectorArgument(false, true)); + } catch (final Exception e) { + this.commandManager.getOwningPlugin() + .getLogger() + .log(Level.WARNING, "Failed to map Bukkit types to NMS argument types", e); + } + } + + /** + * @param single Whether the selector is for a single entity only (true), or for multiple entities (false) + * @param playersOnly Whether the selector is for players only (true), or for all entities (false) + * @return The NMS ArgumentType + */ + private Supplier> getEntitySelectorArgument(final boolean single, + final boolean playersOnly) { + return () -> { + try { + final Constructor constructor = this.getNMSArgument("Entity").getDeclaredConstructors()[0]; + constructor.setAccessible(true); + return (ArgumentType) constructor.newInstance(single, playersOnly); + } catch (final Exception e) { + this.commandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Selector Argument", e); + return null; + } + }; + } + + /** + * Attempt to retrieve an NMS argument type + * + * @param argument Argument type name + * @return Argument class + * @throws Exception If the type cannot be retrieved + */ + @NonNull + private Class getNMSArgument(final @NonNull String argument) throws Exception { + return Class.forName(String.format("net.minecraft.server.%s.Argument%s", this.nmsVersion, argument)); + } + + /** + * Attempt to register a mapping between a type and a NMS argument type + * + * @param type Type to map + * @param constructor Constructor that construct the NMS argument type + */ + public void mapSimpleNMS(final @NonNull Class type, + final @NonNull Constructor constructor) { + try { + this.brigadierManager.registerDefaultArgumentTypeSupplier(type, () -> { + try { + return (ArgumentType) constructor.newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + }); + } catch (final Exception e) { + this.commandManager.getOwningPlugin() + .getLogger() + .warning(String.format("Failed to map '%s' to a Mojang serializable argument type", + type.getCanonicalName())); + } + } + + /** + * Attempt to register a mapping between a type and a NMS argument type + * + * @param type Type to map + * @param argumentTypeSupplier Supplier of the NMS argument type + */ + public void mapComplexNMS(final @NonNull Class type, + final @NonNull Supplier> argumentTypeSupplier) { + try { + this.brigadierManager.registerDefaultArgumentTypeSupplier(type, argumentTypeSupplier); + } catch (final Exception e) { + this.commandManager.getOwningPlugin() + .getLogger() + .warning(String.format("Failed to map '%s' to a Mojang serializable argument type", + type.getCanonicalName())); + } + } +} diff --git a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java index cddfc6ca..96807e14 100644 --- a/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java +++ b/cloud-minecraft/cloud-bukkit/src/main/java/cloud/commandframework/bukkit/CloudCommodoreManager.java @@ -55,6 +55,7 @@ class CloudCommodoreManager extends BukkitPluginRegistrationHandler { this.commodore = CommodoreProvider.getCommodore(commandManager.getOwningPlugin()); this.brigadierManager = new CloudBrigadierManager<>(commandManager, () -> new CommandContext<>(commandManager.getCommandSenderMapper().apply(Bukkit.getConsoleSender()))); + new BukkitBrigadierMapper<>(this.commandManager, this.brigadierManager); } @Override diff --git a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java index bfdfd049..2b0d0382 100644 --- a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java +++ b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java @@ -26,39 +26,24 @@ package cloud.commandframework.paper; import cloud.commandframework.CommandTree; import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.brigadier.CloudBrigadierManager; -import cloud.commandframework.bukkit.arguments.selector.MultipleEntitySelector; -import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector; -import cloud.commandframework.bukkit.arguments.selector.SingleEntitySelector; -import cloud.commandframework.bukkit.arguments.selector.SinglePlayerSelector; +import cloud.commandframework.bukkit.BukkitBrigadierMapper; import cloud.commandframework.context.CommandContext; import cloud.commandframework.permission.CommandPermission; import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; import com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent; -import com.mojang.brigadier.arguments.ArgumentType; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.command.PluginIdentifiableCommand; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.checkerframework.checker.nullness.qual.NonNull; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.UUID; import java.util.function.BiPredicate; -import java.util.function.Supplier; -import java.util.logging.Level; import java.util.regex.Pattern; class PaperBrigadierListener implements Listener { - private static final int UUID_ARGUMENT_VERSION = 16; - private final CloudBrigadierManager brigadierManager; private final PaperCommandManager paperCommandManager; - private final String nmsVersion; PaperBrigadierListener(final @NonNull PaperCommandManager paperCommandManager) { this.paperCommandManager = paperCommandManager; @@ -66,105 +51,7 @@ class PaperBrigadierListener implements Listener { () -> new CommandContext<>( this.paperCommandManager.getCommandSenderMapper() .apply(Bukkit.getConsoleSender()))); - /* Register default mappings */ - final String version = Bukkit.getServer().getClass().getPackage().getName(); - this.nmsVersion = version.substring(version.lastIndexOf(".") + 1); - final int majorMinecraftVersion = Integer.parseInt(this.nmsVersion.split("_")[1]); - try { - /* UUID nms argument is a 1.16+ feature */ - if (majorMinecraftVersion >= UUID_ARGUMENT_VERSION) { - /* Map UUID */ - this.mapSimpleNMS(UUID.class, this.getNMSArgument("UUID").getConstructor()); - } - /* Map Enchantment */ - this.mapSimpleNMS(Enchantment.class, this.getNMSArgument("Enchantment").getConstructor()); - /* Map EntityType */ - this.mapSimpleNMS(EntityType.class, this.getNMSArgument("EntitySummon").getConstructor()); - /* Map Material */ - this.mapSimpleNMS(Material.class, this.getNMSArgument("ItemStack").getConstructor()); - /* Map Entity Selectors */ - this.mapComplexNMS(SingleEntitySelector.class, this.getEntitySelectorArgument(true, false)); - this.mapComplexNMS(SinglePlayerSelector.class, this.getEntitySelectorArgument(true, true)); - this.mapComplexNMS(MultipleEntitySelector.class, this.getEntitySelectorArgument(false, false)); - this.mapComplexNMS(MultiplePlayerSelector.class, this.getEntitySelectorArgument(false, true)); - } catch (final Exception e) { - this.paperCommandManager.getOwningPlugin() - .getLogger() - .log(Level.WARNING, "Failed to map Bukkit types to NMS argument types", e); - } - } - - /** - * @param single Whether the selector is for a single entity only (true), or for multiple entities (false) - * @param playersOnly Whether the selector is for players only (true), or for all entities (false) - * @return The NMS ArgumentType - */ - private Supplier> getEntitySelectorArgument(final boolean single, - final boolean playersOnly) { - return () -> { - try { - final Constructor constructor = this.getNMSArgument("Entity").getDeclaredConstructors()[0]; - constructor.setAccessible(true); - return (ArgumentType) constructor.newInstance(single, playersOnly); - } catch (final Exception e) { - this.paperCommandManager.getOwningPlugin().getLogger().log(Level.INFO, "Failed to retrieve Selector Argument", e); - return null; - } - }; - } - - /** - * Attempt to retrieve an NMS argument type - * - * @param argument Argument type name - * @return Argument class - * @throws Exception If the type cannot be retrieved - */ - private @NonNull Class getNMSArgument(final @NonNull String argument) throws Exception { - return Class.forName(String.format("net.minecraft.server.%s.Argument%s", this.nmsVersion, argument)); - } - - /** - * Attempt to register a mapping between a type and a NMS argument type - * - * @param type Type to map - * @param constructor Constructor that construct the NMS argument type - */ - public void mapSimpleNMS(final @NonNull Class type, - final @NonNull Constructor constructor) { - try { - this.brigadierManager.registerDefaultArgumentTypeSupplier(type, () -> { - try { - return (ArgumentType) constructor.newInstance(); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - return null; - }); - } catch (final Exception e) { - this.paperCommandManager.getOwningPlugin() - .getLogger() - .warning(String.format("Failed to map '%s' to a Mojang serializable argument type", - type.getCanonicalName())); - } - } - - /** - * Attempt to register a mapping between a type and a NMS argument type - * - * @param type Type to map - * @param argumentTypeSupplier Supplier of the NMS argument type - */ - public void mapComplexNMS(final @NonNull Class type, - final @NonNull Supplier> argumentTypeSupplier) { - try { - this.brigadierManager.registerDefaultArgumentTypeSupplier(type, argumentTypeSupplier); - } catch (final Exception e) { - this.paperCommandManager.getOwningPlugin() - .getLogger() - .warning(String.format("Failed to map '%s' to a Mojang serializable argument type", - type.getCanonicalName())); - } + new BukkitBrigadierMapper<>(this.paperCommandManager, this.brigadierManager); } @EventHandler