BlockStats is upgraded to TileSurvey

This commit is contained in:
minjaesong
2023-04-12 19:53:12 +09:00
parent acd215c7c6
commit 928029e6e4
4 changed files with 99 additions and 68 deletions

View File

@@ -1,59 +0,0 @@
package net.torvald.terrarum.blockstats
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.worlddrawer.BlocksDrawer
/**
* Created by minjaesong on 2016-02-01.
*/
object BlockStats {
private val tilestat = HashMap<ItemID, Int>()
/**
* Update tile stats from tiles on screen
*/
fun update() {
tilestat.clear()
// Get stats on no-zoomed screen area. In other words, will behave as if screen zoom were 1.0
// no matter how the screen is zoomed.
val map = (INGAME.world)
val player = (Terrarum.ingame!! as TerrarumIngame).actorNowPlaying
if (player == null) return
val renderWidth = FastMath.ceil(App.scr.wf)
val renderHeight = FastMath.ceil(App.scr.hf)
val noZoomCameraX = Math.round(FastMath.clamp(
player.hitbox.centeredX.toFloat() - renderWidth / 2, TILE_SIZEF, map.width * TILE_SIZE - renderWidth - TILE_SIZEF))
val noZoomCameraY = Math.round(FastMath.clamp(
player.hitbox.centeredY.toFloat() - renderHeight / 2, TILE_SIZEF, map.width * TILE_SIZE - renderHeight - TILE_SIZEF))
val for_x_start = noZoomCameraX / TILE_SIZE
val for_y_start = noZoomCameraY / TILE_SIZE
val for_y_end = BlocksDrawer.clampHTile(for_y_start + (renderHeight / TILE_SIZE) + 2)
val for_x_end = BlocksDrawer.clampWTile(for_x_start + (renderWidth / TILE_SIZE) + 2)
for (y in for_y_start..for_y_end - 1) {
for (x in for_x_start..for_x_end - 1) {
val tileWall = map.getTileFromWall(x, y)
val tileTerrain = map.getTileFromTerrain(x, y)
tilestat[tileWall] = 1 + (tilestat[tileWall] ?: 0)
tilestat[tileTerrain] = 1 + (tilestat[tileTerrain] ?: 0)
}
}
}
fun getCount(vararg tiles: ItemID): Int {
return tiles.fold(0) { acc, key -> acc + (tilestat[key] ?: 0) }
}
}

View File

@@ -0,0 +1,78 @@
package net.torvald.terrarum.blockstats
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import kotlin.math.ceil
import kotlin.math.floor
/**
* Created by minjaesong on 2016-02-01.
*/
object TileSurvey {
data class SurveyProposal(
val surveyIdentifier: String,
val width: Int,
val height: Int,
val spatialGranularity: Int, // 1: survey every (w*h) tile, 2: survey every other (w*h/4) tile ...
val temporalGranularity: Int, // 1: survey every frame, 2: every other frame ...
val predicate: (GameWorld, Int, Int) -> Boolean
)
private val proposals = HashMap<String, SurveyProposal>()
private val results = HashMap<String, Pair<Double, Int>>() // (matching tiles/actually surveyed tiles)
fun submitProposal(proposal: SurveyProposal) {
proposals[proposal.surveyIdentifier] = proposal
}
fun withdrawProposal(surveyIdentifier: String) {
proposals.remove(surveyIdentifier)
results.remove(surveyIdentifier)
}
/**
* Update tile stats from tiles on screen
*/
fun update() {
// Get stats on no-zoomed screen area. In other words, will behave as if screen zoom were 1.0
// no matter how the screen is zoomed.
val world = INGAME.world
val player = (Terrarum.ingame!! as TerrarumIngame).actorNowPlaying
if (player == null) return
proposals.forEach { (_, proposal) ->
if (INGAME.WORLD_UPDATE_TIMER % proposal.temporalGranularity == 0) {
val for_x_start = floor(player.intTilewiseHitbox.centeredX - proposal.width / 2.0).toInt()
val for_y_start = floor(player.intTilewiseHitbox.centeredY - proposal.height / 2.0).toInt()
val for_x_end = ceil(player.intTilewiseHitbox.centeredX + proposal.width / 2.0).toInt()
val for_y_end = ceil(player.intTilewiseHitbox.centeredY + proposal.height / 2.0).toInt()
var akku = 0
for (y in for_y_start until for_y_end step proposal.spatialGranularity) {
for (x in for_x_start until for_x_end step proposal.spatialGranularity) {
if (proposal.predicate(world, x, y)) akku += 1
}
}
val surveyedTileCount =
(proposal.width * proposal.height) / (proposal.spatialGranularity * proposal.spatialGranularity)
val ratio = akku.toDouble() / surveyedTileCount
results[proposal.surveyIdentifier] = ratio to akku
}
}
}
fun getRawCount(surveyIdentifier: String) = results[surveyIdentifier]?.second
fun getRatio(surveyIdentifier: String) = results[surveyIdentifier]?.first
fun getRatioAndRawCount(surveyIdentifier: String) = results[surveyIdentifier]
}

View File

@@ -11,7 +11,7 @@ import net.torvald.terrarum.Terrarum.getWorldSaveFiledesc
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.blockproperties.BlockPropUtil
import net.torvald.terrarum.blockstats.BlockStats
import net.torvald.terrarum.blockstats.TileSurvey
import net.torvald.terrarum.blockstats.MinimapComposer
import net.torvald.terrarum.concurrent.ThreadExecutor
import net.torvald.terrarum.console.AVTracker
@@ -800,7 +800,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
WeatherMixer.update(delta, actorNowPlaying, world)
}
measureDebugTime("BlockStats.update") {
BlockStats.update()
TileSurvey.update()
}
// fill up visibleActorsRenderFront for wires but not on every update
measureDebugTime("Ingame.FillUpWiresBuffer*") {

View File

@@ -9,7 +9,7 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
import net.torvald.terrarum.blendMul
import net.torvald.terrarum.blendNormalStraightAlpha
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockstats.BlockStats
import net.torvald.terrarum.blockstats.TileSurvey
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.roundToInt
@@ -42,6 +42,19 @@ object FeaturesDrawer {
Block.SAND_DESERT
, Block.SAND_RED)
init {
TileSurvey.submitProposal(
TileSurvey.SurveyProposal(
"basegame.FeaturesDrawer.coldTiles", 72, 48, 2, 2
) { world, x, y -> TILES_COLD.contains(world.getTileFromTerrain(x, y)) }
)
TileSurvey.submitProposal(
TileSurvey.SurveyProposal(
"basegame.FeaturesDrawer.warmTiles", 72, 48, 2, 2
) { world, x, y -> TILES_WARM.contains(world.getTileFromTerrain(x, y)) }
)
}
fun update(delta: Float) {
}
@@ -50,13 +63,12 @@ object FeaturesDrawer {
* usually targeted for the environmental temperature (desert/winterland), hence the name.
*/
fun drawEnvOverlay(batch: SpriteBatch) {
val onscreen_tiles_max = FastMath.ceil(App.scr.height * App.scr.width / FastMath.sqr(TILE_SIZEF)) * 2
val onscreen_tiles_cap = onscreen_tiles_max / 4f
val onscreen_cold_tiles = BlockStats.getCount(*TILES_COLD).toFloat()
val onscreen_warm_tiles = BlockStats.getCount(*TILES_WARM).toFloat()
val onscreen_tiles_cap = 0.3
val onscreen_cold_tiles = (TileSurvey.getRatio("basegame.FeaturesDrawer.coldTiles") ?: 0.0).coerceAtMost(onscreen_tiles_cap)
val onscreen_warm_tiles = (TileSurvey.getRatio("basegame.FeaturesDrawer.warmTiles") ?: 0.0).coerceAtMost(onscreen_tiles_cap)
val colTemp_cold = colTempLinearFunc(onscreen_cold_tiles / onscreen_tiles_cap)
val colTemp_warm = colTempLinearFunc(-(onscreen_warm_tiles / onscreen_tiles_cap))
val colTemp_cold = colTempLinearFunc((onscreen_cold_tiles / onscreen_tiles_cap).toFloat())
val colTemp_warm = colTempLinearFunc(-(onscreen_warm_tiles / onscreen_tiles_cap).toFloat())
colTemp = colTemp_warm + colTemp_cold - ENV_COLTEMP_NOON
val zoom = Terrarum.ingame?.screenZoom ?: 1f