Remove enormous placement

This commit is contained in:
DBotThePony 2025-03-24 19:27:36 +07:00
parent 1acd105925
commit 1e6e38ea7d
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 0 additions and 139 deletions

View File

@ -37,7 +37,6 @@ 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.EnormousPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.SplitPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement

View File

@ -6,7 +6,6 @@ import net.neoforged.bus.api.IEventBus
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.worldgen.placement.ChainPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.EllipsoidPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.EnormousPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.SplitPlacement
import ru.dbotthepony.mc.otm.worldgen.placement.WormPlacement
@ -17,7 +16,6 @@ object MPlacementModifiers {
registry.register(bus)
}
val ENORMOUS by registry.register("enormous") { PlacementModifierType { EnormousPlacement.CODEC } }
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} }

View File

@ -1,136 +0,0 @@
package ru.dbotthepony.mc.otm.worldgen.placement
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.Scheduler
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import net.minecraft.Util
import net.minecraft.core.BlockPos
import net.minecraft.core.SectionPos
import net.minecraft.util.RandomSource
import net.minecraft.world.level.ChunkPos
import net.minecraft.world.level.WorldGenLevel
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.kommons.util.XXHash64
import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource
import ru.dbotthepony.mc.otm.data.codec.minRange
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
import java.io.DataOutputStream
import java.time.Duration
import java.util.stream.Stream
import kotlin.math.sqrt
/**
* Enormous placement base, which allows it to span over several chunks without issues.
*
* This modifier is designed to be the only "top-level" placement modifier,
* and all logic regarding actual placements embedded in [children]
*/
class EnormousPlacement(
/**
* How many chunks away to look for actual placements
*
* Too small value will cause placement cutoffs
*/
val chunkScanRange: Int,
val seedMix: Long,
/**
* Baseline placement modifiers, dictating how to appear in chunk
*/
val children: List<PlacementModifier>,
) : PlacementModifier() {
private class GeneratedChunk(positions: Stream<BlockPos>) {
// TODO: memory inefficient
private val positions = ObjectOpenHashSet<BlockPos>()
init {
positions.forEach { this.positions.add(it) }
}
// TODO: this is primitive implementation, need to implement better one
fun getPositions(pos: ChunkPos): Stream<BlockPos> {
return positions.stream().filter {
SectionPos.blockToSectionCoord(it.x) == pos.x &&
SectionPos.blockToSectionCoord(it.z) == pos.z
}
}
}
private val level2cache = Caffeine.newBuilder()
.scheduler(Scheduler.systemScheduler())
.executor(Util.backgroundExecutor())
.expireAfterAccess(Duration.ofMinutes(10))
.weakKeys()
.build<WorldGenLevel, Cache<ChunkPos, GeneratedChunk>>()
private fun getCache(level: WorldGenLevel): Cache<ChunkPos, GeneratedChunk> {
return level2cache.get(level) {
Caffeine.newBuilder()
.scheduler(Scheduler.systemScheduler())
.executor(Util.backgroundExecutor())
.maximumSize(16384L)
.expireAfterWrite(Duration.ofMinutes(5))
.softValues()
.build()
}
}
private fun computeChunk(context: PlacementContext, pos: ChunkPos): GeneratedChunk {
val bytes = FastByteArrayOutputStream()
val dataStream = DataOutputStream(bytes)
dataStream.writeLong(seedMix)
dataStream.writeInt(pos.x)
dataStream.writeInt(pos.z)
val hash = XXHash64()
hash.update(bytes.array, 0, bytes.length)
val random = GJRAND64RandomSource(context.level.seed, hash.digestAsLong())
var stream = Stream.of(BlockPos(pos.minBlockX, 0, pos.minBlockZ))
children.forEach { modifier -> stream = stream.flatMap { modifier.getPositions(context, random, it).sequential() } }
return GeneratedChunk(stream)
}
override fun getPositions(context: PlacementContext, random: RandomSource, pos: BlockPos): Stream<BlockPos> {
val cache = getCache(context.level)
val cPos = ChunkPos(pos)
val instances = ArrayList<GeneratedChunk>()
for (x in -chunkScanRange .. chunkScanRange) {
for (z in -chunkScanRange .. chunkScanRange) {
// floor, so chunk scan range of 1 will give square instead of diamond
val radius = sqrt(x.toDouble() * x + z.toDouble() * z).toInt()
if (radius <= chunkScanRange) {
val thisPos = ChunkPos(cPos.x + x, cPos.z + z)
instances.add(cache.get(thisPos) { computeChunk(context, thisPos) })
}
}
}
return instances.stream().flatMap { it.getPositions(cPos) }
}
override fun type(): PlacementModifierType<*> {
return MPlacementModifiers.ENORMOUS
}
companion object {
val CODEC: MapCodec<EnormousPlacement> = RecordCodecBuilder.mapCodec {
it.group(
Codec.INT.minRange(0).fieldOf("chunk_scan_range").forGetter(EnormousPlacement::chunkScanRange),
Codec.LONG.fieldOf("seed_mix").forGetter(EnormousPlacement::seedMix),
PlacementModifier.CODEC.listOf().optionalFieldOf("children", listOf()).forGetter(EnormousPlacement::children),
).apply(it, ::EnormousPlacement)
}
}
}