Mixin
repository·master·Indexed 23 days ago
https://github.com/spongepowered/mixinA Java trait/mixin framework that uses ASM to hook into the runtime classloading process, allowing developers to modify existing bytecode via pluggable services. It includes an Annotation Processor for handling obfuscation tasks and supports integration with Gradle, Eclipse, and IntelliJ IDEA. The framework provides tools like AnnotatedMixin for managing metadata and Mappings for handling field and method obfuscation data.
What's inside spongepowered-mixin
- Mixin is a trait/mixin framework for Java that utilizes ASM to hook into the runtime classloading process. It uses a set of pluggable services (built-in or user-provided) to perform transformations. While it supports Mojang's LegacyLauncher, it is increasingly used with ModLauncher for better extensibility and support for Java 8 and later.
Configure Mixin Annotation Processor in Eclipse
masterTo receive context-sensitive errors and warnings in Eclipse, you can integrate the Mixin Annotation Processor by following these steps:
- Run
gradle buildto generate the mixin jar. - In your Eclipse project properties, navigate to
Java Compiler->Annotation Processing->Factory Path. - Check
Enable project specific settings. - Click
Add External JARsand select the generated mixin jar with the-processorsuffix (typically found inMixin/build/libs). - Navigate to
Java Compiler->Annotation Processing. - Check
Enable project specific settingsandEnable annotation processing. - Next to
Processor options, clickNew...and set:- Key:
reobfSrgFile - Value: The fully-qualified path to your
mcp-srg.srgfile.
- Key:
- Click
OKto apply.
- Run
Use the Minecraft Development plugin for IntelliJ IDEA
masterFor enhanced functionality and better integration when working with Mixin in IntelliJ IDEA, use the Minecraft Development for IntelliJ IDEA plugin developed by DemonWav.Configure the Mixin Annotation Processor in Gradle
masterMixin provides an Annotation Processor (AP) to handle obfuscation tasks at compile time by generating mappings.
If you are using Gradle 5 or later, you must explicitly specify the annotation processor using the
annotationProcessorconfiguration. Mixin provides "fat jar" artifacts containing all required dependencies via the:processorclassifier.For example, if your dependency is
org.spongepowered:mixin:1.2.3, your configuration should look like this:dependencies { implementation 'org.spongepowered:mixin:1.2.3' annotationProcessor 'org.spongepowered:mixin:1.2.3:processor' }If you are working on a Minecraft Forge project, the MixinGradle plugin can be used to simplify this configuration.
AnnotatedMixin class overview
masterAnnotatedMixinis a class used during the Mixin annotation processing phase to store and manage information about a Mixin class. It implementsIMixinContextandIAnnotatedElement, acting as a central repository for a Mixin's metadata, including its targets, methods, annotations, and handlers for various Mixin features like@Inject,@Shadow,@Overwrite, and@Accessor. It is primarily used by the Mixin annotation processor to validate and prepare Mixins for remapping and bytecode transformation.Access Mixin Binaries and Maven Repositories
masterMixin binaries are available via Jenkins or through the following Maven repositories:
https://repo.spongepowered.org/repository/maven-public/(Contains both SNAPSHOTs and RELEASE builds)https://files.minecraftforge.net/maven/(Contains RELEASE builds only)
Register an @Inject in AnnotatedMixin
masterUse
registerInjectorto register an injection point (e.g., using the@Injectannotation) on a method. This method automatically handles the registration of@Atselectors and@Slicecoordinates if they are present on the annotation.// Example usage annotatedMixin.registerInjector(method, injectAnnotation, remapOption);public void registerInjector(ExecutableElement method, AnnotationHandle inject, InjectorRemap remap) { this.removeMethod(method); AnnotatedElementInjector injectorElement = new AnnotatedElementInjector(method, inject, this, remap); this.injectors.registerInjector(injectorElement); List<IAnnotationHandle> ats = inject.getAnnotationList("at"); for (IAnnotationHandle at : ats) { this.registerInjectionPoint(method, inject, "at", (AnnotationHandle)at, remap, "@At(%s)"); } List<IAnnotationHandle> slices = inject.getAnnotationList("slice"); for (IAnnotationHandle slice : slices) { String id = slice.<String>getValue("id", ""); String coord = "slice"; if (!Strings.isNullOrEmpty(id)) { coord += "." + id; } SelectorAnnotationContext sliceContext = new SelectorAnnotationContext(injectorElement, slice, coord); IAnnotationHandle from = slice.getAnnotation("from"); if (from != null) { this.registerSliceInjectionPoint(method, inject, "from", (AnnotationHandle)from, remap, "@Slice[" + id + "](from=@At(%s))", sliceContext); } IAnnotationHandle to = slice.getAnnotation("to"); if (to != null) { this.registerSliceInjectionPoint(method, inject, "to", (AnnotationHandle)to, remap, "@Slice[" + id + "](to=@At(%s))", sliceContext); } } }Register an @Accessor in AnnotatedMixin
masterUse
registerAccessorto register an accessor method (e.g., using the@Accessorannotation) that provides access to a field in a target class.annotatedMixin.registerAccessor(element, accessorAnnotation, shouldRemap);public void registerAccessor(Element element, AnnotationHandle accessor, boolean shouldRemap) { this.removeMethod(element); this.accessors.registerAccessor(new AnnotatedElementAccessor(element, accessor, this, shouldRemap)); }Ensure mapping uniqueness with asUnique()
masterWhen consuming mappings, you may want to prevent conflicts where the same source field or method is mapped to different destinations. Wrapping your
Mappingsinstance withasUnique()provides aUniqueMappingsdecorator that validates uniqueness.If a conflict is detected (i.e., the same source element is being mapped to a different destination than previously recorded), a
MappingConflictExceptionis thrown.Retrieve Mixin metadata from AnnotatedMixin
masterThe
AnnotatedMixinclass provides several methods to inspect the Mixin's properties during the annotation processing phase:getAnnotation(): Returns theIAnnotationHandlefor the@Mixinannotation.getMixinElement(): Returns theTypeElementrepresenting the Mixin class.getHandle(): Returns theTypeHandlefor the Mixin class.getClassRef(): Returns the internal bytecode name of the Mixin class.getTargetClassName(): Returns the name of the primary target class.getTargetClassRef(): Returns the name of the primary target class.getTargets(): Returns aList<TypeHandle>of all targets this Mixin applies to.isMultiTarget(): Returnstrueif the Mixin targets more than one class.isInterface(): Returnstrueif the Mixin class is an interface.remap(): Returnstrueif remapping should be applied to annotations in this Mixin.
Use Mappings to manage obfuscation mapping data
masterThe
Mappingsclass is a reference implementation ofIMappingConsumerused to store and manage field and method mappings for differentObfuscationTypes. It allows you to add mappings for fields and methods and retrieve them asMappingSets.To ensure that no single source element maps to multiple destination elements (which would cause conflicts), you can wrap the
Mappingsinstance in aUniqueMappingsconsumer using theasUnique()method.Register an @Invoker in AnnotatedMixin
masterUse
registerInvokerto register an invoker method (e.g., using the@Invokerannotation) that allows calling a method in a target class that might otherwise be inaccessible.annotatedMixin.registerInvoker(element, invokerAnnotation, shouldRemap);