From 468949a22c0cdccb836461f0288f1a90802b97ee Mon Sep 17 00:00:00 2001 From: minjaesong Date: Wed, 25 Sep 2024 15:58:17 +0900 Subject: [PATCH] strata implemented --- .../modulebasegame/worldgenerator/Terragen.kt | 116 +++++++----------- .../modulebasegame/worldgenerator/Worldgen.kt | 65 +++++++++- 2 files changed, 105 insertions(+), 76 deletions(-) diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index c1fcfd56a..f2ea1cab6 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -16,10 +16,24 @@ import kotlin.math.sin /** * Created by minjaesong on 2019-07-23. */ -class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: ModuleCache, seed: Long, params: Any) : Gen(world, isFinal, seed, params) { +class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: ModuleCache, val landBlock: ModuleCache, seed: Long, params: Any) : Gen(world, isFinal, seed, params) { private val isAlpha2 = ((params as TerragenParams).versionSince >= 0x0000_000004_000004) + private lateinit var strataCache: Array> + private lateinit var groundDepthBlocksCache: Array> + private lateinit var terragenTiersCache: Array> + + private val terragenYscaling = + if (isAlpha2) + 1.0 + else + (world.height / 2400.0).pow(0.75) + + init { + populateCaches(seed) + } + override fun getDone(loadscreen: LoadScreenBase?) { loadscreen?.let { it.stageValue += 1 @@ -31,6 +45,18 @@ class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: Modu Worldgen.threadExecutor.join() } + private fun populateCaches(seed: Long) { + val params = params as TerragenParams + strataCache = Array(params.LANDBLOCK_VAR_COUNTS) { + params.getStrataForMode(seed, it) + } + groundDepthBlocksCache = Array(params.LANDBLOCK_VAR_COUNTS) { + strataCache[it].map { it.tiles } + } + terragenTiersCache = Array(params.LANDBLOCK_VAR_COUNTS) { + strataCache[it].map { it.yheight * terragenYscaling } + } + } private fun Double.tiered(tiers: List): Int { tiers.reversed().forEachIndexed { index, it -> @@ -39,22 +65,9 @@ class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: Modu return tiers.lastIndex } - private val terragenYscaling = - if (isAlpha2) - 1.0 - else - (world.height / 2400.0).pow(0.75) - //private fun draw(x: Int, y: Int, width: Int, height: Int, noiseValue: List, world: GameWorld) { override fun draw(xStart: Int, yStart: Int, noises: List, soff: Double) { - val strataMode = if (!isAlpha2) - 0 - else - 1// TODO - - val strata = (params as TerragenParams).getStrataForMode(seed, strataMode) - val groundDepthBlock = strata.map { it.tiles } - val terragenTiers = strata.map { it.yheight * terragenYscaling } + val params = params as TerragenParams for (x in xStart until xStart + CHUNK_W) { val st = (x.toDouble() / world.width) * TWO_PI @@ -66,69 +79,21 @@ class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: Modu // DEBUG NOTE: it is the OFFSET FROM THE IDEAL VALUE (observed land height - (HEIGHT * DIVISOR)) that must be constant val noiseValue = noises.map { it.get(sx, sy, sz) } - val terr = noiseValue[0].tiered(terragenTiers) + val strataMode = if (!isAlpha2) + 0 + else + noiseValue[1].times(params.LANDBLOCK_VAR_COUNTS).toInt().coerceIn(0, params.LANDBLOCK_VAR_COUNTS - 1) + + val terrTier = noiseValue[0].tiered(terragenTiersCache[strataMode]) val isMarble = if (!isAlpha2) noiseValue[1] > 0.5 else false - val wallBlock = if (isMarble) Block.STONE_MARBLE else groundDepthBlock[terr] - val terrBlock = if (isMarble) Block.STONE_MARBLE else wallBlock + val block = if (isMarble) Block.STONE_MARBLE else groundDepthBlocksCache[strataMode][terrTier] + //groundDepthBlocksCache[strataMode][terr] - world.setTileTerrain(x, y, terrBlock, true) - world.setTileWall(x, y, wallBlock, true) + world.setTileTerrain(x, y, block, true) + world.setTileWall(x, y, block, true) } - - - // dither shits - /* - # - # - dirt-to-cobble transition, height = dirtStoneDitherSize - # - % - % - cobble-to-rock transition, height = dirtStoneDitherSize - % - * - where the stone layer actually begins - */ - /*if (dirtStoneTransition >= 0) { - for (pos in 0 until dirtStoneDitherSize * 2) { - val y = pos + dirtStoneTransition - (dirtStoneDitherSize * 2) + 1 - if (y >= world.height) break - val hash = XXHash32.hashGeoCoord(x, y).and(0xFFFFFF) / 16777216.0 -// val fore = world.getTileFromTerrain(x, y) -// val back = world.getTileFromWall(x, y) - val newTile = if (pos < dirtStoneDitherSize) - if (hash < pos.toDouble() / dirtStoneDitherSize) Block.STONE_QUARRIED else Block.DIRT - else // don't +1 to pos.toDouble(); I've suffered - if (hash >= (pos.toDouble() - dirtStoneDitherSize) / dirtStoneDitherSize) Block.STONE_QUARRIED else Block.STONE - -// if (fore != Block.AIR) - if (y in yStart until yStart + CHUNK_H) { - world.setTileTerrain(x, y, newTile, true) - world.setTileWall(x, y, newTile, true) - } - } - }*/ - - /* - # - # - stone-to-slate transition, height = stoneSlateDitherSize - # - */ - /*if (stoneSlateTransition >= 0) { - for (pos in 0 until stoneSlateDitherSize) { - val y = pos + stoneSlateTransition - stoneSlateDitherSize + 1 - if (y >= world.height) break - val hash = XXHash32.hashGeoCoord(x, y).and(0xFFFFFF) / 16777216.0 -// val fore = world.getTileFromTerrain(x, y) -// val back = world.getTileFromWall(x, y) - val newTile = if (hash < pos.toDouble() / stoneSlateDitherSize) Block.STONE_SLATE else Block.STONE - - if (y in yStart until yStart + CHUNK_H) { -// if (fore != Block.AIR) - world.setTileTerrain(x, y, newTile, true) - world.setTileWall(x, y, newTile, true) - } - } - }*/ } } @@ -151,7 +116,10 @@ class Terragen(world: GameWorld, isFinal: Boolean, val groundScalingCached: Modu ) } else - listOf(Joise(groundScalingCached)) + listOf( + Joise(groundScalingCached), + Joise(landBlock), + ) } private fun generateRockLayer(ground: Module, seed: Long, params: TerragenParams, thicknessAndRange: List>): Module { diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt index cae35b139..43c700b60 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt @@ -59,6 +59,7 @@ object Worldgen { params = genParams highlandLowlandSelectCache = getHighlandLowlandSelectCache(params.terragenParams, params.seed) + landBlock = getLandBlock(params.terragenParams, params.seed) caveAttenuateBiasScaledForOresCache = getCaveAttenuateBiasScaled(highlandLowlandSelectCache, params.terragenParams) groundScalingCached = getGroundScalingCached(highlandLowlandSelectCache, params.terragenParams) biomeMap = HashMap() @@ -67,6 +68,7 @@ object Worldgen { } internal lateinit var groundScalingCached: ModuleCache + internal lateinit var landBlock: ModuleCache internal lateinit var highlandLowlandSelectCache: ModuleCache internal lateinit var caveAttenuateBiasScaledForOresCache: ModuleCache internal lateinit var biomeMap: HashMap @@ -95,7 +97,7 @@ object Worldgen { else { work: Work -> (work.tags union tags).isNotEmpty() } return listOf( - Work(Lang["MENU_IO_WORLDGEN_RETICULATING_SPLINES"], Terragen(world, false, groundScalingCached, params.seed, params.terragenParams), listOf("TERRAIN")), // also generates marble veins + Work(Lang["MENU_IO_WORLDGEN_RETICULATING_SPLINES"], Terragen(world, false, groundScalingCached, landBlock, params.seed, params.terragenParams), listOf("TERRAIN")), // also generates marble veins Work(Lang["MENU_IO_WORLDGEN_CARVING_EARTH"], Cavegen(world, false, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN", "CAVE")), Work(Lang["MENU_IO_WORLDGEN_FLOODING_UNDERGROUND"], Aquagen(world, false, groundScalingCached, params.seed, params.terragenParams), listOf("WATER")), Work(Lang["MENU_IO_WORLDGEN_GROWING_MINERALS"], Oregen(world, false, caveAttenuateBiasScaledForOresCache, params.seed, oreRegistry, params.terragenParams), listOf("ORES")), @@ -208,6 +210,16 @@ object Worldgen { private val rockScoreMin = 40 private val treeScoreMin = 25 + private fun Int.inChunk() = (this / CHUNK_W) % 2 == 0 + + private fun getRandomX(): Int { + var posX = (Math.random() * world.width).toInt() + while (!posX.inChunk()) + posX = (Math.random() * world.width).toInt() + + return posX + } + private fun tryForSpawnPoint(world: GameWorld): Point2i { val yInit = getChunkGenStrip(world).first val tallies = ArrayList>() // xypos, score (0..1+) @@ -215,7 +227,7 @@ object Worldgen { var found = false val ySearchRadius = 30 while (tries < 99) { - val posX = (Math.random() * world.width).toInt() + val posX = getRandomX() var posY = yInit * CHUNK_H // go up? if (BlockCodex[world.getTileFromTerrain(posX, posY)].isSolid) { @@ -441,6 +453,55 @@ object Worldgen { return highlandLowlandSelectCache } + private fun getLandBlock(params: TerragenParams, seed: Long): ModuleCache { + val landBlock = ModuleScaleDomain().also { + it.setSource(ModuleFractal().also { + it.setType(ModuleFractal.FractalType.DECARPENTIERSWISS) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(2) + it.setFrequency(params.landBlockScale / params.featureSize) + it.seed = seed shake "LandBlock" + }) + it.setScaleX(1.0 / 4.0) + it.setScaleZ(1.0 / 4.0) + it.setScaleY(1.0 / 18.0) + } + + val landBlockPerturbFractal = ModuleScaleOffset().also { + it.setSource(ModuleFractal().also { + it.setType(ModuleFractal.FractalType.FBM) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(6) + it.setFrequency((params.landBlockScale * 3.0) / params.featureSize) + it.seed = seed shake "MassiveMassif" + }) + it.setScale(24.0) + } + + val landBlockPerturb = ModuleTranslateDomain().also { + it.setSource(landBlock) + it.setAxisXSource(landBlockPerturbFractal) + it.setAxisZSource(landBlockPerturbFractal) + } + + val landBlockClamp = ModuleClamp().also { + it.setSource(ModuleScaleOffset().also { + it.setSource(landBlockPerturb) + it.setScale(1.0) + it.setOffset(-1.0) + }) + it.setRange(0.0, 1.0) + } + + val landBlockCache = ModuleCache().also { + it.setSource(landBlockClamp) + } + + return landBlockCache + } + private fun getCaveAttenuateBiasScaled(highlandLowlandSelectCache: ModuleCache, params: TerragenParams): ModuleCache { val caveAttenuateBias1 = ModuleCache().also { it.setSource(ModuleBias().also { it.setSource(highlandLowlandSelectCache)