From 4cddc62be7d97e5f5aed5180f6643d049865bc9a Mon Sep 17 00:00:00 2001 From: Dennis C Date: Mon, 6 Feb 2023 23:03:51 +0100 Subject: [PATCH] Make IForgeIntrinsicHolderTagAppender methods properly chainable (#9331) --- .../IForgeIntrinsicHolderTagAppender.java | 73 ++++++++++++++++++- .../common/extensions/IForgeTagAppender.java | 1 + src/main/resources/META-INF/coremods.json | 3 +- .../intrinsic_tag_appender_binary_compat.js | 65 +++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/main/resources/coremods/intrinsic_tag_appender_binary_compat.js diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeIntrinsicHolderTagAppender.java b/src/main/java/net/minecraftforge/common/extensions/IForgeIntrinsicHolderTagAppender.java index 2dedcfc9c6..e38de07534 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeIntrinsicHolderTagAppender.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeIntrinsicHolderTagAppender.java @@ -6,8 +6,9 @@ package net.minecraftforge.common.extensions; import net.minecraft.data.tags.IntrinsicHolderTagsProvider; -import net.minecraft.data.tags.TagsProvider; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; public interface IForgeIntrinsicHolderTagAppender extends IForgeTagAppender { @@ -23,7 +24,7 @@ public interface IForgeIntrinsicHolderTagAppender extends IForgeTagAppender remove(final T entry) + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(final T entry) { return remove(this.getKey(entry)); } @@ -35,7 +36,7 @@ public interface IForgeIntrinsicHolderTagAppender extends IForgeTagAppender remove(final T first, final T...entries) + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(final T first, final T...entries) { this.remove(first); for (T entry : entries) @@ -44,4 +45,70 @@ public interface IForgeIntrinsicHolderTagAppender extends IForgeTagAppender addTags(TagKey... values) + { + IForgeTagAppender.super.addTags(values); + return self(); + } + + @Override + default IntrinsicHolderTagsProvider.IntrinsicTagAppender replace() + { + IForgeTagAppender.super.replace(); + return self(); + } + + @Override + default IntrinsicHolderTagsProvider.IntrinsicTagAppender replace(boolean value) + { + IForgeTagAppender.super.replace(value); + return self(); + } + + @Override + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(final ResourceLocation location) + { + IForgeTagAppender.super.remove(location); + return self(); + } + + @Override + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(final ResourceLocation first, final ResourceLocation... locations) + { + IForgeTagAppender.super.remove(first, locations); + return self(); + } + + @Override + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(final ResourceKey resourceKey) + { + IForgeTagAppender.super.remove(resourceKey); + return self(); + } + + @Override + @SuppressWarnings("unchecked") + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(final ResourceKey firstResourceKey, final ResourceKey... resourceKeys) + { + IForgeTagAppender.super.remove(firstResourceKey, resourceKeys); + return self(); + } + + @Override + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(TagKey tag) + { + IForgeTagAppender.super.remove(tag); + return self(); + } + + @Override + @SuppressWarnings("unchecked") + default IntrinsicHolderTagsProvider.IntrinsicTagAppender remove(TagKey first, TagKey...tags) + { + IForgeTagAppender.super.remove(first, tags); + return self(); + } } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeTagAppender.java b/src/main/java/net/minecraftforge/common/extensions/IForgeTagAppender.java index c1bc9dcab7..d3f64324b6 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeTagAppender.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeTagAppender.java @@ -79,6 +79,7 @@ public interface IForgeTagAppender * @param resourceKeys The resource keys of the elements to remove * @return The appender for chaining */ + @SuppressWarnings("unchecked") default TagsProvider.TagAppender remove(final ResourceKey firstResourceKey, final ResourceKey... resourceKeys) { this.remove(firstResourceKey.location()); diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json index bc26fe0f09..445d251cbd 100644 --- a/src/main/resources/META-INF/coremods.json +++ b/src/main/resources/META-INF/coremods.json @@ -1,5 +1,6 @@ { "field_to_method": "coremods/field_to_method.js", "field_to_instanceof": "coremods/field_to_instanceof.js", - "add_bouncer_method": "coremods/add_bouncer_method.js" + "add_bouncer_method": "coremods/add_bouncer_method.js", + "intrinsic_tag_appender_binary_compat": "coremods/intrinsic_tag_appender_binary_compat.js" } diff --git a/src/main/resources/coremods/intrinsic_tag_appender_binary_compat.js b/src/main/resources/coremods/intrinsic_tag_appender_binary_compat.js new file mode 100644 index 0000000000..9b3f3fd1e2 --- /dev/null +++ b/src/main/resources/coremods/intrinsic_tag_appender_binary_compat.js @@ -0,0 +1,65 @@ +var Opcodes = Java.type('org.objectweb.asm.Opcodes') +var MethodNode = Java.type('org.objectweb.asm.tree.MethodNode') +var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode') +var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode') +var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode') + +// TODO 1.20: Delete this whole coremod. We won't need to maintain binary compatibility then. +// This coremod exists purely because of Java limitations - 2 methods with the same parameters and name but different return types are not allowed. +// However, this restriction does not exist in the JVM. +// The two remove() methods had their return types narrowed to allow chaining calls. +// This coremod was made to maintain compatibility with mods compiled on old forge in the least invasive way. +// It adds runtime methods for the two methods in IForgeIntrinsicTagAppender that return TagsProvider.TagAppender. +// The ASM methods just delegate to the original methods. + +function initializeCoreMod() { + return { + 'intrinsic_tag_appender_binary_compat': { + 'target': { + 'type': 'CLASS', + 'name': 'net.minecraftforge.common.extensions.IForgeIntrinsicHolderTagAppender' + }, + 'transformer': function (classNode) { + var removeSingleNode = new MethodNode( + Opcodes.ACC_PUBLIC, + 'remove', + '(Ljava/lang/Object;)Lnet/minecraft/data/tags/TagsProvider$TagAppender;', + null, + null + ); + removeSingleNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); + removeSingleNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); + removeSingleNode.instructions.add(new MethodInsnNode( + Opcodes.INVOKEINTERFACE, + 'net/minecraftforge/common/extensions/IForgeIntrinsicHolderTagAppender', + 'remove', + '(Ljava/lang/Object;)Lnet/minecraft/data/tags/IntrinsicHolderTagsProvider$IntrinsicTagAppender;' + )); + removeSingleNode.instructions.add(new InsnNode(Opcodes.ARETURN)); + + var removeMultiNode = new MethodNode( + Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS, + 'remove', + '(Ljava/lang/Object;[Ljava/lang/Object;)Lnet/minecraft/data/tags/TagsProvider$TagAppender;', + null, + null + ); + removeMultiNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); + removeMultiNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); + removeMultiNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); + removeMultiNode.instructions.add(new MethodInsnNode( + Opcodes.INVOKEINTERFACE, + 'net/minecraftforge/common/extensions/IForgeIntrinsicHolderTagAppender', + 'remove', + '(Ljava/lang/Object;[Ljava/lang/Object;)Lnet/minecraft/data/tags/IntrinsicHolderTagsProvider$IntrinsicTagAppender;' + )); + removeMultiNode.instructions.add(new InsnNode(Opcodes.ARETURN)); + + classNode.methods.add(removeSingleNode); + classNode.methods.add(removeMultiNode); + + return classNode; + } + } + } +} \ No newline at end of file