DEV Community

Cover image for How to Develop Minecraft Mods Using Temporal API?
w4t3r
w4t3r

Posted on

How to Develop Minecraft Mods Using Temporal API?

This article is intended for those who have developed Minecraft mods before or are planning to try it out of personal interest. The topic is simplifying development with NeoForge using the Temporal API library.


Introduction

What Is NeoForge?

Before discussing Temporal API, it makes sense to briefly explain what NeoForge is.

If you search Google for “What is NeoForge?”, you’ll find something like this:

NeoForge is a modern open-source API and mod loader for Minecraft: Java Edition, created as a fork of the popular Forge loader.

In simpler terms, NeoForge is one of the most widely used mod loaders (a layer between mods and the game), alongside Fabric, Quilt, and Minecraft Forge.

NeoForge was released relatively recently and is developed by part of the former Forge team. It is actively maintained and updated, and most modern mods are now built with NeoForge. For that reason, I strongly recommend it for new mod development.


One of the Main Problems with NeoForge

One of the main challenges when developing mods with NeoForge is the large amount of repetitive boilerplate code. It often prevents you from focusing on creating something interesting and unique.

As an example, let’s create a basic item and add a simple model in Minecraft 1.21.1 (ignoring project setup and focusing only on the Java side):

@Mod(ExampleMod.MOD_ID)
public class ExampleMod { // 1
    public static final String MOD_ID = "example";

    public ExampleMod(IEventBus modEventBus, ModContainer modContainer) {
        ExampleItems.ITEMS.register(modEventBus); // 5
        NeoForge.EVENT_BUS.register(this); // 10
    }

    @SubscribeEvent
    public static void gatherData(GatherDataEvent event) { // 8
        DataGenerator generator = event.getGenerator();
        PackOutput output = generator.getPackOutput();
        ExistingFileHelper existingFileHelper = event.getExistingFileHelper();

        generator.addProvider(
            event.includeClient(),
            new ExampleItemModelProvider(output, existingFileHelper) // 9
        );
    }
}

public class ExampleItems {  // 2
    public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID);  // 3

    public static final DeferredItem<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item", new Item.Properties()); // 4
}

public class ExampleItemModelProvider extends ItemModelProvider { // 6
    public ExampleItemModelProvider(PackOutput output, ExistingFileHelper existingFileHelper) {
        super(output, "examplemod", existingFileHelper);
    }

    @Override
    protected void registerModels() {
        basicItem(ExampleItems.EXAMPLE_ITEM.get()); // 7
    }
}
Enter fullscreen mode Exit fullscreen mode

What is happening here:

  1. We create the main mod class. Its constructor effectively acts as the main method of the mod.
  2. We create a class to hold our items.
  3. We create a DeferredRegister for items — essentially a container so NeoForge can properly register them in the game.
  4. We create a basic item.
  5. We register the item container with NeoForge.
  6. We create a class responsible for model generation.
  7. We define the basic model.
  8. We subscribe to GatherDataEvent to hook into data generation.
  9. We register our model provider.
  10. We register all events inside ExampleMod.

The code is manageable and clear in small examples. However, once the project grows and includes more complex scenarios, this structure scales significantly and becomes harder to maintain.


Temporal API

What Is Temporal API?

This is where Temporal API comes in — a framework designed to automate many routine tasks in mod development.

Temporal API relies on reflection and annotations. Conceptually, it resembles Spring Framework, but in the modding world.

The best way to understand its value is to see it in action.


How Temporal API Solves This Problem

Let’s rewrite the same example using Temporal API:

@Mod(ExampleMod.MOD_ID)
public class ExampleMod { // 1
    public static final String MOD_ID = "example";

    public ExampleMod(IEventBus modEventBus, ModContainer modContainer) {
        TemporalEngine.run(ExampleMod.class, modEventBus, modContainer); // 2
    }
}

public final class ExampleItems { // 3
    private static final ItemFactory ITEM_FACTORY = InjectionPool.getFromInstance(ItemFactory.class); // 4

    @GenerateBasicItemModel // 6
    public static final DeferredItem<?> EXAMPLE_ITEM = ITEM_FACTORY.create("example_item"); // 5
}
Enter fullscreen mode Exit fullscreen mode

The code becomes significantly shorter while preserving the same functionality:

  1. We create the mod class.
  2. We initialize Temporal API via TemporalEngine.run(...). This acts as the entry point, allowing the framework to collect metadata and required components.
  3. We create an items class.
  4. We obtain an ItemFactory, which wraps DeferredRegister.Items (internally, more precisely, TemporalRegister.Items).
  5. We create a simple item.
  6. We generate the model using the @GenerateBasicItemModel annotation.

And this is just one example. Temporal API includes many utilities and a flexible annotation system that can be extended if needed.


Drawbacks of Temporal API

The main drawback is version support.

The latest version of Temporal API currently targets Minecraft 1.21.1. Porting the entire functionality to newer and older versions requires significant effort and contributor support.


Where to Learn More

Temporal API is an open-source project:


Conclusion

To wrap up, I’d like to ask a few questions:

  • Have you developed Minecraft mods before?
  • If yes, which mod loader and game version did you use?
  • If not, would you like to try?
  • Should I write a detailed article explaining what happens under the hood of Temporal API?

Thank you for reading, and have a great day.

Top comments (0)