Initial worm placement code along with debug feature
This commit is contained in:
parent
97d30d3a19
commit
f6abe0f038
@ -9,6 +9,7 @@ import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.util.valueproviders.ClampedNormalFloat
|
||||
import net.minecraft.util.valueproviders.ClampedNormalInt
|
||||
import net.minecraft.util.valueproviders.ConstantFloat
|
||||
import net.minecraft.util.valueproviders.IntProvider
|
||||
import net.minecraft.util.valueproviders.UniformFloat
|
||||
import net.minecraft.util.valueproviders.UniformInt
|
||||
import net.minecraft.world.level.levelgen.GenerationStep
|
||||
@ -22,20 +23,26 @@ import net.minecraft.world.level.levelgen.placement.HeightRangePlacement
|
||||
import net.minecraft.world.level.levelgen.placement.InSquarePlacement
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature
|
||||
import net.minecraft.world.level.levelgen.placement.RarityFilter
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.AlwaysTrueTest
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockStateMatchTest
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.TagMatchTest
|
||||
import net.neoforged.neoforge.common.world.BiomeModifier
|
||||
import net.neoforged.neoforge.registries.NeoForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.data.world.BooleanProvider
|
||||
import ru.dbotthepony.mc.otm.data.world.OneOfFloatProvider
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.StandardDeviationHeightProvider
|
||||
import ru.dbotthepony.mc.otm.registry.game.MBlocks
|
||||
import ru.dbotthepony.mc.otm.registry.data.MWorldGenFeatures
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.BlackHolePlacerFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.DebugPlacerFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.AbstractEnormousPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousEllipsoidPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
|
||||
|
||||
private object ConfiguredFeatures {
|
||||
val TRITANIUM_ORE = key("tritanium_ore")
|
||||
val TRITANIUM_ORE_SMALL = key("tritanium_ore_small")
|
||||
val DILITHIUM = key("dilithium")
|
||||
val BLACK_HOLE = key("black_hole")
|
||||
|
||||
@ -55,6 +62,8 @@ fun registerConfiguredFeatures(context: BootstrapContext<ConfiguredFeature<*, *>
|
||||
)
|
||||
|
||||
context.register(ConfiguredFeatures.TRITANIUM_ORE, ConfiguredFeature(Feature.ORE, OreConfiguration(target, 9)))
|
||||
//context.register(ConfiguredFeatures.TRITANIUM_ORE_SMALL, ConfiguredFeature(Feature.ORE, OreConfiguration(target, 3)))
|
||||
context.register(ConfiguredFeatures.TRITANIUM_ORE_SMALL, ConfiguredFeature(MWorldGenFeatures.DEBUG_PLACEMENT, DebugPlacerFeature.Config(MBlocks.TRITANIUM_ORE.defaultBlockState())))
|
||||
}
|
||||
|
||||
run {
|
||||
@ -74,6 +83,7 @@ fun registerConfiguredFeatures(context: BootstrapContext<ConfiguredFeature<*, *>
|
||||
private object PlacedFeatures {
|
||||
val NORMAL_TRITANIUM = key("normal_tritanium")
|
||||
val DEEP_TRITANIUM = key("deep_tritanium")
|
||||
val WORM_TRITANIUM = key("worm_tritanium")
|
||||
val DILITHIUM = key("dilithium")
|
||||
val BLACK_HOLE = key("black_hole")
|
||||
|
||||
@ -105,6 +115,27 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
|
||||
HeightRangePlacement.of(VeryBiasedToBottomHeight.of(VerticalAnchor.aboveBottom(4), VerticalAnchor.absolute(0), 16))
|
||||
)
|
||||
))
|
||||
|
||||
context.register(PlacedFeatures.WORM_TRITANIUM, PlacedFeature(
|
||||
configured.getOrThrow(ConfiguredFeatures.TRITANIUM_ORE_SMALL),
|
||||
listOf(
|
||||
WormPlacement(
|
||||
parameters = AbstractEnormousPlacement.Parameters(
|
||||
chunkScanRange = 12,
|
||||
seedMix = 9284343575495L,
|
||||
placementModifiers = listOf(
|
||||
RarityFilter.onAverageOnceEvery(10),
|
||||
InSquarePlacement.spread(),
|
||||
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(120), 15.0)),
|
||||
)
|
||||
),
|
||||
wormLength = UniformInt.of(40, 200),
|
||||
wormTurnChance = BooleanProvider.onceEvery(4),
|
||||
wormTurnXY = WormPlacement.normalDistributedTurnRate(60f),
|
||||
wormTurnXZ = WormPlacement.normalDistributedTurnRate(60f),
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
run {
|
||||
@ -172,6 +203,7 @@ fun registerBiomeModifiers(context: BootstrapContext<BiomeModifier>) {
|
||||
HolderSet.direct(
|
||||
placed.getOrThrow(PlacedFeatures.NORMAL_TRITANIUM),
|
||||
placed.getOrThrow(PlacedFeatures.DEEP_TRITANIUM),
|
||||
placed.getOrThrow(PlacedFeatures.WORM_TRITANIUM),
|
||||
placed.getOrThrow(PlacedFeatures.DILITHIUM),
|
||||
),
|
||||
GenerationStep.Decoration.UNDERGROUND_ORES
|
||||
|
@ -678,3 +678,15 @@ fun RandomSource.nextNormalDoubles(stddev: Double, mean: Double): DoublePair {
|
||||
fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double {
|
||||
return nextGaussian() * stddev + mean
|
||||
}
|
||||
|
||||
fun RandomSource.nextFloat(min: Float, max: Float): Float {
|
||||
require(max >= min) { "Min is bigger than max: $min vs $max" }
|
||||
if (min == max) return min
|
||||
return min + nextFloat() * (max - min)
|
||||
}
|
||||
|
||||
fun RandomSource.nextDouble(min: Double, max: Double): Double {
|
||||
require(max >= min) { "Min is bigger than max: $min vs $max" }
|
||||
if (min == max) return min
|
||||
return min + nextDouble() * (max - min)
|
||||
}
|
||||
|
@ -436,7 +436,9 @@ operator fun Direction.times(int: Int): Vec3i = this.normal.multiply(int)
|
||||
operator fun Vec3i.times(double: Double): Vector = Vector(x * double, y * double, z * double)
|
||||
|
||||
fun Vec3.toIntVector() = Vec3i(x.toInt(), y.toInt(), z.toInt())
|
||||
fun Vec3.toBlockPos() = BlockPos(x.toInt(), y.toInt(), z.toInt())
|
||||
fun Vec3.roundToIntVector() = Vec3i(x.roundToInt(), y.roundToInt(), z.roundToInt())
|
||||
fun Vec3.roundToBlockPos() = BlockPos(x.roundToInt(), y.roundToInt(), z.roundToInt())
|
||||
|
||||
fun BlockPos.asVector(): Vector {
|
||||
return Vector(x + 0.5, y + 0.5, z + 0.5)
|
||||
|
@ -0,0 +1,33 @@
|
||||
package ru.dbotthepony.mc.otm.data.world
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.valueproviders.FloatProvider
|
||||
import net.minecraft.util.valueproviders.UniformFloat
|
||||
|
||||
class BooleanProvider(val sampler: FloatProvider, val threshold: Float, val lessThan: Boolean = true) {
|
||||
fun sample(random: RandomSource): Boolean {
|
||||
val sampled = sampler.sample(random)
|
||||
|
||||
if (lessThan) {
|
||||
return sampled < threshold
|
||||
} else {
|
||||
return sampled >= threshold
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun onceEvery(samples: Int): BooleanProvider {
|
||||
return BooleanProvider(UniformFloat.of(0f, samples.toFloat()), 1f, lessThan = true)
|
||||
}
|
||||
|
||||
val CODEC: Codec<BooleanProvider> = RecordCodecBuilder.create {
|
||||
it.group(
|
||||
FloatProvider.CODEC.fieldOf("sampler").forGetter(BooleanProvider::sampler),
|
||||
Codec.FLOAT.fieldOf("threshold").forGetter(BooleanProvider::threshold),
|
||||
Codec.BOOL.optionalFieldOf("less_than", true).forGetter(BooleanProvider::lessThan)
|
||||
).apply(it, ::BooleanProvider)
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import net.neoforged.bus.api.IEventBus
|
||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousEllipsoidPlacement
|
||||
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
|
||||
|
||||
object MPlacementModifiers {
|
||||
private val registry = MDeferredRegister(BuiltInRegistries.PLACEMENT_MODIFIER_TYPE)
|
||||
@ -16,4 +17,5 @@ object MPlacementModifiers {
|
||||
|
||||
val ELLIPSOID_PLACEMENT by registry.register("ellipsoid") { PlacementModifierType { EllipsoidPlacement.CODEC } }
|
||||
val ENORMOUS_ELLIPSOID_PLACEMENT by registry.register("enormous_ellipsoid") { PlacementModifierType { EnormousEllipsoidPlacement.CODEC } }
|
||||
val WORM_PLACEMENT by registry.register("worm") { PlacementModifierType { WormPlacement.CODEC } }
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package ru.dbotthepony.mc.otm.registry.data
|
||||
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.neoforged.bus.api.IEventBus
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.BlackHolePlacerFeature
|
||||
import ru.dbotthepony.mc.otm.worldgen.feature.DebugPlacerFeature
|
||||
|
||||
object MWorldGenFeatures {
|
||||
private val registry = MDeferredRegister(BuiltInRegistries.FEATURE)
|
||||
@ -13,4 +15,5 @@ object MWorldGenFeatures {
|
||||
}
|
||||
|
||||
val BLACK_HOLE_PLACER by registry.register("black_hole_placer") { BlackHolePlacerFeature }
|
||||
val DEBUG_PLACEMENT by registry.register("debug") { DebugPlacerFeature }
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package ru.dbotthepony.mc.otm.worldgen.feature
|
||||
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.levelgen.feature.Feature
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration
|
||||
import ru.dbotthepony.mc.otm.registry.game.MBlocks
|
||||
|
||||
object DebugPlacerFeature : Feature<DebugPlacerFeature.Config>(BlockState.CODEC.xmap(::Config, Config::blockState)) {
|
||||
data class Config(val blockState: BlockState) : FeatureConfiguration
|
||||
|
||||
override fun place(context: FeaturePlaceContext<Config>): Boolean {
|
||||
return context.level().setBlock(context.origin(), context.config().blockState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
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.ClampedNormalFloat
|
||||
import net.minecraft.util.valueproviders.ConstantFloat
|
||||
import net.minecraft.util.valueproviders.FloatProvider
|
||||
import net.minecraft.util.valueproviders.IntProvider
|
||||
import net.minecraft.util.valueproviders.UniformFloat
|
||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType
|
||||
import ru.dbotthepony.mc.otm.core.math.Vector
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.math.toBlockPos
|
||||
import ru.dbotthepony.mc.otm.core.nextDouble
|
||||
import ru.dbotthepony.mc.otm.data.world.BooleanProvider
|
||||
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
|
||||
import java.util.stream.Stream
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class WormPlacement(
|
||||
parameters: Parameters,
|
||||
val wormLength: IntProvider,
|
||||
val wormTurnChance: BooleanProvider,
|
||||
val wormTurnXZ: FloatProvider,
|
||||
val wormTurnXY: FloatProvider,
|
||||
) : AbstractEnormousPlacement(parameters) {
|
||||
override fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos> {
|
||||
var position = Vector.ZERO
|
||||
val maxDistance = wormLength.sample(random)
|
||||
// determine initial worm facing angle
|
||||
var xzRotation = random.nextDouble(-PI / 2.0, PI / 2.0)
|
||||
var xyRotation = random.nextDouble(-PI / 16.0, PI / 16.0)
|
||||
|
||||
var xzSin = sin(xzRotation)
|
||||
var xzCos = cos(xzRotation)
|
||||
var xySin = sin(xyRotation)
|
||||
|
||||
val positions = ArrayList<BlockPos>()
|
||||
var prevPos = position.toBlockPos()
|
||||
positions.add(prevPos)
|
||||
|
||||
for (traveledDistance in 0 .. maxDistance) {
|
||||
// wormy turn
|
||||
if (wormTurnChance.sample(random)) {
|
||||
// wormy angle
|
||||
// TODO: smooth turning, instead of snapping to new angle make it gradually face new angle
|
||||
xzRotation += wormTurnXZ.sample(random)
|
||||
xyRotation += wormTurnXY.sample(random)
|
||||
|
||||
xzSin = sin(xzRotation)
|
||||
xzCos = cos(xzRotation)
|
||||
xySin = sin(xyRotation)
|
||||
}
|
||||
|
||||
// advance worm
|
||||
position += Vector(xzCos, xySin, xzSin)
|
||||
val calc = position.toBlockPos()
|
||||
|
||||
if (calc != prevPos) {
|
||||
// if worm made a wurm, add new position to set
|
||||
prevPos = calc
|
||||
positions.add(calc)
|
||||
}
|
||||
}
|
||||
|
||||
return positions.stream().map { it + center }
|
||||
}
|
||||
|
||||
override fun type(): PlacementModifierType<*> {
|
||||
return MPlacementModifiers.WORM_PLACEMENT
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun increment(value: Float): Float {
|
||||
var i = 1f
|
||||
|
||||
while (true) {
|
||||
val enlarge = Float.MIN_VALUE * i
|
||||
val sum = value + enlarge
|
||||
|
||||
if (sum != value) {
|
||||
return sum
|
||||
} else {
|
||||
i += 1f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun uniformTurnRate(degrees: Float): FloatProvider {
|
||||
return uniformTurnRateRadians(degrees * DEGREES_TO_RADIANS)
|
||||
}
|
||||
|
||||
fun uniformTurnRateRadians(rad: Float): FloatProvider {
|
||||
require(rad >= 0f) { "Provided value must be non-negative, $rad given" }
|
||||
if (rad == 0f) return ConstantFloat.ZERO
|
||||
return UniformFloat.of(-rad, increment(rad))
|
||||
}
|
||||
|
||||
fun normalDistributedTurnRate(deviation: Float): FloatProvider {
|
||||
return normalDistributedTurnRateRadians(deviation * DEGREES_TO_RADIANS)
|
||||
}
|
||||
|
||||
fun normalDistributedTurnRateRadians(deviation: Float): FloatProvider {
|
||||
require(deviation >= 0f) { "Provided value must be non-negative, $deviation given" }
|
||||
if (deviation == 0f) return ConstantFloat.ZERO
|
||||
return ClampedNormalFloat.of(0f, deviation, -PI.toFloat() * 2f, PI.toFloat() * 2f)
|
||||
}
|
||||
|
||||
private const val DEGREES_TO_RADIANS = PI.toFloat() / 180f
|
||||
|
||||
val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
PARAMETERS_CODEC.forGetter(WormPlacement::parameters),
|
||||
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::wormLength),
|
||||
BooleanProvider.CODEC.fieldOf("turn_chance").forGetter(WormPlacement::wormTurnChance),
|
||||
FloatProvider.CODEC.fieldOf("turn_xz").forGetter(WormPlacement::wormTurnXZ),
|
||||
FloatProvider.CODEC.fieldOf("turn_xy").forGetter(WormPlacement::wormTurnXY),
|
||||
).apply(it, ::WormPlacement)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user