Skip to content

Repository files navigation

SimpleMixinConfig

A Mixin library that physically removes disabled injection methods from Mixin bytecode at runtime, driven by a TOML config file. No runtime guards are needed in your Mixin methods!

Features

  • Bytecode-level removal: Disabled injection methods are stripped from the Mixin ClassNode before the Mixin framework processes them. Your methods simply don't get injected: no isEnabled() checks required.
  • Auto-generated TOML config: Scans your Mixin classes and generates a TOML config file with one toggle per injection method (and group).
  • Package or class scanning: Scan entire packages recursively, or specify individual Mixin classes.
  • Method grouping: Methods with the same base name (e.g. injectHealth, injectHealth_1) share a single config toggle.
  • Auto-migration: Existing config values are preserved; new injection points are added automatically on next load.
  • Runtime queries: Optional isEnabled() helper for cases where you need to know a Mixin's state at runtime.

Setup

1. Add dependency

Gradle (Groovy):

repositories {
    maven { url = uri("https://jitpack.io") }
}
dependencies {
    implementation("com.github.Tater-Certified:SimpleMixinConfig:<version>")
}

2. Register the plugin

Add the preconfigured plugin to your mixins.<modid>.json:

"plugin": "com.github.tatercertified.simplemixinconfig.plugin.MixinConfigPlugin"

Custom IMixinConfigPlugin

If you need your own plugin (e.g. to combine with other Mixin libraries like MixinConstraints), add the following to your IMixinConfigPlugin:

public class MyMixinPlugin implements IMixinConfigPlugin {

    @Override
    public void onLoad(String mixinPackage) {
        // Make sure it is declared in this order
        Path configPath = Path.of("config/mymod_mixins.toml");
        SimpleMixinConfig.init(configPath);
        SimpleMixinConfig.scanPackages("com.example.mixins");
        SimpleMixinConfigBootstrap.registerExtension();
    }

    // ... other methods
}

3. Initialize (before mixins are applied)

If you used the built-in IMixinConfigPlugin, you need to register these before Mixins are loaded:

// These must be declared in this order
Path configPath = Path.of("config/mymod_mixins.toml");
SimpleMixinConfig.init(configPath);
SimpleMixinConfig.scanPackages("com.example.mixins");

That's it! Disabled injection methods are physically removed during runtime. No changes are needed in your Mixin code.

Config Layout

The library generates a TOML file with one section per Mixin class:

[PlayerMixin]
"injectHealth" = true
"modifySpeed" = false

[InventoryMixin]
"onOpen" = true
  • true: the injection method is applied normally
  • false: the injection method is physically removed from the mixin bytecode during runtime; it will never be injected
  • New injection points are automatically added when you add methods to your Mixins

API reference

Method Description
init(Path) Set the config file path. Call once before scanning.
scanPackages(String...) Scan Mixin packages, read/generate config, apply settings.
scanClasses(String...) Scan specific Mixin classes, read/generate config, apply settings.
isEnabled(String className, String methodName) Check if an injection point is enabled at runtime. Returns null if not found.
getScannedData() Access the raw scanned Mixin data.
isInitialized() Check if init() was called and clear() was not.
clear() Free all internal data and memory. Call after Mixin processing is complete.

A more detailed explanation of certain API features is explained below.

Scanning options

Scanning allows this library to access all the Mixins in a package (or specific Mixin file) and gather all injection points within the Mixins. This data is then used to build a config file. Both methods can be used at the same time, but it is discouraged to use the same method twice.

Scan one or more packages (recursive)

SimpleMixinConfig.scanPackages(
    "com.example.mixins",
    "com.example.mixins.world" // This one is not necessary since the first covers it
);

Scan specific Mixin classes

SimpleMixinConfig.scanClasses(
    "com.example.mixins.PlayerMixin",
    "com.example.mixins.InventoryMixin"
);

Runtime checks (optional)

Because disabled methods are removed at transform time, you normally don't need isEnabled(). Use it only when you have non-injection code that depends on knowing whether a mixin is active:

@Mixin(SomeClass.class)
public class PlayerMixin {
    @Inject(method = "getHealth", at = @At("head"))
    private void modid$injectHealth(CallbackInfo info) {
        // This method is only injected if it's enabled in config.
        // No guard needed here.
        doSomething();
    }

    // Non-injection code that depends on the Mixin being active:
    public static void maybeDoSomething() {
        Boolean enabled = SimpleMixinConfig.isEnabled("PlayerMixin", "modid$injectHealth");
        if (enabled != null && enabled) {
            // The injection is active, do something that relies on it
        }
    }
}

Freeing memory

Once all Mixins have been applied, the scanned data is no longer needed for the bytecode removal extension. Call clear() to release it. A good place to do this is once the server starts. Most loaders have an event for it, but if they don't, make the following Mixin:

@Mixin(MinecraftServer.class)
public class ClearConfigMemoryMixin {
    @Inject(method = "<clinit>", at = @At(value = "FIELD", target = "Lnet/minecraft/server/MinecraftServer;LOGGER:Lorg/slf4j/Logger;"))
    private static void modid$onServerStarting(CallbackInfo ci) {
        // Clears the Mixin's held storage
        SimpleMixinConfig.clear();
    }
}

After clear():

  • isInitialized() returns false
  • isEnabled() returns null
  • shouldApplyMixin() returns true

Don't call clear() if you use runtime isEnabled() checks.

License

Licensed under MIT

About

A Mixin library that physically removes disabled injection methods from Mixin bytecode at runtime, driven by a TOML config file

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages