weather in weathercodex

This commit is contained in:
minjaesong
2024-04-14 00:18:30 +09:00
parent 670a308c78
commit 4fba0f70c9
48 changed files with 311 additions and 208 deletions

View File

@@ -2,10 +2,10 @@ package net.torvald.terrarum.weather
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.math.Vector3
import com.badlogic.gdx.utils.JsonValue
import com.jme3.math.FastMath
import net.torvald.terrarum.GdxColorMap
import net.torvald.terrarum.TaggedProp
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import kotlin.math.absoluteValue
@@ -21,7 +21,7 @@ data class BaseModularWeather(
val json: JsonValue,
var skyboxGradColourMap: GdxColorMap, // row 0: skybox grad top, row 1: skybox grad bottom, row 2: sunlight (RGBA)
val daylightClut: GdxColorMap,
val classification: String,
val tags: List<String>,
val cloudChance: Float,
val windSpeed: Float,
val windSpeedVariance: Float,
@@ -33,7 +33,7 @@ data class BaseModularWeather(
val mixFrom: String? = null,
val mixPercentage: Double? = null,
) {
) : TaggedProp {
/**
@@ -60,6 +60,10 @@ data class BaseModularWeather(
return Vector2(gx, gy)
}
override fun hasTag(s: String) = tags.contains(s)
}
data class CloudProps(

View File

@@ -0,0 +1,121 @@
package net.torvald.terrarum.weather
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.utils.Disposable
import net.torvald.terrarum.App
import net.torvald.terrarum.GdxColorMap
import net.torvald.terrarum.ModMgr
import net.torvald.terrarum.tryDispose
import net.torvald.terrarum.utils.JsonFetcher
import net.torvald.terrarum.utils.forEachSiblings
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import java.io.File
/**
* Created by minjaesong on 2024-04-13.
*/
class WeatherCodex : Disposable {
internal val weatherById = HashMap<String, BaseModularWeather>()
internal val weatherByTags = HashMap<String, MutableSet<BaseModularWeather>>()
fun getById(id: String) = weatherById[id]
fun getByAllTags(tags: Array<String>) = weatherById.values.filter { it.hasAllTags(tags) }.ifEmpty { null }
fun getByAllTags(tags: Collection<String>) = weatherById.values.filter { it.hasAllTags(tags) }.ifEmpty { null }
fun getByAllTagsOf(tag: String, vararg tags: String) = weatherById.values.filter { it.hasAllTags(tags.toList() + tag) }.ifEmpty { null }
fun getByAnyTag(tags: Array<String>) = weatherById.values.filter { it.hasAnyTags(tags) }.ifEmpty { null }
fun getByAnyTag(tags: Collection<String>) = weatherById.values.filter { it.hasAnyTags(tags) }.ifEmpty { null }
fun getByAnyTag(tag: String, vararg tags: String) = weatherById.values.filter { it.hasAnyTags(tags.toList() + tag) }.ifEmpty { null }
fun getByTag(tag: String) = weatherByTags[tag]
init {
App.disposables.add(this)
}
fun readFromJson(modname: String, file: File) = readFromJson(modname, file.path)
fun readFromJson(modname: String, path: String) {
/* JSON structure:
{
"skyboxGradColourMap": "colourmap/sky_colour.tga", // string (path to image) for dynamic. Image must be RGBA8888 or RGB888
"extraImages": [
// if any, it will be like:
sun01.tga,
clouds01.tga,
clouds02.tga,
auroraBlueViolet.tga
]
}
*/
val pathToImage = "weathers"
val JSON = JsonFetcher(path)
val skyboxInJson = JSON.getString("skyboxGradColourMap")
val lightbox = JSON.getString("daylightClut")
val cloudsMap = ArrayList<CloudProps>()
val clouds = JSON["clouds"]
clouds.forEachSiblings { name, json ->
cloudsMap.add(CloudProps(
name,
TextureRegionPack(ModMgr.getGdxFile(modname, "$pathToImage/${json.getString("filename")}"), json.getInt("tw"), json.getInt("th")),
json.getFloat("probability"),
json.getFloat("baseScale"),
json.getFloat("scaleVariance"),
json.getFloat("altLow"),
json.getFloat("altHigh"),
))
}
cloudsMap.sortBy { it.probability }
val ident = JSON.getString("identifier")
val tags = JSON.getString("tags").split(',')
val obj = BaseModularWeather(
identifier = ident,
json = JSON,
skyboxGradColourMap = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${skyboxInJson}")),
daylightClut = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${lightbox}")),
tags = tags,
cloudChance = JSON.getFloat("cloudChance"),
windSpeed = JSON.getFloat("windSpeed"),
windSpeedVariance = JSON.getFloat("windSpeedVariance"),
windSpeedDamping = JSON.getFloat("windSpeedDamping"),
cloudGamma = JSON["cloudGamma"].asFloatArray().let { Vector2(it[0], it[1]) },
cloudGammaVariance = JSON["cloudGammaVariance"].asFloatArray().let { Vector2(it[0], it[1]) },
clouds = cloudsMap,
shaderVibrancy = JSON["shaderVibrancy"].asFloatArray()
)
weatherById[ident] = obj
tags.forEach {
if (weatherByTags[it] == null) {
weatherByTags[it] = mutableSetOf()
}
weatherByTags[it]!!.add(obj)
}
}
override fun dispose() {
weatherById.values.forEach {
it.clouds.forEach { it.spriteSheet.tryDispose() }
}
}
fun getRandom(tag: String? = null): BaseModularWeather {
return if (tag == null) {
var k = weatherById.values.random()
if (k.identifier == "titlescreen") k = weatherById.values.random()
k
}
else getByTag(tag)!!.random()
}
}

View File

@@ -59,7 +59,7 @@ internal object WeatherMixer : RNGConsumer {
JsonValue(JsonValue.ValueType.`object`),
GdxColorMap(1, 3, Color(0x55aaffff), Color(0xaaffffff.toInt()), Color.WHITE),
GdxColorMap(2, 2, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE),
"default",
listOf("default"),
0f,
0f,
0f,
@@ -74,9 +74,6 @@ internal object WeatherMixer : RNGConsumer {
var globalLightOverridden = false
val weatherDB: HashMap<String, ArrayList<BaseModularWeather>> // search by classification
val weatherDict: HashMap<String, BaseModularWeather> // search by identifier
private var forceWindVec: Vector3? = null
val globalLightNow = Cvec(0)
@@ -153,37 +150,6 @@ internal object WeatherMixer : RNGConsumer {
oldCamPos.set(WorldCamera.camVector)
}
init {
weatherDB = HashMap<String, ArrayList<BaseModularWeather>>()
weatherDict = HashMap<String, BaseModularWeather>()
// read weather descriptions from assets/weather (modular weather)
val weatherRawValidList = ArrayList<Pair<String, File>>()
val weatherRawsDir = ModMgr.getFilesFromEveryMod("weathers")
weatherRawsDir.forEach { (modname, parentdir) ->
printdbg(this, "Scanning dir $parentdir")
parentdir.listFiles(FileFilter { !it.isDirectory && it.name.endsWith(".json") })?.forEach {
weatherRawValidList.add(modname to it)
printdbg(this, "Registering weather '$it' from module $modname")
}
}
// --> read from directory and store file that looks like RAW
for ((modname, raw) in weatherRawValidList) {
val weather = readFromJson(modname, raw)
weatherDict[weather.identifier] = weather
// if List for the classification does not exist, make one
if (!weatherDB.containsKey(weather.classification))
weatherDB.put(weather.classification, ArrayList())
weatherDB[weather.classification]!!.add(weather)
}
weatherDict["titlescreen"] = weatherDB[WEATHER_GENERIC]?.get(0)?.copy(identifier = "titlescreen", windSpeed = 1f) ?: DEFAULT_WEATHER
}
/**
* Part of Ingame update
*/
@@ -527,7 +493,7 @@ internal object WeatherMixer : RNGConsumer {
}
internal fun titleScreenInitWeather(weatherbox: Weatherbox) {
weatherbox.initWith(weatherDict["titlescreen"]!!, Long.MAX_VALUE)
weatherbox.initWith(WeatherCodex.getById("titlescreen")!!, Long.MAX_VALUE)
forceWindVec = Vector3(
-0.98f,
0f,
@@ -923,72 +889,7 @@ internal object WeatherMixer : RNGConsumer {
return lerp(x, c1.linearise(), c2.linearise()).unlinearise()
}
fun getWeatherList(classification: String) = weatherDB[classification]!!
fun getRandomWeather(classification: String) =
getWeatherList(classification)[RNG.nextInt(getWeatherList(classification).size)]
fun readFromJson(modname: String, file: File): BaseModularWeather = readFromJson(modname, file.path)
fun readFromJson(modname: String, path: String): BaseModularWeather {
/* JSON structure:
{
"skyboxGradColourMap": "colourmap/sky_colour.tga", // string (path to image) for dynamic. Image must be RGBA8888 or RGB888
"extraImages": [
// if any, it will be like:
sun01.tga,
clouds01.tga,
clouds02.tga,
auroraBlueViolet.tga
]
}
*/
val pathToImage = "weathers"
val JSON = JsonFetcher(path)
val skyboxInJson = JSON.getString("skyboxGradColourMap")
val lightbox = JSON.getString("daylightClut")
val cloudsMap = ArrayList<CloudProps>()
val clouds = JSON["clouds"]
clouds.forEachSiblings { name, json ->
cloudsMap.add(CloudProps(
name,
TextureRegionPack(ModMgr.getGdxFile(modname, "$pathToImage/${json.getString("filename")}"), json.getInt("tw"), json.getInt("th")),
json.getFloat("probability"),
json.getFloat("baseScale"),
json.getFloat("scaleVariance"),
json.getFloat("altLow"),
json.getFloat("altHigh"),
))
}
cloudsMap.sortBy { it.probability }
return BaseModularWeather(
identifier = JSON.getString("identifier"),
json = JSON,
skyboxGradColourMap = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${skyboxInJson}")),
daylightClut = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${lightbox}")),
classification = JSON.getString("classification"),
cloudChance = JSON.getFloat("cloudChance"),
windSpeed = JSON.getFloat("windSpeed"),
windSpeedVariance = JSON.getFloat("windSpeedVariance"),
windSpeedDamping = JSON.getFloat("windSpeedDamping"),
cloudGamma = JSON["cloudGamma"].asFloatArray().let { Vector2(it[0], it[1]) },
cloudGammaVariance = JSON["cloudGammaVariance"].asFloatArray().let { Vector2(it[0], it[1]) },
clouds = cloudsMap,
shaderVibrancy = JSON["shaderVibrancy"].asFloatArray()
)
}
fun dispose() {
weatherDB.values.forEach { list ->
list.forEach { weather ->
weather.clouds.forEach { it.spriteSheet.dispose() }
}
}
starmapTex.texture.dispose()
shaderAstrum.dispose()
shaderClouds.dispose()

View File

@@ -3,6 +3,7 @@ package net.torvald.terrarum.weather
import com.badlogic.gdx.math.Vector2
import com.jme3.math.FastMath
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.WeatherCodex
import net.torvald.terrarum.floorToInt
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.fmod
@@ -64,9 +65,9 @@ class Weatherbox {
private fun pickNextWeather(): WeatherSchedule {
// temporary setup for the release
val newName = if (takeUniformRand(0f..1f) < 0.5f) "generic01" else "generic02"
val newWeather = WeatherCodex.getRandom()
val newDuration = takeTriangularRand(3600f..10800f).roundToLong()
return WeatherSchedule(WeatherMixer.weatherDict[newName]!!, newDuration)
return WeatherSchedule(newWeather, newDuration)
}
fun update(world: GameWorld) {