diff --git a/patches/api/0156-Add-Material-Tags.patch b/patches/api/0156-Add-Material-Tags.patch index 3c306dc784..703b063034 100644 --- a/patches/api/0156-Add-Material-Tags.patch +++ b/patches/api/0156-Add-Material-Tags.patch @@ -113,10 +113,10 @@ index 0000000000000000000000000000000000000000..a02a02aa0c87e0f0ed9e509e4dcab015 +} diff --git a/src/main/java/com/destroystokyo/paper/MaterialTags.java b/src/main/java/com/destroystokyo/paper/MaterialTags.java new file mode 100644 -index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d29b5066a9 +index 0000000000000000000000000000000000000000..f5ae132cef01666bacda11422c0b73dd585fea27 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/MaterialTags.java -@@ -0,0 +1,652 @@ +@@ -0,0 +1,655 @@ +/* + * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License + * @@ -149,6 +149,9 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 +/** + * Represents a collection tags to identify materials that share common properties. + * Will map to minecraft for missing tags, as well as custom ones that may be useful. ++ *

++ * All tags in this class are unmodifiable, attempting to modify them will throw an ++ * {@link UnsupportedOperationException}. + */ +@SuppressWarnings({"NonFinalUtilityClass", "unused", "WeakerAccess"}) +public class MaterialTags { @@ -159,94 +162,94 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + } + public static final MaterialSetTag ARROWS = new MaterialSetTag(keyFor("arrows")) + .endsWith("ARROW") -+ .ensureSize("ARROWS", 3); ++ .ensureSize("ARROWS", 3).lock(); + + /** + * Covers all colors of beds. + */ + public static final MaterialSetTag BEDS = new MaterialSetTag(keyFor("beds")) + .endsWith("_BED") -+ .ensureSize("BEDS", 16); ++ .ensureSize("BEDS", 16).lock(); + + /** + * Covers all bucket items. + */ + public static final MaterialSetTag BUCKETS = new MaterialSetTag(keyFor("buckets")) + .endsWith("BUCKET") -+ .ensureSize("BUCKETS", 10); ++ .ensureSize("BUCKETS", 10).lock(); + + /** + * Covers coal and charcoal. + */ + public static final MaterialSetTag COALS = new MaterialSetTag(keyFor("coals")) -+ .add(Material.COAL, Material.CHARCOAL); ++ .add(Material.COAL, Material.CHARCOAL).lock(); + + /** + * Covers both cobblestone wall variants. + */ + public static final MaterialSetTag COBBLESTONE_WALLS = new MaterialSetTag(keyFor("cobblestone_walls")) + .endsWith("COBBLESTONE_WALL") -+ .ensureSize("COBBLESTONE_WALLS", 2); ++ .ensureSize("COBBLESTONE_WALLS", 2).lock(); + + /** + * Covers both cobblestone and mossy Cobblestone. + */ + public static final MaterialSetTag COBBLESTONES = new MaterialSetTag(keyFor("cobblestones")) -+ .add(Material.COBBLESTONE, Material.MOSSY_COBBLESTONE); ++ .add(Material.COBBLESTONE, Material.MOSSY_COBBLESTONE).lock(); + + /** + * Covers all colors of concrete. + */ + public static final MaterialSetTag CONCRETES = new MaterialSetTag(keyFor("concretes")) + .endsWith("_CONCRETE") -+ .ensureSize("CONCRETES", 16); ++ .ensureSize("CONCRETES", 16).lock(); + + /** + * Covers all colors of concrete powder. + */ + public static final MaterialSetTag CONCRETE_POWDER = new MaterialSetTag(keyFor("concrete_powder")) + .endsWith("_CONCRETE_POWDER") -+ .ensureSize("CONCRETE_POWDER", 16); ++ .ensureSize("CONCRETE_POWDER", 16).lock(); + + /** + * Covers the two types of cooked fish. + */ + public static final MaterialSetTag COOKED_FISH = new MaterialSetTag(keyFor("cooked_fish")) -+ .add(Material.COOKED_COD, Material.COOKED_SALMON); ++ .add(Material.COOKED_COD, Material.COOKED_SALMON).lock(); + + /** + * Covers all variants of doors. + */ + public static final MaterialSetTag DOORS = new MaterialSetTag(keyFor("doors")) + .endsWith("_DOOR") -+ .ensureSize("DOORS", 9); ++ .ensureSize("DOORS", 9).lock(); + + /** + * Covers all dyes. + */ + public static final MaterialSetTag DYES = new MaterialSetTag(keyFor("dyes")) + .endsWith("_DYE") -+ .ensureSize("DYES", 16); ++ .ensureSize("DYES", 16).lock(); + + /** + * Covers all variants of gates. + */ + public static final MaterialSetTag FENCE_GATES = new MaterialSetTag(keyFor("fence_gates")) + .endsWith("_GATE") -+ .ensureSize("FENCE_GATES", 8); ++ .ensureSize("FENCE_GATES", 8).lock(); + + /** + * Covers all variants of fences. + */ + public static final MaterialSetTag FENCES = new MaterialSetTag(keyFor("fences")) + .endsWith("_FENCE") -+ .ensureSize("FENCES", 9); ++ .ensureSize("FENCES", 9).lock(); + + /** + * Covers all variants of fish buckets. + */ + public static final MaterialSetTag FISH_BUCKETS = new MaterialSetTag(keyFor("fish_buckets")) -+ .add(Material.COD_BUCKET, Material.PUFFERFISH_BUCKET, Material.SALMON_BUCKET, Material.TROPICAL_FISH_BUCKET); ++ .add(Material.COD_BUCKET, Material.PUFFERFISH_BUCKET, Material.SALMON_BUCKET, Material.TROPICAL_FISH_BUCKET).lock(); + + /** + * Covers the non-colored glass and 16 stained glass (not panes). @@ -254,21 +257,21 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag GLASS = new MaterialSetTag(keyFor("glass")) + .endsWith("_GLASS") + .add(Material.GLASS) -+ .ensureSize("GLASS", 18); ++ .ensureSize("GLASS", 18).lock(); + + /** + * Covers the non-colored glass panes and stained glass panes (panes only). + */ + public static final MaterialSetTag GLASS_PANES = new MaterialSetTag(keyFor("glass_panes")) + .endsWith("GLASS_PANE") -+ .ensureSize("GLASS_PANES", 17); ++ .ensureSize("GLASS_PANES", 17).lock(); + + /** + * Covers all glazed terracotta blocks. + */ + public static final MaterialSetTag GLAZED_TERRACOTTA = new MaterialSetTag(keyFor("glazed_terracotta")) + .endsWith("GLAZED_TERRACOTTA") -+ .ensureSize("GLAZED_TERRACOTTA", 16); ++ .ensureSize("GLAZED_TERRACOTTA", 16).lock(); + + /** + * Covers the colors of stained terracotta. @@ -277,35 +280,35 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + .endsWith("TERRACOTTA") + .not(Material.TERRACOTTA) + .notEndsWith("GLAZED_TERRACOTTA") -+ .ensureSize("STAINED_TERRACOTTA", 16); ++ .ensureSize("STAINED_TERRACOTTA", 16).lock(); + + /** + * Covers terracotta along with the stained variants. + */ + public static final MaterialSetTag TERRACOTTA = new MaterialSetTag(keyFor("terracotta")) + .endsWith("TERRACOTTA") -+ .ensureSize("TERRACOTTA", 33); ++ .ensureSize("TERRACOTTA", 33).lock(); + + /** + * Covers both golden apples. + */ + public static final MaterialSetTag GOLDEN_APPLES = new MaterialSetTag(keyFor("golden_apples")) + .endsWith("GOLDEN_APPLE") -+ .ensureSize("GOLDEN_APPLES", 2); ++ .ensureSize("GOLDEN_APPLES", 2).lock(); + + /** + * Covers the variants of horse armor. + */ + public static final MaterialSetTag HORSE_ARMORS = new MaterialSetTag(keyFor("horse_armors")) + .endsWith("_HORSE_ARMOR") -+ .ensureSize("HORSE_ARMORS", 4); ++ .ensureSize("HORSE_ARMORS", 4).lock(); + + /** + * Covers the variants of infested blocks. + */ + public static final MaterialSetTag INFESTED_BLOCKS = new MaterialSetTag(keyFor("infested_blocks")) + .startsWith("INFESTED_") -+ .ensureSize("INFESTED_BLOCKS", 7); ++ .ensureSize("INFESTED_BLOCKS", 7).lock(); + + /** + * Covers the variants of mushroom blocks. @@ -313,19 +316,19 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag MUSHROOM_BLOCKS = new MaterialSetTag(keyFor("mushroom_blocks")) + .endsWith("MUSHROOM_BLOCK") + .add(Material.MUSHROOM_STEM) -+ .ensureSize("MUSHROOM_BLOCKS", 3); ++ .ensureSize("MUSHROOM_BLOCKS", 3).lock(); + + /** + * Covers all mushrooms. + */ + public static final MaterialSetTag MUSHROOMS = new MaterialSetTag(keyFor("mushrooms")) -+ .add(Material.BROWN_MUSHROOM, Material.RED_MUSHROOM); ++ .add(Material.BROWN_MUSHROOM, Material.RED_MUSHROOM).lock(); + + /** + * Covers all music disc items. + */ + public static final MaterialSetTag MUSIC_DISCS = new MaterialSetTag(keyFor("music_discs")) -+ .startsWith("MUSIC_DISC_"); ++ .startsWith("MUSIC_DISC_").lock(); + + /** + * Covers all ores. @@ -333,91 +336,91 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag ORES = new MaterialSetTag(keyFor("ores")) + .add(Material.ANCIENT_DEBRIS) + .endsWith("_ORE") -+ .ensureSize("ORES", 19); ++ .ensureSize("ORES", 19).lock(); + + /** + * Covers all piston typed items and blocks including the piston head and moving piston. + */ + public static final MaterialSetTag PISTONS = new MaterialSetTag(keyFor("pistons")) + .contains("PISTON") -+ .ensureSize("PISTONS", 4); ++ .ensureSize("PISTONS", 4).lock(); + + /** + * Covers all potato items. + */ + public static final MaterialSetTag POTATOES = new MaterialSetTag(keyFor("potatoes")) + .endsWith("POTATO") -+ .ensureSize("POTATOES", 3); ++ .ensureSize("POTATOES", 3).lock(); + + /** + * Covers all wooden pressure plates and the weighted pressure plates and the stone pressure plate. + */ + public static final MaterialSetTag PRESSURE_PLATES = new MaterialSetTag(keyFor("pressure_plates")) + .endsWith("_PRESSURE_PLATE") -+ .ensureSize("PRESSURE_PLATES", 12); ++ .ensureSize("PRESSURE_PLATES", 12).lock(); + + /** + * Covers the variants of prismarine blocks. + */ + public static final MaterialSetTag PRISMARINE = new MaterialSetTag(keyFor("prismarine")) -+ .add(Material.PRISMARINE, Material.PRISMARINE_BRICKS, Material.DARK_PRISMARINE); ++ .add(Material.PRISMARINE, Material.PRISMARINE_BRICKS, Material.DARK_PRISMARINE).lock(); + + /** + * Covers the variants of prismarine slabs. + */ + public static final MaterialSetTag PRISMARINE_SLABS = new MaterialSetTag(keyFor("prismarine_slabs")) -+ .add(Material.PRISMARINE_SLAB, Material.PRISMARINE_BRICK_SLAB, Material.DARK_PRISMARINE_SLAB); ++ .add(Material.PRISMARINE_SLAB, Material.PRISMARINE_BRICK_SLAB, Material.DARK_PRISMARINE_SLAB).lock(); + + /** + * Covers the variants of prismarine stairs. + */ + public static final MaterialSetTag PRISMARINE_STAIRS = new MaterialSetTag(keyFor("prismarine_stairs")) -+ .add(Material.PRISMARINE_STAIRS, Material.PRISMARINE_BRICK_STAIRS, Material.DARK_PRISMARINE_STAIRS); ++ .add(Material.PRISMARINE_STAIRS, Material.PRISMARINE_BRICK_STAIRS, Material.DARK_PRISMARINE_STAIRS).lock(); + + /** + * Covers the variants of pumpkins. + */ + public static final MaterialSetTag PUMPKINS = new MaterialSetTag(keyFor("pumpkins")) -+ .add(Material.CARVED_PUMPKIN, Material.JACK_O_LANTERN, Material.PUMPKIN); ++ .add(Material.CARVED_PUMPKIN, Material.JACK_O_LANTERN, Material.PUMPKIN).lock(); + + /** + * Covers the variants of quartz blocks. + */ + public static final MaterialSetTag QUARTZ_BLOCKS = new MaterialSetTag(keyFor("quartz_blocks")) -+ .add(Material.QUARTZ_BLOCK, Material.QUARTZ_PILLAR, Material.CHISELED_QUARTZ_BLOCK, Material.SMOOTH_QUARTZ); ++ .add(Material.QUARTZ_BLOCK, Material.QUARTZ_PILLAR, Material.CHISELED_QUARTZ_BLOCK, Material.SMOOTH_QUARTZ).lock(); + + /** + * Covers all uncooked fish items. + */ + public static final MaterialSetTag RAW_FISH = new MaterialSetTag(keyFor("raw_fish")) -+ .add(Material.COD, Material.PUFFERFISH, Material.SALMON, Material.TROPICAL_FISH); ++ .add(Material.COD, Material.PUFFERFISH, Material.SALMON, Material.TROPICAL_FISH).lock(); + + /** + * Covers the variants of red sandstone blocks. + */ + public static final MaterialSetTag RED_SANDSTONES = new MaterialSetTag(keyFor("red_sandstones")) + .endsWith("RED_SANDSTONE") -+ .ensureSize("RED_SANDSTONES", 4); ++ .ensureSize("RED_SANDSTONES", 4).lock(); + + /** + * Covers the variants of sandstone blocks. + */ + public static final MaterialSetTag SANDSTONES = new MaterialSetTag(keyFor("sandstones")) -+ .add(Material.SANDSTONE, Material.CHISELED_SANDSTONE, Material.CUT_SANDSTONE, Material.SMOOTH_SANDSTONE); ++ .add(Material.SANDSTONE, Material.CHISELED_SANDSTONE, Material.CUT_SANDSTONE, Material.SMOOTH_SANDSTONE).lock(); + + /** + * Covers sponge and wet sponge. + */ + public static final MaterialSetTag SPONGES = new MaterialSetTag(keyFor("sponges")) + .endsWith("SPONGE") -+ .ensureSize("SPONGES", 2); ++ .ensureSize("SPONGES", 2).lock(); + + /** + * Covers the non-colored and colored shulker boxes. + */ + public static final MaterialSetTag SHULKER_BOXES = new MaterialSetTag(keyFor("shulker_boxes")) + .endsWith("SHULKER_BOX") -+ .ensureSize("SHULKER_BOXES", 17); ++ .ensureSize("SHULKER_BOXES", 17).lock(); + + /** + * Covers zombie, creeper, skeleton, dragon, and player heads. @@ -426,35 +429,35 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + .endsWith("_HEAD") + .endsWith("_SKULL") + .not(Material.PISTON_HEAD) -+ .ensureSize("SKULLS", 12); ++ .ensureSize("SKULLS", 12).lock(); + + /** + * Covers all spawn egg items. + */ + public static final MaterialSetTag SPAWN_EGGS = new MaterialSetTag(keyFor("spawn_eggs")) + .endsWith("_SPAWN_EGG") -+ .ensureSize("SPAWN_EGGS", 67); ++ .ensureSize("SPAWN_EGGS", 67).lock(); + + /** + * Covers all colors of stained glass. + */ + public static final MaterialSetTag STAINED_GLASS = new MaterialSetTag(keyFor("stained_glass")) + .endsWith("_STAINED_GLASS") -+ .ensureSize("STAINED_GLASS", 16); ++ .ensureSize("STAINED_GLASS", 16).lock(); + + /** + * Covers all colors of stained glass panes. + */ + public static final MaterialSetTag STAINED_GLASS_PANES = new MaterialSetTag(keyFor("stained_glass_panes")) + .endsWith("STAINED_GLASS_PANE") -+ .ensureSize("STAINED_GLASS_PANES", 16); ++ .ensureSize("STAINED_GLASS_PANES", 16).lock(); + + /** + * Covers all variants of trapdoors. + */ + public static final MaterialSetTag TRAPDOORS = new MaterialSetTag(keyFor("trapdoors")) + .endsWith("_TRAPDOOR") -+ .ensureSize("TRAPDOORS", 9); ++ .ensureSize("TRAPDOORS", 9).lock(); + + /** + * Covers all wood variants of doors. @@ -462,7 +465,7 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag WOODEN_DOORS = new MaterialSetTag(keyFor("wooden_doors")) + .endsWith("_DOOR") + .not(Material.IRON_DOOR) -+ .ensureSize("WOODEN_DOORS", 8); ++ .ensureSize("WOODEN_DOORS", 8).lock(); + + /** + * Covers all wood variants of fences. @@ -470,7 +473,7 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag WOODEN_FENCES = new MaterialSetTag(keyFor("wooden_fences")) + .endsWith("_FENCE") + .not(Material.NETHER_BRICK_FENCE) -+ .ensureSize("WOODEN_FENCES", 8); ++ .ensureSize("WOODEN_FENCES", 8).lock(); + + /** + * Covers all wood variants of trapdoors. @@ -478,112 +481,112 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag WOODEN_TRAPDOORS = new MaterialSetTag(keyFor("wooden_trapdoors")) + .endsWith("_TRAPDOOR") + .not(Material.IRON_TRAPDOOR) -+ .ensureSize("WOODEN_TRAPDOORS", 8); ++ .ensureSize("WOODEN_TRAPDOORS", 8).lock(); + + /** + * Covers the wood variants of gates. + */ + public static final MaterialSetTag WOODEN_GATES = new MaterialSetTag(keyFor("wooden_gates")) + .endsWith("_GATE") -+ .ensureSize("WOODEN_GATES", 8); ++ .ensureSize("WOODEN_GATES", 8).lock(); + + /** + * Covers the variants of purpur. + */ + public static final MaterialSetTag PURPUR = new MaterialSetTag(keyFor("purpur")) + .startsWith("PURPUR_") -+ .ensureSize("PURPUR", 4); ++ .ensureSize("PURPUR", 4).lock(); + + /** + * Covers the variants of signs. + */ + public static final MaterialSetTag SIGNS = new MaterialSetTag(keyFor("signs")) + .endsWith("_SIGN") -+ .ensureSize("SIGNS", 16); ++ .ensureSize("SIGNS", 16).lock(); + + /** + * Covers the variants of a regular torch. + */ + public static final MaterialSetTag TORCH = new MaterialSetTag(keyFor("torch")) + .add(Material.TORCH, Material.WALL_TORCH) -+ .ensureSize("TORCH", 2); ++ .ensureSize("TORCH", 2).lock(); + + /** + * Covers the variants of a redstone torch. + */ + public static final MaterialSetTag REDSTONE_TORCH = new MaterialSetTag(keyFor("restone_torch")) + .add(Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH) -+ .ensureSize("REDSTONE_TORCH", 2); ++ .ensureSize("REDSTONE_TORCH", 2).lock(); + + /** + * Covers the variants of a soul torch. + */ + public static final MaterialSetTag SOUL_TORCH = new MaterialSetTag(keyFor("soul_torch")) + .add(Material.SOUL_TORCH, Material.SOUL_WALL_TORCH) -+ .ensureSize("SOUL_TORCH", 2); ++ .ensureSize("SOUL_TORCH", 2).lock(); + + /** + * Covers the variants of torches. + */ + public static final MaterialSetTag TORCHES = new MaterialSetTag(keyFor("torches")) + .add(TORCH, REDSTONE_TORCH, SOUL_TORCH) -+ .ensureSize("TORCHES", 6); ++ .ensureSize("TORCHES", 6).lock(); + + /** + * Covers the variants of lanterns. + */ + public static final MaterialSetTag LANTERNS = new MaterialSetTag(keyFor("lanterns")) + .add(Material.LANTERN, Material.SOUL_LANTERN) -+ .ensureSize("LANTERNS", 2); ++ .ensureSize("LANTERNS", 2).lock(); + + /** + * Covers the variants of rails. + */ + public static final MaterialSetTag RAILS = new MaterialSetTag(keyFor("rails")) + .endsWith("RAIL") -+ .ensureSize("RAILS", 4); ++ .ensureSize("RAILS", 4).lock(); + + /** + * Covers the variants of swords. + */ + public static final MaterialSetTag SWORDS = new MaterialSetTag(keyFor("swords")) + .endsWith("_SWORD") -+ .ensureSize("SWORDS", 6); ++ .ensureSize("SWORDS", 6).lock(); + + /** + * Covers the variants of shovels. + */ + public static final MaterialSetTag SHOVELS = new MaterialSetTag(keyFor("shovels")) + .endsWith("_SHOVEL") -+ .ensureSize("SHOVELS", 6); ++ .ensureSize("SHOVELS", 6).lock(); + + /** + * Covers the variants of pickaxes. + */ + public static final MaterialSetTag PICKAXES = new MaterialSetTag(keyFor("pickaxes")) + .endsWith("_PICKAXE") -+ .ensureSize("PICKAXES", 6); ++ .ensureSize("PICKAXES", 6).lock(); + + /** + * Covers the variants of axes. + */ + public static final MaterialSetTag AXES = new MaterialSetTag(keyFor("axes")) + .endsWith("_AXE") -+ .ensureSize("AXES", 6); ++ .ensureSize("AXES", 6).lock(); + + /** + * Covers the variants of hoes. + */ + public static final MaterialSetTag HOES = new MaterialSetTag(keyFor("hoes")) + .endsWith("_HOE") -+ .ensureSize("HOES", 6); ++ .ensureSize("HOES", 6).lock(); + + /** + * Covers the variants of helmets. + */ + public static final MaterialSetTag HELMETS = new MaterialSetTag(keyFor("helmets")) + .endsWith("_HELMET") -+ .ensureSize("HELMETS", 7); ++ .ensureSize("HELMETS", 7).lock(); + + /** + * Covers the variants of items that can be equipped in the helmet slot. @@ -592,14 +595,14 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + .endsWith("_HELMET") + .add(SKULLS) + .add(Material.CARVED_PUMPKIN) -+ .ensureSize("HEAD_EQUIPPABLE", 20); ++ .ensureSize("HEAD_EQUIPPABLE", 20).lock(); + + /** + * Covers the variants of chestplate. + */ + public static final MaterialSetTag CHESTPLATES = new MaterialSetTag(keyFor("chestplates")) + .endsWith("_CHESTPLATE") -+ .ensureSize("CHESTPLATES", 6); ++ .ensureSize("CHESTPLATES", 6).lock(); + + /** + * Covers the variants of items that can be equipped in the chest slot. @@ -607,21 +610,21 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag CHEST_EQUIPPABLE = new MaterialSetTag(keyFor("chest_equippable")) + .endsWith("_CHESTPLATE") + .add(Material.ELYTRA) -+ .ensureSize("CHEST_EQUIPPABLE", 7); ++ .ensureSize("CHEST_EQUIPPABLE", 7).lock(); + + /** + * Covers the variants of leggings. + */ + public static final MaterialSetTag LEGGINGS = new MaterialSetTag(keyFor("leggings")) + .endsWith("_LEGGINGS") -+ .ensureSize("LEGGINGS", 6); ++ .ensureSize("LEGGINGS", 6).lock(); + + /** + * Covers the variants of boots. + */ + public static final MaterialSetTag BOOTS = new MaterialSetTag(keyFor("boots")) + .endsWith("_BOOTS") -+ .ensureSize("BOOTS", 6); ++ .ensureSize("BOOTS", 6).lock(); + + /** + * Covers the variants of bows. @@ -629,28 +632,28 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag BOWS = new MaterialSetTag(keyFor("bows")) + .add(Material.BOW) + .add(Material.CROSSBOW) -+ .ensureSize("BOWS", 2); ++ .ensureSize("BOWS", 2).lock(); + + /** + * Covers the variants of player-throwable projectiles (not requiring a bow or any other "assistance"). + */ + public static final MaterialSetTag THROWABLE_PROJECTILES = new MaterialSetTag(keyFor("throwable_projectiles")) -+ .add(Material.EGG, Material.SNOWBALL, Material.SPLASH_POTION, Material.TRIDENT, Material.ENDER_PEARL, Material.EXPERIENCE_BOTTLE, Material.FIREWORK_ROCKET); ++ .add(Material.EGG, Material.SNOWBALL, Material.SPLASH_POTION, Material.TRIDENT, Material.ENDER_PEARL, Material.EXPERIENCE_BOTTLE, Material.FIREWORK_ROCKET).lock(); + + /** + * Covers materials that can be colored, such as wool, shulker boxes, stained glass etc. + */ + @SuppressWarnings("unchecked") + public static final MaterialSetTag COLORABLE = new MaterialSetTag(keyFor("colorable")) -+ .add(Tag.WOOL, Tag.CARPETS).add(SHULKER_BOXES, STAINED_GLASS, STAINED_GLASS_PANES, CONCRETES, BEDS); -+ //.ensureSize("COLORABLE", 81); unit test don't have the vanilla item tags, so counts don't line up for real ++ .add(Tag.WOOL, Tag.CARPETS).add(SHULKER_BOXES, STAINED_GLASS, STAINED_GLASS_PANES, CONCRETES, BEDS).lock(); ++ //.ensureSize("COLORABLE", 81).lock(); unit test don't have the vanilla item tags, so counts don't line up for real + + /** + * Covers the variants of coral. + */ + public static final MaterialSetTag CORAL = new MaterialSetTag(keyFor("coral")) + .endsWith("_CORAL") -+ .ensureSize("CORAL", 10); ++ .ensureSize("CORAL", 10).lock(); + + /** + * Covers the variants of coral fans. @@ -658,14 +661,14 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag CORAL_FANS = new MaterialSetTag(keyFor("coral_fans")) + .endsWith("_CORAL_FAN") + .endsWith("_CORAL_WALL_FAN") -+ .ensureSize("CORAL_FANS", 20); ++ .ensureSize("CORAL_FANS", 20).lock(); + + /** + * Covers the variants of coral blocks. + */ + public static final MaterialSetTag CORAL_BLOCKS = new MaterialSetTag(keyFor("coral_blocks")) + .endsWith("_CORAL_BLOCK") -+ .ensureSize("CORAL_BLOCKS", 10); ++ .ensureSize("CORAL_BLOCKS", 10).lock(); + + /** + * Covers all items that can be enchanted from the enchantment table or anvil. @@ -673,50 +676,50 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + public static final MaterialSetTag ENCHANTABLE = new MaterialSetTag(keyFor("enchantable")) + .add(PICKAXES, SWORDS, SHOVELS, AXES, HOES, HELMETS, CHEST_EQUIPPABLE, LEGGINGS, BOOTS, BOWS) + .add(Material.TRIDENT, Material.SHIELD, Material.FISHING_ROD, Material.SHEARS, Material.FLINT_AND_STEEL, Material.CARROT_ON_A_STICK, Material.WARPED_FUNGUS_ON_A_STICK) -+ .ensureSize("ENCHANTABLE", 65); ++ .ensureSize("ENCHANTABLE", 65).lock(); + + /** + * Covers the variants of raw ores. + */ + public static final MaterialSetTag RAW_ORES = new MaterialSetTag(keyFor("raw_ores")) -+ .add(Material.RAW_COPPER, Material.RAW_GOLD, Material.RAW_IRON); ++ .add(Material.RAW_COPPER, Material.RAW_GOLD, Material.RAW_IRON).lock(); + + /** + * Covers the variants of deepslate ores. + */ + public static final MaterialSetTag DEEPSLATE_ORES = new MaterialSetTag(keyFor("deepslate_ores")) + .add(material -> material.name().startsWith("DEEPSLATE_") && material.name().endsWith("_ORE")) -+ .ensureSize("DEEPSLATE_ORES", 8); ++ .ensureSize("DEEPSLATE_ORES", 8).lock(); + + /** + * Covers the variants of raw ore blocks. + */ + public static final MaterialSetTag RAW_ORE_BLOCKS = new MaterialSetTag(keyFor("raw_ore_blocks")) -+ .add(Material.RAW_COPPER_BLOCK, Material.RAW_GOLD_BLOCK, Material.RAW_IRON_BLOCK); ++ .add(Material.RAW_COPPER_BLOCK, Material.RAW_GOLD_BLOCK, Material.RAW_IRON_BLOCK).lock(); + + /** + * Covers all oxidized copper blocks. + */ + public static final MaterialSetTag OXIDIZED_COPPER_BLOCKS = new MaterialSetTag(keyFor("oxidized_copper_blocks")) -+ .startsWith("OXIDIZED_").startsWith("WAXED_OXIDIZED_").ensureSize("OXIDIZED_COPPER_BLOCKS", 8); ++ .startsWith("OXIDIZED_").startsWith("WAXED_OXIDIZED_").ensureSize("OXIDIZED_COPPER_BLOCKS", 8).lock(); + + /** + * Covers all weathered copper blocks. + */ + public static final MaterialSetTag WEATHERED_COPPER_BLOCKS = new MaterialSetTag(keyFor("weathered_copper_blocks")) -+ .startsWith("WEATHERED_").startsWith("WAXED_WEATHERED_").ensureSize("WEATHERED_COPPER_BLOCKS", 8); ++ .startsWith("WEATHERED_").startsWith("WAXED_WEATHERED_").ensureSize("WEATHERED_COPPER_BLOCKS", 8).lock(); + + /** + * Covers all exposed copper blocks. + */ + public static final MaterialSetTag EXPOSED_COPPER_BLOCKS = new MaterialSetTag(keyFor("exposed_copper_blocks")) -+ .startsWith("EXPOSED_").startsWith("WAXED_EXPOSED_").ensureSize("EXPOSED_COPPER_BLOCKS", 8); ++ .startsWith("EXPOSED_").startsWith("WAXED_EXPOSED_").ensureSize("EXPOSED_COPPER_BLOCKS", 8).lock(); + + /** + * Covers all un-weathered copper blocks. + */ + public static final MaterialSetTag UNAFFECTED_COPPER_BLOCKS = new MaterialSetTag(keyFor("unaffected_copper_blocks")) -+ .startsWith("CUT_COPPER").startsWith("WAXED_CUT_COPPER").add(Material.COPPER_BLOCK).add(Material.WAXED_COPPER_BLOCK).ensureSize("UNAFFECTED_COPPER_BLOCKS", 8); ++ .startsWith("CUT_COPPER").startsWith("WAXED_CUT_COPPER").add(Material.COPPER_BLOCK).add(Material.WAXED_COPPER_BLOCK).ensureSize("UNAFFECTED_COPPER_BLOCKS", 8).lock(); + + /** + * Covers all waxed copper blocks. @@ -724,7 +727,7 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + * Combine with other copper-related tags to filter is-waxed or not. + */ + public static final MaterialSetTag WAXED_COPPER_BLOCKS = new MaterialSetTag(keyFor("waxed_copper_blocks")) -+ .add(m -> m.name().startsWith("WAXED_") && m.name().contains("COPPER")).ensureSize("WAXED_COPPER_BLOCKS", 16); ++ .add(m -> m.name().startsWith("WAXED_") && m.name().contains("COPPER")).ensureSize("WAXED_COPPER_BLOCKS", 16).lock(); + + /** + * Covers all un-waxed copper blocks. @@ -732,13 +735,13 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + * Combine with other copper-related tags to filter is-un-waxed or not. + */ + public static final MaterialSetTag UNWAXED_COPPER_BLOCKS = new MaterialSetTag(keyFor("unwaxed_copper_blocks")) -+ .contains("CUT_COPPER").endsWith("_COPPER").notContains("WAXED").ensureSize("UNWAXED_COPPER_BLOCKS", 16); ++ .contains("CUT_COPPER").endsWith("_COPPER").notContains("WAXED").ensureSize("UNWAXED_COPPER_BLOCKS", 16).lock(); + + /** + * Covers all copper block variants. + */ + public static final MaterialSetTag COPPER_BLOCKS = new MaterialSetTag(keyFor("copper_blocks")) -+ .add(WAXED_COPPER_BLOCKS).add(UNWAXED_COPPER_BLOCKS).ensureSize("COPPER_BLOCKS", 32); ++ .add(WAXED_COPPER_BLOCKS).add(UNWAXED_COPPER_BLOCKS).ensureSize("COPPER_BLOCKS", 32).lock(); + + /** + * Covers all weathering/waxed states of the plain copper block. @@ -749,32 +752,32 @@ index 0000000000000000000000000000000000000000..4606fcbb4a7e3857a5d74dac96aed4d2 + .contains("EXPOSED_COPPER") + .contains("COPPER_BLOCK") + .not(Material.RAW_COPPER_BLOCK) -+ .ensureSize("FULL_COPPER_BLOCKS", 8); ++ .ensureSize("FULL_COPPER_BLOCKS", 8).lock(); + + /** + * Covers all weathering/waxed states of the cut copper block. + */ + public static final MaterialSetTag CUT_COPPER_BLOCKS = new MaterialSetTag(keyFor("cut_copper_blocks")) -+ .endsWith("CUT_COPPER").ensureSize("CUT_COPPER_BLOCKS", 8); ++ .endsWith("CUT_COPPER").ensureSize("CUT_COPPER_BLOCKS", 8).lock(); + + /** + * Covers all weathering/waxed states of the cut copper stairs. + */ + public static final MaterialSetTag CUT_COPPER_STAIRS = new MaterialSetTag(keyFor("cut_copper_stairs")) -+ .endsWith("CUT_COPPER_STAIRS").ensureSize("CUT_COPPER_STAIRS", 8); ++ .endsWith("CUT_COPPER_STAIRS").ensureSize("CUT_COPPER_STAIRS", 8).lock(); + + /** + * Covers all weathering/waxed states of the cut copper slab. + */ + public static final MaterialSetTag CUT_COPPER_SLABS = new MaterialSetTag(keyFor("cut_copper_slabs")) -+ .endsWith("CUT_COPPER_SLAB").ensureSize("CUT_COPPER_SLABS", 8); ++ .endsWith("CUT_COPPER_SLAB").ensureSize("CUT_COPPER_SLABS", 8).lock(); +} diff --git a/src/main/java/io/papermc/paper/tag/BaseTag.java b/src/main/java/io/papermc/paper/tag/BaseTag.java new file mode 100644 -index 0000000000000000000000000000000000000000..4b8552e4e4c07b197fa9431fa911535b0222561e +index 0000000000000000000000000000000000000000..71484259de4783b861803c48850317eb2d60bda0 --- /dev/null +++ b/src/main/java/io/papermc/paper/tag/BaseTag.java -@@ -0,0 +1,160 @@ +@@ -0,0 +1,180 @@ +package io.papermc.paper.tag; + +import com.google.common.collect.Lists; @@ -796,6 +799,7 @@ index 0000000000000000000000000000000000000000..4b8552e4e4c07b197fa9431fa911535b + protected final NamespacedKey key; + protected final Set tagged; + private final List> globalPredicates; ++ private boolean locked = false; + + public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Predicate filter) { + this(clazz, key); @@ -822,6 +826,21 @@ index 0000000000000000000000000000000000000000..4b8552e4e4c07b197fa9431fa911535b + return (Set) EnumSet.noneOf((Class) enumClass); + } + ++ public @NotNull C lock() { ++ this.locked = true; ++ return (C) this; ++ } ++ ++ public boolean isLocked() { ++ return this.locked; ++ } ++ ++ private void checkLock() { ++ if (this.locked) { ++ throw new UnsupportedOperationException("Tag (" + this.key + ") is locked"); ++ } ++ } ++ + @NotNull + @Override + public NamespacedKey getKey() { @@ -849,12 +868,14 @@ index 0000000000000000000000000000000000000000..4b8552e4e4c07b197fa9431fa911535b + + @NotNull + public C add(@NotNull T...values) { ++ this.checkLock(); + this.tagged.addAll(Lists.newArrayList(values)); + return (C) this; + } + + @NotNull + public C add(@NotNull Collection collection) { ++ this.checkLock(); + this.tagged.addAll(collection); + return (C) this; + } @@ -889,12 +910,14 @@ index 0000000000000000000000000000000000000000..4b8552e4e4c07b197fa9431fa911535b + + @NotNull + public C not(@NotNull T...values) { ++ this.checkLock(); + this.tagged.removeAll(Lists.newArrayList(values)); + return (C) this; + } + + @NotNull + public C not(@NotNull Collection values) { ++ this.checkLock(); + this.tagged.removeAll(values); + return (C) this; + } @@ -985,16 +1008,20 @@ index 0000000000000000000000000000000000000000..c89c4619aaf388197834d98eb95af2f1 +} diff --git a/src/main/java/io/papermc/paper/tag/EntityTags.java b/src/main/java/io/papermc/paper/tag/EntityTags.java new file mode 100644 -index 0000000000000000000000000000000000000000..683688edff2c86d92f6b3e15271c3289b39e42d7 +index 0000000000000000000000000000000000000000..d7eb49a05c3f0cacf285f8995433c5d5e988de0f --- /dev/null +++ b/src/main/java/io/papermc/paper/tag/EntityTags.java -@@ -0,0 +1,50 @@ +@@ -0,0 +1,54 @@ +package io.papermc.paper.tag; + +import org.bukkit.NamespacedKey; + +import static org.bukkit.entity.EntityType.*; + ++/** ++ * All tags in this class are unmodifiable, attempting to modify them will throw an ++ * {@link UnsupportedOperationException}. ++ */ +public class EntityTags { + + private static NamespacedKey keyFor(String key) { @@ -1008,28 +1035,28 @@ index 0000000000000000000000000000000000000000..683688edff2c86d92f6b3e15271c3289 + */ + public static final EntitySetTag UNDEADS = new EntitySetTag(keyFor("undeads")) + .add(DROWNED, HUSK, PHANTOM, SKELETON, SKELETON_HORSE, STRAY, WITHER, WITHER_SKELETON, ZOGLIN, ZOMBIE, ZOMBIE_HORSE, ZOMBIE_VILLAGER, ZOMBIFIED_PIGLIN) -+ .ensureSize("UNDEADS", 13); ++ .ensureSize("UNDEADS", 13).lock(); + + /** + * Covers all horses + */ + public static final EntitySetTag HORSES = new EntitySetTag(keyFor("horses")) + .contains("HORSE") -+ .ensureSize("HORSES", 3); ++ .ensureSize("HORSES", 3).lock(); + + /** + * Covers all minecarts + */ + public static final EntitySetTag MINECARTS = new EntitySetTag(keyFor("minecarts")) + .contains("MINECART") -+ .ensureSize("MINECARTS", 7); ++ .ensureSize("MINECARTS", 7).lock(); + + /** + * Covers mobs that split into smaller mobs + */ + public static final EntitySetTag SPLITTING_MOBS = new EntitySetTag(keyFor("splitting_mobs")) + .add(SLIME, MAGMA_CUBE) -+ .ensureSize("SLIMES", 2); ++ .ensureSize("SLIMES", 2).lock(); + + /** + * Covers all water based mobs @@ -1037,7 +1064,7 @@ index 0000000000000000000000000000000000000000..683688edff2c86d92f6b3e15271c3289 + */ + public static final EntitySetTag WATER_BASED = new EntitySetTag(keyFor("water_based")) + .add(AXOLOTL, DOLPHIN, SQUID, GLOW_SQUID, GUARDIAN, ELDER_GUARDIAN, TURTLE, COD, SALMON, PUFFERFISH, TROPICAL_FISH) -+ .ensureSize("WATER_BASED", 11); ++ .ensureSize("WATER_BASED", 11).lock(); +} diff --git a/src/main/java/org/bukkit/Tag.java b/src/main/java/org/bukkit/Tag.java index 5a25301a81b0e88a4891cbc4710289544d44105c..34d23f53acf00620223731c4fdacffde9cff41a8 100644 @@ -1056,27 +1083,41 @@ index 5a25301a81b0e88a4891cbc4710289544d44105c..34d23f53acf00620223731c4fdacffde public interface Tag extends Keyed { diff --git a/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java new file mode 100644 -index 0000000000000000000000000000000000000000..328c51471dc12e81c1a1b643455337b3fef4d14a +index 0000000000000000000000000000000000000000..f849d8b12a7e3d1606698408ab4bb140a3b370e4 --- /dev/null +++ b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java -@@ -0,0 +1,25 @@ +@@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License + */ + +package com.destroystokyo.paper; + ++import io.papermc.paper.tag.BaseTag; ++import io.papermc.paper.tag.EntityTags; +import org.bukkit.Bukkit; +import org.bukkit.TestServer; ++import org.junit.Before; +import org.junit.Test; + ++import java.lang.reflect.Field; ++import java.lang.reflect.Modifier; ++import java.util.HashSet; ++import java.util.Set; +import java.util.logging.Level; + ++import static org.junit.Assert.assertTrue; ++ +public class MaterialTagsTest { ++ ++ @Before ++ public void before() { ++ TestServer.getInstance(); ++ } ++ + @Test + public void testInitialize() { + try { -+ TestServer.getInstance(); + MaterialTags.SHULKER_BOXES.getValues(); + assert true; + } catch (Throwable e) { @@ -1084,6 +1125,32 @@ index 0000000000000000000000000000000000000000..328c51471dc12e81c1a1b643455337b3 + assert false; + } + } ++ ++ @Test ++ public void testLocked() { ++ testLocked(MaterialTags.class); ++ testLocked(EntityTags.class); ++ } ++ ++ private static void testLocked(Class clazz) { ++ for (BaseTag tag : collectTags(clazz)) { ++ assertTrue("Tag " + tag.key() + " is not locked", tag.isLocked()); ++ } ++ } ++ ++ private static Set> collectTags(Class clazz) { ++ Set> tags = new HashSet<>(); ++ try { ++ for (Field field : clazz.getDeclaredFields()) { ++ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && BaseTag.class.isAssignableFrom(field.getType())) { ++ tags.add((BaseTag) field.get(null)); ++ } ++ } ++ } catch (IllegalAccessException e) { ++ e.printStackTrace(); ++ } ++ return tags; ++ } +} diff --git a/src/test/java/io/papermc/paper/EntityTagsTest.java b/src/test/java/io/papermc/paper/EntityTagsTest.java new file mode 100644