Unify placement modifier and feature under single "placement" interface, greatly simplifying and empowering things at the same time
This commit is contained in:
parent
2e104dcbce
commit
e2369b3a24
@ -34,22 +34,20 @@ import ru.dbotthepony.mc.otm.registry.game.MBlocks
|
||||
import ru.dbotthepony.mc.otm.registry.data.MWorldGenFeatures
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.BlackHolePlacerFeature
|
||||
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
|
||||
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.EnhancedPlacement
|
||||
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")
|
||||
val TRITANIUM_ORE_SMALL = key("tritanium_ore_small")
|
||||
val DILITHIUM = ekey("dilithium")
|
||||
val DILITHIUM = key("dilithium")
|
||||
val BLACK_HOLE = key("black_hole")
|
||||
|
||||
private fun key(name: String): ResourceKey<ConfiguredFeature<*, *>> {
|
||||
@ -62,17 +60,6 @@ private object ConfiguredFeatures {
|
||||
}
|
||||
|
||||
fun registerEnhancedConfiguredFeatures(context: BootstrapContext<EnhancedFeature.Configured<*, *>>) {
|
||||
val stone = TagMatchTest(BlockTags.STONE_ORE_REPLACEABLES)
|
||||
val deepslate = TagMatchTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES)
|
||||
|
||||
run {
|
||||
val target = listOf(
|
||||
OreConfiguration.target(stone, MBlocks.DILITHIUM_ORE.defaultBlockState()),
|
||||
OreConfiguration.target(deepslate, MBlocks.DEEPSLATE_DILITHIUM_ORE.defaultBlockState()),
|
||||
)
|
||||
|
||||
context.register(ConfiguredFeatures.DILITHIUM, EnhancedFeature.Wrapper.configure(ConfiguredFeature(Feature.REPLACE_SINGLE_BLOCK, ReplaceBlockConfiguration(target))))
|
||||
}
|
||||
}
|
||||
|
||||
fun registerConfiguredFeatures(context: BootstrapContext<ConfiguredFeature<*, *>>) {
|
||||
@ -90,6 +77,15 @@ fun registerConfiguredFeatures(context: BootstrapContext<ConfiguredFeature<*, *>
|
||||
//context.register(ConfiguredFeatures.TRITANIUM_ORE_SMALL, ConfiguredFeature(MWorldGenFeatures.DEBUG_PLACEMENT, DebugPlacerFeature.Config(MBlocks.TRITANIUM_ORE.defaultBlockState())))
|
||||
}
|
||||
|
||||
run {
|
||||
val target = listOf(
|
||||
OreConfiguration.target(stone, MBlocks.DILITHIUM_ORE.defaultBlockState()),
|
||||
OreConfiguration.target(deepslate, MBlocks.DEEPSLATE_DILITHIUM_ORE.defaultBlockState()),
|
||||
)
|
||||
|
||||
context.register(ConfiguredFeatures.DILITHIUM, ConfiguredFeature(Feature.REPLACE_SINGLE_BLOCK, ReplaceBlockConfiguration(target)))
|
||||
}
|
||||
|
||||
context.register(ConfiguredFeatures.BLACK_HOLE, ConfiguredFeature(
|
||||
MWorldGenFeatures.BLACK_HOLE_PLACER,
|
||||
BlackHolePlacerFeature.Config(Decimal("0.25"), Decimal(1))))
|
||||
@ -134,11 +130,16 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
|
||||
context.register(
|
||||
PlacedFeatures.WORM_TRITANIUM,
|
||||
EnhancedPlacedFeature.Builder(RarityFilter.onAverageOnceEvery(140))
|
||||
.then(InSquarePlacement.spread())
|
||||
.then(HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(-40), 15.0)))
|
||||
.then(
|
||||
EnhancedPlacedFeature.configure(
|
||||
chunkScanRange = 24,
|
||||
seedMix = 9284343575495L,
|
||||
root = EnhancedChainPlacement(
|
||||
RarityFilter.onAverageOnceEvery(140).wrap(),
|
||||
InSquarePlacement.spread().wrap(),
|
||||
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(-40), 15.0)).wrap(),
|
||||
|
||||
EnhancedSplitPlacement(
|
||||
EnhancedSplitPlacement.Mode.COMBINE,
|
||||
// "heart"
|
||||
EllipsoidPlacement(
|
||||
count = UniformInt.of(600, 900),
|
||||
@ -174,18 +175,16 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
z = ClampedNormalFloat.of(0f, 0.2f, -1f, 1f),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(configured.getOrThrow(ConfiguredFeatures.TRITANIUM_ORE_SMALL))
|
||||
.build(
|
||||
chunkScanRange = 24,
|
||||
seedMix = 9284343575495L,
|
||||
),
|
||||
|
||||
configured.getOrThrow(ConfiguredFeatures.TRITANIUM_ORE_SMALL).placement()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
run {
|
||||
val ore = econfigured.getOrThrow(ConfiguredFeatures.DILITHIUM)
|
||||
val ore = configured.getOrThrow(ConfiguredFeatures.DILITHIUM)
|
||||
|
||||
val ringularity = OneOfFloatProvider.of(
|
||||
ClampedNormalFloat.of(0.4f, 0.2f, -2f, 2f),
|
||||
@ -194,10 +193,13 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
|
||||
context.register(
|
||||
PlacedFeatures.DILITHIUM,
|
||||
EnhancedPlacedFeature.Builder(RarityFilter.onAverageOnceEvery(120))
|
||||
.then(InSquarePlacement.spread())
|
||||
.then(HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(0), 15.0)))
|
||||
.then(
|
||||
EnhancedPlacedFeature.configure(
|
||||
chunkScanRange = 6,
|
||||
seedMix = 237483209523709234L,
|
||||
root = EnhancedChainPlacement(
|
||||
RarityFilter.onAverageOnceEvery(120).wrap(),
|
||||
InSquarePlacement.spread().wrap(),
|
||||
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(0), 15.0)).wrap(),
|
||||
EllipsoidPlacement(
|
||||
x = ringularity,
|
||||
y = ringularity,
|
||||
@ -206,13 +208,10 @@ 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(
|
||||
chunkScanRange = 6,
|
||||
seedMix = 237483209523709234L,
|
||||
),
|
||||
ore.placement()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,8 @@ import net.neoforged.bus.api.EventPriority
|
||||
import net.neoforged.fml.common.Mod
|
||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchDescription
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchDescriptions
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchManager
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchResult
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchResults
|
||||
import ru.dbotthepony.mc.otm.player.android.feature.EnderTeleporterFeature
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||
@ -93,7 +91,7 @@ import ru.dbotthepony.mc.otm.server.MCommands
|
||||
import ru.dbotthepony.mc.otm.storage.StorageStack
|
||||
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.EnhancedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacement
|
||||
import thedarkcolour.kotlinforforge.neoforge.forge.DIST
|
||||
import thedarkcolour.kotlinforforge.neoforge.forge.FORGE_BUS
|
||||
import thedarkcolour.kotlinforforge.neoforge.forge.LOADING_CONTEXT
|
||||
@ -142,7 +140,7 @@ object OverdriveThatMatters {
|
||||
DecimalProvider.register(MOD_BUS)
|
||||
BooleanProvider.register(MOD_BUS)
|
||||
EnhancedFeature.register(MOD_BUS)
|
||||
EnhancedPlacementModifier.register(MOD_BUS)
|
||||
EnhancedPlacement.register(MOD_BUS)
|
||||
AndroidResearchDescriptions.register(MOD_BUS)
|
||||
AndroidResearchResults.register(MOD_BUS)
|
||||
|
||||
|
@ -13,9 +13,8 @@ import ru.dbotthepony.mc.otm.player.android.AndroidFeatureType
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchDescription
|
||||
import ru.dbotthepony.mc.otm.player.android.AndroidResearchResult
|
||||
import ru.dbotthepony.mc.otm.storage.StorageStack
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.EnhancedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacement
|
||||
|
||||
object MRegistries {
|
||||
private fun <T> k(name: String): ResourceKey<Registry<T>> {
|
||||
@ -33,5 +32,5 @@ object MRegistries {
|
||||
val BOOLEAN_PROVIDER = k<BooleanProvider.Type<*>>("boolean_provider")
|
||||
val FEATURE = k<EnhancedFeature<*>>("feature")
|
||||
val CONFIGURED_FEATURE = k<EnhancedFeature.Configured<*, *>>("configured_feature")
|
||||
val PLACEMENT_MODIFIER = k<EnhancedPlacementModifier.Type<*>>("placement_modifier")
|
||||
val PLACEMENT_MODIFIER = k<EnhancedPlacement.Type<*>>("placement_modifier")
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ 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.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
|
||||
@ -28,6 +29,7 @@ object MPlacementModifiers {
|
||||
val CHAIN by registry.register("chain") { PlacementModifierType { ChainPlacement.CODEC } }
|
||||
|
||||
init {
|
||||
enhancedRegistry.register("feature") { EnhancedFeature.ConfiguredWrapper.Companion }
|
||||
enhancedRegistry.register("ellipsoid") { EllipsoidPlacement.Companion }
|
||||
enhancedRegistry.register("worm") { WormPlacement.Companion }
|
||||
enhancedRegistry.register("split") { EnhancedSplitPlacement.Companion }
|
||||
|
@ -10,7 +10,6 @@ import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.core.BlockPos
|
||||
@ -26,122 +25,38 @@ import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfigur
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier
|
||||
import ru.dbotthepony.kommons.util.XXHash64
|
||||
import ru.dbotthepony.mc.otm.core.collect.BlockPosSet
|
||||
import ru.dbotthepony.mc.otm.core.collect.Vec3iHashStrategy
|
||||
import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource
|
||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.EnhancedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacement
|
||||
import java.io.DataOutputStream
|
||||
import java.time.Duration
|
||||
import java.util.LinkedList
|
||||
import kotlin.math.sqrt
|
||||
|
||||
private object NodeCodec : Codec<EnhancedPlacedFeature.Node> {
|
||||
private val list = Codec.list(this)
|
||||
|
||||
override fun <T : Any?> encode(input: EnhancedPlacedFeature.Node, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
val result = HashMap<T, T>()
|
||||
|
||||
if (input.children.isNotEmpty()) {
|
||||
val re = list.encodeStart(ops, input.children)
|
||||
|
||||
if (re.isError)
|
||||
return re
|
||||
|
||||
result[ops.createString("children")] = re.resultOrPartial().get()
|
||||
}
|
||||
|
||||
if (input.contents.left().isPresent) {
|
||||
val re = EnhancedPlacementModifier.CODEC.encodeStart(ops, input.contents.left().get())
|
||||
|
||||
if (re.isError)
|
||||
return DataResult.error { "Failed to serialize placement modifier: ${re.error().get().message()}" }
|
||||
|
||||
result[ops.createString("modifier")] = re.resultOrPartial().get()
|
||||
} else {
|
||||
val re = EnhancedFeature.CODEC.encodeStart(ops, input.contents.right().get())
|
||||
|
||||
if (re.isError)
|
||||
return DataResult.error { "Failed to serialize feature: ${re.error().get().message()}" }
|
||||
|
||||
result[ops.createString("feature")] = re.resultOrPartial().get()
|
||||
}
|
||||
|
||||
return ops.mergeToMap(prefix, result)
|
||||
}
|
||||
|
||||
override fun <T : Any?> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<EnhancedPlacedFeature.Node, T>> {
|
||||
return ops.getMap(input).flatMap {
|
||||
val children = it.get("children")
|
||||
val modifier = it.get("modifier")
|
||||
val feature = it.get("feature")
|
||||
|
||||
if (modifier != null && feature != null) {
|
||||
return@flatMap DataResult.error { "Enhanced feature placement node should have either modifier or feature, but both are present" }
|
||||
} else if (modifier == null && feature == null) {
|
||||
return@flatMap DataResult.error { "Enhanced feature placement node contains no modifier and no feature" }
|
||||
}
|
||||
|
||||
val deserializeChildren: List<EnhancedPlacedFeature.Node>
|
||||
|
||||
if (children != null) {
|
||||
val result = list.decode(ops, children)
|
||||
|
||||
if (result.isError)
|
||||
return@flatMap DataResult.error { result.error().get().message() }
|
||||
|
||||
deserializeChildren = result.map { it.first }.getOrThrow()
|
||||
} else {
|
||||
deserializeChildren = emptyList()
|
||||
}
|
||||
|
||||
if (modifier != null) {
|
||||
return@flatMap EnhancedPlacementModifier.CODEC.decode(ops, modifier).map { Pair(EnhancedPlacedFeature.Node(deserializeChildren, Either.left(it.first)), ops.empty()) }
|
||||
} else {
|
||||
return@flatMap EnhancedFeature.CODEC.decode(ops, feature).map { Pair(EnhancedPlacedFeature.Node(deserializeChildren, Either.right(it.first)), ops.empty()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object EnhancedPlacedFeature : Feature<EnhancedPlacedFeature.Config>(
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
Codec.INT.minRange(0).fieldOf("chunk_scan_range").forGetter(Config::chunkScanRange),
|
||||
Codec.LONG.fieldOf("seed_mix").forGetter(Config::seedMix),
|
||||
NodeCodec.fieldOf("root").forGetter(Config::root),
|
||||
EnhancedPlacement.CODEC.fieldOf("root").forGetter(Config::root),
|
||||
).apply(it, ::Config)
|
||||
}
|
||||
) {
|
||||
class Node(val children: List<Node>, val contents: Either<EnhancedPlacementModifier, Holder<EnhancedFeature.Configured<*, *>>>){
|
||||
fun evaluate(context: EnhancedPlacementContext) {
|
||||
evaluate(context, listOf(PlacementPos(BlockPos(context.origin.minBlockX, 0, context.origin.minBlockZ), PlacementVariableMap())))
|
||||
}
|
||||
|
||||
private fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>) {
|
||||
val actualPositions = if (contents.left().isPresent) {
|
||||
contents.left().get().evaluate(context, positions)
|
||||
} else {
|
||||
positions
|
||||
}
|
||||
|
||||
if (contents.right().isPresent) {
|
||||
context.place(actualPositions, contents.right().get().value())
|
||||
}
|
||||
|
||||
children.forEach {
|
||||
it.evaluate(context.push(), actualPositions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val emptyVariableMap = PlacementVariableMap()
|
||||
|
||||
fun configure(
|
||||
chunkScanRange: Int,
|
||||
seedMix: Long,
|
||||
root: EnhancedPlacement
|
||||
): PlacedFeature {
|
||||
return PlacedFeature(Holder.direct(ConfiguredFeature(EnhancedPlacedFeature, Config(chunkScanRange, seedMix, root))), listOf())
|
||||
}
|
||||
|
||||
class Config(
|
||||
val chunkScanRange: Int,
|
||||
val seedMix: Long,
|
||||
val root: Node,
|
||||
val root: EnhancedPlacement,
|
||||
) : FeatureConfiguration {
|
||||
private class GeneratedChunk : EnhancedPlacementContext.Placer {
|
||||
private data class Placement(val context: EnhancedPlacementContext, val positions: ObjectRBTreeSet<PlacementPos>, val feature: EnhancedFeature.Configured<*, *>)
|
||||
@ -215,7 +130,7 @@ object EnhancedPlacedFeature : Feature<EnhancedPlacedFeature.Config>(
|
||||
|
||||
val chunk = GeneratedChunk()
|
||||
val enhancedContext = EnhancedPlacementContext(context.level(), context.chunkGenerator(), random, chunkPos, chunk)
|
||||
root.evaluate(enhancedContext)
|
||||
root.evaluate(enhancedContext, listOf(PlacementPos(BlockPos(chunkPos.minBlockX, 0, chunkPos.minBlockZ), PlacementVariableMap())))
|
||||
return chunk
|
||||
}
|
||||
|
||||
@ -245,91 +160,4 @@ object EnhancedPlacedFeature : Feature<EnhancedPlacedFeature.Config>(
|
||||
override fun place(context: FeaturePlaceContext<Config>): Boolean {
|
||||
return context.config().place(context)
|
||||
}
|
||||
|
||||
class Builder {
|
||||
private val root: Builder?
|
||||
private val children = ArrayList<Builder>()
|
||||
private val contents: Either<EnhancedPlacementModifier, Holder<EnhancedFeature.Configured<*, *>>>
|
||||
|
||||
constructor() : this(EnhancedPlacementModifier.Passthrough)
|
||||
|
||||
constructor(root: EnhancedPlacementModifier) {
|
||||
this.root = null
|
||||
this.contents = Either.left(root)
|
||||
}
|
||||
|
||||
constructor(root: PlacementModifier) : this(EnhancedPlacementModifier.Wrapper(root))
|
||||
|
||||
constructor(root: Holder<EnhancedFeature.Configured<*, *>>) {
|
||||
this.root = null
|
||||
this.contents = Either.right(root)
|
||||
}
|
||||
|
||||
constructor(root: EnhancedFeature.Configured<*, *>) {
|
||||
this.root = null
|
||||
this.contents = Either.right(Holder.direct(root))
|
||||
}
|
||||
|
||||
private constructor(parent: Builder, root: PlacementModifier) : this(parent, EnhancedPlacementModifier.Wrapper(root))
|
||||
|
||||
private constructor(parent: Builder, root: EnhancedPlacementModifier) {
|
||||
this.root = parent
|
||||
this.contents = Either.left(root)
|
||||
}
|
||||
|
||||
private constructor(parent: Builder, root: Holder<EnhancedFeature.Configured<*, *>>) {
|
||||
this.root = parent
|
||||
this.contents = Either.right(root)
|
||||
}
|
||||
|
||||
private constructor(parent: Builder, root: EnhancedFeature.Configured<*, *>) {
|
||||
this.root = parent
|
||||
this.contents = Either.right(Holder.direct(root))
|
||||
}
|
||||
|
||||
fun then(action: PlacementModifier): Builder {
|
||||
return Builder(root ?: this, action).also(children::add)
|
||||
}
|
||||
|
||||
fun then(action: EnhancedPlacementModifier): Builder {
|
||||
return Builder(root ?: this, action).also(children::add)
|
||||
}
|
||||
|
||||
fun then(action: EnhancedFeature.Configured<*, *>): Builder {
|
||||
return Builder(root ?: this, action).also(children::add)
|
||||
}
|
||||
|
||||
fun then(action: Holder<EnhancedFeature.Configured<*, *>>): Builder {
|
||||
return Builder(root ?: this, action).also(children::add)
|
||||
}
|
||||
|
||||
@JvmName("thenVanilla")
|
||||
fun then(action: ConfiguredFeature<*, *>): Builder {
|
||||
return then(EnhancedFeature.Wrapper.configure(action))
|
||||
}
|
||||
|
||||
@JvmName("thenVanilla")
|
||||
fun then(action: Holder<ConfiguredFeature<*, *>>): Builder {
|
||||
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)
|
||||
}
|
||||
|
||||
fun build(
|
||||
chunkScanRange: Int,
|
||||
seedMix: Long,
|
||||
): PlacedFeature {
|
||||
if (root != null)
|
||||
return root.build(chunkScanRange, seedMix)
|
||||
|
||||
return PlacedFeature(Holder.direct(ConfiguredFeature(EnhancedPlacedFeature, Config(chunkScanRange, seedMix, buildNode()))), listOf())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.ChunkPos
|
||||
@ -9,10 +8,8 @@ import net.minecraft.world.level.chunk.ChunkGenerator
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementContext
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.EnhancedFeature
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
class EnhancedPlacementContext {
|
||||
fun interface Placer {
|
||||
|
@ -1,12 +1,15 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier
|
||||
import ru.dbotthepony.mc.otm.core.collect.Vec3iHashStrategy
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacementModifier
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.EnhancedFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacement
|
||||
|
||||
fun PlacementModifier.wrap(): EnhancedPlacementModifier {
|
||||
return EnhancedPlacementModifier.Wrapper(this)
|
||||
fun PlacementModifier.wrap(): EnhancedPlacement {
|
||||
return EnhancedPlacement.Wrapper(this)
|
||||
}
|
||||
|
||||
data class PlacementPos(val pos: BlockPos, val variables: PlacementVariableMap) : Comparable<PlacementPos> {
|
||||
@ -14,3 +17,9 @@ data class PlacementPos(val pos: BlockPos, val variables: PlacementVariableMap)
|
||||
return Vec3iHashStrategy.compare(pos, other.pos)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmName("placement")
|
||||
fun Holder<EnhancedFeature.Configured<*, *>>.placement() = EnhancedFeature.ConfiguredWrapper(this)
|
||||
@JvmName("vanillaPlacement")
|
||||
fun Holder<ConfiguredFeature<*, *>>.placement() = EnhancedFeature.Wrapper.configure(this)
|
||||
fun ConfiguredFeature<*, *>.placement() = EnhancedFeature.Wrapper.configure(this)
|
||||
|
@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistries
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementPos
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnhancedPlacement
|
||||
|
||||
abstract class EnhancedFeature<FC>(codec: Codec<FC>) {
|
||||
abstract fun place(context: EnhancedPlacementContext, config: FC, positions: Set<PlacementPos>, allPositions: Set<PlacementPos>): Boolean
|
||||
@ -21,10 +22,30 @@ abstract class EnhancedFeature<FC>(codec: Codec<FC>) {
|
||||
fun place(context: EnhancedPlacementContext, positions: Set<PlacementPos>, allPositions: Set<PlacementPos>): Boolean {
|
||||
return feature.place(context, config, positions, allPositions)
|
||||
}
|
||||
|
||||
fun placement(): ConfiguredWrapper {
|
||||
return ConfiguredWrapper(Holder.direct(this))
|
||||
}
|
||||
}
|
||||
|
||||
data class ConfiguredWrapper(val configured: Holder<Configured<*, *>>) : EnhancedPlacement {
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
context.place(positions, configured.value())
|
||||
return positions
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacement.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacement.Type<ConfiguredWrapper> {
|
||||
override val codec: MapCodec<ConfiguredWrapper> by lazy {
|
||||
CODEC.xmap(::ConfiguredWrapper, ConfiguredWrapper::configured).fieldOf("feature")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val codec: MapCodec<Configured<*, FC>> = codec.fieldOf("config").xmap({ Configured(this, it) }, { it.config })
|
||||
fun configure(config: FC) = Configured(this, config)
|
||||
fun configure(config: FC) = Configured(this, config).placement()
|
||||
|
||||
object Wrapper : EnhancedFeature<Holder<ConfiguredFeature<*, *>>>(ConfiguredFeature.CODEC) {
|
||||
override fun place(
|
||||
|
@ -14,7 +14,6 @@ import ru.dbotthepony.mc.otm.core.collect.Vec3iHashStrategy
|
||||
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementPos
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementVariableMap
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
@ -55,7 +54,7 @@ data class EllipsoidPlacement(
|
||||
* Ellipsoid size sampler on Y axis
|
||||
*/
|
||||
val yLength: FloatProvider,
|
||||
) : PlacementModifier(), EnhancedPlacementModifier {
|
||||
) : PlacementModifier(), EnhancedPlacement {
|
||||
init {
|
||||
require(xLength.minValue >= 1f) { "Bad ellipsoid x minimal size: $xLength" }
|
||||
require(zLength.minValue >= 1f) { "Bad ellipsoid z minimal size: $zLength" }
|
||||
@ -113,14 +112,14 @@ data class EllipsoidPlacement(
|
||||
return result
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
override val type: EnhancedPlacement.Type<*>
|
||||
get() = Companion
|
||||
|
||||
override fun type(): PlacementModifierType<*> {
|
||||
return MPlacementModifiers.ELLIPSOID_PLACEMENT
|
||||
}
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EllipsoidPlacement> {
|
||||
companion object : EnhancedPlacement.Type<EllipsoidPlacement> {
|
||||
val CODEC: MapCodec<EllipsoidPlacement> by lazy {
|
||||
RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
|
@ -3,31 +3,37 @@ 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
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementPos
|
||||
|
||||
/**
|
||||
* Daisy-chaining placements. Required only when using placement modifiers which operate on children list
|
||||
* Chains placements, feeding results from one placement into next
|
||||
*
|
||||
* Each placement gets its own, new [EnhancedPlacementContext], so variables can be pushed safely into it
|
||||
*/
|
||||
class EnhancedChainPlacement(
|
||||
val children: List<EnhancedPlacementModifier>
|
||||
) : EnhancedPlacementModifier {
|
||||
constructor(vararg children: EnhancedPlacementModifier) : this(ImmutableList.copyOf(children))
|
||||
val children: List<EnhancedPlacement>
|
||||
) : EnhancedPlacement {
|
||||
constructor(vararg children: EnhancedPlacement) : this(ImmutableList.copyOf(children))
|
||||
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
var currentContext = context
|
||||
var current = positions
|
||||
children.forEach { current = it.evaluate(context, current) }
|
||||
|
||||
children.forEach {
|
||||
current = it.evaluate(context, current)
|
||||
currentContext = currentContext.push()
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
override val type: EnhancedPlacement.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EnhancedChainPlacement> {
|
||||
companion object : EnhancedPlacement.Type<EnhancedChainPlacement> {
|
||||
override val codec: MapCodec<EnhancedChainPlacement> by lazy {
|
||||
Codec.list(EnhancedPlacementModifier.CODEC).xmap(::EnhancedChainPlacement, EnhancedChainPlacement::children).fieldOf("children")
|
||||
Codec.list(EnhancedPlacement.CODEC).xmap(::EnhancedChainPlacement, EnhancedChainPlacement::children).fieldOf("children")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import net.minecraft.util.valueproviders.IntProvider
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementPos
|
||||
|
||||
class EnhancedCountPlacement(val provider: IntProvider) : EnhancedPlacementModifier {
|
||||
class EnhancedCountPlacement(val provider: IntProvider) : EnhancedPlacement {
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
val count = provider.sample(context.random)
|
||||
|
||||
@ -21,10 +21,10 @@ class EnhancedCountPlacement(val provider: IntProvider) : EnhancedPlacementModif
|
||||
}
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
override val type: EnhancedPlacement.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EnhancedCountPlacement> {
|
||||
companion object : EnhancedPlacement.Type<EnhancedCountPlacement> {
|
||||
override val codec: MapCodec<EnhancedCountPlacement> = IntProvider.CODEC.xmap(::EnhancedCountPlacement, EnhancedCountPlacement::provider).fieldOf("count")
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package ru.dbotthepony.mc.otm.worldgen.placement
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementContext
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier
|
||||
import net.neoforged.bus.api.IEventBus
|
||||
import ru.dbotthepony.mc.otm.registry.MBuiltInRegistries
|
||||
@ -11,18 +9,17 @@ import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistries
|
||||
import ru.dbotthepony.mc.otm.worldgen.EnhancedPlacementContext
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementPos
|
||||
import ru.dbotthepony.mc.otm.worldgen.PlacementVariableMap
|
||||
import java.util.stream.Collectors
|
||||
|
||||
interface EnhancedPlacementModifier {
|
||||
interface Type<T : EnhancedPlacementModifier> {
|
||||
interface EnhancedPlacement {
|
||||
interface Type<T : EnhancedPlacement> {
|
||||
val codec: MapCodec<T>
|
||||
}
|
||||
|
||||
fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos>
|
||||
val type: Type<*>
|
||||
|
||||
class Wrapper(val parent: PlacementModifier) : EnhancedPlacementModifier {
|
||||
class Wrapper(val parent: PlacementModifier) : EnhancedPlacement {
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
return positions.stream()
|
||||
.flatMap { (pos, vars) -> parent.getPositions(context.vanillaContext, context.random, pos).map { PlacementPos(it, vars) } }
|
||||
@ -37,7 +34,7 @@ interface EnhancedPlacementModifier {
|
||||
}
|
||||
}
|
||||
|
||||
object Passthrough : EnhancedPlacementModifier, Type<Passthrough> {
|
||||
object Passthrough : EnhancedPlacement, Type<Passthrough> {
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
return positions
|
||||
}
|
||||
@ -56,7 +53,7 @@ interface EnhancedPlacementModifier {
|
||||
registrar.register("passthrough") { Passthrough }
|
||||
}
|
||||
|
||||
val CODEC: Codec<EnhancedPlacementModifier> by lazy {
|
||||
val CODEC: Codec<EnhancedPlacement> by lazy {
|
||||
MBuiltInRegistries.PLACEMENT_MODIFIER.byNameCodec().dispatch({ it.type }, { it.codec })
|
||||
}
|
||||
|
@ -3,16 +3,11 @@ 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 com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.util.StringRepresentable
|
||||
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 ru.dbotthepony.mc.otm.worldgen.PlacementPos
|
||||
import java.util.stream.Collectors
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
* Or "shard" placement, if you will.
|
||||
@ -20,22 +15,48 @@ import java.util.stream.Stream
|
||||
* 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))
|
||||
val mode: Mode,
|
||||
val children: List<EnhancedPlacement>,
|
||||
) : EnhancedPlacement {
|
||||
constructor(mode: Mode, vararg children: EnhancedPlacement) : this(mode, ImmutableList.copyOf(children))
|
||||
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
val result = ArrayList<PlacementPos>()
|
||||
children.forEach { result.addAll(it.evaluate(context, positions)) }
|
||||
return result
|
||||
enum class Mode : StringRepresentable {
|
||||
COMBINE,
|
||||
FORK;
|
||||
|
||||
private val lname = name.lowercase()
|
||||
|
||||
override fun getSerializedName(): String {
|
||||
return lname
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<Mode> = StringRepresentable.fromEnum(::values)
|
||||
}
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
override fun evaluate(context: EnhancedPlacementContext, positions: List<PlacementPos>): List<PlacementPos> {
|
||||
if (mode == Mode.COMBINE) {
|
||||
val result = ArrayList<PlacementPos>()
|
||||
children.forEach { result.addAll(it.evaluate(context.push(), positions)) }
|
||||
return result
|
||||
} else {
|
||||
children.forEach { it.evaluate(context.push(), positions) }
|
||||
return positions
|
||||
}
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacement.Type<*>
|
||||
get() = Companion
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<EnhancedSplitPlacement> {
|
||||
companion object : EnhancedPlacement.Type<EnhancedSplitPlacement> {
|
||||
override val codec: MapCodec<EnhancedSplitPlacement> by lazy {
|
||||
Codec.list(EnhancedPlacementModifier.CODEC).xmap(::EnhancedSplitPlacement, EnhancedSplitPlacement::children).fieldOf("children")
|
||||
RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
Mode.CODEC.fieldOf("mode").forGetter(EnhancedSplitPlacement::mode),
|
||||
Codec.list(EnhancedPlacement.CODEC).fieldOf("children").forGetter(EnhancedSplitPlacement::children),
|
||||
).apply(it, ::EnhancedSplitPlacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ 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
|
||||
@ -46,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(), EnhancedPlacementModifier {
|
||||
) : PlacementModifier(), EnhancedPlacement {
|
||||
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)
|
||||
@ -165,7 +164,7 @@ class WormPlacement(
|
||||
}
|
||||
}
|
||||
|
||||
override val type: EnhancedPlacementModifier.Type<*>
|
||||
override val type: EnhancedPlacement.Type<*>
|
||||
get() = Companion
|
||||
|
||||
override fun getPositions(context: PlacementContext, random: RandomSource, center: BlockPos): Stream<BlockPos> {
|
||||
@ -176,7 +175,7 @@ class WormPlacement(
|
||||
return MPlacementModifiers.WORM_PLACEMENT
|
||||
}
|
||||
|
||||
companion object : EnhancedPlacementModifier.Type<WormPlacement> {
|
||||
companion object : EnhancedPlacement.Type<WormPlacement> {
|
||||
private fun increment(value: Float): Float {
|
||||
var i = 1f
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user