Skip to content
This repository was archived by the owner on Nov 29, 2025. It is now read-only.
melontini edited this page Jan 6, 2024 · 3 revisions

This page covers the Base module of Dark Matter.

ConfigManager

This class provides a common interface for saving and loading configs. Unlike other config managers, this one does not store an instance of your config.

The Path must be provided separately for each load/save call. In most cases, this will be FabricLoader.getInstance().getConfigDir().

The implementation also provides simple onSave and onLoad events, as well as a way to handle config exceptions.

    private static final ConfigManager<Config> MANAGER = ConfigManager.of(Config.class, "my_mod/client", Config::new)
            .exceptionHandler((e, stage, path) -> LOGGER.error("Failed to %s my_mod/client config!".formatted(stage.toString().toLowerCase()), e));
    public static final Config CONFIG;
    public static final Config DEFAULT;

    static {
        CONFIG = MANAGER.load(FabricLoader.getInstance().getConfigDir());
        DEFAULT = MANAGER.createDefault();
        MANAGER.save(FabricLoader.getInstance().getConfigDir(), CONFIG);
    }

    public static void save() {
        MANAGER.save(FabricLoader.getInstance().getConfigDir(), CONFIG);
    }

There's no real point in using this for single-instance configs, when better solutions, like Cloth and Carbon, are available. This is meant for situations, where you have to store multiple config instances, like Andromeda's ScopedConfigs system.

ExtendablePlugin

ExtendablePlugin is an experimental IMixinConfigPlugin extension. Replaces the old ExtendedPlugin.

This class provides a pseudo-plugin system where plugins can add different modules to themselves. For example, to process simple annotations.

Built-in plugins include:


@MixinPredicate

Decides if a mixin should be applied based on some conditions.

Currently, you can specify an array of @Mod annotations. For example:

@Mixin(MinecraftClient.class)
@MixinPredicate(mods = @Mod(value = "minecraft", version = "<=1.19.2"))
public class MinecraftClientMixin {
   //throw exception on clinit
}

Other examples:

@MixinPredicate(mods = @Mod(value = "connectormod", state = Mod.State.NOT_LOADED)) //Apply only if Connector is not loaded

@MixinPredicate(mods = {@Mod("sodium"), @Mod("iris")}) //Apply only if both sodium and iris are loaded.

@Publicize

Meant to be used alongside @Unique static methods and fields. Changes access of a member from private/protected to public.


@AsmTransformer

In some cases Mixin might not be enough for your transformation needs. In those cases your alternative is ASM.

If your modifications only require ASM transformations, Fabric-ASM is a perfect fit, but what if your transformation is complementary to your Mixin? Maybe you have to un-abstract a method, break a loop, change a field type, etc. In that case this annotation provides just that.

Just annotate a @Mixin class and provide an array of classes implementing the IAsmTransformer interface.


@ConstructDummy

This annotation is experimental. Use at your own risk!

Meant to be used with HEAD/TAIL @Inject annotations. Creates a dummy that simply calls super, if no such method exists.

For example. Let's say I want to mixin into SnowballEntity.tick(), but the only class in the hierarchy which overrides tick() is ThrownEntity. In this case, you'll probably want to inject into ThrownEntity.tick() and add an instanceof check:

@Mixin(ThrownEntity.class)
public class ThrownEntityMixin {
    
    @Inject(at = @At("HEAD"), method = "tick()V")
    public void inject(CallbackInfo ci) {
        if ((Object) this instanceof SnowballEntity) {
            //whatever
        }
    }
}

It's fine in most cases, just a little ugly, and if you need to add new, snowball-only logic/fields, they will be available for all inheritors of this class.

@ConstructDummy has 3 required and 1 optional parameters.

  • owner - the original owner of the method. In case of SnowballEntity this would be Entity and not ThrownEntity.
  • name - the name of the method.
  • desc - the descriptor of the method. In case of tick, its ()V.

Names must be in the intermediary format! If you use yarn, you can find them here: https://github.com/FabricMC/yarn

Optional:

  • access - public by default.
@Mixin(SnowballEntity.class)
public class SnowballEntityMixin {

    @SuppressWarnings({"MixinAnnotationTarget", "UnresolvedMixinReference"})
    @ConstructDummy(owner = "net.minecraft.class_1297", name = "method_5773", desc = "()V")
    @Inject(at = @At("HEAD"), method = "tick()V")
    public void inject(CallbackInfo ci) {
        //whatever
    }
}

Note

Why this is experimental:

  • No validation. The plugin just creates a method, it doesn't check the superclass to see if the method is: not static, varargs, synthetic, exists, etc.
  • Names must be provided separately. It would be great to parse them from the method selector, but I can't figure it out.
  • Warnings during build. Because the method does not exist, Mixin AP raises valid warnings.
  • Is this even useful?

@MixinShouldApply

Old version of @MixinPredicate. Has less features and should not be used.

Clone this wiki locally