Ore Generation Configuration
Ore Generation Configuration is a server-side-behavior NeoForge mod for Minecraft 1.21.1 that controls ore block generation in newly generated chunks.
It can deny or reduce vanilla and modded ores. It does not add blocks, items, entities, recipes, or regenerating ore veins.
The mod contains no client gameplay, assets, networking, blocks, items, or entities. It can run on a dedicated server, and it can also run in singleplayer because singleplayer uses an integrated server. Multiplayer clients should not need to install it to join a server that has it, because the server sends the resulting normal chunk data.
Technical Approach
The mod uses NeoForge ChunkEvent.Load and only queues chunks where isNewChunk() is true. On later server ticks it scans those newly generated chunks once, finds configured ore block ids, and replaces matching blocks according to ores.json.
This was chosen over biome modifiers, placed-feature mutation, or mixins because it gives reliable block-level frontier gating across vanilla and modded ores without fragile worldgen hooks.
Limitations:
- Existing chunks are not modified.
- Loaded chunks are not scanned continuously.
- Player-placed blocks are not targeted by normal operation.
- Ores not listed in
ores.json are left alone.
- If Regenerating Ore Veins is installed, OGC skips positions already tracked by that mod so managed regenerating veins are not reduced or removed by OGC.
Config Files
The mod creates:
config/ore_generation_configuration/global.json
config/ore_generation_configuration/areas.json
config/ore_generation_configuration/ores.json
If a config file fails to parse, the mod logs the problem to latest.log and tells players on login or /ogc reload that the configuration has warnings or errors.
global.json
Example:
{
"enabled": true,
"debug_logging": false,
"dry_run": false,
"fail_on_unknown_blocks": false,
"fail_on_unknown_biomes": false,
"default_keep_chance": 1.0,
"print_startup_summary": true
}
Fields:
enabled: disables all processing when false.
debug_logging: logs every processed new chunk.
dry_run: counts matching blocks but does not replace them.
fail_on_unknown_blocks: reports unknown target blocks as errors instead of warnings.
fail_on_unknown_biomes: reserved for stricter future biome validation.
default_keep_chance: fallback chance for a matching ore block to remain.
print_startup_summary: logs loaded area and rule counts.
areas.json
Areas are named spatial filters using In Control!-style area semantics.
Supported area types:
box: rectangular prism. dimx, dimy, and dimz are half-extents from the center.
sphere: ellipsoid. dimx, dimy, and dimz are the X/Y/Z radii from the center.
cylinder: vertical elliptical cylinder. dimx and dimz are horizontal radii, and dimy is vertical half-height.
Example:
[
{
"dimension": "minecraft:overworld",
"name": "frontier_0",
"type": "box",
"x": 0,
"y": 128,
"z": 0,
"dimx": 128,
"dimy": 256,
"dimz": 128
}
]
Area fields:
name: unique area id.
dimension: optional dimension id. If omitted, the area can match any dimension.
type: box, sphere, or cylinder.
x, y, z: center of the area.
dimx, dimy, dimz: In Control-style half-size/radius values, not full dimensions.
Examples:
- A
box at 0,64,0 with dimx: 10, dimy: 20, dimz: 30 covers x=-10..10, y=44..84, and z=-30..30.
- A
sphere with dimx: 16, dimy: 8, dimz: 16 is an ellipsoid centered on x,y,z.
- A
cylinder with dimx: 32, dimy: 128, dimz: 32 is a vertical cylinder with radius 32 and height 257 blocks.
The default areas.json creates frontier boxes centered at 0, 128, 0 with these X/Z half-widths:
| Area |
Half-width |
frontier_0 |
128 |
frontier_1 |
224 |
frontier_2 |
448 |
frontier_3 |
768 |
frontier_4 |
1152 |
frontier_5 |
1600 |
frontier_6 |
2304 |
frontier_7 |
3072 |
frontier_8 |
4096 |
ores.json
Each rule targets ore blocks and decides whether matching generated blocks stay or are replaced.
Example:
{
"id": "deny_iron_before_frontier_2",
"blocks": [
"minecraft:iron_ore",
"minecraft:deepslate_iron_ore"
],
"dimension_whitelist": [
"minecraft:overworld"
],
"area_whitelist": [
"frontier_1"
],
"keep_chance": 0.0,
"replacement": "auto",
"priority": 20
}
Rule fields:
id: unique rule id.
enabled: optional, defaults to true.
blocks: block ids to target. Works with vanilla and modded ore blocks.
dimension_whitelist: optional dimensions where the rule can apply.
dimension_blacklist: dimensions where the rule cannot apply.
biome_whitelist: exact biome ids or tags such as #c:is_jungle.
biome_blacklist: exact biome ids or tags where the rule cannot apply.
area_whitelist: areas where the rule can apply.
area_blacklist: areas where the rule cannot apply.
min_y and max_y: optional vertical range. If omitted, all Y levels are considered. When an area is used, that area's y and dimy still constrain the rule.
keep_chance: 0.0..1.0 chance for a matching ore block to remain.
generation_multiplier: accepted as an alias for keep_chance.
replacement: auto, nothing, a block id, or a list of block ids.
weight: optional list of replacement weights when replacement is a list.
priority: lower values run first. If priorities tie, the matching rule with the lower keep_chance takes precedence. If both priority and keep_chance tie, JSON file order wins.
Filter behavior:
- If neither whitelist nor blacklist is provided for a filter type, that filter does not restrict the rule.
- If only a whitelist is provided, the rule applies only inside that whitelist.
- If only a blacklist is provided, the rule applies everywhere except that blacklist.
- If both are provided and overlap, the blacklist takes precedence.
- Empty lists such as
"biome_whitelist": [] are treated the same as omitting the field.
- All filters combine as constraints. For example,
area_whitelist: ["frontier_0"] plus min_y: -64 and max_y: 64 applies only inside frontier_0 and only between Y -64 and 64.
Dimension and biome entries:
- Exact ids are supported, such as
"minecraft:overworld" or "minecraft:plains".
- Biome tags are supported with
#, such as "#c:is_jungle".
- Namespace wildcards are supported with
modid:*, such as "biomeswevegone:*" for all biomes from that mod or "mydimensions:*" for all dimensions from that mod.
Conflict behavior:
- Rules are sorted by
priority, then by lower keep_chance, then by the order they appear in ores.json.
- For a given generated ore block, the first matching rule is applied.
- Later matching rules for that same block position are ignored.
Example: a global 50% ore reduction can use priority 100 and keep_chance: 0.5. A frontier-specific rule for the same ore blocks can also use priority 100 with keep_chance: 0.0 and area_whitelist: ["frontier_0"]. Inside frontier_0, the 0% rule wins for its listed blocks. Outside frontier_0, it does not match, so the global 50% rule applies.
Replacement examples:
"replacement": "auto"
auto tries nearby base stone first, then falls back to stone, deepslate, netherrack, or end stone based on context.
"replacement": "nothing"
nothing replaces the ore with air.
"replacement": "minecraft:stone"
A single block id replaces every denied ore with that block.
{
"replacement": [
"minecraft:coal_ore",
"minecraft:deepslate_coal_ore"
],
"weight": [
1,
1
]
}
A replacement list chooses one replacement block with weighted random selection. If weight is omitted, every replacement has weight 1.
Commands
Reload configuration without restarting:
/ogc reload
/ore_generation_configuration reload
Reloading affects newly generated chunks after the reload. It does not revisit chunks already generated before the reload.
Testing
Suggested test flow:
- Start a new world or travel into terrain that has never generated.
- Set
dry_run to true and debug_logging to true.
- Run
/ogc reload.
- Generate new chunks and check
latest.log for dry-run match counts.
- Set
dry_run to false, reload, and generate fresh chunks.
- Inspect ores in denied frontiers.
License
MIT