Remove enormous placement
This commit is contained in:
parent
1acd105925
commit
1e6e38ea7d
@ -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
|
||||
|
@ -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} }
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user