Implement legacy material conversion and fix command sender

- Add three-tier legacy material lookup in PatchBukkitLegacy: data-value
  map, rename map, and direct name match covering all 462 LEGACY_*
  materials
- Fix null player sender by creating PatchBukkitPlayer on-the-fly with
  op when Java-side getPlayer returns null
- Add DynamicTestProvider interface and LEGACY_MATERIALS test category
  that validates every legacy material converts to non-AIR
- Fix protobuf codegen naming collision with java_outer_classname
- Clean up command_manager: extract get_or_init_command_map helper,
  remove debug logging and dead code
This commit is contained in:
Purdze 2026-03-02 22:42:09 +00:00
parent 018ef2a8fa
commit 640d6268ab
11 changed files with 629 additions and 160 deletions

View File

@ -0,0 +1,7 @@
package org.patchbukkit.testplugin;
import java.util.List;
public interface DynamicTestProvider {
List<TestResult> runDynamicTests();
}

View File

@ -22,6 +22,7 @@ public final class PatchBukkitTestPlugin extends JavaPlugin {
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);

View File

@ -10,5 +10,6 @@ public enum TestCategory {
ENTITY,
CONSOLE_SENDER,
UNSAFE_VALUES,
STUBS
STUBS,
LEGACY_MATERIALS
}

View File

@ -40,16 +40,9 @@ public final class TestFramework {
}
public List<TestResult> runCategory(TestCategory category) {
List<TestResult> 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<TestResult> runSuite(Object suite) {
@ -60,6 +53,9 @@ public final class TestFramework {
results.add(runTest(suite, method, ann));
}
}
if (suite instanceof DynamicTestProvider provider) {
results.addAll(provider.runDynamicTests());
}
return results;
}

View File

@ -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<TestResult> runDynamicTests() {
List<TestResult> 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;
}
}

View File

@ -3,10 +3,350 @@ package org.patchbukkit;
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<String, String[]> DATA_VALUE_MAP = new HashMap<>();
// Simple 1:1 rename mappings: legacy name (without LEGACY_ prefix) -> modern name
private static final Map<String, String> 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 final class PatchBukkitLegacy {
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;
}
}

View File

@ -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;

193
rust/Cargo.lock generated
View File

@ -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",
@ -1904,13 +1913,13 @@ dependencies = [
"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 +2032,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 +2048,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 +2202,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 +2213,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 +2222,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 +2243,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 +2254,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 +2266,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 +2278,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 +2293,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 +2304,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 +2316,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 +2339,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 +2364,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 +2381,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 +2421,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 +2554,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 +2840,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 +2851,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 +2862,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 +2873,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 +3003,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 +3224,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 +3233,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 +3468,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 +3543,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 +3602,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 +3612,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 +3624,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 +3853,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"
name = "wit-bindgen-core"
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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b881a098cae03686d7a0587f8f306f8a58102ad8da8b5599100fbe0e7f5800b"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
@ -3884,9 +3873,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 +3889,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 +3904,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 +3923,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",

View File

@ -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));
}}
}}

View File

@ -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,
}
}
}

View File

@ -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<Location>,
) -> Result<Option<Vec<CommandSuggestion>>> {
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<JvmCommand>,
) -> 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,48 @@ 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)
}
}
}
}