From c581955633379f8a334e85aed82491e05ad9957e Mon Sep 17 00:00:00 2001 From: nelind Date: Sat, 16 Nov 2024 23:33:19 +0100 Subject: [PATCH] Handle last compatibility issue with Architectury API --- loofah/build.gradle.kts | 5 ++ loofah/src/main/resources/fabric.mod.json | 4 + .../world/level/ExplosionMixin.java | 84 +++++++++++++++++++ .../mixin/plugin/FabricCompatMixinPlugin.java | 44 ++++++++++ .../plugin/FabricMixinAnnotationAdjuster.java | 50 +++++++++++ .../mixin/plugin/FabricMixinPlugin.java | 4 + .../resources/mixins.loofah.compat.json | 13 +++ 7 files changed, 204 insertions(+) create mode 100644 loofah/src/mixins/java/dk/nelind/loofah/mixin/compat/architectury/world/level/ExplosionMixin.java create mode 100644 loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricCompatMixinPlugin.java create mode 100644 loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinAnnotationAdjuster.java create mode 100644 loofah/src/mixins/resources/mixins.loofah.compat.json diff --git a/loofah/build.gradle.kts b/loofah/build.gradle.kts index 2aa6e5f2594..9c89622fa17 100644 --- a/loofah/build.gradle.kts +++ b/loofah/build.gradle.kts @@ -13,6 +13,9 @@ repositories { maven("https://repo.spongepowered.org/repository/maven-public/") { name = "SpongePowered" } + maven("https://maven.bawnorton.com/releases") { + name = "Bawnorton" + } } plugins { @@ -185,6 +188,8 @@ dependencies { modImplementation(fabricApi.module("fabric-lifecycle-events-v1", fabricApiVersion)) "modMixinsImplementation"(modImplementation(fabricApi.module("fabric-networking-api-v1", fabricApiVersion))!!) + include(fabricLibrariesConfig(annotationProcessor("com.github.bawnorton.mixinsquared:mixinsquared-fabric:0.2.0")!!)!!) + // API dependencies fabricBootstrapLibrariesConfig(apiLibs.pluginSpi) { exclude("org.apache.commons", "commons-lang3") diff --git a/loofah/src/main/resources/fabric.mod.json b/loofah/src/main/resources/fabric.mod.json index 95424a50e55..4ff59376bf4 100644 --- a/loofah/src/main/resources/fabric.mod.json +++ b/loofah/src/main/resources/fabric.mod.json @@ -23,11 +23,15 @@ ], "client": [ "dk.nelind.loofah.Loofah" + ], + "mixinsquared-adjuster": [ + "dk.nelind.loofah.mixin.plugin.FabricMixinAnnotationAdjuster" ] }, "accessWidener" : "common.accesswidener", "mixins": [ "mixins.loofah.api.json", + "mixins.loofah.compat.json", "mixins.loofah.core.json", "mixins.loofah.core.shared.json", "mixins.loofah.inventory.json", diff --git a/loofah/src/mixins/java/dk/nelind/loofah/mixin/compat/architectury/world/level/ExplosionMixin.java b/loofah/src/mixins/java/dk/nelind/loofah/mixin/compat/architectury/world/level/ExplosionMixin.java new file mode 100644 index 00000000000..e48a5acadb4 --- /dev/null +++ b/loofah/src/mixins/java/dk/nelind/loofah/mixin/compat/architectury/world/level/ExplosionMixin.java @@ -0,0 +1,84 @@ +/* + * This file is part of Loofah, licensed under the MIT License (MIT). + * + * Copyright (c) Nelind + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package dk.nelind.loofah.mixin.compat.architectury.world.level; + +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import org.apache.logging.log4j.LogManager; +import org.spongepowered.asm.mixin.Debug; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +/** + * Replaces Architectury's detonate event call with a Loofah/SpongeCommon compatible implementation if + * Architectury is installed + */ +@Debug(export = true) +@Mixin(Explosion.class) +public class ExplosionMixin { + @Shadow @Final private Level level; + + @Inject( + method = "explode", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/phys/Vec3;(DDD)V", + ordinal = 0 + ), + locals = LocalCapture.CAPTURE_FAILHARD + ) + private void callArchitecturyExplodePostEvent(CallbackInfo ci, float q, int k, int l, int r, int s, int t, int u, List list) { + // Call the event using reflection. It's technically a bit brittle, but I think it'll be fine. + try { + var eventClass = Class.forName("dev.architectury.event.Event"); + var eventInkoverMethod = eventClass.getDeclaredMethod("invoker"); + + var explosionEventClass = Class.forName("dev.architectury.event.events.common.ExplosionEvent"); + var detonateEventClass = Class.forName("dev.architectury.event.events.common.ExplosionEvent$Detonate"); + var detonateEventInstance = explosionEventClass.getField("DETONATE"); + var eventInvoker = eventInkoverMethod.invoke(detonateEventInstance.get(null)); + var eventCallMethod = detonateEventClass.getDeclaredMethod("explode", Level.class, Explosion.class, List.class); + + eventCallMethod.invoke(eventInvoker, this.level, this, list); + LogManager.getLogger().info("Called arch event"); + } catch ( + ClassNotFoundException | + NoSuchFieldException | + NoSuchMethodException | + InvocationTargetException | + IllegalAccessException e + ) { + throw new RuntimeException(e); + } + } +} diff --git a/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricCompatMixinPlugin.java b/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricCompatMixinPlugin.java new file mode 100644 index 00000000000..0b588c48263 --- /dev/null +++ b/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricCompatMixinPlugin.java @@ -0,0 +1,44 @@ +/* + * This file is part of Loofah, licensed under the MIT License (MIT). + * + * Copyright (c) Nelind + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package dk.nelind.loofah.mixin.plugin; + +import net.fabricmc.loader.api.FabricLoader; +import org.spongepowered.common.mixin.plugin.AbstractMixinConfigPlugin; + +public class FabricCompatMixinPlugin extends AbstractMixinConfigPlugin { + @Override + public boolean shouldApplyMixin(final String targetClassName, final String mixinClassName) { + + if ( + mixinClassName.equals("dk.nelind.loofah.mixin.compat.architectury.world.level.ExplosionMixin") && + FabricLoader.getInstance().isModLoaded("architectury") + ) { + FabricMixinPlugin.LOGGER.info("Architectury API detected. Enabling compatibility features in Loofah"); + return true; + } + + return false; + } +} diff --git a/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinAnnotationAdjuster.java b/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinAnnotationAdjuster.java new file mode 100644 index 00000000000..7a50f7248f9 --- /dev/null +++ b/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinAnnotationAdjuster.java @@ -0,0 +1,50 @@ +/* + * This file is part of Loofah, licensed under the MIT License (MIT). + * + * Copyright (c) Nelind + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package dk.nelind.loofah.mixin.plugin; + +import com.bawnorton.mixinsquared.adjuster.tools.AdjustableAnnotationNode; +import com.bawnorton.mixinsquared.api.MixinAnnotationAdjuster; +import org.objectweb.asm.tree.MethodNode; +import org.spongepowered.asm.mixin.injection.Inject; + +import java.util.List; + +public class FabricMixinAnnotationAdjuster implements MixinAnnotationAdjuster { + @Override + public AdjustableAnnotationNode adjust(List targetClassNames, String mixinClassName, MethodNode handlerNode, AdjustableAnnotationNode annotationNode) { + // Don't inject Architectury's MixinExplosion inject as the priorities are in the wrong order + // and even if they were in the right order the LVT has been changed by an overwrite in + // SpongeCommon ExplosionMixin and the local capture would fail. Not the pretties thing ever but + // sometimes modding is just inherently ugly. If some other better solution presents itself at some point + // that is mostly likely preferable + // + // See also dk.nelind.loofah.mixin.compat.world.level.ExplosionMixin + if (mixinClassName.equals("dev.architectury.mixin.fabric.MixinExplosion") && annotationNode.is(Inject.class)) { + return null; + } + + return annotationNode; + } +} diff --git a/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinPlugin.java b/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinPlugin.java index 622734800e6..ca78e883125 100644 --- a/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinPlugin.java +++ b/loofah/src/mixins/java/dk/nelind/loofah/mixin/plugin/FabricMixinPlugin.java @@ -25,12 +25,16 @@ package dk.nelind.loofah.mixin.plugin; import dk.nelind.loofah.applaunch.plugin.FabricPluginPlatform; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.spongepowered.common.mixin.plugin.AbstractMixinConfigPlugin; /** * Inspired by {@link org.spongepowered.forge.mixin.plugin.ForgeCorePlugin} */ public class FabricMixinPlugin extends AbstractMixinConfigPlugin { + public static final Logger LOGGER = LogManager.getLogger("Loofah/Mixin"); + public FabricMixinPlugin() { FabricPluginPlatform.bootstrap(); } diff --git a/loofah/src/mixins/resources/mixins.loofah.compat.json b/loofah/src/mixins/resources/mixins.loofah.compat.json new file mode 100644 index 00000000000..a7b8dd8fdf7 --- /dev/null +++ b/loofah/src/mixins/resources/mixins.loofah.compat.json @@ -0,0 +1,13 @@ +{ + "required": true, + "parent": "mixins.sponge.parent.json", + "package": "dk.nelind.loofah.mixin.compat", + "plugin": "dk.nelind.loofah.mixin.plugin.FabricCompatMixinPlugin", + "mixinPriority": 1301, + "mixins": [ + "architectury.world.level.ExplosionMixin" + ], + "overwrites": { + "conformVisibility": true + } +}