Commit Graph
34 Commits
Author SHA1 Message Date
feldenr 600393399f feat(worldgen): custom ultra-large terrain + fix spawn-dark-forest bias
Two related worldgen improvements validated in-game with Distant
Horizons + Lithosphere. Build + 6 GameTests green.

== Custom ultra-large terrain (preset ultra_wide_biome) ==
The mod controlled biome distribution but not relief, so the "long
prairies / immense mountain chains" effect was weak (relief was the
vanilla one that changes every ~1-2k blocks). Added a custom noise
settings custom_ore_gen:ultra_large_biome, built on top of Lithosphere's
large_biomes (which the mod already depends on for the mountain/cave
density functions).

Approach (iteratively tuned - v1/v2 with amplitude boost created HOLES in
the terrain; this v3-safe is the one that works):
  - 34 density functions copied verbatim from lithosphere, re-pointed
    to the custom_ore_gen: namespace (so our preset can reference them).
  - Cave density functions are NOT copied (left pointing at lithosphere:)
    so cave generation stays the natural Lithosphere one.
  - NOISE parameter references are NEVER namespacespaced - the noise
    parameter definitions live in the lithosphere jar and we just
    reference them (this was the v2 crash: an "Unbound values in
    registry noise: [custom_ore_gen:rivers, ...]" crash).
  - 9 MACRO density functions are stretched 2x in xz_scale only:
    continents, mountains_shape, basic_topography, orogeny,
    topography_final, topography_mountains, topography_swamps,
    topography_rivers, topography_cliffs. These drive the large-scale
    relief, so the effect is "longer plains, longer mountain chains".
  - 25 DETAIL density functions are left UNTOUCHED (xz_scale = original):
    roughness, rivers, mesas, erosion_detail, lake_placement, etc. Details
    must NOT be stretched or the terrain becomes incoherent.
  - NO amplitude boost on sloped_cheese: a v1 attempt with a x1.3
    multiplier pushed final_density out of [-1,1], which broke the
    `squeeze` envelope and carved literal HOLES in the terrain.

The preset data/custom_ore_gen/worldgen/world_preset/ultra_wide_biome.json
now references custom_ore_gen:ultra_large_biome (instead of the vanilla
minecraft:overworld it pointed at after the tectonic preset cleanup).

== Fix: spawn always landed in dark_forest ==
Root cause found by offline analysis:
  - LatitudeBiomeSource.spawnSafeBiomes (plains/forest/birch/...) only
    applied inside a 191x191 square (SPAWN_SAFE_RADIUS=96).
  - LatitudeSpawnHandler.findSpawnBiome scans rings up to MAX_RADIUS=512,
    so once it wandered past 96 blocks it fell out of the safe square and
    into the latitude_temperate_surface pool - which contains dark_forest.
  - Worse: findSpawnBiome probed biomes at y=0 (underground), but the
    latitude biome legitimately differs between y=0 and y=64 (the 3-zone
    underground model extends latitude DOWNWARDS), so a "safe" biome at
    y=0 could be dark_forest at the actual surface.

Fix:
  - SPAWN_SAFE_RADIUS 96 -> 540 (covers the handler's MAX_RADIUS=512
    search so the safe-square guarantee applies to everything found).
  - SPAWN_SELECTOR_SCALE 0.02 -> 0.004 so the safe square is populated
    by large blocks of the same safe biome (instead of a per-block
    patchwork).
  - LatitudeSpawnHandler now probes biomes at SURFACE_Y=64 instead of
    y=0, so what it validates matches what the player actually sees.

LatitudeMathTest updated for the new radius (191->1079 inclusive square).

Verification: ./gradlew test build -> BUILD SUCCESSFUL, 71/71 unit tests
            ./gradlew runGameTestServer -> 6/6 GameTests passed in 1.0s,
              spawn=birch_forest (safe, not dark_forest),
              north=100% cold, south=100% hot, deepDark=1.3%
2026-06-21 16:13:47 +02:00
feldenr d0df118270 fix: remove redundant tectonic preset + dead custom noise settings
The mod shipped two world presets that produced the *exact same world*:
  ultra_wide_biome.json     -> settings:"custom_ore_gen:overworld"
  tectonic_ultra_wide_biome.json -> settings:"minecraft:overworld"

The only difference was which overworld noise settings they referenced, so I
compared the mod's custom_ore_gen:overworld against the vanilla
minecraft:overworld byte-for-byte. Verdict: 100% identical (same 109394 bytes,
11/11 fields identical including the 30k-char surface_rule). The custom noise
settings was dead weight - a pure clone of vanilla that changed nothing about
the terrain.

Removed:
  - data/custom_ore_gen/worldgen/world_preset/tectonic_ultra_wide_biome.json
  - data/custom_ore_gen/worldgen/noise_settings/overworld.json (109 KB dead clone)
  - the tectonic entry from data/minecraft/tags/worldgen/world_preset/normal.json
    (so it no longer appears in the world-creation menu)
  - the two tectonic_* lang keys in en_us.json / fr_fr.json

Kept ultra_wide_biome as the single latitude world preset, now pointing at
minecraft:overworld directly (no indirection through a cloned settings file).
This also drops a misleading "requires Tectonic" claim - the preset never had
anything to do with the Tectonic mod.

Verification: ./gradlew test build -> BUILD SUCCESSFUL, 71/71 unit tests
            ./gradlew runGameTestServer -> 6/6 GameTests passed in 1.0s
              (latitude gen still loads via the cleaned-up preset)
2026-06-21 11:31:58 +02:00
feldenr 0fb650bdb0 fix: remove dead config + enchant class, extract & test drop math
Three correctness passes that remove lie-to-the-user code and add real
test coverage on the drop logic. Nothing broke; build + 6 GameTests green.

== Remove dead OreGenConfig (lie to the user) ==
OreGenConfig (veinSize/veinsPerChunk/min/max) was NEVER read anywhere
(grep ORE_GEN. -> NONE), and its defaults did not even match the JSONs:
  - copperhighore: JSON count=20 vs config default 2 (10x)
  - concentratedcoalore: JSON count=10 vs default 2 (5x)
  - deepslateironore: JSON count=20 vs impureIronOreCount default 2 (10x)
  - sharddiamondblockore: JSON size=4 vs shardDiamondOreSize default 8 (2x)
So a user reading the generated .toml was actively misled ("2 iron veins
per chunk" when 20 generate). Branching it to runtime config is
architecturally impossible in NeoForge (datapacks load before the runtime
config - the same problem ConfigGatedFeaturesModifier solves). Removed
the class + instance + matching structural tests. Vein params now live
only in the data-driven JSONs, like vanilla.

== Remove dead EnchantabilityFix (non-compiling API) ==
EnchantabilityFix was fully commented out because it referenced
DataComponents.ENCHANTABLE and net.minecraft.world.item.enchantment.Enchantable,
which DO NOT EXIST in 1.21.1 (confirmed via javap on neoforge-21.1.219.jar:
only ENCHANTMENTS / ENCHANTMENT_GLINT_OVERRIDE / STORED_ENCHANTMENTS exist).
Uncommenting it would fail to compile. Enchantability already works
natively via the enchantable tags
(data/minecraft/tags/item/enchantable/{mining,weapon,armor,durability}.json
- all Shard Diamond tools + armor listed) combined with the Tier
getEnchantmentValue()==9. Deleted the dead class.

== Extract & test drop math ==
ConfigurableOreDropsProcedure is hand-written (git log shows fix(drops)/
replace-event-with-GlobalLootModifier commits, no MCreator regeneration).
Extracted the pure fortune/drop/XP math into OreDropMath -> procedure now
delegates: dropCount = OreDropMath.dropCount(...), XP = experienceFor(...).
Added OreDropMathTest (16 tests) covering:
  - isMultiDropOre classification
  - baseDropCount range + uniform coverage + degenerate (min==max, no draw)
  - fortune: disabled/level-0 are no-ops (no RNG consumed)
  - discrete ores: bonus bounded in [0, fortuneLevel], vanilla III distribution
  - multiplier ores: results are exact multiples of base, vanilla III distribution
  - dropCount random-draw order pinned (base then fortune)
  - XP: zero-XP types (iron/gold/copper), vanilla ranges, bounds hit
  - determinism: same seed -> identical sequences
The procedure is now correct-by-construction for the math; the only
untested part is the MC orchestration (player/tool/registry lookup, spawn).

== Docs ==
CLAUDE.md: mark feature toggles + enchantability as already-working,
correct the "hardcoded tools" / "EnchantabilityFix commented out" claims,
document the native enchantability path (tags + Tier.getEnchantmentValue).

Verification: ./gradlew test build -> BUILD SUCCESSFUL, 71/71 unit tests
            ./gradlew runGameTestServer -> 6/6 GameTests passed in 1.0s
2026-06-21 01:26:53 +02:00
feldenr dfff76b0f9 test+fix: deep generation tests + bug cleanup (licence, docs, deps)
Two cohesive passes that harden the latitude worldgen and clean up
long-standing inconsistencies.

== Bug fixes & doc alignment ==
- licence: set MIT in gradle.properties and neoforge.mods.toml
  (was "Not specified" - blocks distribution)
- OreAuditHandler: fix javadoc that referenced a non-existent system
  property; the trigger is the .oreaudit marker file. Add an explicit
  warning about the System.exit(0) and point to LatitudeGameTest as the
  non-destructive alternative
- KubeJS: remove the dead kubejs_version, the commented dependency and
  all README claims about an "automatic KubeJS script"/KubeJSIntegration
  class that no longer exists. Vanilla ore removal is now native via the
  neoforge:remove_features biome modifier
- README: refresh the technical header (1.21.1 / NeoForge 21.1.219 /
  Java 21 / v3.2, was 1.20.1/Forge/Java17/v2.1.5) and the shard-diamond
  surface note (both variants are generated, gated by shardDiamondOre)
- CLAUDE.md / CONFIG_INTEGRATION_GUIDE.md: mark the feature toggles and
  tool stats as wired (they read ModConfigs at runtime); correct the
  "hardcoded tools" claim

== Generation tests (56 unit + 6 GameTest, all green) ==
- Extract the pure geometry of LatitudeBiomeSource into LatitudeMath
  (temperature, 3-zone underground model, spawn safe zone, dual-octave
  selector index). LatitudeBiomeSource now delegates to it, so one
  source of truth drives both runtime and tests - no behaviour drift
- LatitudeMathTest (21): temperature clamp/monotonicity, zone boundaries
  without gaps, Deep Dark / cave threshold predicates, spawn-safe square
  symmetry, selector index bounds + near-uniform distribution
- BiomeBandTest (18): fromTemperature boundary cases, surface/ocean
  pool non-empty, cave biomes never in a surface pool
- ModConfigsTest (+2 guards): every ConfigHelper toggle string maps to
  a real FeatureToggleConfig field, so a typo cannot silently produce a
  dead toggle (default: return true)
- LatitudeGameTest (+4 server tests): determinism (1485 pts, 0 mismatch),
  no cave biome at surface (160k samples, 0 leak), surface continuity
  (7% transitions - large biomes), climate gradient (north=cold 100%,
  south=hot 100%, equator cold 0%)

== Build ==
- build.gradle: addModdingDependenciesTo(sourceSets.test) so pure unit
  tests can reference Minecraft types without a full game server
- neoforge.mods.toml: optional BOP/create/mekanism dependencies removed;
  declared with mandatory=false + versionRange="[0,)" they broke mod
  loading when the mods were absent ("requires X 0 or above"). Optional
  integration is already handled via data tags (required:false) and
  data-only recipes that no-op if the mod is missing
- gradlew: restore executable bit

Verification: ./gradlew test build -> BUILD SUCCESSFUL, 56/56 unit tests
            ./gradlew runGameTestServer -> 6/6 GameTests passed in 840ms
2026-06-20 22:33:06 +02:00
feldenr 0c831bdff8 fix(ores): prove ore generation works for BOP biomes + blacklist highland
Investigation of 'no ores in BOP biomes' (highland, shrubland) reported during
in-game testing. Root cause: the early version of ConfigGatedFeaturesModifier
used a static firstCallLogged flag and threw when the COMMON config was not yet
loaded at biome-info build time, so its features were silently dropped. That
was already fixed (per-instance flag + try/catch defaulting to enabled); this
commit proves the fix end-to-end and removes the leftover debug logging.

Two automated proofs added (no manual in-game testing needed):

1. oreFeaturesAcrossBiomes GameTest: queries each biome holder's
   modifiableBiomeInfo().get() (the generation settings AFTER NeoForge applies
   every biome modifier). Result: every temperate biome - vanilla AND Biomes
   O' Plenty (shrubland, field, moor, grassland, woodland, mediterranean_forest)
   - contains the custom iron/coal/shard features. All 2 GameTests pass.

2. OreAuditHandler: a file-gated diagnostic (active only when run/.oreaudit
   exists) that runs on a dedicated server, generates real chunks under the
   latitude world type, scans actual ore blocks per surface biome, writes
   ore_audit_report.txt, then stops. Run with level-type=
   custom_ore_gen:ultra_wide_biome + the .oreaudit flag. Result on a 12x12
   chunk scan: biomes with ores=5, biomes with zero ores=0. BOP biomes
   (biomesoplenty:moor, biomesoplenty:grassland) contain iron, coal and shard
   diamond, identical to vanilla biomes. Totals: shard=89 iron=2667 coal=4803.

Design change: biomesoplenty:highland removed from latitude_temperate_surface,
mountain_biomes and tempered_biomes tags. The user finds the biome ugly; it no
longer generates. (Its ore generation was already correct - the removal is a
pure aesthetic preference, not an ore fix.)
2026-06-18 22:14:26 +02:00
feldenr 147c9d6b4a fix(biomes): remove cross-climate tag leaks (copper/gold in temperate spawn)
minecraft:birch_forest was listed in BOTH latitude_hot_surface AND
latitude_temperate_surface. Since ore generation is gated on the climate
tags, the hot-band ores (copper, pure gold, redstone) were spawning in
birch_forest - the default temperate spawn biome - so players found copper
in what looks like a temperate forest. birch_forest is a vanilla temperate
biome (temperature 0.6) and is the configured safe spawn; it never belonged
in the hot tag. Removed from hot, kept in temperate.

Also fixed a second leak: minecraft:windswept_forest was in BOTH temperate
AND cold, so it received both temperate (iron/coal) and cold (lapis/diamond)
ores. Kept in temperate only (windswept forest is not a genuinely cold biome
like snowy/taiga/grove).

Validated: each surface biome now belongs to exactly one climate tag (no
overlap). Latitude GameTest still green: spawn=birch_forest | north=100% |
south=100% | swamp=1.26% | deepDark=1.30% | caveBiomes=6.5%.
2026-06-17 21:34:07 +02:00
feldenr 48a0d797f0 feat(config): make ore feature toggles actually gate generation + cleanup
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.
2026-06-17 21:21:53 +02:00
feldenr 9182bda998 fix(drops): make iron/gold ores ignore Fortune like vanilla
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%.
2026-06-17 13:28:49 +02:00
feldenr 3ea6906369 fix(create): repair processing recipes + make them standalone-safe
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.
2026-06-16 22:34:53 +02:00
feldenr dac57d3c63 fix: synchronize ore generation with latitude climate tags
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.
2026-06-16 21:41:25 +02:00
feldenr fa8c40652b test+feat: depth-slice map validation + tune cave thresholds to target
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%
2026-06-16 21:26:32 +02:00
feldenr 060b77b506 feat: rethink cave generation - latitude extends underground, Deep Dark legendary
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%.
2026-06-16 21:12:17 +02:00
feldenr 45213d3580 fix(test): use tag membership for climate band assertions
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%
2026-06-15 23:10:24 +02:00
feldenr 169a447f7b test: add automated latitude validation via GameTest server
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
2026-06-15 21:07:43 +02:00
feldenr 7729eeb65c feat: latitude biome system with two world types + map validation command
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.
2026-06-14 22:59:09 +02:00
feldenr 74480d9d2c feat: replace event-based drops with Global Loot Modifier (fix Create drill crash)
- 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
2026-06-14 11:08:59 +02:00
feldenrandClaude 3ef6f03244 fix: make ore generation biome-specific and add command permissions
- Replace overworld-wide ore spawning with biome-specific generation
- Delete add_custom_ores.json that caused ores to spawn everywhere
- Create 6 biome-specific modifiers:
  * add_cold_biomes_ores.json - Lapis, concentrated diamond
  * add_hot_biomes_ores.json - Pure gold, copper, redstone
  * add_mountain_biomes_ores.json - High emerald
  * add_rare_biomes_ores.json - Lower emerald
  * add_tempered_biomes_ores.json - Iron, concentrated coal
  * add_shard_diamond_ores.json - Shard diamond (all biomes)
- Add permission level 2 requirement to /ores and /ore commands

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
2026-02-03 14:06:50 +01:00
feldenr 93bb4afb97 refactor: cleanup block classes and migrate tests to NeoForge
- 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
2026-02-02 23:21:11 +01:00
feldenr 0fa495474b fix: register config and update recipe formats 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
2026-02-02 23:20:17 +01:00
feldenr bca6034dd7 fix: restore ore drops and make them configurable via procedure
- 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
2026-02-02 23:11:42 +01:00
feldenr 4b9a4b0a05 Fix custom ore drops and tool enchantability for 1.21 2026-02-02 22:24:52 +01:00
feldenr 1030689b64 v2.1.12: Fix Ore Gen, Optional BOP Tags, Add Create Millstone Recipe 2026-02-01 00:43:06 +01:00
feldenr 734f89a720 feat: Add FR translation and Mekanism/Create compatibility + Bump version to 2.1.8 2026-01-23 14:27:15 +01:00
feldenr d64792d3d3 feat: Version 2.1.7 - Mekanism Compatibility & Ore Rebalance
- Added Forge tags (forge:ores/*) for all ores

- Added Shik Mekanism Enrichment recipe for Shard Diamond

- Rebalanced Lapis (0-32, 2x) and Diamond (Deepslate 6x) to match Vanilla

- Reduced Shard Diamond vein sizes for rarity

- Updated Biome Scanner & /ores to display Y-levels

- Fixed Shard Diamond Boots crafting recipe
2026-01-22 22:20:48 +01:00
feldenrandClaude 8699a36294 Rename Concentrated Diamond Ore to Deepslate Diamond Ore
- Renamed ConcentrateddiamondoreBlock to DeepslatediamondoreBlock
- Updated registry references (CONCENTRATEDDIAMONDORE → DEEPSLATEDIAMONDORE)
- Renamed all JSON resource files
- Updated display name: "Concentrated diamond ore" → "Deepslate diamond ore"
- Updated minecraft tags and biome modifiers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
2026-01-14 13:31:36 +01:00
feldenrandClaude 0d3805f654 Version 2.1.6 - Bug fixes and recipe improvements
- Fixed paxel recipe: now requires 1 pickaxe + 1 shovel + 1 axe + 2 sticks
- Fixed silk touch on Concentrated Diamond Ore: now drops vanilla diamond_ore
- Fixed Copper High Ore sound: changed from GRAVEL to STONE
- Added Sculk Catalyst recipe: 4 Diamond Shards + 4 Soul Sand + 1 Soul Soil
- Fixed Ore Biome Finder recipe: moved from recipe/ to recipes/ folder

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
2026-01-07 17:44:37 +01:00
feldenrandClaude 613d679525 Add Sculk Catalyst recipe with Diamond Shards
- Added alternative recipe to craft Sculk Catalyst
- Recipe: 4 Diamond Shards + 4 Soul Sand + 1 Soul Soil
- Provides a way to craft Sculk Catalyst without Sculk Sensor

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
2026-01-07 17:28:36 +01:00
feldenrandClaude 140b1f9111 Version 2.1.6 - Bug fixes
- 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]>
2026-01-07 17:09:36 +01:00
feldenrandClaude 93cfa0dfe3 Mise à jour README.md version 2.1.5
- 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]>
2026-01-07 14:18:04 +01:00
feldenrandClaude 11d596b788 Version 2.1.5 - Major update with armor, creative tab, KubeJS integration
Features:
- Added Diamond Shard armor set (helmet, chestplate, leggings, boots)
- Added Diamond Shard tools (pickaxe, shovel, axe, paxel)
- Created custom creative tab "Custom Ore Gen" with all mod items
- Fixed armor texture loading with proper ArmorMaterial implementation
- Updated diamond shard item texture to 32x32
- Fixed diamond shard ore textures (swapped surface/deepslate)
- Disabled surface diamond shard ore generation (only deepslate remains)
- Added KubeJS as mandatory dependency
- Auto-create KubeJS startup script to remove vanilla ores

Technical changes:
- Created ShardDiamondArmorMaterial class with proper getName() format
- Created KubeJSIntegration class for automatic script creation
- Updated mods.toml with KubeJS dependency and version 2.1.5
- Removed ModArmorMaterials enum (replaced by class-based approach)
- Updated CreativeTab to include all mod items in custom tab

Textures:
- New armor textures from new_armor folder
- New diamond shard item texture
- Fixed armor layer textures for proper rendering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
2026-01-07 13:52:01 +01:00
feldenr 3f199c1bdf Creation d'un menu dans le creatif, Rework image de l'ore du Diamond shard et de l'items 2026-01-07 12:51:24 +01:00
feldenrandClaude 1876805803 Fix armor textures and implement new armor material system
- 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]>
2026-01-07 11:24:12 +01:00
feldenrandClaude 919980cb34 Version 2.0.8 - Correction armure et craft paxel
- 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]>
2026-01-05 21:44:03 +01:00
feldenr e388fb6ad1 Changement global + ajout item et commande 2026-01-04 22:08:42 +01:00