diff --git a/assets/mods/basegame/items/itemid.csv b/assets/mods/basegame/items/itemid.csv index 7c3d48271..f43848ce9 100644 --- a/assets/mods/basegame/items/itemid.csv +++ b/assets/mods/basegame/items/itemid.csv @@ -158,3 +158,5 @@ id;classname;tags # ... # 10FF00h..10FFFFh : Fluid type 255 (???) x container type 0..255 +# reserved for debug items +16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL diff --git a/src/net/torvald/terrarum/ModMgr.kt b/src/net/torvald/terrarum/ModMgr.kt index a8a0da664..2d0751db2 100644 --- a/src/net/torvald/terrarum/ModMgr.kt +++ b/src/net/torvald/terrarum/ModMgr.kt @@ -8,10 +8,7 @@ import net.torvald.gdx.graphics.Cvec import net.torvald.terrarum.App.* import net.torvald.terrarum.App.setToGameConfig import net.torvald.terrarum.audio.AudioCodex -import net.torvald.terrarum.blockproperties.BlockCodex -import net.torvald.terrarum.blockproperties.BlockProp -import net.torvald.terrarum.blockproperties.OreCodex -import net.torvald.terrarum.blockproperties.WireCodex +import net.torvald.terrarum.blockproperties.* import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gamecontroller.IME import net.torvald.terrarum.gameitems.FixtureInteractionBlocked @@ -765,6 +762,18 @@ object ModMgr { } } + object GameFluidLoader { + const val fluidPath = "fluids/" + + init { + Terrarum.fluidCodex = FluidCodex() + } + + @JvmStatic operator fun invoke(module: String) { + Terrarum.fluidCodex.fromModule(module, fluidPath + "fluids.csv") + } + } + object GameAudioLoader { val audioPath = listOf( "audio/music", diff --git a/src/net/torvald/terrarum/TerrarumPostProcessor.kt b/src/net/torvald/terrarum/TerrarumPostProcessor.kt index ca3486c21..e2dd442ae 100644 --- a/src/net/torvald/terrarum/TerrarumPostProcessor.kt +++ b/src/net/torvald/terrarum/TerrarumPostProcessor.kt @@ -42,7 +42,7 @@ object TerrarumPostProcessor : Disposable { private val safeAreaCol2 = Color(0xffffff44.toInt()) private val currentResCol = Color(0xfff066_88.toInt()) - private val debugUI = BasicDebugInfoWindow() + internal val debugUI = BasicDebugInfoWindow() private val functionRowHelper = Texture(Gdx.files.internal("assets/graphics/function_row_help.png")) diff --git a/src/net/torvald/terrarum/blockproperties/FluidCodex.kt b/src/net/torvald/terrarum/blockproperties/FluidCodex.kt index 19a96d72b..e94d34580 100644 --- a/src/net/torvald/terrarum/blockproperties/FluidCodex.kt +++ b/src/net/torvald/terrarum/blockproperties/FluidCodex.kt @@ -1,14 +1,18 @@ package net.torvald.terrarum.blockproperties import net.torvald.gdx.graphics.Cvec +import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.gameitems.ItemID +import net.torvald.terrarum.utils.CSVFetcher +import org.apache.commons.csv.CSVRecord +import java.io.IOException /** * Created by minjaesong on 2023-10-09. */ class FluidCodex { - @Transient val blockProps = HashMap() + @Transient val fluidProps = HashMap() @Transient private val nullProp = FluidProp() @@ -20,22 +24,105 @@ class FluidCodex { try { return if (fluidID.startsWith("fluid@")) - blockProps[fluidID.substring(6)]!! + fluidProps[fluidID]!! else - blockProps[fluidID]!! + throw NullPointerException("Missing prefix 'fluid@' for the ID '$fluidID'") } catch (e: NullPointerException) { throw NullPointerException("Fluidprop with id $fluidID does not exist.") } } + + /** + * Later entry (possible from other modules) will replace older ones + */ + fun fromModule(module: String, path: String, registerHook: (FluidProp) -> Unit = {}) { + printdbg(this, "Building fluid properties table") + try { + register(module, CSVFetcher.readFromModule(module, path), registerHook) + } + catch (e: IOException) { e.printStackTrace() } + } + + private fun register(module: String, records: List, registerHook: (FluidProp) -> Unit) { + records.forEach { + setProp(module, it.intVal("id"), it) + val tileId = "fluid@$module:${it.intVal("id")}" + fluidProps[tileId]?.let(registerHook) + } + } + + private fun setProp(module: String, key: Int, record: CSVRecord) { + val prop = FluidProp() + prop.nameKey = record.get("name") + prop.tags = record.get("tags").split(',').map { it.trim().toUpperCase() }.toHashSet() + + prop.id = "fluid@$module:$key" + prop.numericID = key + + prop.shadeColR = record.floatVal("shdr") + prop.shadeColG = record.floatVal("shdg") + prop.shadeColB = record.floatVal("shdb") + prop.shadeColA = record.floatVal("shduv") + prop.opacity = Cvec(prop.shadeColR, prop.shadeColG, prop.shadeColB, prop.shadeColA) + + prop.strength = record.intVal("str") + prop.density = record.intVal("dsty") + + prop.lumColR = record.floatVal("lumr") + prop.lumColG = record.floatVal("lumg") + prop.lumColB = record.floatVal("lumb") + prop.lumColA = record.floatVal("lumuv") + prop.lumCol.set(prop.lumColR, prop.lumColG, prop.lumColB, prop.lumColA) + + prop.viscosity = record.intVal("vscs") + prop.colour = record.str16ToInt("colour") + + prop.reflectance = record.floatVal("refl") + + prop.material = record.get("mate") + + fluidProps[prop.id] = prop + + printdbg(this, "Setting fluid prop ${prop.id} ->>\t${prop.nameKey}") + } + } class FluidProp { - val opacity: Cvec = Cvec() - val lumCol: Cvec = Cvec() var id: ItemID = "" + var numericID: Int = -1 var nameKey: String = "" + + /** 1.0f for 1023, 0.25f for 255 */ + var shadeColR = 0f + var shadeColG = 0f + var shadeColB = 0f + var shadeColA = 0f + var opacity = Cvec() + + var strength: Int = 0 + var density: Int = 0 + + var material: String = "" + + /** 1.0f for 1023, 0.25f for 255 */ + var lumColR = 0f + var lumColG = 0f + var lumColB = 0f + var lumColA = 0f + var lumCol = Cvec() + + /** Fluid colour */ + var colour: Int = 0 + + var viscosity: Int = 0 + + var reflectance = 0f // the exact colour of the reflected light depends on the texture + + @Transient var tags = HashSet() + } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 9ba235302..c9dcda132 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -248,6 +248,12 @@ open class GameWorld( tileNameToNumberMap[it.key] = it.value.tileNumber } } + Terrarum.fluidCodex.fluidProps.entries.forEach { + if (!forcedFluidNumberToTiles.contains(it.key)) { + fluidNumberToNameMap[it.value.numericID.toLong()] = it.key + fluidNameToNumberMap[it.key] = it.value.numericID + } + } } } @@ -270,6 +276,10 @@ open class GameWorld( tileNumberToNameMap[it.value.tileNumber.toLong()] = it.key tileNameToNumberMap[it.key] = it.value.tileNumber } + Terrarum.fluidCodex.fluidProps.entries.forEach { + fluidNumberToNameMap[it.value.numericID.toLong()] = it.key + fluidNameToNumberMap[it.key] = it.value.numericID + } // force this rule to the old saves tileNumberToNameMap[0] = Block.AIR @@ -749,11 +759,11 @@ open class GameWorld( if (fluidType == Fluid.NULL && fill != 0f) { - throw Error("Illegal fluid at ($x,$y): ${FluidInfo(fluidType, fill)}") + throw Error("Illegal fluid fill at ($x,$y): ${FluidInfo(fluidType, fill)}") } - val addr = LandUtil.getBlockAddr(this, x, y) +// val addr = LandUtil.getBlockAddr(this, x, y) val fluidNumber = fluidNameToNumberMap[fluidType]!! @@ -778,7 +788,7 @@ open class GameWorld( val (type, fill) = layerFluids.unsafeGetTile1(x, y) val fluidID = fluidNumberToNameMap[type.toLong()] ?: throw NullPointerException("No such fluid: $type") - return FluidInfo(fluidID, fill) + return FluidInfo(fluidID, fill.let { if (it.isNaN()) 0f else it }) // hex FFFFFFFF (magic number for ungenerated tiles) is interpreted as Float.NaN } /*private fun fluidTypeToBlock(type: FluidType) = when (type.abs()) { diff --git a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt index 7bb7be72e..a673e468e 100644 --- a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt +++ b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt @@ -35,6 +35,7 @@ class EntryPoint : ModuleEntryPoint() { ModMgr.GameItemLoader.invoke(moduleName) ModMgr.GameBlockLoader.invoke(moduleName) ModMgr.GameOreLoader.invoke(moduleName) + ModMgr.GameFluidLoader.invoke(moduleName) ModMgr.GameLanguageLoader.invoke(moduleName) ModMgr.GameCraftingRecipeLoader.invoke(moduleName) ModMgr.GameAudioLoader.invoke(moduleName) diff --git a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt index c3fa116ab..edd06f86d 100644 --- a/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt +++ b/src/net/torvald/terrarum/modulebasegame/IngameRenderer.kt @@ -196,6 +196,8 @@ object IngameRenderer : Disposable { // printdbg(this, "Set new RenderedWorld (UUID=${world.worldIndex}) at time ${System.currentTimeMillis()} (disposed: ${world.disposed}), called by:") // printStackTrace(this) + var successful = false + try { // change worlds from internal methods @@ -210,11 +212,19 @@ object IngameRenderer : Disposable { // "new world: ${world.hashCode()}") newWorldLoadedLatch = true } + + successful = true } catch (e: Throwable) { e.printStackTrace() // new init, do nothing } + finally { + if (successful) + TerrarumPostProcessor.debugUI.world = world + else + TerrarumPostProcessor.debugUI.world = null + } } private var oldCamX = 0 diff --git a/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt b/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt index 7422b19bc..7c7bf8467 100644 --- a/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt +++ b/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt @@ -88,7 +88,7 @@ object WorldSimulator { if (ingame.terrainChangeQueue.isNotEmpty()) { App.measureDebugTime("WorldSimulator.degrass") { buryGrassImmediately() } } App.measureDebugTime("WorldSimulator.growGrass") { growOrKillGrass() } - App.measureDebugTime("WorldSimulator.fluids") { /*moveFluids(delta)*/ } + App.measureDebugTime("WorldSimulator.fluids") { moveFluids(delta) } App.measureDebugTime("WorldSimulator.fallables") { displaceFallables(delta) } App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) } App.measureDebugTime("WorldSimulator.collisionDroppedItem") { collideDroppedItems() } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorLobbed.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorLobbed.kt index ba207708b..a322b687c 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorLobbed.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorLobbed.kt @@ -163,7 +163,7 @@ class ActorGlowOrb(throwPitch: Float) : ActorLobbed(throwPitch) { spriteEmissive = SingleImageSprite(this, itemImage) avBaseMass = 1.0 - density = 1400.0 + density = 580.0 } @Transient private val lifePower = 10000L // charge reaches 0 on timeDelta = 9 * lifePower diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt new file mode 100644 index 000000000..dd4d190e4 --- /dev/null +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt @@ -0,0 +1,36 @@ +package net.torvald.terrarum.modulebasegame.gameitems + +import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.INGAME +import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.blockproperties.Fluid +import net.torvald.terrarum.gameactors.ActorWithBody +import net.torvald.terrarum.gameitems.GameItem +import net.torvald.terrarum.gameitems.GameItem.EquipPosition.HAND_GRIP +import net.torvald.terrarum.gameitems.ItemID + +/** + * Created by minjaesong on 2024-07-14. + */ +class ItemBottomlessWaterBucket(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_WATER_BUCKET" + + init { + stackable = false + isUnique = true + } + + override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long { + val mx = Terrarum.mouseTileX; val my =Terrarum.mouseTileY + INGAME.world.setFluid(mx, my, Fluid.WATER, 1f) + printdbg(this, "Pouring water at ($mx, $my)") + return 0L + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index cb87dd22d..a5ccb09bb 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -51,7 +51,7 @@ class BasicDebugInfoWindow : UICanvas() { private var ydelta = 0.0 private var ingame: IngameInstance? = null - private var world: GameWorld? = null + internal var world: GameWorld? = null // is set by IngameRenderer.setRenderedWorld(GameWorld) private val icons = TextureRegionPack(Gdx.files.internal("assets/graphics/gui/debug_window_symbols.tga"), 21, 26) private val back = Texture(Gdx.files.internal("assets/graphics/gui/debug_window_background.tga")) @@ -86,12 +86,9 @@ class BasicDebugInfoWindow : UICanvas() { private var showAudioMixer2 = false private var showChunks = false - override fun show() { - ingame = Terrarum.ingame - world = ingame?.world - } - override fun updateImpl(delta: Float) { + ingame = Terrarum.ingame + val player = ingame?.actorNowPlaying val hitbox = player?.hitbox @@ -382,24 +379,24 @@ class BasicDebugInfoWindow : UICanvas() { */ if (ingame != null) { - App.fontSmallNumbers.draw(batch, "${ccY}Actors total $ccG${ingame!!.actorContainerActive.size + ingame!!.actorContainerInactive.size}", - TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 2f) - App.fontSmallNumbers.draw(batch, "${ccY}Active $ccG${ingame!!.actorContainerActive.size}", - TinyAlphNum.W * 2f + (17 * 8), App.scr.height - TinyAlphNum.H * 2f) - App.fontSmallNumbers.draw(batch, "${ccY}Dormant $ccG${ingame!!.actorContainerInactive.size}", - TinyAlphNum.W * 2f + (28 * 8), App.scr.height - TinyAlphNum.H * 2f) +// App.fontSmallNumbers.draw(batch, "${ccY}Actors total $ccG${ingame!!.actorContainerActive.size + ingame!!.actorContainerInactive.size}", +// TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 2f) +// App.fontSmallNumbers.draw(batch, "${ccY}Active $ccG${ingame!!.actorContainerActive.size}", +// TinyAlphNum.W * 2f + (17 * 8), App.scr.height - TinyAlphNum.H * 2f) +// App.fontSmallNumbers.draw(batch, "${ccY}Dormant $ccG${ingame!!.actorContainerInactive.size}", +// TinyAlphNum.W * 2f + (28 * 8), App.scr.height - TinyAlphNum.H * 2f) if (ingame is TerrarumIngame) { App.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${(ingame as TerrarumIngame).particlesActive}$ccY/$ccG${(ingame as TerrarumIngame).PARTICLES_MAX}", - TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 4f) + TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 3f) } App.fontSmallNumbers.draw(batch, "${ccM}Clouds $ccG${WeatherMixer.cloudsSpawned}$ccY/$ccG${WeatherMixer.cloudSpawnMax}", - TinyAlphNum.W * 2f + (18 * 8), App.scr.height - TinyAlphNum.H * 4f) + TinyAlphNum.W * 2f + (18 * 8), App.scr.height - TinyAlphNum.H * 3f) } App.fontSmallNumbers.draw(batch, "${ccY}Actors rendering $ccG${IngameRenderer.renderingActorsCount}", - TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 3f) + TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 2f) App.fontSmallNumbers.draw(batch, "${ccY}UIs rendering $ccG${IngameRenderer.renderingUIsCount}", - TinyAlphNum.W * 2f + (21 * 8), App.scr.height - TinyAlphNum.H * 3f) + TinyAlphNum.W * 2f + (21 * 8), App.scr.height - TinyAlphNum.H * 2f) /** * Bottom right