Make enormous placement a wrapper around regular placement modifiers, simplifying code

This commit is contained in:
DBotThePony 2025-03-09 12:59:36 +07:00
parent 7736762c86
commit 674c875249
Signed by: DBot
GPG Key ID: DCC23B5715498507
7 changed files with 148 additions and 251 deletions

View File

@ -8,7 +8,6 @@ import net.minecraft.tags.BiomeTags
import net.minecraft.tags.BlockTags import net.minecraft.tags.BlockTags
import net.minecraft.util.valueproviders.ClampedNormalFloat import net.minecraft.util.valueproviders.ClampedNormalFloat
import net.minecraft.util.valueproviders.ConstantFloat import net.minecraft.util.valueproviders.ConstantFloat
import net.minecraft.util.valueproviders.ConstantInt
import net.minecraft.util.valueproviders.UniformFloat import net.minecraft.util.valueproviders.UniformFloat
import net.minecraft.util.valueproviders.UniformInt import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.level.levelgen.GenerationStep import net.minecraft.world.level.levelgen.GenerationStep
@ -33,10 +32,8 @@ import ru.dbotthepony.mc.otm.worldgen.placement.StandardDeviationHeightProvider
import ru.dbotthepony.mc.otm.registry.game.MBlocks import ru.dbotthepony.mc.otm.registry.game.MBlocks
import ru.dbotthepony.mc.otm.registry.data.MWorldGenFeatures import ru.dbotthepony.mc.otm.registry.data.MWorldGenFeatures
import ru.dbotthepony.mc.otm.worldgen.feature.BlackHolePlacerFeature import ru.dbotthepony.mc.otm.worldgen.feature.BlackHolePlacerFeature
import ru.dbotthepony.mc.otm.worldgen.feature.DebugPlacerFeature import ru.dbotthepony.mc.otm.worldgen.placement.EnormousPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.AbstractEnormousPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousEllipsoidPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
private object ConfiguredFeatures { private object ConfiguredFeatures {
@ -118,16 +115,24 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
context.register(PlacedFeatures.WORM_TRITANIUM, PlacedFeature( context.register(PlacedFeatures.WORM_TRITANIUM, PlacedFeature(
configured.getOrThrow(ConfiguredFeatures.TRITANIUM_ORE_SMALL), configured.getOrThrow(ConfiguredFeatures.TRITANIUM_ORE_SMALL),
listOf( listOf(
WormPlacement( EnormousPlacement(
parameters = AbstractEnormousPlacement.Parameters(
chunkScanRange = 24, chunkScanRange = 24,
seedMix = 9284343575495L, seedMix = 9284343575495L,
prePlacementModifiers = listOf( children = listOf(
RarityFilter.onAverageOnceEvery(300), RarityFilter.onAverageOnceEvery(300),
InSquarePlacement.spread(), InSquarePlacement.spread(),
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(-40), 15.0)), HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(-40), 15.0)),
WormPlacement(
length = UniformInt.of(120, 400),
turnRateXY = WormPlacement.normalDistributedTurnRate(10f),
turnRateXZ = WormPlacement.normalDistributedTurnRate(60f),
turnSpeedXZ = WormPlacement.constantTurnRate(10f),
turnSpeedXY = WormPlacement.constantTurnRate(4f),
turnChanceXY = BooleanProvider.Unbiased(6),
turnChanceXZ = BooleanProvider.BiasedLinear(0.6f, 5),
maxTravelUp = 16,
maxTravelDown = 16,
), ),
postPlacementModifiers = listOf(
EllipsoidPlacement( EllipsoidPlacement(
count = UniformInt.of(15, 30), count = UniformInt.of(15, 30),
xLength = ConstantFloat.of(14f), xLength = ConstantFloat.of(14f),
@ -138,16 +143,6 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
z = ClampedNormalFloat.of(0f, 0.4f, -1f, 1f), z = ClampedNormalFloat.of(0f, 0.4f, -1f, 1f),
) )
) )
),
length = UniformInt.of(120, 400),
turnRateXY = WormPlacement.normalDistributedTurnRate(10f),
turnRateXZ = WormPlacement.normalDistributedTurnRate(60f),
turnSpeedXZ = WormPlacement.constantTurnRate(10f),
turnSpeedXY = WormPlacement.constantTurnRate(4f),
turnChanceXY = BooleanProvider.Unbiased(6),
turnChanceXZ = BooleanProvider.BiasedLinear(0.6f, 5),
maxTravelUp = 16,
maxTravelDown = 16,
) )
) )
)) ))
@ -164,16 +159,14 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
context.register(PlacedFeatures.DILITHIUM, PlacedFeature( context.register(PlacedFeatures.DILITHIUM, PlacedFeature(
ore, ore,
listOf( listOf(
EnormousEllipsoidPlacement( EnormousPlacement(
parameters = AbstractEnormousPlacement.Parameters( chunkScanRange = 6,
chunkScanRange = 5,
seedMix = 237483209523709234L, seedMix = 237483209523709234L,
prePlacementModifiers = listOf( children = listOf(
RarityFilter.onAverageOnceEvery(120), RarityFilter.onAverageOnceEvery(120),
InSquarePlacement.spread(), InSquarePlacement.spread(),
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(0), 15.0)), HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(0), 15.0)),
), EllipsoidPlacement(
),
x = ringularity, x = ringularity,
y = ringularity, y = ringularity,
z = ringularity, z = ringularity,
@ -182,6 +175,8 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
yLength = UniformFloat.of(40f, 90f), yLength = UniformFloat.of(40f, 90f),
zLength = UniformFloat.of(30f, 70f), zLength = UniformFloat.of(30f, 70f),
) )
),
)
) )
)) ))
} }

View File

@ -5,7 +5,7 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType
import net.neoforged.bus.api.IEventBus import net.neoforged.bus.api.IEventBus
import ru.dbotthepony.mc.otm.registry.MDeferredRegister import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousEllipsoidPlacement import ru.dbotthepony.mc.otm.worldgen.placement.EnormousPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
object MPlacementModifiers { object MPlacementModifiers {
@ -15,7 +15,7 @@ object MPlacementModifiers {
registry.register(bus) registry.register(bus)
} }
val ENORMOUS by registry.register("enormous") { PlacementModifierType { EnormousPlacement.CODEC } }
val ELLIPSOID_PLACEMENT by registry.register("ellipsoid") { PlacementModifierType { EllipsoidPlacement.CODEC } } val ELLIPSOID_PLACEMENT by registry.register("ellipsoid") { PlacementModifierType { EllipsoidPlacement.CODEC } }
val ENORMOUS_ELLIPSOID_PLACEMENT by registry.register("enormous_ellipsoid") { PlacementModifierType { EnormousEllipsoidPlacement.CODEC } }
val WORM_PLACEMENT by registry.register("worm") { PlacementModifierType { WormPlacement.CODEC } } val WORM_PLACEMENT by registry.register("worm") { PlacementModifierType { WormPlacement.CODEC } }
} }

View File

@ -25,14 +25,41 @@ import kotlin.math.roundToInt
* This placement modifier is designed to be terminal; other placement modifiers after this MUST NOT be placed * This placement modifier is designed to be terminal; other placement modifiers after this MUST NOT be placed
*/ */
data class EllipsoidPlacement( data class EllipsoidPlacement(
override val x: FloatProvider, /**
override val z: FloatProvider, * X position within ellipsoid sampler, expected to be in range -1 .. 1
override val y: FloatProvider, */
override val count: IntProvider, val x: FloatProvider,
override val xLength: FloatProvider,
override val zLength: FloatProvider, /**
override val yLength: FloatProvider, * Z position within ellipsoid sampler, expected to be in range -1 .. 1
) : PlacementModifier(), IEllipsoidPlacement { */
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,
) : PlacementModifier() {
init { init {
require(xLength.minValue >= 1f) { "Bad ellipsoid x minimal size: $xLength" } require(xLength.minValue >= 1f) { "Bad ellipsoid x minimal size: $xLength" }
require(zLength.minValue >= 1f) { "Bad ellipsoid z minimal size: $zLength" } require(zLength.minValue >= 1f) { "Bad ellipsoid z minimal size: $zLength" }
@ -44,7 +71,36 @@ data class EllipsoidPlacement(
random: RandomSource, random: RandomSource,
position: BlockPos position: BlockPos
): Stream<BlockPos> { ): Stream<BlockPos> {
return getEllipsoidPositions(random, position) 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 }
} }
override fun type(): PlacementModifierType<*> { override fun type(): PlacementModifierType<*> {

View File

@ -1,60 +0,0 @@
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)
}
}
}
}

View File

@ -12,17 +12,16 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.SectionPos import net.minecraft.core.SectionPos
import net.minecraft.util.RandomSource import net.minecraft.util.RandomSource
import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.ChunkPos
import net.minecraft.world.level.Level
import net.minecraft.world.level.WorldGenLevel import net.minecraft.world.level.WorldGenLevel
import net.minecraft.world.level.levelgen.placement.PlacementContext import net.minecraft.world.level.levelgen.placement.PlacementContext
import net.minecraft.world.level.levelgen.placement.PlacementModifier import net.minecraft.world.level.levelgen.placement.PlacementModifier
import net.minecraft.world.level.levelgen.placement.PlacementModifierType
import ru.dbotthepony.kommons.util.XXHash64 import ru.dbotthepony.kommons.util.XXHash64
import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource
import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.data.codec.minRange
import ru.dbotthepony.mc.otm.worldgen.placement.AbstractEnormousPlacement.Parameters import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
import java.io.DataOutputStream import java.io.DataOutputStream
import java.time.Duration import java.time.Duration
import java.util.Collections
import java.util.WeakHashMap import java.util.WeakHashMap
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import java.util.stream.Stream import java.util.stream.Stream
@ -32,14 +31,10 @@ import kotlin.math.sqrt
/** /**
* Enormous placement base, which allows it to span over several chunks without issues. * 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 * This modifier is designed to be the only "top-level" placement modifier,
* shuffle of center point within chunks) must be provided inside [Parameters.prePlacementModifiers] list, in same order as if they were * and all logic regarding actual placements embedded in [children]
* *before* this placement
*
* If "post-processing" placements are required, better provide them as [Parameters.postPlacementModifiers].
*/ */
abstract class AbstractEnormousPlacement(val parameters: Parameters) : PlacementModifier() { class EnormousPlacement(
data class Parameters(
/** /**
* How many chunks away to look for actual placements * How many chunks away to look for actual placements
* *
@ -51,16 +46,8 @@ abstract class AbstractEnormousPlacement(val parameters: Parameters) : Placement
/** /**
* Baseline placement modifiers, dictating how to appear in chunk * Baseline placement modifiers, dictating how to appear in chunk
*/ */
val prePlacementModifiers: List<PlacementModifier> = listOf(), val children: List<PlacementModifier>,
) : PlacementModifier() {
/**
* Post placement modifiers, operating on positions returned by this placement
*
* Generally, using this will yield better results
*/
val postPlacementModifiers: List<PlacementModifier> = listOf(),
)
private class GeneratedChunk(positions: Stream<BlockPos>) { private class GeneratedChunk(positions: Stream<BlockPos>) {
// TODO: memory inefficient // TODO: memory inefficient
private val positions = ArrayList<BlockPos>() private val positions = ArrayList<BlockPos>()
@ -78,8 +65,6 @@ abstract class AbstractEnormousPlacement(val parameters: Parameters) : Placement
} }
} }
protected abstract fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos>
private val level2cache = WeakHashMap<WorldGenLevel, Cache<ChunkPos, GeneratedChunk>>() private val level2cache = WeakHashMap<WorldGenLevel, Cache<ChunkPos, GeneratedChunk>>()
private val lock = ReentrantLock() private val lock = ReentrantLock()
@ -102,7 +87,7 @@ abstract class AbstractEnormousPlacement(val parameters: Parameters) : Placement
val dataStream = DataOutputStream(bytes) val dataStream = DataOutputStream(bytes)
dataStream.writeLong(context.level.seed) dataStream.writeLong(context.level.seed)
dataStream.writeLong(parameters.seedMix) dataStream.writeLong(seedMix)
dataStream.writeInt(pos.x) dataStream.writeInt(pos.x)
dataStream.writeInt(pos.z) dataStream.writeInt(pos.z)
@ -111,25 +96,24 @@ abstract class AbstractEnormousPlacement(val parameters: Parameters) : Placement
val random = PCG32RandomSource(hash.digestAsLong()) val random = PCG32RandomSource(hash.digestAsLong())
var stream = Stream.of(BlockPos(pos.minBlockX, 0, pos.minBlockZ)) var stream = Stream.of(BlockPos(pos.minBlockX, 0, pos.minBlockZ))
parameters.prePlacementModifiers.forEach { modifier -> stream = stream.flatMap { modifier.getPositions(context, random, it).sequential() } } children.forEach { modifier -> stream = stream.flatMap { modifier.getPositions(context, random, it).sequential() } }
stream = stream.flatMap { getPositions(it, random) }
parameters.postPlacementModifiers.forEach { modifier -> stream = stream.flatMap { modifier.getPositions(context, random, it).sequential() } }
return GeneratedChunk(stream) return GeneratedChunk(stream)
} }
final override fun getPositions(context: PlacementContext, random: RandomSource, pos: BlockPos): Stream<BlockPos> { override fun getPositions(context: PlacementContext, random: RandomSource, pos: BlockPos): Stream<BlockPos> {
val cache = getCache(context.level)
val cPos = ChunkPos(pos) val cPos = ChunkPos(pos)
val instances = ArrayList<GeneratedChunk>() val instances = ArrayList<GeneratedChunk>()
for (x in -parameters.chunkScanRange .. parameters.chunkScanRange) { for (x in -chunkScanRange .. chunkScanRange) {
for (z in -parameters.chunkScanRange .. parameters.chunkScanRange) { for (z in -chunkScanRange .. chunkScanRange) {
// floor, so chunk scan range of 1 will give square instead of diamond // floor, so chunk scan range of 1 will give square instead of diamond
val radius = sqrt(x.toDouble() * x + z.toDouble() * z).toInt() val radius = sqrt(x.toDouble() * x + z.toDouble() * z).toInt()
if (radius <= parameters.chunkScanRange) { if (radius <= chunkScanRange) {
val thisPos = ChunkPos(cPos.x + x, cPos.z + z) val thisPos = ChunkPos(cPos.x + x, cPos.z + z)
instances.add(getCache(context.level).get(thisPos) { computeChunk(context, thisPos) }) instances.add(cache.get(thisPos) { computeChunk(context, thisPos) })
} }
} }
} }
@ -137,14 +121,17 @@ abstract class AbstractEnormousPlacement(val parameters: Parameters) : Placement
return instances.stream().flatMap { it.getPositions(cPos) } return instances.stream().flatMap { it.getPositions(cPos) }
} }
override fun type(): PlacementModifierType<*> {
return MPlacementModifiers.ENORMOUS
}
companion object { companion object {
val PARAMETERS_CODEC: MapCodec<Parameters> = RecordCodecBuilder.mapCodec { val CODEC: MapCodec<EnormousPlacement> = RecordCodecBuilder.mapCodec {
it.group( it.group(
Codec.INT.minRange(0).fieldOf("chunk_scan_range").forGetter(Parameters::chunkScanRange), Codec.INT.minRange(0).fieldOf("chunk_scan_range").forGetter(EnormousPlacement::chunkScanRange),
Codec.LONG.fieldOf("seed_mix").forGetter(Parameters::seedMix), Codec.LONG.fieldOf("seed_mix").forGetter(EnormousPlacement::seedMix),
CODEC.listOf().optionalFieldOf("placement", listOf()).forGetter(Parameters::prePlacementModifiers), PlacementModifier.CODEC.listOf().optionalFieldOf("children", listOf()).forGetter(EnormousPlacement::children),
CODEC.listOf().optionalFieldOf("post_placement", listOf()).forGetter(Parameters::postPlacementModifiers), ).apply(it, ::EnormousPlacement)
).apply(it, ::Parameters)
} }
} }
} }

View File

@ -1,81 +0,0 @@
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 }
}
}

View File

@ -10,6 +10,8 @@ import net.minecraft.util.valueproviders.ConstantFloat
import net.minecraft.util.valueproviders.FloatProvider import net.minecraft.util.valueproviders.FloatProvider
import net.minecraft.util.valueproviders.IntProvider import net.minecraft.util.valueproviders.IntProvider
import net.minecraft.util.valueproviders.UniformFloat import net.minecraft.util.valueproviders.UniformFloat
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 net.minecraft.world.level.levelgen.placement.PlacementModifierType
import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.angleDifference import ru.dbotthepony.mc.otm.core.math.angleDifference
@ -28,7 +30,6 @@ import kotlin.math.sign
import kotlin.math.sin import kotlin.math.sin
class WormPlacement( class WormPlacement(
parameters: Parameters,
val length: IntProvider, val length: IntProvider,
val turnChanceXZ: BooleanProvider, val turnChanceXZ: BooleanProvider,
val turnChanceXY: BooleanProvider, val turnChanceXY: BooleanProvider,
@ -39,7 +40,7 @@ class WormPlacement(
val initialAngleXY: FloatProvider = DEFAULT_INITIAL_ANGLE_XY, val initialAngleXY: FloatProvider = DEFAULT_INITIAL_ANGLE_XY,
val maxTravelDown: Int = Int.MAX_VALUE, val maxTravelDown: Int = Int.MAX_VALUE,
val maxTravelUp: Int = Int.MAX_VALUE, val maxTravelUp: Int = Int.MAX_VALUE,
) : AbstractEnormousPlacement(parameters) { ) : PlacementModifier() {
private inner class Worm(private val random: RandomSource, private var position: Vector) { private inner class Worm(private val random: RandomSource, private var position: Vector) {
private var remainingDistance = length.sample(random) private var remainingDistance = length.sample(random)
private var xzRotation = random.nextDouble(-PI / 2.0, PI / 2.0) private var xzRotation = random.nextDouble(-PI / 2.0, PI / 2.0)
@ -129,7 +130,7 @@ class WormPlacement(
} }
} }
override fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos> { override fun getPositions(context: PlacementContext, random: RandomSource, center: BlockPos): Stream<BlockPos> {
val worms = ArrayList<Worm>() val worms = ArrayList<Worm>()
worms.add(Worm(random, Vector.ZERO)) worms.add(Worm(random, Vector.ZERO))
val positions = ArrayList<BlockPos>() val positions = ArrayList<BlockPos>()
@ -200,7 +201,6 @@ class WormPlacement(
val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec { val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec {
it.group( it.group(
PARAMETERS_CODEC.forGetter(WormPlacement::parameters),
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::length), IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::length),
BooleanProvider.CODEC.fieldOf("turn_chance_xz").forGetter(WormPlacement::turnChanceXZ), BooleanProvider.CODEC.fieldOf("turn_chance_xz").forGetter(WormPlacement::turnChanceXZ),
BooleanProvider.CODEC.fieldOf("turn_chance_xy").forGetter(WormPlacement::turnChanceXY), BooleanProvider.CODEC.fieldOf("turn_chance_xy").forGetter(WormPlacement::turnChanceXY),