Skip to content

Mixin Annotation Adjuster

Bawnorton edited this page Aug 5, 2024 · 4 revisions

⚠️ Usage of MixinSquared on a maintained project is discouraged ⚠️
Making a PR or raising an issue would be more suitable

MixinSquared provides a way to manipulate the annotations used in Mixins that would normally be out of a user's control as other mod's mixins are not passed through their IMixinConfigPlugin.

Implementation

To use the adjuster is you need to implement the MixinAnnotationAdjuster interface and then register it.

public class YourModMixinAnnotationAdjuster implements MixinAnnotationAdjuster {
    @Override
    public AdjustableAnnotationNode adjust(List<String> targetClassNames, String mixinClassName, MethodNode method, AdjustableAnnotationNode annotation) {
        // To leave the annotation unchanged simply:
        /* return annotation; */

        // You can check if you're inside a specific mixin and targeting a specific annotation:
        if(!mixinClassName.equals("com.bawnorton.sandbox.mixin.LivingEntityMixin")) return annotation;
        if(!annotation.is(WrapOperation.class)) return annotation;

        // You can now safely cast to the appropriate AdjustableAnnotationNode:
        // Use a normal cast or the "as" helper if you wish to chain method calls instead
        AdjustableWrapOperationNode wrapOpNode = annotation.as(AdjustableWrapOperationNode.class);
        
        // If you want to narrow down the search even further, helper methods are provided for each adjustable node to query their attributes.
        if(wrapOpNode.getAt() // "at = "
                     .get(0) // at accepts an array so "getAt" returns a list
                     .getTarget() // "target = "
                     .equals("Lnet/minecraft/entity/LivingEntity;getWorld()Lnet/minecraft/world/World;")) {
            // You can remove the annotation entirely, the specified annotation will not be present when the mixin is applied and thus, will not be injected. 
            // The handler will still be present in the resultant mixin, it'll just be treated as a normal merged method.
            return null;
        } else {
            // You can also modify the node directly with use of the helper methods.
            return wrapOpNode.withAt(at -> {
                at.get(0)
                  .setOrdinal(1); // "ordinal = "
                return at;
            });
        }
    }
}

Note:

All AdjustableAnnotationNode classes that are provided have getAttribute, setAttribute and withAttribute helper methods for querying and adjusting the annotation they represent.
AdjustableAnnotationNode can represent an annotation that is not recognised but there will be no helper methods, instead you can use:

  • <T>get(String key) -> Optional<T> to query an attribute.
  • getEnum(String key, Class<T> enumClass) -> Optional<T> to query an enum attribute.
  • set(String key, Object value) -> void to set a value.

⚠️ Warning ⚠️

There are minimal checks on these methods as they interact directly with the node which allows you to set or query attributes which do not normally exist on the annotation which can cause crashes.

Registering

I am using Fabric

Inside your fabric.mod.json you will need to add the following entrypoint:

  "entrypoints": {
    "mixinsquared-adjuster": [
      "com.example.mod.YourModMixinAnnotationAdjuster"
    ]
  }

I am using Forge or anything else

You will need to declare a service called com.bawnorton.mixinsquared.api.MixinAnnotationAdjuster inside the META-INF/services/ directory.
The content of this file will need to be a reference to your MixinAnnotationAdjuster implementation(s):

com.example.mod.YourModMixinAnnotationAdjuster
Screenshot 2024-05-20 at 5 44 30 PM

I want to register it myself

In the onLoad method inside a IMixinConfigPlugin you can register a MixinAnnotationAdjuster directly using the MixinAnnotationAdjusterRegistrar like so:

public class YourModMixinConfigPlugin implements IMixinConfigPlugin {
    @Override
    public void onLoad(String mixinPackage) {
        MixinAnnotationAdjusterRegistrar.register(new YourModMixinAnnotationAdjuster());
    }
    ...
}