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:
+1
-1
@@ -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() {
|
||||
|
||||
-143
@@ -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"));
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user