Add enhanced variants for placement modifiers
This commit is contained in:
parent
ba492e0cee
commit
07b295ce45
@ -38,8 +38,13 @@ import ru.dbotthepony.mc.otm.worldgen.feature.DebugPlacerFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.EnhancedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.ChainPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedChainPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedCountPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedSplitPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.SplitPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.wrap
|
||||
|
||||
private object ConfiguredFeatures {
|
||||
val TRITANIUM_ORE = key("tritanium_ore")
|
||||
@ -133,7 +138,7 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
.then(InSquarePlacement.spread())
|
||||
.then(HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(-40), 15.0)))
|
||||
.then(
|
||||
SplitPlacement(
|
||||
EnhancedSplitPlacement(
|
||||
// "heart"
|
||||
EllipsoidPlacement(
|
||||
count = UniformInt.of(600, 900),
|
||||
@ -145,8 +150,8 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
z = ClampedNormalFloat.of(0f, 0.4f, -1f, 1f),
|
||||
),
|
||||
// "branches"
|
||||
ChainPlacement(
|
||||
CountPlacement.of(UniformInt.of(2, 7)),
|
||||
EnhancedChainPlacement(
|
||||
EnhancedCountPlacement(UniformInt.of(2, 7)),
|
||||
WormPlacement(
|
||||
length = UniformInt.of(60, 120),
|
||||
turnRateXY = WormPlacement.normalDistributedTurnRate(2f, 3f),
|
||||
@ -201,7 +206,7 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
xLength = UniformFloat.of(30f, 70f),
|
||||
yLength = UniformFloat.of(40f, 90f),
|
||||
zLength = UniformFloat.of(30f, 70f),
|
||||
)
|
||||
) as EnhancedPlacementModifier
|
||||
)
|
||||
.then(ore)
|
||||
.build(
|
||||
|
@ -4,20 +4,34 @@ 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.registry.MDeferredRegister
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistries
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.ChainPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedChainPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedCountPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedSplitPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.SplitPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
|
||||
|
||||
object MPlacementModifiers {
|
||||
private val registry = MDeferredRegister(BuiltInRegistries.PLACEMENT_MODIFIER_TYPE)
|
||||
private val enhancedRegistry = MDeferredRegister(MRegistries.PLACEMENT_MODIFIER)
|
||||
|
||||
internal fun register(bus: IEventBus) {
|
||||
registry.register(bus)
|
||||
enhancedRegistry.register(bus)
|
||||
}
|
||||
|
||||
val ELLIPSOID_PLACEMENT by registry.register("ellipsoid") { PlacementModifierType { EllipsoidPlacement.CODEC } }
|
||||
val WORM_PLACEMENT by registry.register("worm") { PlacementModifierType { WormPlacement.CODEC } }
|
||||
val SPLIT by registry.register("split") { PlacementModifierType { SplitPlacement.CODEC} }
|
||||
val CHAIN by registry.register("chain") { PlacementModifierType { ChainPlacement.CODEC} }
|
||||
val CHAIN by registry.register("chain") { PlacementModifierType { ChainPlacement.CODEC } }
|
||||
|
||||
init {
|
||||
enhancedRegistry.register("ellipsoid") { EllipsoidPlacement.Companion }
|
||||
enhancedRegistry.register("worm") { WormPlacement.Companion }
|
||||
enhancedRegistry.register("split") { EnhancedSplitPlacement.Companion }
|
||||
enhancedRegistry.register("chain") { EnhancedChainPlacement.Companion }
|
||||
enhancedRegistry.register("count") { EnhancedCountPlacement.Companion }
|
||||
}
|
||||
}
|
||||
|
@ -297,6 +297,11 @@ object EnhancedPlacedFeature : Feature<EnhancedPlacedFeature.Config>(
|
||||
return then(EnhancedFeature.Wrapper.configure(action))
|
||||
}
|
||||
|
||||
inline fun fork(configurator: Builder.() -> Unit): Builder {
|
||||
configurator(this)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun buildNode(): Node {
|
||||
return Node(children.map { it.buildNode() }, contents)
|
||||
}
|
||||
|
8
src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/Ext.kt
Normal file
8
src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/Ext.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen
|
||||
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacementModifier
|
||||
|
||||
fun PlacementModifier.wrap(): EnhancedPlacementModifier {
|
||||
return EnhancedPlacementModifier.Wrapper(this)
|
||||
}
|
@ -15,6 +15,7 @@ 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.registry.data.MPlacementModifiers
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import java.util.stream.Stream
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.roundToInt
|
||||
@ -57,22 +58,18 @@ data class EllipsoidPlacement(
|
||||
* Ellipsoid size sampler on Y axis
|
||||
*/
|
||||
val yLength: FloatProvider,
|
||||
) : PlacementModifier() {
|
||||
) : PlacementModifier(), EnhancedPlacementModifier {
|
||||
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> {
|
||||
private fun evaluate(random: RandomSource, position: BlockPos, result: ArrayList<BlockPos>) {
|
||||
val count = count.sample(random)
|
||||
|
||||
if (count <= 0)
|
||||
return Stream.empty()
|
||||
return
|
||||
|
||||
val xLength = xLength.sample(random)
|
||||
val zLength = zLength.sample(random)
|
||||
@ -82,7 +79,9 @@ data class EllipsoidPlacement(
|
||||
val zPow = zLength * zLength
|
||||
val yPow = yLength * yLength
|
||||
|
||||
return Stream.generate {
|
||||
result.ensureCapacity(result.size + count + 1)
|
||||
|
||||
Stream.generate {
|
||||
val x = this.x.sample(random) * xLength
|
||||
val y = this.y.sample(random) * yLength
|
||||
val z = this.z.sample(random) * zLength
|
||||
@ -99,13 +98,33 @@ data class EllipsoidPlacement(
|
||||
.distinct()
|
||||
.limit(count.toLong())
|
||||
.map { it + position }
|
||||
.forEach { result.add(it) }
|
||||
}
|
||||
|
||||
override fun getPositions(
|
||||
context: PlacementContext,
|
||||
random: RandomSource,
|
||||
position: BlockPos
|
||||
): Stream<BlockPos> {
|
||||
val result = ArrayList<BlockPos>()
|
||||
evaluate(random, position, result)
|
||||
return result.stream()
|
||||
}
|
||||
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<BlockPos>): List<BlockPos> {
|
||||
val result = ArrayList<BlockPos>()
|
||||
positions.forEach { evaluate(context.random, it, result) }
|
||||
return result
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
get() = Companion
|
||||
|
||||
override fun type(): PlacementModifierType<*> {
|
||||
return MPlacementModifiers.ELLIPSOID_PLACEMENT
|
||||
}
|
||||
|
||||
companion object {
|
||||
companion object : EnhancedPlacementModifier.Type<EllipsoidPlacement> {
|
||||
val CODEC: MapCodec<EllipsoidPlacement> by lazy {
|
||||
RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
@ -119,5 +138,8 @@ data class EllipsoidPlacement(
|
||||
).apply(it, ::EllipsoidPlacement)
|
||||
}
|
||||
}
|
||||
|
||||
override val codec: MapCodec<EllipsoidPlacement>
|
||||
get() = CODEC
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
|
||||
/**
|
||||
* Daisy-chaining placements. Required only when using placement modifiers which operate on children list
|
||||
*/
|
||||
class EnhancedChainPlacement(
|
||||
val children: List<EnhancedPlacementModifier>
|
||||
) : EnhancedPlacementModifier {
|
||||
constructor(vararg children: EnhancedPlacementModifier) : this(ImmutableList.copyOf(children))
|
||||
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<BlockPos>): List<BlockPos> {
|
||||
var current = positions
|
||||
children.forEach { current = it.evaluate(context, current) }
|
||||
return current
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EnhancedChainPlacement> {
|
||||
override val codec: MapCodec<EnhancedChainPlacement> by lazy {
|
||||
Codec.list(EnhancedPlacementModifier.CODEC).xmap(::EnhancedChainPlacement, EnhancedChainPlacement::children).fieldOf("children")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.valueproviders.IntProvider
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
|
||||
class EnhancedCountPlacement(val provider: IntProvider) : EnhancedPlacementModifier {
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<BlockPos>): List<BlockPos> {
|
||||
val count = provider.sample(context.random)
|
||||
|
||||
if (count <= 0) {
|
||||
return listOf()
|
||||
} else if (count == 1) {
|
||||
return positions
|
||||
} else {
|
||||
val result = ArrayList<BlockPos>()
|
||||
result.ensureCapacity(positions.size * count)
|
||||
for (i in 0 until count) result.addAll(positions)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EnhancedCountPlacement> {
|
||||
override val codec: MapCodec<EnhancedCountPlacement> = IntProvider.CODEC.xmap(::EnhancedCountPlacement, EnhancedCountPlacement::provider).fieldOf("count")
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.RandomSource
|
||||
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.registry.data.MPlacementModifiers
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import java.util.stream.Collectors
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
* Or "shard" placement, if you will.
|
||||
*
|
||||
* Basically, allows multiple [PlacementModifier]s to split/branch off from provided point.
|
||||
*/
|
||||
class EnhancedSplitPlacement(
|
||||
val children: List<EnhancedPlacementModifier>
|
||||
) : EnhancedPlacementModifier {
|
||||
constructor(vararg children: EnhancedPlacementModifier) : this(ImmutableList.copyOf(children))
|
||||
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<BlockPos>): List<BlockPos> {
|
||||
val result = ArrayList<BlockPos>()
|
||||
children.forEach { result.addAll(it.evaluate(context, positions)) }
|
||||
return result
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EnhancedSplitPlacement> {
|
||||
override val codec: MapCodec<EnhancedSplitPlacement> by lazy {
|
||||
Codec.list(EnhancedPlacementModifier.CODEC).xmap(::EnhancedSplitPlacement, EnhancedSplitPlacement::children).fieldOf("children")
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ 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 ru.dbotthepony.mc.otm.core.addAll
|
||||
import ru.dbotthepony.mc.otm.core.math.Vector
|
||||
import ru.dbotthepony.mc.otm.core.math.angleDifference
|
||||
import ru.dbotthepony.mc.otm.core.math.normalizeAngle
|
||||
@ -22,6 +23,7 @@ import ru.dbotthepony.mc.otm.core.nextDouble
|
||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||
import ru.dbotthepony.mc.otm.data.world.BooleanProvider
|
||||
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import java.util.stream.Stream
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.absoluteValue
|
||||
@ -43,7 +45,7 @@ class WormPlacement(
|
||||
val initialAngleXY: FloatProvider = DEFAULT_INITIAL_ANGLE_XY,
|
||||
val maxTravelDown: Int = Int.MAX_VALUE,
|
||||
val maxTravelUp: Int = Int.MAX_VALUE,
|
||||
) : PlacementModifier() {
|
||||
) : PlacementModifier(), EnhancedPlacementModifier {
|
||||
private inner class Worm(private val random: RandomSource, private var position: Vector) {
|
||||
private var remainingDistance = length.sample(random)
|
||||
private var xzRotation = random.nextDouble(-PI, PI)
|
||||
@ -133,28 +135,44 @@ class WormPlacement(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPositions(context: PlacementContext, random: RandomSource, center: BlockPos): Stream<BlockPos> {
|
||||
private fun evaluate(random: RandomSource, position: BlockPos, results: ArrayList<BlockPos>) {
|
||||
val worms = ArrayList<Worm>()
|
||||
worms.add(Worm(random, Vector.ZERO))
|
||||
val positions = ArrayList<BlockPos>()
|
||||
positions.add(BlockPos.ZERO)
|
||||
results.add(position)
|
||||
|
||||
while (worms.isNotEmpty()) {
|
||||
worms.removeIf {
|
||||
val pos = it.follow()
|
||||
if (pos != null) positions.add(pos)
|
||||
if (pos != null) results.add(pos + position)
|
||||
it.hasFinished
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return positions.stream().map { it + center }
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<BlockPos>): List<BlockPos> {
|
||||
if (positions.isEmpty())
|
||||
return positions
|
||||
else {
|
||||
val results = ArrayList<BlockPos>()
|
||||
positions.forEach { evaluate(context.random, it, results) }
|
||||
return results
|
||||
}
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
get() = Companion
|
||||
|
||||
override fun getPositions(context: PlacementContext, random: RandomSource, center: BlockPos): Stream<BlockPos> {
|
||||
val results = ArrayList<BlockPos>()
|
||||
evaluate(random, center, results)
|
||||
return results.stream()
|
||||
}
|
||||
|
||||
override fun type(): PlacementModifierType<*> {
|
||||
return MPlacementModifiers.WORM_PLACEMENT
|
||||
}
|
||||
|
||||
companion object {
|
||||
companion object : EnhancedPlacementModifier.Type<WormPlacement> {
|
||||
private fun increment(value: Float): Float {
|
||||
var i = 1f
|
||||
|
||||
@ -202,19 +220,24 @@ class WormPlacement(
|
||||
|
||||
private const val DEGREES_TO_RADIANS = PI.toFloat() / 180f
|
||||
|
||||
val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::length),
|
||||
BooleanProvider.CODEC.fieldOf("turn_chance_xz").forGetter(WormPlacement::turnChanceXZ),
|
||||
BooleanProvider.CODEC.fieldOf("turn_chance_xy").forGetter(WormPlacement::turnChanceXY),
|
||||
FloatProvider.CODEC.fieldOf("turn_speed_xz").forGetter(WormPlacement::turnSpeedXZ),
|
||||
FloatProvider.CODEC.fieldOf("turn_speed_xy").forGetter(WormPlacement::turnSpeedXY),
|
||||
FloatProvider.CODEC.fieldOf("turn_rate_xz").forGetter(WormPlacement::turnRateXZ),
|
||||
FloatProvider.CODEC.fieldOf("turn_rate_xy").forGetter(WormPlacement::turnRateXY),
|
||||
FloatProvider.CODEC.optionalFieldOf("initial_angle_xy", DEFAULT_INITIAL_ANGLE_XY).forGetter(WormPlacement::initialAngleXY),
|
||||
Codec.INT.minRange(1).optionalFieldOf("max_travel_down", Int.MAX_VALUE).forGetter(WormPlacement::maxTravelDown),
|
||||
Codec.INT.minRange(1).optionalFieldOf("max_travel_up", Int.MAX_VALUE).forGetter(WormPlacement::maxTravelUp),
|
||||
).apply(it, ::WormPlacement)
|
||||
val CODEC: MapCodec<WormPlacement> by lazy {
|
||||
RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::length),
|
||||
BooleanProvider.CODEC.fieldOf("turn_chance_xz").forGetter(WormPlacement::turnChanceXZ),
|
||||
BooleanProvider.CODEC.fieldOf("turn_chance_xy").forGetter(WormPlacement::turnChanceXY),
|
||||
FloatProvider.CODEC.fieldOf("turn_speed_xz").forGetter(WormPlacement::turnSpeedXZ),
|
||||
FloatProvider.CODEC.fieldOf("turn_speed_xy").forGetter(WormPlacement::turnSpeedXY),
|
||||
FloatProvider.CODEC.fieldOf("turn_rate_xz").forGetter(WormPlacement::turnRateXZ),
|
||||
FloatProvider.CODEC.fieldOf("turn_rate_xy").forGetter(WormPlacement::turnRateXY),
|
||||
FloatProvider.CODEC.optionalFieldOf("initial_angle_xy", DEFAULT_INITIAL_ANGLE_XY).forGetter(WormPlacement::initialAngleXY),
|
||||
Codec.INT.minRange(1).optionalFieldOf("max_travel_down", Int.MAX_VALUE).forGetter(WormPlacement::maxTravelDown),
|
||||
Codec.INT.minRange(1).optionalFieldOf("max_travel_up", Int.MAX_VALUE).forGetter(WormPlacement::maxTravelUp),
|
||||
).apply(it, ::WormPlacement)
|
||||
}
|
||||
}
|
||||
|
||||
override val codec: MapCodec<WormPlacement>
|
||||
get() = CODEC
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user