From a6aa21a9857594ce1f94b7d200877a96b345b99b Mon Sep 17 00:00:00 2001 From: zaaarf Date: Thu, 15 Feb 2024 00:54:12 +0100 Subject: feat: reworked to make it extension-based, done? might just work, but it's untested for now so take care --- README.md | 6 +- build.gradle | 8 +- src/main/java/ftbsc/lll/mixin/LilleroMixin.java | 124 ----------------- .../java/ftbsc/lll/mixin/LilleroMixinPlugin.java | 152 +++++++++++++++++++++ ...ods.modlauncher.serviceapi.ILaunchPluginService | 2 +- 5 files changed, 162 insertions(+), 130 deletions(-) delete mode 100644 src/main/java/ftbsc/lll/mixin/LilleroMixin.java create mode 100644 src/main/java/ftbsc/lll/mixin/LilleroMixinPlugin.java diff --git a/README.md b/README.md index b47183d..0a5c48f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# WIP, IT DOES NOT WORK YET! +# UNTESTED FOR NOW, TAKE CARE! # Lillero-mixin Lillero-mixin is a Mixin plugin capable of applying [Lillero](https://github.com/zaaarf/lillero) ASM patches without @@ -6,6 +6,10 @@ needing to inject itself as a JAR library. While slightly dirtier code-wise, thi [Lillero-loader](https://github.com/zaaarf/lillero-loader) of being compatible with both Forge and Fabric - and, barring major API changes, with any other future mod loader that will try to force Mixin on you. +To use this, write a class extending `LilleroMixinPlugin`. Then, register it as a Mixin plugin; it usually involves editing +or writing your mod's configuration, but the exact steps vary depending on your mod loader. +Specific instructions for Fabric and Forge coming as soon as I have time for this. + ## Credits This time there's one other project that must be mentioned. I would've never thought of this had I not stumbled on [Manningham Mills](https://github.com/Chocohead/Fabric-ASM). So, thanks to Chocohead for showing that it was indeed diff --git a/build.gradle b/build.gradle index 47c7511..3fa75da 100644 --- a/build.gradle +++ b/build.gradle @@ -25,9 +25,9 @@ repositories { } dependencies { - implementation 'org.apache.logging.log4j:log4j-api:2.17.1' - implementation 'org.apache.logging.log4j:log4j-core:2.17.1' - implementation 'org.ow2.asm:asm-commons:9.4' + implementation 'org.apache.logging.log4j:log4j-api:2.22.1' + implementation 'org.apache.logging.log4j:log4j-core:2.22.1' + implementation 'org.ow2.asm:asm-commons:9.6' implementation 'ftbsc:lll:0.5.0' - implementation 'org.spongepowered:mixin:0.8.3' + implementation 'org.spongepowered:mixin:0.8.5' } diff --git a/src/main/java/ftbsc/lll/mixin/LilleroMixin.java b/src/main/java/ftbsc/lll/mixin/LilleroMixin.java deleted file mode 100644 index 835a77f..0000000 --- a/src/main/java/ftbsc/lll/mixin/LilleroMixin.java +++ /dev/null @@ -1,124 +0,0 @@ -package ftbsc.lll.mixin; - -import ftbsc.lll.IInjector; -import ftbsc.lll.exceptions.InjectionException; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.*; - -public class LilleroMixin implements IMixinConfigPlugin { - - private final Map> injectorMap = new HashMap<>(); - - /** - * Called after the plugin is instantiated, do any setup here. - * @param mixinPackage The mixin root package from the config - */ - @Override - public void onLoad(String mixinPackage) { - for (IInjector inj : ServiceLoader.load(IInjector.class, this.getClass().getClassLoader())) { - //LOGGER.info(RESOURCE, "Registering injector {}", inj.name()); - List injectors = this.injectorMap.get(inj.targetClass()); - if(injectors == null) { - injectors = new ArrayList<>(); - injectorMap.put(inj.targetClass(), injectors); - } - injectors.add(inj); - } - } - - /** - * Called only if the "referenceMap" key in the config is not set. - * This allows the refmap file name to be supplied by the plugin - * programatically if desired. Returning null will revert to - * the default behaviour of using the default refmap json file. - * - * @return Path to the refmap resource or null to revert to the default - */ - @Override //TODO ? - public String getRefMapperConfig() { - return null; - } - - /** - * Called during mixin intialisation, allows this plugin to control whether - * a specific will be applied to the specified target. Returning false will - * remove the target from the mixin's target set, and if all targets are - * removed then the mixin will not be applied at all. - * - * @param targetClassName Fully qualified class name of the target class - * @param mixinClassName Fully qualified class name of the mixin - * @return True to allow the mixin to be applied, or false to remove it from - * target's mixin set - */ - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return true; - } - - /** - * Called after all configurations are initialised, this allows this plugin - * to observe classes targetted by other mixin configs and optionally remove - * targets from its own set. The set myTargets is a direct view of the - * targets collection in this companion config and keys may be removed from - * this set to suppress mixins in this config which target the specified - * class. Adding keys to the set will have no effect. - * - * @param myTargets Target class set from the companion config - * @param otherTargets Target class set incorporating targets from all other - * configs, read-only - */ - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - /** - * After mixins specified in the configuration have been processed, this - * method is called to allow the plugin to add any additional mixins to - * load. It should return a list of mixin class names or return null if the - * plugin does not wish to append any mixins of its own. - * - * @return additional mixins to apply - */ - @Override - public List getMixins() { - return null; - } - - /** - * Called immediately before a mixin is applied to a target class, - * allows any pre-application transformations to be applied. - * - * @param targetClassName Transformed name of the target class - * @param targetClass Target class tree - * @param mixinClassName Name of the mixin class - * @param mixinInfo Information about this mixin - */ - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - injectorMap.get(targetClassName).forEach((inj) -> targetClass.methods.stream() - .filter(m -> m.name.equals(inj.methodName()) && m.desc.equals(inj.methodDesc())) - .forEach(m -> { - try { - inj.inject(targetClass, m); - } catch (InjectionException ignored) {} //TODO log - })); - } - - /** - * Called immediately after a mixin is applied to a target class, - * allows any post-application transformations to be applied. - * - * @param targetClassName Transformed name of the target class - * @param targetClass Target class tree - * @param mixinClassName Name of the mixin class - * @param mixinInfo Information about this mixin - */ - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/src/main/java/ftbsc/lll/mixin/LilleroMixinPlugin.java b/src/main/java/ftbsc/lll/mixin/LilleroMixinPlugin.java new file mode 100644 index 0000000..8b23e4e --- /dev/null +++ b/src/main/java/ftbsc/lll/mixin/LilleroMixinPlugin.java @@ -0,0 +1,152 @@ +package ftbsc.lll.mixin; + +import ftbsc.lll.IInjector; +import ftbsc.lll.exceptions.InjectionException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.*; + +/** + * Allows you to load your mod's Lillero patches as a Mixin plugin. + * Extend this class and specify the child as a plugin in your mod's Mixin + * config. Refer to your mod loader's instructions for details on how this + * is done. + * Methods are left non-final in case you want to alter their behaviour in + * any way, but I can't really see any merit in doing so. + */ +public abstract class LilleroMixinPlugin implements IMixinConfigPlugin { + /** + * The {@link Logger} used by this library. + */ + protected static final Logger LOGGER = LogManager.getLogger(LilleroMixinPlugin.class); + + /** + * Maps each fully-qualified name to its associated class. + */ + private final Map> injectorMap = new HashMap<>(); + + /** + * Whether Lillero should take precedence over regular mixins. + */ + private final boolean precedence; + + /** + * The constructor. + * @param precedence whether Lillero should take precedence over regular mixins + */ + public LilleroMixinPlugin(boolean precedence) { + this.precedence = precedence; + } + + /** + * Called after the plugin is instantiated, do any setup here. + * @param mixinPackage The mixin root package from the config + */ + @Override + public void onLoad(String mixinPackage) { + for(IInjector inj : ServiceLoader.load(IInjector.class, this.getClass().getClassLoader())) { + LOGGER.info("Registering injector {}", inj.name()); + List injectors = this.injectorMap.get(inj.targetClass()); + if(injectors == null) { + injectors = new ArrayList<>(); + injectorMap.put(inj.targetClass(), injectors); + } + injectors.add(inj); + } + } + + /** + * Returns null, so it's effectively ignored. + * @return always null + */ + @Override + public String getRefMapperConfig() { + return null; + } + + /** + * Tells Mixin to always apply these patches. + * Lillero doesn't support conditional patches: any check should happen + * within the patch code itself, with the patch code's scope. + * @param targetClassName fully qualified class name of the target class + * @param mixinClassName fully qualified class name of the mixin + * @return always true + */ + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return true; + } + + /** + * Does nothing, as we don't need to alter the target class list. + * @param myTargets target class set from the companion config + * @param otherTargets target class set incorporating targets from all other + * configs, read-only + */ + @Override + public void acceptTargets(Set myTargets, Set otherTargets) {} + + /** + * This does not apply any additional mixins. + * @return always null + */ + @Override + public List getMixins() { + return null; + } + + /** + * Called immediately before a mixin is applied to a target class. + * Will apply Lillero patches if {@link #precedence} is true. + * @param className transformed name of the target class + * @param clazz target class tree + * @param mixinClassName name of the mixin class + * @param mixinInfo information about this mixin + */ + @Override + public void preApply(String className, ClassNode clazz, String mixinClassName, IMixinInfo mixinInfo) { + if(precedence) this.applyLilleroPatches(className, clazz); + } + + /** + * Called immediately after a mixin is applied to a target class. + * Will apply Lillero patches if {@link #precedence} is false. + * @param className transformed name of the target class + * @param clazz target class tree + * @param mixinClassName name of the mixin class + * @param mixinInfo information about this mixin + */ + @Override + public void postApply(String className, ClassNode clazz, String mixinClassName, IMixinInfo mixinInfo) { + if(!precedence) this.applyLilleroPatches(className, clazz); + } + + /** + * Applies the appropriate Lillero patches given a node and a class name. + * @param className the class' fully qualified name + * @param clazz the target class + */ + protected void applyLilleroPatches(String className, ClassNode clazz) { + List injectors = this.injectorMap.remove(className); // remove so it's only once + if(injectors != null) { + injectors.forEach((inj) -> clazz.methods.stream() + .filter(m -> m.name.equals(inj.methodName()) && m.desc.equals(inj.methodDesc())) + .forEach(m -> { + try { + LOGGER.info( + "Patching {}.{} with {} ({})", + className, m.name, + inj.name(), + inj.reason()); + inj.inject(clazz, m); + } catch (InjectionException exception) { + LOGGER.error("Error applying patch '{}' : {}", inj.name(), exception); + } + })); + } + } +} diff --git a/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService b/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService index 24a7caf..c159a13 100644 --- a/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService +++ b/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService @@ -1 +1 @@ -ftbsc.lll.mixin.LilleroMixin +ftbsc.lll.mixin.LilleroMixinPlugin -- cgit v1.2.3-56-ga3b1