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 2e464be48..54c7f57eb 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/WorldGen.kt @@ -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 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 2d5b282ec..8049d21c1 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 @@ -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} } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnormousPlacement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnormousPlacement.kt deleted file mode 100644 index 6947f42a3..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/placement/EnormousPlacement.kt +++ /dev/null @@ -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() { - private class GeneratedChunk(positions: Stream) { - // TODO: memory inefficient - private val positions = ObjectOpenHashSet() - - init { - positions.forEach { this.positions.add(it) } - } - - // TODO: this is primitive implementation, need to implement better one - fun getPositions(pos: ChunkPos): Stream { - 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>() - - private fun getCache(level: WorldGenLevel): Cache { - 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 { - val cache = getCache(context.level) - val cPos = ChunkPos(pos) - val instances = ArrayList() - - 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 = 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) - } - } -}