working lava pool prototype

This commit is contained in:
minjaesong
2024-09-08 01:51:40 +09:00
parent 11cdcbe2fc
commit 56c12949f8
8 changed files with 276 additions and 21 deletions

View File

@@ -160,3 +160,4 @@ id;classname;tags
# reserved for debug items # reserved for debug items
16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL 16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL
16777217;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessLavaBucket;DEBUG,TOOL
1 id classname tags
160
161
162
163

View File

@@ -0,0 +1,35 @@
package com.sudoplay.joise.module
import com.sudoplay.joise.ModuleInstanceMap
import com.sudoplay.joise.ModuleMap
import com.sudoplay.joise.ModulePropertyMap
/**
* Created by minjaesong on 2024-09-08.
*/
class ModuleConstant : Module() {
private val constant = ScalarParameter(1.0)
override fun _writeToMap(map: ModuleMap?) {
val props = ModulePropertyMap(this)
writeScalar("constant", constant, props, map)
map!![id] = props
}
override fun get(x: Double, y: Double) = constant.value
override fun get(x: Double, y: Double, z: Double) = constant.value
override fun get(x: Double, y: Double, z: Double, w: Double) = constant.value
override fun get(x: Double, y: Double, z: Double, w: Double, u: Double, v: Double) = constant.value
fun setConstant(c: Double) {
constant.set(c)
}
override fun buildFromPropertyMap(props: ModulePropertyMap?, map: ModuleInstanceMap?): Module {
readScalar("constant", "setConstant", props, map)
return this
}
}

View File

@@ -0,0 +1,53 @@
package com.sudoplay.joise.module
import com.sudoplay.joise.ModuleInstanceMap
import com.sudoplay.joise.ModuleMap
import com.sudoplay.joise.ModulePropertyMap
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC
/**
* Params:
* - H: World height MINUS 100
* - L: 620
*
* Created by minjaesong on 2024-09-07.
*/
class TerrarumModuleCaveLayerClosureGrad : Module() {
protected val h = ScalarParameter(17.2)
protected val l = ScalarParameter(3.0)
private fun Double.op() = Math.sqrt((-this + h.value - l.value) / l.value).let { if (it.isNaN()) 0.0 else it.coerceIn(0.0, 1.0) }
override fun get(x: Double, y: Double) = y.op()
override fun get(x: Double, y: Double, z: Double) = y.op()/*.also {
println("$y\t$it")
}*/
override fun get(x: Double, y: Double, z: Double, w: Double) = y.op()
override fun get(x: Double, y: Double, z: Double, w: Double, u: Double, v: Double) = y.op()
fun setL(source: Double) {
l.set(source)
}
fun setH(source: Double) {
h.set(source)
}
override fun _writeToMap(map: ModuleMap?) {
val props = ModulePropertyMap(this)
writeScalar("l", l, props, map)
writeScalar("h", h, props, map)
map!![id] = props
}
override fun buildFromPropertyMap(props: ModulePropertyMap?, map: ModuleInstanceMap?): Module {
readScalar("l", "setL", props, map)
readScalar("h", "setH", props, map)
return this
}
}

View File

@@ -0,0 +1,54 @@
package com.sudoplay.joise.module
import com.sudoplay.joise.ModuleInstanceMap
import com.sudoplay.joise.ModuleMap
import com.sudoplay.joise.ModulePropertyMap
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC
/**
* Params:
* - H: World height MINUS 100
* - L: 620
*
* Created by minjaesong on 2024-09-07.
*/
class TerrarumModuleLavaFloorGrad : Module() {
protected val h = ScalarParameter(5300.0)
protected val l = ScalarParameter(620.0)
private fun undoYtransform(yp: Double): Double = yp + (3200 - YHEIGHT_MAGIC) * YHEIGHT_DIVISOR
private fun Double.op() = Math.sqrt((this - h.value + l.value) / l.value).let { if (it.isNaN()) 0.0 else it }
override fun get(x: Double, y: Double) = undoYtransform(y).op()
override fun get(x: Double, y: Double, z: Double) = undoYtransform(y).op()/*.also {
println("$y\t$it")
}*/
override fun get(x: Double, y: Double, z: Double, w: Double) = undoYtransform(y).op()
override fun get(x: Double, y: Double, z: Double, w: Double, u: Double, v: Double) = undoYtransform(y).op()
fun setL(source: Double) {
l.set(source)
}
fun setH(source: Double) {
h.set(source)
}
override fun _writeToMap(map: ModuleMap?) {
val props = ModulePropertyMap(this)
writeScalar("l", l, props, map)
writeScalar("h", h, props, map)
map!![id] = props
}
override fun buildFromPropertyMap(props: ModulePropertyMap?, map: ModuleInstanceMap?): Module {
readScalar("l", "setL", props, map)
readScalar("h", "setH", props, map)
return this
}
}

View File

@@ -50,7 +50,6 @@ object WorldSimulator {
const val FLUID_MAX_COMP = 0.02f // How much excess water a cell can store, compared to the cell above it. A tile of fluid can contain more than MaxMass water. const val FLUID_MAX_COMP = 0.02f // How much excess water a cell can store, compared to the cell above it. A tile of fluid can contain more than MaxMass water.
// const val FLUID_MIN_MASS = net.torvald.terrarum.gameworld.FLUID_MIN_MASS //Ignore cells that are almost dry (smaller than epsilon of float16) // const val FLUID_MIN_MASS = net.torvald.terrarum.gameworld.FLUID_MIN_MASS //Ignore cells that are almost dry (smaller than epsilon of float16)
const val minFlow = 1f / 512f const val minFlow = 1f / 512f
const val maxSpeed = 1f // max units of water moved out of one block to another, per timestamp
// END OF FLUID-RELATED STUFFS // END OF FLUID-RELATED STUFFS
@@ -348,6 +347,8 @@ object WorldSimulator {
val worldY = y + updateYFrom val worldY = y + updateYFrom
val remainingType = fluidTypeMap[y][x] val remainingType = fluidTypeMap[y][x]
val maxSpeed = 1f / FluidCodex[remainingType].viscosity.sqr()
// check solidity // check solidity
if (!isFlowable(remainingType, worldX, worldY)) continue if (!isFlowable(remainingType, worldX, worldY)) continue
// check if the fluid is a same kind // check if the fluid is a same kind
@@ -386,7 +387,7 @@ object WorldSimulator {
if (flow > minFlow) { if (flow > minFlow) {
flow *= 0.5f flow *= 0.5f
} }
flow = flow.coerceIn(0f, remainingMass) flow = flow.coerceIn(0f, min(maxSpeed, remainingMass))
fluidNewMap[y][x] -= flow fluidNewMap[y][x] -= flow
fluidNewMap[y][x - 1] += flow fluidNewMap[y][x - 1] += flow
@@ -406,7 +407,7 @@ object WorldSimulator {
if (flow > minFlow) { if (flow > minFlow) {
flow *= 0.5f flow *= 0.5f
} }
flow = flow.coerceIn(0f, remainingMass) flow = flow.coerceIn(0f, min(maxSpeed, remainingMass))
fluidNewMap[y][x] -= flow fluidNewMap[y][x] -= flow
fluidNewMap[y][x + 1] += flow fluidNewMap[y][x + 1] += flow

View File

@@ -38,4 +38,34 @@ class ItemBottomlessWaterBucket(originalID: ItemID) : GameItem(originalID) {
return -1L return -1L
} }
} }
}
/**
* Created by minjaesong on 2024-09-07.
*/
class ItemBottomlessLavaBucket(originalID: ItemID) : GameItem(originalID) {
override var baseToolSize: Double? = PickaxeCore.BASE_MASS_AND_SIZE
override var inventoryCategory = Category.TOOL
override val canBeDynamic = false
override val materialId = "CUPR"
override var baseMass = 2.0
override var equipPosition = HAND_GRIP
override var originalName = "ITEM_BOTTOMLESS_LAVA_BUCKET"
init {
stackable = false
isUnique = true
}
override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long {
val mx = Terrarum.mouseTileX; val my =Terrarum.mouseTileY
if (!BlockCodex[INGAME.world.getTileFromTerrain(mx, my)].isSolid) {
INGAME.world.setFluid(mx, my, Fluid.LAVA, 1f)
return 0L
}
else {
return -1L
}
}
} }

View File

@@ -256,10 +256,11 @@ interface TerragenParams {
val caveBlockageFractalFreq: Double val caveBlockageFractalFreq: Double
val caveBlockageSelectThre: Double // adjust cave closing-up strength. Lower = more closing val caveBlockageSelectThre: Double // adjust cave closing-up strength. Lower = more closing
val rockBandCutoffFreq: Double val rockBandCutoffFreq: Double
}
val lavaShapeFreg: Double }
data class TerragenParamsAlpha1( data class TerragenParamsAlpha1(
override val terragenTiers: List<Double> = listOf(.0, .5, 1.0, 2.5, 11.0), override val terragenTiers: List<Double> = listOf(.0, .5, 1.0, 2.5, 11.0 * 9999),
override val featureSize: Double = 333.0, override val featureSize: Double = 333.0,
override val lowlandScaleOffset: Double = -0.65, // linearly alters the height override val lowlandScaleOffset: Double = -0.65, // linearly alters the height
@@ -277,10 +278,12 @@ data class TerragenParamsAlpha1(
override val caveBlockageSelectThre: Double = 1.40, // adjust cave closing-up strength. Lower = more closing override val caveBlockageSelectThre: Double = 1.40, // adjust cave closing-up strength. Lower = more closing
override val rockBandCutoffFreq: Double = 4.0, override val rockBandCutoffFreq: Double = 4.0,
override val lavaShapeFreg: Double = 0.03,
) : TerragenParams ) : TerragenParams
data class TerragenParamsAlpha2( data class TerragenParamsAlpha2(
override val terragenTiers: List<Double> = listOf(.0, .5, 1.5, 3.75, 11.0), override val terragenTiers: List<Double> = listOf(.0, .5, 1.5, 3.75, 11.0 * 9999),
override val featureSize: Double = 333.0, override val featureSize: Double = 333.0,
override val lowlandScaleOffset: Double = -0.65, // linearly alters the height override val lowlandScaleOffset: Double = -0.65, // linearly alters the height
@@ -298,4 +301,7 @@ data class TerragenParamsAlpha2(
override val caveBlockageSelectThre: Double = 1.40, // adjust cave closing-up strength. Lower = more closing override val caveBlockageSelectThre: Double = 1.40, // adjust cave closing-up strength. Lower = more closing
override val rockBandCutoffFreq: Double = 4.0, override val rockBandCutoffFreq: Double = 4.0,
override val lavaShapeFreg: Double = 0.03,
) : TerragenParams ) : TerragenParams

View File

@@ -19,20 +19,25 @@ import com.sudoplay.joise.ModuleMap
import com.sudoplay.joise.ModulePropertyMap import com.sudoplay.joise.ModulePropertyMap
import com.sudoplay.joise.module.* import com.sudoplay.joise.module.*
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.terrarum.* import net.torvald.terrarum.FlippingSpriteBatch
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.concurrent.ThreadExecutor import net.torvald.terrarum.concurrent.ThreadExecutor
import net.torvald.terrarum.modulebasegame.worldgenerator.* import net.torvald.terrarum.inUse
import net.torvald.terrarum.modulebasegame.worldgenerator.BiomegenParams
import net.torvald.terrarum.modulebasegame.worldgenerator.TerragenParams
import net.torvald.terrarum.modulebasegame.worldgenerator.TerragenParamsAlpha2
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC
import net.torvald.terrarum.modulebasegame.worldgenerator.shake
import net.torvald.terrarum.sqr
import net.torvald.terrarum.worlddrawer.toRGBA import net.torvald.terrarum.worlddrawer.toRGBA
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
import java.io.PrintStream
import java.util.*
import java.util.concurrent.Callable
import java.util.concurrent.Future import java.util.concurrent.Future
import kotlin.math.* import kotlin.math.*
import kotlin.random.Random import kotlin.random.Random
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC
import java.io.PrintStream
import java.util.Calendar
import java.util.concurrent.Callable
const val NOISEBOX_WIDTH = 90 * 18 const val NOISEBOX_WIDTH = 90 * 18
const val NOISEBOX_HEIGHT = 90 * 26 const val NOISEBOX_HEIGHT = 90 * 26
@@ -227,10 +232,8 @@ class WorldgenNoiseSandbox : ApplicationAdapter() {
threadExecutor.renew() threadExecutor.renew()
callables.forEach { callables.shuffle()
threadExecutor.submit(it) threadExecutor.submitAll(callables)
}
threadExecutor.join() threadExecutor.join()
worldgenDone = true worldgenDone = true
@@ -388,6 +391,7 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
private val AMETHYST = 0xee77ffff.toInt() private val AMETHYST = 0xee77ffff.toInt()
private val ROCKSALT = 0xff00ffff.toInt() private val ROCKSALT = 0xff00ffff.toInt()
private val NITRE = 0xdbd6a1ff.toInt() private val NITRE = 0xdbd6a1ff.toInt()
private val LAVA = 0xff5900ff.toInt()
private val oreCols = listOf( private val oreCols = listOf(
COPPER_ORE, IRON_ORE, COAL_ORE, ZINC_ORE, TIN_ORE, GOLD_ORE, SILVER_ORE, LEAD_ORE, ROCKSALT, QUARTZ, AMETHYST, NITRE COPPER_ORE, IRON_ORE, COAL_ORE, ZINC_ORE, TIN_ORE, GOLD_ORE, SILVER_ORE, LEAD_ORE, ROCKSALT, QUARTZ, AMETHYST, NITRE
@@ -399,16 +403,19 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
override fun draw(x: Int, y: Int, noiseValue: List<Double>, outTex: Pixmap) { override fun draw(x: Int, y: Int, noiseValue: List<Double>, outTex: Pixmap) {
val terr = noiseValue[0].tiered(terragenTiers) val terr = noiseValue[0].tiered(terragenTiers)
val cave = if (noiseValue[1] < 0.5) 0 else 1 val cave = if (noiseValue[1] < 0.5) 0 else 1
val ore = (noiseValue.subList(2, noiseValue.size)).zip(oreCols).firstNotNullOfOrNull { (n, colour) -> if (n > 0.5) colour else null } val ore = (noiseValue.subList(2, noiseValue.size - 1)).zip(oreCols).firstNotNullOfOrNull { (n, colour) -> if (n > 0.5) colour else null }
val isMarble = false // noiseValue[13] > 0.5 val isMarble = false // noiseValue[13] > 0.5
val wallBlock = if (isMarble) Block.STONE_MARBLE else groundDepthBlockWall[terr] val wallBlock = if (isMarble) Block.STONE_MARBLE else groundDepthBlockWall[terr]
val terrBlock = if (cave == 0) Block.AIR else if (isMarble) Block.STONE_MARBLE else groundDepthBlockTERR[terr] val terrBlock = if (cave == 0) Block.AIR else if (isMarble) Block.STONE_MARBLE else groundDepthBlockTERR[terr]
val lavaVal = noiseValue.last()
val lava = (lavaVal >= 0.5)
outTex.drawPixel(x, y, outTex.drawPixel(x, y,
if (ore != null && (terrBlock == Block.STONE || terrBlock == Block.STONE_SLATE)) ore if (lava) LAVA
else if (ore != null && (terrBlock == Block.STONE || terrBlock == Block.STONE_SLATE)) ore
else if (wallBlock == Block.AIR && terrBlock == Block.AIR) BACK else if (wallBlock == Block.AIR && terrBlock == Block.AIR) BACK
else blockToCol[terrBlock]!!.toRGBA() else blockToCol[terrBlock]!!.toRGBA()
) )
@@ -650,11 +657,19 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
it.setOffset(0.0) it.setOffset(0.0)
} }
val cavePerturb = ModuleTranslateDomain().also { val cavePerturb0 = ModuleTranslateDomain().also {
it.setSource(caveShapeAttenuate) it.setSource(caveShapeAttenuate)
it.setAxisXSource(cavePerturbScale) it.setAxisXSource(cavePerturbScale)
} }
val caveTerminalClosureGrad = TerrarumModuleCaveLayerClosureGrad()
val cavePerturb = ModuleCombiner().also { // 0: rock, 1: air
it.setType(ModuleCombiner.CombinerType.MULT)
it.setSource(0, cavePerturb0)
it.setSource(1, caveTerminalClosureGrad)
}
val caveSelect = ModuleSelect().also { val caveSelect = ModuleSelect().also {
it.setLowSource(1.0) it.setLowSource(1.0)
it.setHighSource(0.0) it.setHighSource(0.0)
@@ -663,7 +678,7 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
it.setFalloff(0.0) it.setFalloff(0.0)
} }
val caveBlockageFractal = ModuleFractal().also { val caveBlockageFractal0 = ModuleFractal().also {
it.setType(ModuleFractal.FractalType.RIDGEMULTI) it.setType(ModuleFractal.FractalType.RIDGEMULTI)
it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT)
it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC)
@@ -672,6 +687,11 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
it.seed = seed shake caveBlockageMagic it.seed = seed shake caveBlockageMagic
} }
val caveBlockageFractal = ModuleCombiner().also { // 0: air, 1: rock
it.setType(ModuleCombiner.CombinerType.MULT)
it.setSource(0, caveBlockageFractal0)
}
// will only close-up deeper caves. Shallow caves will be less likely to be closed up // will only close-up deeper caves. Shallow caves will be less likely to be closed up
val caveBlockageAttenuate = ModuleCombiner().also { val caveBlockageAttenuate = ModuleCombiner().also {
it.setType(ModuleCombiner.CombinerType.MULT) it.setType(ModuleCombiner.CombinerType.MULT)
@@ -759,6 +779,8 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
Joise(generateRockLayer(groundScalingCached, seed, params, (0..7).map { Joise(generateRockLayer(groundScalingCached, seed, params, (0..7).map {
thicknesses[it] + marblerng.nextTriangularBal() * 0.006 to (2.6 * terragenYscaling) + it * 0.18 + marblerng.nextTriangularBal() * 0.09 thicknesses[it] + marblerng.nextTriangularBal() * 0.006 to (2.6 * terragenYscaling) + it * 0.18 + marblerng.nextTriangularBal() * 0.09
})), })),
Joise(generateSeaOfLava(seed)),
) )
} }
@@ -905,6 +927,59 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker {
return oreSelect return oreSelect
} }
private fun generateSeaOfLava(seed: Long): Module {
val lavaPipe = ModuleScaleDomain().also {
it.setSource(ModuleFractal().also {
it.setType(ModuleFractal.FractalType.RIDGEMULTI)
it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT)
it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC)
it.setNumOctaves(1)
it.setFrequency(params.lavaShapeFreg) // adjust the "density" of the caves
it.seed = seed shake "LattiaOnLavaa"
})
it.setScaleY(1.0 / 6.0)
}
val lavaPerturbFractal = ModuleFractal().also {
it.setType(ModuleFractal.FractalType.FBM)
it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT)
it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC)
it.setNumOctaves(6)
it.setFrequency(params.lavaShapeFreg * 3.0 / 4.0)
it.seed = seed shake "FloorIsLava"
}
val lavaPerturbScale = ModuleScaleOffset().also {
it.setSource(lavaPerturbFractal)
it.setScale(23.0)
it.setOffset(0.0)
}
val lavaPerturb = ModuleTranslateDomain().also {
it.setSource(lavaPipe)
it.setAxisXSource(lavaPerturbScale)
}
// val = sqrt((y-H+L) / L); where H=5300 (world height-100), L=620;
// 100 is the height of the "base lava sheet", 600 is the height of the "transitional layer"
// in this setup, the entire lava layer never exceeds 8 chunks (720 tiles) in height
val lavaGrad = TerrarumModuleLavaFloorGrad().also {
it.setH(5300.0)
it.setL(620.0)
}
val lavaSelect = ModuleSelect().also {
it.setLowSource(1.0)
it.setHighSource(0.0)
it.setControlSource(lavaPerturb)
it.setThreshold(lavaGrad)
it.setFalloff(0.0)
}
return lavaSelect
}
private object DummyModule : Module() { private object DummyModule : Module() {
override fun get(x: Double, y: Double) = 0.0 override fun get(x: Double, y: Double) = 0.0