fix: corrections complètes + version 4.5

- Enregistre la config Forge (registerConfig) : bug bloquant, la config n'était jamais chargée
- Worldgen latitude: résolution des biomes via le registre du serveur (ServerLifecycleHooks)
  car ForgeRegistries.BIOMES est vide sur les threads de génération (crash IndexOutOfBounds)
- Filets de sécurité anti-crash dans LatitudeBiomeSource (select/fallback), collectPossibleBiomes paresseux
- Câble la config worldgen (temperatureBandWidth, biomeSize, enableBOP/Oceans, spawnSearchRadius, welcome)
- OreexperienceProcedure: supprime la double casse, XP depuis la config
- Handlers spawn/welcome par joueur (suppression des static boolean)
- Outils Shard Diamond câblés sur la config (durabilité/vitesse) via ConfigHelper rendu sûr
- Supprime le code mort (ConfigurableOreDropsProcedure, helpers inutilisés, config non câblable)
- Corrige le nom 'Custom Ore Gem' -> 'Custom Ore Gen'
This commit is contained in:
2026-07-31 20:11:27 +00:00
parent ee1b203a7f
commit d84f1ecafc
14 changed files with 168 additions and 231 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ plugins {
id 'net.minecraftforge.gradle' version '[6.0.16,6.2)'
}
version = '2.2.0'
version = '4.5'
group = 'com.aulyrius.custom_ore_gen'
archivesBaseName = 'custom_ore_gen'
@@ -8,6 +8,8 @@ import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.fml.util.thread.SidedThreadGroups;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.eventbus.api.IEventBus;
@@ -20,6 +22,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.mcreator.customoregen.init.CustomOreGenModTabs;
import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.init.CustomOreGenModBlocks;
import net.mcreator.customoregen.config.ModConfigs;
import net.mcreator.customoregen.worldgen.WorldGenRegistration;
import java.util.function.Supplier;
@@ -42,6 +45,9 @@ public class CustomOreGenMod {
MinecraftForge.EVENT_BUS.register(this);
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
// Enregistre la configuration COMMON (crée/charge custom_ore_gen.toml)
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.SPEC, "custom_ore_gen.toml");
CustomOreGenModBlocks.REGISTRY.register(bus);
CustomOreGenModItems.REGISTRY.register(bus);
@@ -1,35 +1,22 @@
package net.mcreator.customoregen.config;
import net.minecraftforge.fml.ModList;
/**
* Accès sûr aux valeurs de configuration du mod.
* <p>
* Chaque méthode retourne une valeur par défaut si la configuration n'est pas
* encore chargée (par ex. pendant la construction des objets enregistrés),
* évitant ainsi tout plantage lié à un accès prématuré au {@code ForgeConfigSpec}.
*/
public class ConfigHelper {
// Helper method to safely access config values
public static boolean isFeatureEnabled(String featureName) {
switch (featureName) {
case "shardDiamondTools":
return ModConfigs.FEATURES.enableShardDiamondTools.get();
case "shardDiamondOre":
return ModConfigs.FEATURES.enableShardDiamondOre.get();
case "concentratedOres":
return ModConfigs.FEATURES.enableConcentratedOres.get();
case "impureOres":
return ModConfigs.FEATURES.enableImpureOres.get();
case "ashCoalOre":
return ModConfigs.FEATURES.enableAshCoalOre.get();
case "pureGoldenOre":
return ModConfigs.FEATURES.enablePureGoldenOre.get();
case "customEmeraldOres":
return ModConfigs.FEATURES.enableCustomEmeraldOres.get();
case "customCopperOres":
return ModConfigs.FEATURES.enableCustomCopperOres.get();
case "vanillaOreVariants":
return ModConfigs.FEATURES.enableVanillaOreVariants.get();
default:
return true;
}
private static boolean loaded() {
return ModConfigs.SPEC.isLoaded();
}
/** Durabilité de l'outil Shard Diamond concerné (par défaut 200). */
public static int getShardDiamondToolDurability(String toolType) {
if (!loaded())
return 200;
switch (toolType) {
case "pickaxe":
return ModConfigs.TOOL_STATS.shardDiamondPickaxeDurability.get();
@@ -42,7 +29,10 @@ public class ConfigHelper {
}
}
/** Vitesse de minage de l'outil Shard Diamond concerné. */
public static float getShardDiamondToolSpeed(String toolType) {
if (!loaded())
return defaultSpeed(toolType);
switch (toolType) {
case "pickaxe":
return ModConfigs.TOOL_STATS.shardDiamondPickaxeSpeed.get().floatValue();
@@ -55,16 +45,7 @@ public class ConfigHelper {
}
}
public static int getShardDiamondToolDamage(String toolType) {
switch (toolType) {
case "pickaxe":
return ModConfigs.TOOL_STATS.shardDiamondPickaxeAttackDamage.get();
case "axe":
return ModConfigs.TOOL_STATS.shardDiamondAxeAttackDamage.get();
case "shovel":
return ModConfigs.TOOL_STATS.shardDiamondShovelAttackDamage.get();
default:
return 1;
}
private static float defaultSpeed(String toolType) {
return "shovel".equals(toolType) ? 4.0f : 7.0f;
}
}
@@ -13,7 +13,7 @@ public class ModConfigs {
public static final WorldGenConfig WORLD_GEN;
static {
BUILDER.push("Custom Ore Gem Configuration");
BUILDER.push("Custom Ore Gen Configuration");
ORE_GEN = new OreGenConfig(BUILDER);
TOOL_STATS = new ToolStatsConfig(BUILDER);
@@ -130,15 +130,12 @@ public class ModConfigs {
public static class ToolStatsConfig {
public final ForgeConfigSpec.ConfigValue<Integer> shardDiamondPickaxeDurability;
public final ForgeConfigSpec.DoubleValue shardDiamondPickaxeSpeed;
public final ForgeConfigSpec.ConfigValue<Integer> shardDiamondPickaxeAttackDamage;
public final ForgeConfigSpec.ConfigValue<Integer> shardDiamondAxeDurability;
public final ForgeConfigSpec.DoubleValue shardDiamondAxeSpeed;
public final ForgeConfigSpec.ConfigValue<Integer> shardDiamondAxeAttackDamage;
public final ForgeConfigSpec.ConfigValue<Integer> shardDiamondShovelDurability;
public final ForgeConfigSpec.DoubleValue shardDiamondShovelSpeed;
public final ForgeConfigSpec.ConfigValue<Integer> shardDiamondShovelAttackDamage;
public ToolStatsConfig(ForgeConfigSpec.Builder builder) {
builder.push("tool_stats");
@@ -150,9 +147,6 @@ public class ModConfigs {
shardDiamondPickaxeSpeed = builder
.comment("Mining speed of Shard Diamond Pickaxe (default: 7.0)")
.defineInRange("pickaxeSpeed", 7.0, 0.1, 20.0);
shardDiamondPickaxeAttackDamage = builder
.comment("Attack damage of Shard Diamond Pickaxe (default: 1)")
.defineInRange("pickaxeAttackDamage", 1, 0, 20);
shardDiamondAxeDurability = builder
.comment("Durability of Shard Diamond Axe (default: 200)")
@@ -160,9 +154,6 @@ public class ModConfigs {
shardDiamondAxeSpeed = builder
.comment("Mining speed of Shard Diamond Axe (default: 7.0)")
.defineInRange("axeSpeed", 7.0, 0.1, 20.0);
shardDiamondAxeAttackDamage = builder
.comment("Attack damage of Shard Diamond Axe (default: 6)")
.defineInRange("axeAttackDamage", 6, 0, 20);
shardDiamondShovelDurability = builder
.comment("Durability of Shard Diamond Shovel (default: 200)")
@@ -170,9 +161,6 @@ public class ModConfigs {
shardDiamondShovelSpeed = builder
.comment("Mining speed of Shard Diamond Shovel (default: 4.0)")
.defineInRange("shovelSpeed", 4.0, 0.1, 20.0);
shardDiamondShovelAttackDamage = builder
.comment("Attack damage of Shard Diamond Shovel (default: 2)")
.defineInRange("shovelAttackDamage", 2, 0, 20);
builder.pop();
builder.pop();
@@ -333,7 +321,6 @@ public class ModConfigs {
public static class WorldGenConfig {
public final ForgeConfigSpec.ConfigValue<Integer> biomeSize;
public final ForgeConfigSpec.ConfigValue<Integer> temperatureBandWidth;
public final ForgeConfigSpec.DoubleValue mountainHeightMultiplier;
public final ForgeConfigSpec.ConfigValue<Boolean> enableBOPBiomes;
public final ForgeConfigSpec.ConfigValue<Boolean> enableOceans;
public final ForgeConfigSpec.ConfigValue<Boolean> enableWelcomeMessage;
@@ -348,9 +335,6 @@ public class ModConfigs {
temperatureBandWidth = builder
.comment("Width of each temperature band in blocks (default: 4000)")
.defineInRange("temperatureBandWidth", 4000, 1000, 50000);
mountainHeightMultiplier = builder
.comment("Multiplier for mountain terrain height (1.0 = vanilla, default: 1.5)")
.defineInRange("mountainHeightMultiplier", 1.5, 1.0, 3.0);
enableBOPBiomes = builder
.comment("Include Biomes O' Plenty biomes in temperature bands (default: true)")
.define("enableBOPBiomes", true);
@@ -7,16 +7,17 @@ import net.minecraft.world.item.AxeItem;
import net.minecraft.world.item.ItemStack;
import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ConfigHelper;
public class SharddiamondaxeItem extends AxeItem {
public SharddiamondaxeItem() {
super(new Tier() {
public int getUses() {
return 200;
return ConfigHelper.getShardDiamondToolDurability("axe");
}
public float getSpeed() {
return 7f;
return ConfigHelper.getShardDiamondToolSpeed("axe");
}
public float getAttackDamageBonus() {
@@ -8,16 +8,17 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item;
import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ConfigHelper;
public class SharddiamondpickaxeItem extends PickaxeItem {
public SharddiamondpickaxeItem() {
super(new Tier() {
public int getUses() {
return 200; // Hardcoded - config not loaded yet
return ConfigHelper.getShardDiamondToolDurability("pickaxe");
}
public float getSpeed() {
return 7f;
return ConfigHelper.getShardDiamondToolSpeed("pickaxe");
}
public float getAttackDamageBonus() {
@@ -8,16 +8,17 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Item;
import net.mcreator.customoregen.init.CustomOreGenModItems;
import net.mcreator.customoregen.config.ConfigHelper;
public class SharddiamondshovelItem extends ShovelItem {
public SharddiamondshovelItem() {
super(new Tier() {
public int getUses() {
return 200;
return ConfigHelper.getShardDiamondToolDurability("shovel");
}
public float getSpeed() {
return 4f;
return ConfigHelper.getShardDiamondToolSpeed("shovel");
}
public float getAttackDamageBonus() {
@@ -1,143 +0,0 @@
package net.mcreator.customoregen.procedures;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.ExperienceOrb;
import net.mcreator.customoregen.config.ModConfigs;
import net.mcreator.customoregen.init.CustomOreGenModItems;
import java.util.Random;
public class ConfigurableOreDropsProcedure {
public static void execute(LevelAccessor world, double x, double y, double z, Entity entity, String oreType) {
if (world.isClientSide())
return;
Random random = new Random();
int fortuneLevel = 0;
boolean silkTouch = false;
// Get fortune and silk touch from the tool if mining by player
if (entity instanceof Player) {
Player player = (Player) entity;
ItemStack mainHandItem = player.getMainHandItem();
fortuneLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, mainHandItem);
silkTouch = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, mainHandItem) > 0;
}
// If silk touch, drop the block itself and return
if (silkTouch) {
return; // Let vanilla handle silk touch
}
int minDrops = 1;
int maxDrops = 2;
boolean enableFortune = true;
ItemStack dropItem = ItemStack.EMPTY;
// Configure drops based on ore type
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();
dropItem = new ItemStack(Items.COAL);
break;
case "pure_golden":
minDrops = ModConfigs.DROPS.pureGoldenOreMinDrops.get();
maxDrops = ModConfigs.DROPS.pureGoldenOreMaxDrops.get();
dropItem = new ItemStack(Items.GOLD_NUGGET);
break;
case "ash_coal":
minDrops = ModConfigs.DROPS.ashCoalOreMinDrops.get();
maxDrops = ModConfigs.DROPS.ashCoalOreMaxDrops.get();
dropItem = new ItemStack(Items.COAL); // Temporarily use coal until ASHCOAL item is created
break;
case "impure_iron":
minDrops = ModConfigs.DROPS.impureIronOreMinDrops.get();
maxDrops = ModConfigs.DROPS.impureIronOreMaxDrops.get();
dropItem = new ItemStack(Items.IRON_NUGGET); // Use iron nugget until IMPUREIRON item is created
break;
case "impure_gold":
minDrops = ModConfigs.DROPS.impureGoldOreMinDrops.get();
maxDrops = ModConfigs.DROPS.impureGoldOreMaxDrops.get();
dropItem = new ItemStack(Items.RAW_GOLD);
break;
default:
return;
}
// Calculate drops
int dropCount = minDrops + random.nextInt(maxDrops - minDrops + 1);
// Apply fortune if enabled
if (enableFortune && fortuneLevel > 0) {
int fortuneBonus = random.nextInt(fortuneLevel + 2) - 1;
if (fortuneBonus < 0)
fortuneBonus = 0;
dropCount += fortuneBonus;
}
// Drop the items
if (!dropItem.isEmpty() && dropCount > 0) {
dropItem.setCount(dropCount);
if (world instanceof ServerLevel) {
ItemEntity itemEntity = new ItemEntity(
(ServerLevel) world,
x + 0.5, y + 0.5, z + 0.5,
dropItem
);
itemEntity.setDefaultPickUpDelay();
((ServerLevel) world).addFreshEntity(itemEntity);
}
}
// Drop experience if configured
int expAmount = ModConfigs.DROPS.oreExperienceDrops.get();
if (expAmount > 0 && entity instanceof Player) {
ExperienceOrb expOrb = new ExperienceOrb(
(ServerLevel) world,
x + 0.5, y + 0.5, z + 0.5,
expAmount
);
((ServerLevel) world).addFreshEntity(expOrb);
}
}
}
@@ -8,16 +8,36 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.Entity;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.core.BlockPos;
import net.mcreator.customoregen.config.ModConfigs;
public class OreexperienceProcedure {
/**
* Ajoute de l'expérience lors de la casse d'un minerai personnalisé.
* <p>
* Ne recasse PAS le bloc : le bloc est déjà détruit par
* {@code onDestroyedByPlayer} (qui appelle {@code super} et génère les
* drops via la loot table). Cette procédure se contente d'ajouter l'orbe
* d'XP, en respectant Silk Touch et la valeur de configuration.
*/
public static void execute(LevelAccessor world, double x, double y, double z, Entity entity) {
// Uniquement côté serveur : l'XP ne doit pas être spawnée côté client.
if (world.isClientSide())
return;
if (entity == null)
return;
if (!(EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, (entity instanceof LivingEntity _livEnt ? _livEnt.getMainHandItem() : ItemStack.EMPTY)) != 0)) {
world.destroyBlock(BlockPos.containing(x, y, z), false);
if (world instanceof ServerLevel _level)
_level.addFreshEntity(new ExperienceOrb(_level, x, y, z, 2));
}
// Pas d'XP si l'outil est enchanté Silk Touch (comportement vanilla).
ItemStack mainHand = (entity instanceof LivingEntity living) ? living.getMainHandItem() : ItemStack.EMPTY;
boolean silkTouch = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, mainHand) > 0;
if (silkTouch)
return;
int amount = ModConfigs.SPEC.isLoaded() ? ModConfigs.DROPS.oreExperienceDrops.get() : 2;
if (amount <= 0)
return;
if (world instanceof ServerLevel level)
level.addFreshEntity(new ExperienceOrb(level, x + 0.5, y + 0.5, z + 0.5, amount));
}
}
@@ -1,12 +1,16 @@
package net.mcreator.customoregen.worldgen;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.server.ServerLifecycleHooks;
import net.mcreator.customoregen.config.ModConfigs;
import java.util.ArrayList;
import java.util.List;
@@ -129,6 +133,8 @@ public enum BiomeBand {
}
private static void addBOP(List<ResourceKey<Biome>> list, String... ids) {
// Respecte le toggle de configuration enableBOPBiomes (true par défaut).
if (!bopEnabled()) return;
for (String id : ids) {
ResourceKey<Biome> key = ResourceKey.create(Registries.BIOME,
new ResourceLocation("biomesoplenty", id));
@@ -141,11 +147,50 @@ public enum BiomeBand {
private static List<Holder<Biome>> resolveHolders(List<ResourceKey<Biome>> keys) {
List<Holder<Biome>> holders = new ArrayList<>();
for (ResourceKey<Biome> key : keys) {
ForgeRegistries.BIOMES.getHolder(key).ifPresent(holders::add);
Holder<Biome> holder = resolveOne(key);
if (holder != null)
holders.add(holder);
}
return holders;
}
/**
* Résout un holder de biome de façon robuste :
* 1) registre vanilla {@link BuiltInRegistries} (toujours peuplé pour les
* biomes vanilla, fiable pendant la génération du monde) ;
* 2) registre Forge (biomes ajoutés par d'autres mods, ex. Biomes O' Plenty).
*/
/**
* Résout un holder de biome de façon robuste.
* <p>
* Pendant la génération du monde, {@code ForgeRegistries.BIOMES} peut être
* vide (notamment sur les threads de génération asynchrone). On passe donc
* d'abord par le registre de biomes du serveur — celui-là même qu'utilise la
* worldgen — avant de retomber sur le registre Forge (biomes de mods).
*/
private static Holder<Biome> resolveOne(ResourceKey<Biome> key) {
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
if (server != null) {
Registry<Biome> reg = server.registryAccess().registryOrThrow(Registries.BIOME);
Holder<Biome> holder = reg.getHolder(key).orElse(null);
if (holder != null)
return holder;
}
Holder<Biome> holder = ForgeRegistries.BIOMES.getHolder(key).orElse(null);
if (holder != null)
return holder;
return ForgeRegistries.BIOMES.getHolder(key.location()).orElse(null);
}
/** Holder de secours (plaine), résolu via le registre du serveur. */
private static Holder<Biome> fallbackHolder;
public static Holder<Biome> fallback() {
if (fallbackHolder == null)
fallbackHolder = resolveOne(Biomes.PLAINS);
return fallbackHolder;
}
public static List<Holder<Biome>> allPossible() {
List<Holder<Biome>> all = new ArrayList<>();
for (BiomeBand band : values()) {
@@ -159,8 +204,10 @@ public enum BiomeBand {
}
public static double getTemperatureAtZ(int blockZ, net.minecraft.world.level.levelgen.synth.ImprovedNoise noise) {
double raw = blockZ / 4000.0;
double noiseVal = noise.noise(blockZ * 0.00033, 0, 0) * 0.8;
// La largeur de bande est configurable (par défaut 4000 blocs).
double bandWidth = bandWidth();
double raw = blockZ / bandWidth;
double noiseVal = noise.noise(blockZ * (1.32 / bandWidth), 0, 0) * 0.8;
return Math.max(-3.0, Math.min(3.0, raw + noiseVal));
}
@@ -179,4 +226,14 @@ public enum BiomeBand {
idx = Math.max(0, Math.min(values().length - 1, idx));
return values()[idx];
}
// --- Accès sûrs à la configuration (valeurs par défaut si non chargée) ---
private static int bandWidth() {
return ModConfigs.SPEC.isLoaded() ? ModConfigs.WORLD_GEN.temperatureBandWidth.get() : 4000;
}
private static boolean bopEnabled() {
return !ModConfigs.SPEC.isLoaded() || ModConfigs.WORLD_GEN.enableBOPBiomes.get();
}
}
@@ -9,6 +9,7 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.levelgen.synth.ImprovedNoise;
import net.mcreator.customoregen.config.ModConfigs;
import java.util.List;
import java.util.stream.Stream;
@@ -27,7 +28,6 @@ public class LatitudeBiomeSource extends BiomeSource {
private final ImprovedNoise moistureNoise;
private final ImprovedNoise oceanNoise;
private final ImprovedNoise biomeSelectorNoise;
private final List<Holder<Biome>> possibleBiomes;
public LatitudeBiomeSource(long seed) {
this.seed = seed;
@@ -36,7 +36,6 @@ public class LatitudeBiomeSource extends BiomeSource {
this.moistureNoise = new ImprovedNoise(rng);
this.oceanNoise = new ImprovedNoise(rng);
this.biomeSelectorNoise = new ImprovedNoise(rng);
this.possibleBiomes = BiomeBand.allPossible();
}
@Override
@@ -46,7 +45,9 @@ public class LatitudeBiomeSource extends BiomeSource {
@Override
protected Stream<Holder<Biome>> collectPossibleBiomes() {
return possibleBiomes.stream();
// Résolution paresseuse : le registre du serveur n'est pas forcément
// disponible au moment de la construction du BiomeSource.
return BiomeBand.allPossible().stream();
}
@Override
@@ -58,18 +59,18 @@ public class LatitudeBiomeSource extends BiomeSource {
double temperature = BiomeBand.getTemperatureAtZ(blockZ, temperatureNoise);
double moisture = BiomeBand.getMoistureAtX(blockX, blockZ, moistureNoise);
if (BiomeBand.isOceanAt(blockX, blockZ, temperature, oceanNoise)) {
if (oceansEnabled() && BiomeBand.isOceanAt(blockX, blockZ, temperature, oceanNoise)) {
List<Holder<Biome>> oceans = BiomeBand.oceanFor(temperature);
double pick = biomeSelectorNoise.noise(blockX * 0.005, blockZ * 0.005, 1000);
int idx = (int) ((pick * 0.5 + 0.5) * oceans.size());
return oceans.get(Math.max(0, Math.min(oceans.size() - 1, idx)));
return select(oceans, idx);
}
if (blockY < 0) {
List<Holder<Biome>> underground = BiomeBand.undergroundFor(temperature);
double pick = biomeSelectorNoise.noise(blockX * 0.01, blockZ * 0.01, 2000);
int idx = (int) ((pick * 0.5 + 0.5) * underground.size());
return underground.get(Math.max(0, Math.min(underground.size() - 1, idx)));
return select(underground, idx);
}
BiomeBand band = BiomeBand.fromTemperature(temperature);
@@ -78,9 +79,35 @@ public class LatitudeBiomeSource extends BiomeSource {
biomes = BiomeBand.TEMPERATE.surface();
}
double pick = biomeSelectorNoise.noise(blockX * 0.0008, blockZ * 0.0008, 3000);
double selectorScale = 2.4 / biomeSize();
double pick = biomeSelectorNoise.noise(blockX * selectorScale, blockZ * selectorScale, 3000);
double adjusted = pick * 0.5 + moisture * 0.3;
int idx = (int) ((adjusted * 0.5 + 0.5) * biomes.size());
return biomes.get(Math.max(0, Math.min(biomes.size() - 1, idx)));
return select(biomes, idx);
}
/**
* Sélectionne un biome dans la liste à l'indice donné, sans jamais lever
* d'exception : si la liste est vide (résolution de holders échouée),
* retourne un biome de secours garanti.
*/
private Holder<Biome> select(List<Holder<Biome>> list, int idx) {
if (list.isEmpty()) {
Holder<Biome> fb = BiomeBand.fallback();
if (fb != null)
return fb;
}
int clamped = Math.max(0, Math.min(list.size() - 1, idx));
return list.get(clamped);
}
// --- Accès sûrs à la configuration (valeurs par défaut si non chargée) ---
private static boolean oceansEnabled() {
return !ModConfigs.SPEC.isLoaded() || ModConfigs.WORLD_GEN.enableOceans.get();
}
private static int biomeSize() {
return ModConfigs.SPEC.isLoaded() ? ModConfigs.WORLD_GEN.biomeSize.get() : 3000;
}
}
@@ -1,6 +1,7 @@
package net.mcreator.customoregen.worldgen;
import net.mcreator.customoregen.CustomOreGenMod;
import net.mcreator.customoregen.config.ModConfigs;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.biome.Biomes;
@@ -14,17 +15,14 @@ import net.minecraft.world.entity.player.Player;
@Mod.EventBusSubscriber(modid = CustomOreGenMod.MODID)
public class PlainsSpawnHandler {
private static boolean hasSetSpawn = false;
@SubscribeEvent
public static void onPlayerJoin(EntityJoinLevelEvent event) {
if (hasSetSpawn) return;
if (!(event.getEntity() instanceof Player player)) return;
if (!(event.getLevel() instanceof ServerLevel level)) return;
if (!level.dimensionType().natural()) return;
hasSetSpawn = true;
// Garde naturel : si le spawn a déjà été déplacé (non nul), on ne fait plus rien.
// Évite le booléen statique global qui ne se déclenchait qu'une fois par serveur.
if (level.getSharedSpawnPos().getX() != 0 || level.getSharedSpawnPos().getZ() != 0) return;
BlockPos spawn = findPlainsSpawn(level);
@@ -33,7 +31,7 @@ public class PlainsSpawnHandler {
}
private static BlockPos findPlainsSpawn(ServerLevel level) {
int radius = 100;
int radius = ModConfigs.SPEC.isLoaded() ? ModConfigs.WORLD_GEN.spawnSearchRadius.get() : 100;
BlockPos bestPos = new BlockPos(0, 64, 0);
double bestDistance = Double.MAX_VALUE;
@@ -1,6 +1,7 @@
package net.mcreator.customoregen.worldgen;
import net.mcreator.customoregen.CustomOreGenMod;
import net.mcreator.customoregen.config.ModConfigs;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
@@ -13,19 +14,22 @@ import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(modid = CustomOreGenMod.MODID)
public class WelcomeMessageHandler {
private static boolean hasShownMessage = false;
private static final String WELCOMED_KEY = "custom_ore_gen_welcomed";
@SubscribeEvent
public static void onPlayerJoin(EntityJoinLevelEvent event) {
if (hasShownMessage) return;
if (!(event.getEntity() instanceof Player player)) return;
if (!(event.getLevel() instanceof ServerLevel level)) return;
hasShownMessage = true;
// Message configurable et envoyé UNE fois par joueur (persisté dans ses données).
if (ModConfigs.SPEC.isLoaded() && !ModConfigs.WORLD_GEN.enableWelcomeMessage.get()) return;
if (player.getPersistentData().getBoolean(WELCOMED_KEY)) return;
ChunkGenerator generator = level.getChunkSource().getGenerator();
if (!(generator.getBiomeSource() instanceof LatitudeBiomeSource)) return;
player.getPersistentData().putBoolean(WELCOMED_KEY, true);
player.sendSystemMessage(Component.literal(""));
player.sendSystemMessage(Component.literal("\u00A76\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
player.sendSystemMessage(Component.literal("\u00A7e Custom Ore Gen \u00BB Mode Latitude"));
+1 -1
View File
@@ -4,7 +4,7 @@ license="Not specified"
[[mods]]
modId="custom_ore_gen"
version="2.2.0-forge"
version="4.5-forge"
displayName="Custom Ore Gen"
displayURL="https://lanro.eu"
credits="Created using mod maker MCreator - https://mcreator.net/about"