From 6ae39d38e35117da51089e6b0c4b2a9175245fd0 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 4 Nov 2023 00:54:15 +0900 Subject: [PATCH] cavegen after the oregen --- assets/mods/basegame/gui/loadscr_layer01.png | 4 +- assets/mods/basegame/gui/loadscr_layer03.png | 3 + .../FancyWorldReadLoadScreen.kt | 6 +- .../modulebasegame/worldgenerator/Cavegen.kt | 169 ++++++++++++++++++ .../modulebasegame/worldgenerator/Terragen.kt | 118 +----------- .../modulebasegame/worldgenerator/Worldgen.kt | 1 + 6 files changed, 188 insertions(+), 113 deletions(-) create mode 100644 assets/mods/basegame/gui/loadscr_layer03.png create mode 100644 src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt diff --git a/assets/mods/basegame/gui/loadscr_layer01.png b/assets/mods/basegame/gui/loadscr_layer01.png index 4543c4760..02fea463b 100644 --- a/assets/mods/basegame/gui/loadscr_layer01.png +++ b/assets/mods/basegame/gui/loadscr_layer01.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5f0c0dcd3229f0ed324f5acf9d28d77eb580c8800fadcdcd0298ff4616b891a -size 50389 +oid sha256:23b119e197d4c5a0935ede71fb5ac0f8eab5c54305d2072a7c39ca7bf685968f +size 6113 diff --git a/assets/mods/basegame/gui/loadscr_layer03.png b/assets/mods/basegame/gui/loadscr_layer03.png new file mode 100644 index 000000000..64dc1c8ef --- /dev/null +++ b/assets/mods/basegame/gui/loadscr_layer03.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f42132d0aa45c62de8c06df646de0b3c61e674a6fcad28d631f2e899626a0ee1 +size 75740 diff --git a/src/net/torvald/terrarum/modulebasegame/FancyWorldReadLoadScreen.kt b/src/net/torvald/terrarum/modulebasegame/FancyWorldReadLoadScreen.kt index 79932b768..56e6aa980 100644 --- a/src/net/torvald/terrarum/modulebasegame/FancyWorldReadLoadScreen.kt +++ b/src/net/torvald/terrarum/modulebasegame/FancyWorldReadLoadScreen.kt @@ -23,6 +23,9 @@ open class FancyWorldReadLoadScreen(screenToBeLoaded: IngameInstance, private va CommonResourcePool.addToLoadingList("basegame-gui-loadscrlayer02") { Texture(ModMgr.getGdxFile("basegame", "gui/loadscr_layer02.png")) } + CommonResourcePool.addToLoadingList("basegame-gui-loadscrlayer03") { + Texture(ModMgr.getGdxFile("basegame", "gui/loadscr_layer03.png")) + } CommonResourcePool.loadAll() App.disposables.add(this) @@ -44,6 +47,7 @@ open class FancyWorldReadLoadScreen(screenToBeLoaded: IngameInstance, private va val baseTileTex = arrayOf( CommonResourcePool.getAsTexture("basegame-gui-loadscrlayer01"), CommonResourcePool.getAsTexture("basegame-gui-loadscrlayer02"), + CommonResourcePool.getAsTexture("basegame-gui-loadscrlayer03"), ) val drawWidth = Toolkit.drawWidth @@ -88,7 +92,7 @@ open class FancyWorldReadLoadScreen(screenToBeLoaded: IngameInstance, private va } protected open fun getStage(): Int { - return 2 // fixed value for Read screen + return 3 // fixed value for Read screen } protected val batchColour = Color(-1) // create new Color instance just for the progress bar diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt new file mode 100644 index 000000000..32c57ffc1 --- /dev/null +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Cavegen.kt @@ -0,0 +1,169 @@ +package net.torvald.terrarum.modulebasegame.worldgenerator + +import com.sudoplay.joise.Joise +import com.sudoplay.joise.module.* +import net.torvald.random.XXHash32 +import net.torvald.terrarum.App +import net.torvald.terrarum.LoadScreenBase +import net.torvald.terrarum.blockproperties.Block +import net.torvald.terrarum.concurrent.sliceEvenly +import net.torvald.terrarum.gameworld.GameWorld +import kotlin.math.cos +import kotlin.math.sin + +/** + * Created by minjaesong on 2023-11-04. + */ +class Cavegen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, seed: Long, params: Any) : Gen(world, seed, params) { + + companion object { + const val YHEIGHT_MAGIC = 2800.0 / 3.0 + const val YHEIGHT_DIVISOR = 2.0 / 7.0 + } + + override fun getDone(loadscreen: LoadScreenBase) { + loadscreen.stageValue += 1 + loadscreen.progress.set(0L) + + Worldgen.threadExecutor.renew() + (0 until world.width).sliceEvenly(Worldgen.genSlices).mapIndexed { i, xs -> + Worldgen.threadExecutor.submit { + val localJoise = getGenerator(seed, params as TerragenParams) + for (x in xs) { + val sampleTheta = (x.toDouble() / world.width) * TWO_PI + val sampleOffset = world.width / 8.0 + draw(x, localJoise, sampleTheta, sampleOffset) + } + loadscreen.progress.addAndGet((xs.last - xs.first + 1).toLong()) + } + } + + Worldgen.threadExecutor.join() + + App.printdbg(this, "Waking up Worldgen") + } + + + //private fun draw(x: Int, y: Int, width: Int, height: Int, noiseValue: List, world: GameWorld) { + private fun draw(x: Int, noises: List, st: Double, soff: Double) { + for (y in 0 until world.height) { + val sx = sin(st) * soff + soff // plus sampleOffset to make only + val sz = cos(st) * soff + soff // positive points are to be sampled + val sy = y - (world.height - YHEIGHT_MAGIC) * YHEIGHT_DIVISOR // Q&D offsetting to make ratio of sky:ground to be constant + // 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 cave = if (noiseValue[0] < 0.5) 0 else 1 + + if (cave == 0) { + world.setTileTerrain(x, y, Block.AIR, true) + } + } + } + + + private fun getGenerator(seed: Long, params: TerragenParams): List { + val caveMagic: Long = 0x00215741CDF // Urist McDF + val cavePerturbMagic: Long = 0xA2410C // Armok + val caveBlockageMagic: Long = 0xD15A57E5 // Disaster + + /* caves */ + + val caveShape = ModuleFractal().also { + it.setType(ModuleFractal.FractalType.RIDGEMULTI) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(1) + it.setFrequency(params.caveShapeFreq) // adjust the "density" of the caves + it.seed = seed shake caveMagic + } + + val caveAttenuateBias = ModuleBias().also { + it.setSource(highlandLowlandSelectCache) + it.setBias(params.caveAttenuateBias) // (0.5+) adjust the "concentration" of the cave gen. Lower = larger voids + } + + val caveShapeAttenuate = ModuleCombiner().also { + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, caveShape) + it.setSource(1, caveAttenuateBias) + } + + val cavePerturbFractal = ModuleFractal().also { + it.setType(ModuleFractal.FractalType.FBM) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(6) + it.setFrequency(params.caveShapeFreq * 3.0 / 4.0) + it.seed = seed shake cavePerturbMagic + } + + val cavePerturbScale = ModuleScaleOffset().also { + it.setSource(cavePerturbFractal) + it.setScale(0.45) + it.setOffset(0.0) + } + + val cavePerturb = ModuleTranslateDomain().also { + it.setSource(caveShapeAttenuate) + it.setAxisXSource(cavePerturbScale) + } + + val caveSelect = ModuleSelect().also { + it.setLowSource(1.0) + it.setHighSource(0.0) + it.setControlSource(cavePerturb) + it.setThreshold(params.caveSelectThre) // also adjust this if you've touched the bias value. Number can be greater than 1.0 + it.setFalloff(0.0) + } + + val caveBlockageFractal = ModuleFractal().also { + it.setType(ModuleFractal.FractalType.RIDGEMULTI) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(2) + it.setFrequency(params.caveBlockageFractalFreq) // same as caveShape frequency? + it.seed = seed shake caveBlockageMagic + } + + // will only close-up deeper caves. Shallow caves will be less likely to be closed up + val caveBlockageAttenuate = ModuleCombiner().also { + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, caveBlockageFractal) + it.setSource(1, caveAttenuateBias) + } + + val caveBlockageSelect = ModuleSelect().also { + it.setLowSource(0.0) + it.setHighSource(1.0) + it.setControlSource(caveBlockageAttenuate) + it.setThreshold(params.caveBlockageSelectThre) // adjust cave cloing-up strength. Larger = more closing + it.setFalloff(0.0) + } + + // note: gradient-multiply DOESN'T generate "naturally cramped" cave entrance + + val caveInMix = ModuleCombiner().also { + it.setType(ModuleCombiner.CombinerType.ADD) + it.setSource(0, caveSelect) + it.setSource(1, caveBlockageSelect) + } + + val caveClamp = ModuleClamp().also { + it.setRange(0.0, 1.0) + it.setSource(caveInMix) + } + + val caveScaling = ModuleScaleDomain().also { + it.setScaleX(1.0 / params.featureSize) // adjust this value to change features size + it.setScaleY(1.0 / params.featureSize) + it.setScaleZ(1.0 / params.featureSize) + it.setSource(caveClamp) + } + + + return listOf( + Joise(caveScaling) + ) + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index bbbfacd0a..cdbe45df0 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -74,7 +74,6 @@ class Terragen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, se val noiseValue = noises.map { it.get(sx, sy, sz) } val terr = noiseValue[0].tiered(.0, .5, .88, 1.88) - val cave = if (noiseValue[1] < 0.5) 0 else 1 // mark off the position where the transition occurred if (dirtStoneTransition == 0 && terr == 2) @@ -83,7 +82,7 @@ class Terragen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, se stoneSlateTransition = y val wallBlock = groundDepthBlock[terr] - val terrBlock = if (cave == 0) Block.AIR else wallBlock + val terrBlock = wallBlock world.setTileTerrain(x, y, terrBlock, true) world.setTileWall(x, y, wallBlock, true) @@ -103,14 +102,14 @@ class Terragen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, se val y = pos + dirtStoneTransition - (dirtStoneDitherSize * 2) + 1 if (y >= world.height) break val hash = XXHash32.hashGeoCoord(x, y).and(0x7FFFFFFF) / 2147483647.0 - val fore = world.getTileFromTerrain(x, y) - val back = world.getTileFromWall(x, y) +// 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 (fore != Block.AIR) world.setTileTerrain(x, y, newTile, true) world.setTileWall(x, y, newTile, true) @@ -125,11 +124,11 @@ class Terragen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, se val y = pos + stoneSlateTransition - stoneSlateDitherSize + 1 if (y >= world.height) break val hash = XXHash32.hashGeoCoord(x, y).and(0x7FFFFFFF) / 2147483647.0 - val fore = world.getTileFromTerrain(x, y) - val back = world.getTileFromWall(x, y) +// 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 (fore != Block.AIR) +// if (fore != Block.AIR) world.setTileTerrain(x, y, newTile, true) world.setTileWall(x, y, newTile, true) @@ -138,92 +137,6 @@ class Terragen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, se private fun getGenerator(seed: Long, params: TerragenParams): List { - val caveMagic: Long = 0x00215741CDF // Urist McDF - val cavePerturbMagic: Long = 0xA2410C // Armok - val caveBlockageMagic: Long = 0xD15A57E5 // Disaster - - /* caves */ - - val caveShape = ModuleFractal().also { - it.setType(ModuleFractal.FractalType.RIDGEMULTI) - it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) - it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) - it.setNumOctaves(1) - it.setFrequency(params.caveShapeFreq) // adjust the "density" of the caves - it.seed = seed shake caveMagic - } - - val caveAttenuateBias = ModuleBias().also { - it.setSource(highlandLowlandSelectCache) - it.setBias(params.caveAttenuateBias) // (0.5+) adjust the "concentration" of the cave gen. Lower = larger voids - } - - val caveShapeAttenuate = ModuleCombiner().also { - it.setType(ModuleCombiner.CombinerType.MULT) - it.setSource(0, caveShape) - it.setSource(1, caveAttenuateBias) - } - - val cavePerturbFractal = ModuleFractal().also { - it.setType(ModuleFractal.FractalType.FBM) - it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) - it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) - it.setNumOctaves(6) - it.setFrequency(params.caveShapeFreq * 3.0 / 4.0) - it.seed = seed shake cavePerturbMagic - } - - val cavePerturbScale = ModuleScaleOffset().also { - it.setSource(cavePerturbFractal) - it.setScale(0.45) - it.setOffset(0.0) - } - - val cavePerturb = ModuleTranslateDomain().also { - it.setSource(caveShapeAttenuate) - it.setAxisXSource(cavePerturbScale) - } - - val caveSelect = ModuleSelect().also { - it.setLowSource(1.0) - it.setHighSource(0.0) - it.setControlSource(cavePerturb) - it.setThreshold(params.caveSelectThre) // also adjust this if you've touched the bias value. Number can be greater than 1.0 - it.setFalloff(0.0) - } - - val caveBlockageFractal = ModuleFractal().also { - it.setType(ModuleFractal.FractalType.RIDGEMULTI) - it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) - it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) - it.setNumOctaves(2) - it.setFrequency(params.caveBlockageFractalFreq) // same as caveShape frequency? - it.seed = seed shake caveBlockageMagic - } - - // will only close-up deeper caves. Shallow caves will be less likely to be closed up - val caveBlockageAttenuate = ModuleCombiner().also { - it.setType(ModuleCombiner.CombinerType.MULT) - it.setSource(0, caveBlockageFractal) - it.setSource(1, caveAttenuateBias) - } - - val caveBlockageSelect = ModuleSelect().also { - it.setLowSource(0.0) - it.setHighSource(1.0) - it.setControlSource(caveBlockageAttenuate) - it.setThreshold(params.caveBlockageSelectThre) // adjust cave cloing-up strength. Larger = more closing - it.setFalloff(0.0) - } - - // note: gradient-multiply DOESN'T generate "naturally cramped" cave entrance - - val caveInMix = ModuleCombiner().also { - it.setType(ModuleCombiner.CombinerType.ADD) - it.setSource(0, caveSelect) - it.setSource(1, caveBlockageSelect) - } - // this noise tree WILL generate noise value greater than 1.0 // they should be treated properly when you actually generate the world out of the noisemap // for the visualisation, no treatment will be done in this demo app. @@ -240,23 +153,8 @@ class Terragen(world: GameWorld, val highlandLowlandSelectCache: ModuleCache, se it.setSource(groundClamp) } - val caveClamp = ModuleClamp().also { - it.setRange(0.0, 1.0) - it.setSource(caveInMix) - } - - val caveScaling = ModuleScaleDomain().also { - it.setScaleX(1.0 / params.featureSize) // adjust this value to change features size - it.setScaleY(1.0 / params.featureSize) - it.setScaleZ(1.0 / params.featureSize) - it.setSource(caveClamp) - } - - - //return Joise(caveInMix) return listOf( - Joise(groundScaling), - Joise(caveScaling) + Joise(groundScaling) ) } } diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt index 436574a75..dfd0d82ee 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Worldgen.kt @@ -60,6 +60,7 @@ object Worldgen { Work("Reticulating Splines", Terragen(world, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN")), Work("Adding Rocks", Oregen(world, caveAttenuateBiasScaled, params.seed, oreRegistry), listOf("ORES")), Work("Positioning Rocks", OregenAutotiling(world, params.seed, oreTilingModes), listOf("ORES")), + Work("Carving", Cavegen(world, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN", "CAVE")), Work("Adding Vegetations", Biomegen(world, params.seed, params.biomegenParams), listOf("BIOME")), ).filter(tagFilter) }