diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java index 7a6676b4ac..b8ebaceade 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java @@ -5,7 +5,6 @@ import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; import org.bukkit.entity.FallingBlock; @@ -32,7 +31,7 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { @Override public Material getMaterial() { - return CraftMagicNumbers.getMaterial(getHandle().getBlock()).getItemType(); + return getBlockData().getMaterial(); } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftEvil.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftEvil.java similarity index 96% rename from src/main/java/org/bukkit/craftbukkit/util/CraftEvil.java rename to src/main/java/org/bukkit/craftbukkit/legacy/CraftEvil.java index 1580db8362..afb706fc82 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftEvil.java +++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftEvil.java @@ -1,4 +1,4 @@ -package org.bukkit.craftbukkit.util; +package org.bukkit.craftbukkit.legacy; import com.google.common.base.Preconditions; import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; @@ -16,7 +16,7 @@ import org.bukkit.inventory.ItemStack; * @deprecated do not use for any reason */ @Deprecated -public class CraftEvil { +public final class CraftEvil { private static final Int2ObjectMap byId = new Int2ObjectLinkedOpenHashMap<>(); @@ -31,6 +31,10 @@ public class CraftEvil { } } + private CraftEvil() { + // + } + public static int getBlockTypeIdAt(World world, int x, int y, int z) { return getId(world.getBlockAt(x, y, z).getType()); } diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java new file mode 100644 index 0000000000..5e385a3788 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java @@ -0,0 +1,448 @@ +package org.bukkit.craftbukkit.legacy; + +import com.google.common.base.Preconditions; +import com.mojang.datafixers.Dynamic; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import net.minecraft.server.Block; +import net.minecraft.server.BlockStateList; +import net.minecraft.server.Blocks; +import net.minecraft.server.DataConverterFlattenData; +import net.minecraft.server.DataConverterMaterialId; +import net.minecraft.server.DataConverterRegistry; +import net.minecraft.server.DataConverterTypes; +import net.minecraft.server.DispenserRegistry; +import net.minecraft.server.DynamicOpsNBT; +import net.minecraft.server.IBlockData; +import net.minecraft.server.IBlockState; +import net.minecraft.server.IRegistry; +import net.minecraft.server.Item; +import net.minecraft.server.Items; +import net.minecraft.server.MinecraftKey; +import net.minecraft.server.NBTBase; +import net.minecraft.server.NBTTagCompound; +import org.bukkit.Material; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.material.MaterialData; + +/** + * This class may seem unnecessarily slow and complicated/repetitive however it + * is able to handle a lot more edge cases and invertible transformations (many + * of which are not immediately obvious) than any other alternative. If you do + * make changes to this class please make sure to contribute them back + * https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse so + * that all may benefit. + * + * @deprecated legacy use only + */ +@Deprecated +public final class CraftLegacy { + + private static final Map SPAWN_EGGS = new HashMap<>(); + private static final Set whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable", "facing")); + private static final Map materialToItem = new HashMap<>(16384); + private static final Map itemToMaterial = new HashMap<>(1024); + private static final Map materialToData = new HashMap<>(4096); + private static final Map dataToMaterial = new HashMap<>(4096); + private static final Map materialToBlock = new HashMap<>(4096); + private static final Map blockToMaterial = new HashMap<>(1024); + + private CraftLegacy() { + // + } + + public static Material toLegacy(Material material) { + if (material == null || material.isLegacy()) { + return material; + } + + return toLegacyData(material).getItemType(); + } + + public static MaterialData toLegacyData(Material material) { + Preconditions.checkArgument(!material.isLegacy(), "toLegacy on legacy Material"); + MaterialData mappedData; + + if (material.isBlock()) { + Block block = CraftMagicNumbers.getBlock(material); + IBlockData blockData = block.getBlockData(); + + // Try exact match first + mappedData = dataToMaterial.get(blockData); + // Fallback to any block + if (mappedData == null) { + mappedData = blockToMaterial.get(block); + // Fallback to matching item + if (mappedData == null) { + mappedData = itemToMaterial.get(block.getItem()); + } + } + } else { + Item item = CraftMagicNumbers.getItem(material); + mappedData = itemToMaterial.get(item); + } + + return (mappedData == null) ? new MaterialData(Material.LEGACY_AIR) : mappedData; + } + + public static IBlockData fromLegacyData(Material material, Block block, byte data) { + Preconditions.checkArgument(material.isLegacy(), "fromLegacyData on modern Material"); + + MaterialData materialData = new MaterialData(material, data); + + // Try exact match first + IBlockData converted = materialToData.get(materialData); + if (converted != null) { + return converted; + } + + // Fallback to any block + Block convertedBlock = materialToBlock.get(materialData); + if (convertedBlock != null) { + return convertedBlock.getBlockData(); + } + + // Return existing block + return block.getBlockData(); + } + + public static Item fromLegacyData(Material material, Item item, short data) { + Preconditions.checkArgument(material.isLegacy(), "fromLegacyData on modern Material. Did you forget to define api-version: 1.13 in your plugin.yml?"); + + MaterialData materialData = new MaterialData(material, (byte) data); + + // First try matching item + Item convertedItem = materialToItem.get(materialData); + if (convertedItem != null) { + return convertedItem; + } + + // Fallback to matching block + if (material.isBlock()) { + // Try exact match first + IBlockData converted = materialToData.get(materialData); + if (converted != null) { + return converted.getBlock().getItem(); + } + + // Fallback to any block + Block convertedBlock = materialToBlock.get(materialData); + if (convertedBlock != null) { + return convertedBlock.getItem(); + } + } + + // Return existing item + return item; + } + + public static byte toLegacyData(IBlockData blockData) { + return toLegacy(blockData).getData(); + } + + public static Material toLegacyMaterial(IBlockData blockData) { + return toLegacy(blockData).getItemType(); + } + + public static MaterialData toLegacy(IBlockData blockData) { + MaterialData mappedData; + + // Try exact match first + mappedData = dataToMaterial.get(blockData); + // Fallback to any block + if (mappedData == null) { + mappedData = blockToMaterial.get(blockData.getBlock()); + } + + return (mappedData == null) ? new MaterialData(Material.LEGACY_AIR) : mappedData; + } + + public static Material fromLegacy(Material material) { + if (material == null || !material.isLegacy()) { + return material; + } + + return fromLegacy(new MaterialData(material)); + } + + public static Material fromLegacy(MaterialData materialData) { + return fromLegacy(materialData, false); + } + + public static Material fromLegacy(MaterialData materialData, boolean itemPriority) { + Material material = materialData.getItemType(); + if (material == null || !material.isLegacy()) { + return material; + } + + Material mappedData = null; + + // Try item first + if (itemPriority) { + Item item = materialToItem.get(materialData); + if (item != null) { + mappedData = CraftMagicNumbers.getMaterial(item); + } + } + + if (mappedData == null && material.isBlock()) { + // Try exact match first + IBlockData iblock = materialToData.get(materialData); + if (iblock != null) { + mappedData = CraftMagicNumbers.getMaterial(iblock.getBlock()); + } + + // Fallback to any block + if (mappedData == null) { + Block block = materialToBlock.get(materialData); + if (block != null) { + mappedData = CraftMagicNumbers.getMaterial(block); + } + } + } + + // Fallback to matching item + if (!itemPriority && mappedData == null) { + Item item = materialToItem.get(materialData); + if (item != null) { + mappedData = CraftMagicNumbers.getMaterial(item); + } + } + + return (mappedData == null) ? Material.AIR : mappedData; + } + + public static Material[] values() { + Material[] values = Material.values(); + return Arrays.copyOfRange(values, Material.LEGACY_AIR.ordinal(), values.length); + } + + public static Material valueOf(String name) { + return (name.startsWith(Material.LEGACY_PREFIX)) ? Material.valueOf(name) : Material.valueOf(Material.LEGACY_PREFIX + name); + } + + public static Material getMaterial(String name) { + return (name.startsWith(Material.LEGACY_PREFIX)) ? Material.getMaterial(name) : Material.getMaterial(Material.LEGACY_PREFIX + name); + } + + public static Material matchMaterial(String name) { + return (name.startsWith(Material.LEGACY_PREFIX)) ? Material.matchMaterial(name) : Material.matchMaterial(Material.LEGACY_PREFIX + name); + } + + public static int ordinal(Material material) { + Preconditions.checkArgument(material.isLegacy(), "ordinal on modern Material"); + + return material.ordinal() - Material.LEGACY_AIR.ordinal(); + } + + public static String name(Material material) { + return material.name().substring(Material.LEGACY_PREFIX.length()); + } + + public static String toString(Material material) { + return name(material); + } + + public static Material[] modern_values() { + Material[] values = Material.values(); + return Arrays.copyOfRange(values, 0, Material.LEGACY_AIR.ordinal()); + } + + public static int modern_ordinal(Material material) { + if (material.isLegacy()) { + // SPIGOT-4002: Fix for eclipse compiler manually compiling in default statements to lookupswitch + throw new NoSuchFieldError("Legacy field ordinal: " + material); + } + + return material.ordinal(); + } + + public static void init() { + // + } + + static { + System.err.println("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); + + SPAWN_EGGS.put((byte) 0, Material.PIG_SPAWN_EGG); // Will be fixed by updateMaterial if possible + + SPAWN_EGGS.put((byte) EntityType.BAT.getTypeId(), Material.BAT_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.BLAZE.getTypeId(), Material.BLAZE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.CAVE_SPIDER.getTypeId(), Material.CAVE_SPIDER_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.CHICKEN.getTypeId(), Material.CHICKEN_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.COD.getTypeId(), Material.COD_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.COW.getTypeId(), Material.COW_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.CREEPER.getTypeId(), Material.CREEPER_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.DOLPHIN.getTypeId(), Material.DOLPHIN_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.DONKEY.getTypeId(), Material.DONKEY_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.ELDER_GUARDIAN.getTypeId(), Material.ELDER_GUARDIAN_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.ENDERMAN.getTypeId(), Material.ENDERMAN_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.ENDERMITE.getTypeId(), Material.ENDERMITE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.EVOKER.getTypeId(), Material.EVOKER_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.GHAST.getTypeId(), Material.GHAST_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.GUARDIAN.getTypeId(), Material.GUARDIAN_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.HORSE.getTypeId(), Material.HORSE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.HUSK.getTypeId(), Material.HUSK_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.LLAMA.getTypeId(), Material.LLAMA_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.MAGMA_CUBE.getTypeId(), Material.MAGMA_CUBE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.MUSHROOM_COW.getTypeId(), Material.MOOSHROOM_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.MULE.getTypeId(), Material.MULE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.OCELOT.getTypeId(), Material.OCELOT_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.PARROT.getTypeId(), Material.PARROT_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.PIG.getTypeId(), Material.PIG_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.PHANTOM.getTypeId(), Material.PHANTOM_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.POLAR_BEAR.getTypeId(), Material.POLAR_BEAR_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.PUFFERFISH.getTypeId(), Material.PUFFERFISH_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.RABBIT.getTypeId(), Material.RABBIT_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SALMON.getTypeId(), Material.SALMON_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SHEEP.getTypeId(), Material.SHEEP_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SHULKER.getTypeId(), Material.SHULKER_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SILVERFISH.getTypeId(), Material.SILVERFISH_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SKELETON.getTypeId(), Material.SKELETON_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SKELETON_HORSE.getTypeId(), Material.SKELETON_HORSE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SLIME.getTypeId(), Material.SLIME_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SPIDER.getTypeId(), Material.SPIDER_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.SQUID.getTypeId(), Material.SQUID_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.STRAY.getTypeId(), Material.STRAY_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.TROPICAL_FISH.getTypeId(), Material.TROPICAL_FISH_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.TURTLE.getTypeId(), Material.TURTLE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.VEX.getTypeId(), Material.VEX_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.VILLAGER.getTypeId(), Material.VILLAGER_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.VINDICATOR.getTypeId(), Material.VINDICATOR_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.WITCH.getTypeId(), Material.WITCH_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.WITHER_SKELETON.getTypeId(), Material.WITHER_SKELETON_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.WOLF.getTypeId(), Material.WOLF_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.ZOMBIE.getTypeId(), Material.ZOMBIE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.ZOMBIE_HORSE.getTypeId(), Material.ZOMBIE_HORSE_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.PIG_ZOMBIE.getTypeId(), Material.ZOMBIE_PIGMAN_SPAWN_EGG); + SPAWN_EGGS.put((byte) EntityType.ZOMBIE_VILLAGER.getTypeId(), Material.ZOMBIE_VILLAGER_SPAWN_EGG); + + DispenserRegistry.init(); + + for (Material material : Material.values()) { + if (!material.isLegacy()) { + continue; + } + + // Handle blocks + if (material.isBlock()) { + for (byte data = 0; data < 16; data++) { + MaterialData matData = new MaterialData(material, data); + Dynamic blockTag = DataConverterFlattenData.b(material.getId() << 4 | data); + // TODO: better skull conversion, chests + if (blockTag.get("Name").asString("").contains("%%FILTER_ME%%")) { + continue; + } + + String name = blockTag.get("Name").asString(""); + // TODO: need to fix + if (name.equals("minecraft:portal")) { + name = "minecraft:nether_portal"; + } + + Block block = IRegistry.BLOCK.get(new MinecraftKey(name)); + if (block == null) { + continue; + } + IBlockData blockData = block.getBlockData(); + BlockStateList states = block.getStates(); + + Optional propMap = blockTag.getElement("Properties"); + if (propMap.isPresent()) { + NBTTagCompound properties = propMap.get(); + for (String dataKey : properties.getKeys()) { + IBlockState state = states.a(dataKey); + + if (state == null) { + if (whitelistedStates.contains(dataKey)) { + continue; + } + throw new IllegalStateException("No state for " + dataKey); + } + + Preconditions.checkState(!properties.getString(dataKey).isEmpty(), "Empty data string"); + Optional opt = state.b(properties.getString(dataKey)); + + blockData = blockData.set(state, (Comparable) opt.get()); + } + } + + if (block == Blocks.AIR) { + continue; + } + + materialToData.put(matData, blockData); + if (!dataToMaterial.containsKey(blockData)) { + dataToMaterial.put(blockData, matData); + } + + materialToBlock.put(matData, block); + if (!blockToMaterial.containsKey(block)) { + blockToMaterial.put(block, matData); + } + } + } + + // Handle items (and second fallback for blocks) + int maxData = material.getMaxDurability() == 0 ? 16 : 1; + // Manually do oldold spawn eggs + if (material == Material.LEGACY_MONSTER_EGG) { + maxData = 121; // Vilager + 1 + } + + for (byte data = 0; data < maxData; data++) { + // Manually skip invalid oldold spawn + if (material == Material.LEGACY_MONSTER_EGG /*&& data != 0 && EntityType.fromId(data) == null*/) { // Mojang broke 18w19b + continue; + } + // Skip non item stacks for now (18w19b) + if (DataConverterMaterialId.a(material.getId()) == null) { + continue; + } + + MaterialData matData = new MaterialData(material, data); + + NBTTagCompound stack = new NBTTagCompound(); + stack.setInt("id", material.getId()); + stack.setShort("Damage", data); + + Dynamic converted = DataConverterRegistry.a().update(DataConverterTypes.ITEM_STACK, new Dynamic(DynamicOpsNBT.a, stack), -1, CraftMagicNumbers.INSTANCE.getDataVersion()); + + String newId = converted.get("id").asString(""); + // Recover spawn eggs with invalid data + if (newId.equals("minecraft:spawn_egg")) { + newId = "minecraft:pig_spawn_egg"; + } + + // Preconditions.checkState(newId.contains("minecraft:"), "Unknown new material for " + matData); + Item newMaterial = IRegistry.ITEM.get(new MinecraftKey(newId)); + + if (newMaterial == Items.AIR) { + continue; + } + + materialToItem.put(matData, newMaterial); + if (!itemToMaterial.containsKey(newMaterial)) { + itemToMaterial.put(newMaterial, matData); + } + } + + for (Map.Entry entry : SPAWN_EGGS.entrySet()) { + MaterialData matData = new MaterialData(Material.LEGACY_MONSTER_EGG, entry.getKey()); + Item newMaterial = CraftMagicNumbers.getItem(entry.getValue()); + + materialToItem.put(matData, newMaterial); + itemToMaterial.put(newMaterial, matData); + } + } + } + + public static void main(String[] args) { + System.err.println(""); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java index 467b2d9385..b577eb3692 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -273,7 +273,7 @@ public class Commodore newArgs[0] = Type.getObjectType( owner ); System.arraycopy( args, 0, newArgs, 1, args.length ); - super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/util/CraftEvil", name, Type.getMethodDescriptor( retType, newArgs ), false ); + super.visitMethodInsn( Opcodes.INVOKESTATIC, "org/bukkit/craftbukkit/legacy/CraftEvil", name, Type.getMethodDescriptor( retType, newArgs ), false ); return; } @@ -290,7 +290,7 @@ public class Commodore { if ( name.equals( "getMaterial" ) && desc.equals( "(I)Lorg/bukkit/Material;" ) ) { - super.visitMethodInsn( opcode, "org/bukkit/craftbukkit/util/CraftEvil", name, desc, itf ); + super.visitMethodInsn( opcode, "org/bukkit/craftbukkit/legacy/CraftEvil", name, desc, itf ); return; } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/util/CraftLegacy.java index 4539a4a773..7d2ab460c7 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftLegacy.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftLegacy.java @@ -1,160 +1,16 @@ package org.bukkit.craftbukkit.util; -import com.google.common.base.Preconditions; -import com.mojang.datafixers.Dynamic; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import net.minecraft.server.Block; -import net.minecraft.server.BlockStateList; -import net.minecraft.server.Blocks; -import net.minecraft.server.DataConverterFlattenData; -import net.minecraft.server.DataConverterMaterialId; -import net.minecraft.server.DataConverterRegistry; -import net.minecraft.server.DataConverterTypes; -import net.minecraft.server.DispenserRegistry; -import net.minecraft.server.DynamicOpsNBT; -import net.minecraft.server.IBlockData; -import net.minecraft.server.IBlockState; -import net.minecraft.server.IRegistry; -import net.minecraft.server.Item; -import net.minecraft.server.Items; -import net.minecraft.server.MinecraftKey; -import net.minecraft.server.NBTBase; -import net.minecraft.server.NBTTagCompound; import org.bukkit.Material; -import org.bukkit.entity.EntityType; import org.bukkit.material.MaterialData; /** - * This class may seem unnecessarily slow and complicated/repetitive however it - * is able to handle a lot more edge cases and invertible transformations (many - * of which are not immediately obvious) than any other alternative. If you do - * make changes to this class please make sure to contribute them back - * https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse so - * that all may benefit. - * * @deprecated legacy use only */ @Deprecated -public class CraftLegacy { +public final class CraftLegacy { - private static final Map SPAWN_EGGS = new HashMap<>(); - private static final Set whitelistedStates = new HashSet<>(Arrays.asList("explode", "check_decay", "decayable", "facing")); - private static final Map materialToItem = new HashMap<>(16384); - private static final Map itemToMaterial = new HashMap<>(1024); - private static final Map materialToData = new HashMap<>(4096); - private static final Map dataToMaterial = new HashMap<>(4096); - private static final Map materialToBlock = new HashMap<>(4096); - private static final Map blockToMaterial = new HashMap<>(1024); - - public static Material toLegacy(Material material) { - if (material == null || material.isLegacy()) { - return material; - } - - return toLegacyData(material).getItemType(); - } - - public static MaterialData toLegacyData(Material material) { - Preconditions.checkArgument(!material.isLegacy(), "toLegacy on legacy Material"); - MaterialData mappedData; - - if (material.isBlock()) { - Block block = CraftMagicNumbers.getBlock(material); - IBlockData blockData = block.getBlockData(); - - // Try exact match first - mappedData = dataToMaterial.get(blockData); - // Fallback to any block - if (mappedData == null) { - mappedData = blockToMaterial.get(block); - // Fallback to matching item - if (mappedData == null) { - mappedData = itemToMaterial.get(block.getItem()); - } - } - } else { - Item item = CraftMagicNumbers.getItem(material); - mappedData = itemToMaterial.get(item); - } - - return (mappedData == null) ? new MaterialData(Material.LEGACY_AIR) : mappedData; - } - - public static IBlockData fromLegacyData(Material material, Block block, byte data) { - Preconditions.checkArgument(material.isLegacy(), "fromLegacyData on modern Material"); - - MaterialData materialData = new MaterialData(material, data); - - // Try exact match first - IBlockData converted = materialToData.get(materialData); - if (converted != null) { - return converted; - } - - // Fallback to any block - Block convertedBlock = materialToBlock.get(materialData); - if (convertedBlock != null) { - return convertedBlock.getBlockData(); - } - - // Return existing block - return block.getBlockData(); - } - - public static Item fromLegacyData(Material material, Item item, short data) { - Preconditions.checkArgument(material.isLegacy(), "fromLegacyData on modern Material. Did you forget to define api-version: 1.13 in your plugin.yml?"); - - MaterialData materialData = new MaterialData(material, (byte) data); - - // First try matching item - Item convertedItem = materialToItem.get(materialData); - if (convertedItem != null) { - return convertedItem; - } - - // Fallback to matching block - if (material.isBlock()) { - // Try exact match first - IBlockData converted = materialToData.get(materialData); - if (converted != null) { - return converted.getBlock().getItem(); - } - - // Fallback to any block - Block convertedBlock = materialToBlock.get(materialData); - if (convertedBlock != null) { - return convertedBlock.getItem(); - } - } - - // Return existing item - return item; - } - - public static byte toLegacyData(IBlockData blockData) { - return toLegacy(blockData).getData(); - } - - public static Material toLegacyMaterial(IBlockData blockData) { - return toLegacy(blockData).getItemType(); - } - - public static MaterialData toLegacy(IBlockData blockData) { - MaterialData mappedData; - - // Try exact match first - mappedData = dataToMaterial.get(blockData); - // Fallback to any block - if (mappedData == null) { - mappedData = blockToMaterial.get(blockData.getBlock()); - } - - return (mappedData == null) ? new MaterialData(Material.LEGACY_AIR) : mappedData; + private CraftLegacy() { + // } public static Material fromLegacy(Material material) { @@ -162,276 +18,10 @@ public class CraftLegacy { return material; } - return fromLegacy(new MaterialData(material)); + return org.bukkit.craftbukkit.legacy.CraftLegacy.fromLegacy(material); } public static Material fromLegacy(MaterialData materialData) { - return fromLegacy(materialData, false); - } - - public static Material fromLegacy(MaterialData materialData, boolean itemPriority) { - Material material = materialData.getItemType(); - if (material == null || !material.isLegacy()) { - return material; - } - - Material mappedData = null; - - // Try item first - if (itemPriority) { - Item item = materialToItem.get(materialData); - if (item != null) { - mappedData = CraftMagicNumbers.getMaterial(item); - } - } - - if (mappedData == null && material.isBlock()) { - // Try exact match first - IBlockData iblock = materialToData.get(materialData); - if (iblock != null) { - mappedData = CraftMagicNumbers.getMaterial(iblock.getBlock()); - } - - // Fallback to any block - if (mappedData == null) { - Block block = materialToBlock.get(materialData); - if (block != null) { - mappedData = CraftMagicNumbers.getMaterial(block); - } - } - } - - // Fallback to matching item - if (!itemPriority && mappedData == null) { - Item item = materialToItem.get(materialData); - if (item != null) { - mappedData = CraftMagicNumbers.getMaterial(item); - } - } - - return (mappedData == null) ? Material.AIR : mappedData; - } - - public static Material[] values() { - Material[] values = Material.values(); - return Arrays.copyOfRange(values, Material.LEGACY_AIR.ordinal(), values.length); - } - - public static Material valueOf(String name) { - return (name.startsWith(Material.LEGACY_PREFIX)) ? Material.valueOf(name) : Material.valueOf(Material.LEGACY_PREFIX + name); - } - - public static Material getMaterial(String name) { - return (name.startsWith(Material.LEGACY_PREFIX)) ? Material.getMaterial(name) : Material.getMaterial(Material.LEGACY_PREFIX + name); - } - - public static Material matchMaterial(String name) { - return (name.startsWith(Material.LEGACY_PREFIX)) ? Material.matchMaterial(name) : Material.matchMaterial(Material.LEGACY_PREFIX + name); - } - - public static int ordinal(Material material) { - Preconditions.checkArgument(material.isLegacy(), "ordinal on modern Material"); - - return material.ordinal() - Material.LEGACY_AIR.ordinal(); - } - - public static String name(Material material) { - return material.name().substring(Material.LEGACY_PREFIX.length()); - } - - public static String toString(Material material) { - return name(material); - } - - public static Material[] modern_values() { - Material[] values = Material.values(); - return Arrays.copyOfRange(values, 0, Material.LEGACY_AIR.ordinal()); - } - - public static int modern_ordinal(Material material) { - if (material.isLegacy()) { - // SPIGOT-4002: Fix for eclipse compiler manually compiling in default statements to lookupswitch - throw new NoSuchFieldError("Legacy field ordinal: " + material); - } - - return material.ordinal(); - } - - static { - SPAWN_EGGS.put((byte) 0, Material.PIG_SPAWN_EGG); // Will be fixed by updateMaterial if possible - - SPAWN_EGGS.put((byte) EntityType.BAT.getTypeId(), Material.BAT_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.BLAZE.getTypeId(), Material.BLAZE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.CAVE_SPIDER.getTypeId(), Material.CAVE_SPIDER_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.CHICKEN.getTypeId(), Material.CHICKEN_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.COD.getTypeId(), Material.COD_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.COW.getTypeId(), Material.COW_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.CREEPER.getTypeId(), Material.CREEPER_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.DOLPHIN.getTypeId(), Material.DOLPHIN_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.DONKEY.getTypeId(), Material.DONKEY_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.ELDER_GUARDIAN.getTypeId(), Material.ELDER_GUARDIAN_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.ENDERMAN.getTypeId(), Material.ENDERMAN_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.ENDERMITE.getTypeId(), Material.ENDERMITE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.EVOKER.getTypeId(), Material.EVOKER_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.GHAST.getTypeId(), Material.GHAST_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.GUARDIAN.getTypeId(), Material.GUARDIAN_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.HORSE.getTypeId(), Material.HORSE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.HUSK.getTypeId(), Material.HUSK_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.LLAMA.getTypeId(), Material.LLAMA_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.MAGMA_CUBE.getTypeId(), Material.MAGMA_CUBE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.MUSHROOM_COW.getTypeId(), Material.MOOSHROOM_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.MULE.getTypeId(), Material.MULE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.OCELOT.getTypeId(), Material.OCELOT_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.PARROT.getTypeId(), Material.PARROT_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.PIG.getTypeId(), Material.PIG_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.PHANTOM.getTypeId(), Material.PHANTOM_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.POLAR_BEAR.getTypeId(), Material.POLAR_BEAR_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.PUFFERFISH.getTypeId(), Material.PUFFERFISH_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.RABBIT.getTypeId(), Material.RABBIT_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SALMON.getTypeId(), Material.SALMON_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SHEEP.getTypeId(), Material.SHEEP_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SHULKER.getTypeId(), Material.SHULKER_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SILVERFISH.getTypeId(), Material.SILVERFISH_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SKELETON.getTypeId(), Material.SKELETON_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SKELETON_HORSE.getTypeId(), Material.SKELETON_HORSE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SLIME.getTypeId(), Material.SLIME_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SPIDER.getTypeId(), Material.SPIDER_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.SQUID.getTypeId(), Material.SQUID_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.STRAY.getTypeId(), Material.STRAY_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.TROPICAL_FISH.getTypeId(), Material.TROPICAL_FISH_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.TURTLE.getTypeId(), Material.TURTLE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.VEX.getTypeId(), Material.VEX_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.VILLAGER.getTypeId(), Material.VILLAGER_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.VINDICATOR.getTypeId(), Material.VINDICATOR_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.WITCH.getTypeId(), Material.WITCH_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.WITHER_SKELETON.getTypeId(), Material.WITHER_SKELETON_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.WOLF.getTypeId(), Material.WOLF_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.ZOMBIE.getTypeId(), Material.ZOMBIE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.ZOMBIE_HORSE.getTypeId(), Material.ZOMBIE_HORSE_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.PIG_ZOMBIE.getTypeId(), Material.ZOMBIE_PIGMAN_SPAWN_EGG); - SPAWN_EGGS.put((byte) EntityType.ZOMBIE_VILLAGER.getTypeId(), Material.ZOMBIE_VILLAGER_SPAWN_EGG); - - DispenserRegistry.init(); - - for (Material material : Material.values()) { - if (!material.isLegacy()) { - continue; - } - - // Handle blocks - if (material.isBlock()) { - for (byte data = 0; data < 16; data++) { - MaterialData matData = new MaterialData(material, data); - Dynamic blockTag = DataConverterFlattenData.b(material.getId() << 4 | data); - // TODO: better skull conversion, chests - if (blockTag.get("Name").asString("").contains("%%FILTER_ME%%")) { - continue; - } - - String name = blockTag.get("Name").asString(""); - // TODO: need to fix - if (name.equals("minecraft:portal")) { - name = "minecraft:nether_portal"; - } - - Block block = IRegistry.BLOCK.get(new MinecraftKey(name)); - if (block == null) { - continue; - } - IBlockData blockData = block.getBlockData(); - BlockStateList states = block.getStates(); - - Optional propMap = blockTag.getElement("Properties"); - if (propMap.isPresent()) { - NBTTagCompound properties = propMap.get(); - for (String dataKey : properties.getKeys()) { - IBlockState state = states.a(dataKey); - - if (state == null) { - if (whitelistedStates.contains(dataKey)) { - continue; - } - throw new IllegalStateException("No state for " + dataKey); - } - - Preconditions.checkState(!properties.getString(dataKey).isEmpty(), "Empty data string"); - Optional opt = state.b(properties.getString(dataKey)); - - blockData = blockData.set(state, (Comparable) opt.get()); - } - } - - if (block == Blocks.AIR) { - continue; - } - - materialToData.put(matData, blockData); - if (!dataToMaterial.containsKey(blockData)) { - dataToMaterial.put(blockData, matData); - } - - materialToBlock.put(matData, block); - if (!blockToMaterial.containsKey(block)) { - blockToMaterial.put(block, matData); - } - } - } - - // Handle items (and second fallback for blocks) - int maxData = material.getMaxDurability() == 0 ? 16 : 1; - // Manually do oldold spawn eggs - if (material == Material.LEGACY_MONSTER_EGG) { - maxData = 121; // Vilager + 1 - } - - for (byte data = 0; data < maxData; data++) { - // Manually skip invalid oldold spawn - if (material == Material.LEGACY_MONSTER_EGG /*&& data != 0 && EntityType.fromId(data) == null*/) { // Mojang broke 18w19b - continue; - } - // Skip non item stacks for now (18w19b) - if (DataConverterMaterialId.a(material.getId()) == null) { - continue; - } - - MaterialData matData = new MaterialData(material, data); - - NBTTagCompound stack = new NBTTagCompound(); - stack.setInt("id", material.getId()); - stack.setShort("Damage", data); - - Dynamic converted = DataConverterRegistry.a().update(DataConverterTypes.ITEM_STACK, new Dynamic(DynamicOpsNBT.a, stack), -1, CraftMagicNumbers.INSTANCE.getDataVersion()); - - String newId = converted.get("id").asString(""); - // Recover spawn eggs with invalid data - if (newId.equals("minecraft:spawn_egg")) { - newId = "minecraft:pig_spawn_egg"; - } - - // Preconditions.checkState(newId.contains("minecraft:"), "Unknown new material for " + matData); - Item newMaterial = IRegistry.ITEM.get(new MinecraftKey(newId)); - - if (newMaterial == Items.AIR) { - continue; - } - - materialToItem.put(matData, newMaterial); - if (!itemToMaterial.containsKey(newMaterial)) { - itemToMaterial.put(newMaterial, matData); - } - } - - for (Map.Entry entry : SPAWN_EGGS.entrySet()) { - MaterialData matData = new MaterialData(Material.LEGACY_MONSTER_EGG, entry.getKey()); - Item newMaterial = CraftMagicNumbers.getItem(entry.getValue()); - - materialToItem.put(matData, newMaterial); - itemToMaterial.put(newMaterial, matData); - } - } - } - - public static void main(String[] args) { - System.err.println(""); + return org.bukkit.craftbukkit.legacy.CraftLegacy.fromLegacy(materialData); } } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index 1860fbb1bb..afe4004ff2 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -39,6 +39,7 @@ import org.bukkit.advancement.Advancement; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.legacy.CraftLegacy; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; import org.bukkit.plugin.InvalidPluginException; @@ -90,6 +91,10 @@ public final class CraftMagicNumbers implements UnsafeValues { } for (Material material : Material.values()) { + if (material.isLegacy()) { + continue; + } + MinecraftKey key = key(material); IRegistry.ITEM.getOptional(key).ifPresent((item) -> { MATERIAL_ITEM.put(material, item); @@ -117,10 +122,6 @@ public final class CraftMagicNumbers implements UnsafeValues { } public static MinecraftKey key(Material mat) { - if (mat.isLegacy()) { - mat = CraftLegacy.fromLegacy(mat); - } - return CraftNamespacedKey.toMinecraft(mat.getKey()); } // ======================================================================== @@ -266,7 +267,8 @@ public final class CraftMagicNumbers implements UnsafeValues { } } else { if (minimumIndex == -1) { - Bukkit.getLogger().log(Level.WARNING, "Plugin " + pdf.getFullName() + " does not specify an api-version."); + CraftLegacy.init(); + Bukkit.getLogger().log(Level.WARNING, "Legacy plugin " + pdf.getFullName() + " does not specify an api-version."); } else { throw new InvalidPluginException("Plugin API version " + pdf.getAPIVersion() + " is lower than the minimum allowed version. Please update or replace it."); } diff --git a/src/test/java/org/bukkit/EvilTest.java b/src/test/java/org/bukkit/craftbukkit/legacy/EvilTest.java similarity index 86% rename from src/test/java/org/bukkit/EvilTest.java rename to src/test/java/org/bukkit/craftbukkit/legacy/EvilTest.java index 39c6cb26d0..23e5d98cf7 100644 --- a/src/test/java/org/bukkit/EvilTest.java +++ b/src/test/java/org/bukkit/craftbukkit/legacy/EvilTest.java @@ -1,6 +1,6 @@ -package org.bukkit; +package org.bukkit.craftbukkit.legacy; -import org.bukkit.craftbukkit.util.CraftEvil; +import org.bukkit.Material; import org.junit.Assert; import org.junit.Test; diff --git a/src/test/java/org/bukkit/LegacyTest.java b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java similarity index 99% rename from src/test/java/org/bukkit/LegacyTest.java rename to src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java index 524495841c..a246f6d31d 100644 --- a/src/test/java/org/bukkit/LegacyTest.java +++ b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java @@ -1,9 +1,9 @@ -package org.bukkit; +package org.bukkit.craftbukkit.legacy; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import org.bukkit.craftbukkit.util.CraftLegacy; +import org.bukkit.Material; import org.bukkit.material.MaterialData; import org.bukkit.support.AbstractTestingBase; import org.junit.Assert;