LogoSinytra Connector

Plugins

Plugins

Connector offers a transformer API that extending its mod processing pipeline. This can be used to add new jar transformers or mixin patches.

Example usage includes developing addons that provide support for specific mods through hardcoded mixin patches.

All API classes including javadocs can be found under the org.sinytra.connector.transformer.api package.

Authoring plugins

Plugins are loaded as Java services from the runtime classpath during mod discovery. Connector will initialize plugins at once, and then run them to gather patches and transformers for every jar individually.

To get started, create a class that implements the org.sinytra.connector.transformer.api.TransformerPlugin interface.

ExampleTransformerPlugin.java
public class ExampleTransformerPlugin implements TransformerPlugin {
@Override
public String name() {
return "examplemod:plugin";
}
// Override methods as desired
}

Then, create a file that provivides this plugin under META-INF/services/org.sinytra.connector.transformer.api.TransformerPlugin.

org.sinytra.connector.transformer.api.TransformerPlugin
com.example.examplemod.ExampleTransformerPlugin

Loading the jar

Connector runs before mod discovery, and therefore all plugins must be present at this time as well.

For this, you'll need to mark you jar as an early FML service to make FML load it before it begins the discovery process. This is very simple, as all you need to do is add a service file for an eligible early service. In this guide, we'll be using IModFileCandidateLocator.

Simply create an empty file under META-INF/services/net.neoforged.neoforgespi.locating.IModFileCandidateLocator.

Registering jar transformers

One of the available plugin methods is registerJarTransformers, which accepts a TransformerRegistrar. You can use this interface to register ART transformers that modify the contents of jars at the file level.

You can choose the order in which these transformers are executed by supplying a set of transformer names that should run before/after your transformer as well as ordering hints that affect the general sorting order.

Each transformer should be given a globally unique name. We recommend using prefixed names in line with the game's resource location standard.

@Override
public void registerJarTransformers(TransformerRegistrar registrar, TransformerContext context) {
// Run regardless of order
registrar.register("examplemod:example_tx", new ExampleTransformer());
// Run before all transformers
registrar.register("examplemod:early_tx", null, null, OrderingHint.EARLY, new ExampleTransformer());
// Run after mixin patches
registrar.registerAfter("examplemod:late_patch", Set.of(TransformerIds.METHOD_PATCHES), new PatchTransformer());
}

Adding mixin patches

The registerPatches method allows adding manual/hardcoded mixin patches. This is particularly useful when you want to fix compatibility with a specific mod.

@Override
public void registerPatches(PatchRegistrar registrar, TransformerContext context) {
// Target a specific mod only
if (!context.candidateJar().modMetadata().getId().equals("sandbox")) {
return;
}
// Register with default priority
registrar.add(
MethodPatch.builder()
.targetClass("net/minecraft/client/KeyMapping")
.targetMethod("set")
.targetInjectionPoint("TAIL")
.modifyInjectionPoint("INVOKE", "Lnet/minecraft/client/KeyMapping;setDown(Z)V")
.build()
);
// Register with given priority
registrar.register(
PatchRegistrar.HIGHER_SYSTEM_PRIORITY, // 500
MethodPatch.builder().build()
);
}