diff --git a/src/main/java/net/mcreator/customoregen/OreTypes.java b/src/main/java/net/mcreator/customoregen/OreTypes.java
new file mode 100644
index 00000000..19ada175
--- /dev/null
+++ b/src/main/java/net/mcreator/customoregen/OreTypes.java
@@ -0,0 +1,44 @@
+package net.mcreator.customoregen;
+
+import net.minecraft.world.level.block.Block;
+
+import net.mcreator.customoregen.init.CustomOreGenModBlocks;
+
+/**
+ * Central mapping between the mod's ore blocks and their logical ore type.
+ *
+ *
The ore type drives both item drops ({@code CustomOreLootModifier}) and experience
+ * ({@code ConfigurableOreDropsProcedure} via {@code OreDropMath}). Single source of truth:
+ * previously this mapping was copy-pasted in two classes.
+ */
+public final class OreTypes {
+
+ public static final String SHARD_DIAMOND = "shard_diamond";
+ public static final String CONCENTRATED_DIAMOND = "concentrated_diamond";
+ public static final String CONCENTRATED_COAL = "concentrated_coal";
+ public static final String PURE_GOLDEN = "pure_golden";
+ public static final String IMPURE_IRON = "impure_iron";
+ public static final String LAPIS = "lapis";
+ public static final String REDSTONE = "redstone";
+ public static final String EMERALD = "emerald";
+ public static final String COPPER = "copper";
+
+ private OreTypes() {}
+
+ /**
+ * Returns the logical ore type for a block, or {@code null} if the block is not one of
+ * the mod's custom ores.
+ */
+ public static String of(Block block) {
+ if (block == CustomOreGenModBlocks.SHARDDIAMONDBLOCKORE.get() || block == CustomOreGenModBlocks.DEEPSLATESHARDDIAMONDORE.get()) return SHARD_DIAMOND;
+ if (block == CustomOreGenModBlocks.CONCENTRATEDCOALORE.get()) return CONCENTRATED_COAL;
+ if (block == CustomOreGenModBlocks.PUREGOLDENORE.get() || block == CustomOreGenModBlocks.DEEPSLATEPUREGOLDENORE.get()) return PURE_GOLDEN;
+ if (block == CustomOreGenModBlocks.IRONORE.get() || block == CustomOreGenModBlocks.DEEPSLATEIRONORE.get()) return IMPURE_IRON;
+ if (block == CustomOreGenModBlocks.DEEPSLATEDIAMONDORE.get()) return CONCENTRATED_DIAMOND;
+ if (block == CustomOreGenModBlocks.LAPISORE.get() || block == CustomOreGenModBlocks.DEEPSLATELAPISORE.get()) return LAPIS;
+ if (block == CustomOreGenModBlocks.REDSTONEORE.get() || block == CustomOreGenModBlocks.DEEPSLATEREDSTONEORE.get()) return REDSTONE;
+ if (block == CustomOreGenModBlocks.HIGHEMERALDORE.get() || block == CustomOreGenModBlocks.LOWEREMERALDORE.get()) return EMERALD;
+ if (block == CustomOreGenModBlocks.COPPERHIGHORE.get() || block == CustomOreGenModBlocks.COPPERLOWERORE.get()) return COPPER;
+ return null;
+ }
+}
diff --git a/src/main/java/net/mcreator/customoregen/OresCommand.java b/src/main/java/net/mcreator/customoregen/OresCommand.java
index 8ff2ccc8..b0ea9b3f 100644
--- a/src/main/java/net/mcreator/customoregen/OresCommand.java
+++ b/src/main/java/net/mcreator/customoregen/OresCommand.java
@@ -2,7 +2,6 @@ package net.mcreator.customoregen;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
-import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
@@ -10,35 +9,11 @@ import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
-import java.util.*;
-
-import net.mcreator.customoregen.worldgen.LatitudeConfig;
+import net.mcreator.customoregen.worldgen.OreZoneCatalog;
@EventBusSubscriber(modid = CustomOreGenMod.MODID, bus = EventBusSubscriber.Bus.GAME)
public class OresCommand {
- private static final List COLD_ORES = Arrays.asList(
- "Lapis (stone) [Y: 0 a 32]",
- "Lapis (deepslate) [Y: -64 a 0]",
- "Diamant (deepslate) [Y: -64 a 0]");
-
- private static final List HOT_ORES = Arrays.asList(
- "Or (stone) [Y: 0 a 320]",
- "Or (deepslate) [Y: -64 a 0]",
- "Cuivre (haut) [Y: 15 a 320]",
- "Cuivre (bas) [Y: -64 a 0]",
- "Redstone (stone) [Y: -10 a 20]",
- "Redstone (deepslate) [Y: -80 a -30]");
-
- private static final List TEMPERATE_ORES = Arrays.asList(
- "Fer (stone) [Y: 0 a 100]",
- "Fer (deepslate) [Y: -64 a 0]",
- "Charbon concentre [Y: 0 a 70]");
-
- private static final List EVERYWHERE_ORES = Arrays.asList(
- "Diamant Shard (deepslate) [Y: -64 a -40]",
- "Bloc Diamant Shard [Y: 0 a 15]");
-
@SubscribeEvent
public static void onRegisterCommands(RegisterCommandsEvent event) {
event.getDispatcher().register(Commands.literal("ores")
@@ -58,48 +33,10 @@ public class OresCommand {
int x = player.blockPosition().getX();
int z = player.blockPosition().getZ();
- String zone = LatitudeConfig.zoneName(z);
- int coldZ = LatitudeConfig.getColdZoneZ();
- int hotZ = LatitudeConfig.getHotZoneZ();
- ChatFormatting zoneColor = zoneColor(zone);
-
- context.getSource().sendSuccess(() -> Component.literal(
- "=== Position: X=" + x + " Z=" + z + " ===").withStyle(ChatFormatting.GRAY), true);
- context.getSource().sendSuccess(() -> Component.literal(
- "Zone determinee par la coordonnee Z : " + zone).withStyle(zoneColor), true);
- context.getSource().sendSuccess(() -> Component.literal(
- "Z < " + coldZ + " = froid | " + coldZ + " a " + hotZ + " = tempere | Z > " + hotZ + " = chaud")
- .withStyle(ChatFormatting.GRAY), true);
-
- List zoneOres = new ArrayList<>();
- switch (zone) {
- case "COLD" -> zoneOres.addAll(COLD_ORES);
- case "HOT" -> zoneOres.addAll(HOT_ORES);
- case "TEMPERATE" -> zoneOres.addAll(TEMPERATE_ORES);
- }
-
- Set allOres = new LinkedHashSet<>(zoneOres);
- allOres.addAll(EVERYWHERE_ORES);
-
- context.getSource().sendSuccess(() -> Component.literal(
- "Minerais trouvables (" + allOres.size() + ") :").withStyle(ChatFormatting.WHITE), true);
- for (String ore : zoneOres) {
- context.getSource().sendSuccess(() -> Component.literal(" * " + ore).withStyle(zoneColor), true);
- }
- for (String ore : EVERYWHERE_ORES) {
- context.getSource().sendSuccess(() -> Component.literal(" * " + ore)
- .withStyle(ChatFormatting.LIGHT_PURPLE), true);
+ for (Component line : OreZoneCatalog.buildZoneReport(x, z)) {
+ context.getSource().sendSuccess(() -> line, true);
}
return 1;
}
-
- private static ChatFormatting zoneColor(String zone) {
- return switch (zone) {
- case "COLD" -> ChatFormatting.AQUA;
- case "HOT" -> ChatFormatting.GOLD;
- case "TEMPERATE" -> ChatFormatting.GREEN;
- default -> ChatFormatting.WHITE;
- };
- }
}
diff --git a/src/main/java/net/mcreator/customoregen/event/OreBreakEventHandler.java b/src/main/java/net/mcreator/customoregen/event/OreBreakEventHandler.java
index e80c0ea5..4ad2e066 100644
--- a/src/main/java/net/mcreator/customoregen/event/OreBreakEventHandler.java
+++ b/src/main/java/net/mcreator/customoregen/event/OreBreakEventHandler.java
@@ -3,10 +3,8 @@ package net.mcreator.customoregen.event;
import net.neoforged.neoforge.event.level.BlockDropsEvent;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
-import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.block.Block;
-import net.mcreator.customoregen.init.CustomOreGenModBlocks;
+import net.mcreator.customoregen.OreTypes;
import net.mcreator.customoregen.procedures.ConfigurableOreDropsProcedure;
@EventBusSubscriber
@@ -14,30 +12,13 @@ public class OreBreakEventHandler {
@SubscribeEvent
public static void onBlockDrops(BlockDropsEvent event) {
- BlockState state = event.getState();
- Block block = state.getBlock();
- String oreType = getOreType(block);
+ String oreType = OreTypes.of(event.getState().getBlock());
- if (oreType != null) {
- // Item drops are now handled by CustomOreLootModifier (Global Loot Modifier)
- // to ensure compatibility with machines and avoid duplication.
-
- if (event.getBreaker() != null) {
- ConfigurableOreDropsProcedure.execute(event.getLevel(), event.getPos().getX(), event.getPos().getY(), event.getPos().getZ(), event.getBreaker(), oreType);
- }
+ // Item drops are handled by CustomOreLootModifier (Global Loot Modifier)
+ // to ensure compatibility with machines and avoid duplication.
+ // This handler only spawns the experience orb for player-mined ores.
+ if (oreType != null && event.getBreaker() != null) {
+ ConfigurableOreDropsProcedure.execute(event.getLevel(), event.getPos().getX(), event.getPos().getY(), event.getPos().getZ(), event.getBreaker(), oreType);
}
}
-
- private static String getOreType(Block block) {
- if (block == CustomOreGenModBlocks.SHARDDIAMONDBLOCKORE.get() || block == CustomOreGenModBlocks.DEEPSLATESHARDDIAMONDORE.get()) return "shard_diamond";
- if (block == CustomOreGenModBlocks.CONCENTRATEDCOALORE.get()) return "concentrated_coal";
- if (block == CustomOreGenModBlocks.PUREGOLDENORE.get() || block == CustomOreGenModBlocks.DEEPSLATEPUREGOLDENORE.get()) return "pure_golden";
- if (block == CustomOreGenModBlocks.IRONORE.get() || block == CustomOreGenModBlocks.DEEPSLATEIRONORE.get()) return "impure_iron";
- if (block == CustomOreGenModBlocks.DEEPSLATEDIAMONDORE.get()) return "concentrated_diamond";
- if (block == CustomOreGenModBlocks.LAPISORE.get() || block == CustomOreGenModBlocks.DEEPSLATELAPISORE.get()) return "lapis";
- if (block == CustomOreGenModBlocks.REDSTONEORE.get() || block == CustomOreGenModBlocks.DEEPSLATEREDSTONEORE.get()) return "redstone";
- if (block == CustomOreGenModBlocks.HIGHEMERALDORE.get() || block == CustomOreGenModBlocks.LOWEREMERALDORE.get()) return "emerald";
- if (block == CustomOreGenModBlocks.COPPERHIGHORE.get() || block == CustomOreGenModBlocks.COPPERLOWERORE.get()) return "copper";
- return null;
- }
}
diff --git a/src/main/java/net/mcreator/customoregen/item/OreBiomeFinderItem.java b/src/main/java/net/mcreator/customoregen/item/OreBiomeFinderItem.java
index 59f0caa7..1a1f1dfd 100644
--- a/src/main/java/net/mcreator/customoregen/item/OreBiomeFinderItem.java
+++ b/src/main/java/net/mcreator/customoregen/item/OreBiomeFinderItem.java
@@ -1,6 +1,5 @@
package net.mcreator.customoregen.item;
-import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
@@ -9,34 +8,10 @@ import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
-import java.util.*;
-
-import net.mcreator.customoregen.worldgen.LatitudeConfig;
+import net.mcreator.customoregen.worldgen.OreZoneCatalog;
public class OreBiomeFinderItem extends Item {
- private static final List COLD_ORES = Arrays.asList(
- "Lapis (stone) [Y: 0 a 32]",
- "Lapis (deepslate) [Y: -64 a 0]",
- "Diamant (deepslate) [Y: -64 a 0]");
-
- private static final List HOT_ORES = Arrays.asList(
- "Or (stone) [Y: 0 a 320]",
- "Or (deepslate) [Y: -64 a 0]",
- "Cuivre (haut) [Y: 15 a 320]",
- "Cuivre (bas) [Y: -64 a 0]",
- "Redstone (stone) [Y: -10 a 20]",
- "Redstone (deepslate) [Y: -80 a -30]");
-
- private static final List TEMPERATE_ORES = Arrays.asList(
- "Fer (stone) [Y: 0 a 100]",
- "Fer (deepslate) [Y: -64 a 0]",
- "Charbon concentre [Y: 0 a 70]");
-
- private static final List EVERYWHERE_ORES = Arrays.asList(
- "Diamant Shard (deepslate) [Y: -64 a -40]",
- "Bloc Diamant Shard [Y: 0 a 15]");
-
public OreBiomeFinderItem() {
super(new Item.Properties().stacksTo(1));
}
@@ -49,49 +24,11 @@ public class OreBiomeFinderItem extends Item {
int x = player.blockPosition().getX();
int z = player.blockPosition().getZ();
- String zone = LatitudeConfig.zoneName(z);
- int coldZ = LatitudeConfig.getColdZoneZ();
- int hotZ = LatitudeConfig.getHotZoneZ();
- ChatFormatting zoneColor = zoneColor(zone);
-
- player.displayClientMessage(Component.literal(
- "=== Position: X=" + x + " Z=" + z + " ===").withStyle(ChatFormatting.GRAY), false);
- player.displayClientMessage(Component.literal(
- "Zone determinee par la coordonnee Z : " + zone).withStyle(zoneColor), false);
- player.displayClientMessage(Component.literal(
- "Z < " + coldZ + " = froid | " + coldZ + " a " + hotZ + " = tempere | Z > " + hotZ + " = chaud")
- .withStyle(ChatFormatting.GRAY), false);
-
- List zoneOres = new ArrayList<>();
- switch (zone) {
- case "COLD" -> zoneOres.addAll(COLD_ORES);
- case "HOT" -> zoneOres.addAll(HOT_ORES);
- case "TEMPERATE" -> zoneOres.addAll(TEMPERATE_ORES);
- }
-
- Set allOres = new LinkedHashSet<>(zoneOres);
- allOres.addAll(EVERYWHERE_ORES);
-
- player.displayClientMessage(Component.literal(
- "Minerais trouvables (" + allOres.size() + ") :").withStyle(ChatFormatting.WHITE), false);
- for (String ore : zoneOres) {
- player.displayClientMessage(Component.literal(" * " + ore).withStyle(zoneColor), false);
- }
- for (String ore : EVERYWHERE_ORES) {
- player.displayClientMessage(Component.literal(" * " + ore)
- .withStyle(ChatFormatting.LIGHT_PURPLE), false);
+ for (Component line : OreZoneCatalog.buildZoneReport(x, z)) {
+ player.displayClientMessage(line, false);
}
}
return InteractionResultHolder.sidedSuccess(stack, level.isClientSide);
}
-
- private static ChatFormatting zoneColor(String zone) {
- return switch (zone) {
- case "COLD" -> ChatFormatting.AQUA;
- case "HOT" -> ChatFormatting.GOLD;
- case "TEMPERATE" -> ChatFormatting.GREEN;
- default -> ChatFormatting.WHITE;
- };
- }
}
diff --git a/src/main/java/net/mcreator/customoregen/item/ShardDiamondToolTier.java b/src/main/java/net/mcreator/customoregen/item/ShardDiamondToolTier.java
new file mode 100644
index 00000000..d2d89330
--- /dev/null
+++ b/src/main/java/net/mcreator/customoregen/item/ShardDiamondToolTier.java
@@ -0,0 +1,87 @@
+package net.mcreator.customoregen.item;
+
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+
+import net.minecraft.tags.BlockTags;
+import net.minecraft.tags.TagKey;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Tier;
+import net.minecraft.world.item.crafting.Ingredient;
+import net.minecraft.world.level.block.Block;
+
+import net.mcreator.customoregen.config.ModConfigs;
+import net.mcreator.customoregen.init.CustomOreGenModItems;
+
+/**
+ * Shared {@link Tier} for all Shard Diamond tools (previously an anonymous Tier
+ * copy-pasted in each tool class). Stats are read live from the config, with
+ * fallbacks for the pre-config-load phase (item registration).
+ */
+public enum ShardDiamondToolTier implements Tier {
+ PICKAXE(200, 7.0f, 1.0f, 9,
+ () -> ModConfigs.TOOL_STATS.shardDiamondPickaxeDurability.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondPickaxeSpeed.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondPickaxeAttackDamage.get()),
+ AXE(200, 7.0f, 6.0f, 9,
+ () -> ModConfigs.TOOL_STATS.shardDiamondAxeDurability.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondAxeSpeed.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondAxeAttackDamage.get()),
+ SHOVEL(200, 4.0f, 2.0f, 9,
+ () -> ModConfigs.TOOL_STATS.shardDiamondShovelDurability.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondShovelSpeed.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondShovelAttackDamage.get()),
+ PAXEL(1000, 6.5f, 4.0f, 14,
+ () -> ModConfigs.TOOL_STATS.shardDiamondPaxelDurability.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondPaxelSpeed.get(),
+ () -> ModConfigs.TOOL_STATS.shardDiamondPaxelAttackDamage.get());
+
+ private final int fallbackUses;
+ private final float fallbackSpeed;
+ private final float fallbackAttackDamage;
+ private final int enchantmentValue;
+ private final IntSupplier uses;
+ private final DoubleSupplier speed;
+ private final IntSupplier attackDamage;
+
+ ShardDiamondToolTier(int fallbackUses, float fallbackSpeed, float fallbackAttackDamage, int enchantmentValue,
+ IntSupplier uses, DoubleSupplier speed, IntSupplier attackDamage) {
+ this.fallbackUses = fallbackUses;
+ this.fallbackSpeed = fallbackSpeed;
+ this.fallbackAttackDamage = fallbackAttackDamage;
+ this.enchantmentValue = enchantmentValue;
+ this.uses = uses;
+ this.speed = speed;
+ this.attackDamage = attackDamage;
+ }
+
+ @Override
+ public int getUses() {
+ return ModConfigs.isLoaded() ? uses.getAsInt() : fallbackUses;
+ }
+
+ @Override
+ public float getSpeed() {
+ return ModConfigs.isLoaded() ? (float) speed.getAsDouble() : fallbackSpeed;
+ }
+
+ @Override
+ public float getAttackDamageBonus() {
+ return ModConfigs.isLoaded() ? attackDamage.getAsInt() : fallbackAttackDamage;
+ }
+
+ @Override
+ public int getEnchantmentValue() {
+ return enchantmentValue;
+ }
+
+ @Override
+ public Ingredient getRepairIngredient() {
+ return Ingredient.of(new ItemStack(CustomOreGenModItems.DIAMONDSHARD.get()));
+ }
+
+ @Override
+ public TagKey getIncorrectBlocksForDrops() {
+ return BlockTags.INCORRECT_FOR_DIAMOND_TOOL;
+ }
+}
diff --git a/src/main/java/net/mcreator/customoregen/item/SharddiamondaxeItem.java b/src/main/java/net/mcreator/customoregen/item/SharddiamondaxeItem.java
index 4e0d79c8..7a18f494 100644
--- a/src/main/java/net/mcreator/customoregen/item/SharddiamondaxeItem.java
+++ b/src/main/java/net/mcreator/customoregen/item/SharddiamondaxeItem.java
@@ -1,46 +1,16 @@
package net.mcreator.customoregen.item;
-import net.minecraft.world.item.crafting.Ingredient;
-import net.minecraft.world.item.Tier;
-import net.minecraft.world.item.Item;
import net.minecraft.world.item.AxeItem;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.tags.TagKey;
+import net.minecraft.world.item.Item;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.block.Block;
-import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ModConfigs;
public class SharddiamondaxeItem extends AxeItem {
public SharddiamondaxeItem() {
- super(new Tier() {
- public int getUses() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondAxeDurability.get() : 200;
- }
-
- public float getSpeed() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondAxeSpeed.get().floatValue() : 7.0f;
- }
-
- public float getAttackDamageBonus() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondAxeAttackDamage.get().floatValue() : 6.0f;
- }
-
- public int getEnchantmentValue() {
- return 9;
- }
-
- public Ingredient getRepairIngredient() {
- return Ingredient.of(new ItemStack(CustomOreGenModItems.DIAMONDSHARD.get()));
- }
-
- // 1.21 - new method required - returns diamond-tier incorrect blocks
- public TagKey getIncorrectBlocksForDrops() {
- return BlockTags.INCORRECT_FOR_DIAMOND_TOOL;
- }
- }, new Item.Properties());
+ super(ShardDiamondToolTier.AXE, new Item.Properties());
}
@Override
diff --git a/src/main/java/net/mcreator/customoregen/item/SharddiamondpaxelItem.java b/src/main/java/net/mcreator/customoregen/item/SharddiamondpaxelItem.java
index 6c1f5118..c59e3739 100644
--- a/src/main/java/net/mcreator/customoregen/item/SharddiamondpaxelItem.java
+++ b/src/main/java/net/mcreator/customoregen/item/SharddiamondpaxelItem.java
@@ -1,46 +1,16 @@
package net.mcreator.customoregen.item;
-import net.minecraft.world.item.crafting.Ingredient;
-import net.minecraft.world.item.Tier;
import net.minecraft.world.item.PickaxeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item;
-import net.minecraft.tags.TagKey;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.block.Block;
-import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ModConfigs;
public class SharddiamondpaxelItem extends PickaxeItem {
public SharddiamondpaxelItem() {
- super(new Tier() {
- public int getUses() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPaxelDurability.get() : 1000;
- }
-
- public float getSpeed() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPaxelSpeed.get().floatValue() : 6.5f;
- }
-
- public float getAttackDamageBonus() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPaxelAttackDamage.get().floatValue() : 4.0f;
- }
-
- public int getEnchantmentValue() {
- return 14;
- }
-
- public Ingredient getRepairIngredient() {
- return Ingredient.of(new ItemStack(CustomOreGenModItems.DIAMONDSHARD.get()));
- }
-
- // 1.21 - new method required - returns diamond-tier incorrect blocks
- public TagKey getIncorrectBlocksForDrops() {
- return BlockTags.INCORRECT_FOR_DIAMOND_TOOL;
- }
- }, new Item.Properties());
+ super(ShardDiamondToolTier.PAXEL, new Item.Properties());
}
@Override
diff --git a/src/main/java/net/mcreator/customoregen/item/SharddiamondpickaxeItem.java b/src/main/java/net/mcreator/customoregen/item/SharddiamondpickaxeItem.java
index f782ab2e..ee964f25 100644
--- a/src/main/java/net/mcreator/customoregen/item/SharddiamondpickaxeItem.java
+++ b/src/main/java/net/mcreator/customoregen/item/SharddiamondpickaxeItem.java
@@ -1,47 +1,16 @@
-
package net.mcreator.customoregen.item;
-import net.minecraft.world.item.crafting.Ingredient;
-import net.minecraft.world.item.Tier;
import net.minecraft.world.item.PickaxeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item;
-import net.minecraft.tags.TagKey;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.block.Block;
-import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ModConfigs;
public class SharddiamondpickaxeItem extends PickaxeItem {
public SharddiamondpickaxeItem() {
- super(new Tier() {
- public int getUses() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPickaxeDurability.get() : 200;
- }
-
- public float getSpeed() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPickaxeSpeed.get().floatValue() : 7.0f;
- }
-
- public float getAttackDamageBonus() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondPickaxeAttackDamage.get().floatValue() : 1.0f;
- }
-
- public int getEnchantmentValue() {
- return 9;
- }
-
- public Ingredient getRepairIngredient() {
- return Ingredient.of(new ItemStack(CustomOreGenModItems.DIAMONDSHARD.get()));
- }
-
- // 1.21 - new method required - returns diamond-tier incorrect blocks
- public TagKey getIncorrectBlocksForDrops() {
- return BlockTags.INCORRECT_FOR_DIAMOND_TOOL;
- }
- }, new Item.Properties());
+ super(ShardDiamondToolTier.PICKAXE, new Item.Properties());
}
@Override
diff --git a/src/main/java/net/mcreator/customoregen/item/SharddiamondshovelItem.java b/src/main/java/net/mcreator/customoregen/item/SharddiamondshovelItem.java
index 96bc153c..9e45c089 100644
--- a/src/main/java/net/mcreator/customoregen/item/SharddiamondshovelItem.java
+++ b/src/main/java/net/mcreator/customoregen/item/SharddiamondshovelItem.java
@@ -1,47 +1,16 @@
-
package net.mcreator.customoregen.item;
-import net.minecraft.world.item.crafting.Ingredient;
-import net.minecraft.world.item.Tier;
import net.minecraft.world.item.ShovelItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item;
-import net.minecraft.tags.TagKey;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.block.Block;
-import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ModConfigs;
public class SharddiamondshovelItem extends ShovelItem {
public SharddiamondshovelItem() {
- super(new Tier() {
- public int getUses() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondShovelDurability.get() : 200;
- }
-
- public float getSpeed() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondShovelSpeed.get().floatValue() : 4.0f;
- }
-
- public float getAttackDamageBonus() {
- return ModConfigs.isLoaded() ? ModConfigs.TOOL_STATS.shardDiamondShovelAttackDamage.get().floatValue() : 2.0f;
- }
-
- public int getEnchantmentValue() {
- return 9;
- }
-
- public Ingredient getRepairIngredient() {
- return Ingredient.of(new ItemStack(CustomOreGenModItems.DIAMONDSHARD.get()));
- }
-
- // 1.21 - new method required - returns diamond-tier incorrect blocks
- public TagKey getIncorrectBlocksForDrops() {
- return BlockTags.INCORRECT_FOR_DIAMOND_TOOL;
- }
- }, new Item.Properties());
+ super(ShardDiamondToolTier.SHOVEL, new Item.Properties());
}
@Override
diff --git a/src/main/java/net/mcreator/customoregen/loot/CustomOreLootModifier.java b/src/main/java/net/mcreator/customoregen/loot/CustomOreLootModifier.java
index cd64e59e..dd4d2868 100644
--- a/src/main/java/net/mcreator/customoregen/loot/CustomOreLootModifier.java
+++ b/src/main/java/net/mcreator/customoregen/loot/CustomOreLootModifier.java
@@ -3,6 +3,8 @@ package net.mcreator.customoregen.loot;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
@@ -16,18 +18,57 @@ import net.neoforged.neoforge.common.loot.LootModifier;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.enchantment.Enchantments;
+import net.mcreator.customoregen.OreTypes;
import net.mcreator.customoregen.init.CustomOreGenModBlocks;
import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ModConfigs;
+import net.mcreator.customoregen.procedures.OreDropMath;
import net.mcreator.customoregen.CustomOreGenMod;
+import java.util.Map;
+import java.util.function.Supplier;
+
import javax.annotation.Nonnull;
public class CustomOreLootModifier extends LootModifier {
- public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst ->
+ public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst ->
codecStart(inst).apply(inst, CustomOreLootModifier::new)
);
+ /** Drop parameters for one ore type, read live from the config. */
+ private record DropSpec(Supplier minDrops, Supplier maxDrops,
+ Supplier enableFortune, Supplier- item) {}
+
+ private static final Map DROP_SPECS = Map.of(
+ OreTypes.SHARD_DIAMOND, new DropSpec(ModConfigs.DROPS.shardDiamondOreMinDrops::get,
+ ModConfigs.DROPS.shardDiamondOreMaxDrops::get, ModConfigs.DROPS.shardDiamondOreEnableFortune::get,
+ CustomOreGenModItems.DIAMONDSHARD::get),
+ OreTypes.CONCENTRATED_DIAMOND, new DropSpec(ModConfigs.DROPS.concentratedDiamondOreMinDrops::get,
+ ModConfigs.DROPS.concentratedDiamondOreMaxDrops::get, ModConfigs.DROPS.concentratedDiamondOreEnableFortune::get,
+ () -> Items.DIAMOND),
+ OreTypes.CONCENTRATED_COAL, new DropSpec(ModConfigs.DROPS.concentratedCoalOreMinDrops::get,
+ ModConfigs.DROPS.concentratedCoalOreMaxDrops::get, ModConfigs.DROPS.concentratedCoalOreEnableFortune::get,
+ () -> Items.COAL),
+ OreTypes.PURE_GOLDEN, new DropSpec(ModConfigs.DROPS.pureGoldenOreMinDrops::get,
+ ModConfigs.DROPS.pureGoldenOreMaxDrops::get, ModConfigs.DROPS.pureGoldenOreEnableFortune::get,
+ () -> Items.RAW_GOLD),
+ OreTypes.IMPURE_IRON, new DropSpec(ModConfigs.DROPS.impureIronOreMinDrops::get,
+ ModConfigs.DROPS.impureIronOreMaxDrops::get, ModConfigs.DROPS.impureIronOreEnableFortune::get,
+ () -> Items.RAW_IRON),
+ OreTypes.LAPIS, new DropSpec(ModConfigs.DROPS.lapisOreMinDrops::get,
+ ModConfigs.DROPS.lapisOreMaxDrops::get, ModConfigs.DROPS.lapisOreEnableFortune::get,
+ () -> Items.LAPIS_LAZULI),
+ OreTypes.REDSTONE, new DropSpec(ModConfigs.DROPS.redstoneOreMinDrops::get,
+ ModConfigs.DROPS.redstoneOreMaxDrops::get, ModConfigs.DROPS.redstoneOreEnableFortune::get,
+ () -> Items.REDSTONE),
+ OreTypes.EMERALD, new DropSpec(ModConfigs.DROPS.emeraldOreMinDrops::get,
+ ModConfigs.DROPS.emeraldOreMaxDrops::get, () -> true,
+ () -> Items.EMERALD),
+ OreTypes.COPPER, new DropSpec(ModConfigs.DROPS.copperOreMinDrops::get,
+ ModConfigs.DROPS.copperOreMaxDrops::get, ModConfigs.DROPS.copperOreEnableFortune::get,
+ () -> Items.RAW_COPPER)
+ );
+
public CustomOreLootModifier(LootItemCondition[] conditionsIn) {
super(conditionsIn);
}
@@ -45,44 +86,40 @@ public class CustomOreLootModifier extends LootModifier {
if (state == null) return generatedLoot;
Block block = state.getBlock();
- String oreType = getOreType(block);
+ String oreType = OreTypes.of(block);
if (oreType != null) {
ItemStack tool = context.getParamOrNull(LootContextParams.TOOL);
-
- // Check for Silk Touch
- if (tool != null && !tool.isEmpty()) {
- var registry = context.getLevel().registryAccess().lookupOrThrow(Registries.ENCHANTMENT);
- int silkLevel = tool.getEnchantmentLevel(registry.getOrThrow(Enchantments.SILK_TOUCH));
-
- if (silkLevel > 0) {
- // For Diamond Shard, we want to keep the modded block itself
- if (oreType.equals("shard_diamond")) {
- ObjectArrayList shardLoot = new ObjectArrayList<>();
- shardLoot.add(new ItemStack(block));
- return shardLoot;
- }
- // For others, convert to vanilla block equivalent
- ItemStack vanillaBlock = getVanillaBlockDrop(block);
- if (!vanillaBlock.isEmpty()) {
- ObjectArrayList silkLoot = new ObjectArrayList<>();
- silkLoot.add(vanillaBlock);
- return silkLoot;
- }
- return generatedLoot;
+ var enchantmentRegistry = context.getLevel().registryAccess().lookupOrThrow(Registries.ENCHANTMENT);
+
+ // Silk Touch: drop the ore block itself instead of the custom drops
+ if (tool != null && !tool.isEmpty()
+ && tool.getEnchantmentLevel(enchantmentRegistry.getOrThrow(Enchantments.SILK_TOUCH)) > 0) {
+ // For Diamond Shard, we want to keep the modded block itself
+ if (oreType.equals(OreTypes.SHARD_DIAMOND)) {
+ ObjectArrayList shardLoot = new ObjectArrayList<>();
+ shardLoot.add(new ItemStack(block));
+ return shardLoot;
}
+ // For others, convert to vanilla block equivalent
+ ItemStack vanillaBlock = getVanillaBlockDrop(block);
+ if (!vanillaBlock.isEmpty()) {
+ ObjectArrayList silkLoot = new ObjectArrayList<>();
+ silkLoot.add(vanillaBlock);
+ return silkLoot;
+ }
+ return generatedLoot;
}
- // If not silk touch, replace with custom drops
- ObjectArrayList customDrops = new ObjectArrayList<>();
+ // No Silk Touch: replace with custom drops (fortune-aware)
int fortuneLevel = 0;
if (tool != null && !tool.isEmpty()) {
- var registry = context.getLevel().registryAccess().lookupOrThrow(Registries.ENCHANTMENT);
- fortuneLevel = tool.getEnchantmentLevel(registry.getOrThrow(Enchantments.FORTUNE));
+ fortuneLevel = tool.getEnchantmentLevel(enchantmentRegistry.getOrThrow(Enchantments.FORTUNE));
}
+ ObjectArrayList customDrops = new ObjectArrayList<>();
addCustomDrops(customDrops, oreType, fortuneLevel, context.getRandom());
-
+
// Only return custom drops if we generated some, otherwise fallback to original
if (!customDrops.isEmpty()) {
return customDrops;
@@ -91,21 +128,8 @@ public class CustomOreLootModifier extends LootModifier {
} catch (Exception e) {
CustomOreGenMod.LOGGER.error("Error applying CustomOreLootModifier", e);
}
-
- return generatedLoot;
- }
- private String getOreType(Block block) {
- if (block == CustomOreGenModBlocks.SHARDDIAMONDBLOCKORE.get() || block == CustomOreGenModBlocks.DEEPSLATESHARDDIAMONDORE.get()) return "shard_diamond";
- if (block == CustomOreGenModBlocks.CONCENTRATEDCOALORE.get()) return "concentrated_coal";
- if (block == CustomOreGenModBlocks.PUREGOLDENORE.get() || block == CustomOreGenModBlocks.DEEPSLATEPUREGOLDENORE.get()) return "pure_golden";
- if (block == CustomOreGenModBlocks.IRONORE.get() || block == CustomOreGenModBlocks.DEEPSLATEIRONORE.get()) return "impure_iron";
- if (block == CustomOreGenModBlocks.DEEPSLATEDIAMONDORE.get()) return "concentrated_diamond";
- if (block == CustomOreGenModBlocks.LAPISORE.get() || block == CustomOreGenModBlocks.DEEPSLATELAPISORE.get()) return "lapis";
- if (block == CustomOreGenModBlocks.REDSTONEORE.get() || block == CustomOreGenModBlocks.DEEPSLATEREDSTONEORE.get()) return "redstone";
- if (block == CustomOreGenModBlocks.HIGHEMERALDORE.get() || block == CustomOreGenModBlocks.LOWEREMERALDORE.get()) return "emerald";
- if (block == CustomOreGenModBlocks.COPPERHIGHORE.get() || block == CustomOreGenModBlocks.COPPERLOWERORE.get()) return "copper";
- return null;
+ return generatedLoot;
}
private ItemStack getVanillaBlockDrop(Block block) {
@@ -126,87 +150,14 @@ public class CustomOreLootModifier extends LootModifier {
return ItemStack.EMPTY;
}
- private void addCustomDrops(ObjectArrayList drops, String oreType, int fortuneLevel, net.minecraft.util.RandomSource random) {
- int minDrops = 1;
- int maxDrops = 1;
- boolean enableFortune = true;
- ItemStack dropItem = ItemStack.EMPTY;
-
- switch (oreType) {
- case "shard_diamond":
- minDrops = ModConfigs.DROPS.shardDiamondOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.shardDiamondOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.shardDiamondOreEnableFortune.get();
- dropItem = new ItemStack(CustomOreGenModItems.DIAMONDSHARD.get());
- break;
- case "concentrated_diamond":
- minDrops = ModConfigs.DROPS.concentratedDiamondOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.concentratedDiamondOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.concentratedDiamondOreEnableFortune.get();
- dropItem = new ItemStack(Items.DIAMOND);
- break;
- case "concentrated_coal":
- minDrops = ModConfigs.DROPS.concentratedCoalOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.concentratedCoalOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.concentratedCoalOreEnableFortune.get();
- dropItem = new ItemStack(Items.COAL);
- break;
- case "pure_golden":
- minDrops = ModConfigs.DROPS.pureGoldenOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.pureGoldenOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.pureGoldenOreEnableFortune.get();
- dropItem = new ItemStack(Items.RAW_GOLD);
- break;
- case "impure_iron":
- minDrops = ModConfigs.DROPS.impureIronOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.impureIronOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.impureIronOreEnableFortune.get();
- dropItem = new ItemStack(Items.RAW_IRON);
- break;
- case "lapis":
- minDrops = ModConfigs.DROPS.lapisOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.lapisOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.lapisOreEnableFortune.get();
- dropItem = new ItemStack(Items.LAPIS_LAZULI);
- break;
- case "redstone":
- minDrops = ModConfigs.DROPS.redstoneOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.redstoneOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.redstoneOreEnableFortune.get();
- dropItem = new ItemStack(Items.REDSTONE);
- break;
- case "emerald":
- minDrops = ModConfigs.DROPS.emeraldOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.emeraldOreMaxDrops.get();
- dropItem = new ItemStack(Items.EMERALD);
- break;
- case "copper":
- minDrops = ModConfigs.DROPS.copperOreMinDrops.get();
- maxDrops = ModConfigs.DROPS.copperOreMaxDrops.get();
- enableFortune = ModConfigs.DROPS.copperOreEnableFortune.get();
- dropItem = new ItemStack(Items.RAW_COPPER);
- break;
- }
-
- if (dropItem.isEmpty()) return;
-
- int dropCount = minDrops + (maxDrops > minDrops ? random.nextInt(maxDrops - minDrops + 1) : 0);
-
- if (enableFortune && fortuneLevel > 0) {
- if (oreType.equals("lapis") || oreType.equals("copper") || oreType.equals("redstone")) {
- int multiplier = random.nextInt(fortuneLevel + 2) - 1;
- if (multiplier < 0) multiplier = 0;
- dropCount *= (multiplier + 1);
- } else {
- int fortuneBonus = random.nextInt(fortuneLevel + 2) - 1;
- if (fortuneBonus < 0) fortuneBonus = 0;
- dropCount += fortuneBonus;
- }
- }
+ private void addCustomDrops(ObjectArrayList drops, String oreType, int fortuneLevel, RandomSource random) {
+ DropSpec spec = DROP_SPECS.get(oreType);
+ if (spec == null) return;
+ int dropCount = OreDropMath.dropCount(oreType, spec.minDrops().get(), spec.maxDrops().get(),
+ spec.enableFortune().get(), fortuneLevel, random::nextInt);
if (dropCount > 0) {
- dropItem.setCount(dropCount);
- drops.add(dropItem);
+ drops.add(new ItemStack(spec.item().get(), dropCount));
}
}
}
diff --git a/src/main/java/net/mcreator/customoregen/procedures/ConfigurableOreDropsProcedure.java b/src/main/java/net/mcreator/customoregen/procedures/ConfigurableOreDropsProcedure.java
index bbc89aaa..3657c5f0 100644
--- a/src/main/java/net/mcreator/customoregen/procedures/ConfigurableOreDropsProcedure.java
+++ b/src/main/java/net/mcreator/customoregen/procedures/ConfigurableOreDropsProcedure.java
@@ -34,7 +34,7 @@ public class ConfigurableOreDropsProcedure {
return;
}
- int expAmount = OreDropMath.experienceFor(oreType, new Random());
+ int expAmount = OreDropMath.experienceFor(oreType, new Random()::nextInt);
if (expAmount > 0 && world instanceof ServerLevel serverLevel) {
serverLevel.addFreshEntity(new ExperienceOrb(serverLevel, x + 0.5, y + 0.5, z + 0.5, expAmount));
}
diff --git a/src/main/java/net/mcreator/customoregen/procedures/OreDropMath.java b/src/main/java/net/mcreator/customoregen/procedures/OreDropMath.java
index 71af422e..55fbfa0c 100644
--- a/src/main/java/net/mcreator/customoregen/procedures/OreDropMath.java
+++ b/src/main/java/net/mcreator/customoregen/procedures/OreDropMath.java
@@ -1,18 +1,24 @@
package net.mcreator.customoregen.procedures;
-import java.util.Random;
-
/**
* Pure (Minecraft-free) ore drop math, extracted from {@link ConfigurableOreDropsProcedure}
* so it can be unit-tested without a game server. The procedure delegates the drop-count and
* experience calculations here, which mirrors vanilla 1.21 behaviour for the multi-drop ores
* (Lapis, Copper, Redstone) vs the discrete ores (Diamond, Coal, Emerald).
*
- *
All methods are deterministic given the {@link Random} argument, so tests can pin exact
- * outputs with a seeded {@code Random}.
+ * All methods draw randomness through {@link IntRandom}, so they accept both
+ * {@code new Random(seed)::nextInt} (deterministic unit tests) and
+ * {@code lootContext.getRandom()::nextInt} (world-seeded Minecraft {@code RandomSource}).
*/
public final class OreDropMath {
+ /** Minimal random source abstraction: compatible with both {@link java.util.Random} and
+ * Minecraft's {@code RandomSource} via a {@code ::nextInt} method reference. */
+ @FunctionalInterface
+ public interface IntRandom {
+ int nextInt(int bound);
+ }
+
private OreDropMath() {}
/**
@@ -29,7 +35,7 @@ public final class OreDropMath {
* {@code minDrops + random.nextInt(maxDrops - minDrops + 1)} when {@code maxDrops > minDrops},
* else {@code minDrops} (no-op random draw when the range is a single value).
*/
- public static int baseDropCount(int minDrops, int maxDrops, Random random) {
+ public static int baseDropCount(int minDrops, int maxDrops, IntRandom random) {
if (maxDrops > minDrops) {
return minDrops + random.nextInt(maxDrops - minDrops + 1);
}
@@ -49,7 +55,7 @@ public final class OreDropMath {
* (and no random draw is consumed, matching the procedure guard).
*/
public static int applyFortune(String oreType, int baseCount, boolean enableFortune,
- int fortuneLevel, Random random) {
+ int fortuneLevel, IntRandom random) {
if (!enableFortune || fortuneLevel <= 0) {
return baseCount;
}
@@ -69,7 +75,7 @@ public final class OreDropMath {
* single fortune draw).
*/
public static int dropCount(String oreType, int minDrops, int maxDrops,
- boolean enableFortune, int fortuneLevel, Random random) {
+ boolean enableFortune, int fortuneLevel, IntRandom random) {
int base = baseDropCount(minDrops, maxDrops, random);
return applyFortune(oreType, base, enableFortune, fortuneLevel, random);
}
@@ -80,7 +86,7 @@ public final class OreDropMath {
*
* @return XP amount in {@code [0, max]} for the ore type, or 0 if the type does not drop XP
*/
- public static int experienceFor(String oreType, Random random) {
+ public static int experienceFor(String oreType, IntRandom random) {
switch (oreType) {
case "concentrated_coal":
return random.nextInt(3); // 0-2
diff --git a/src/main/java/net/mcreator/customoregen/worldgen/OreZoneCatalog.java b/src/main/java/net/mcreator/customoregen/worldgen/OreZoneCatalog.java
new file mode 100644
index 00000000..cf0831e0
--- /dev/null
+++ b/src/main/java/net/mcreator/customoregen/worldgen/OreZoneCatalog.java
@@ -0,0 +1,86 @@
+package net.mcreator.customoregen.worldgen;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import net.minecraft.ChatFormatting;
+import net.minecraft.network.chat.Component;
+
+/**
+ * Shared "which ores generate at this Z" report, used by both the {@code /ores} command
+ * and the Ore Biome Finder item (previously copy-pasted in both classes).
+ *
+ * Each caller decides how to deliver the lines (command feedback vs client chat).
+ */
+public final class OreZoneCatalog {
+
+ private static final List COLD_ORES = List.of(
+ "Lapis (stone) [Y: 0 a 32]",
+ "Lapis (deepslate) [Y: -64 a 0]",
+ "Diamant (deepslate) [Y: -64 a 0]");
+
+ private static final List HOT_ORES = List.of(
+ "Or (stone) [Y: 0 a 320]",
+ "Or (deepslate) [Y: -64 a 0]",
+ "Cuivre (haut) [Y: 15 a 320]",
+ "Cuivre (bas) [Y: -64 a 0]",
+ "Redstone (stone) [Y: -10 a 20]",
+ "Redstone (deepslate) [Y: -80 a -30]");
+
+ private static final List TEMPERATE_ORES = List.of(
+ "Fer (stone) [Y: 0 a 100]",
+ "Fer (deepslate) [Y: -64 a 0]",
+ "Charbon concentre [Y: 0 a 70]");
+
+ private static final List EVERYWHERE_ORES = List.of(
+ "Diamant Shard (deepslate) [Y: -64 a -40]",
+ "Bloc Diamant Shard [Y: 0 a 15]");
+
+ private OreZoneCatalog() {}
+
+ /** Ores specific to the given zone ("COLD", "HOT" or "TEMPERATE"). */
+ public static List oresForZone(String zone) {
+ return switch (zone) {
+ case "COLD" -> COLD_ORES;
+ case "HOT" -> HOT_ORES;
+ default -> TEMPERATE_ORES;
+ };
+ }
+
+ /** Color associated with a zone for chat output. */
+ public static ChatFormatting zoneColor(String zone) {
+ return switch (zone) {
+ case "COLD" -> ChatFormatting.AQUA;
+ case "HOT" -> ChatFormatting.GOLD;
+ case "TEMPERATE" -> ChatFormatting.GREEN;
+ default -> ChatFormatting.WHITE;
+ };
+ }
+
+ /**
+ * Builds the full zone report (position, zone, thresholds, ore list) as chat components,
+ * one per line.
+ */
+ public static List buildZoneReport(int x, int z) {
+ String zone = LatitudeConfig.zoneName(z);
+ int coldZ = LatitudeConfig.getColdZoneZ();
+ int hotZ = LatitudeConfig.getHotZoneZ();
+ ChatFormatting zoneColor = zoneColor(zone);
+ List zoneOres = oresForZone(zone);
+
+ List lines = new ArrayList<>();
+ lines.add(Component.literal("=== Position: X=" + x + " Z=" + z + " ===").withStyle(ChatFormatting.GRAY));
+ lines.add(Component.literal("Zone determinee par la coordonnee Z : " + zone).withStyle(zoneColor));
+ lines.add(Component.literal("Z < " + coldZ + " = froid | " + coldZ + " a " + hotZ + " = tempere | Z > " + hotZ + " = chaud")
+ .withStyle(ChatFormatting.GRAY));
+ lines.add(Component.literal("Minerais trouvables (" + (zoneOres.size() + EVERYWHERE_ORES.size()) + ") :")
+ .withStyle(ChatFormatting.WHITE));
+ for (String ore : zoneOres) {
+ lines.add(Component.literal(" * " + ore).withStyle(zoneColor));
+ }
+ for (String ore : EVERYWHERE_ORES) {
+ lines.add(Component.literal(" * " + ore).withStyle(ChatFormatting.LIGHT_PURPLE));
+ }
+ return lines;
+ }
+}
diff --git a/src/test/java/net/mcreator/customoregen/procedures/OreDropMathTest.java b/src/test/java/net/mcreator/customoregen/procedures/OreDropMathTest.java
index cc5115c2..491925d3 100644
--- a/src/test/java/net/mcreator/customoregen/procedures/OreDropMathTest.java
+++ b/src/test/java/net/mcreator/customoregen/procedures/OreDropMathTest.java
@@ -52,7 +52,7 @@ class OreDropMathTest {
void baseDropCount_range() {
Random rng = new Random(42L);
for (int i = 0; i < 10_000; i++) {
- int c = OreDropMath.baseDropCount(2, 5, rng);
+ int c = OreDropMath.baseDropCount(2, 5, rng::nextInt);
assertTrue(c >= 2 && c <= 5, "out of [2,5]: " + c);
}
}
@@ -64,7 +64,7 @@ class OreDropMathTest {
Random rng = new Random(7L);
boolean[] seen = new boolean[10];
for (int i = 0; i < 60_000; i++) {
- seen[OreDropMath.baseDropCount(4, 9, rng)] = true;
+ seen[OreDropMath.baseDropCount(4, 9, rng::nextInt)] = true;
}
for (int v = 4; v <= 9; v++) {
assertTrue(seen[v], "value " + v + " never appeared in [4,9] base draw");
@@ -79,7 +79,7 @@ class OreDropMathTest {
// Vanilla Emerald default: 1..1 -> always 1, and the random must NOT be consumed
// (so that the subsequent Fortune draw lands on the same sequence).
Random rngA = new Random(123L);
- int c = OreDropMath.baseDropCount(1, 1, rngA);
+ int c = OreDropMath.baseDropCount(1, 1, rngA::nextInt);
assertEquals(1, c);
// Verify no random draw happened: an identical RNG feeding dropCount()+fortune must
@@ -102,7 +102,7 @@ class OreDropMathTest {
// When Fortune is disabled, the RNG must not be consumed at all.
Random rngA = new Random(999L);
Random rngB = new Random(999L);
- int with = OreDropMath.applyFortune("shard_diamond", 3, false, 3, rngA);
+ int with = OreDropMath.applyFortune("shard_diamond", 3, false, 3, rngA::nextInt);
assertEquals(3, with);
assertEquals(rngB.nextInt(), rngA.nextInt(),
"disabled fortune must not consume a random draw");
@@ -113,7 +113,7 @@ class OreDropMathTest {
void applyFortune_zeroLevelIsNoOp() {
Random rngA = new Random(999L);
Random rngB = new Random(999L);
- int with = OreDropMath.applyFortune("shard_diamond", 3, true, 0, rngA);
+ int with = OreDropMath.applyFortune("shard_diamond", 3, true, 0, rngA::nextInt);
assertEquals(3, with);
assertEquals(rngB.nextInt(), rngA.nextInt(),
"fortune level 0 must not consume a random draw");
@@ -131,7 +131,7 @@ class OreDropMathTest {
Random rng = new Random(1L);
for (int i = 0; i < 5_000; i++) {
int base = 1 + rng.nextInt(8);
- int with = OreDropMath.applyFortune(t, base, true, fortune, rng);
+ int with = OreDropMath.applyFortune(t, base, true, fortune, rng::nextInt);
assertTrue(with >= base,
t + " fortune=" + fortune + " base=" + base + " -> " + with + " < base");
assertTrue(with >= 0, t + " fortune result negative: " + with);
@@ -154,7 +154,7 @@ class OreDropMathTest {
Random rng = new Random(t.hashCode() + fortune);
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for (int i = 0; i < 20_000; i++) {
- int with = OreDropMath.applyFortune(t, 1, true, fortune, rng);
+ int with = OreDropMath.applyFortune(t, 1, true, fortune, rng::nextInt);
// base=1, so 'with' equals 1 + bonus in [1, 1+fortune]
assertTrue(with >= 1 && with <= 1 + fortune,
t + " fortune=" + fortune + " with=" + with + " outside [1," + (1 + fortune) + "]");
@@ -176,7 +176,7 @@ class OreDropMathTest {
int[] counts = new int[5]; // index 0..4
int n = 200_000;
for (int i = 0; i < n; i++) {
- counts[OreDropMath.applyFortune("shard_diamond", 1, true, 3, rng)]++;
+ counts[OreDropMath.applyFortune("shard_diamond", 1, true, 3, rng::nextInt)]++;
}
// Allow generous tolerance ±5% for RNG noise.
assertRatio("discrete fortune III base=1 -> outcome 1 (+0)", counts[1] / (double) n, 0.40, 0.05);
@@ -201,7 +201,7 @@ class OreDropMathTest {
Random rng = new Random(t.hashCode() + fortune * 7);
for (int i = 0; i < 10_000; i++) {
int base = 4; // vanilla lapis-ish
- int with = OreDropMath.applyFortune(t, base, true, fortune, rng);
+ int with = OreDropMath.applyFortune(t, base, true, fortune, rng::nextInt);
assertTrue(with % base == 0,
t + " multiplier result " + with + " is not a multiple of base " + base);
assertTrue(with >= base && with <= base * (fortune + 1),
@@ -220,7 +220,7 @@ class OreDropMathTest {
int[] counts = new int[8];
int n = 200_000;
for (int i = 0; i < n; i++) {
- counts[OreDropMath.applyFortune("lapis", 1, true, 3, rng)]++;
+ counts[OreDropMath.applyFortune("lapis", 1, true, 3, rng::nextInt)]++;
}
assertRatio("lapis multiplier fortune III -> result 1 (x1)", counts[1] / (double) n, 0.40, 0.05);
assertRatio("lapis multiplier fortune III -> result 2 (x2)", counts[2] / (double) n, 0.20, 0.05);
@@ -239,11 +239,11 @@ class OreDropMathTest {
// SAME continuation of the RNG. This guards against subtle behaviour drift if a refactor
// reorders the random draws.
Random rngA = new Random(55L);
- int base = OreDropMath.baseDropCount(4, 9, rngA);
- int fortune = OreDropMath.applyFortune("lapis", base, true, 3, rngA);
+ int base = OreDropMath.baseDropCount(4, 9, rngA::nextInt);
+ int fortune = OreDropMath.applyFortune("lapis", base, true, 3, rngA::nextInt);
Random rngB = new Random(55L);
- int combined = OreDropMath.dropCount("lapis", 4, 9, true, 3, rngB);
+ int combined = OreDropMath.dropCount("lapis", 4, 9, true, 3, rngB::nextInt);
assertEquals(fortune, combined, "dropCount must be base+fortune in order");
}
@@ -256,12 +256,12 @@ class OreDropMathTest {
@DisplayName("XP: iron/gold/copper/unknown drop 0 raw XP")
void experienceFor_zeroXpTypes() {
Random rng = new Random(1L);
- assertEquals(0, OreDropMath.experienceFor("impure_iron", rng));
- assertEquals(0, OreDropMath.experienceFor("impure_gold", rng));
- assertEquals(0, OreDropMath.experienceFor("pure_golden", rng));
- assertEquals(0, OreDropMath.experienceFor("copper", rng));
- assertEquals(0, OreDropMath.experienceFor("unknown", rng));
- assertEquals(0, OreDropMath.experienceFor("", rng));
+ assertEquals(0, OreDropMath.experienceFor("impure_iron", rng::nextInt));
+ assertEquals(0, OreDropMath.experienceFor("impure_gold", rng::nextInt));
+ assertEquals(0, OreDropMath.experienceFor("pure_golden", rng::nextInt));
+ assertEquals(0, OreDropMath.experienceFor("copper", rng::nextInt));
+ assertEquals(0, OreDropMath.experienceFor("unknown", rng::nextInt));
+ assertEquals(0, OreDropMath.experienceFor("", rng::nextInt));
}
@Test
@@ -270,24 +270,24 @@ class OreDropMathTest {
Random rng = new Random(2L);
// coal: 0-2
for (int i = 0; i < 5_000; i++) {
- int xp = OreDropMath.experienceFor("concentrated_coal", rng);
+ int xp = OreDropMath.experienceFor("concentrated_coal", rng::nextInt);
assertTrue(xp >= 0 && xp <= 2, "coal XP " + xp + " out of [0,2]");
}
// diamond/emerald/shard: 3-7
for (String t : new String[]{"shard_diamond", "concentrated_diamond", "emerald"}) {
for (int i = 0; i < 5_000; i++) {
- int xp = OreDropMath.experienceFor(t, rng);
+ int xp = OreDropMath.experienceFor(t, rng::nextInt);
assertTrue(xp >= 3 && xp <= 7, t + " XP " + xp + " out of [3,7]");
}
}
// lapis: 2-5
for (int i = 0; i < 5_000; i++) {
- int xp = OreDropMath.experienceFor("lapis", rng);
+ int xp = OreDropMath.experienceFor("lapis", rng::nextInt);
assertTrue(xp >= 2 && xp <= 5, "lapis XP " + xp + " out of [2,5]");
}
// redstone: 1-5
for (int i = 0; i < 5_000; i++) {
- int xp = OreDropMath.experienceFor("redstone", rng);
+ int xp = OreDropMath.experienceFor("redstone", rng::nextInt);
assertTrue(xp >= 1 && xp <= 5, "redstone XP " + xp + " out of [1,5]");
}
}
@@ -300,9 +300,9 @@ class OreDropMathTest {
boolean[] redstoneSeen = new boolean[6]; // 1..5
boolean[] diamondSeen = new boolean[8]; // 3..7
for (int i = 0; i < 100_000; i++) {
- coalSeen[OreDropMath.experienceFor("concentrated_coal", rng)] = true;
- redstoneSeen[OreDropMath.experienceFor("redstone", rng)] = true;
- diamondSeen[OreDropMath.experienceFor("emerald", rng)] = true;
+ coalSeen[OreDropMath.experienceFor("concentrated_coal", rng::nextInt)] = true;
+ redstoneSeen[OreDropMath.experienceFor("redstone", rng::nextInt)] = true;
+ diamondSeen[OreDropMath.experienceFor("emerald", rng::nextInt)] = true;
}
for (int v = 0; v <= 2; v++) assertTrue(coalSeen[v], "coal XP " + v + " never observed");
for (int v = 1; v <= 5; v++) assertTrue(redstoneSeen[v], "redstone XP " + v + " never observed");
@@ -321,11 +321,11 @@ class OreDropMathTest {
Random rngA = new Random(0xC0FFEE);
Random rngB = new Random(0xC0FFEE);
for (String t : oreTypes) {
- int da = OreDropMath.dropCount(t, 2, 5, true, 3, rngA);
- int db = OreDropMath.dropCount(t, 2, 5, true, 3, rngB);
+ int da = OreDropMath.dropCount(t, 2, 5, true, 3, rngA::nextInt);
+ int db = OreDropMath.dropCount(t, 2, 5, true, 3, rngB::nextInt);
assertEquals(da, db, t + " dropCount diverged with same seed");
- int xa = OreDropMath.experienceFor(t, rngA);
- int xb = OreDropMath.experienceFor(t, rngB);
+ int xa = OreDropMath.experienceFor(t, rngA::nextInt);
+ int xb = OreDropMath.experienceFor(t, rngB::nextInt);
assertEquals(xa, xb, t + " XP diverged with same seed");
}
}
diff --git a/src/test/java/net/mcreator/customoregen/worldgen/OreZoneCatalogTest.java b/src/test/java/net/mcreator/customoregen/worldgen/OreZoneCatalogTest.java
new file mode 100644
index 00000000..d5f5d436
--- /dev/null
+++ b/src/test/java/net/mcreator/customoregen/worldgen/OreZoneCatalogTest.java
@@ -0,0 +1,72 @@
+package net.mcreator.customoregen.worldgen;
+
+import net.minecraft.network.chat.Component;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Tests for the shared zone report used by the /ores command and the Ore Biome Finder item.
+ *
+ * Note: the default config thresholds (cold: Z < -8000, hot: Z > 8000) apply because
+ * the config is not loaded in unit tests (LatitudeConfig falls back to its defaults).
+ */
+@DisplayName("OreZoneCatalog Tests")
+class OreZoneCatalogTest {
+
+ private static String reportText(int x, int z) {
+ List report = OreZoneCatalog.buildZoneReport(x, z);
+ StringBuilder sb = new StringBuilder();
+ for (Component line : report) {
+ sb.append(line.getString()).append('\n');
+ }
+ return sb.toString();
+ }
+
+ @Test
+ @DisplayName("Cold zone report lists cold ores plus shard ores")
+ void testReport_ColdZone() {
+ String report = reportText(100, -10000);
+ assertTrue(report.contains("COLD"), "should name the COLD zone");
+ assertTrue(report.contains("Lapis"), "cold zone should list lapis");
+ assertTrue(report.contains("Diamant Shard"), "everywhere ores should always be listed");
+ assertFalse(report.contains("Cuivre"), "cold zone should not list hot ores");
+ // 3 cold ores + 2 everywhere ores
+ assertTrue(report.contains("Minerais trouvables (5)"), "should count 3 zone ores + 2 everywhere ores");
+ }
+
+ @Test
+ @DisplayName("Hot zone report lists hot ores plus shard ores")
+ void testReport_HotZone() {
+ String report = reportText(0, 20000);
+ assertTrue(report.contains("HOT"), "should name the HOT zone");
+ assertTrue(report.contains("Cuivre"), "hot zone should list copper");
+ assertTrue(report.contains("Redstone"), "hot zone should list redstone");
+ // 6 hot ores + 2 everywhere ores
+ assertTrue(report.contains("Minerais trouvables (8)"), "should count 6 zone ores + 2 everywhere ores");
+ }
+
+ @Test
+ @DisplayName("Temperate zone report lists temperate ores plus shard ores")
+ void testReport_TemperateZone() {
+ String report = reportText(-50, 0);
+ assertTrue(report.contains("TEMPERATE"), "should name the TEMPERATE zone");
+ assertTrue(report.contains("Fer"), "temperate zone should list iron");
+ assertFalse(report.contains("Lapis"), "temperate zone should not list cold ores");
+ // 3 temperate ores + 2 everywhere ores
+ assertTrue(report.contains("Minerais trouvables (5)"), "should count 3 zone ores + 2 everywhere ores");
+ }
+
+ @Test
+ @DisplayName("Report includes position and zone thresholds")
+ void testReport_ContainsPositionAndThresholds() {
+ String report = reportText(123, -456);
+ assertTrue(report.contains("X=123"), "should show the X coordinate");
+ assertTrue(report.contains("Z=-456"), "should show the Z coordinate");
+ assertTrue(report.contains("-8000"), "should show the cold threshold");
+ assertTrue(report.contains("8000"), "should show the hot threshold");
+ }
+}