Developers
9 TOP-LEVEL ITEMSAdding Built-in Crops
If you opened this page because you want to keep adding one more built-in crop to Croparia IF, the most important conclusions can come first:
- built-in fruit crops are mainly added in
registry/Crops.java - built-in melon crops are mainly added in
registry/Melons.java - neither of these content lines ends with “add one registry record”; both automatically derive the matching blocks and items
- whether content actually appears depends not only on whether you instantiated an object, but also on
shouldLoad(), dependency checks, and configuration filters
So this page is not trying to be a generic crop-system overview. It directly answers:
- which file should be edited to add a built-in crop
- what the minimum required data is for one
CroporMelon - which blocks and items Croparia IF derives automatically after you add it
- which layer you should debug first if the new content does not show up
If what you need is the modpack-side customization route, see Custom Crops.
First separate the two content lines
Inside Croparia IF, built-in crop-related content mainly splits into two lines:
Crop- fruit crops
- typically produce seeds, fruits, and one crop block
Melon- melon crops
- typically produce seeds, fruit blocks, stems, and attached stems
If all you want to know is “which file should I edit”, use this distinction first:
- if the result is a normal fruit harvested from one crop plant
- look at
Crop
- look at
- if the result is a large fruit block produced by a stem structure
- look at
Melon
- look at
They both belong to the crop system, but they do not share the same implementation template in code.
The most important differences are:
CropusesItemMaterialMelonusesBlockMaterialCrophastypeMelondoes notCropderives “crop block + seed + fruit”Melonderives “fruit block + seed + stem + attached stem + fruit item”
From the developer’s point of view, they are better understood as two different content templates rather than one class with different textures.
How to add a built-in Crop
Step 1: go to Crops.java
The main entrypoint for built-in fruit crops is registry/Crops.java.
Croparia IF currently defines most built-in fruit crops there and registers them through field initialization into:
DgRegistries.CROPS
If your goal is simply to add one more built-in content entry, you usually do not need to change the lower-level Crop class first. Start with a new definition in Crops.java.
Step 2: pick the right helper
The most common helper entrypoints currently fall into three groups:
croparia(...)- best when the material itself is content provided by Croparia IF
vanilla(...)- best when the material directly corresponds to a vanilla item
compat(...)- best when the material comes from a compatibility mod, or when loading should depend on tags and dependency conditions
If you are adding a built-in crop for a vanilla item, copying one of the existing vanilla(...) patterns is usually enough.
Step 3: prepare the minimum fields
When constructing one Crop definition, you should at least know:
name- becomes part of the final registration name
material- the material meaning produced by this crop
color- mainly used by rendering and resource generation
tier- crop tier
type- resource presentation category such as
crop,animal, ormonster
- resource presentation category such as
dependencies- used when loading should depend on another mod and translation key selection
This is why Crop should not be thought of as “just crop metadata”. It already carries most of the information needed to land real content.
Step 4: what gets derived automatically
Once a Crop is created and registered, it does not only yield one definition object.
Its constructor prepares three derived content objects:
CropariaCropBlockCropSeedCropFruit
Then onRegister() actually registers them.
So from the developer experience point of view, adding one built-in crop usually looks like this:
- add one definition in
Crops.java - make it enter
DgRegistries.CROPS - let
Crophandle the derived crop block, seed, and fruit registration
That is one of the most convenient parts of the design.
What one Crop really represents
The core fields of Crop include:
Identifier idItemMaterial materialColor colorint tierString typeMap<String, String> translationsCropDependencies dependencies
When adding built-in crops, the two most important fields are usually material and type:
material- decides the material meaning produced by the crop
- is also reused by other systems later on
type- is closer to presentation and resource classification
- for example
crop,animal,monster, andnature
So Crop is better understood as “fruit crop definition + derived registration template”, not as a plain config object.
Why a definition may exist but not appear
If you add a definition in Crops.java but still do not see the resulting content in-game, check these layers first:
dependencies- should this content load in the current environment?
shouldLoad()- do dependency checks and config filters pass?
CropariaIf.CONFIG.isCropValid(...)- does the current configuration still allow this crop?
onRegister()- did the derived blocks and items actually reach the registration step?
In other words, “definition exists” and “content appears” are separated by one more loading decision layer.
How to add a built-in Melon
Step 1: go to Melons.java
The main entrypoint for built-in melon content is registry/Melons.java.
Just like Crops.java, each definition there first enters:
DgRegistries.MELONS
So if your goal is “add one built-in melon crop”, the first step is again to add one definition in Melons.java.
Step 2: prepare the minimum fields
The Melon line is more fixed than Crop, and the most common built-in helper is currently something like vanilla(...).
At minimum, you need:
namematerial- here it is
BlockMaterial
- here it is
colortier
Unlike Crop, it has no type, because the presentation template of melon-style crops is already more fixed.
Step 3: what gets derived automatically
One Melon definition prepares five derived content objects:
MelonStemMelonAttachMelonSeedMelonBlockMelonItem
Then onRegister() registers them all together.
So from the developer’s point of view, adding a built-in melon crop usually looks like:
- add one definition in
Melons.java - register it into
DgRegistries.MELONS - let
Melonderive the stem, attached stem, fruit block, fruit item, and seed
How Melon is best understood
The core fields of Melon are more compact:
Identifier idBlockMaterial materialColor colorint tierMap<String, String> translationsCropDependencies dependencies
The most important thing to remember here is:
Melonis not a simplified version of fruit crops- it is a “melon crop structure definition + derived registration template”
If you are adding one built-in melon crop, the work usually centers on writing the definition correctly rather than changing lots of runtime logic.
Why everything passes through DgRegistries
Whether it is Crop or Melon, built-in content is not registered by writing blocks and items straight from Crops / Melons into vanilla registries first. It enters:
DgRegistries.CROPSDgRegistries.MELONS
For developers maintaining built-in content, the sequence to remember is:
- write the content definition in
Crops.java/Melons.java - let
DgRegistriescollect those definitions - let
Crop/Melonderive and register the actual blocks and items during registration
This design exists so later systems such as resource generation, language generation, and derived registration can all work around the same definition objects.
Compatibility, translation, and load control
Both Crop and Melon carry CropDependencies.
That layer is not only about “recording which mod is required”. More importantly, it controls:
- whether the content should load in the current environment
- which translation key should be used
So if you are working on built-in compatibility content, do not think of dependency handling as something you “add at the end”.
In this design:
- dependency conditions are part of the content definition itself
- translation-key selection also travels together with that definition
That is one of the reasons helpers such as compat(...) exist:
- the same content definition
- can choose different loading behavior and translation behavior depending on the environment
Debug chain: how one definition reaches the game
Both Crop and Melon implement two very important methods:
shouldLoad()onRegister()
shouldLoad() mainly checks:
- whether dependency conditions are satisfied
- whether configuration still allows the crop to load
onRegister() is what actually pushes the derived content into registration.
If you want to debug why one new content definition did not land, the most useful order is usually:
- create the definition in
Crops.javaorMelons.java - register it into the matching
DgRegistries - call
shouldLoad()to decide whether it should load - if allowed, run
onRegister() - let the derived blocks and items enter the real registration flow
So when you are asking “why is this crop missing?”, do not only stare at the vanilla registry layer. Go back and check shouldLoad(), dependency conditions, and whether onRegister() was actually reached.
What is most worth remembering
If your goal is to maintain or extend Croparia IF’s own built-in crop content, the most important takeaways are:
- to add a built-in fruit crop, start with
Crops.java - to add a built-in melon crop, start with
Melons.java CropandMelonare not final registered content by themselves; they derive a full set of blocks and items- whether content appears depends on the definition, dependencies, config filters, and registration flow together
- this page is better treated as “built-in content maintenance reference” than as a complete public extension API
Where to go next
- If you want to see how these definitions enter the data-generation system, see Runtime Data Generation System
- If you want the modpack-level customization path, see Custom Crops
- If you want to see how core modules consume these crop definitions, Crop Transmuter is usually the best starting point