From 07b295ce4597166510030a54f2e14fc931b6ff28 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 25 Mar 2025 00:07:55 +0700 Subject: [PATCH] Add enhanced variants for placement modifiers --- .../ru/dbotthepony/mc/otm/datagen/WorldGen.kt | 13 ++-- .../otm/registry/data/MPlacementModifiers.kt | 16 ++++- .../mc/otm/worldgen/EnhancedPlacedFeature.kt | 5 ++ .../ru/dbotthepony/mc/otm/worldgen/Ext.kt | 8 +++ .../worldgen/placement/EllipsoidPlacement.kt | 40 +++++++++--- .../placement/EnhancedChainPlacement.kt | 32 ++++++++++ .../placement/EnhancedCountPlacement.kt | 30 +++++++++ .../placement/EnhancedSplitPlacement.kt | 40 ++++++++++++ .../otm/worldgen/placement/WormPlacement.kt | 63 +++++++++++++------ 9 files changed, 213 insertions(+), 34 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/Ext.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedChainPlacement.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedCountPlacement.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedSplitPlacement.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 54c7f57eb..d805e41db 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt @@ -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) { .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) { 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) { xLength = UniformFloat.of(30f, 70f), yLength = UniformFloat.of(40f, 90f), zLength = UniformFloat.of(30f, 70f), - ) + ) as EnhancedPlacementModifier ) .then(ore) .build( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/data/MPlacementModifiers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/data/MPlacementModifiers.kt index 8049d21c1..499c7f7a7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/data/MPlacementModifiers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/data/MPlacementModifiers.kt @@ -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 } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/EnhancedPlacedFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/EnhancedPlacedFeature.kt index 5482cdcb1..840bbd662 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/EnhancedPlacedFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/EnhancedPlacedFeature.kt @@ -297,6 +297,11 @@ object EnhancedPlacedFeature : Feature( 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) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/Ext.kt new file mode 100644 index 000000000..207faf3f2 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/Ext.kt @@ -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) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EllipsoidPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EllipsoidPlacement.kt index 7a28d1053..68a7011aa 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EllipsoidPlacement.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EllipsoidPlacement.kt @@ -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 { + private fun evaluate(random: RandomSource, position: BlockPos, result: ArrayList) { 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 { + val result = ArrayList() + evaluate(random, position, result) + return result.stream() + } + + override fun evaluate(context: EnhancedPlacementContext, positions: List): List { + val result = ArrayList() + 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 { val CODEC: MapCodec by lazy { RecordCodecBuilder.mapCodec { it.group( @@ -119,5 +138,8 @@ data class EllipsoidPlacement( ).apply(it, ::EllipsoidPlacement) } } + + override val codec: MapCodec + get() = CODEC } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedChainPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedChainPlacement.kt new file mode 100644 index 000000000..2dbd19dad --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedChainPlacement.kt @@ -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 { + constructor(vararg children: EnhancedPlacementModifier) : this(ImmutableList.copyOf(children)) + + override fun evaluate(context: EnhancedPlacementContext, positions: List): List { + var current = positions + children.forEach { current = it.evaluate(context, current) } + return current + } + + override val type: EnhancedPlacementModifier.Type<*> + get() = Companion + + companion object : EnhancedPlacementModifier.Type { + override val codec: MapCodec by lazy { + Codec.list(EnhancedPlacementModifier.CODEC).xmap(::EnhancedChainPlacement, EnhancedChainPlacement::children).fieldOf("children") + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedCountPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedCountPlacement.kt new file mode 100644 index 000000000..5e665a09c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedCountPlacement.kt @@ -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): List { + val count = provider.sample(context.random) + + if (count <= 0) { + return listOf() + } else if (count == 1) { + return positions + } else { + val result = ArrayList() + 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 { + override val codec: MapCodec = IntProvider.CODEC.xmap(::EnhancedCountPlacement, EnhancedCountPlacement::provider).fieldOf("count") + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedSplitPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedSplitPlacement.kt new file mode 100644 index 000000000..6e3d97eb3 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnhancedSplitPlacement.kt @@ -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 { + constructor(vararg children: EnhancedPlacementModifier) : this(ImmutableList.copyOf(children)) + + override fun evaluate(context: EnhancedPlacementContext, positions: List): List { + val result = ArrayList() + children.forEach { result.addAll(it.evaluate(context, positions)) } + return result + } + + override val type: EnhancedPlacementModifier.Type<*> + get() = Companion + + companion object : EnhancedPlacementModifier.Type { + override val codec: MapCodec by lazy { + Codec.list(EnhancedPlacementModifier.CODEC).xmap(::EnhancedSplitPlacement, EnhancedSplitPlacement::children).fieldOf("children") + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/WormPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/WormPlacement.kt index a1987b3ba..c369998e3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/WormPlacement.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/WormPlacement.kt @@ -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 { + private fun evaluate(random: RandomSource, position: BlockPos, results: ArrayList) { val worms = ArrayList() worms.add(Worm(random, Vector.ZERO)) - val positions = ArrayList() - 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): List { + if (positions.isEmpty()) + return positions + else { + val results = ArrayList() + 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 { + val results = ArrayList() + evaluate(random, center, results) + return results.stream() } override fun type(): PlacementModifierType<*> { return MPlacementModifiers.WORM_PLACEMENT } - companion object { + companion object : EnhancedPlacementModifier.Type { 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 = 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 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 + get() = CODEC } }