Getting Started

Registering Content

Learn how to register content with Balm.

Content, such as Blocks and Items, is registered using helpers you can access through the BalmRegistrars instance that is passed to your initializer. Balm provides various convenient helper methods for registering standard content, as well as the ability to register into any other registry using the generic registrar(...) method.

common/src/main/java/Waystones.java
public class Waystones {
    public static DeferredBlock waystoneBlock;

    public static void initialize(BalmRegistrars registrars) {
        registrars.blocks(registrar -> {
            waystoneBlock = blocks.register("waystone", WaystoneBlock::new, it -> it.sound(SoundType.STONE).strength(5f, 2000f)).withItem(WaystoneBlockItem::new).asDeferredBlock();
        });
    }
}

Structuring your Content

As your mod grows, it often makes sense to split content registrations into their own classes depending on their type.

common/src/main/java/ModBlocks.java
public class ModBlocks {
    public static void initialize(BalmBlockRegistrar blocks) {
        blocks.register(registrar -> {
            waystoneBlock = blocks.register("waystone", WaystoneBlock::new, 
                it -> it.sound(SoundType.STONE)
                        .strength(5f, 2000f)
            ).withItem(WaystoneBlockItem::new).asDeferredBlock();
        });
    }
}
common/src/main/java/Waystones.java
public class Waystones {
    public static void initialize(BalmRegistrars registrars) {
        registrars.blocks(ModBlocks::initialize);
    }
}

Caveat: Deferred Registrations

In a multi-loader context, registrations are not necessarily instant across all loaders.

While Fabric registers content the moment you make the call, NeoForge and Forge defer registrations until a later time.

That's why anything you register with Balm will generally either provide you with a Holder, or something like DeferredBlock or DeferredItem rather than the Block or Item directly.

Many Minecraft methods accept Holders (or Balm's DeferredBlock and DeferredItem classes) just fine, but if you need to, you can access the underlying values using Holder.value() or e.g. DeferredBlock.asBlock().

DeferredBlock also comes with a useful defaultBlockState() method (since that is what you most commonly need a Block field for), and both DeferredBlock and DeferredItem have a createStack(int count) method to quickly get a new ItemStack of them.

Be careful not to access the underlying values too early, i.e. before the game has finished loading, or your mod may crash on NeoForge and Forge.
Avoid equality checks such as itemStack.getItem() == ModItems.warpStone, as they will always be false when using DeferredItem. Use itemStack.is(ModItems.warpStone) instead, or consider using an Item Tag where it makes sense.

Using other Registries

The most common registries are covered by specialized Balm...Registrar classes which not only provide useful helpers for registering things in a neat and streamlined manner, but may also take care of additional steps in the background that are needed to make your content function. Therefore, if Balm provides a specialized registrar for the registry you need, you should use it to avoid issues.

For registries that are not covered by Balm, you can use the custom registrar method instead:

common/src/java/main/ModSounds.java
public class ModSounds {
    public static Holder<SoundEvent> fridgeOpen;

    public static void initialize(BalmRegistrar.Scoped<SoundEvent> sounds) {
        fridgeOpen = sounds.register("fridge_open", SoundEvent::createVariableRangeEvent);
    }
}
common/src/java/main/CookingForBlockheads.java
public class CookingForBlockheads {
    public static void initialize(BalmRegistrars registrars) {
        registrars.registrar(Registries.SOUND_EVENT, ModSounds::initialize);
    }
}