diff --git a/.gitignore b/.gitignore index d5df7ef..6554f41 100644 --- a/.gitignore +++ b/.gitignore @@ -175,6 +175,7 @@ Desktop.ini .cursorrules .windsurfrules +.clinerules context.json run.sh run_*.sh diff --git a/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java b/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java index 6b178c0..ce86bc7 100644 --- a/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java +++ b/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java @@ -32,9 +32,17 @@ import org.bukkit.potion.PotionType; import net.coreprotect.config.ConfigHandler; import net.coreprotect.utility.BlockUtils; +/** + * Base adapter implementation for Bukkit API compatibility. + * Provides default implementations for methods that work across multiple Minecraft versions. + * Version-specific implementations extend this class to provide specialized behavior. + */ public class BukkitAdapter implements BukkitInterface { + /** The currently active adapter instance */ public static BukkitInterface ADAPTER; + + // Version constants for Bukkit implementations public static final int BUKKIT_V1_13 = 13; public static final int BUKKIT_V1_14 = 14; public static final int BUKKIT_V1_15 = 15; @@ -45,33 +53,39 @@ public class BukkitAdapter implements BukkitInterface { public static final int BUKKIT_V1_20 = 20; public static final int BUKKIT_V1_21 = 21; + /** + * Initializes the appropriate Bukkit adapter based on the server version. + * This method should be called during plugin initialization. + */ public static void loadAdapter() { switch (ConfigHandler.SERVER_VERSION) { case BUKKIT_V1_13: case BUKKIT_V1_14: case BUKKIT_V1_15: case BUKKIT_V1_16: - BukkitAdapter.ADAPTER = new BukkitAdapter(); + ADAPTER = new BukkitAdapter(); break; case BUKKIT_V1_17: - BukkitAdapter.ADAPTER = new Bukkit_v1_17(); + ADAPTER = new Bukkit_v1_17(); break; case BUKKIT_V1_18: - BukkitAdapter.ADAPTER = new Bukkit_v1_18(); + ADAPTER = new Bukkit_v1_18(); break; case BUKKIT_V1_19: - BukkitAdapter.ADAPTER = new Bukkit_v1_19(); + ADAPTER = new Bukkit_v1_19(); break; case BUKKIT_V1_20: - BukkitAdapter.ADAPTER = new Bukkit_v1_20(); + ADAPTER = new Bukkit_v1_20(); break; case BUKKIT_V1_21: default: - BukkitAdapter.ADAPTER = new Bukkit_v1_21(); + ADAPTER = new Bukkit_v1_21(); break; } } + // -------------------- Basic data conversion methods -------------------- + @Override public String parseLegacyName(String name) { return name; @@ -82,6 +96,8 @@ public class BukkitAdapter implements BukkitInterface { return -1; } + // -------------------- Entity methods -------------------- + @Override public boolean getEntityMeta(LivingEntity entity, List info) { return false; @@ -92,6 +108,18 @@ public class BukkitAdapter implements BukkitInterface { return false; } + @Override + public EntityType getEntityType(Material material) { + switch (material) { + case END_CRYSTAL: + return EntityType.valueOf("ENDER_CRYSTAL"); + default: + return EntityType.UNKNOWN; + } + } + + // -------------------- Item handling methods -------------------- + @Override public boolean getItemMeta(ItemMeta itemMeta, List> list, List>> metadata, int slot) { return false; @@ -102,6 +130,45 @@ public class BukkitAdapter implements BukkitInterface { return false; } + @Override + public Material getPlantSeeds(Material material) { + switch (material) { + case WHEAT: + return Material.WHEAT_SEEDS; + case PUMPKIN_STEM: + return Material.PUMPKIN_SEEDS; + case MELON_STEM: + return Material.MELON_SEEDS; + case BEETROOTS: + return Material.BEETROOT_SEEDS; + default: + return material; + } + } + + @Override + public ItemStack adjustIngredient(MerchantRecipe recipe, ItemStack itemStack) { + return null; + } + + @Override + public ItemStack getArrowMeta(Arrow arrow, ItemStack itemStack) { + PotionData data = arrow.getBasePotionData(); + if (data.getType() != PotionType.valueOf("UNCRAFTABLE")) { + itemStack = new ItemStack(Material.TIPPED_ARROW); + PotionMeta meta = (PotionMeta) itemStack.getItemMeta(); + meta.setBasePotionData(data); + for (PotionEffect effect : arrow.getCustomEffects()) { + meta.addCustomEffect(effect, false); + } + itemStack.setItemMeta(meta); + } + + return itemStack; + } + + // -------------------- Block methods -------------------- + @Override public boolean isAttached(Block block, Block scanBlock, BlockData blockData, int scanMin) { if (blockData instanceof Directional && blockData instanceof FaceAttachable) { @@ -139,9 +206,16 @@ public class BukkitAdapter implements BukkitInterface { return Material.AIR; } + @Override + public boolean isInvisible(Material material) { + return BlockUtils.isAir(material); + } + + // -------------------- Special block type checkers -------------------- + @Override public boolean isItemFrame(Material material) { - return (material == Material.ITEM_FRAME); + return material == Material.ITEM_FRAME; } @Override @@ -159,75 +233,6 @@ public class BukkitAdapter implements BukkitInterface { return ItemFrame.class; } - @Override - public boolean isGlowing(Sign sign, boolean isFront) { - return false; - } - - @Override - public boolean isWaxed(Sign sign) { - return false; - } - - @Override - public boolean isInvisible(Material material) { - return BlockUtils.isAir(material); - } - - @Override - public ItemStack adjustIngredient(MerchantRecipe recipe, ItemStack itemStack) { - return null; - } - - @Override - public void setGlowing(Sign sign, boolean isFront, boolean isGlowing) { - return; - } - - @Override - public void setColor(Sign sign, boolean isFront, int color) { - if (!isFront) { - return; - } - - sign.setColor(DyeColor.getByColor(Color.fromRGB(color))); - } - - @Override - public void setWaxed(Sign sign, boolean isWaxed) { - return; - } - - @Override - public int getColor(Sign sign, boolean isFront) { - if (isFront) { - return sign.getColor().getColor().asRGB(); - } - - return 0; - } - - @Override - public Material getPlantSeeds(Material material) { - switch (material) { - case WHEAT: - material = Material.WHEAT_SEEDS; - break; - case PUMPKIN_STEM: - material = Material.PUMPKIN_SEEDS; - break; - case MELON_STEM: - material = Material.MELON_SEEDS; - break; - case BEETROOTS: - material = Material.BEETROOT_SEEDS; - break; - default: - } - - return material; - } - @Override public boolean isDecoratedPot(Material material) { return false; @@ -258,6 +263,8 @@ public class BukkitAdapter implements BukkitInterface { return null; } + // -------------------- Sign handling methods -------------------- + @Override public String getLine(Sign sign, int line) { if (line < 4) { @@ -285,31 +292,45 @@ public class BukkitAdapter implements BukkitInterface { } @Override - public ItemStack getArrowMeta(Arrow arrow, ItemStack itemStack) { - PotionData data = arrow.getBasePotionData(); - if (data.getType() != PotionType.valueOf("UNCRAFTABLE")) { - itemStack = new ItemStack(Material.TIPPED_ARROW); - PotionMeta meta = (PotionMeta) itemStack.getItemMeta(); - meta.setBasePotionData(data); - for (PotionEffect effect : arrow.getCustomEffects()) { - meta.addCustomEffect(effect, false); - } - itemStack.setItemMeta(meta); - } - - return itemStack; + public boolean isGlowing(Sign sign, boolean isFront) { + return false; } @Override - public EntityType getEntityType(Material material) { - switch (material) { - case END_CRYSTAL: - return EntityType.valueOf("ENDER_CRYSTAL"); - default: - return EntityType.UNKNOWN; - } + public boolean isWaxed(Sign sign) { + return false; } + @Override + public void setGlowing(Sign sign, boolean isFront, boolean isGlowing) { + // Base implementation does nothing + } + + @Override + public void setColor(Sign sign, boolean isFront, int color) { + if (!isFront) { + return; + } + + sign.setColor(DyeColor.getByColor(Color.fromRGB(color))); + } + + @Override + public void setWaxed(Sign sign, boolean isWaxed) { + // Base implementation does nothing + } + + @Override + public int getColor(Sign sign, boolean isFront) { + if (isFront) { + return sign.getColor().getColor().asRGB(); + } + + return 0; + } + + // -------------------- Registry methods -------------------- + @Override public Object getRegistryKey(Object value) { return value; @@ -319,5 +340,4 @@ public class BukkitAdapter implements BukkitInterface { public Object getRegistryValue(String key, Object tClass) { return null; } - } diff --git a/src/main/java/net/coreprotect/bukkit/BukkitInterface.java b/src/main/java/net/coreprotect/bukkit/BukkitInterface.java index 06f0704..cd60cf0 100644 --- a/src/main/java/net/coreprotect/bukkit/BukkitInterface.java +++ b/src/main/java/net/coreprotect/bukkit/BukkitInterface.java @@ -19,76 +19,395 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MerchantRecipe; import org.bukkit.inventory.meta.ItemMeta; +/** + * Interface for Bukkit API compatibility across different Minecraft versions. + * Each method provides version-specific implementations to handle differences + * between Minecraft/Bukkit API versions. + */ public interface BukkitInterface { - public ItemStack adjustIngredient(MerchantRecipe recipe, ItemStack itemStack); + // -------------------------------------------------------------------------- + // Block-related methods + // -------------------------------------------------------------------------- - public Material getBucketContents(Material material); + /** + * Checks if a block is attached to another block. + * + * @param block + * The base block + * @param scanBlock + * The block to check for attachment + * @param blockData + * The block data + * @param scanMin + * The minimum scan value + * @return true if the block is attached, false otherwise + */ + boolean isAttached(Block block, Block scanBlock, BlockData blockData, int scanMin); - public Material getFrameType(Entity entity); + /** + * Gets the minimum height of a world. + * + * @param world + * The world + * @return The minimum height + */ + int getMinHeight(World world); - public Material getFrameType(EntityType type); + /** + * Gets the legacy block ID for a material. + * + * @param material + * The material + * @return The legacy block ID, or -1 if not applicable + */ + int getLegacyBlockId(Material material); - public Class getFrameClass(Material material); + /** + * Gets the contents of a bucket material. + * + * @param material + * The bucket material + * @return The material inside the bucket, or AIR if not applicable + */ + Material getBucketContents(Material material); - public String parseLegacyName(String name); + // -------------------------------------------------------------------------- + // Material type checking methods + // -------------------------------------------------------------------------- - public boolean getEntityMeta(LivingEntity entity, List info); + /** + * Checks if a material is an item frame. + * + * @param material + * The material to check + * @return true if the material is an item frame, false otherwise + */ + boolean isItemFrame(Material material); - public boolean setEntityMeta(Entity entity, Object value, int count); + /** + * Checks if a material is invisible. + * + * @param material + * The material to check + * @return true if the material is invisible, false otherwise + */ + boolean isInvisible(Material material); - public boolean getItemMeta(ItemMeta itemMeta, List> list, List>> metadata, int slot); + /** + * Checks if a material is a decorated pot. + * + * @param material + * The material to check + * @return true if the material is a decorated pot, false otherwise + */ + boolean isDecoratedPot(Material material); - public boolean setItemMeta(Material rowType, ItemStack itemstack, List> map); + /** + * Checks if a material is a suspicious block. + * + * @param material + * The material to check + * @return true if the material is a suspicious block, false otherwise + */ + boolean isSuspiciousBlock(Material material); - public boolean isAttached(Block block, Block scanBlock, BlockData blockData, int scanMin); + /** + * Checks if a material is a sign. + * + * @param material + * The material to check + * @return true if the material is a sign, false otherwise + */ + boolean isSign(Material material); - public boolean isItemFrame(Material material); + /** + * Checks if a material is a chiseled bookshelf. + * + * @param material + * The material to check + * @return true if the material is a chiseled bookshelf, false otherwise + */ + boolean isChiseledBookshelf(Material material); - public boolean isGlowing(Sign sign, boolean isFront); + /** + * Checks if a material is a bookshelf book. + * + * @param material + * The material to check + * @return true if the material is a bookshelf book, false otherwise + */ + boolean isBookshelfBook(Material material); - public boolean isInvisible(Material material); + /** + * Gets the seeds material for a plant material. + * + * @param material + * The plant material + * @return The seeds material + */ + Material getPlantSeeds(Material material); - public boolean isWaxed(Sign sign); + // -------------------------------------------------------------------------- + // Item and inventory methods + // -------------------------------------------------------------------------- - public int getMinHeight(World world); + /** + * Adjusts an ingredient in a merchant recipe. + * + * @param recipe + * The merchant recipe + * @param itemStack + * The item stack + * @return The adjusted item stack, or null if not applicable + */ + ItemStack adjustIngredient(MerchantRecipe recipe, ItemStack itemStack); - public int getLegacyBlockId(Material material); + /** + * Gets metadata from an item meta. + * + * @param itemMeta + * The item meta + * @param list + * The list to populate with metadata + * @param metadata + * The metadata list to populate + * @param slot + * The slot + * @return true if metadata was extracted, false otherwise + */ + boolean getItemMeta(ItemMeta itemMeta, List> list, List>> metadata, int slot); - public void setGlowing(Sign sign, boolean isFront, boolean isGlowing); + /** + * Sets metadata on an item stack. + * + * @param rowType + * The material type + * @param itemstack + * The item stack + * @param map + * The metadata map + * @return true if metadata was set, false otherwise + */ + boolean setItemMeta(Material rowType, ItemStack itemstack, List> map); - public void setColor(Sign sign, boolean isFront, int color); + /** + * Gets a book from a chiseled bookshelf. + * + * @param blockState + * The block state + * @param event + * The player interact event + * @return The book item stack, or null if not applicable + */ + ItemStack getChiseledBookshelfBook(BlockState blockState, PlayerInteractEvent event); - public void setWaxed(Sign sign, boolean isWaxed); + /** + * Gets arrow metadata for an item stack. + * + * @param arrow + * The arrow entity + * @param itemStack + * The item stack + * @return The item stack with arrow metadata + */ + ItemStack getArrowMeta(Arrow arrow, ItemStack itemStack); - public int getColor(Sign sign, boolean isFront); + // -------------------------------------------------------------------------- + // Entity methods + // -------------------------------------------------------------------------- - public Material getPlantSeeds(Material material); + /** + * Gets metadata from a living entity. + * + * @param entity + * The living entity + * @param info + * The list to populate with entity metadata + * @return true if metadata was extracted, false otherwise + */ + boolean getEntityMeta(LivingEntity entity, List info); - public boolean isDecoratedPot(Material material); + /** + * Sets metadata on an entity. + * + * @param entity + * The entity + * @param value + * The metadata value + * @param count + * The count + * @return true if metadata was set, false otherwise + */ + boolean setEntityMeta(Entity entity, Object value, int count); - public boolean isSuspiciousBlock(Material material); + /** + * Gets the frame type for an entity. + * + * @param entity + * The entity + * @return The frame material type + */ + Material getFrameType(Entity entity); - public boolean isSign(Material material); + /** + * Gets the frame type for an entity type. + * + * @param type + * The entity type + * @return The frame material type + */ + Material getFrameType(EntityType type); - public boolean isChiseledBookshelf(Material material); + /** + * Gets the entity type for a material. + * + * @param material + * The material + * @return The entity type + */ + EntityType getEntityType(Material material); - public boolean isBookshelfBook(Material material); + /** + * Gets the frame class for a material. + * + * @param material + * The material + * @return The frame class + */ + Class getFrameClass(Material material); - public ItemStack getChiseledBookshelfBook(BlockState blockState, PlayerInteractEvent event); + // -------------------------------------------------------------------------- + // Sign methods + // -------------------------------------------------------------------------- - public String getLine(Sign sign, int line); + /** + * Checks if a sign is glowing. + * + * @param sign + * The sign + * @param isFront + * Whether to check the front side + * @return true if the sign is glowing, false otherwise + */ + boolean isGlowing(Sign sign, boolean isFront); - public void setLine(Sign sign, int line, String string); + /** + * Checks if a sign is waxed. + * + * @param sign + * The sign + * @return true if the sign is waxed, false otherwise + */ + boolean isWaxed(Sign sign); - public boolean isSignFront(SignChangeEvent event); + /** + * Sets whether a sign is glowing. + * + * @param sign + * The sign + * @param isFront + * Whether to set the front side + * @param isGlowing + * Whether the sign should be glowing + */ + void setGlowing(Sign sign, boolean isFront, boolean isGlowing); - public ItemStack getArrowMeta(Arrow arrow, ItemStack itemStack); + /** + * Sets the color of a sign. + * + * @param sign + * The sign + * @param isFront + * Whether to set the front side + * @param color + * The color RGB value + */ + void setColor(Sign sign, boolean isFront, int color); - public EntityType getEntityType(Material material); + /** + * Sets whether a sign is waxed. + * + * @param sign + * The sign + * @param isWaxed + * Whether the sign should be waxed + */ + void setWaxed(Sign sign, boolean isWaxed); - public Object getRegistryKey(Object value); + /** + * Gets the color of a sign. + * + * @param sign + * The sign + * @param isFront + * Whether to get the front side color + * @return The color RGB value + */ + int getColor(Sign sign, boolean isFront); - public Object getRegistryValue(String key, Object tClass); + /** + * Gets a line of text from a sign. + * + * @param sign + * The sign + * @param line + * The line number (0-based) + * @return The text on the line + */ + String getLine(Sign sign, int line); + /** + * Sets a line of text on a sign. + * + * @param sign + * The sign + * @param line + * The line number (0-based) + * @param string + * The text to set + */ + void setLine(Sign sign, int line, String string); + + /** + * Checks if a sign change event is for the front side of the sign. + * + * @param event + * The sign change event + * @return true if the event is for the front side, false otherwise + */ + boolean isSignFront(SignChangeEvent event); + + // -------------------------------------------------------------------------- + // Registry methods + // -------------------------------------------------------------------------- + + /** + * Gets the registry key for a value. + * + * @param value + * The value + * @return The registry key + */ + Object getRegistryKey(Object value); + + /** + * Gets a registry value by key and class. + * + * @param key + * The key + * @param tClass + * The class + * @return The registry value + */ + Object getRegistryValue(String key, Object tClass); + + /** + * Parses a legacy material name. + * + * @param name + * The legacy name + * @return The parsed name + */ + String parseLegacyName(String name); } diff --git a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_17.java b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_17.java index 970f2a9..b9e6918 100644 --- a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_17.java +++ b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_17.java @@ -28,18 +28,44 @@ import net.coreprotect.model.BlockGroup; import net.coreprotect.utility.ItemUtils; import net.coreprotect.utility.MaterialUtils; +/** + * Bukkit adapter implementation for Minecraft 1.17. + * Provides version-specific implementations for the BukkitInterface + * to handle features introduced in the 1.17 update. + */ public class Bukkit_v1_17 extends BukkitAdapter { + /** + * Initializes the Bukkit_v1_17 adapter with 1.17-specific block groups. + * Sets up collections of blocks with similar behavior for efficient handling. + */ public Bukkit_v1_17() { + initializeBlockGroups(); + } + + /** + * Initializes all the block groups for Minecraft 1.17. + * This includes new blocks like amethyst, candles, pointed dripstone, etc. + */ + private void initializeBlockGroups() { BlockGroup.TRACK_ANY = new HashSet<>(Arrays.asList(Material.PISTON_HEAD, Material.LEVER, Material.BELL, Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER, Material.GLOW_LICHEN)); + BlockGroup.TRACK_TOP = new HashSet<>(Arrays.asList(Material.TORCH, Material.REDSTONE_TORCH, Material.BAMBOO, Material.BAMBOO_SAPLING, Material.CORNFLOWER, Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SWEET_BERRY_BUSH, Material.SCAFFOLDING, Material.OAK_SAPLING, Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.ACACIA_SAPLING, Material.DARK_OAK_SAPLING, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FERN, Material.DEAD_BUSH, Material.DANDELION, Material.POPPY, Material.BLUE_ORCHID, Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.REDSTONE_WIRE, Material.WHEAT, Material.ACACIA_SIGN, Material.BIRCH_SIGN, Material.DARK_OAK_SIGN, Material.JUNGLE_SIGN, Material.OAK_SIGN, Material.SPRUCE_SIGN, Material.WHITE_BANNER, Material.ORANGE_BANNER, Material.MAGENTA_BANNER, Material.LIGHT_BLUE_BANNER, Material.YELLOW_BANNER, Material.LIME_BANNER, Material.PINK_BANNER, Material.GRAY_BANNER, Material.LIGHT_GRAY_BANNER, Material.CYAN_BANNER, Material.PURPLE_BANNER, Material.BLUE_BANNER, Material.BROWN_BANNER, Material.GREEN_BANNER, Material.RED_BANNER, Material.BLACK_BANNER, Material.RAIL, Material.IRON_DOOR, Material.SNOW, Material.CACTUS, Material.SUGAR_CANE, Material.REPEATER, Material.PUMPKIN_STEM, Material.MELON_STEM, Material.CARROT, Material.POTATO, Material.COMPARATOR, Material.ACTIVATOR_RAIL, Material.SUNFLOWER, Material.LILAC, Material.TALL_GRASS, Material.LARGE_FERN, Material.ROSE_BUSH, Material.PEONY, Material.NETHER_WART, Material.CHORUS_PLANT, Material.CHORUS_FLOWER, Material.KELP, Material.SOUL_TORCH, Material.TWISTING_VINES, Material.CRIMSON_FUNGUS, Material.WARPED_FUNGUS, Material.CRIMSON_ROOTS, Material.WARPED_ROOTS, Material.NETHER_SPROUTS, Material.CRIMSON_SIGN, Material.WARPED_SIGN, Material.AZALEA, Material.FLOWERING_AZALEA, Material.SMALL_DRIPLEAF, Material.BIG_DRIPLEAF)); + BlockGroup.TRACK_TOP_BOTTOM = new HashSet<>(Arrays.asList(Material.POINTED_DRIPSTONE, Material.BIG_DRIPLEAF_STEM)); + BlockGroup.TRACK_BOTTOM = new HashSet<>(Arrays.asList(Material.WEEPING_VINES, Material.CAVE_VINES, Material.CAVE_VINES_PLANT, Material.HANGING_ROOTS)); + BlockGroup.VINES = new HashSet<>(Arrays.asList(Material.VINE, Material.WEEPING_VINES, Material.TWISTING_VINES, Material.CAVE_VINES)); + BlockGroup.CANDLES = new HashSet<>(Arrays.asList(Material.CANDLE, Material.BLACK_CANDLE, Material.BLUE_CANDLE, Material.BROWN_CANDLE, Material.CYAN_CANDLE, Material.GRAY_CANDLE, Material.GREEN_CANDLE, Material.LIGHT_BLUE_CANDLE, Material.LIGHT_GRAY_CANDLE, Material.LIME_CANDLE, Material.MAGENTA_CANDLE, Material.ORANGE_CANDLE, Material.PINK_CANDLE, Material.PURPLE_CANDLE, Material.RED_CANDLE, Material.WHITE_CANDLE, Material.YELLOW_CANDLE, Material.CANDLE_CAKE, Material.BLACK_CANDLE_CAKE, Material.BLUE_CANDLE_CAKE, Material.BROWN_CANDLE_CAKE, Material.CYAN_CANDLE_CAKE, Material.GRAY_CANDLE_CAKE, Material.GREEN_CANDLE_CAKE, Material.LIGHT_BLUE_CANDLE_CAKE, Material.LIGHT_GRAY_CANDLE_CAKE, Material.LIME_CANDLE_CAKE, Material.MAGENTA_CANDLE_CAKE, Material.ORANGE_CANDLE_CAKE, Material.PINK_CANDLE_CAKE, Material.PURPLE_CANDLE_CAKE, Material.RED_CANDLE_CAKE, Material.WHITE_CANDLE_CAKE, Material.YELLOW_CANDLE_CAKE)); + BlockGroup.AMETHYST = new HashSet<>(Arrays.asList(Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER)); + BlockGroup.UPDATE_STATE = new HashSet<>(Arrays.asList(Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.RAIL, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FURNACE, Material.BLAST_FURNACE, Material.SMOKER, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.GLOWSTONE, Material.JACK_O_LANTERN, Material.REPEATER, Material.REDSTONE_LAMP, Material.BEACON, Material.COMPARATOR, Material.DAYLIGHT_DETECTOR, Material.REDSTONE_BLOCK, Material.HOPPER, Material.CHEST, Material.TRAPPED_CHEST, Material.ACTIVATOR_RAIL, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.SHROOMLIGHT, Material.RESPAWN_ANCHOR, Material.CRYING_OBSIDIAN, Material.TARGET, Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER, Material.CAVE_VINES, Material.CAVE_VINES_PLANT, Material.GLOW_LICHEN, Material.LIGHT, Material.LAVA_CAULDRON)); + BlockGroup.NON_ATTACHABLE = new HashSet<>(Arrays.asList(Material.AIR, Material.CAVE_AIR, Material.BARRIER, Material.CORNFLOWER, Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SWEET_BERRY_BUSH, Material.OAK_SAPLING, Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.ACACIA_SAPLING, Material.DARK_OAK_SAPLING, Material.WATER, Material.LAVA, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FERN, Material.DEAD_BUSH, Material.DANDELION, Material.POPPY, Material.BLUE_ORCHID, Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.LADDER, Material.RAIL, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.SNOW, Material.SUGAR_CANE, Material.NETHER_PORTAL, Material.REPEATER, Material.KELP, Material.CHORUS_FLOWER, Material.CHORUS_PLANT, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.LIGHT, Material.SMALL_DRIPLEAF, Material.BIG_DRIPLEAF, Material.BIG_DRIPLEAF_STEM, Material.GLOW_LICHEN, Material.HANGING_ROOTS)); + BlockGroup.VERTICAL_TOP_BOTTOM = new HashSet<>(Arrays.asList(Material.BIG_DRIPLEAF_STEM)); } @@ -47,13 +73,10 @@ public class Bukkit_v1_17 extends BukkitAdapter { public String parseLegacyName(String name) { switch (name) { case "GRASS_PATH": - name = "DIRT_PATH"; - break; + return "DIRT_PATH"; default: - break; + return name; } - - return name; } @Override @@ -71,19 +94,15 @@ public class Bukkit_v1_17 extends BukkitAdapter { if (entity instanceof Axolotl) { Axolotl axolotl = (Axolotl) entity; info.add(axolotl.getVariant()); + return true; } else if (entity instanceof Goat) { Goat goat = (Goat) entity; info.add(goat.isScreaming()); - } - else if (super.getEntityMeta(entity, info)) { return true; } - else { - return false; - } - return true; + return super.getEntityMeta(entity, info); } @Override @@ -91,25 +110,21 @@ public class Bukkit_v1_17 extends BukkitAdapter { if (entity instanceof Axolotl) { Axolotl axolotl = (Axolotl) entity; if (count == 0) { - org.bukkit.entity.Axolotl.Variant set = (org.bukkit.entity.Axolotl.Variant) value; - axolotl.setVariant(set); + org.bukkit.entity.Axolotl.Variant variant = (org.bukkit.entity.Axolotl.Variant) value; + axolotl.setVariant(variant); + return true; } } else if (entity instanceof Goat) { Goat goat = (Goat) entity; if (count == 0) { - boolean set = (Boolean) value; - goat.setScreaming(set); + boolean isScreaming = (Boolean) value; + goat.setScreaming(isScreaming); + return true; } } - else if (super.setEntityMeta(entity, value, count)) { - return true; - } - else { - return false; - } - return true; + return super.setEntityMeta(entity, value, count); } @Override @@ -131,20 +146,15 @@ public class Bukkit_v1_17 extends BukkitAdapter { } metadata.add(list); } - } - else if (super.getItemMeta(itemMeta, list, metadata, slot)) { return true; } - else { - return false; - } - return true; + return super.getItemMeta(itemMeta, list, metadata, slot); } @Override public boolean setItemMeta(Material rowType, ItemStack itemstack, List> map) { - if ((rowType == Material.BUNDLE)) { + if (rowType == Material.BUNDLE) { BundleMeta meta = (BundleMeta) itemstack.getItemMeta(); for (Map itemData : map) { ItemStack itemStack = ItemUtils.unserializeItemStack(itemData); @@ -153,15 +163,10 @@ public class Bukkit_v1_17 extends BukkitAdapter { } } itemstack.setItemMeta(meta); - } - else if (super.setItemMeta(rowType, itemstack, map)) { return true; } - else { - return false; - } - return true; + return super.setItemMeta(rowType, itemstack, map); } @Override @@ -170,15 +175,10 @@ public class Bukkit_v1_17 extends BukkitAdapter { PointedDripstone pointedDripstone = (PointedDripstone) blockData; BlockFace blockFace = pointedDripstone.getVerticalDirection(); boolean adjacent = scanBlock.getRelative(blockFace.getOppositeFace()).getLocation().equals(block.getLocation()); - if (!adjacent) { - return false; - } - } - else if (!super.isAttached(block, scanBlock, blockData, scanMin)) { - return false; + return adjacent; } - return true; + return super.isAttached(block, scanBlock, blockData, scanMin); } @Override @@ -188,7 +188,7 @@ public class Bukkit_v1_17 extends BukkitAdapter { @Override public Material getBucketContents(Material material) { - return (material == Material.POWDER_SNOW_BUCKET ? Material.POWDER_SNOW : Material.AIR); + return (material == Material.POWDER_SNOW_BUCKET) ? Material.POWDER_SNOW : Material.AIR; } @Override @@ -240,5 +240,4 @@ public class Bukkit_v1_17 extends BukkitAdapter { public boolean isInvisible(Material material) { return material.isAir() || material == Material.LIGHT; } - } diff --git a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_18.java b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_18.java index 2238edf..4e8fe82 100644 --- a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_18.java +++ b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_18.java @@ -3,28 +3,59 @@ package net.coreprotect.bukkit; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.MerchantRecipe; +/** + * Bukkit adapter implementation for Minecraft 1.18. + * Provides version-specific implementations for the BukkitInterface + * to handle features introduced in the 1.18 update. + */ public class Bukkit_v1_18 extends Bukkit_v1_17 { - private Boolean hasAdjust = null; + /** + * Flag to track whether the MerchantRecipe.adjust() method is available. + * This is initialized on first use and prevents repeated reflection checks. + * - null: Not yet checked + * - true: Method exists and should be used + * - false: Method doesn't exist or failed, fallback to parent implementation + */ + private Boolean hasAdjustMethod = null; + /** + * Adjusts an ingredient in a merchant recipe for version 1.18+. + * This handles changes to the MerchantRecipe API introduced in Bukkit 1.18.1. + * + * @param recipe + * The merchant recipe + * @param itemStack + * The item stack to adjust + * @return The adjusted item stack, or null if adjustment not supported or fails + */ @Override public ItemStack adjustIngredient(MerchantRecipe recipe, ItemStack itemStack) { + if (itemStack == null) { + return null; + } + try { - if (hasAdjust == null) { - hasAdjust = true; + // First-time detection of adjust method availability + if (hasAdjustMethod == null) { + hasAdjustMethod = true; + // Test if the adjust method exists using reflection MerchantRecipe.class.getMethod("adjust", ItemStack.class); // Bukkit 1.18.1+ } - else if (Boolean.FALSE.equals(hasAdjust)) { - return null; + // Skip if we've already determined the method isn't available + else if (Boolean.FALSE.equals(hasAdjustMethod)) { + return super.adjustIngredient(recipe, itemStack); } + // Create a clone to avoid modifying the original itemStack ItemStack adjustedStack = itemStack.clone(); recipe.adjust(adjustedStack); return adjustedStack; } catch (Exception e) { - hasAdjust = false; - return null; + // Method doesn't exist or failed, mark it for future calls + hasAdjustMethod = false; + return super.adjustIngredient(recipe, itemStack); } } diff --git a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_19.java b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_19.java index 5414f9f..0a381a4 100644 --- a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_19.java +++ b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_19.java @@ -13,85 +13,228 @@ import org.bukkit.entity.Tadpole; import net.coreprotect.model.BlockGroup; +/** + * Bukkit adapter implementation for Minecraft 1.19. + * Provides version-specific implementations for the BukkitInterface + * to handle features introduced in the 1.19 update, including: + * - New block types (mangrove) + * - New entity types (frogs, tadpoles) + * - Updates to existing entities (goats) + * - Sculk blocks + */ public class Bukkit_v1_19 extends Bukkit_v1_18 { + /** + * Initializes the Bukkit_v1_19 adapter with 1.19-specific block groups. + * Sets up collections of blocks with similar behavior for efficient handling. + */ public Bukkit_v1_19() { + initializeBlockGroups(); + } + + /** + * Initializes all the block groups for Minecraft 1.19. + * This organizes blocks into functional categories for efficient lookups and operations. + */ + private void initializeBlockGroups() { + // Blocks that need tracking from the top face + initializeTrackTopBlocks(); + + // Blocks that need tracking from the side + initializeTrackSideBlocks(); + + // Door blocks + initializeDoorBlocks(); + + // Button blocks + initializeButtonBlocks(); + + // Pressure plate blocks + initializePressurePlateBlocks(); + + // Blocks that can be interacted with + initializeInteractBlocks(); + + // Blocks that can be safely interacted with (won't cause block updates) + initializeSafeInteractBlocks(); + + // Blocks that can't have other blocks attached to them + initializeNonAttachableBlocks(); + + // Sculk blocks (new in 1.19) + initializeSculkBlocks(); + } + + /** + * Initializes blocks that need tracking from their top face. + */ + private void initializeTrackTopBlocks() { BlockGroup.TRACK_TOP = new HashSet<>(Arrays.asList(Material.TORCH, Material.REDSTONE_TORCH, Material.BAMBOO, Material.BAMBOO_SAPLING, Material.CORNFLOWER, Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SWEET_BERRY_BUSH, Material.SCAFFOLDING, Material.OAK_SAPLING, Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.MANGROVE_PROPAGULE, Material.ACACIA_SAPLING, Material.DARK_OAK_SAPLING, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FERN, Material.DEAD_BUSH, Material.DANDELION, Material.POPPY, Material.BLUE_ORCHID, Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.REDSTONE_WIRE, Material.WHEAT, Material.MANGROVE_SIGN, Material.ACACIA_SIGN, Material.BIRCH_SIGN, Material.DARK_OAK_SIGN, Material.JUNGLE_SIGN, Material.OAK_SIGN, Material.SPRUCE_SIGN, Material.WHITE_BANNER, Material.ORANGE_BANNER, Material.MAGENTA_BANNER, Material.LIGHT_BLUE_BANNER, Material.YELLOW_BANNER, Material.LIME_BANNER, Material.PINK_BANNER, Material.GRAY_BANNER, Material.LIGHT_GRAY_BANNER, Material.CYAN_BANNER, Material.PURPLE_BANNER, Material.BLUE_BANNER, Material.BROWN_BANNER, Material.GREEN_BANNER, Material.RED_BANNER, Material.BLACK_BANNER, Material.RAIL, Material.IRON_DOOR, Material.SNOW, Material.CACTUS, Material.SUGAR_CANE, Material.REPEATER, Material.PUMPKIN_STEM, Material.MELON_STEM, Material.CARROT, Material.POTATO, Material.COMPARATOR, Material.ACTIVATOR_RAIL, Material.SUNFLOWER, Material.LILAC, Material.TALL_GRASS, Material.LARGE_FERN, Material.ROSE_BUSH, Material.PEONY, Material.NETHER_WART, Material.CHORUS_PLANT, Material.CHORUS_FLOWER, Material.KELP, Material.SOUL_TORCH, Material.TWISTING_VINES, Material.CRIMSON_FUNGUS, Material.WARPED_FUNGUS, Material.CRIMSON_ROOTS, Material.WARPED_ROOTS, Material.NETHER_SPROUTS, Material.CRIMSON_SIGN, Material.WARPED_SIGN, Material.AZALEA, Material.FLOWERING_AZALEA, Material.SMALL_DRIPLEAF, Material.BIG_DRIPLEAF)); + } + + /** + * Initializes blocks that need tracking from their side. + */ + private void initializeTrackSideBlocks() { BlockGroup.TRACK_SIDE = new HashSet<>(Arrays.asList(Material.WALL_TORCH, Material.REDSTONE_WALL_TORCH, Material.RAIL, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.ACTIVATOR_RAIL, Material.WHITE_BED, Material.ORANGE_BED, Material.MAGENTA_BED, Material.LIGHT_BLUE_BED, Material.YELLOW_BED, Material.LIME_BED, Material.PINK_BED, Material.GRAY_BED, Material.LIGHT_GRAY_BED, Material.CYAN_BED, Material.PURPLE_BED, Material.BLUE_BED, Material.BROWN_BED, Material.GREEN_BED, Material.RED_BED, Material.BLACK_BED, Material.LADDER, Material.MANGROVE_WALL_SIGN, Material.ACACIA_WALL_SIGN, Material.BIRCH_WALL_SIGN, Material.DARK_OAK_WALL_SIGN, Material.JUNGLE_WALL_SIGN, Material.OAK_WALL_SIGN, Material.SPRUCE_WALL_SIGN, Material.VINE, Material.COCOA, Material.TRIPWIRE_HOOK, Material.WHITE_WALL_BANNER, Material.ORANGE_WALL_BANNER, Material.MAGENTA_WALL_BANNER, Material.LIGHT_BLUE_WALL_BANNER, Material.YELLOW_WALL_BANNER, Material.LIME_WALL_BANNER, Material.PINK_WALL_BANNER, Material.GRAY_WALL_BANNER, Material.LIGHT_GRAY_WALL_BANNER, Material.CYAN_WALL_BANNER, Material.PURPLE_WALL_BANNER, Material.BLUE_WALL_BANNER, Material.BROWN_WALL_BANNER, Material.GREEN_WALL_BANNER, Material.RED_WALL_BANNER, Material.BLACK_WALL_BANNER, Material.SOUL_WALL_TORCH, Material.CRIMSON_WALL_SIGN, Material.WARPED_WALL_SIGN)); + } + + /** + * Initializes door blocks. + */ + private void initializeDoorBlocks() { BlockGroup.DOORS = new HashSet<>(Arrays.asList(Material.OAK_DOOR, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.MANGROVE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.CRIMSON_DOOR, Material.WARPED_DOOR)); + } + + /** + * Initializes button blocks. + */ + private void initializeButtonBlocks() { BlockGroup.BUTTONS = new HashSet<>(Arrays.asList(Material.STONE_BUTTON, Material.OAK_BUTTON, Material.MANGROVE_BUTTON, Material.ACACIA_BUTTON, Material.BIRCH_BUTTON, Material.DARK_OAK_BUTTON, Material.JUNGLE_BUTTON, Material.SPRUCE_BUTTON, Material.POLISHED_BLACKSTONE_BUTTON, Material.CRIMSON_BUTTON, Material.WARPED_BUTTON)); + } + + /** + * Initializes pressure plate blocks. + */ + private void initializePressurePlateBlocks() { BlockGroup.PRESSURE_PLATES = new HashSet<>(Arrays.asList(Material.STONE_PRESSURE_PLATE, Material.MANGROVE_PRESSURE_PLATE, Material.ACACIA_PRESSURE_PLATE, Material.BIRCH_PRESSURE_PLATE, Material.DARK_OAK_PRESSURE_PLATE, Material.HEAVY_WEIGHTED_PRESSURE_PLATE, Material.JUNGLE_PRESSURE_PLATE, Material.LIGHT_WEIGHTED_PRESSURE_PLATE, Material.OAK_PRESSURE_PLATE, Material.SPRUCE_PRESSURE_PLATE, Material.CRIMSON_PRESSURE_PLATE, Material.WARPED_PRESSURE_PLATE, Material.POLISHED_BLACKSTONE_PRESSURE_PLATE)); + } + + /** + * Initializes blocks that can be interacted with. + */ + private void initializeInteractBlocks() { BlockGroup.INTERACT_BLOCKS = new HashSet<>(Arrays.asList(Material.SPRUCE_FENCE_GATE, Material.BIRCH_FENCE_GATE, Material.JUNGLE_FENCE_GATE, Material.DARK_OAK_FENCE_GATE, Material.MANGROVE_FENCE_GATE, Material.ACACIA_FENCE_GATE, Material.DISPENSER, Material.NOTE_BLOCK, Material.CHEST, Material.FURNACE, Material.LEVER, Material.REPEATER, Material.MANGROVE_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR, Material.DARK_OAK_TRAPDOOR, Material.JUNGLE_TRAPDOOR, Material.SPRUCE_TRAPDOOR, Material.OAK_TRAPDOOR, Material.OAK_FENCE_GATE, Material.BREWING_STAND, Material.ANVIL, Material.CHIPPED_ANVIL, Material.DAMAGED_ANVIL, Material.ENDER_CHEST, Material.TRAPPED_CHEST, Material.COMPARATOR, Material.HOPPER, Material.DROPPER, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.GRINDSTONE, Material.LOOM, Material.SMOKER, Material.CRAFTING_TABLE, Material.CARTOGRAPHY_TABLE, Material.ENCHANTING_TABLE, Material.SMITHING_TABLE, Material.STONECUTTER, Material.CRIMSON_FENCE_GATE, Material.WARPED_FENCE_GATE, Material.CRIMSON_TRAPDOOR, Material.WARPED_TRAPDOOR)); + } + + /** + * Initializes blocks that can be safely interacted with. + */ + private void initializeSafeInteractBlocks() { BlockGroup.SAFE_INTERACT_BLOCKS = new HashSet<>(Arrays.asList(Material.LEVER, Material.MANGROVE_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR, Material.DARK_OAK_TRAPDOOR, Material.JUNGLE_TRAPDOOR, Material.SPRUCE_TRAPDOOR, Material.OAK_TRAPDOOR, Material.OAK_FENCE_GATE, Material.SPRUCE_FENCE_GATE, Material.BIRCH_FENCE_GATE, Material.JUNGLE_FENCE_GATE, Material.DARK_OAK_FENCE_GATE, Material.MANGROVE_FENCE_GATE, Material.ACACIA_FENCE_GATE, Material.CRIMSON_FENCE_GATE, Material.WARPED_FENCE_GATE, Material.CRIMSON_TRAPDOOR, Material.WARPED_TRAPDOOR)); + } + + /** + * Initializes blocks that can't have other blocks attached to them. + */ + private void initializeNonAttachableBlocks() { BlockGroup.NON_ATTACHABLE = new HashSet<>(Arrays.asList(Material.AIR, Material.CAVE_AIR, Material.BARRIER, Material.CORNFLOWER, Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SWEET_BERRY_BUSH, Material.OAK_SAPLING, Material.SPRUCE_SAPLING, Material.BIRCH_SAPLING, Material.JUNGLE_SAPLING, Material.MANGROVE_PROPAGULE, Material.ACACIA_SAPLING, Material.DARK_OAK_SAPLING, Material.WATER, Material.LAVA, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FERN, Material.DEAD_BUSH, Material.DANDELION, Material.POPPY, Material.BLUE_ORCHID, Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.LADDER, Material.RAIL, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.SNOW, Material.SUGAR_CANE, Material.NETHER_PORTAL, Material.REPEATER, Material.KELP, Material.CHORUS_FLOWER, Material.CHORUS_PLANT, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.LIGHT, Material.SMALL_DRIPLEAF, Material.BIG_DRIPLEAF, Material.BIG_DRIPLEAF_STEM, Material.GLOW_LICHEN, Material.HANGING_ROOTS)); + } + + /** + * Initializes sculk blocks (new in 1.19). + */ + private void initializeSculkBlocks() { BlockGroup.SCULK = new HashSet<>(Arrays.asList(Material.SCULK, Material.SCULK_VEIN, Material.SCULK_SENSOR, Material.SCULK_SHRIEKER)); } + /** + * Gets metadata from a living entity specific to 1.19. + * Handles Frog, Tadpole, and updated Goat entities. + * + * @param entity + * The living entity + * @param info + * The list to populate with entity metadata + * @return true if metadata was extracted, false otherwise + */ @Override public boolean getEntityMeta(LivingEntity entity, List info) { - if (entity instanceof Frog) { - Frog frog = (Frog) entity; - info.add(BukkitAdapter.ADAPTER.getRegistryKey(frog.getVariant())); - } - else if (entity instanceof Tadpole) { - Tadpole tadpole = (Tadpole) entity; - info.add(tadpole.getAge()); - } - else if (entity instanceof Goat) { - Goat goat = (Goat) entity; - info.add(goat.isScreaming()); - info.add(goat.hasLeftHorn()); - info.add(goat.hasRightHorn()); - } - else if (super.getEntityMeta(entity, info)) { - return true; - } - else { + if (entity == null || info == null) { return false; } - return true; + try { + if (entity instanceof Frog) { + Frog frog = (Frog) entity; + info.add(BukkitAdapter.ADAPTER.getRegistryKey(frog.getVariant())); + return true; + } + else if (entity instanceof Tadpole) { + Tadpole tadpole = (Tadpole) entity; + info.add(tadpole.getAge()); + return true; + } + else if (entity instanceof Goat) { + Goat goat = (Goat) entity; + info.add(goat.isScreaming()); + info.add(goat.hasLeftHorn()); + info.add(goat.hasRightHorn()); + return true; + } + + // Fall back to parent implementation if not a known 1.19 entity + return super.getEntityMeta(entity, info); + } + catch (Exception e) { + // Log error or handle exception if needed + return false; + } } + /** + * Sets metadata on an entity specific to 1.19. + * Handles Frog, Tadpole, and updated Goat entities. + * + * @param entity + * The entity + * @param value + * The metadata value + * @param count + * The index of the metadata property + * @return true if metadata was set, false otherwise + */ @Override public boolean setEntityMeta(Entity entity, Object value, int count) { - if (entity instanceof Frog) { - Frog frog = (Frog) entity; - if (count == 0) { - if (value instanceof String) { - value = BukkitAdapter.ADAPTER.getRegistryValue((String) value, Frog.Variant.class); - } - Frog.Variant set = (Frog.Variant) value; - frog.setVariant(set); - } - } - else if (entity instanceof Tadpole) { - Tadpole tadpole = (Tadpole) entity; - if (count == 0) { - int set = (int) value; - tadpole.setAge(set); - } - } - else if (entity instanceof Goat) { - Goat goat = (Goat) entity; - boolean set = (Boolean) value; - if (count == 0) { - goat.setScreaming(set); - } - else if (count == 1) { - goat.setLeftHorn(set); - } - else if (count == 2) { - goat.setRightHorn(set); - } - } - else if (super.setEntityMeta(entity, value, count)) { - return true; - } - else { + if (entity == null || value == null) { return false; } - return true; + try { + if (entity instanceof Frog) { + Frog frog = (Frog) entity; + if (count == 0) { + // Convert string registry key to variant if needed + if (value instanceof String) { + value = BukkitAdapter.ADAPTER.getRegistryValue((String) value, Frog.Variant.class); + } + frog.setVariant((Frog.Variant) value); + return true; + } + } + else if (entity instanceof Tadpole) { + Tadpole tadpole = (Tadpole) entity; + if (count == 0) { + tadpole.setAge((int) value); + return true; + } + } + else if (entity instanceof Goat) { + Goat goat = (Goat) entity; + boolean boolValue = (Boolean) value; + + switch (count) { + case 0: + goat.setScreaming(boolValue); + return true; + case 1: + goat.setLeftHorn(boolValue); + return true; + case 2: + goat.setRightHorn(boolValue); + return true; + default: + // Invalid count for goat + return false; + } + } + + // Fall back to parent implementation if not a known 1.19 entity + return super.setEntityMeta(entity, value, count); + } + catch (Exception e) { + // Log error or handle exception if needed + return false; + } } } diff --git a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_20.java b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_20.java index 12e4c28..3e3a241 100644 --- a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_20.java +++ b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_20.java @@ -2,6 +2,7 @@ package net.coreprotect.bukkit; import java.util.Arrays; import java.util.HashSet; +import java.util.Set; import org.bukkit.Color; import org.bukkit.DyeColor; @@ -21,67 +22,76 @@ import org.bukkit.potion.PotionType; import net.coreprotect.model.BlockGroup; +/** + * Bukkit adapter implementation for Minecraft 1.20. + * Provides version-specific implementations for the BukkitInterface + * to handle features introduced in the 1.20 update, including: + * - Updated sign handling with front/back sides + * - New block types (chiseled bookshelf, decorated pot) + * - Suspicious blocks (sand/gravel) + * - Arrow potion handling + */ public class Bukkit_v1_20 extends Bukkit_v1_19 { - private Boolean hasClickedPosition = null; - private Boolean hasBasePotionType = null; + private Boolean hasClickedPosition; + private Boolean hasBasePotionType; + /** + * Initializes the Bukkit_v1_20 adapter with 1.20-specific block groups and mappings. + * Sets up collections of blocks with similar behavior for efficient handling. + */ public Bukkit_v1_20() { - BlockGroup.CONTAINERS = new HashSet<>(Arrays.asList(Material.JUKEBOX, Material.DISPENSER, Material.CHEST, Material.FURNACE, Material.BREWING_STAND, Material.TRAPPED_CHEST, Material.HOPPER, Material.DROPPER, Material.ARMOR_STAND, Material.ITEM_FRAME, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.SMOKER, Material.LECTERN, Material.CHISELED_BOOKSHELF, Material.DECORATED_POT)); - BlockGroup.UPDATE_STATE = new HashSet<>(Arrays.asList(Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.RAIL, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FURNACE, Material.BLAST_FURNACE, Material.SMOKER, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.GLOWSTONE, Material.JACK_O_LANTERN, Material.REPEATER, Material.REDSTONE_LAMP, Material.BEACON, Material.COMPARATOR, Material.DAYLIGHT_DETECTOR, Material.REDSTONE_BLOCK, Material.HOPPER, Material.CHEST, Material.TRAPPED_CHEST, Material.ACTIVATOR_RAIL, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.SHROOMLIGHT, Material.RESPAWN_ANCHOR, Material.CRYING_OBSIDIAN, Material.TARGET, Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER, Material.CAVE_VINES, Material.CAVE_VINES_PLANT, Material.GLOW_LICHEN, Material.LIGHT, Material.LAVA_CAULDRON, Material.CHISELED_BOOKSHELF)); + initializeBlockGroups(); + initializeTaggedBlocks(); + } + /** + * Initializes the block groups specific to Minecraft 1.20. + */ + private void initializeBlockGroups() { + BlockGroup.CONTAINERS = new HashSet<>(Arrays.asList(Material.JUKEBOX, Material.DISPENSER, Material.CHEST, Material.FURNACE, Material.BREWING_STAND, Material.TRAPPED_CHEST, Material.HOPPER, Material.DROPPER, Material.ARMOR_STAND, Material.ITEM_FRAME, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.SMOKER, Material.LECTERN, Material.CHISELED_BOOKSHELF, Material.DECORATED_POT)); + + BlockGroup.UPDATE_STATE = new HashSet<>(Arrays.asList(Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.RAIL, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FURNACE, Material.BLAST_FURNACE, Material.SMOKER, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.GLOWSTONE, Material.JACK_O_LANTERN, Material.REPEATER, Material.REDSTONE_LAMP, Material.BEACON, Material.COMPARATOR, Material.DAYLIGHT_DETECTOR, Material.REDSTONE_BLOCK, Material.HOPPER, Material.CHEST, Material.TRAPPED_CHEST, Material.ACTIVATOR_RAIL, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.SHROOMLIGHT, Material.RESPAWN_ANCHOR, Material.CRYING_OBSIDIAN, Material.TARGET, Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER, Material.CAVE_VINES, Material.CAVE_VINES_PLANT, Material.GLOW_LICHEN, Material.LIGHT, Material.LAVA_CAULDRON, Material.CHISELED_BOOKSHELF)); + } + + /** + * Initializes blocks based on Bukkit Tags for 1.20. + */ + private void initializeTaggedBlocks() { + // Clear and update button blocks from tag BlockGroup.BUTTONS.clear(); BlockGroup.BUTTONS.addAll(Tag.BUTTONS.getValues()); + + // Clear and update pressure plate blocks from tag BlockGroup.PRESSURE_PLATES.clear(); BlockGroup.PRESSURE_PLATES.addAll(Tag.PRESSURE_PLATES.getValues()); - for (Material value : Tag.DOORS.getValues()) { - if (!BlockGroup.DOORS.contains(value)) { - BlockGroup.DOORS.add(value); - } - } - for (Material value : Tag.FENCE_GATES.getValues()) { - if (!BlockGroup.INTERACT_BLOCKS.contains(value)) { - BlockGroup.INTERACT_BLOCKS.add(value); - } - if (!BlockGroup.SAFE_INTERACT_BLOCKS.contains(value)) { - BlockGroup.SAFE_INTERACT_BLOCKS.add(value); - } - } - for (Material value : Tag.WOODEN_TRAPDOORS.getValues()) { - if (!BlockGroup.INTERACT_BLOCKS.contains(value)) { - BlockGroup.INTERACT_BLOCKS.add(value); - } - if (!BlockGroup.SAFE_INTERACT_BLOCKS.contains(value)) { - BlockGroup.SAFE_INTERACT_BLOCKS.add(value); - } - } - for (Material value : Tag.CEILING_HANGING_SIGNS.getValues()) { - if (!BlockGroup.TRACK_BOTTOM.contains(value)) { - BlockGroup.TRACK_BOTTOM.add(value); - } - } - for (Material value : Tag.WALL_SIGNS.getValues()) { - if (!BlockGroup.TRACK_SIDE.contains(value)) { - BlockGroup.TRACK_SIDE.add(value); - } - } - for (Material value : Tag.SAPLINGS.getValues()) { - if (!BlockGroup.TRACK_TOP.contains(value)) { - BlockGroup.TRACK_TOP.add(value); - } - if (!BlockGroup.NON_ATTACHABLE.contains(value)) { - BlockGroup.NON_ATTACHABLE.add(value); - } - } - for (Material value : Tag.FLOWERS.getValues()) { - if (!BlockGroup.TRACK_TOP.contains(value)) { - BlockGroup.TRACK_TOP.add(value); - } - if (!BlockGroup.NON_ATTACHABLE.contains(value)) { - BlockGroup.NON_ATTACHABLE.add(value); - } - } + // Add all doors from tag + addMissingTaggedBlocks(Tag.DOORS.getValues(), BlockGroup.DOORS); + + // Add all fence gates to interaction blocks + addMissingTaggedBlocks(Tag.FENCE_GATES.getValues(), BlockGroup.INTERACT_BLOCKS); + addMissingTaggedBlocks(Tag.FENCE_GATES.getValues(), BlockGroup.SAFE_INTERACT_BLOCKS); + + // Add all wooden trapdoors to interaction blocks + addMissingTaggedBlocks(Tag.WOODEN_TRAPDOORS.getValues(), BlockGroup.INTERACT_BLOCKS); + addMissingTaggedBlocks(Tag.WOODEN_TRAPDOORS.getValues(), BlockGroup.SAFE_INTERACT_BLOCKS); + + // Add hanging signs to bottom-tracked blocks + addMissingTaggedBlocks(Tag.CEILING_HANGING_SIGNS.getValues(), BlockGroup.TRACK_BOTTOM); + + // Add wall signs to side-tracked blocks + addMissingTaggedBlocks(Tag.WALL_SIGNS.getValues(), BlockGroup.TRACK_SIDE); + + // Add saplings to top-tracked and non-attachable blocks + addMissingTaggedBlocks(Tag.SAPLINGS.getValues(), BlockGroup.TRACK_TOP); + addMissingTaggedBlocks(Tag.SAPLINGS.getValues(), BlockGroup.NON_ATTACHABLE); + + // Add flowers to top-tracked and non-attachable blocks + addMissingTaggedBlocks(Tag.FLOWERS.getValues(), BlockGroup.TRACK_TOP); + addMissingTaggedBlocks(Tag.FLOWERS.getValues(), BlockGroup.NON_ATTACHABLE); + + // Add signs (except wall signs) to top-tracked blocks for (Material value : Tag.SIGNS.getValues()) { if (!Tag.WALL_SIGNS.isTagged(value) && !BlockGroup.TRACK_TOP.contains(value)) { BlockGroup.TRACK_TOP.add(value); @@ -89,48 +99,50 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { } } + /** + * Helper method to add missing blocks from a tag to a block group. + * + * @param taggedBlocks + * The collection of blocks from a tag + * @param targetGroup + * The block group to add missing blocks to + */ + private void addMissingTaggedBlocks(Iterable taggedBlocks, Set targetGroup) { + for (Material value : taggedBlocks) { + if (!targetGroup.contains(value)) { + targetGroup.add(value); + } + } + } + @Override public void setGlowing(Sign sign, boolean isFront, boolean isGlowing) { - if (isFront) { - sign.getSide(Side.FRONT).setGlowingText(isGlowing); - } - else { - sign.getSide(Side.BACK).setGlowingText(isGlowing); - } + Side side = isFront ? Side.FRONT : Side.BACK; + sign.getSide(side).setGlowingText(isGlowing); } @Override public String parseLegacyName(String name) { switch (name) { case "GRASS_PATH": - name = "DIRT_PATH"; - break; + return "DIRT_PATH"; case "GRASS": - name = "SHORT_GRASS"; - break; + return "SHORT_GRASS"; case "SCUTE": - name = "TURTLE_SCUTE"; - break; + return "TURTLE_SCUTE"; default: - break; + // Fallback until this method is moved up into v1_21 + if ("SHORT_GRASS".equals(name) && Material.getMaterial(name) == null) { + return "GRASS"; + } + return name; } - - // fallback until this method is moved up into v1_21 - if (name.equals("SHORT_GRASS") && Material.getMaterial(name) == null) { - name = "GRASS"; - } - - return name; } @Override public void setColor(Sign sign, boolean isFront, int color) { - if (isFront) { - sign.getSide(Side.FRONT).setColor(DyeColor.getByColor(Color.fromRGB(color))); - } - else { - sign.getSide(Side.BACK).setColor(DyeColor.getByColor(Color.fromRGB(color))); - } + Side side = isFront ? Side.FRONT : Side.BACK; + sign.getSide(side).setColor(DyeColor.getByColor(Color.fromRGB(color))); } @Override @@ -140,22 +152,14 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { @Override public int getColor(Sign sign, boolean isFront) { - if (isFront) { - return sign.getSide(Side.FRONT).getColor().getColor().asRGB(); - } - else { - return sign.getSide(Side.BACK).getColor().getColor().asRGB(); - } + Side side = isFront ? Side.FRONT : Side.BACK; + return sign.getSide(side).getColor().getColor().asRGB(); } @Override public boolean isGlowing(Sign sign, boolean isFront) { - if (isFront) { - return sign.getSide(Side.FRONT).isGlowingText(); - } - else { - return sign.getSide(Side.BACK).isGlowingText(); - } + Side side = isFront ? Side.FRONT : Side.BACK; + return sign.getSide(side).isGlowingText(); } @Override @@ -167,24 +171,18 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { public Material getPlantSeeds(Material material) { switch (material) { case WHEAT: - material = Material.WHEAT_SEEDS; - break; + return Material.WHEAT_SEEDS; case PUMPKIN_STEM: - material = Material.PUMPKIN_SEEDS; - break; + return Material.PUMPKIN_SEEDS; case MELON_STEM: - material = Material.MELON_SEEDS; - break; + return Material.MELON_SEEDS; case BEETROOTS: - material = Material.BEETROOT_SEEDS; - break; + return Material.BEETROOT_SEEDS; case TORCHFLOWER_CROP: - material = Material.TORCHFLOWER_SEEDS; - break; + return Material.TORCHFLOWER_SEEDS; default: + return material; } - - return material; } @Override @@ -217,14 +215,17 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { try { if (hasClickedPosition == null) { hasClickedPosition = true; - PlayerInteractEvent.class.getMethod("getClickedPosition"); // Bukkit 1.20.1+ + // Check if getClickedPosition method exists (Bukkit 1.20.1+) + PlayerInteractEvent.class.getMethod("getClickedPosition"); } else if (Boolean.FALSE.equals(hasClickedPosition)) { - return null; + return null; // Method doesn't exist, return null } - ChiseledBookshelf chiseledBookshelf = (ChiseledBookshelf) blockState; - ItemStack book = chiseledBookshelf.getInventory().getItem(chiseledBookshelf.getSlot(event.getClickedPosition())); + ChiseledBookshelf bookshelf = (ChiseledBookshelf) blockState; + int slot = bookshelf.getSlot(event.getClickedPosition()); + ItemStack book = bookshelf.getInventory().getItem(slot); + return book == null ? new ItemStack(Material.AIR) : book; } catch (Exception e) { @@ -245,9 +246,7 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { @Override public void setLine(Sign sign, int line, String string) { - if (string == null) { - string = ""; - } + string = string == null ? "" : string; if (line < 4) { sign.getSide(Side.FRONT).setLine(line, string); @@ -267,22 +266,27 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { try { if (hasBasePotionType == null) { hasBasePotionType = true; - Arrow.class.getMethod("getBasePotionType"); // Bukkit 1.20.2+ + // Check if getBasePotionType method exists (Bukkit 1.20.2+) + Arrow.class.getMethod("getBasePotionType"); } else if (Boolean.FALSE.equals(hasBasePotionType)) { return super.getArrowMeta(arrow, itemStack); } + // Apply potion effects to the arrow PotionType potionType = arrow.getBasePotionType(); Color color = arrow.getColor(); + if (potionType != null || color != null) { itemStack = new ItemStack(Material.TIPPED_ARROW); PotionMeta meta = (PotionMeta) itemStack.getItemMeta(); meta.setBasePotionType(potionType); meta.setColor(color); + for (PotionEffect effect : arrow.getCustomEffects()) { meta.addCustomEffect(effect, false); } + itemStack.setItemMeta(meta); } @@ -293,5 +297,4 @@ public class Bukkit_v1_20 extends Bukkit_v1_19 { return super.getArrowMeta(arrow, itemStack); } } - } diff --git a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java index 09f5cf0..c97319f 100644 --- a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java +++ b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java @@ -2,6 +2,7 @@ package net.coreprotect.bukkit; import java.util.Arrays; import java.util.HashSet; +import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.Keyed; @@ -12,27 +13,79 @@ import org.bukkit.entity.EntityType; import net.coreprotect.model.BlockGroup; +/** + * Bukkit adapter implementation for Minecraft 1.21. + * Provides version-specific implementations for the BukkitInterface + * to handle features introduced in the 1.21 update, including: + * - New block types (crafter) + * - Registry handling for named objects + * - Updated interaction blocks + */ public class Bukkit_v1_21 extends Bukkit_v1_20 implements BukkitInterface { + /** + * Initializes the Bukkit_v1_21 adapter with 1.21-specific block groups and mappings. + * Sets up collections of blocks with similar behavior for efficient handling. + */ public Bukkit_v1_21() { - BlockGroup.CONTAINERS = new HashSet<>(Arrays.asList(Material.JUKEBOX, Material.DISPENSER, Material.CHEST, Material.FURNACE, Material.BREWING_STAND, Material.TRAPPED_CHEST, Material.HOPPER, Material.DROPPER, Material.ARMOR_STAND, Material.ITEM_FRAME, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.SMOKER, Material.LECTERN, Material.CHISELED_BOOKSHELF, Material.DECORATED_POT, Material.CRAFTER)); - BlockGroup.INTERACT_BLOCKS = new HashSet<>(Arrays.asList(Material.SPRUCE_FENCE_GATE, Material.BIRCH_FENCE_GATE, Material.JUNGLE_FENCE_GATE, Material.DARK_OAK_FENCE_GATE, Material.MANGROVE_FENCE_GATE, Material.ACACIA_FENCE_GATE, Material.DISPENSER, Material.NOTE_BLOCK, Material.CHEST, Material.FURNACE, Material.LEVER, Material.REPEATER, Material.MANGROVE_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR, Material.DARK_OAK_TRAPDOOR, Material.JUNGLE_TRAPDOOR, Material.SPRUCE_TRAPDOOR, Material.OAK_TRAPDOOR, Material.OAK_FENCE_GATE, Material.BREWING_STAND, Material.ANVIL, Material.CHIPPED_ANVIL, Material.DAMAGED_ANVIL, Material.ENDER_CHEST, Material.TRAPPED_CHEST, Material.COMPARATOR, Material.HOPPER, Material.DROPPER, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.GRINDSTONE, Material.LOOM, Material.SMOKER, Material.CRAFTING_TABLE, Material.CARTOGRAPHY_TABLE, Material.ENCHANTING_TABLE, Material.SMITHING_TABLE, Material.STONECUTTER, Material.CRIMSON_FENCE_GATE, Material.WARPED_FENCE_GATE, Material.CRIMSON_TRAPDOOR, Material.WARPED_TRAPDOOR, Material.CRAFTER)); - BlockGroup.UPDATE_STATE = new HashSet<>(Arrays.asList(Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.RAIL, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FURNACE, Material.BLAST_FURNACE, Material.SMOKER, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.GLOWSTONE, Material.JACK_O_LANTERN, Material.REPEATER, Material.REDSTONE_LAMP, Material.BEACON, Material.COMPARATOR, Material.DAYLIGHT_DETECTOR, Material.REDSTONE_BLOCK, Material.HOPPER, Material.CHEST, Material.TRAPPED_CHEST, Material.ACTIVATOR_RAIL, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.SHROOMLIGHT, Material.RESPAWN_ANCHOR, Material.CRYING_OBSIDIAN, Material.TARGET, Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER, Material.CAVE_VINES, Material.CAVE_VINES_PLANT, Material.GLOW_LICHEN, Material.LIGHT, Material.LAVA_CAULDRON, Material.CHISELED_BOOKSHELF, Material.CRAFTER)); + initializeBlockGroups(); + initializeTrapdoorBlocks(); + } + /** + * Initializes the block groups specific to Minecraft 1.21. + * Updates container, interaction, and update state blocks with new 1.21 blocks. + */ + private void initializeBlockGroups() { + // Container blocks in 1.21 (added CRAFTER) + BlockGroup.CONTAINERS = new HashSet<>(Arrays.asList(Material.JUKEBOX, Material.DISPENSER, Material.CHEST, Material.FURNACE, Material.BREWING_STAND, Material.TRAPPED_CHEST, Material.HOPPER, Material.DROPPER, Material.ARMOR_STAND, Material.ITEM_FRAME, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.SMOKER, Material.LECTERN, Material.CHISELED_BOOKSHELF, Material.DECORATED_POT, Material.CRAFTER)); + + // Interaction blocks in 1.21 (comprehensive list including CRAFTER) + BlockGroup.INTERACT_BLOCKS = new HashSet<>(Arrays.asList(Material.SPRUCE_FENCE_GATE, Material.BIRCH_FENCE_GATE, Material.JUNGLE_FENCE_GATE, Material.DARK_OAK_FENCE_GATE, Material.MANGROVE_FENCE_GATE, Material.ACACIA_FENCE_GATE, Material.DISPENSER, Material.NOTE_BLOCK, Material.CHEST, Material.FURNACE, Material.LEVER, Material.REPEATER, Material.MANGROVE_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR, Material.DARK_OAK_TRAPDOOR, Material.JUNGLE_TRAPDOOR, Material.SPRUCE_TRAPDOOR, Material.OAK_TRAPDOOR, Material.OAK_FENCE_GATE, Material.BREWING_STAND, Material.ANVIL, Material.CHIPPED_ANVIL, Material.DAMAGED_ANVIL, Material.ENDER_CHEST, Material.TRAPPED_CHEST, Material.COMPARATOR, Material.HOPPER, Material.DROPPER, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.BARREL, Material.BLAST_FURNACE, Material.GRINDSTONE, Material.LOOM, Material.SMOKER, Material.CRAFTING_TABLE, Material.CARTOGRAPHY_TABLE, Material.ENCHANTING_TABLE, Material.SMITHING_TABLE, Material.STONECUTTER, Material.CRIMSON_FENCE_GATE, Material.WARPED_FENCE_GATE, Material.CRIMSON_TRAPDOOR, Material.WARPED_TRAPDOOR, Material.CRAFTER)); + + // Update state blocks in 1.21 (added CRAFTER to redstone responsive blocks) + BlockGroup.UPDATE_STATE = new HashSet<>(Arrays.asList(Material.TORCH, Material.WALL_TORCH, Material.REDSTONE_WIRE, Material.RAIL, Material.POWERED_RAIL, Material.DETECTOR_RAIL, Material.FURNACE, Material.BLAST_FURNACE, Material.SMOKER, Material.LEVER, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.GLOWSTONE, Material.JACK_O_LANTERN, Material.REPEATER, Material.REDSTONE_LAMP, Material.BEACON, Material.COMPARATOR, Material.DAYLIGHT_DETECTOR, Material.REDSTONE_BLOCK, Material.HOPPER, Material.CHEST, Material.TRAPPED_CHEST, Material.ACTIVATOR_RAIL, Material.SOUL_TORCH, Material.SOUL_WALL_TORCH, Material.SHROOMLIGHT, Material.RESPAWN_ANCHOR, Material.CRYING_OBSIDIAN, Material.TARGET, Material.SMALL_AMETHYST_BUD, Material.MEDIUM_AMETHYST_BUD, Material.LARGE_AMETHYST_BUD, Material.AMETHYST_CLUSTER, Material.CAVE_VINES, Material.CAVE_VINES_PLANT, Material.GLOW_LICHEN, Material.LIGHT, Material.LAVA_CAULDRON, Material.CHISELED_BOOKSHELF, Material.CRAFTER)); + } + + /** + * Initializes trapdoor blocks for interaction handling. + * Excludes iron trapdoors as they cannot be directly interacted with. + */ + private void initializeTrapdoorBlocks() { for (Material value : Tag.TRAPDOORS.getValues()) { + // Iron trapdoors are not directly interactable if (value == Material.IRON_TRAPDOOR) { continue; } - if (!BlockGroup.INTERACT_BLOCKS.contains(value)) { - BlockGroup.INTERACT_BLOCKS.add(value); - } - if (!BlockGroup.SAFE_INTERACT_BLOCKS.contains(value)) { - BlockGroup.SAFE_INTERACT_BLOCKS.add(value); - } + // Add to interaction blocks if not already present + addToBlockGroupIfMissing(value, BlockGroup.INTERACT_BLOCKS); + addToBlockGroupIfMissing(value, BlockGroup.SAFE_INTERACT_BLOCKS); } } + /** + * Helper method to add a block to a block group if it's not already present. + * + * @param block + * The block to add + * @param group + * The group to add the block to + */ + private void addToBlockGroupIfMissing(Material block, Set group) { + if (!group.contains(block)) { + group.add(block); + } + } + + /** + * Gets the EntityType corresponding to a Material. + * Maps Material to its equivalent EntityType for entity handling. + * + * @param material + * The material to convert + * @return The corresponding EntityType, or UNKNOWN if not mappable + */ @Override public EntityType getEntityType(Material material) { switch (material) { @@ -43,17 +96,34 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 implements BukkitInterface { } } + /** + * Gets a registry key string from a keyed object. + * Used for serializing objects that implement Keyed. + * + * @param value + * The keyed object + * @return The string representation of the registry key + */ @Override public Object getRegistryKey(Object value) { return ((Keyed) value).getKey().toString(); } + /** + * Gets a registry value from a key string and class. + * Used for deserializing registry objects. + * + * @param key + * The registry key as a string + * @param tClass + * The class of the registry + * @return The registry value + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Object getRegistryValue(String key, Object tClass) { NamespacedKey namespacedKey = NamespacedKey.fromString(key); // return RegistryAccess.registryAccess().getRegistry(RegistryKey.CAT_VARIANT).get((NamespacedKey)value); return Bukkit.getRegistry((Class) tClass).get(namespacedKey); - } - }