The feature toggles (enableConcentratedOres, enableImpureOres, ...) were
defined in config but never read: ConfigHelper.isFeatureEnabled() had no
caller, so the toggles were decorative. Wiring them is non-trivial because
NeoForge biome modifiers are loaded as data at bootstrap, before ModConfig
exists, so a data JSON cannot read a runtime config value directly.
Fix: a custom BiomeModifier (ConfigGatedFeaturesModifier) registered as
'custom_ore_gen:config_gated_features'. Its modify() runs at world load, when
the config is available, and only adds each feature group when its toggle is
on. The six add_*_biomes_ores.json modifiers now use this type, with each ore
mapped to its toggle:
- shardDiamondOre -> shard diamonds (surface + deep)
- concentratedOres -> concentrated coal, deepslate diamond
- impureOres -> iron (+deepslate)
- pureGoldenOre -> pure golden (+deepslate)
- customCopperOres -> copper high/lower
- customEmeraldOres -> emerald high/lower
- vanillaOreVariants -> lapis, redstone (+deepslate)
With all toggles defaulting to true, behaviour is identical to the previous
neoforge:add_features modifiers (code-equivalent), so existing worlds keep
their ores.
Also fixes a pre-existing bug: sharddiamondblockore (surface shard diamond)
was referenced by no biome modifier and never generated; it is now linked via
the shard diamond group (neoforge:any).
Dead code removed: the ash_coal feature/drop config (enableAshCoalOre,
ashCoalOreMinDrops/MaxDrops) and the 'ash_coal' drop case referenced an ore
block that was deleted long ago, plus the 'Temporarily use coal' placeholder.
Testing: the latitude GameTest still passes. A new oreGatingMatchesConfig test
verifies the shard feature presence in biome settings matches the toggle, but
skips with a note on runGameTestServer (its level is a void world with no
decoration features, so biome modifiers are not observable there); run it
against a real world to exercise the ON/OFF assertion.
Iron and Gold ores were the only ones reacting to Fortune (Fortune III could
yield up to 4 raw iron/gold per block). In vanilla 1.21, iron and gold ores
ignore Fortune entirely (the raw ore is smelted, not multiplied). Copper,
lapis and redstone legitimately keep Fortune (vanilla behavior), so those are
unchanged.
Added pureGoldenOreEnableFortune and impureIronOreEnableFortune config toggles
(default: false) for consistency with the other ores (which all have an
enableFortune toggle) and wired them into both the ConfigurableOreDropsProcedure
(XP path) and the CustomOreLootModifier (item drops path, authoritative).
Verified after a GameTest run that NeoForge merges the new keys with the
default false WITHOUT touching the user's existing custom drop values
(e.g. minDrops/maxDrops overrides are preserved). GameTest still green:
spawn=birch_forest | north=100% | south=100% | swamp=1.26% | deepDark=1.30%
| caveBiomes=6.5%.
The Create processing recipes (crushing/milling/mixing) were broken in two
ways, plus leaked parse errors when Create was absent.
1. Format migration to Create 6.x (matched against native recipes in the
Create 6.0.9 jar):
- results entries: item -> id
- processingTime -> processing_time (snake_case)
- ingredients keep item (still correct in 6.x)
2. Phantom item references: 9 recipes targeted blocks that no longer exist
(renamed/removed ores). Reaffected 8 to their real block (e.g.
highlapisore -> lapisore, goldore -> puregoldenore, highcopperore ->
copperhighore) and deleted 9 with no real equivalent or that would
duplicate an existing recipe (deepslate variants of coal/copper/emerald
that don't exist as blocks).
Result: all 16 registered ore blocks now have at least one valid Create
recipe (15 direct + sharddiamond via the forge:ores/shard_diamond tag).
3. Standalone safety: wrapped all 20 Create recipes + the Mekanism enriching
recipe in neoforge:conditions (mod_loaded) so they only parse when the
target mod is present. Without this, the RecipeManager logged ERRORs
(Unknown registry key create:crushing) on every boot when the mod ran
alone. Conditions use the sibling format, verified empirically.
Validated both configurations via runGameTestServer:
- Standalone (Create + Mekanism absent): 0 recipe parse errors, latitude OK
- With all mods (BOP + Tectonic + Create + JEI): 0 parse errors, recipes
load, latitude OK (spawn=birch_forest | north=100% | south=100% |
swamp=1.26% | deepDark=1.30% | caveBiomes=6.5%)
The mod has no hard dependency on Create (no compile dep, no Java imports,
optional in mods.toml) and now boots cleanly with zero recipe errors whether
or not Create/Mekanism are installed.
The ore biome modifiers still referenced the legacy climate tags
(cold_biomes / tempered_biomes / hot_biomes) which were out of sync with the
new latitude system (latitude_cold_surface / _temperate_surface / _hot_surface).
As a result ores did not spawn where the player would expect them, several BOP
biomes got no ores at all, and surface ores leaked into oceans.
All three climate modifiers now point at the latitude surface tags, so ore
distribution follows the climate exactly. Because the latitude tags exclude
oceans, the fix also removes iron/coal generation under oceans.
Result (verified by coverage analysis):
North (cold/frozen) -> Lapis + Diamond (27 biomes, +16 BOP)
Equator (temperate/spawn)-> Iron + Coal (31 biomes, +21 BOP)
South (hot) -> Gold + Copper + Redstone(22 biomes, +11 BOP)
0 orphan surface biomes; no ocean surface ores. GameTest still green.
Add geological depth slices to the automated GameTest: it now samples the
latitude world at three depths and renders one PNG per depth (a top-down
'view' of that Y layer):
- latitude_map_surface.png (Y=64)
- latitude_map_mid_cave.png (Y=-15)
- latitude_map_deep.png (Y=-50)
plus a report section per slice and new assertions:
- Deep Dark must stay rare in the deep zone (<8%)
- cave biomes (lush/dripstone) must stay a minority in mid-cave (<25%)
Cave biome colors are now distinct (lush=green, dripstone=orange, deep_dark=
teal) so the slices are readable.
Tuned the cave thresholds using the test as a fast feedback loop (BiomeSource-
only sampling, ~30s per run, mods-independent):
- CAVE_THRESHOLD 0.55 -> 0.38 (lush/dripstone pockets now ~6.5%)
- DEEP_DARK_THRESHOLD 0.88 -> 0.55 (Deep Dark now legendary ~1.3%; was 0%)
Validated with BOP + Tectonic:
spawn=birch_forest | north=100% | south=100% | swamp=1.26% |
deepDark=1.30% | caveBiomes=6.5%
The previous implementation forced a uniform cave-biome slab (lush/dripstone/
deep_dark) across all of Y<30, which overrode the latitude logic for a huge
volume and made the Deep Dark far too common.
New 3-zone underground model keeps the latitude surface biome as the default
at every depth (mining under a desert feels like the desert) and only carves
rare cave features on top:
- Near surface (Y >= 0): latitude biome as-is, no override.
- Mid caves (-30 <= Y < 0): lush/dripstone pockets (~8%) matching the climate
(humid/warm bands -> lush, dry/cold bands -> dripstone).
- Deep zone (Y < -30): legendary Deep Dark pockets (~1%, very low-frequency
noise so they form large rare regions suitable for Ancient Cities); the
surface latitude biome otherwise.
Deep Dark is removed from the biome band pools and driven solely by its own
noise, restoring it to a rare, legendary discovery. Cave biomes are now
resolved once and declared in possibleBiomes. BiomeBand.underground() removed
(caves are climate-driven, not band-pool-driven).
Validated by GameTest (BOP + Tectonic): spawn=birch_forest | north=100% |
south=100% | swamp=1.26%.
With Biomes O' Plenty installed, the FROZEN/HOT bands are filled with BOP
cold/hot biomes which the previous hardcoded vanilla-only assertion sets
did not include, causing a false failure (FROZEN measured 31% vs real ~100%).
Assertions now resolve the surface tags from the real registry and check
membership, so vanilla + BOP biomes are both counted. Adds a per-band
breakdown to the report for easier diagnostics.
Validated with Create + JEI + Biomes O' Plenty + Tectonic + deps:
spawn=birch_forest | north=100% | south=100% | swamp=1.26%
Run `./gradlew runGameTestServer` to validate the latitude biome system
without manual in-game testing. Boots a headless game server (full biome
registry), samples a 32000x32000 grid through LatitudeBiomeSource, renders a
PNG map and writes a distribution report, then asserts climate invariants:
- spawn on a safe biome (plains/forest)
- FROZEN band dominated by cold/frozen biomes (>60%)
- HOT band dominated by warm/hot biomes (>60%)
- swamp remains rare in the temperate band (<15%)
Outputs land in run/gametest-results/latitude/ (latitude_map.png +
latitude_report.txt). Sampling is BiomeSource-only (no chunk generation),
so it runs in ~35s regardless of installed mods.
- LatitudeGameTest: @GameTestHolder + @PrefixGameTestTemplate(false)
- structure/empty_1x1.nbt: minimal 1x1x1 air structure required by GameTest
- build.gradle: add gameTestServer run configuration
Add a latitude-based world generation system: biomes are distributed by Z
coordinate (frozen north -> temperate equator -> hot south) with extremely
large biomes on a continental scale, plus full Biomes O' Plenty support.
World types (selectable in the world creation 'World Type' button):
- Ultra Wide Biome: latitude biomes + vanilla terrain (immune to Tectonic
via a private noise_settings copy under custom_ore_gen).
- Tectonic Ultra Wide Biome: latitude biomes + minecraft:overworld terrain
(uses Tectonic when present, vanilla otherwise).
Core implementation:
- LatitudeBiomeSource: custom BiomeSource distributing biomes by latitude.
Temperature derived from Z with a boundary wobble, dual-octave selector
noise for a flat biome distribution (no biome dominates), land/ocean mask,
underground cave layer, moisture-driven rare swamp/mangrove pockets, and a
guaranteed safe spawn zone (plains/forests) around the origin.
- BiomeBand: 5 climate bands (FROZEN/COLD/TEMPERATE/WARM/HOT) with vanilla
surface pools + dedicated climate tags (latitude_*_surface) for optional
BOP biomes via required:false, plus ocean and underground pools.
- WorldGenRegistration: DeferredRegister for the 'custom_ore_gen:latitude'
BiomeSource codec.
- LatitudeSpawnHandler: pins spawn to a plains/forest biome on overworld load.
Validation:
- /latitude map [radius] [step]: samples the LatitudeBiomeSource on a large
grid, renders a top-down PNG map (run/latitude/latitude_map.png) and writes
a per-band distribution + invariant report (run/latitude/latitude_report.txt).
Constants tuned for a continental scale:
TEMPERATURE_SCALE = 16000 (equator->pole)
SURFACE_SELECTOR_SCALE = 0.00033 (biomes ~3000 blocks wide)
Swamp fix: removed from the common temperate surface tag and made rare
(~8% of temperate land via moisture noise), matching vanilla humidity biomes.
- Add CustomOreLootModifier (Global Loot Modifier) handling all ore drops,
ensuring compatibility with machines (Create drill/contraptions) and avoiding
duplication. Handles silk touch (vanilla block / shard diamond block) and
fortune via config-driven min/max drops.
- Register GLM serializer via DeferredRegister in CustomOreGenMod (user code block)
- Rewrite OreBreakEventHandler: remove direct drops mutation that caused
UnsupportedOperationException on immutable list when broken by Create drill.
Drops are now fully GLM-driven; handler only triggers XP/procedure logic.
- Migrate loot tables from loot_table/ (singular, 1.20) to loot_tables/
(plural, NeoForge 1.21 format) for all 16 ore blocks.
- Declare GLM in data/neoforge/loot_modifiers/global_loot_modifiers.json
- Add Create crushing + milling recipes for diamond -> diamond shards
- Config tweaks: tool durabilities (pickaxe/axe/shovel 450, paxel 800),
Pure Golden Ore maxHeight 256 -> 320
- Refresh shard diamond armor/item textures
- Simplify unit tests for new drop system
- Removed onDestroyedByPlayer from blocks (now handled by OreBreakEventHandler)
- Updated tests to use NeoForge classes (ModConfigSpec instead of ForgeConfigSpec)
- Fixed EnchantabilityFix annotation and commented out placeholder code
- Updated pack.mcmeta format for 1.21.1
- Registered ModConfigs.SPEC in CustomOreGenMod to avoid IllegalStateException
- Updated all recipe JSONs to use 'id' instead of 'item' in result fields
- Renamed mekanism recipes folder to match 1.21.1 conventions
- Renamed data folders to 1.21.1 standards (singular names)
- Implemented OreBreakEventHandler to call ConfigurableOreDropsProcedure
- Updated procedure and config to handle all custom and variant ores
- Modified loot tables to only handle Silk Touch (manual drops via procedure)
- Fixed missing drops issue caused by folder name mismatch in 1.21.1
- Fixed paxel recipe: now requires 1 pickaxe + 2 sticks (instead of 3 pickaxes)
- Fixed silk touch on Concentrated Diamond Ore: now drops vanilla diamond_ore
- Fixed Copper High Ore sound: changed from GRAVEL to STONE
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
- Documentation de la dépendance obligatoire KubeJS
- Création automatique du script de suppression des minerais vanilla
- Nouvel onglet créatif personnalisé
- Changelog complet de la version 2.1.5
- Architecture mise à jour avec KubeJSIntegration et ShardDiamondArmorMaterial
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
- Created ShardDiamondArmorMaterial class with proper getName() returning "custom_ore_gen:shard_diamond"
- Updated all armor items to use the new material instance
- Added new armor textures from new_armor folder
- Fixed armor texture loading by using correct modid:name format in getName()
- Added CLAUDE.md for project documentation
- Added armor crafting recipes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
- Correction bug texture armure Diamond Shard (renommage textures layer_1/layer_2)
- Correction craft paxel (remplacement espace par lettre T pour stick)
- Correction compilation SharddiamondpaxelItem (getTier().getSpeed())
- Mise à jour version 2.0.6 -> 2.0.8
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Nouvelles fonctionnalités :
- Armure complète en Diamond Shard (casque, plastron, jambières, bottes)
- Paxel en Diamond Shard (outil combiné pioche+pelle+hache, 1000 durabilité)
- Désactivation du Shard Diamond Ore de surface (deepslate uniquement)
- Mise à jour README.md avec toutes les nouvelles fonctionnalités
Fichiers ajoutés :
- Classes d'armure : Sharddiamondhelmet/chestplate/leggings/bootsItem.java
- Classe paxel : SharddiamondpaxelItem.java
- Recettes de craft pour armure et paxel
- Modèles et textures pour tous les nouveaux items
- Textures d'armure (layer 1 et 2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>