Developers
10 TOP-LEVEL ITEMSJEI Integration
Croparia IF's JEI integration is built on top of the Recipe API. The core idea is not "write a completely separate JEI layer for every recipe type," but instead:
- let recipes implement
DisplayableRecipe - keep type-level metadata inside
TypedSerializer - let
JeiCategoryread those pieces and handle registration and display
That keeps the JEI-facing layer fairly thin.
Mental model
The most important JEI-side objects are:
JeiClient- the JEI plugin entrypoint
JeiCategory<R>- the JEI category for one recipe family
TypedSerializer<R>- provider of type ID, recipe class, workstations, and runtime recipe queries
Their relationship is:
DisplayableRecipeexposes recipe-side display dataTypedSerializerdefines how one recipe family is identified and queriedJeiCategorydefines how that family appears inside JEIJeiClientregisters all categories and recipes into JEI itself
JeiCategory
Croparia IF's JeiCategory<R> is an abstract base class that implements IRecipeCategory<R>.
It already handles several common tasks for you:
- generating a
RecipeType<R>fromTypedSerializer - generating a default translated title from the recipe type ID
- deriving the category icon from
TypedSerializer.getStations()
So a concrete recipe family usually only needs to:
- extend
JeiCategory<R> - return its
TypedSerializer - provide the actual layout logic
That makes "one recipe family, one category class" a very natural pattern.
The role of TypedSerializer inside JEI
TypedSerializer is the real center of JEI integration. JeiCategory relies on it for:
- the category ID
- the recipe class type
- the workstation icons
- the runtime list of recipes for this type
Two points matter especially:
getStations()- used to register recipe catalysts and derive the default icon
find()- used to register every recipe of this type into JEI
So if your TypedSerializer is well-defined, the JEI side usually needs very little extra glue.
Registration flow
Croparia IF's JEI registration flow can be summarized in three steps:
- keep a list of
JeiCategory<?>instances inJeiClient - register categories through
registerCategories(...) - register recipes and recipe catalysts through
registerRecipes(...)andregisterRecipeCatalysts(...)
In other words, JEI does not understand your recipe type by itself. It only consumes the information already prepared by the category and the typed serializer.
That is also why the Recipe API encourages recipes and type objects to own their own display data.
When more customization is needed
In the basic case, JeiCategory already handles:
- title
- icon
- type identity
You usually only need extra custom logic for:
- layout
- interaction widgets
- special rendering elements
If your recipe UI is unusual, such as:
- multi-page inputs
- structure-like displays
- dynamic state switching
then the concrete category will need to add more JEI-side UI behavior.
Tips
- Design the recipe class and its
TypedSerializerfirst, then add JEI support. The category becomes much lighter that way. - If
getStations()is empty, make sure to override the icon logic, because the default base implementation will throw. - The default title relies on the translation key
gui.<namespace>.<path>.title, so stable naming helps. - If a JEI category starts carrying too much recipe-side business logic, it usually means that data belongs earlier in
DisplayableRecipeorTypedSerializer.
If you also want REI support, continue with REI integration. The overall design is similar, even though the platform APIs differ.