mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
treegen wip
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user