|
6 | 6 |
|
7 | 7 | import java.io.File;
|
8 | 8 | import java.io.IOException;
|
| 9 | +import java.security.CodeSource; |
9 | 10 | import java.util.ArrayList;
|
10 | 11 | import java.util.Arrays;
|
11 | 12 | import java.util.Collection;
|
|
51 | 52 | import be.seeseemelk.mockbukkit.WorldMock;
|
52 | 53 | import be.seeseemelk.mockbukkit.enchantments.EnchantmentMock;
|
53 | 54 | import be.seeseemelk.mockbukkit.potion.MockPotionEffectType;
|
| 55 | +import dev.jorel.commandapi.Brigadier; |
54 | 56 | import dev.jorel.commandapi.CommandAPIBukkit;
|
55 | 57 | import dev.jorel.commandapi.commandsenders.AbstractCommandSender;
|
56 | 58 | import dev.jorel.commandapi.commandsenders.BukkitCommandSender;
|
| 59 | +import dev.jorel.commandapi.commandsenders.BukkitPlayer; |
57 | 60 | import io.papermc.paper.advancement.AdvancementDisplay;
|
58 |
| -import net.kyori.adventure.text.Component; |
59 | 61 | import net.minecraft.SharedConstants;
|
60 | 62 | import net.minecraft.advancements.Advancement;
|
| 63 | +import net.minecraft.commands.CommandFunction; |
61 | 64 | import net.minecraft.commands.CommandSourceStack;
|
62 | 65 | import net.minecraft.commands.arguments.EntityAnchorArgument.Anchor;
|
63 | 66 | import net.minecraft.core.BlockPos;
|
|
68 | 71 | import net.minecraft.server.Bootstrap;
|
69 | 72 | import net.minecraft.server.MinecraftServer;
|
70 | 73 | import net.minecraft.server.ServerAdvancementManager;
|
| 74 | +import net.minecraft.server.ServerFunctionLibrary; |
| 75 | +import net.minecraft.server.ServerFunctionManager; |
71 | 76 | import net.minecraft.server.ServerScoreboard;
|
72 | 77 | import net.minecraft.server.level.ServerLevel;
|
73 | 78 | import net.minecraft.server.level.ServerPlayer;
|
74 | 79 | import net.minecraft.server.players.GameProfileCache;
|
75 | 80 | import net.minecraft.server.players.PlayerList;
|
| 81 | +import net.minecraft.tags.Tag; |
| 82 | +import net.minecraft.tags.TagCollection; |
| 83 | +import net.minecraft.util.profiling.metrics.profiling.InactiveMetricsRecorder; |
76 | 84 | import net.minecraft.world.item.crafting.Recipe;
|
77 | 85 | import net.minecraft.world.item.crafting.RecipeManager;
|
| 86 | +import net.minecraft.world.level.GameRules; |
78 | 87 | import net.minecraft.world.level.Level;
|
79 | 88 | import net.minecraft.world.level.storage.loot.BuiltInLootTables;
|
80 | 89 | import net.minecraft.world.level.storage.loot.LootTables;
|
|
84 | 93 |
|
85 | 94 | public class MockNMS extends Enums {
|
86 | 95 |
|
| 96 | + static { |
| 97 | + CodeSource src = PotionEffectType.class.getProtectionDomain().getCodeSource(); |
| 98 | + if (src != null) { |
| 99 | + System.err.println("Loading PotionEffectType sources from " + src.getLocation()); |
| 100 | + } |
| 101 | + src = MinecraftServer.class.getProtectionDomain().getCodeSource(); |
| 102 | + if (src != null) { |
| 103 | + System.err.println("Loading MinecraftServer sources from " + src.getLocation()); |
| 104 | + } |
| 105 | + } |
| 106 | + |
87 | 107 | static ServerAdvancementManager advancementDataWorld = new ServerAdvancementManager(null);
|
88 | 108 |
|
89 | 109 | MinecraftServer minecraftServerMock = null;
|
90 | 110 | List<ServerPlayer> players = new ArrayList<>();
|
91 | 111 | PlayerList playerListMock;
|
92 | 112 | final RecipeManager recipeManager;
|
| 113 | + Map<ResourceLocation, CommandFunction> functions = new HashMap<>(); |
| 114 | + Map<ResourceLocation, Collection<CommandFunction>> tags = new HashMap<>(); |
93 | 115 |
|
94 | 116 | public MockNMS(CommandAPIBukkit<?> baseNMS) {
|
95 | 117 | super(baseNMS);
|
@@ -119,6 +141,7 @@ public MockNMS(CommandAPIBukkit<?> baseNMS) {
|
119 | 141 | registerDefaultEnchantments();
|
120 | 142 |
|
121 | 143 | this.recipeManager = new RecipeManager();
|
| 144 | + this.functions = new HashMap<>(); |
122 | 145 | registerDefaultRecipes();
|
123 | 146 | }
|
124 | 147 |
|
@@ -311,6 +334,11 @@ public CommandSourceStack getBrigadierSourceFromCommandSender(AbstractCommandSen
|
311 | 334 | // ChatArgument, AdventureChatArgument
|
312 | 335 | Mockito.when(css.hasPermission(anyInt())).thenAnswer(invocation -> sender.isOp());
|
313 | 336 | Mockito.when(css.hasPermission(anyInt(), anyString())).thenAnswer(invocation -> sender.isOp());
|
| 337 | + |
| 338 | + // FunctionArgument |
| 339 | + // We don't really need to do anything funky here, we'll just return the same CSS |
| 340 | + Mockito.when(css.withSuppressedOutput()).thenReturn(css); |
| 341 | + Mockito.when(css.withMaximumPermission(anyInt())).thenReturn(css); |
314 | 342 | }
|
315 | 343 | return css;
|
316 | 344 | }
|
@@ -434,9 +462,79 @@ public <T> T getMinecraftServer() {
|
434 | 462 | // RecipeArgument
|
435 | 463 | Mockito.when(minecraftServerMock.getRecipeManager()).thenAnswer(i -> this.recipeManager);
|
436 | 464 |
|
| 465 | + // FunctionArgument |
| 466 | + // We're using 2 as the function compilation level. |
| 467 | + Mockito.when(minecraftServerMock.getFunctionCompilationLevel()).thenReturn(2); |
| 468 | + Mockito.when(minecraftServerMock.getFunctions()).thenAnswer(i -> { |
| 469 | + ServerFunctionLibrary serverFunctionLibrary = Mockito.mock(ServerFunctionLibrary.class); |
| 470 | + |
| 471 | + // Functions |
| 472 | + Mockito.when(serverFunctionLibrary.getFunction(any())).thenAnswer(invocation -> Optional.ofNullable(functions.get(invocation.getArgument(0)))); |
| 473 | + Mockito.when(serverFunctionLibrary.getFunctions()).thenAnswer(invocation -> functions); |
| 474 | + |
| 475 | + // Tags |
| 476 | + Mockito.when(serverFunctionLibrary.getTag(any())).thenAnswer(invocation -> { |
| 477 | + Collection<CommandFunction> tagsFromResourceLocation = tags.getOrDefault(invocation.getArgument(0), List.of()); |
| 478 | + return Tag.fromSet(Set.copyOf(tagsFromResourceLocation)); |
| 479 | + }); |
| 480 | + Mockito.when(serverFunctionLibrary.getTags()).thenAnswer(invocation -> { |
| 481 | + Map<ResourceLocation, Tag<?>> tagMap = new HashMap<>(); |
| 482 | + for(Map.Entry<ResourceLocation, Collection<CommandFunction>> entry : tags.entrySet()) { |
| 483 | + tagMap.put(entry.getKey(), Tag.fromSet(Set.copyOf(entry.getValue()))); |
| 484 | + } |
| 485 | + return TagCollection.of((Map) tagMap); |
| 486 | + }); |
| 487 | + |
| 488 | + return new ServerFunctionManager(minecraftServerMock, serverFunctionLibrary) { |
| 489 | + |
| 490 | + // Make sure we don't use ServerFunctionManager#getDispatcher! |
| 491 | + // That method accesses MinecraftServer.vanillaCommandDispatcher |
| 492 | + // directly (boo) and that causes all sorts of nonsense. |
| 493 | + @Override |
| 494 | + public CommandDispatcher<CommandSourceStack> getDispatcher() { |
| 495 | + return Brigadier.getCommandDispatcher(); |
| 496 | + } |
| 497 | + }; |
| 498 | + }); |
| 499 | + |
| 500 | + Mockito.when(minecraftServerMock.getGameRules()).thenAnswer(i -> new GameRules()); |
| 501 | + Mockito.when(minecraftServerMock.getProfiler()).thenAnswer(i -> InactiveMetricsRecorder.INSTANCE.getProfiler()); |
| 502 | + |
437 | 503 | return (T) minecraftServerMock;
|
438 | 504 | }
|
439 | 505 |
|
| 506 | + @SuppressWarnings("unchecked") |
| 507 | + @Override |
| 508 | + public void addFunction(NamespacedKey key, List<String> commands) { |
| 509 | + if(Bukkit.getOnlinePlayers().isEmpty()) { |
| 510 | + throw new IllegalStateException("You need to have at least one player on the server to add a function"); |
| 511 | + } |
| 512 | + |
| 513 | + ResourceLocation resourceLocation = new ResourceLocation(key.toString()); |
| 514 | + CommandSourceStack css = getBrigadierSourceFromCommandSender(new BukkitPlayer(Bukkit.getOnlinePlayers().iterator().next())); |
| 515 | + |
| 516 | + // So for very interesting reasons, Brigadier.getCommandDispatcher() |
| 517 | + // gives a different result in this method than using getBrigadierDispatcher() |
| 518 | + this.functions.put(resourceLocation, CommandFunction.fromLines(resourceLocation, Brigadier.getCommandDispatcher(), css, commands)); |
| 519 | + } |
| 520 | + |
| 521 | + @SuppressWarnings("unchecked") |
| 522 | + @Override |
| 523 | + public void addTag(NamespacedKey key, List<List<String>> commands) { |
| 524 | + if(Bukkit.getOnlinePlayers().isEmpty()) { |
| 525 | + throw new IllegalStateException("You need to have at least one player on the server to add a function"); |
| 526 | + } |
| 527 | + |
| 528 | + ResourceLocation resourceLocation = new ResourceLocation(key.toString()); |
| 529 | + CommandSourceStack css = getBrigadierSourceFromCommandSender(new BukkitPlayer(Bukkit.getOnlinePlayers().iterator().next())); |
| 530 | + |
| 531 | + List<CommandFunction> tagFunctions = new ArrayList<>(); |
| 532 | + for(List<String> functionCommands : commands) { |
| 533 | + tagFunctions.add(CommandFunction.fromLines(resourceLocation, Brigadier.getCommandDispatcher(), css, functionCommands)); |
| 534 | + } |
| 535 | + this.tags.put(resourceLocation, tagFunctions); |
| 536 | + } |
| 537 | + |
440 | 538 | @Override
|
441 | 539 | public org.bukkit.advancement.Advancement addAdvancement(NamespacedKey key) {
|
442 | 540 | advancementDataWorld.advancements.advancements.put(new ResourceLocation(key.toString()),
|
|
0 commit comments