treegen wip

This commit is contained in:
minjaesong
2023-11-11 12:17:45 +09:00
parent 6291c799cf
commit df7089f4ac
3 changed files with 178 additions and 13 deletions

View File

@@ -7,14 +7,16 @@ import net.torvald.terrarum.LoadScreenBase
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.concurrent.sliceEvenly
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.realestate.LandUtil
import kotlin.math.cos
import kotlin.math.sin
/**
* Created by minjaesong on 2019-09-02.
*/
class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, params) {
class Biomegen(world: GameWorld, seed: Long, params: Any, val biomeMapOut: HashMap<BlockAddress, Byte>) : Gen(world, seed, params) {
private val YHEIGHT_MAGIC = 2800.0 / 3.0
private val YHEIGHT_DIVISOR = 2.0 / 7.0
@@ -84,33 +86,47 @@ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par
private const val BT = 5
private const val LF = 6
private const val RH = 7
const val BIOME_KEY_WOODLANDS = 1.toByte()
const val BIOME_KEY_SHRUBLANDS = 2.toByte()
const val BIOME_KEY_PLAINS = 3.toByte()
const val BIOME_KEY_ROCKY = (-1).toByte()
const val BIOME_KEY_SANDY = (-2).toByte()
const val BIOME_KEY_GRAVELS = (-3).toByte()
}
private fun draw(x: Int, y: Int, noiseValue: List<Double>, world: GameWorld) {
val control1 = noiseValue[0].coerceIn(0.0, 0.99999).times(slices).toInt().coerceAtMost(slices - 1)
val control2 = noiseValue[1].coerceIn(0.0, 0.99999).times(9).toInt().coerceAtMost(9 - 1)
val ba = LandUtil.getBlockAddr(world, x, y)
if (y > 0) {
val tileThis = world.getTileFromTerrain(x, y)
val wallThis = world.getTileFromWall(x, y)
val nearbyTerr = nearbyArr.map { world.getTileFromTerrain(x + it.first, y + it.second) }
val nearbyWall = nearbyArr.map { world.getTileFromWall(x + it.first, y + it.second) }
val exposedToAir = nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }
val hasNoFloor = (nearbyTerr[BT] == Block.AIR)
val grassRock = when (control1) {
0 -> { // woodlands
if (tileThis == Block.DIRT && nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }) {
if (tileThis == Block.DIRT && exposedToAir) {
biomeMapOut[ba] = BIOME_KEY_WOODLANDS
Block.GRASS to null
}
else null to null
}
1 -> { // shrublands
if (tileThis == Block.DIRT && nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }) {
if (tileThis == Block.DIRT && exposedToAir) {
biomeMapOut[ba] = BIOME_KEY_SHRUBLANDS
Block.GRASS to null
}
else null to null
}
2, 3 -> { // plains
if (tileThis == Block.DIRT && nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }) {
if (tileThis == Block.DIRT && exposedToAir) {
biomeMapOut[ba] = BIOME_KEY_PLAINS
Block.GRASS to null
}
else null to null
@@ -125,6 +141,7 @@ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par
}*/
4 -> { // rockylands
if (tileThis == Block.DIRT || tileThis == Block.STONE_QUARRIED) {
if (exposedToAir) biomeMapOut[ba] = BIOME_KEY_ROCKY
Block.STONE to Block.STONE
}
else null to null
@@ -133,19 +150,23 @@ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par
}
val sablum = when (control2) {
0 -> {
if (tileThis == Block.DIRT && (nearbyTerr[BT] == Block.AIR)) {
if (tileThis == Block.DIRT && hasNoFloor) {
if (exposedToAir) biomeMapOut[ba] = BIOME_KEY_GRAVELS
Block.STONE_QUARRIED to null
}
else if (tileThis == Block.DIRT) {
if (exposedToAir) biomeMapOut[ba] = BIOME_KEY_GRAVELS
Block.GRAVEL to null
}
else null to null
}
8 -> {
if (tileThis == Block.DIRT && (nearbyTerr[BT] == Block.AIR)) {
if (tileThis == Block.DIRT && hasNoFloor) {
if (exposedToAir) biomeMapOut[ba] = BIOME_KEY_SANDY
THISWORLD_SANDSTONE to null
}
else if (tileThis == Block.DIRT) {
if (exposedToAir) biomeMapOut[ba] = BIOME_KEY_SANDY
THISWORLD_SAND to null
}
else null to null

View File

@@ -1,6 +1,143 @@
package net.torvald.terrarum.modulebasegame.worldgenerator
import net.torvald.terrarum.App
import net.torvald.terrarum.BlockCodex
import net.torvald.terrarum.LoadScreenBase
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.concurrent.sliceEvenly
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.worldgenerator.Biomegen.Companion.BIOME_KEY_PLAINS
import net.torvald.terrarum.modulebasegame.worldgenerator.Biomegen.Companion.BIOME_KEY_SHRUBLANDS
import net.torvald.terrarum.modulebasegame.worldgenerator.Biomegen.Companion.BIOME_KEY_WOODLANDS
import net.torvald.terrarum.realestate.LandUtil
import kotlin.math.absoluteValue
/**
* Created by minjaesong on 2023-11-10.
*/class Treegen {
}
*/
class Treegen(world: GameWorld, seed: Long, params: TreegenParams, val biomeMap: HashMap<BlockAddress, Byte>) : Gen(world, seed, params) {
override fun getDone(loadscreen: LoadScreenBase) {
loadscreen.stageValue += 1
loadscreen.progress.set(0L)
Worldgen.threadExecutor.renew()
(0 until world.width).sliceEvenly(Worldgen.genSlices).rearrange().mapIndexed { i, xs ->
Worldgen.threadExecutor.submit {
tryToPlant(xs, makeGrassMap(xs))
loadscreen.progress.addAndGet((xs.last - xs.first + 1).toLong())
}
}
Worldgen.threadExecutor.join()
App.printdbg(this, "Waking up Worldgen")
}
private val treegenProbabilityToBiome = hashMapOf(
0.toByte() to 0.0,
BIOME_KEY_WOODLANDS to 1.0/params.woodlandsTreeDist,
BIOME_KEY_SHRUBLANDS to 1.0/params.shrublandsTreeDist,
BIOME_KEY_PLAINS to 1.0/params.plainsTreeDist,
)
private fun makeGrassMap(xs: IntProgression): Array<List<Int>> {
val STRIDE = 4
val r = Array<List<Int>>(xs.last - xs.first + 1) { emptyList() }
for (x in xs) {
val ys = ArrayList<Int>()
var y = 0
while (y < 800) {
val tile = world.getTileFromTerrain(x, y)
val tileProp = BlockCodex[tile]
if (tileProp.hasAnyTagOf("ROCK", "STONE")) break
if (tile == Block.GRASS) {
ys.add(y)
}
// if dirt was hit, climb back up until a grass is seen
else if (tile == Block.DIRT) {
var yi = 1
var tile0 = world.getTileFromTerrain(x, y - yi)
var found = false
while (tile0 == Block.DIRT || yi < STRIDE) {
tile0 = world.getTileFromTerrain(x, y - yi)
if (tile0 == Block.GRASS) found = true
yi += 1
}
// filter duplicates
if (found && ys.last() != y - yi) {
ys.add(y - yi)
}
}
y += STRIDE
}
r[x - xs.first] = ys
}
return r
}
private fun tryToPlant(xs: IntProgression, grassMap: Array<List<Int>>) {
for (x in xs.first+1..xs.last-1) {
grassMap[x - xs.first].forEachIndexed { index, y ->
val yLeft = grassMap[x - xs.first - 1].getOrNull(index) ?: -1
val yRight = grassMap[x - xs.first + 1].getOrNull(index) ?: -1
val grad1 = y - yLeft
val grad2 = yRight - y
if ((grad1 * grad2).absoluteValue <= 1) {
val rnd = Math.random()
val biome = biomeMap[LandUtil.getBlockAddr(world, x, y)] ?: 0
val prob = treegenProbabilityToBiome[biome]!!
// actually plant a tree
if (rnd < prob) {
}
}
}
for (y in grassMap[x - xs.first]) {
}
}
}
/**
* Rearranges the list such that:
* `1,2,3,4,5,6,7,8,9`
* is ordered as:
* `1,5,9,2,6,3,7,4,8`
*/
private fun List<IntProgression>.rearrange(): List<IntProgression> {
val r = ArrayList<IntProgression>()
val stride = this.size / 2
for (i in 0 until stride) {
var b = i
while (b < this.size) {
r.add(this[b])
b += stride
}
}
return r
}
}
data class TreegenParams(
val woodlandsTreeDist: Int = 9, // distances are merely a suggestion tho
val shrublandsTreeDist: Int = 14,
val plainsTreeDist: Int = 21,
)

View File

@@ -7,6 +7,7 @@ import net.torvald.terrarum.App.*
import net.torvald.terrarum.BlockCodex
import net.torvald.terrarum.LoadScreenBase
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame
@@ -36,6 +37,8 @@ object Worldgen {
internal lateinit var highlandLowlandSelectCache: ModuleCache
internal lateinit var caveAttenuateBiasScaled: ModuleScaleDomain
internal lateinit var biomeMap: HashMap<BlockAddress, Byte>
/**
* Other modules are free to add their own ores to the world generator.
@@ -62,13 +65,16 @@ object Worldgen {
Work(Lang["MENU_IO_WORLDGEN_GROWING_MINERALS"], Oregen(world, caveAttenuateBiasScaled, params.seed, oreRegistry), listOf("ORES")),
Work(Lang["MENU_IO_WORLDGEN_POSITIONING_ROCKS"], OregenAutotiling(world, params.seed, oreTilingModes), listOf("ORES")),
Work(Lang["MENU_IO_WORLDGEN_CARVING_EARTH"], Cavegen(world, highlandLowlandSelectCache, params.seed, params.terragenParams), listOf("TERRAIN", "CAVE")),
Work(Lang["MENU_IO_WORLDGEN_PAINTING_GREEN"], Biomegen(world, params.seed, params.biomegenParams), listOf("BIOME")),
Work(Lang["MENU_IO_WORLDGEN_PAINTING_GREEN"], Biomegen(world, params.seed, params.biomegenParams, biomeMap), listOf("BIOME")),
Work(Lang["MENU_IO_WORLDGEN_PAINTING_GREEN"], Treegen(world, params.seed, params.treegenParams, biomeMap), listOf("TREES")),
).filter(tagFilter)
}
fun generateMap(loadscreen: LoadScreenBase) {
highlandLowlandSelectCache = getHighlandLowlandSelectCache(params.terragenParams, params.seed)
caveAttenuateBiasScaled = getCaveAttenuateBiasScaled(highlandLowlandSelectCache, params.terragenParams)
biomeMap = HashMap()
genSlices = max(threadExecutor.threadCount, world.width / 9)
@@ -271,10 +277,11 @@ abstract class Gen(val world: GameWorld, val seed: Long, val params: Any? = null
}
data class WorldgenParams(
val seed: Long,
// optional parameters
val terragenParams: TerragenParams = TerragenParams(),
val biomegenParams: BiomegenParams = BiomegenParams()
val seed: Long,
// optional parameters
val terragenParams: TerragenParams = TerragenParams(),
val biomegenParams: BiomegenParams = BiomegenParams(),
val treegenParams: TreegenParams = TreegenParams(),
)
infix fun Long.shake(other: Long): Long {