From d528f8465c4adba0f44413238f8fafd20d63c0ef Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 19 Jan 2025 15:10:46 +0700 Subject: [PATCH] Tritanium cloud/ellipsoid ore distribution --- .../ru/dbotthepony/mc/otm/datagen/WorldGen.kt | 27 +++++- .../mc/otm/OverdriveThatMatters.kt | 1 + .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 27 ++---- .../mc/otm/data/world/EllipsoidPlacement.kt | 93 +++++++++++++++++++ .../world/StandardDeviationHeightProvider.kt | 6 +- .../mc/otm/registry/MPlacementModifiers.kt | 16 ++++ 6 files changed, 147 insertions(+), 23 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/world/EllipsoidPlacement.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/registry/MPlacementModifiers.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt index 38d45dc92..f7d9fe349 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt @@ -6,6 +6,9 @@ import net.minecraft.data.worldgen.BootstrapContext import net.minecraft.resources.ResourceKey import net.minecraft.tags.BiomeTags import net.minecraft.tags.BlockTags +import net.minecraft.util.valueproviders.ClampedNormalFloat +import net.minecraft.util.valueproviders.ClampedNormalInt +import net.minecraft.util.valueproviders.UniformInt import net.minecraft.world.level.levelgen.GenerationStep import net.minecraft.world.level.levelgen.VerticalAnchor import net.minecraft.world.level.levelgen.feature.ConfiguredFeature @@ -16,10 +19,12 @@ import net.minecraft.world.level.levelgen.placement.CountPlacement import net.minecraft.world.level.levelgen.placement.HeightRangePlacement import net.minecraft.world.level.levelgen.placement.InSquarePlacement import net.minecraft.world.level.levelgen.placement.PlacedFeature +import net.minecraft.world.level.levelgen.placement.RarityFilter import net.minecraft.world.level.levelgen.structure.templatesystem.TagMatchTest import net.neoforged.neoforge.common.world.BiomeModifier import net.neoforged.neoforge.registries.NeoForgeRegistries import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.data.world.EllipsoidPlacement import ru.dbotthepony.mc.otm.data.world.StandardDeviationHeightProvider import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MWorldGenFeatures @@ -51,6 +56,7 @@ fun registerConfiguredFeatures(context: BootstrapContext private object PlacedFeatures { val NORMAL_TRITANIUM = key("normal_tritanium") val DEEP_TRITANIUM = key("deep_tritanium") + val CLOUD_TITANIUM = key("cloud_tritanium") val BLACK_HOLE = key("black_hole") private fun key(name: String): ResourceKey { @@ -80,6 +86,24 @@ fun registerPlacedFeatures(context: BootstrapContext) { ) )) + context.register(PlacedFeatures.CLOUD_TITANIUM, PlacedFeature( + ore, + listOf( + RarityFilter.onAverageOnceEvery(6), + InSquarePlacement.spread(), + HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(10), 15.0)), + EllipsoidPlacement( + x = ClampedNormalInt.of(0f, 12f, Int.MIN_VALUE, Int.MAX_VALUE), + y = ClampedNormalInt.of(0f, 12f, Int.MIN_VALUE, Int.MAX_VALUE), + z = ClampedNormalInt.of(0f, 8f, Int.MIN_VALUE, Int.MAX_VALUE), + count = ClampedNormalInt.of(100f, 100f, 80, 300), + xLength = ClampedNormalFloat.of(11f, 4f, 4f, 16f), + yLength = ClampedNormalFloat.of(11f, 4f, 4f, 16f), + zLength = ClampedNormalFloat.of(11f, 4f, 4f, 16f), + ) + ) + )) + val blackHole = configured.getOrThrow(ConfiguredFeatures.BLACK_HOLE) context.register(PlacedFeatures.BLACK_HOLE, PlacedFeature( @@ -110,7 +134,8 @@ fun registerBiomeModifiers(context: BootstrapContext) { biomes.getOrThrow(BiomeTags.IS_OVERWORLD), HolderSet.direct( placed.getOrThrow(PlacedFeatures.NORMAL_TRITANIUM), - placed.getOrThrow(PlacedFeatures.DEEP_TRITANIUM) + placed.getOrThrow(PlacedFeatures.DEEP_TRITANIUM), + placed.getOrThrow(PlacedFeatures.CLOUD_TITANIUM), ), GenerationStep.Decoration.UNDERGROUND_ORES ) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt index f6314ccd8..f24096cca 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt @@ -99,6 +99,7 @@ object OverdriveThatMatters { MWorldGenFeatures.register(MOD_BUS) CommandArgumentTypes.register(MOD_BUS) MHeightProviders.register(MOD_BUS) + MPlacementModifiers.register(MOD_BUS) StorageStack.Companion.register(MOD_BUS) MatteryChestMenu.Companion.register(MOD_BUS) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 5e44c3d69..be590c9e4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -598,7 +598,7 @@ infix fun FluidStack.isNotSameAs(other: FluidStack): Boolean { data class DoublePair(val first: Double, val second: Double) // normal distribution via Box-Muller -fun RandomGenerator.nextNormalDouble(stddev: Double, mean: Double): DoublePair { +fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { var rand1: Double var rand2: Double var distSqr: Double @@ -617,22 +617,15 @@ fun RandomGenerator.nextNormalDouble(stddev: Double, mean: Double): DoublePair { ) } -// this kinda exists in form of nextGaussian, but it doesn't allow to specify deviation and mean -fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): DoublePair { - var rand1: Double - var rand2: Double - var distSqr: Double - - do { - rand1 = 2.0 * nextDouble() - 1.0 - rand2 = 2.0 * nextDouble() - 1.0 - distSqr = rand1 * rand1 + rand2 * rand2 - } while (distSqr >= 1) - - val mapping = sqrt(-2.0 * ln(distSqr) / distSqr) - +// All Mojang's random sources use MarsagliaPolarGaussian for generating normal distributed doubles, +// which is Box-Muller transform already, so we can use that +fun RandomSource.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { return DoublePair( - rand1 * mapping * stddev + mean, - rand2 * mapping * stddev + mean + nextGaussian() * stddev + mean, + nextGaussian() * stddev + mean ) } + +fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double { + return nextGaussian() * stddev + mean +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/EllipsoidPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/EllipsoidPlacement.kt new file mode 100644 index 000000000..6a1bbe408 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/EllipsoidPlacement.kt @@ -0,0 +1,93 @@ +package ru.dbotthepony.mc.otm.data.world + +import com.mojang.serialization.Codec +import com.mojang.serialization.MapCodec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.core.BlockPos +import net.minecraft.util.RandomSource +import net.minecraft.util.valueproviders.FloatProvider +import net.minecraft.util.valueproviders.IntProvider +import net.minecraft.world.level.levelgen.placement.PlacementContext +import net.minecraft.world.level.levelgen.placement.PlacementModifier +import net.minecraft.world.level.levelgen.placement.PlacementModifierType +import ru.dbotthepony.mc.otm.core.math.component1 +import ru.dbotthepony.mc.otm.core.math.component2 +import ru.dbotthepony.mc.otm.core.math.component3 +import ru.dbotthepony.mc.otm.core.math.minus +import ru.dbotthepony.mc.otm.core.math.plus +import ru.dbotthepony.mc.otm.data.codec.minRange +import ru.dbotthepony.mc.otm.registry.MPlacementModifiers +import java.util.stream.Stream +import kotlin.math.PI +import kotlin.math.roundToInt + +// aka "cloud placement" +data class EllipsoidPlacement( + val x: IntProvider, + val z: IntProvider, + val y: IntProvider, + val count: IntProvider, + val xLength: FloatProvider, + val zLength: FloatProvider, + val yLength: FloatProvider, +) : PlacementModifier() { + init { + require(xLength.minValue >= 1f) { "Bad ellipsoid x minimal size: $xLength" } + require(zLength.minValue >= 1f) { "Bad ellipsoid z minimal size: $zLength" } + require(yLength.minValue >= 1f) { "Bad ellipsoid y minimal size: $yLength" } + } + + override fun getPositions( + context: PlacementContext, + random: RandomSource, + position: BlockPos + ): Stream { + var count = count.sample(random) + + if (count <= 0) { + return Stream.empty() + } + + val xLength = xLength.sample(random) + val zLength = zLength.sample(random) + val yLength = yLength.sample(random) + + val xPow = xLength * xLength + val zPow = zLength * zLength + val yPow = yLength * yLength + + count = minOf(count, (xLength * zLength * yLength * PI * (4.0 / 3.0)).roundToInt()) + + return Stream.generate { position + BlockPos(this.x.sample(random), this.y.sample(random), this.z.sample(random)) } + .limit(count * 10L) // failsafe + .filter { + val (ellipsoidX, ellipsoidY, ellipsoidZ) = it - position + + (ellipsoidX * ellipsoidX) / xPow + + (ellipsoidY * ellipsoidY) / yPow + + (ellipsoidZ * ellipsoidZ) / zPow <= 1.0f + } + .distinct() + .limit(count.toLong()) + } + + override fun type(): PlacementModifierType<*> { + return MPlacementModifiers.ELLIPSOID_PLACEMENT + } + + companion object { + val CODEC: MapCodec by lazy { + RecordCodecBuilder.mapCodec { + it.group( + IntProvider.CODEC.fieldOf("x").forGetter(EllipsoidPlacement::x), + IntProvider.CODEC.fieldOf("y").forGetter(EllipsoidPlacement::y), + IntProvider.CODEC.fieldOf("z").forGetter(EllipsoidPlacement::z), + IntProvider.CODEC.fieldOf("count").forGetter(EllipsoidPlacement::count), + FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("x_size").forGetter(EllipsoidPlacement::xLength), + FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("z_size").forGetter(EllipsoidPlacement::zLength), + FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("y_size").forGetter(EllipsoidPlacement::yLength), + ).apply(it, ::EllipsoidPlacement) + } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/StandardDeviationHeightProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/StandardDeviationHeightProvider.kt index 1b44faf34..4e90c1d5c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/StandardDeviationHeightProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/StandardDeviationHeightProvider.kt @@ -26,14 +26,10 @@ data class StandardDeviationHeightProvider( var i = 100 while (i-- > 0) { - val (r0, r1) = random.nextNormalDouble(deviation, yd) - val i0 = r0.toInt() - val i1 = r1.toInt() + val i0 = random.nextNormalDouble(deviation, yd).toInt() if (i0 in context.minGenY .. context.genDepth) { return i0 - } else if (i1 in context.minGenY .. context.genDepth) { - return i1 } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MPlacementModifiers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MPlacementModifiers.kt new file mode 100644 index 000000000..6067daa4f --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MPlacementModifiers.kt @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.registry + +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.world.level.levelgen.placement.PlacementModifierType +import net.neoforged.bus.api.IEventBus +import ru.dbotthepony.mc.otm.data.world.EllipsoidPlacement + +object MPlacementModifiers { + private val registry = MDeferredRegister(BuiltInRegistries.PLACEMENT_MODIFIER_TYPE) + + fun register(bus: IEventBus) { + registry.register(bus) + } + + val ELLIPSOID_PLACEMENT by registry.register("ellipsoid") { PlacementModifierType { EllipsoidPlacement.CODEC } } +}