Enormous placement modifier, greatly enhance dilithium ore placement
This commit is contained in:
parent
f655405d4b
commit
a903b9cff8
@ -13,6 +13,7 @@ val mod_id: String by project
|
||||
val handle_deps: String by project
|
||||
val use_commit_hash_in_version: String by project
|
||||
val handleDeps = handle_deps.toBoolean()
|
||||
val caffeine_cache_version: String by project
|
||||
|
||||
plugins {
|
||||
java
|
||||
@ -142,14 +143,11 @@ dependencies {
|
||||
|
||||
implementation("thedarkcolour:kotlinforforge-neoforge:$kotlin_for_forge_version")
|
||||
|
||||
jarJar("ru.dbotthepony.kommons:kommons:[$kommons_version,)") { setTransitive(false) }
|
||||
implementation("ru.dbotthepony.kommons:kommons:[$kommons_version,)") { setTransitive(false) }
|
||||
jarJar(implementation("com.github.ben-manes.caffeine:caffeine:[$caffeine_cache_version,)")!!)
|
||||
|
||||
jarJar("ru.dbotthepony.kommons:kommons-gson:[$kommons_version,)") { setTransitive(false) }
|
||||
implementation("ru.dbotthepony.kommons:kommons-gson:[$kommons_version,)") { setTransitive(false) }
|
||||
|
||||
jarJar("ru.dbotthepony.kommons:kommons-guava:[$kommons_version,)") { setTransitive(false) }
|
||||
implementation("ru.dbotthepony.kommons:kommons-guava:[$kommons_version,)") { setTransitive(false) }
|
||||
jarJar(implementation("ru.dbotthepony.kommons:kommons:[$kommons_version,)") { setTransitive(false) })
|
||||
jarJar(implementation("ru.dbotthepony.kommons:kommons-gson:[$kommons_version,)") { setTransitive(false) })
|
||||
jarJar(implementation("ru.dbotthepony.kommons:kommons-guava:[$kommons_version,)") { setTransitive(false) })
|
||||
|
||||
compileOnly("yalter.mousetweaks:MouseTweaks:2.23:api")
|
||||
annotationProcessor("org.spongepowered:mixin:${mixin_version}:processor")
|
||||
@ -228,6 +226,10 @@ minecraft {
|
||||
|
||||
// Log4j console level
|
||||
systemProperty("forge.logging.console.level", "debug")
|
||||
|
||||
dependencies {
|
||||
runtime("com.github.ben-manes.caffeine:caffeine:[$caffeine_cache_version,)")
|
||||
}
|
||||
}
|
||||
|
||||
getByName("client") {
|
||||
|
@ -23,6 +23,7 @@ neogradle.subsystems.parchment.minecraftVersion=1.21.1
|
||||
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
|
||||
|
||||
kommons_version=3.1.3
|
||||
caffeine_cache_version=3.1.5
|
||||
|
||||
jei_version=19.16.4.171
|
||||
jupiter_version=5.9.2
|
||||
|
@ -9,6 +9,7 @@ import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.util.valueproviders.ClampedNormalFloat
|
||||
import net.minecraft.util.valueproviders.ClampedNormalInt
|
||||
import net.minecraft.util.valueproviders.ConstantFloat
|
||||
import net.minecraft.util.valueproviders.UniformFloat
|
||||
import net.minecraft.util.valueproviders.UniformInt
|
||||
import net.minecraft.world.level.levelgen.GenerationStep
|
||||
import net.minecraft.world.level.levelgen.VerticalAnchor
|
||||
@ -25,11 +26,12 @@ 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.worldgen.placement.StandardDeviationHeightProvider
|
||||
import ru.dbotthepony.mc.otm.registry.game.MBlocks
|
||||
import ru.dbotthepony.mc.otm.registry.data.MWorldGenFeatures
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.BlackHolePlacerFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.AbstractEnormousPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousEllipsoidPlacement
|
||||
|
||||
private object ConfiguredFeatures {
|
||||
val TRITANIUM_ORE = key("tritanium_ore")
|
||||
@ -71,7 +73,6 @@ 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 DILITHIUM = key("dilithium")
|
||||
val BLACK_HOLE = key("black_hole")
|
||||
|
||||
@ -103,24 +104,6 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
HeightRangePlacement.of(VeryBiasedToBottomHeight.of(VerticalAnchor.aboveBottom(4), VerticalAnchor.absolute(0), 16))
|
||||
)
|
||||
))
|
||||
|
||||
context.register(PlacedFeatures.CLOUD_TITANIUM, PlacedFeature(
|
||||
ore,
|
||||
listOf(
|
||||
RarityFilter.onAverageOnceEvery(16),
|
||||
InSquarePlacement.spread(),
|
||||
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(10), 15.0)),
|
||||
EllipsoidPlacement(
|
||||
x = ClampedNormalInt.of(0f, 6f, Int.MIN_VALUE, Int.MAX_VALUE),
|
||||
y = ClampedNormalInt.of(0f, 12f, Int.MIN_VALUE, Int.MAX_VALUE),
|
||||
z = ClampedNormalInt.of(0f, 6f, Int.MIN_VALUE, Int.MAX_VALUE),
|
||||
count = ClampedNormalInt.of(60f, 60f, 40, 160),
|
||||
xLength = ClampedNormalFloat.of(11f, 4f, 6f, 14f),
|
||||
yLength = ClampedNormalFloat.of(11f, 4f, 6f, 14f),
|
||||
zLength = ClampedNormalFloat.of(11f, 4f, 6f, 14f),
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
run {
|
||||
@ -129,19 +112,22 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
context.register(PlacedFeatures.DILITHIUM, PlacedFeature(
|
||||
ore,
|
||||
listOf(
|
||||
RarityFilter.onAverageOnceEvery(12),
|
||||
InSquarePlacement.spread(),
|
||||
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(0), 15.0)),
|
||||
EllipsoidPlacement(
|
||||
x = ClampedNormalInt.of(0f, 8f, Int.MIN_VALUE, Int.MAX_VALUE),
|
||||
y = ClampedNormalInt.of(0f, 20f, Int.MIN_VALUE, Int.MAX_VALUE),
|
||||
z = ClampedNormalInt.of(0f, 8f, Int.MIN_VALUE, Int.MAX_VALUE),
|
||||
count = ClampedNormalInt.of(200f, 200f, 200, 600),
|
||||
xLength = ClampedNormalFloat.of(11f, 4f, 8f, 14f),
|
||||
// allow crystals to generate as far as standard deviation allows
|
||||
// to increase chance for player to discover crystal vein
|
||||
yLength = ConstantFloat.of(60f),
|
||||
zLength = ClampedNormalFloat.of(11f, 4f, 8f, 14f),
|
||||
EnormousEllipsoidPlacement(
|
||||
parameters = AbstractEnormousPlacement.Parameters(
|
||||
chunkScanRange = 4,
|
||||
placementModifiers = listOf(
|
||||
RarityFilter.onAverageOnceEvery(40),
|
||||
InSquarePlacement.spread(),
|
||||
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(0), 15.0)),
|
||||
)
|
||||
),
|
||||
x = ClampedNormalFloat.of(0f, 0.5f, 0f, 2f),
|
||||
y = ClampedNormalFloat.of(0f, 0.5f, 0f, 2f),
|
||||
z = ClampedNormalFloat.of(0f, 0.5f, 0f, 2f),
|
||||
count = UniformInt.of(4800, 12400),
|
||||
xLength = UniformFloat.of(60f, 80f),
|
||||
yLength = UniformFloat.of(60f, 80f),
|
||||
zLength = UniformFloat.of(60f, 80f),
|
||||
)
|
||||
)
|
||||
))
|
||||
@ -179,7 +165,6 @@ fun registerBiomeModifiers(context: BootstrapContext<BiomeModifier>) {
|
||||
HolderSet.direct(
|
||||
placed.getOrThrow(PlacedFeatures.NORMAL_TRITANIUM),
|
||||
placed.getOrThrow(PlacedFeatures.DEEP_TRITANIUM),
|
||||
placed.getOrThrow(PlacedFeatures.CLOUD_TITANIUM),
|
||||
placed.getOrThrow(PlacedFeatures.DILITHIUM),
|
||||
),
|
||||
GenerationStep.Decoration.UNDERGROUND_ORES
|
||||
|
@ -53,3 +53,5 @@ fun <S : Comparable<S>> Codec<S>.maxRange(max: S, exclusive: Boolean = false) =
|
||||
ComparableCodec(this, max = max, maxExclusive = exclusive)
|
||||
fun <S : Comparable<S>> Codec<S>.inRange(min: S, minExclusive: Boolean = false, max: S, maxExclusive: Boolean = false) =
|
||||
ComparableCodec(this, min, max, minExclusive, maxExclusive)
|
||||
fun <S : Comparable<S>> Codec<S>.inRange(min: S, max: S) =
|
||||
ComparableCodec(this, min, max, false, false)
|
||||
|
@ -3,7 +3,7 @@ package ru.dbotthepony.mc.otm.registry.data
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.world.level.levelgen.heightproviders.HeightProviderType
|
||||
import net.neoforged.bus.api.IEventBus
|
||||
import ru.dbotthepony.mc.otm.data.world.StandardDeviationHeightProvider
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.StandardDeviationHeightProvider
|
||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||
|
||||
object MHeightProviders {
|
||||
|
@ -3,8 +3,9 @@ package ru.dbotthepony.mc.otm.registry.data
|
||||
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
|
||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousEllipsoidPlacement
|
||||
|
||||
object MPlacementModifiers {
|
||||
private val registry = MDeferredRegister(BuiltInRegistries.PLACEMENT_MODIFIER_TYPE)
|
||||
@ -14,4 +15,5 @@ object MPlacementModifiers {
|
||||
}
|
||||
|
||||
val ELLIPSOID_PLACEMENT by registry.register("ellipsoid") { PlacementModifierType { EllipsoidPlacement.CODEC } }
|
||||
val ENORMOUS_ELLIPSOID_PLACEMENT by registry.register("enormous_ellipsoid") { PlacementModifierType { EnormousEllipsoidPlacement.CODEC } }
|
||||
}
|
||||
|
@ -0,0 +1,110 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.github.benmanes.caffeine.cache.Scheduler
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import it.unimi.dsi.fastutil.HashCommon
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.SectionPos
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.ChunkPos
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementContext
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier
|
||||
import ru.dbotthepony.mc.otm.data.codec.inRange
|
||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||
import java.time.Duration
|
||||
import java.util.stream.Stream
|
||||
import kotlin.math.sqrt
|
||||
|
||||
/**
|
||||
* Enormous placement base, which allows it to span over several chunks without issues.
|
||||
*
|
||||
* MUST come as first placement modifier, other placement modifiers (such as rarity and
|
||||
* shuffle of center point within chunks) must be provided inside [Parameters.placementModifiers] list, in same order as if they were
|
||||
* *before* this placement
|
||||
*/
|
||||
abstract class AbstractEnormousPlacement(val parameters: Parameters) : PlacementModifier() {
|
||||
data class Parameters(
|
||||
/**
|
||||
* How many chunks away to look for actual placements
|
||||
*
|
||||
* Too small value will cause placement cutoffs
|
||||
*/
|
||||
val chunkScanRange: Int,
|
||||
|
||||
/**
|
||||
* Baseline placement modifiers, dictating how to appear in chunk
|
||||
*/
|
||||
val placementModifiers: List<PlacementModifier>,
|
||||
|
||||
/**
|
||||
* How many chunks to remember placements in, usually not required to be adjusted
|
||||
*/
|
||||
val chunkCacheSize: Int = 16384,
|
||||
)
|
||||
|
||||
private class GeneratedChunk(positions: Stream<BlockPos>) {
|
||||
private val positions = ArrayList<BlockPos>()
|
||||
|
||||
init {
|
||||
positions.forEach { this.positions.add(it) }
|
||||
}
|
||||
|
||||
fun getPositions(pos: ChunkPos): Stream<BlockPos> {
|
||||
return positions.stream().filter {
|
||||
SectionPos.blockToSectionCoord(it.x) == pos.x &&
|
||||
SectionPos.blockToSectionCoord(it.z) == pos.z
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos>
|
||||
|
||||
private val chunkCache = Caffeine.newBuilder()
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.executor(Util.backgroundExecutor())
|
||||
.maximumSize(parameters.chunkCacheSize.toLong())
|
||||
.expireAfterWrite(Duration.ofMinutes(5))
|
||||
.softValues()
|
||||
.build<ChunkPos, GeneratedChunk>()
|
||||
|
||||
private fun computeChunk(context: PlacementContext, pos: ChunkPos): GeneratedChunk {
|
||||
val random = RandomSource.create(context.level.seed + HashCommon.murmurHash3(pos.x + pos.z * 31))
|
||||
var stream = Stream.of(BlockPos(pos.minBlockX, 0, pos.minBlockZ))
|
||||
parameters.placementModifiers.forEach { modifier -> stream = stream.flatMap { modifier.getPositions(context, random, it).sequential() } }
|
||||
return GeneratedChunk(stream.flatMap { getPositions(it, random) })
|
||||
}
|
||||
|
||||
final override fun getPositions(context: PlacementContext, random: RandomSource, pos: BlockPos): Stream<BlockPos> {
|
||||
val cPos = ChunkPos(pos)
|
||||
val instances = ArrayList<GeneratedChunk>()
|
||||
|
||||
for (x in -parameters.chunkScanRange .. parameters.chunkScanRange) {
|
||||
for (z in -parameters.chunkScanRange .. parameters.chunkScanRange) {
|
||||
// floor, so chunk scan range of 1 will give square instead of diamond
|
||||
val radius = sqrt(x.toDouble() * x + z.toDouble() * z).toInt()
|
||||
|
||||
if (radius <= parameters.chunkScanRange) {
|
||||
val thisPos = ChunkPos(cPos.x + x, cPos.z + z)
|
||||
|
||||
instances.add(chunkCache.get(thisPos) { computeChunk(context, thisPos) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instances.stream().flatMap { it.getPositions(cPos) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val PARAMETERS_CODEC: MapCodec<Parameters> = RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
Codec.INT.minRange(0).fieldOf("chunk_scan_range").forGetter(Parameters::chunkScanRange),
|
||||
CODEC.listOf().fieldOf("placement").forGetter(Parameters::placementModifiers),
|
||||
Codec.INT.inRange(0, 128_000).optionalFieldOf("cache_size", 16384).forGetter(Parameters::chunkCacheSize),
|
||||
).apply(it, ::Parameters)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package ru.dbotthepony.mc.otm.data.world
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
@ -19,16 +19,20 @@ import java.util.stream.Stream
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
// aka "cloud placement"
|
||||
/**
|
||||
* Regular ellipsoid ("cloud") placement, suitable to be used as non-primary placement modifier
|
||||
*
|
||||
* This placement modifier is designed to be terminal; other placement modifiers after this MUST NOT be placed
|
||||
*/
|
||||
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() {
|
||||
override val x: FloatProvider,
|
||||
override val z: FloatProvider,
|
||||
override val y: FloatProvider,
|
||||
override val count: IntProvider,
|
||||
override val xLength: FloatProvider,
|
||||
override val zLength: FloatProvider,
|
||||
override val yLength: FloatProvider,
|
||||
) : PlacementModifier(), IEllipsoidPlacement {
|
||||
init {
|
||||
require(xLength.minValue >= 1f) { "Bad ellipsoid x minimal size: $xLength" }
|
||||
require(zLength.minValue >= 1f) { "Bad ellipsoid z minimal size: $zLength" }
|
||||
@ -40,34 +44,7 @@ data class EllipsoidPlacement(
|
||||
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())
|
||||
count = 600
|
||||
|
||||
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())
|
||||
return getEllipsoidPositions(random, position)
|
||||
}
|
||||
|
||||
override fun type(): PlacementModifierType<*> {
|
||||
@ -78,9 +55,9 @@ data class EllipsoidPlacement(
|
||||
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),
|
||||
FloatProvider.CODEC.fieldOf("x").forGetter(EllipsoidPlacement::x),
|
||||
FloatProvider.CODEC.fieldOf("y").forGetter(EllipsoidPlacement::y),
|
||||
FloatProvider.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),
|
@ -0,0 +1,60 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
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.PlacementModifierType
|
||||
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
* Enormous ellipsoid ("cloud") placement, suitable to be used as ONLY primary placement modifier
|
||||
*
|
||||
* This placement modifier is designed to be terminal; other placement modifiers after this MUST NOT be placed
|
||||
*
|
||||
* @see AbstractEnormousPlacement
|
||||
*/
|
||||
class EnormousEllipsoidPlacement(
|
||||
parameters: Parameters,
|
||||
override val x: FloatProvider,
|
||||
override val z: FloatProvider,
|
||||
override val y: FloatProvider,
|
||||
override val count: IntProvider,
|
||||
override val xLength: FloatProvider,
|
||||
override val zLength: FloatProvider,
|
||||
override val yLength: FloatProvider,
|
||||
) : AbstractEnormousPlacement(parameters), IEllipsoidPlacement {
|
||||
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 type(): PlacementModifierType<*> {
|
||||
return MPlacementModifiers.ENORMOUS_ELLIPSOID_PLACEMENT
|
||||
}
|
||||
|
||||
override fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos> {
|
||||
return getEllipsoidPositions(random, center)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<EnormousEllipsoidPlacement> by lazy {
|
||||
RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
PARAMETERS_CODEC.forGetter(EnormousEllipsoidPlacement::parameters),
|
||||
FloatProvider.CODEC.fieldOf("x").forGetter(EnormousEllipsoidPlacement::x),
|
||||
FloatProvider.CODEC.fieldOf("y").forGetter(EnormousEllipsoidPlacement::y),
|
||||
FloatProvider.CODEC.fieldOf("z").forGetter(EnormousEllipsoidPlacement::z),
|
||||
IntProvider.CODEC.fieldOf("count").forGetter(EnormousEllipsoidPlacement::count),
|
||||
FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("x_size").forGetter(EnormousEllipsoidPlacement::xLength),
|
||||
FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("z_size").forGetter(EnormousEllipsoidPlacement::zLength),
|
||||
FloatProvider.codec(1f, Float.MAX_VALUE).fieldOf("y_size").forGetter(EnormousEllipsoidPlacement::yLength),
|
||||
).apply(it, ::EnormousEllipsoidPlacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.valueproviders.FloatProvider
|
||||
import net.minecraft.util.valueproviders.IntProvider
|
||||
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.plus
|
||||
import java.util.stream.Stream
|
||||
|
||||
interface IEllipsoidPlacement {
|
||||
/**
|
||||
* X position within ellipsoid sampler, expected to be in range -1 .. 1
|
||||
*/
|
||||
val x: FloatProvider
|
||||
|
||||
/**
|
||||
* Z position within ellipsoid sampler, expected to be in range -1 .. 1
|
||||
*/
|
||||
val z: FloatProvider
|
||||
|
||||
/**
|
||||
* Y position within ellipsoid sampler, expected to be in range -1 .. 1
|
||||
*/
|
||||
val y: FloatProvider
|
||||
|
||||
/**
|
||||
* Total amount of block positions to generate
|
||||
*/
|
||||
val count: IntProvider
|
||||
|
||||
/**
|
||||
* Ellipsoid size sampler on X axis
|
||||
*/
|
||||
val xLength: FloatProvider
|
||||
|
||||
/**
|
||||
* Ellipsoid size sampler on Z axis
|
||||
*/
|
||||
val zLength: FloatProvider
|
||||
|
||||
/**
|
||||
* Ellipsoid size sampler on Y axis
|
||||
*/
|
||||
val yLength: FloatProvider
|
||||
|
||||
fun getEllipsoidPositions(random: RandomSource, position: BlockPos): Stream<BlockPos> {
|
||||
val 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
|
||||
|
||||
return Stream.generate {
|
||||
val x = this.x.sample(random) * xLength
|
||||
val y = this.y.sample(random) * yLength
|
||||
val z = this.z.sample(random) * zLength
|
||||
BlockPos(x.toInt(), y.toInt(), z.toInt())
|
||||
}
|
||||
.limit(count.toLong() * 10)
|
||||
.filter {
|
||||
val (ellipsoidX, ellipsoidY, ellipsoidZ) = it
|
||||
|
||||
(ellipsoidX * ellipsoidX) / xPow +
|
||||
(ellipsoidY * ellipsoidY) / yPow +
|
||||
(ellipsoidZ * ellipsoidZ) / zPow <= 1.0f
|
||||
}
|
||||
.distinct()
|
||||
.limit(count.toLong())
|
||||
.map { it + position }
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package ru.dbotthepony.mc.otm.data.world
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
Loading…
Reference in New Issue
Block a user