diff --git a/patches/minecraft/net/minecraft/enchantment/EnumEnchantmentType.java.patch b/patches/minecraft/net/minecraft/enchantment/EnumEnchantmentType.java.patch index 37bfabc0f..0232f4292 100644 --- a/patches/minecraft/net/minecraft/enchantment/EnumEnchantmentType.java.patch +++ b/patches/minecraft/net/minecraft/enchantment/EnumEnchantmentType.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/enchantment/EnumEnchantmentType.java +++ b/net/minecraft/enchantment/EnumEnchantmentType.java +@@ -13,7 +13,7 @@ + import net.minecraft.item.ItemTool; + import net.minecraft.item.ItemTrident; + +-public enum EnumEnchantmentType { ++public enum EnumEnchantmentType implements net.minecraftforge.common.IExtensibleEnum { + ALL { + public boolean func_77557_a(Item p_77557_1_) { + for(EnumEnchantmentType enumenchantmenttype : EnumEnchantmentType.values()) { @@ -90,5 +90,16 @@ private EnumEnchantmentType() { } @@ -11,7 +20,7 @@ + } + + public static EnumEnchantmentType create(String name, java.util.function.Predicate delegate) { -+ return null; ++ throw new IllegalStateException("Enum not extended"); + } + + public boolean func_77557_a(Item p_77557_1_) { diff --git a/patches/minecraft/net/minecraft/entity/EnumCreatureType.java.patch b/patches/minecraft/net/minecraft/entity/EnumCreatureType.java.patch index fe2fb981d..695908b4c 100644 --- a/patches/minecraft/net/minecraft/entity/EnumCreatureType.java.patch +++ b/patches/minecraft/net/minecraft/entity/EnumCreatureType.java.patch @@ -1,11 +1,20 @@ --- a/net/minecraft/entity/EnumCreatureType.java +++ b/net/minecraft/entity/EnumCreatureType.java +@@ -6,7 +6,7 @@ + import net.minecraft.entity.passive.EntityWaterMob; + import net.minecraft.entity.passive.IAnimal; + +-public enum EnumCreatureType { ++public enum EnumCreatureType implements net.minecraftforge.common.IExtensibleEnum { + MONSTER(IMob.class, 70, false, false), + CREATURE(EntityAnimal.class, 10, true, true), + AMBIENT(EntityAmbientCreature.class, 15, true, false), @@ -39,4 +39,8 @@ public boolean func_82705_e() { return this.field_82707_i; } + + public static EnumCreatureType create(String name, Class p_i47849_3_, int p_i47849_4_, boolean p_i47849_5_, boolean p_i47849_6_) { -+ return null; ++ throw new IllegalStateException("Enum not extended"); + } } diff --git a/patches/minecraft/net/minecraft/entity/passive/HorseArmorType.java.patch b/patches/minecraft/net/minecraft/entity/passive/HorseArmorType.java.patch index 06ce551e5..cadcab247 100644 --- a/patches/minecraft/net/minecraft/entity/passive/HorseArmorType.java.patch +++ b/patches/minecraft/net/minecraft/entity/passive/HorseArmorType.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/entity/passive/HorseArmorType.java +++ b/net/minecraft/entity/passive/HorseArmorType.java +@@ -7,7 +7,7 @@ + import net.minecraftforge.api.distmarker.Dist; + import net.minecraftforge.api.distmarker.OnlyIn; + +-public enum HorseArmorType { ++public enum HorseArmorType implements net.minecraftforge.common.IExtensibleEnum { + NONE(0), + IRON(5, "iron", "meo"), + GOLD(7, "gold", "goo"), @@ -16,6 +16,7 @@ private final String field_188586_e; private final String field_188587_f; @@ -18,7 +27,7 @@ + } + + public static HorseArmorType create(String name, int strength, String texture, String hash, Item item) { -+ return null; ++ throw new IllegalStateException("Enum not extended"); + } + public int func_188579_a() { diff --git a/patches/minecraft/net/minecraft/item/ArmorMaterial.java.patch b/patches/minecraft/net/minecraft/item/ArmorMaterial.java.patch index d0b6c415a..e03ab0102 100644 --- a/patches/minecraft/net/minecraft/item/ArmorMaterial.java.patch +++ b/patches/minecraft/net/minecraft/item/ArmorMaterial.java.patch @@ -1,11 +1,20 @@ --- a/net/minecraft/item/ArmorMaterial.java +++ b/net/minecraft/item/ArmorMaterial.java +@@ -10,7 +10,7 @@ + import net.minecraftforge.api.distmarker.Dist; + import net.minecraftforge.api.distmarker.OnlyIn; + +-public enum ArmorMaterial implements IArmorMaterial { ++public enum ArmorMaterial implements IArmorMaterial, net.minecraftforge.common.IExtensibleEnum { + LEATHER("leather", 5, new int[]{1, 2, 3, 1}, 15, SoundEvents.field_187728_s, 0.0F, () -> { + return Ingredient.func_199804_a(Items.field_151116_aA); + }), @@ -77,4 +77,8 @@ public float func_200901_e() { return this.field_189417_k; } + + public static ArmorMaterial create(String name, String p_i48533_3_, int p_i48533_4_, int[] p_i48533_5_, int p_i48533_6_, SoundEvent p_i48533_7_, float p_i48533_8_, Supplier p_i48533_9_) { -+ return null; ++ throw new IllegalStateException("Enum not extended"); ++ } } -+} diff --git a/patches/minecraft/net/minecraft/world/dimension/DimensionType.java.patch b/patches/minecraft/net/minecraft/world/dimension/DimensionType.java.patch index 3528251fc..5c2a89e66 100644 --- a/patches/minecraft/net/minecraft/world/dimension/DimensionType.java.patch +++ b/patches/minecraft/net/minecraft/world/dimension/DimensionType.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/world/dimension/DimensionType.java +++ b/net/minecraft/world/dimension/DimensionType.java +@@ -2,7 +2,7 @@ + + import java.util.function.Supplier; + +-public enum DimensionType { ++public enum DimensionType implements net.minecraftforge.common.IExtensibleEnum { + OVERWORLD(0, "overworld", "", OverworldDimension::new), + NETHER(-1, "the_nether", "_nether", NetherDimension::new), + THE_END(1, "the_end", "_end", EndDimension::new); @@ -11,12 +11,19 @@ private final String field_186075_e; private final String field_186076_f; @@ -20,15 +29,14 @@ } public int func_186068_a() { -@@ -54,4 +61,11 @@ +@@ -54,4 +61,10 @@ throw new IllegalArgumentException("Invalid dimension " + p_193417_0_); } + + public boolean shouldLoadSpawn(){ return this.shouldLoadSpawn; } + -+ public static DimensionType create(int id, String name, String suffix, Supplier provider, boolean shouldLoadSpawn) -+ { -+ return null; ++ public static DimensionType create(String enumName, int id, String name, String suffix, Supplier provider, boolean shouldLoadSpawn) { ++ throw new IllegalStateException("Enum not extended"); + } } diff --git a/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java b/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java index 1ebed7d0e..92f94231e 100644 --- a/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java +++ b/src/fmllauncher/java/net/minecraftforge/common/asm/RuntimeEnumExtender.java @@ -20,6 +20,8 @@ package net.minecraftforge.common.asm; import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; import net.minecraftforge.fml.loading.AdvancedLogMessageAdapter; import org.apache.logging.log4j.LogManager; @@ -43,6 +45,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService { private static final Logger LOGGER = LogManager.getLogger(); private final Type STRING = Type.getType(String.class); private final Type ENUM = Type.getType(Enum.class); + private final Type MARKER_IFACE = Type.getType("Lnet/minecraftforge/common/IExtensibleEnum;"); private final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); //Don't directly reference this to prevent class loading. private final String ADD_DESC = Type.getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class)); private final Type UNSAFE_HACKS = Type.getType("Lnet/minecraftforge/fml/UnsafeHacks;"); //Again, not direct reference to prevent class loading. @@ -75,13 +78,28 @@ public class RuntimeEnumExtender implements ILaunchPluginService { final int flags = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC; FieldNode values = classNode.fields.stream().filter(f -> f.desc.contentEquals(array.getDescriptor()) && ((f.access & flags) == flags)).findFirst().orElse(null); + + if (!classNode.interfaces.contains(MARKER_IFACE.getInternalName())) { + return classNode; + } + //Static methods named "create", with first argument as a string, and returning this type - classNode.methods.stream().filter(m -> ((m.access & Opcodes.ACC_STATIC) != 0) && m.name.equals("create") && Type.getReturnType(m.desc).equals(classType)).forEach(mtd -> + List candidates = classNode.methods.stream() + .filter(m -> ((m.access & Opcodes.ACC_STATIC) != 0) && m.name.equals("create") && Type.getReturnType(m.desc).equals(classType)) + .collect(Collectors.toList()); + + candidates.forEach(mtd -> { Type[] args = Type.getArgumentTypes(mtd.desc); - if (args.length == 0 || !args[0].equals(STRING)) - return; - + if (args.length == 0 || !args[0].equals(STRING)) { + LOGGER.fatal(()->new AdvancedLogMessageAdapter(sb-> { + sb.append("Enum has create method without String as first parameter:\n"); + sb.append(" Enum: " + classType.getDescriptor()).append("\n"); + sb.append(" Target: ").append(mtd.name + mtd.desc).append("\n"); + })); + throw new IllegalStateException("Enum has create method without String as first parameter: " + mtd.name + mtd.desc); + } + Type[] ctrArgs = new Type[args.length + 1]; ctrArgs[0] = STRING; ctrArgs[1] = Type.INT_TYPE; @@ -95,7 +113,8 @@ public class RuntimeEnumExtender implements ILaunchPluginService { { LOGGER.fatal(()->new AdvancedLogMessageAdapter(sb-> { sb.append("Enum has create method with no matching constructor:\n"); - sb.append(" Enum: " + classType.getDescriptor()).append("\n"); + sb.append(" Enum: ").append(classType.getDescriptor()).append("\n"); + sb.append(" Candidate: ").append(mtd.desc).append("\n"); sb.append(" Target: ").append(desc).append("\n"); classNode.methods.stream().filter(m -> m.name.equals("")).forEach(m -> sb.append(" : ").append(m.desc).append("\n")); })); diff --git a/src/main/java/net/minecraftforge/common/IExtensibleEnum.java b/src/main/java/net/minecraftforge/common/IExtensibleEnum.java new file mode 100644 index 000000000..7c8b051e4 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/IExtensibleEnum.java @@ -0,0 +1,25 @@ +package net.minecraftforge.common; + +/** + * To be implemented on vanilla enums that should be enhanced with ASM to be + * extensible. If this is implemented on a class, the class must define a static + * method called "create" which takes a String (enum name), and the rest of the + * parameters matching a constructor. + *

+ * For example, an enum with the constructor {@code MyEnum(Object foo)} would + * require the method: + * + *

+ * public static MyEnum create(String name, Object foo)
+ * {
+ *     throw new IllegalStateException("Enum not extended");
+ * }
+ * 
+ * + * The method contents will be replaced with ASM at runtime. Multiple + * {@code create} methods can be defined as long as each + * matches a constructor. + */ +public interface IExtensibleEnum +{ +} \ No newline at end of file