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
258 lines
14 KiB
Markdown
258 lines
14 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
Custom Ore Gem is a Minecraft **NeoForge** 1.21.1 mod (mod ID: `custom_ore_gen`) that modifies ore distribution and adds Diamond Shard-tier tools and armor. This is an **MCreator project** - code in `src/main/java` is partially regenerated on each build.
|
|
|
|
**Note**: This mod replaces vanilla ore distribution with custom biome-based ore generation. For full functionality, it's recommended to use with KubeJS to remove vanilla ores (manual setup required).
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
# Build the mod (generates .jar in build/libs/)
|
|
./gradlew build
|
|
|
|
# Run client for testing
|
|
./gradlew runClient
|
|
|
|
# Run server for testing
|
|
./gradlew runServer
|
|
|
|
# Clean build artifacts
|
|
./gradlew clean
|
|
|
|
# Generate resources (data generation for assets/resources)
|
|
./gradlew runData
|
|
```
|
|
|
|
The built JAR is named `custom_ore_gen-{version}.jar` and appears in `build/libs/`.
|
|
|
|
## Architecture
|
|
|
|
### MCreator Workflow
|
|
|
|
This project uses MCreator. Files marked with `MCreator note: This file will be REGENERATED on each build.` at the top will be completely overwritten on each build. These include:
|
|
- `src/main/java/net/mcreator/customoregen/init/CustomOreGenModBlocks.java`
|
|
- `src/main/java/net/mcreator/customoregen/init/CustomOreGenModItems.java`
|
|
- `src/main/java/net/mcreator/customoregen/init/CustomOreGenModTabs.java`
|
|
|
|
**Protected User Code Blocks**: Only `CustomOreGenModItems.java` contains protected user code blocks:
|
|
|
|
```java
|
|
// Start of user code block custom items
|
|
// End of user code block custom items
|
|
```
|
|
|
|
**Always preserve code between these markers** when editing. All custom items (Ore Biome Finder, Shard Diamond armor, Paxel) are registered in this section.
|
|
|
|
### Package Structure
|
|
|
|
```
|
|
net.mcreator.customoregen/
|
|
├── CustomOreGenMod.java # Main mod class, registers event bus
|
|
├── OresCommand.java # /ores command implementation
|
|
├── ShardDiamondArmorMaterial.java # Armor material class for Shard Diamond armor
|
|
├── block/ # Ore block classes (17 blocks)
|
|
├── item/ # Items (Diamond Shard, tools, armor, Paxel, OreBiomeFinder)
|
|
├── config/ # NeoForge configuration system (ModConfigs.java)
|
|
├── event/ # Event handlers (OreBreakEventHandler)
|
|
├── procedures/ # Game logic (ConfigurableOreDropsProcedure, OreexperienceProcedure)
|
|
└── init/
|
|
├── CustomOreGenModBlocks.java # Block registry (deferred register)
|
|
├── CustomOreGenModItems.java # Item registry (REGENERATED)
|
|
└── CustomOreGenModTabs.java # Creative tabs registry
|
|
```
|
|
|
|
### Ore Generation System
|
|
|
|
The mod uses **NeoForge** biome modifiers to distribute ores based on biome temperature tags. The architecture:
|
|
|
|
1. **Biome Tags** (`src/main/resources/data/custom_ore_gen/tags/worldgen/biome/`):
|
|
- `cold_biomes.json` - Cold biomes (lapis, concentrated diamond)
|
|
- `hot_biomes.json` - Hot biomes (pure gold, copper, redstone)
|
|
- `mountain_biomes.json` - Mountain biomes (high emerald)
|
|
- `rare_biomes.json` - Rare biomes (lower emerald)
|
|
- `tempered_biomes.json` - Temperate biomes (iron, concentrated coal)
|
|
- BOP biomes are included with `"required": false` for optional compatibility
|
|
|
|
2. **Biome Modifiers** (`src/main/resources/data/custom_ore_gen/neoforge/biome_modifier/`):
|
|
- Each ore has a JSON file linking it to biome tags
|
|
- Special case: `deepslatesharddiamondore_biome_modifier.json` uses `"type": "forge:any"` for all biomes
|
|
- **JSON Structure**:
|
|
```json
|
|
{
|
|
"type": "neoforge:add_features",
|
|
"biomes": "custom_ore_gen:cold_biomes", // or {"type": "forge:any"} for all biomes
|
|
"features": "custom_ore_gen:deepslatesharddiamondore",
|
|
"step": "underground_ores"
|
|
}
|
|
```
|
|
|
|
3. **Worldgen Features** (`src/main/resources/data/custom_ore_gen/worldgen/`):
|
|
- `configured_feature/` - Defines ore vein size and height range
|
|
- `placed_feature/` - Places the feature in the world with vertical anchors
|
|
|
|
### Diamond Shard Progression Tier
|
|
|
|
Diamond Shards are an intermediate tier between Iron and Diamond:
|
|
|
|
- **Items**: Diamond Shard (`diamondshard`) - craft 9 shards into 1 diamond
|
|
- **Tools**: Pickaxe, Shovel, Axe (200 durability), Paxel (1000 durability, combines all three)
|
|
- **Armor**: Helmet (3), Chestplate (7), Leggings (5), Boots (2) - Total 17 protection, 1060 durability
|
|
- **Repair**: All Diamond Shard equipment uses Diamond Shards
|
|
|
|
### Configuration System
|
|
|
|
Located in `src/main/java/net/mcreator/customoregen/config/`:
|
|
|
|
- `ModConfigs.java` - NeoForge configuration with 4 nested config classes: `OreGenConfig`, `ToolStatsConfig`, `DropsConfig`, `FeatureToggleConfig`
|
|
- `ConfigHelper.java` - Utility class for accessing config values
|
|
- Generated config file: `config/custom_ore_gen-common.toml` (created on first run)
|
|
|
|
**Current Implementation Status**:
|
|
- **✅ Ore Drops**: Fully implemented via `OreBreakEventHandler.java` which listens to `BlockEvent.BreakEvent` and calls `ConfigurableOreDropsProcedure.execute()` for all custom ores
|
|
- **⚠️ Tool Stats**: Wired. Tools read their stats from `TOOL_STATS` config when the config is loaded, with a hardcoded fallback when not yet loaded (e.g. `SharddiamondpickaxeItem.java`: `return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPickaxeDurability.get() : 200;`). See also `ConfigHelper.getShardDiamondToolDurability/Speed/Damage`.
|
|
- **⚠️ Feature Toggles**: Wired (commit `48a0d797`). Toggles in `FeatureToggleConfig` drive ore *generation* via `ConfigGatedFeaturesModifier` + the `config_gated_features` biome modifiers in `data/custom_ore_gen/neoforge/biome_modifier/add_*_ores.json`. A regression test (`ModConfigsTest.testFeatureToggleConfig_declaresAllTogglesReferencedByConfigHelper()`) ensures every toggle string used by `ConfigHelper.isFeatureEnabled()` actually maps to a field on `FeatureToggleConfig`, so a typo can't silently produce a dead toggle. Note: item/block *registration* still always fires (toggling only gates worldgen, not whether the items exist in creative).
|
|
- **⚠️ Ore Generation (gating)**: Feature toggles gate *whether* each ore feature is added (see Feature Toggles above). Vein parameters (size, count, height) are hard-coded in the data-driven worldgen JSONs under `data/custom_ore_gen/worldgen/` (`configured_feature/` + `placed_feature/`), exactly like vanilla; there is no runtime-config-driven ore parameter provider.
|
|
- **Enchantability**: Works natively in 1.21.1 via the enchantable tags (`data/minecraft/tags/item/enchantable/{mining,weapon,armor,durability}.json`, which include all Shard Diamond tools + armor) combined with `Tier.getEnchantmentValue() == 9` on the tool `Tier`s. The dead `EnchantabilityFix.java` class (which referenced the non-existent `DataComponents.ENCHANTABLE` / `net.minecraft.world.item.enchantment.Enchantable` from an earlier 1.20.5-snapshot API) has been removed.
|
|
|
|
### Ore Biome Finder
|
|
|
|
The `OreBiomeFinderItem` (`item/OreBiomeFinderItem.java`) and `/ores` command (`OresCommand.java`) detect which mod tags apply to the current biome and list findable ores.
|
|
|
|
**Implementation Details**:
|
|
- Uses `TagKey.create(Registries.BIOME, ResourceLocation.fromNamespaceAndPath("custom_ore_gen", "..."))` to define biome tags
|
|
- Checks `level.getBiome(pos()).is()` to test tag membership
|
|
- Displays biome ID, applicable tags, and ore list with height ranges
|
|
- Hardcoded ore lists by category (COLD_ORES, HOT_ORES, etc.) in `OreBiomeFinderItem.java`
|
|
|
|
## Adding a New Ore
|
|
|
|
To add a new ore type (requires MCreator for full integration):
|
|
|
|
1. **Create the block** in MCreator with proper properties (sound type, harvest level, etc.)
|
|
2. **Add loot table** at `src/main/resources/data/custom_ore_gen/loot_table/blocks/{orename}.json` (note: `loot_table` not `loot_tables`)
|
|
3. **Add configured_feature** JSON in `src/main/resources/data/custom_ore_gen/worldgen/configured_feature/`
|
|
4. **Add placed_feature** JSON in `src/main/resources/data/custom_ore_gen/worldgen/placed_feature/`
|
|
5. **Create biome_modifier** JSON in `src/main/resources/data/custom_ore_gen/neoforge/biome_modifier/` linking to a biome tag (or create a new tag in `tags/worldgen/biome/`)
|
|
6. **Add BOP entries** (optional) to appropriate biome tag JSON files with `"required": false` wrapper
|
|
7. **Update `OreBiomeFinderItem.java`** to add the new ore to the appropriate category list
|
|
8. **Add ore type mapping** in `OreBreakEventHandler.java` if you want configurable drops via `ConfigurableOreDropsProcedure`
|
|
|
|
## User Code Sections
|
|
|
|
When editing MCreator-generated files, only modify code between:
|
|
```java
|
|
// Start of user code block [section_name]
|
|
// End of user code block [section_name]
|
|
```
|
|
|
|
For example, in `CustomOreGenModItems.java` (lines 67-78):
|
|
```java
|
|
// Start of user code block custom items
|
|
public static final Supplier<Item> ORE_BIOME_FINDER = REGISTRY.register("ore_biome_finder", () -> new OreBiomeFinderItem());
|
|
// ... armor, paxel registrations
|
|
// End of user code block custom items
|
|
```
|
|
|
|
**Important**: Custom items like the Ore Biome Finder, Shard Diamond armor, and Paxel are registered in this protected section and will survive MCreator rebuilds.
|
|
|
|
## Event Handlers
|
|
|
|
The mod uses NeoForge's event system for ore processing:
|
|
|
|
### OreBreakEventHandler
|
|
- Listens to `BlockEvent.BreakEvent` with `@SubscribeEvent`
|
|
- Maps custom ore blocks to ore type strings (`shard_diamond`, `concentrated_coal`, `pure_golden`, etc.)
|
|
- Calls `ConfigurableOreDropsProcedure.execute()` with ore type when player breaks ore with correct tool
|
|
- Supports 10 ore types: shard_diamond, concentrated_coal, pure_golden, impure_iron, concentrated_diamond, lapis, redstone, emerald, copper
|
|
|
|
### Enchantability
|
|
- Implemented natively via 1.21.1 mechanisms: the Shard Diamond tools + armor are listed in `data/minecraft/tags/item/enchantable/{mining,weapon,armor,durability}.json`, and the tool `Tier`s return `getEnchantmentValue() == 9`.
|
|
- A former `EnchantabilityFix.java` used `ModifyDefaultComponentsEvent` to set a `DataComponents.ENCHANTABLE` component, but that API does not exist in 1.21.1 (only `ENCHANTMENTS`/`ENCHANTMENT_GLINT_OVERRIDE`/`STORED_ENCHANTMENTS` exist on `DataComponents`). The dead class has been deleted.
|
|
|
|
## Loot Table Format
|
|
|
|
NeoForge 1.21 uses `loot_table` (singular) instead of `loot_tables` (plural):
|
|
- Location: `src/main/resources/data/custom_ore_gen/loot_table/blocks/{orename}.json`
|
|
- Includes Silk Touch support via `match_tool` condition
|
|
- Uses `random_sequence` for loot table randomization
|
|
- Example structure in `deepslatesharddiamondore.json` shows Silk Touch → drop block, otherwise drops handled by `OreBreakEventHandler`
|
|
|
|
## Vanilla Ore Removal
|
|
|
|
The mod removes vanilla ores via NeoForge biome modifiers (NOT KubeJS anymore):
|
|
- `src/main/resources/data/custom_ore_gen/neoforge/biome_modifier/remove_vanilla_ores.json`
|
|
- Uses `neoforge:remove_features` type to remove vanilla ore generation
|
|
- This replaces the old KubeJS automatic script system from Forge 1.20.1
|
|
|
|
## Biomes O' Plenty Integration
|
|
|
|
The mod includes BOP biome support through biome tag entries. BOP biomes are wrapped with:
|
|
```json
|
|
{
|
|
"id": "biomesoplenty:biome_name",
|
|
"required": false
|
|
}
|
|
```
|
|
|
|
The `"required": false` flag ensures the game doesn't crash if BOP isn't installed. When adding new BOP biomes, add them to the appropriate category tag JSON files in `tags/worldgen/biome/`.
|
|
|
|
## Testing
|
|
|
|
After making changes:
|
|
1. Run `./gradlew build` to verify compilation
|
|
2. Run `./gradlew runClient` to test in-game
|
|
3. Check logs in `run/logs/` for errors
|
|
|
|
## Enchantment Tags
|
|
|
|
The mod includes enchantment tags at `src/main/resources/data/minecraft/tags/item/enchantable/`:
|
|
- **armor.json** - Marks Shard Diamond armor pieces as enchantable
|
|
- **durability.json** - Marks tools and armor for durability enchantments
|
|
- **mining.json** - Marks pickaxes, shovels, and paxel as mining tools
|
|
- **weapon.json** - Marks axes as weapons
|
|
|
|
These tags enable proper enchantment behavior for custom items in the enchanting table and anvil.
|
|
|
|
## Important Notes
|
|
|
|
### README Disclaimer
|
|
The `README.md` file contains outdated information referring to Forge 1.20.1. The current codebase uses **NeoForge 1.21.1**. Always trust `gradle.properties` and this file for accurate version information.
|
|
|
|
### Recipe Compatibility
|
|
The mod includes recipes for:
|
|
- **Mekanism**: Enriching recipes for concentrated ores and shard diamond
|
|
- **Create**: Crushing and milling recipes for ore processing
|
|
- **Sculk Catalyst**: Diamond shard to sculk catalyst conversion
|
|
|
|
### Version Information
|
|
- **Minecraft**: 1.21.1
|
|
- **NeoForge**: 21.1.219 (defined in `gradle.properties` as `neo_version`)
|
|
- **Java**: 21 (configured via Java toolchain in build.gradle)
|
|
- **Mod Version**: 3.0 (defined in `gradle.properties` as `mod_version`)
|
|
|
|
### Mod Registration Order
|
|
In `CustomOreGenMod` constructor, registration order is:
|
|
1. `CustomOreGenModBlocks.REGISTRY.register(modEventBus)` - Blocks must be registered first
|
|
2. `CustomOreGenModItems.REGISTRY.register(modEventBus)` - Items depend on blocks for BlockItems
|
|
3. `CustomOreGenModTabs.REGISTRY.register(modEventBus)` - Creative tabs depend on items
|
|
|
|
### Server Work Queue Pattern
|
|
The mod includes a server tick work queue (`CustomOreGenMod.java:52-69`) for deferring execution:
|
|
- `queueServerWork(int tick, Runnable action)` - Schedule work to run after N server ticks
|
|
- Only executes on server thread (`SidedThreadGroups.SERVER`)
|
|
- Processed during `ServerTickEvent.Post`
|
|
- Use this for operations that need to happen after a delay or during gameplay
|
|
|
|
### DeferredRegister Pattern
|
|
All registries use NeoForge's `DeferredRegister.create(Registries.X, CustomOreGenMod.MODID)` pattern. This is the modern NeoForge 1.21 registration method replacing the old Forge registry system.
|
|
|
|
### NeoForge 1.21 Tool Tier Implementation
|
|
When creating custom tool items (Tier), you must implement `getIncorrectBlocksForDrops()`:
|
|
- Returns `TagKey<Block>` or `null`
|
|
- If `null`, all blocks can be dropped (current implementation in `SharddiamondpickaxeItem.java:38-40`)
|
|
- This replaces the old Forge 1.20 `getTier()` and incorrect blocks logic
|