Tritanium cloud/ellipsoid ore distribution

This commit is contained in:
DBotThePony 2025-01-19 15:10:46 +07:00
parent 35e871890c
commit d528f8465c
Signed by: DBot
GPG Key ID: DCC23B5715498507
6 changed files with 147 additions and 23 deletions

View File

@ -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<ConfiguredFeature<*, *>
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<PlacedFeature> {
@ -80,6 +86,24 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
)
))
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<BiomeModifier>) {
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
)

View File

@ -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)

View File

@ -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
}

View File

@ -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<BlockPos> {
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<EllipsoidPlacement> 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)
}
}
}
}

View File

@ -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
}
}

View File

@ -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 } }
}