From 442f4723c80dc9ca289f744f2c20d40632be84a2 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Mon, 23 Dec 2024 21:56:46 -0500 Subject: [PATCH] Deprecate `@ObjectHolder`, add a couple of fast-paths (#10228) Co-authored-by: Paint_Ninja --- .../common/asm/ObjectHolderDefinalize.java | 39 ++++++++++++++----- .../registries/ObjectHolder.java | 12 ++++++ .../registries/ObjectHolderRegistry.java | 3 ++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/fmlloader/src/main/java/net/minecraftforge/fml/common/asm/ObjectHolderDefinalize.java b/fmlloader/src/main/java/net/minecraftforge/fml/common/asm/ObjectHolderDefinalize.java index 1337ec2f46..a8afc027cf 100644 --- a/fmlloader/src/main/java/net/minecraftforge/fml/common/asm/ObjectHolderDefinalize.java +++ b/fmlloader/src/main/java/net/minecraftforge/fml/common/asm/ObjectHolderDefinalize.java @@ -8,6 +8,7 @@ package net.minecraftforge.fml.common.asm; import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; import java.util.stream.Collectors; @@ -35,7 +36,11 @@ public class ObjectHolderDefinalize implements ILaunchPluginService { new VanillaObjectHolderData("net.minecraft.core.particles.ParticleTypes", "particle_type", "net.minecraft.core.particles.ParticleType"), new VanillaObjectHolderData("net.minecraft.sounds.SoundEvents", "sound_event", "net.minecraft.sounds.SoundEvent") ).collect(Collectors.toMap(VanillaObjectHolderData::holderClass, Function.identity())); - private final String OBJECT_HOLDER = "Lnet/minecraftforge/registries/ObjectHolder;"; //Don't directly reference this to prevent class loading. + private static final Set VANILLA_OBJECT_HOLDER_CLASSES = VANILLA_OBJECT_HOLDERS.keySet().stream() + .map(it -> it.replace('.', '/')) + .collect(Collectors.toUnmodifiableSet()); + private static final String OBJECT_HOLDER = "Lnet/minecraftforge/registries/ObjectHolder;"; //Don't directly reference this to prevent class loading. + private static final int PUBLIC_STATIC_FINAL_FLAGS = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL; @Override public String name() { @@ -46,13 +51,30 @@ public class ObjectHolderDefinalize implements ILaunchPluginService { private static final EnumSet NAY = EnumSet.noneOf(Phase.class); @Override - public EnumSet handlesClass(Type classType, boolean isEmpty) - { - return isEmpty ? NAY : YAY; + public EnumSet handlesClass(Type classType, boolean isEmpty) { + if (isEmpty) + return NAY; + + // Let's skip processing classes that definitely don't have object holders + String internalName = classType.getInternalName(); + + // Forge classes that aren't in the debug package (that package is used for tests) + if (internalName.startsWith("net/minecraftforge/") && !internalName.substring(18).contains("debug") + && !internalName.equals("net/minecraftforge/common/crafting/ConditionalRecipe")) + return NAY; + + // Vanilla classes that don't have object holders + if (internalName.startsWith("com/mojang/")) + return NAY; + + // ...except specific ones we added to the VANILLA_OBJECT_HOLDERS map + if (internalName.startsWith("net/minecraft/") && !VANILLA_OBJECT_HOLDER_CLASSES.contains(internalName)) + return NAY; + + return YAY; } - private boolean hasHolder(List lst) - { + private boolean hasHolder(List lst) { return lst != null && lst.stream().anyMatch(n -> n.desc.equals(OBJECT_HOLDER)); } @@ -75,10 +97,9 @@ public class ObjectHolderDefinalize implements ILaunchPluginService { { final AtomicBoolean changes = new AtomicBoolean(); //Must be public static finals, and non-array objects - final int flags = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL; //Fix Annotated Fields before injecting from class level - classNode.fields.stream().filter(f -> ((f.access & flags) == flags) && f.desc.startsWith("L") && hasHolder(f.visibleAnnotations)).forEach(f -> + classNode.fields.stream().filter(f -> ((f.access & PUBLIC_STATIC_FINAL_FLAGS) == PUBLIC_STATIC_FINAL_FLAGS) && f.desc.startsWith("L") && hasHolder(f.visibleAnnotations)).forEach(f -> { int prev = f.access; f.access &= ~Opcodes.ACC_FINAL; //Strip final @@ -88,7 +109,7 @@ public class ObjectHolderDefinalize implements ILaunchPluginService { if (VANILLA_OBJECT_HOLDERS.containsKey(classType.getClassName())) //Class level, de-finalize all fields and add @ObjectHolder to them! { - classNode.fields.stream().filter(f -> ((f.access & flags) == flags) && f.desc.startsWith("L")).forEach(f -> + classNode.fields.stream().filter(f -> ((f.access & PUBLIC_STATIC_FINAL_FLAGS) == PUBLIC_STATIC_FINAL_FLAGS) && f.desc.startsWith("L")).forEach(f -> { int prev = f.access; f.access &= ~Opcodes.ACC_FINAL; diff --git a/src/main/java/net/minecraftforge/registries/ObjectHolder.java b/src/main/java/net/minecraftforge/registries/ObjectHolder.java index f92b2ecaf3..887f2ddefa 100644 --- a/src/main/java/net/minecraftforge/registries/ObjectHolder.java +++ b/src/main/java/net/minecraftforge/registries/ObjectHolder.java @@ -16,7 +16,19 @@ import java.lang.annotation.Target; /** * ObjectHolder can be used to automatically populate public static final fields with entries * from the registry. These values can then be referred within mod code directly. + * @deprecated Use {@link DeferredRegister} or {@link RegistryObject} instead. Refer to the MDK for more detailed examples. + *
+ * Example usage of alternatives: + *
{@code
+ * // To register something
+ * public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
+ * public static final RegistryObject EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Properties()));
+ *
+ * // To get a RegistryObject that you didn't register yourself:
+ * public static final RegistryObject DIRT = RegistryObject.create(ResourceLocation.withDefaultNamespace("dirt"), ForgeRegistries.BLOCKS);
+ * }
*/ +@Deprecated(since = "1.21.4", forRemoval = true) @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ObjectHolder diff --git a/src/main/java/net/minecraftforge/registries/ObjectHolderRegistry.java b/src/main/java/net/minecraftforge/registries/ObjectHolderRegistry.java index 166dc04e30..6218b87ed7 100644 --- a/src/main/java/net/minecraftforge/registries/ObjectHolderRegistry.java +++ b/src/main/java/net/minecraftforge/registries/ObjectHolderRegistry.java @@ -89,6 +89,9 @@ public class ObjectHolderRegistry .filter(a -> OBJECT_HOLDER.equals(a.annotationType()) || MOD.equals(a.annotationType())) .toList(); + if (annotations.stream().noneMatch(a -> OBJECT_HOLDER.equals(a.annotationType()))) + return; // No object holders found, skip the rest of the processing + Map classModIds = Maps.newHashMap(); Map> classCache = Maps.newHashMap();