Эта статья предназначена для тех, кто разрабатывал моды на Minecraft или ради собственного интереса планирует этим заняться. Поэтому темой данной статьи станет упрощение процесса разработки на NeoForge с помощью библиотеки Temporal API.

Вступление

Что такое NeoForge?

Перед тем, как начать говорить о Temporal API, стоило бы немного замолвиться о NeoForge и с чем его едят:

Вот что выдает Гугл при запросе "Что такое NeoForge"

NeoForge это современный API с открытым исходным кодом и загрузчик модификаций для Minecraft: Java Edition, созданный как форк популярного загрузчика Forge.

Проще говоря, NeoForge это один из самых используемых модлоадеров (прослойка между модами и игрой) наряду с Fabric, Quilt, Forge и другими. Этот модлоадер вышел относительно недавно и разрабатывается частью команды, которая ранее отвечала за разработку Forge. На данный момент NeoForge активно разрабатывается и обновляется, а также большинство модов создаются именно с помощью NeoForge, поэтому очень рекомендую именно этот модлоадер при разработке модов.

Какая одна из главных проблем NeoForge?

Одной из главных проблем при разработке модов с помощью NeoForge является огромное количество повторяющегося кода, который не даёт нормальной возможности сосредоточиться на творении чего-то интересного и уникального.

В качестве примера возьмём создание обычного предмета и добавление простой модельки на Minecraft 1.21.1 (не берём в учёт настройку проекта, а берём чисто сторону Java кода):

@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
    }
}

В целом код выглядит так:

  1. Создаём класс мода. Конструктор данного класса, по сути, является для нашего мода тем же, чем и метод main для любого Java приложения.

  2. Создаём класс, где у нас будут находиться все наши предметы.

  3. Создаём DeferredRegister для наших предметов. Проще говоря, мы создаём объект-контейнер для всех наших предметов, чтобы NeoForge корректно добавил их в игру.

  4. Создаём собственно обычный предмет, который ничего не умеет, но уже будет добавлен в игру.

  5. Подключаем наш контейнер предметов к NeoForge.

  6. Создаём класс, отвечающий за генерацию моделек.

  7. Описываем создание модельки (в данном случае, самой базовой).

  8. Подписываемся на GatherDataEvent, чтобы добавить код дата-генерации.

  9. Подключаем наш новосозданный класс.

  10. Подключаем все события внутри ExampleMod.

В принципе кода не так много и всё понятно, но при большом количестве контента и более сложных сценариях, данный код разрастается до гигантских масштабов и поддержка становится очень сложной.

Temporal API

Что такое Temporal API?

Здесь в игру вступает фреймворк под названием Temporal API, который автоматизирует большинство повседневных задач мододела.

Temporal API полагается на магию рефлексии и аннотаций, и чем-то похож на Spring, но в мире моддинга. Лучше всего взглянуть на эффективность данного фреймворка в действии.

Как с данной проблемой справляется Temporal API?

Предлагаю переписать данный код полностью с помощью 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
}

Код стал в разы короче и проще, при этом функциональность не изменилась:

  1. Создаём класс мода.

  2. Подключаем Temporal API с помощью TemporalEngine.run(...). По сути, это точка входа для Temporal API, которая даёт возможность фреймворку собрать всю информацию о моде и нужных компонентах.

  3. Создаём класс предметов.

  4. Создаём объект ItemFactory, который является обёрткой над DeferredRegister.Items (под капотом даже скорее над TemporalRegister.Items).

  5. Создаём простой предмет.

  6. Добавляем модельку, используя аннотацию @GenerateBasicItemModel.

И это только одна из проблем, которая решает данная библиотека, ибо еще Temporal API содержит очень много полезных утилит, а также собственную систему аннотаций, которую при необходимости достаточно легко расширять.

Какие минусы Temporal API?

Основным минусом является то, что новейшая версия Temporal API застряла на Minecraft 1.21.1, потому что не хватает рук для переноса на более новые и старые версии всего функционала (поэтому, если кто-то хочет помочь, то это очень даже бы не помешало :D).

Где можно больше почитать о Temporal API

Данный проект является open-source проектом с открытым исходным кодом и Wiki.

Заключение

Под конец статьи, я бы хотел спросить у вас несколько вопросов:

  • Приходилось ли вам делать моды на Minecraft?

  • Если да, то какой модлоадер использовали и на какой версии игры?

  • Если нет, то хотели бы попробовать?

  • Стоит ли написать статью, полностью объясняющую, что происходит под капотом Temporal API?

Всем спасибо за потраченное время на данную статью и хорошего вам дня :)