import java.nio.file.*; import java.util.*; import java.util.stream.Stream; import com.google.gson.*; import com.mojang.brigadier.StringReader; import net.minecraft.SharedConstants; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.item.ItemParser; import net.minecraft.core.*; import net.minecraft.core.registries.*; import net.minecraft.resources.*; import net.minecraft.server.*; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.repository.ServerPacksSource; import net.minecraft.server.packs.resources.MultiPackResourceManager; import net.minecraft.server.permissions.LevelBasedPermissionSet; import net.minecraft.tags.TagLoader; import net.minecraft.util.Util; import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.level.*; import org.bukkit.craftbukkit.CraftRegistry; /** Offline verification only: loads cached vanilla registries, never starts a server or sends commands. */ public class VerifyGear { public static void main(String[] args) throws Exception { SharedConstants.tryDetectVersion(); if (!SharedConstants.getCurrentVersion().name().equals("26.2")) throw new AssertionError("Expected Minecraft 26.2"); Bootstrap.bootStrap(); var flags = FeatureFlags.VANILLA_SET; var packs = ServerPacksSource.createVanillaTrustedRepository(); MinecraftServer.configurePackRepository(packs, new WorldDataConfiguration(new DataPackConfig( FeatureFlags.REGISTRY.toNames(flags).stream().map(Identifier::getPath).toList(), List.of()), flags), true, false); try (var resources = new MultiPackResourceManager(PackType.SERVER_DATA, packs.openAllSelected())) { LayeredRegistryAccess layers = RegistryLayer.createRegistryAccess(); List> tags = TagLoader.loadTagsForExistingRegistries(resources, layers.getLayer(RegistryLayer.STATIC)); List> lookups = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLDGEN), tags); RegistryAccess.Frozen worldgen = RegistryDataLoader.load(resources, lookups, RegistryDataLoader.WORLDGEN_REGISTRIES, Util.backgroundExecutor()).join(); layers = layers.replaceFrom(RegistryLayer.WORLDGEN, worldgen); RegistryAccess.Frozen dimensions = RegistryDataLoader.load(resources, Stream.concat(lookups.stream(), worldgen.listRegistries()).toList(), RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor()).join(); layers = layers.replaceFrom(RegistryLayer.DIMENSIONS, dimensions); Class.forName(org.bukkit.Registry.class.getName()); var datapack = ReloadableServerResources.loadResources(resources, layers, tags, flags, Commands.CommandSelection.DEDICATED, LevelBasedPermissionSet.ALL_PERMISSIONS, Util.backgroundExecutor(), Runnable::run).join(); datapack.updateComponentsAndStaticRegistryTags(); var registries = layers.compositeAccess().freeze(); CraftRegistry.setMinecraftRegistry(registries); var items = BuiltInRegistries.ITEM.keySet().stream().filter(id -> id.getNamespace().equals("minecraft") && (id.getPath().matches("(wooden|stone|copper|iron|golden|diamond|netherite)_(sword|axe|pickaxe|shovel|hoe|spear)") || id.getPath().matches("(leather|copper|chainmail|iron|golden|diamond|netherite)_(helmet|chestplate|leggings|boots)") || Set.of("bow", "crossbow", "trident", "mace", "fishing_rod", "shears", "shield", "turtle_helmet").contains(id.getPath()))) .sorted(Comparator.comparing(Identifier::toString)).toList(); var enchantments = registries.lookupOrThrow(Registries.ENCHANTMENT); var catalog = new JsonObject(); catalog.addProperty("version", "26.2"); catalog.addProperty("purpurBuild", 2618); var itemList = new JsonArray(); items.forEach(id -> itemList.add(id.toString())); catalog.add("items", itemList); var enchantmentList = new JsonArray(); enchantments.listElements().sorted(Comparator.comparing(h -> h.key().identifier().toString())).forEach(holder -> { var value = holder.value(); var entry = new JsonObject(); entry.addProperty("id", holder.key().identifier().toString()); entry.addProperty("maxLevel", value.getMaxLevel()); var supported = new JsonArray(); items.stream().filter(id -> value.isSupportedItem(new net.minecraft.world.item.ItemStack(BuiltInRegistries.ITEM.getValue(id)))).forEach(id -> supported.add(id.toString())); entry.add("items", supported); var conflicts = new JsonArray(); enchantments.listElements().filter(other -> !Enchantment.areCompatible(holder, other)).map(h -> h.key().identifier().toString()).sorted().forEach(conflicts::add); entry.add("conflicts", conflicts); enchantmentList.add(entry); }); catalog.add("enchantments", enchantmentList); Files.writeString(Path.of(args[0]), new GsonBuilder().setPrettyPrinting().create().toJson(catalog) + "\n"); if (args.length > 1) { var parser = new ItemParser(registries); var wrapper = new org.bukkit.craftbukkit.command.VanillaCommandWrapper(datapack.getCommands().getDispatcher().getRoot().getChild("give")); var toDispatcher = wrapper.getClass().getDeclaredMethod("toDispatcher", String[].class, String.class); toDispatcher.setAccessible(true); var cases = JsonParser.parseString(Files.readString(Path.of(args[1]))).getAsJsonArray(); for (var element : cases) { var test = element.getAsJsonObject(); var command = test.get("command").getAsString(); boolean valid = false; try { // Bukkit maps minecraft:give to this vanilla wrapper; use its real argument // reconstruction rather than inventing the command dispatched to Brigadier. if (!command.startsWith("minecraft:give ")) throw new AssertionError("Expected literal minecraft:give"); var arguments = command.substring("minecraft:give ".length()).split(" "); var dispatched = (String) toDispatcher.invoke(wrapper, arguments, wrapper.getName()); var reader = new StringReader(dispatched); var parsed = datapack.getCommands().getDispatcher().parse(reader, Commands.createCompilationContext(LevelBasedPermissionSet.ALL_PERMISSIONS)); Commands.validateParseResults(parsed); if (parsed.getContext().getCommand() == null || parsed.getReader().canRead()) throw new AssertionError("Incomplete give parse"); // Decode components into an actual ItemStack, not just a syntactic SNBT parse. var itemReader = new StringReader(command.substring(command.indexOf(' ', command.indexOf(' ') + 1) + 1)); var item = parser.parse(itemReader).createItemStack(1); if (item.getCount() != 1) throw new AssertionError("Count mismatch"); if (test.has("name") && !item.getHoverName().getString().equals(test.get("name").getAsString())) throw new AssertionError("Plain text name mismatch"); if (test.has("lore")) { var lore = item.get(net.minecraft.core.component.DataComponents.LORE); var actual = new JsonArray(); if (lore != null) lore.lines().forEach(line -> actual.add(line.getString())); if (!actual.equals(test.get("lore"))) throw new AssertionError("Lore mismatch: " + actual); } if (test.has("enchantments")) { var actual = new JsonObject(); item.getEnchantments().entrySet().forEach(e -> actual.addProperty(e.getKey().unwrapKey().orElseThrow().identifier().toString(), e.getIntValue())); if (!actual.equals(test.get("enchantments"))) throw new AssertionError("Enchantment mismatch: " + actual); } valid = true; } catch (com.mojang.brigadier.exceptions.CommandSyntaxException expected) { /* invalid fixture */ } if (valid != test.get("valid").getAsBoolean()) throw new AssertionError("Unexpected grammar result: " + command); } System.out.println("Verified " + cases.size() + " give grammar/component cases against Minecraft 26.2 / Purpur 2618"); } } System.exit(0); } }