From 06e9c212e0083c544c01ea4d4a7476e02be4eeb5 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Tue, 13 Jun 2023 06:58:44 -0400 Subject: [PATCH] Add 1.20 support for registering commands during server runtime --- .../dev/jorel/commandapi/nms/NMS_1_20_R1.java | 131 +++++++----------- .../jorel/commandapi/test/ArgumentNMS.java | 4 +- .../dev/jorel/commandapi/test/MockNMS.java | 130 +++++++++-------- 3 files changed, 117 insertions(+), 148 deletions(-) diff --git a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-nms/commandapi-bukkit-1.20/src/main/java/dev/jorel/commandapi/nms/NMS_1_20_R1.java b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-nms/commandapi-bukkit-1.20/src/main/java/dev/jorel/commandapi/nms/NMS_1_20_R1.java index 046ca8446b..789a421685 100644 --- a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-nms/commandapi-bukkit-1.20/src/main/java/dev/jorel/commandapi/nms/NMS_1_20_R1.java +++ b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-nms/commandapi-bukkit-1.20/src/main/java/dev/jorel/commandapi/nms/NMS_1_20_R1.java @@ -20,56 +20,6 @@ *******************************************************************************/ package dev.jorel.commandapi.nms; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.function.Predicate; -import java.util.function.ToIntFunction; - -import dev.jorel.commandapi.CommandAPIHandler; -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.Particle; -import org.bukkit.Particle.DustOptions; -import org.bukkit.Particle.DustTransition; -import org.bukkit.Vibration; -import org.bukkit.Vibration.Destination; -import org.bukkit.Vibration.Destination.BlockDestination; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.SimpleCommandMap; -import org.bukkit.craftbukkit.v1_20_R1.CraftLootTable; -import org.bukkit.craftbukkit.v1_20_R1.CraftParticle; -import org.bukkit.craftbukkit.v1_20_R1.CraftServer; -import org.bukkit.craftbukkit.v1_20_R1.CraftSound; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R1.command.VanillaCommandWrapper; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_20_R1.help.CustomHelpTopic; -import org.bukkit.craftbukkit.v1_20_R1.help.SimpleHelpMap; -import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.help.HelpTopic; -import org.bukkit.inventory.Recipe; -import org.bukkit.potion.PotionEffectType; - import com.google.common.collect.ImmutableList; import com.google.common.io.Files; import com.google.gson.GsonBuilder; @@ -80,9 +30,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.logging.LogUtils; - import dev.jorel.commandapi.CommandAPI; +import dev.jorel.commandapi.CommandAPIHandler; import dev.jorel.commandapi.SafeVarHandle; import dev.jorel.commandapi.arguments.ArgumentSubType; import dev.jorel.commandapi.arguments.SuggestionProviders; @@ -92,12 +43,7 @@ import dev.jorel.commandapi.preprocessor.Differs; import dev.jorel.commandapi.preprocessor.NMSMeta; import dev.jorel.commandapi.preprocessor.RequireField; -import dev.jorel.commandapi.wrappers.ComplexRecipeImpl; -import dev.jorel.commandapi.wrappers.FunctionWrapper; -import dev.jorel.commandapi.wrappers.Location2D; -import dev.jorel.commandapi.wrappers.NativeProxyCommandSender; -import dev.jorel.commandapi.wrappers.ParticleData; -import dev.jorel.commandapi.wrappers.SimpleFunctionWrapper; +import dev.jorel.commandapi.wrappers.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -106,13 +52,7 @@ import net.minecraft.commands.CommandFunction.Entry; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.commands.arguments.ColorArgument; -import net.minecraft.commands.arguments.ComponentArgument; -import net.minecraft.commands.arguments.DimensionArgument; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.ParticleArgument; -import net.minecraft.commands.arguments.ResourceArgument; -import net.minecraft.commands.arguments.ResourceLocationArgument; +import net.minecraft.commands.arguments.*; import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; import net.minecraft.commands.arguments.blocks.BlockStateArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; @@ -127,15 +67,7 @@ import net.minecraft.commands.synchronization.ArgumentUtils; import net.minecraft.core.BlockPos; import net.minecraft.core.RegistryAccess.Frozen; -import net.minecraft.core.particles.BlockParticleOption; -import net.minecraft.core.particles.DustColorTransitionOptions; -import net.minecraft.core.particles.DustParticleOptions; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.core.particles.SculkChargeParticleOptions; -import net.minecraft.core.particles.ShriekParticleOption; -import net.minecraft.core.particles.SimpleParticleType; -import net.minecraft.core.particles.VibrationParticleOption; +import net.minecraft.core.particles.*; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; @@ -165,6 +97,44 @@ import net.minecraft.world.level.storage.loot.LootDataType; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; +import org.bukkit.*; +import org.bukkit.Particle.DustOptions; +import org.bukkit.Particle.DustTransition; +import org.bukkit.Vibration.Destination; +import org.bukkit.Vibration.Destination.BlockDestination; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.craftbukkit.v1_20_R1.CraftLootTable; +import org.bukkit.craftbukkit.v1_20_R1.CraftParticle; +import org.bukkit.craftbukkit.v1_20_R1.CraftServer; +import org.bukkit.craftbukkit.v1_20_R1.CraftSound; +import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R1.command.VanillaCommandWrapper; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R1.help.CustomHelpTopic; +import org.bukkit.craftbukkit.v1_20_R1.help.SimpleHelpMap; +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.help.HelpTopic; +import org.bukkit.inventory.Recipe; +import org.bukkit.potion.PotionEffectType; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; +import java.util.function.ToIntFunction; // Mojang-Mapped reflection /** @@ -253,10 +223,8 @@ public final ArgumentType _ArgumentSyntheticBiome() { } @Override - public final void addToHelpMap(Map helpTopicsToAdd) { - // We have to use VarHandles to use helpTopics.put (instead of .addTopic) - // because we're updating an existing help topic, not adding a new help topic - helpMapTopics.get((SimpleHelpMap) Bukkit.getServer().getHelpMap()).putAll(helpTopicsToAdd); + public final Map getHelpMap() { + return helpMapTopics.get((SimpleHelpMap) Bukkit.getHelpMap()); } @Override @@ -339,8 +307,8 @@ public final BlockData getBlockState(CommandContext cmdCtx, } @Override - public final com.mojang.brigadier.CommandDispatcher getBrigadierDispatcher() { - return this.getMinecraftServer().vanillaCommandDispatcher.getDispatcher(); + public final CommandDispatcher getResourcesDispatcher() { + return this.getMinecraftServer().getCommands().getDispatcher(); } @Override @@ -650,6 +618,11 @@ public final boolean isVanillaCommandWrapper(Command command) { return command instanceof VanillaCommandWrapper; } + @Override + public Command wrapToVanillaCommandWrapper(LiteralCommandNode node) { + return new VanillaCommandWrapper(this.getMinecraftServer().vanillaCommandDispatcher, node); + } + @Override public final void reloadDataPacks() { CommandAPI.logNormal("Reloading datapacks..."); diff --git a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/ArgumentNMS.java b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/ArgumentNMS.java index 7a88ada891..b64ee2115c 100644 --- a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/ArgumentNMS.java +++ b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/ArgumentNMS.java @@ -71,10 +71,10 @@ @SuppressWarnings({ "unchecked", "rawtypes" }) public abstract class ArgumentNMS extends MockPlatform { - CommandAPIBukkit baseNMS; + CommandAPIBukkit baseNMS; protected ArgumentNMS(CommandAPIBukkit baseNMS) { - this.baseNMS = baseNMS; + this.baseNMS = (CommandAPIBukkit) baseNMS; } @Override diff --git a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/MockNMS.java b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/MockNMS.java index deb165efe0..791644a42b 100644 --- a/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/MockNMS.java +++ b/commandapi-platforms/commandapi-bukkit/commandapi-bukkit-test/commandapi-bukkit-test-impl-1.20/src/main/java/dev/jorel/commandapi/test/MockNMS.java @@ -1,58 +1,17 @@ package dev.jorel.commandapi.test; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; - -import java.io.File; -import java.io.IOException; -import java.security.CodeSource; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.Particle; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.command.SimpleCommandMap; -import org.bukkit.craftbukkit.v1_20_R1.CraftParticle; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemFactory; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.help.HelpTopic; -import org.bukkit.inventory.ItemFactory; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scoreboard.Team; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.mockito.Mockito; - -import com.google.common.collect.Streams; -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.CommandDispatcher; - import be.seeseemelk.mockbukkit.ServerMock; import be.seeseemelk.mockbukkit.WorldMock; import be.seeseemelk.mockbukkit.enchantments.EnchantmentMock; +import be.seeseemelk.mockbukkit.help.HelpMapMock; import be.seeseemelk.mockbukkit.potion.MockPotionEffectType; +import com.google.common.collect.Streams; +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.tree.LiteralCommandNode; import dev.jorel.commandapi.Brigadier; import dev.jorel.commandapi.CommandAPIBukkit; +import dev.jorel.commandapi.SafeVarHandle; import dev.jorel.commandapi.commandsenders.AbstractCommandSender; import dev.jorel.commandapi.commandsenders.BukkitCommandSender; import dev.jorel.commandapi.commandsenders.BukkitPlayer; @@ -66,12 +25,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.Bootstrap; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.ServerAdvancementManager; -import net.minecraft.server.ServerFunctionLibrary; -import net.minecraft.server.ServerFunctionManager; -import net.minecraft.server.ServerScoreboard; +import net.minecraft.server.*; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.GameProfileCache; @@ -90,8 +44,37 @@ import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.criteria.ObjectiveCriteria; import net.minecraft.world.scores.criteria.ObjectiveCriteria.RenderType; +import org.bukkit.*; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.craftbukkit.v1_20_R1.CraftParticle; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemFactory; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.help.HelpTopic; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scoreboard.Team; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.mockito.Mockito; + +import java.io.File; +import java.io.IOException; +import java.security.CodeSource; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.mockito.ArgumentMatchers.*; public class MockNMS extends Enums { + private static final SafeVarHandle> helpMapTopics = + SafeVarHandle.ofOrNull(HelpMapMock.class, "topics", "topics", Map.class); static { CodeSource src = PotionEffectType.class.getProtectionDomain().getCodeSource(); @@ -113,7 +96,7 @@ public MockNMS(CommandAPIBukkit baseNMS) { super(baseNMS); // Stub in our getMinecraftServer implementation - CommandAPIBukkit nms = Mockito.spy(super.baseNMS); + CommandAPIBukkit nms = Mockito.spy(super.baseNMS); Mockito.when(nms.getMinecraftServer()).thenAnswer(i -> getMinecraftServer()); super.baseNMS = nms; @@ -140,6 +123,18 @@ public MockNMS(CommandAPIBukkit baseNMS) { this.recipeManager = new RecipeManager(); this.functions = new HashMap<>(); registerDefaultRecipes(); + + // Setup playerListMock + playerListMock = Mockito.mock(PlayerList.class); + Mockito.when(playerListMock.getPlayerByName(anyString())).thenAnswer(invocation -> { + String playerName = invocation.getArgument(0); + for (ServerPlayer onlinePlayer : players) { + if (onlinePlayer.getBukkitEntity().getName().equals(playerName)) { + return onlinePlayer; + } + } + return null; + }); } /************************* @@ -256,6 +251,16 @@ public SimpleCommandMap getSimpleCommandMap() { return ((ServerMock) Bukkit.getServer()).getCommandMap(); } + @Override + public boolean isVanillaCommandWrapper(Command command) { + return baseNMS.isVanillaCommandWrapper(command); + } + + @Override + public Command wrapToVanillaCommandWrapper(LiteralCommandNode node) { + return baseNMS.wrapToVanillaCommandWrapper(node); + } + @SuppressWarnings({ "deprecation", "unchecked" }) @Override public CommandSourceStack getBrigadierSourceFromCommandSender(AbstractCommandSender senderWrapper) { @@ -301,19 +306,6 @@ public CommandSourceStack getBrigadierSourceFromCommandSender(AbstractCommandSen players.add(entityPlayerMock); } - if (playerListMock == null) { - playerListMock = Mockito.mock(PlayerList.class); - Mockito.when(playerListMock.getPlayerByName(anyString())).thenAnswer(invocation -> { - String playerName = invocation.getArgument(0); - for (ServerPlayer onlinePlayer : players) { - if (onlinePlayer.getBukkitEntity().getName().equals(playerName)) { - return onlinePlayer; - } - } - return null; - }); - } - // CommandSourceStack#levels Mockito.when(css.levels()).thenAnswer(invocation -> { Set> set = new HashSet<>(); @@ -808,4 +800,8 @@ public HelpTopic generateHelpTopic(String commandName, String shortDescription, return baseNMS.generateHelpTopic(commandName, shortDescription, fullDescription, permission); } + @Override + public Map getHelpMap() { + return helpMapTopics.get((HelpMapMock) Bukkit.getHelpMap()); + } }