Skip to content

Instantly share code, notes, and snippets.

@CorgiTaco
Last active April 30, 2022 06:00
Show Gist options
  • Save CorgiTaco/d1146ade86b9fe9582f5a263b0d75c00 to your computer and use it in GitHub Desktop.
Save CorgiTaco/d1146ade86b9fe9582f5a263b0d75c00 to your computer and use it in GitHub Desktop.
MultiLoader abstract registration

Multi Loader Abstract Registration

The point of this gist is to explain how my mods like BYG register their registry objects(ie. blocks) in a way that avoids duplicate code across all modules and keeps it only in the common module.

Common Module

In the common module objects we utilize a helper class that contains both the object and the ID like so:

public record BYGRegistryObject<T>(T object, String id) {
}

In our class containing an object type(let's use blocks in this example) we need the following statics:

    private static final List<BYGRegistryObject<Block>> BLOCKS = new ArrayList<>();
    
        public static Block createBlock(Block block, String id) {
        BLOCKS.add(new BYGRegistryObject<>(block, id));
        return block;
    }

    public static Collection<BYGRegistryObject<Block>> bootStrap() {
        return BLOCKS;
    }

Which allows us to static final init our blocks:

    public static final Block ASPEN_PLANKS = createPlanks("aspen_planks");
    public static final Block BAOBAB_PLANKS = createPlanks("baobab_planks");
    public static final Block BLUE_ENCHANTED_PLANKS = createPlanks("blue_enchanted_planks");
    public static final Block CHERRY_PLANKS = createPlanks("cherry_planks");
    public static final Block CIKA_PLANKS = createPlanks("cika_planks");
    
    private static Block createPlanks(String id) {
        return createBlock(new Block(BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2.0f, 3.0f)), id);
    }

Below are how we use this system in the Common Module by mod loader:

Forge Module

@Mod(BYG.MOD_ID)
public class BYGForge {

    public BYGForge() {
        IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus();
        bootStrap(eventBus);
    }

    private static void bootStrap(IEventBus eventBus) {
        // We want to static init the class during the registry event not during mod class construction, so we use a supplier here.
        register(Block.class, eventBus, () -> BYGBlocks.bootStrap());
    }


    private static <T extends IForgeRegistryEntry<T>> void register(Class clazz, IEventBus eventBus, Supplier<Collection<BYGRegistryObject<T>>> registryObjectsSupplier) {
        eventBus.addGenericListener(clazz, (RegistryEvent.Register<T> event) -> {
            Collection<BYGRegistryObject<T>> registryObjects = registryObjectsSupplier.get();
            IForgeRegistry<T> registry = event.getRegistry();
            for (BYGRegistryObject<T> registryObject : registryObjects) {
                registryObject.object().setRegistryName(BYG.createLocation(registryObject.id()));
                registry.register(registryObject.object());
            }
        });
    }
}

Fabric Module

public class BYGFabric implements ModInitializer {

    @Override
    public void onInitialize() {
        registryBootStrap();
    }

    private void registryBootStrap() {
        register(Registry.BLOCK, BYGBlocks.bootStrap());
    }

    public static <T> void register(Registry<T> registry, Collection<BYGRegistryObject<T>> objects) {
        for (BYGRegistryObject<T> object : objects) {
            Registry.register(registry, createLocation(object.id()), object.object());
        }
    }

Minecraft now does registry freezing for us(1.18.2+), any calls we make that are early(before registration) or if we attempt to register after the registries freeze, is an incorrect call and the call in question should use a supplier if possible. The goal for us is we want to avoid use mod loader specific registration classes systems for registration which helps keep duplicate code low. It is also possible that using static finals may assist the Java Internal Compiler in optimizing calls to these fields, although I have no evidence of said optimization, but one can dream :')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment