diff --git a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/DynamicTestProvider.java b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/DynamicTestProvider.java new file mode 100644 index 0000000..de519bc --- /dev/null +++ b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/DynamicTestProvider.java @@ -0,0 +1,7 @@ +package org.patchbukkit.testplugin; + +import java.util.List; + +public interface DynamicTestProvider { + List runDynamicTests(); +} diff --git a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/PatchBukkitTestPlugin.java b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/PatchBukkitTestPlugin.java index 0dd6660..1ec56a8 100644 --- a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/PatchBukkitTestPlugin.java +++ b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/PatchBukkitTestPlugin.java @@ -22,6 +22,7 @@ public void onEnable() { framework.registerSuite(new ConsoleSenderTests()); framework.registerSuite(new UnsafeValuesTests()); framework.registerSuite(new StubTests()); + framework.registerSuite(new LegacyMaterialTests()); // Set executor on the PluginCommand created by PatchBukkit's Rust side PbTestCommand cmd = new PbTestCommand(framework); diff --git a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestCategory.java b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestCategory.java index 5c42f91..3b644e9 100644 --- a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestCategory.java +++ b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestCategory.java @@ -10,5 +10,6 @@ public enum TestCategory { ENTITY, CONSOLE_SENDER, UNSAFE_VALUES, - STUBS + STUBS, + LEGACY_MATERIALS } diff --git a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestFramework.java b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestFramework.java index 3eb847e..b255550 100644 --- a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestFramework.java +++ b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/TestFramework.java @@ -40,16 +40,9 @@ public List runAll() { } public List runCategory(TestCategory category) { - List results = new ArrayList<>(); - for (Object suite : suites) { - for (Method method : suite.getClass().getDeclaredMethods()) { - ConformanceTest ann = method.getAnnotation(ConformanceTest.class); - if (ann != null && ann.category() == category) { - results.add(runTest(suite, method, ann)); - } - } - } - return results; + return runAll().stream() + .filter(r -> r.category() == category) + .toList(); } private List runSuite(Object suite) { @@ -60,6 +53,9 @@ private List runSuite(Object suite) { results.add(runTest(suite, method, ann)); } } + if (suite instanceof DynamicTestProvider provider) { + results.addAll(provider.runDynamicTests()); + } return results; } diff --git a/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/tests/LegacyMaterialTests.java b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/tests/LegacyMaterialTests.java new file mode 100644 index 0000000..5f62d1d --- /dev/null +++ b/java/patchbukkit-test-plugin/src/main/java/org/patchbukkit/testplugin/tests/LegacyMaterialTests.java @@ -0,0 +1,58 @@ +package org.patchbukkit.testplugin.tests; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.material.MaterialData; +import org.patchbukkit.testplugin.DynamicTestProvider; +import org.patchbukkit.testplugin.TestCategory; +import org.patchbukkit.testplugin.TestExpectation; +import org.patchbukkit.testplugin.TestResult; + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("deprecation") +public final class LegacyMaterialTests implements DynamicTestProvider { + + @Override + public List runDynamicTests() { + List results = new ArrayList<>(); + + for (Material mat : Material.values()) { + if (!mat.isLegacy()) continue; + if (mat == Material.LEGACY_AIR) continue; + + String name = mat.name(); + try { + Material result = Bukkit.getUnsafe().fromLegacy(new MaterialData(mat, (byte) 0)); + if (result != null && result != Material.AIR) { + results.add(new TestResult( + name + " -> " + result.name(), + TestCategory.LEGACY_MATERIALS, + TestExpectation.SHOULD_WORK, + true, + null + )); + } else { + results.add(new TestResult( + name + " -> " + result, + TestCategory.LEGACY_MATERIALS, + TestExpectation.SHOULD_WORK, + false, + "Converted to " + result + " (expected non-AIR)" + )); + } + } catch (Exception e) { + results.add(new TestResult( + name + " -> ERROR", + TestCategory.LEGACY_MATERIALS, + TestExpectation.SHOULD_WORK, + false, + e.getClass().getSimpleName() + ": " + e.getMessage() + )); + } + } + + return results; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java index 3e0b0f2..18fb80e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitLegacy.java @@ -3,10 +3,350 @@ import org.bukkit.Material; import org.bukkit.material.MaterialData; +import java.util.HashMap; +import java.util.Map; + @SuppressWarnings({ "deprecation", "removal" }) public final class PatchBukkitLegacy { private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(PatchBukkitLegacy.class); + private static final String[] COLORS = { + "WHITE", "ORANGE", "MAGENTA", "LIGHT_BLUE", "YELLOW", "LIME", "PINK", + "GRAY", "LIGHT_GRAY", "CYAN", "PURPLE", "BLUE", "BROWN", "GREEN", "RED", "BLACK" + }; + + // Banner data values use inverted color order (0=BLACK, 15=WHITE) + private static final String[] BANNER_COLORS = { + "BLACK", "RED", "GREEN", "BROWN", "BLUE", "PURPLE", "CYAN", "LIGHT_GRAY", + "GRAY", "PINK", "LIME", "YELLOW", "LIGHT_BLUE", "MAGENTA", "ORANGE", "WHITE" + }; + + // Data-value dependent mappings: legacy name -> array of modern names indexed by data value + private static final Map DATA_VALUE_MAP = new HashMap<>(); + + // Simple 1:1 rename mappings: legacy name (without LEGACY_ prefix) -> modern name + private static final Map RENAME_MAP = new HashMap<>(); + + static { + initDataValueMap(); + initRenameMap(); + } + + private static String[] withSuffix(String[] prefixes, String suffix) { + String[] result = new String[prefixes.length]; + for (int i = 0; i < prefixes.length; i++) { + result[i] = prefixes[i] + "_" + suffix; + } + return result; + } + + private static void initDataValueMap() { + // 16-color materials + DATA_VALUE_MAP.put("WOOL", withSuffix(COLORS, "WOOL")); + DATA_VALUE_MAP.put("STAINED_GLASS", withSuffix(COLORS, "STAINED_GLASS")); + DATA_VALUE_MAP.put("STAINED_GLASS_PANE", withSuffix(COLORS, "STAINED_GLASS_PANE")); + DATA_VALUE_MAP.put("STAINED_CLAY", withSuffix(COLORS, "TERRACOTTA")); + DATA_VALUE_MAP.put("CARPET", withSuffix(COLORS, "CARPET")); + DATA_VALUE_MAP.put("CONCRETE", withSuffix(COLORS, "CONCRETE")); + DATA_VALUE_MAP.put("CONCRETE_POWDER", withSuffix(COLORS, "CONCRETE_POWDER")); + DATA_VALUE_MAP.put("BED", withSuffix(COLORS, "BED")); + DATA_VALUE_MAP.put("BED_BLOCK", withSuffix(COLORS, "BED")); + DATA_VALUE_MAP.put("BANNER", withSuffix(BANNER_COLORS, "BANNER")); + DATA_VALUE_MAP.put("STANDING_BANNER", withSuffix(BANNER_COLORS, "BANNER")); + DATA_VALUE_MAP.put("WALL_BANNER", withSuffix(BANNER_COLORS, "WALL_BANNER")); + + // Wood types (LOG/LEAVES use data % 4 to strip axis/decay bits) + DATA_VALUE_MAP.put("WOOD", new String[]{ + "OAK_PLANKS", "SPRUCE_PLANKS", "BIRCH_PLANKS", + "JUNGLE_PLANKS", "ACACIA_PLANKS", "DARK_OAK_PLANKS" + }); + DATA_VALUE_MAP.put("LOG", new String[]{ + "OAK_LOG", "SPRUCE_LOG", "BIRCH_LOG", "JUNGLE_LOG" + }); + DATA_VALUE_MAP.put("LOG_2", new String[]{"ACACIA_LOG", "DARK_OAK_LOG"}); + DATA_VALUE_MAP.put("LEAVES", new String[]{ + "OAK_LEAVES", "SPRUCE_LEAVES", "BIRCH_LEAVES", "JUNGLE_LEAVES" + }); + DATA_VALUE_MAP.put("LEAVES_2", new String[]{"ACACIA_LEAVES", "DARK_OAK_LEAVES"}); + DATA_VALUE_MAP.put("SAPLING", new String[]{ + "OAK_SAPLING", "SPRUCE_SAPLING", "BIRCH_SAPLING", + "JUNGLE_SAPLING", "ACACIA_SAPLING", "DARK_OAK_SAPLING" + }); + // Wood slabs: 8-entry array so data % 8 strips upper/lower bit + String[] woodSlabs = { + "OAK_SLAB", "SPRUCE_SLAB", "BIRCH_SLAB", "JUNGLE_SLAB", + "ACACIA_SLAB", "DARK_OAK_SLAB", "OAK_SLAB", "OAK_SLAB" + }; + DATA_VALUE_MAP.put("WOOD_STEP", woodSlabs); + DATA_VALUE_MAP.put("WOOD_DOUBLE_STEP", woodSlabs); + + // Stone variants + DATA_VALUE_MAP.put("STONE", new String[]{ + "STONE", "GRANITE", "POLISHED_GRANITE", "DIORITE", + "POLISHED_DIORITE", "ANDESITE", "POLISHED_ANDESITE" + }); + DATA_VALUE_MAP.put("DIRT", new String[]{"DIRT", "COARSE_DIRT", "PODZOL"}); + DATA_VALUE_MAP.put("SAND", new String[]{"SAND", "RED_SAND"}); + DATA_VALUE_MAP.put("SANDSTONE", new String[]{ + "SANDSTONE", "CHISELED_SANDSTONE", "CUT_SANDSTONE" + }); + DATA_VALUE_MAP.put("RED_SANDSTONE", new String[]{ + "RED_SANDSTONE", "CHISELED_RED_SANDSTONE", "CUT_RED_SANDSTONE" + }); + DATA_VALUE_MAP.put("SMOOTH_BRICK", new String[]{ + "STONE_BRICKS", "MOSSY_STONE_BRICKS", + "CRACKED_STONE_BRICKS", "CHISELED_STONE_BRICKS" + }); + DATA_VALUE_MAP.put("PRISMARINE", new String[]{ + "PRISMARINE", "PRISMARINE_BRICKS", "DARK_PRISMARINE" + }); + DATA_VALUE_MAP.put("COBBLE_WALL", new String[]{ + "COBBLESTONE_WALL", "MOSSY_COBBLESTONE_WALL" + }); + // Quartz: 5-entry array so data 3,4 (pillar facing) still resolve to QUARTZ_PILLAR + DATA_VALUE_MAP.put("QUARTZ_BLOCK", new String[]{ + "QUARTZ_BLOCK", "CHISELED_QUARTZ_BLOCK", + "QUARTZ_PILLAR", "QUARTZ_PILLAR", "QUARTZ_PILLAR" + }); + // Anvil: 12-entry array; damage = data/4, facing = data%4 + DATA_VALUE_MAP.put("ANVIL", new String[]{ + "ANVIL", "ANVIL", "ANVIL", "ANVIL", + "CHIPPED_ANVIL", "CHIPPED_ANVIL", "CHIPPED_ANVIL", "CHIPPED_ANVIL", + "DAMAGED_ANVIL", "DAMAGED_ANVIL", "DAMAGED_ANVIL", "DAMAGED_ANVIL" + }); + DATA_VALUE_MAP.put("SPONGE", new String[]{"SPONGE", "WET_SPONGE"}); + + // Stone slabs (data % 8 strips upper/lower bit) + String[] stoneSlabs = { + "STONE_SLAB", "SANDSTONE_SLAB", "PETRIFIED_OAK_SLAB", + "COBBLESTONE_SLAB", "BRICK_SLAB", "STONE_BRICK_SLAB", + "NETHER_BRICK_SLAB", "QUARTZ_SLAB" + }; + DATA_VALUE_MAP.put("STEP", stoneSlabs); + DATA_VALUE_MAP.put("DOUBLE_STEP", stoneSlabs); + + // Silverfish blocks + DATA_VALUE_MAP.put("MONSTER_EGGS", new String[]{ + "INFESTED_STONE", "INFESTED_COBBLESTONE", "INFESTED_STONE_BRICKS", + "INFESTED_MOSSY_STONE_BRICKS", "INFESTED_CRACKED_STONE_BRICKS", + "INFESTED_CHISELED_STONE_BRICKS" + }); + + // Plants + DATA_VALUE_MAP.put("LONG_GRASS", new String[]{"DEAD_BUSH", "SHORT_GRASS", "FERN"}); + DATA_VALUE_MAP.put("RED_ROSE", new String[]{ + "POPPY", "BLUE_ORCHID", "ALLIUM", "AZURE_BLUET", + "RED_TULIP", "ORANGE_TULIP", "WHITE_TULIP", "PINK_TULIP", "OXEYE_DAISY" + }); + DATA_VALUE_MAP.put("DOUBLE_PLANT", new String[]{ + "SUNFLOWER", "LILAC", "TALL_GRASS", "LARGE_FERN", "ROSE_BUSH", "PEONY" + }); + + // Items with data variants + DATA_VALUE_MAP.put("INK_SACK", new String[]{ + "INK_SAC", "RED_DYE", "GREEN_DYE", "COCOA_BEANS", + "LAPIS_LAZULI", "PURPLE_DYE", "CYAN_DYE", "LIGHT_GRAY_DYE", + "GRAY_DYE", "PINK_DYE", "LIME_DYE", "YELLOW_DYE", + "LIGHT_BLUE_DYE", "MAGENTA_DYE", "ORANGE_DYE", "BONE_MEAL" + }); + DATA_VALUE_MAP.put("RAW_FISH", new String[]{ + "COD", "SALMON", "TROPICAL_FISH", "PUFFERFISH" + }); + DATA_VALUE_MAP.put("COOKED_FISH", new String[]{"COOKED_COD", "COOKED_SALMON"}); + DATA_VALUE_MAP.put("COAL", new String[]{"COAL", "CHARCOAL"}); + DATA_VALUE_MAP.put("GOLDEN_APPLE", new String[]{ + "GOLDEN_APPLE", "ENCHANTED_GOLDEN_APPLE" + }); + String[] skulls = { + "SKELETON_SKULL", "WITHER_SKELETON_SKULL", "ZOMBIE_HEAD", + "PLAYER_HEAD", "CREEPER_HEAD", "DRAGON_HEAD" + }; + DATA_VALUE_MAP.put("SKULL_ITEM", skulls); + DATA_VALUE_MAP.put("SKULL", skulls); + } + + private static void initRenameMap() { + // GOLD_* -> GOLDEN_* + RENAME_MAP.put("GOLD_SWORD", "GOLDEN_SWORD"); + RENAME_MAP.put("GOLD_PICKAXE", "GOLDEN_PICKAXE"); + RENAME_MAP.put("GOLD_AXE", "GOLDEN_AXE"); + RENAME_MAP.put("GOLD_SPADE", "GOLDEN_SHOVEL"); + RENAME_MAP.put("GOLD_HOE", "GOLDEN_HOE"); + RENAME_MAP.put("GOLD_HELMET", "GOLDEN_HELMET"); + RENAME_MAP.put("GOLD_CHESTPLATE", "GOLDEN_CHESTPLATE"); + RENAME_MAP.put("GOLD_LEGGINGS", "GOLDEN_LEGGINGS"); + RENAME_MAP.put("GOLD_BOOTS", "GOLDEN_BOOTS"); + RENAME_MAP.put("GOLD_BARDING", "GOLDEN_HORSE_ARMOR"); + RENAME_MAP.put("GOLD_PLATE", "LIGHT_WEIGHTED_PRESSURE_PLATE"); + RENAME_MAP.put("GOLD_RECORD", "MUSIC_DISC_13"); + + // WOOD_* -> WOODEN_* + RENAME_MAP.put("WOOD_SWORD", "WOODEN_SWORD"); + RENAME_MAP.put("WOOD_PICKAXE", "WOODEN_PICKAXE"); + RENAME_MAP.put("WOOD_AXE", "WOODEN_AXE"); + RENAME_MAP.put("WOOD_SPADE", "WOODEN_SHOVEL"); + RENAME_MAP.put("WOOD_HOE", "WOODEN_HOE"); + RENAME_MAP.put("WOOD_PLATE", "OAK_PRESSURE_PLATE"); + RENAME_MAP.put("WOOD_BUTTON", "OAK_BUTTON"); + RENAME_MAP.put("WOOD_DOOR", "OAK_DOOR"); + + // *_SPADE -> *_SHOVEL + RENAME_MAP.put("DIAMOND_SPADE", "DIAMOND_SHOVEL"); + RENAME_MAP.put("IRON_SPADE", "IRON_SHOVEL"); + RENAME_MAP.put("STONE_SPADE", "STONE_SHOVEL"); + + // Block renames + RENAME_MAP.put("GRASS", "GRASS_BLOCK"); + RENAME_MAP.put("WEB", "COBWEB"); + RENAME_MAP.put("WORKBENCH", "CRAFTING_TABLE"); + RENAME_MAP.put("SOIL", "FARMLAND"); + RENAME_MAP.put("MOB_SPAWNER", "SPAWNER"); + RENAME_MAP.put("THIN_GLASS", "GLASS_PANE"); + RENAME_MAP.put("IRON_FENCE", "IRON_BARS"); + RENAME_MAP.put("NETHER_FENCE", "NETHER_BRICK_FENCE"); + RENAME_MAP.put("FENCE", "OAK_FENCE"); + RENAME_MAP.put("FENCE_GATE", "OAK_FENCE_GATE"); + RENAME_MAP.put("TRAP_DOOR", "OAK_TRAPDOOR"); + RENAME_MAP.put("HARD_CLAY", "TERRACOTTA"); + RENAME_MAP.put("STONE_PLATE", "STONE_PRESSURE_PLATE"); + RENAME_MAP.put("IRON_PLATE", "HEAVY_WEIGHTED_PRESSURE_PLATE"); + RENAME_MAP.put("BURNING_FURNACE", "FURNACE"); + RENAME_MAP.put("ENCHANTMENT_TABLE", "ENCHANTING_TABLE"); + RENAME_MAP.put("ENDER_PORTAL", "END_PORTAL"); + RENAME_MAP.put("ENDER_PORTAL_FRAME", "END_PORTAL_FRAME"); + RENAME_MAP.put("ENDER_STONE", "END_STONE"); + RENAME_MAP.put("END_BRICKS", "END_STONE_BRICKS"); + RENAME_MAP.put("MELON_BLOCK", "MELON"); + RENAME_MAP.put("SMOOTH_STAIRS", "SANDSTONE_STAIRS"); + RENAME_MAP.put("WOOD_STAIRS", "OAK_STAIRS"); + RENAME_MAP.put("WOODEN_DOOR", "OAK_DOOR"); + RENAME_MAP.put("SIGN_POST", "OAK_SIGN"); + RENAME_MAP.put("SIGN", "OAK_SIGN"); + RENAME_MAP.put("WALL_SIGN", "OAK_WALL_SIGN"); + RENAME_MAP.put("SUGAR_CANE_BLOCK", "SUGAR_CANE"); + RENAME_MAP.put("PISTON_BASE", "PISTON"); + RENAME_MAP.put("PISTON_STICKY_BASE", "STICKY_PISTON"); + RENAME_MAP.put("REDSTONE_LAMP_ON", "REDSTONE_LAMP"); + RENAME_MAP.put("REDSTONE_LAMP_OFF", "REDSTONE_LAMP"); + RENAME_MAP.put("REDSTONE_TORCH_ON", "REDSTONE_TORCH"); + RENAME_MAP.put("REDSTONE_TORCH_OFF", "REDSTONE_TORCH"); + RENAME_MAP.put("DIODE", "REPEATER"); + RENAME_MAP.put("DIODE_BLOCK_ON", "REPEATER"); + RENAME_MAP.put("DIODE_BLOCK_OFF", "REPEATER"); + RENAME_MAP.put("REDSTONE_COMPARATOR", "COMPARATOR"); + RENAME_MAP.put("REDSTONE_COMPARATOR_ON", "COMPARATOR"); + RENAME_MAP.put("REDSTONE_COMPARATOR_OFF", "COMPARATOR"); + RENAME_MAP.put("DAYLIGHT_DETECTOR_INVERTED", "DAYLIGHT_DETECTOR"); + RENAME_MAP.put("COMMAND", "COMMAND_BLOCK"); + RENAME_MAP.put("COMMAND_CHAIN", "CHAIN_COMMAND_BLOCK"); + RENAME_MAP.put("COMMAND_REPEATING", "REPEATING_COMMAND_BLOCK"); + RENAME_MAP.put("YELLOW_FLOWER", "DANDELION"); + RENAME_MAP.put("BRICK", "BRICKS"); + RENAME_MAP.put("NETHER_BRICK", "NETHER_BRICKS"); + RENAME_MAP.put("NETHER_BRICK_ITEM", "NETHER_BRICK"); + RENAME_MAP.put("CLAY_BRICK", "BRICK"); + RENAME_MAP.put("STATIONARY_WATER", "WATER"); + RENAME_MAP.put("STATIONARY_LAVA", "LAVA"); + RENAME_MAP.put("GLOWING_REDSTONE_ORE", "REDSTONE_ORE"); + RENAME_MAP.put("HUGE_MUSHROOM_1", "BROWN_MUSHROOM_BLOCK"); + RENAME_MAP.put("HUGE_MUSHROOM_2", "RED_MUSHROOM_BLOCK"); + RENAME_MAP.put("CAKE_BLOCK", "CAKE"); + RENAME_MAP.put("CROPS", "WHEAT"); + RENAME_MAP.put("POTATO", "POTATOES"); + RENAME_MAP.put("POTATO_ITEM", "POTATO"); + RENAME_MAP.put("CARROT", "CARROTS"); + RENAME_MAP.put("CARROT_ITEM", "CARROT"); + RENAME_MAP.put("BEETROOT_BLOCK", "BEETROOTS"); + RENAME_MAP.put("GRASS_PATH", "DIRT_PATH"); + RENAME_MAP.put("PISTON_EXTENSION", "PISTON_HEAD"); + RENAME_MAP.put("PISTON_MOVING_PIECE", "MOVING_PISTON"); + RENAME_MAP.put("IRON_DOOR_BLOCK", "IRON_DOOR"); + RENAME_MAP.put("RAILS", "RAIL"); + RENAME_MAP.put("PORTAL", "NETHER_PORTAL"); + RENAME_MAP.put("MYCEL", "MYCELIUM"); + RENAME_MAP.put("WATER_LILY", "LILY_PAD"); + RENAME_MAP.put("NETHER_WARTS", "NETHER_WART"); + RENAME_MAP.put("SPRUCE_WOOD_STAIRS", "SPRUCE_STAIRS"); + RENAME_MAP.put("BIRCH_WOOD_STAIRS", "BIRCH_STAIRS"); + RENAME_MAP.put("JUNGLE_WOOD_STAIRS", "JUNGLE_STAIRS"); + RENAME_MAP.put("MAGMA", "MAGMA_BLOCK"); + RENAME_MAP.put("RED_NETHER_BRICK", "RED_NETHER_BRICKS"); + RENAME_MAP.put("QUARTZ_ORE", "NETHER_QUARTZ_ORE"); + RENAME_MAP.put("DOUBLE_STONE_SLAB2", "RED_SANDSTONE_SLAB"); + RENAME_MAP.put("STONE_SLAB2", "RED_SANDSTONE_SLAB"); + RENAME_MAP.put("PURPUR_DOUBLE_SLAB", "PURPUR_SLAB"); + RENAME_MAP.put("SILVER_SHULKER_BOX", "LIGHT_GRAY_SHULKER_BOX"); + RENAME_MAP.put("SILVER_GLAZED_TERRACOTTA", "LIGHT_GRAY_GLAZED_TERRACOTTA"); + + // Item renames + RENAME_MAP.put("SULPHUR", "GUNPOWDER"); + RENAME_MAP.put("WATCH", "CLOCK"); + RENAME_MAP.put("LEASH", "LEAD"); + RENAME_MAP.put("FIREWORK", "FIREWORK_ROCKET"); + RENAME_MAP.put("FIREWORK_CHARGE", "FIREWORK_STAR"); + RENAME_MAP.put("BOOK_AND_QUILL", "WRITABLE_BOOK"); + RENAME_MAP.put("SNOW_BALL", "SNOWBALL"); + RENAME_MAP.put("EXP_BOTTLE", "EXPERIENCE_BOTTLE"); + RENAME_MAP.put("EMPTY_MAP", "MAP"); + RENAME_MAP.put("MELON", "MELON_SLICE"); + RENAME_MAP.put("SPECKLED_MELON", "GLISTERING_MELON_SLICE"); + RENAME_MAP.put("RAW_BEEF", "BEEF"); + RENAME_MAP.put("RAW_CHICKEN", "CHICKEN"); + RENAME_MAP.put("GRILLED_PORK", "COOKED_PORKCHOP"); + RENAME_MAP.put("PORK", "PORKCHOP"); + RENAME_MAP.put("MUSHROOM_SOUP", "MUSHROOM_STEW"); + RENAME_MAP.put("NETHER_STALK", "NETHER_WART"); + RENAME_MAP.put("SEEDS", "WHEAT_SEEDS"); + RENAME_MAP.put("TOTEM", "TOTEM_OF_UNDYING"); + RENAME_MAP.put("CHORUS_FRUIT_POPPED", "POPPED_CHORUS_FRUIT"); + RENAME_MAP.put("FLOWER_POT_ITEM", "FLOWER_POT"); + RENAME_MAP.put("BREWING_STAND_ITEM", "BREWING_STAND"); + RENAME_MAP.put("CAULDRON_ITEM", "CAULDRON"); + RENAME_MAP.put("EYE_OF_ENDER", "ENDER_EYE"); + RENAME_MAP.put("FIREBALL", "FIRE_CHARGE"); + RENAME_MAP.put("CARROT_STICK", "CARROT_ON_A_STICK"); + RENAME_MAP.put("DRAGONS_BREATH", "DRAGON_BREATH"); + RENAME_MAP.put("MONSTER_EGG", "PIG_SPAWN_EGG"); + + // Minecarts + RENAME_MAP.put("STORAGE_MINECART", "CHEST_MINECART"); + RENAME_MAP.put("POWERED_MINECART", "FURNACE_MINECART"); + RENAME_MAP.put("EXPLOSIVE_MINECART", "TNT_MINECART"); + RENAME_MAP.put("COMMAND_MINECART", "COMMAND_BLOCK_MINECART"); + + // Boats + RENAME_MAP.put("BOAT", "OAK_BOAT"); + RENAME_MAP.put("BOAT_SPRUCE", "SPRUCE_BOAT"); + RENAME_MAP.put("BOAT_BIRCH", "BIRCH_BOAT"); + RENAME_MAP.put("BOAT_JUNGLE", "JUNGLE_BOAT"); + RENAME_MAP.put("BOAT_ACACIA", "ACACIA_BOAT"); + RENAME_MAP.put("BOAT_DARK_OAK", "DARK_OAK_BOAT"); + + // Horse armor + RENAME_MAP.put("IRON_BARDING", "IRON_HORSE_ARMOR"); + RENAME_MAP.put("DIAMOND_BARDING", "DIAMOND_HORSE_ARMOR"); + + // Door items + RENAME_MAP.put("SPRUCE_DOOR_ITEM", "SPRUCE_DOOR"); + RENAME_MAP.put("BIRCH_DOOR_ITEM", "BIRCH_DOOR"); + RENAME_MAP.put("JUNGLE_DOOR_ITEM", "JUNGLE_DOOR"); + RENAME_MAP.put("ACACIA_DOOR_ITEM", "ACACIA_DOOR"); + RENAME_MAP.put("DARK_OAK_DOOR_ITEM", "DARK_OAK_DOOR"); + + // Music discs + RENAME_MAP.put("GREEN_RECORD", "MUSIC_DISC_CAT"); + RENAME_MAP.put("RECORD_3", "MUSIC_DISC_BLOCKS"); + RENAME_MAP.put("RECORD_4", "MUSIC_DISC_CHIRP"); + RENAME_MAP.put("RECORD_5", "MUSIC_DISC_FAR"); + RENAME_MAP.put("RECORD_6", "MUSIC_DISC_MALL"); + RENAME_MAP.put("RECORD_7", "MUSIC_DISC_MELLOHI"); + RENAME_MAP.put("RECORD_8", "MUSIC_DISC_STAL"); + RENAME_MAP.put("RECORD_9", "MUSIC_DISC_STRAD"); + RENAME_MAP.put("RECORD_10", "MUSIC_DISC_WARD"); + RENAME_MAP.put("RECORD_11", "MUSIC_DISC_11"); + RENAME_MAP.put("RECORD_12", "MUSIC_DISC_WAIT"); + } + public static Material fromLegacy(Material material) { if (material == null || !material.isLegacy()) { return material; @@ -25,6 +365,37 @@ public static Material fromLegacy(MaterialData materialData, boolean itemPriorit return material; } - throw new UnsupportedOperationException("Cannot convert from legacy to new Material"); + String legacyName = material.name(); + String name = legacyName.startsWith("LEGACY_") ? legacyName.substring(7) : legacyName; + int data = materialData.getData() & 0xFF; + + // Tier 1: Data-value dependent lookup + String[] dataMap = DATA_VALUE_MAP.get(name); + if (dataMap != null) { + int index = data % dataMap.length; + Material result = Material.getMaterial(dataMap[index]); + if (result != null) { + return result; + } + } + + // Tier 2: Simple rename lookup + String renamed = RENAME_MAP.get(name); + if (renamed != null) { + Material result = Material.getMaterial(renamed); + if (result != null) { + return result; + } + } + + // Tier 3: Direct name match (handles ~275 materials like DIAMOND -> DIAMOND) + Material direct = Material.getMaterial(name); + if (direct != null) { + return direct; + } + + // Fallback: log warning and return AIR + LOGGER.warn("Unknown legacy material: {} (data={}), returning AIR", legacyName, data); + return Material.AIR; } } diff --git a/proto/patchbukkit/itemstack.proto b/proto/patchbukkit/itemstack.proto index 6e9670a..75429d3 100644 --- a/proto/patchbukkit/itemstack.proto +++ b/proto/patchbukkit/itemstack.proto @@ -6,6 +6,7 @@ import "patchbukkit/common/types.proto"; option java_multiple_files = true; option java_package = "patchbukkit.itemstack"; +option java_outer_classname = "ItemStackProto"; // message GetPatchBukkitConfigResponse { // string minimum_supported_plugin_api = 1; diff --git a/rust/Cargo.lock b/rust/Cargo.lock index abb3802..bf1c831 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -25,7 +25,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -133,9 +133,9 @@ checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] name = "async-compression" -version = "0.4.39" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68650b7df54f0293fd061972a0fb05aaf4fc0879d3b3d21a638a182c5c543b9f" +checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" dependencies = [ "compression-codecs", "compression-core", @@ -208,9 +208,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -307,12 +307,12 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chacha20" -version = "0.10.0-rc.10" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c536927023d1c432e6e23a25ef45f6756094eac2ab460db5fb17a772acdfd312" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.3.0", "rand_core 0.10.0", ] @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" dependencies = [ "compression-core", "flate2", @@ -448,6 +448,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.3.0" @@ -540,9 +549,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "3.0.4" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86db11309bffee9435040d648c13c3efbdbcdcd3ead9872e65ce9dff4c3f79ce" +checksum = "3fb12e9c05ae4854f743f0acec2f817148ba59a902484f6aa298d4fc7df2fac4" dependencies = [ "crossbeam-utils", "futures-core", @@ -683,9 +692,9 @@ dependencies = [ [[package]] name = "der" -version = "0.8.0-rc.10" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c1d73e9668ea6b6a28172aa55f3ebec38507131ce179051c8033b5c6037653" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" dependencies = [ "const-oid 0.10.2", "pem-rfc7468 1.0.0", @@ -1132,9 +1141,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.0-rc.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f70a332ddf75e5e5e43284304179ba02f391f82f692f030b08a8378adf3c99" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" dependencies = [ "cfg-if", "libc", @@ -1903,14 +1912,13 @@ dependencies = [ "pumpkin-data", "pumpkin-protocol", "pumpkin-util", - "pumpkin-world", - "rand", + "rand 0.10.0 (git+https://github.com/rust-random/rand)", "rust-embed", "serde", "serde-saphyr", "serde_json", "tokio", - "toml 1.0.2+spec-1.1.0", + "toml", "tracing", "uuid", "walkdir", @@ -2023,7 +2031,7 @@ version = "0.8.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" dependencies = [ - "der 0.8.0-rc.10", + "der 0.8.0", "spki 0.8.0-rc.4", ] @@ -2039,11 +2047,11 @@ dependencies = [ [[package]] name = "pkcs8" -version = "0.11.0-rc.10" +version = "0.11.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b226d2cc389763951db8869584fd800cbbe2962bf454e2edeb5172b31ee99774" +checksum = "12922b6296c06eb741b02d7b5161e3aaa22864af38dfa025a1a3ba3f68c84577" dependencies = [ - "der 0.8.0-rc.10", + "der 0.8.0", "spki 0.8.0-rc.4", ] @@ -2193,7 +2201,7 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "arc-swap", "base64", @@ -2204,7 +2212,7 @@ dependencies = [ "hmac 0.13.0-rc.5", "libloading 0.9.0", "num-bigint", - "pkcs8 0.11.0-rc.10", + "pkcs8 0.11.0-rc.11", "pumpkin-config", "pumpkin-data", "pumpkin-inventory", @@ -2213,7 +2221,7 @@ dependencies = [ "pumpkin-protocol", "pumpkin-util", "pumpkin-world", - "rand", + "rand 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "rsa", "rustc-hash", "rustyline", @@ -2234,7 +2242,7 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2245,11 +2253,11 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "pumpkin-util", "serde", - "toml 0.9.11+spec-1.1.0", + "toml", "tracing", "uuid", ] @@ -2257,7 +2265,7 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "crc-fast", "phf", @@ -2269,7 +2277,7 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "crossbeam-utils", "pumpkin-data", @@ -2284,7 +2292,7 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "proc-macro-error2", "pumpkin-data", @@ -2295,7 +2303,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "bytes", "cesu8", @@ -2307,7 +2315,7 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "aes", "async-compression", @@ -2330,7 +2338,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "base64", "bytes", @@ -2355,7 +2363,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#6e1bea72b7ec7b1d193149a124225e08930764f3" +source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#552d7b8d497132ae6f54bbc592b83eba3cd1130a" dependencies = [ "bitflags", "bytes", @@ -2372,11 +2380,10 @@ dependencies = [ "pumpkin-data", "pumpkin-nbt", "pumpkin-util", - "rand", + "rand 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash", "ruzstd", "serde", - "serde_json", "sha2 0.11.0-rc.5", "slotmap", "thiserror", @@ -2413,11 +2420,22 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0-rc.9" -source = "git+https://github.com/rust-random/rand#72afe1e973fcd83d840cf597888223072bbdb04c" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ "chacha20", - "getrandom 0.4.0-rc.1", + "getrandom 0.4.1", + "rand_core 0.10.0", +] + +[[package]] +name = "rand" +version = "0.10.0" +source = "git+https://github.com/rust-random/rand#50516ff45c3675d9c2d247e70bc8db691ed8366d" +dependencies = [ + "chacha20", + "getrandom 0.4.1", "rand_core 0.10.0", ] @@ -2535,7 +2553,7 @@ dependencies = [ "crypto-primes", "digest 0.11.0-rc.11", "pkcs1", - "pkcs8 0.11.0-rc.10", + "pkcs8 0.11.0-rc.11", "rand_core 0.10.0", "signature 3.0.0-rc.10", "spki 0.8.0-rc.4", @@ -2821,7 +2839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -2832,7 +2850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b167252f3c126be0d8926639c4c4706950f01445900c4b3db0fd7e89fcb750a" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.11.0-rc.11", ] @@ -2843,7 +2861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -2854,7 +2872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.11.0-rc.11", ] @@ -2984,7 +3002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" dependencies = [ "base64ct", - "der 0.8.0-rc.10", + "der 0.8.0", ] [[package]] @@ -3205,21 +3223,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.9.11+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" -dependencies = [ - "indexmap", - "serde_core", - "serde_spanned", - "toml_datetime 0.7.5+spec-1.1.0", - "toml_parser", - "toml_writer", - "winnow", -] - [[package]] name = "toml" version = "1.0.2+spec-1.1.0" @@ -3229,21 +3232,12 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime 1.0.0+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", "winnow", ] -[[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_datetime" version = "1.0.0+spec-1.1.0" @@ -3473,11 +3467,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.1", "js-sys", "md-5", "serde_core", @@ -3548,16 +3542,16 @@ version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasip3" -version = "0.3.1+wasi-0.3.0-rc-2025-09-16" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba4be47b1d11244670d11857eee0758a8f2c39aea64d80b78c1ce29b4642cd" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen 0.48.1", + "wit-bindgen", ] [[package]] @@ -3607,9 +3601,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.241.2" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ "leb128fmt", "wasmparser", @@ -3617,9 +3611,9 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.241.2" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", "indexmap", @@ -3629,9 +3623,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.241.2" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags", "hashbrown 0.15.5", @@ -3858,24 +3852,18 @@ checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" [[package]] name = "wit-bindgen" -version = "0.48.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8c2adb5f74ac9395bc3121c99a1254bf9310482c27b13f97167aedb5887138" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ "wit-bindgen-rust-macro", ] -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" - [[package]] name = "wit-bindgen-core" -version = "0.48.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b881a098cae03686d7a0587f8f306f8a58102ad8da8b5599100fbe0e7f5800b" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ "anyhow", "heck", @@ -3884,9 +3872,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rust" -version = "0.48.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69667efa439a453e1d50dac939c6cab6d2c3ac724a9d232b6631dad2472a5b70" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", @@ -3900,9 +3888,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rust-macro" -version = "0.48.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae2e22cceb5d105d52326c07e3e67603a861cc7add70fc467f7cc7ec5265017" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" dependencies = [ "anyhow", "prettyplease", @@ -3915,9 +3903,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.241.2" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags", @@ -3934,9 +3922,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.241.2" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 5da1da6..20d35ce 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,7 +14,7 @@ pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "ma pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-protocol" } pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-util" } pumpkin-api-macros = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-api-macros" } -pumpkin-world = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-world" } + tokio = "1" tracing = "0.1" diff --git a/rust/build/protobufs.rs b/rust/build/protobufs.rs index b45a25c..40d752f 100644 --- a/rust/build/protobufs.rs +++ b/rust/build/protobufs.rs @@ -106,19 +106,28 @@ pub unsafe extern "C" fn {fn_name}( output_len: *mut usize, ) -> *mut u8 {{ use prost::Message; + tracing::debug!("{fn_name}: called with input_ptr={{:?}}, input_len={{}}", input_ptr, input_len); + if input_ptr.is_null() || input_len == 0 {{ + tracing::warn!("{fn_name}: null or empty input (ptr={{:?}}, len={{}})", input_ptr, input_len); + unsafe {{ *output_len = 0 }}; + return std::ptr::null_mut(); + }} let input_slice = unsafe {{ std::slice::from_raw_parts(input_ptr, input_len) }}; let Ok(request) = {input_type}::decode(input_slice) else {{ + tracing::warn!("{fn_name}: failed to decode request"); unsafe {{ *output_len = 0 }}; return std::ptr::null_mut(); }}; let Some(response) = {0}::{fn_name}_impl(request) else {{ + tracing::debug!("{fn_name}: impl returned None"); unsafe {{ *output_len = 0 }}; return std::ptr::null_mut(); }}; - let encoded = response.encode_to_vec(); - unsafe {{ *output_len = encoded.len() }}; - let ptr = encoded.as_ptr() as *mut u8; - std::mem::forget(encoded); + let encoded = response.encode_to_vec().into_boxed_slice(); + let len = encoded.len(); + unsafe {{ *output_len = len }}; + let ptr = Box::into_raw(encoded) as *mut u8; + tracing::debug!("{fn_name}: returning ptr={{:?}}, len={{}}", ptr, len); ptr }} "#, @@ -185,10 +194,12 @@ pub fn setup_protobufs(base: PathBuf) { /// - The pointer must not have been freed previously #[unsafe(no_mangle)] pub unsafe extern "C" fn ffi_free_bytes(ptr: *mut u8, len: usize) {{ - if !ptr.is_null() && len > 0 {{ - unsafe {{ - drop(Vec::from_raw_parts(ptr, len, len)); - }} + if ptr.is_null() || len == 0 {{ + return; + }} + unsafe {{ + let slice = std::slice::from_raw_parts_mut(ptr, len); + drop(Box::from_raw(slice)); }} }} diff --git a/rust/src/commands/mod.rs b/rust/src/commands/mod.rs index 9fb37de..0fac2a3 100644 --- a/rust/src/commands/mod.rs +++ b/rust/src/commands/mod.rs @@ -25,8 +25,8 @@ pub struct JavaCommandExecutor { #[derive(Clone)] pub enum SimpleCommandSender { Console, - /// UUID - Player(String), + /// UUID, Name + Player(String, String), } pub struct AnyCommandNode { @@ -114,8 +114,12 @@ impl From<&CommandSender> for SimpleCommandSender { match val { CommandSender::Rcon(_mutex) => todo!(), CommandSender::Console => Self::Console, - CommandSender::Player(player) => Self::Player(player.gameprofile.id.to_string()), + CommandSender::Player(player) => Self::Player( + player.gameprofile.id.to_string(), + player.gameprofile.name.clone(), + ), CommandSender::CommandBlock(_block_entity, _world) => todo!(), + CommandSender::Dummy => Self::Console, } } } diff --git a/rust/src/java/native_callbacks/config.rs b/rust/src/java/native_callbacks/config.rs index 04e8730..eed3dec 100644 --- a/rust/src/java/native_callbacks/config.rs +++ b/rust/src/java/native_callbacks/config.rs @@ -6,8 +6,9 @@ use crate::{ pub fn ffi_native_bridge_get_patch_bukkit_config_impl( _request: EmptyRequest, ) -> Option { - if let Some(context) = CALLBACK_CONTEXT.get() { - Some(GetPatchBukkitConfigResponse { + CALLBACK_CONTEXT + .get() + .map(|context| GetPatchBukkitConfigResponse { minimum_supported_plugin_api: context .config .settings @@ -15,7 +16,4 @@ pub fn ffi_native_bridge_get_patch_bukkit_config_impl( .clone() .unwrap_or("0.0.0".to_string()), }) - } else { - None - } } diff --git a/rust/src/java/native_callbacks/mod.rs b/rust/src/java/native_callbacks/mod.rs index b2a72a5..56698aa 100644 --- a/rust/src/java/native_callbacks/mod.rs +++ b/rust/src/java/native_callbacks/mod.rs @@ -37,7 +37,6 @@ pub mod config; pub use config::*; pub mod itemstack; -pub use itemstack::*; static CALLBACK_CONTEXT: OnceLock = OnceLock::new(); diff --git a/rust/src/java/plugin/command_manager.rs b/rust/src/java/plugin/command_manager.rs index 90095e5..419e508 100644 --- a/rust/src/java/plugin/command_manager.rs +++ b/rust/src/java/plugin/command_manager.rs @@ -47,6 +47,13 @@ impl CommandManager { Ok(()) } + fn get_or_init_command_map(&mut self, jvm: &Jvm) -> Result<&Instance> { + if self.command_map.is_none() { + self.init(jvm)?; + } + Ok(self.command_map.as_ref().unwrap()) + } + pub fn get_tab_complete( &mut self, jvm: &Jvm, @@ -70,13 +77,7 @@ impl CommandManager { full_command: String, location: Option, ) -> Result>> { - let command_map = match self.command_map { - Some(ref command_map) => command_map, - None => match self.init(jvm) { - Ok(()) => self.command_map.as_ref().unwrap(), - Err(_) => return Ok(None), - }, - }; + let command_map = self.get_or_init_command_map(jvm)?; let sender = Self::sender_to_jsender(jvm, sender)?; @@ -149,13 +150,7 @@ impl CommandManager { cmd_data: &config::spigot::Command, command_tx: mpsc::Sender, ) -> Result<()> { - let command_map = match self.command_map { - Some(ref command_map) => command_map, - None => match self.init(jvm) { - Ok(()) => self.command_map.as_ref().unwrap(), - Err(err) => return Err(err), - }, - }; + let command_map = self.get_or_init_command_map(jvm)?; let plugin_instance = jvm.clone_instance(plugin.instance.as_ref().expect( @@ -190,12 +185,6 @@ impl CommandManager { cmd_data.description.clone().unwrap_or_default(), ); - // TODO - // let permission = if let Some(perm) = cmd_data.permission.clone() { - // perm - // } else { - // format!("patchbukkit:{}", cmd_name) // TODO - // }; let permission = format!("patchbukkit:{cmd_name}"); if let Err(e) = context @@ -224,13 +213,7 @@ impl CommandManager { full_command: String, sender: SimpleCommandSender, ) -> Result<()> { - let command_map = match self.command_map { - Some(ref command_map) => command_map, - None => match self.init(jvm) { - Ok(()) => self.command_map.as_ref().unwrap(), - Err(err) => return Err(err), - }, - }; + let command_map = self.get_or_init_command_map(jvm)?; let j_sender = Self::sender_to_jsender(jvm, sender)?; @@ -239,14 +222,20 @@ impl CommandManager { "dispatch", &[ InvocationArg::from(j_sender), - InvocationArg::try_from(full_command)?, + InvocationArg::try_from(full_command.clone())?, ], - )?; - - let handled: bool = jvm.to_rust(dispatch_result)?; + ); - if !handled { - //tracing::warn!("Command was not handled by any Java plugin: {}", cmd_name); + match dispatch_result { + Ok(result) => { + let handled: bool = jvm.to_rust(result)?; + if !handled { + tracing::warn!("Command not handled by any Java plugin: {full_command}"); + } + } + Err(e) => { + tracing::error!("Java exception during command dispatch '{full_command}': {e:?}"); + } } Ok(()) @@ -260,7 +249,7 @@ impl CommandManager { InvocationArg::empty(), )?), - SimpleCommandSender::Player(uuid_str) => { + SimpleCommandSender::Player(uuid_str, name) => { let server = jvm.invoke_static("org.bukkit.Bukkit", "getServer", InvocationArg::empty())?; let patch_server = jvm.cast(&server, "org.patchbukkit.PatchBukkitServer")?; @@ -271,7 +260,44 @@ impl CommandManager { &[InvocationArg::try_from(uuid_str)?], )?; - Ok(jvm.invoke(&patch_server, "getPlayer", &[InvocationArg::from(j_uuid)])?) + let j_player = jvm.invoke( + &patch_server, + "getPlayer", + &[InvocationArg::from(jvm.clone_instance(&j_uuid)?)], + )?; + + let is_null: bool = jvm.to_rust(jvm.invoke_static( + "java.util.Objects", + "isNull", + &[InvocationArg::from(jvm.clone_instance(&j_player)?)], + )?)?; + + if is_null { + tracing::info!( + "Player not found in Java, creating PatchBukkitPlayer for {}", + name + ); + let j_player = jvm.create_instance( + "org.patchbukkit.entity.PatchBukkitPlayer", + &[InvocationArg::from(j_uuid), InvocationArg::try_from(name)?], + )?; + + jvm.invoke( + &j_player, + "setOp", + &[InvocationArg::try_from(true)?.into_primitive()?], + )?; + + jvm.invoke( + &patch_server, + "registerPlayer", + &[InvocationArg::from(jvm.clone_instance(&j_player)?)], + )?; + + Ok(j_player) + } else { + Ok(j_player) + } } } }