Advanced

Mod Entrypoints

Learn how to setup your mod entrypoints to initialize Balm.

Overview

In order for your mod to be loaded, you must create a mod-loader specific entrypoint inside each corresponding mod-loader subproject, and register your mod with Balm inside.

If you use the balm-mod template repository, this setup is already done for you.

To do that, you need to add calls to Balm.initializeMod() in each of your entrypoints - that is your ModInitializer on Fabric, and your @Mod class constructors in Neo/Forge.

Similarly, your ClientModInitializer and your client-side @Mod class (NeoForge only) should use BalmClient.initializeMod(). On Forge, wrap this call in a FMLEnvironment.dist.isClient() check. Examples for each mod loader are provided below.

NeoForge

neoforge.mods.toml

Your mod must come with a neoforge.mods.toml file that defines the metadata, dependencies and mixin configurations to load.

Refer to the NeoForge documentation to learn more.

Common Entrypoint

neoforge/src/main/java/NeoForgeWaystones.java
@Mod(Waystones.MOD_ID)
public class NeoForgeWaystones {

    public NeoForgeWaystones(IEventBus modEventBus) {
        final var loadContext = new NeoForgeLoadContext(modEventBus);
        Balm.initializeMod(Waystones.MOD_ID, loadContext, Waystones::initialize);
    }

}

Client Entrypoint

neoforge/src/main/java/NeoForgeWaystonesClient.java
@Mod(value = Waystones.MOD_ID, dist = Dist.CLIENT)
public class NeoForgeWaystonesClient {

    public NeoForgeWaystonesClient(IEventBus modEventBus) {
        final var loadContext = new NeoForgeLoadContext(modEventBus);
        BalmClient.initializeMod(Waystones.MOD_ID, loadContext, WaystonesClient::initialize);
    }

}

Fabric

fabric.mod.json

Your mod must come with a fabric.mod.json file that defines the main and client entrypoints to your entrypoint classes as well as all other metadata.

Refer to the Fabric documentation to learn more.

Balm provides a default Mod Menu entrypoint to automatically expose your mod's configuration through supported config screens.You should only need to define a custom modmenu entrypoint if you want to provide your own configuration screen or make other changes.

Common Entrypoint

fabric/src/main/java/FabricWaystones.java
public class FabricWaystones implements ModInitializer {
    
    @Override
    public void onInitialize() {
        Balm.initializeMod(Waystones.MOD_ID, FabricLoadContext.INSTANCE, Waystones::initialize);
    }

}

Client Entrypoint

fabric/src/main/java/FabricWaystonesClient.java
public class FabricWaystonesClient implements ClientModInitializer {
    
    @Override
    public void onInitializeClient() {
        BalmClient.initializeMod(Waystones.MOD_ID, FabricLoadContext.INSTANCE, WaystonesClient::initialize);
    }

}

Forge

mods.toml

Your mod must come with a mods.toml file that defines the metadata and dependencies to load.

Refer to the Forge documentation to learn more.

Also note that Forge uses the MixinConfigs manifest attribute to define mixin configurations. On the template projects this is already taken care of, but otherwise you may have to adjust your gradle files to set the attribute accordingly.

Common & Client Entrypoint

forge/src/main/java/ForgeWaystones.java
@Mod(Waystones.MOD_ID)
public class ForgeWaystones {
    final var loadContext = new ForgeLoadContext(context.getModEventBus());
    Balm.initialize(Waystones.MOD_ID, loadContext, Waystones::initialize);
    if (FMLEnvironment.dist.isClient()) {
        BalmClient.initialize(Waystones.MOD_ID, loadContext, WaystonesClient::initialize);
    }
}
This looks scary because it's accessing client-only code from a common context, but it's actually safe in modern Java as long as the methods involved are all static.

Third Party Mod Compatibility

The mod-loader specific entrypoints are also a good place to initialize addon compatibility classes that are only present in your mod-loader subprojects.

You can use Balm.initializeIfLoaded to only load the given class if the mod is present, avoiding a hard dependency on the third party mod.

Example
Balm.initializeIfLoaded("exnihilosequentia", "net.blay09.mods.excompressum.compat.ExNihiloSequentiaIntegration");
Don't use YourIntegration.class.getName() as that will cause the class to be loaded even if the third party mod isn't present, which would lead to a crash if that class happens to access any classes from the third party mod.