mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
new: world update ahchoring
This commit is contained in:
@@ -121,6 +121,46 @@ emph {
|
|||||||
|
|
||||||
val uptime = App.getTIME_T() - App.startupTime
|
val uptime = App.getTIME_T() - App.startupTime
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// print out the error
|
||||||
|
printStream.println("<h3>The Error Info</h3>")
|
||||||
|
System.err.println("== The Error Info ==")
|
||||||
|
|
||||||
|
printStream.println("<pre>")
|
||||||
|
e.printStackTrace(printStream)
|
||||||
|
printStream.println("</pre>")
|
||||||
|
e.printStackTrace(System.err)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
printStream.println("<h3>Module Info</h3>")
|
||||||
|
printStream.println("<h4>Load Order</h4>")
|
||||||
|
printStream.println("<ol>${ModMgr.loadOrder.joinToString(separator = "") { "<li>" +
|
||||||
|
"$it <small>(" +
|
||||||
|
"${moduleMetaToText(ModMgr.moduleInfo[it] ?: ModMgr.moduleInfoErrored[it])}" +
|
||||||
|
")</small></li>" }
|
||||||
|
}</ol>")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// print out loaded modules
|
||||||
|
ModMgr.errorLogs.let {
|
||||||
|
if (it.size > 0) {
|
||||||
|
printStream.println("<h4>Module Errors</h4>")
|
||||||
|
System.err.println("== Module Errors ==")
|
||||||
|
it.forEach {
|
||||||
|
printStream.println("<p>From Module <strong>${it.moduleName}</strong> (${it.type.toHTML()}):</p>")
|
||||||
|
printStream.println("<pre>")
|
||||||
|
it.cause?.printStackTrace(printStream)
|
||||||
|
printStream.println("</pre>")
|
||||||
|
it.cause?.printStackTrace(System.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// print out device info
|
// print out device info
|
||||||
printStream.println("<h3>System Info</h3>")
|
printStream.println("<h3>System Info</h3>")
|
||||||
printStream.println("<ul>")
|
printStream.println("<ul>")
|
||||||
@@ -146,39 +186,6 @@ emph {
|
|||||||
printStream.println("<p><emph>GL not initialised</emph></p>")
|
printStream.println("<p><emph>GL not initialised</emph></p>")
|
||||||
}
|
}
|
||||||
|
|
||||||
printStream.println("<h3>Module Info</h3>")
|
|
||||||
printStream.println("<h4>Load Order</h4>")
|
|
||||||
printStream.println("<ol>${ModMgr.loadOrder.joinToString(separator = "") { "<li>" +
|
|
||||||
"$it <small>(" +
|
|
||||||
"${moduleMetaToText(ModMgr.moduleInfo[it] ?: ModMgr.moduleInfoErrored[it])}" +
|
|
||||||
")</small></li>" }
|
|
||||||
}</ol>")
|
|
||||||
|
|
||||||
|
|
||||||
ModMgr.errorLogs.let {
|
|
||||||
if (it.size > 0) {
|
|
||||||
printStream.println("<h4>Module Errors</h4>")
|
|
||||||
System.err.println("== Module Errors ==")
|
|
||||||
it.forEach {
|
|
||||||
printStream.println("<p>From Module <strong>${it.moduleName}</strong> (${it.type.toHTML()}):</p>")
|
|
||||||
printStream.println("<pre>")
|
|
||||||
it.cause?.printStackTrace(printStream)
|
|
||||||
printStream.println("</pre>")
|
|
||||||
it.cause?.printStackTrace(System.err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printStream.println("<h3>The Error Info</h3>")
|
|
||||||
System.err.println("== The Error Info ==")
|
|
||||||
|
|
||||||
printStream.println("<pre>")
|
|
||||||
e.printStackTrace(printStream)
|
|
||||||
printStream.println("</pre>")
|
|
||||||
e.printStackTrace(System.err)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
textArea.text = "<html><style type=\"text/css\">$css</style><body>$htmlSB</body></html>"
|
textArea.text = "<html><style type=\"text/css\">$css</style><body>$htmlSB</body></html>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import net.torvald.terrarum.gameactors.ActorID
|
|||||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||||
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.PHYS_EPSILON_DIST
|
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.PHYS_EPSILON_DIST
|
||||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||||
|
import net.torvald.terrarum.gameactors.WorldUpdater
|
||||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||||
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||||
import net.torvald.terrarum.gameitems.ItemID
|
import net.torvald.terrarum.gameitems.ItemID
|
||||||
@@ -147,6 +148,13 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
val actorAdditionQueue = ArrayList<Triple<Actor, Throwable, (Actor) -> Unit>>() // actor, stacktrace object, onSpawn
|
val actorAdditionQueue = ArrayList<Triple<Actor, Throwable, (Actor) -> Unit>>() // actor, stacktrace object, onSpawn
|
||||||
val actorRemovalQueue = ArrayList<Triple<Actor, Throwable, (Actor) -> Unit>>() // actor, stacktrace object, onDespawn
|
val actorRemovalQueue = ArrayList<Triple<Actor, Throwable, (Actor) -> Unit>>() // actor, stacktrace object, onDespawn
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry of actors that implement [WorldUpdater].
|
||||||
|
* World simulation (fluids, wires, tile updates) is active around these actors.
|
||||||
|
* Automatically maintained when actors are added/removed.
|
||||||
|
*/
|
||||||
|
val worldUpdaters: MutableSet<ActorWithBody> = HashSet()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## BIG NOTE: Calculated actor distance is the **Euclidean distance SQUARED**
|
* ## BIG NOTE: Calculated actor distance is the **Euclidean distance SQUARED**
|
||||||
*
|
*
|
||||||
@@ -378,6 +386,10 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
actorContainer.removeAt(indexToDelete)
|
actorContainer.removeAt(indexToDelete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Unregister from worldUpdaters if applicable
|
||||||
|
if (actor is WorldUpdater && actor is ActorWithBody) {
|
||||||
|
worldUpdaters.remove(actor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun forceAddActor(actor: Actor?, caller: Throwable = StackTraceRecorder()) {
|
protected open fun forceAddActor(actor: Actor?, caller: Throwable = StackTraceRecorder()) {
|
||||||
@@ -388,6 +400,10 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
actorContainerActive.add(actor)
|
actorContainerActive.add(actor)
|
||||||
|
// Register to worldUpdaters if applicable
|
||||||
|
if (actor is WorldUpdater && actor is ActorWithBody) {
|
||||||
|
worldUpdaters.add(actor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
47
src/net/torvald/terrarum/gameactors/WorldUpdateAnchor.kt
Normal file
47
src/net/torvald/terrarum/gameactors/WorldUpdateAnchor.kt
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package net.torvald.terrarum.gameactors
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal anchor actor for world updates.
|
||||||
|
*
|
||||||
|
* This actor has no visible representation and does not participate in physics.
|
||||||
|
* It serves purely as a point around which world simulation (fluids, wires, tile updates)
|
||||||
|
* remains active.
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 2026-01-19.
|
||||||
|
*/
|
||||||
|
class WorldUpdateAnchor : ActorWithBody, WorldUpdater, NoSerialise {
|
||||||
|
|
||||||
|
constructor() : super(RenderOrder.MIDDLE, PhysProperties.IMMOBILE()) {
|
||||||
|
isVisible = false
|
||||||
|
chunkAnchoring = true
|
||||||
|
setHitboxDimension(1, 1, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(id: ActorID) : super(RenderOrder.MIDDLE, PhysProperties.IMMOBILE(), id) {
|
||||||
|
isVisible = false
|
||||||
|
chunkAnchoring = true
|
||||||
|
setHitboxDimension(1, 1, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateImpl(delta: Float) {
|
||||||
|
// No-op; this actor exists solely as a world update anchor
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawBody(frameDelta: Float, batch: SpriteBatch) {
|
||||||
|
// No-op; this actor is invisible
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawGlow(frameDelta: Float, batch: SpriteBatch) {
|
||||||
|
// No-op; this actor is invisible
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawEmissive(frameDelta: Float, batch: SpriteBatch) {
|
||||||
|
// No-op; this actor is invisible
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
// Nothing to dispose
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/net/torvald/terrarum/gameactors/WorldUpdater.kt
Normal file
13
src/net/torvald/terrarum/gameactors/WorldUpdater.kt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package net.torvald.terrarum.gameactors
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for actors that serve as "world update anchors".
|
||||||
|
*
|
||||||
|
* Actors implementing this interface cause world simulation (fluids, wires, tile updates)
|
||||||
|
* to be active in their vicinity, regardless of camera position.
|
||||||
|
*
|
||||||
|
* All implementations must also extend [ActorWithBody].
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 2026-01-19.
|
||||||
|
*/
|
||||||
|
interface WorldUpdater
|
||||||
@@ -150,8 +150,23 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
(a.hitbox.centeredY - WorldCamera.yCentre).sqr()
|
(a.hitbox.centeredY - WorldCamera.yCentre).sqr()
|
||||||
)
|
)
|
||||||
|
|
||||||
/** whether the actor is within update range */
|
/**
|
||||||
fun ActorWithBody.inUpdateRange(world: GameWorld) = distToCameraSqr(world, this) <= ACTOR_UPDATE_RANGE.sqr()
|
* Returns the minimum squared distance from the actor to any living WorldUpdater.
|
||||||
|
* Falls back to camera distance if no WorldUpdaters exist.
|
||||||
|
*/
|
||||||
|
fun distToNearestUpdaterSqr(world: GameWorld, actor: ActorWithBody): Double {
|
||||||
|
val worldUpdaters = Terrarum.ingame?.worldUpdaters
|
||||||
|
if (worldUpdaters.isNullOrEmpty()) {
|
||||||
|
return distToCameraSqr(world, actor)
|
||||||
|
}
|
||||||
|
return worldUpdaters.minOf { updater ->
|
||||||
|
if (updater.flagDespawn || updater.despawned) Double.MAX_VALUE
|
||||||
|
else distToActorSqr(world, actor, updater)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** whether the actor is within update range of any WorldUpdater */
|
||||||
|
fun ActorWithBody.inUpdateRange(world: GameWorld) = distToNearestUpdaterSqr(world, this) <= ACTOR_UPDATE_RANGE.sqr()
|
||||||
|
|
||||||
/** whether the actor is within screen */
|
/** whether the actor is within screen */
|
||||||
fun ActorWithBody.inScreen(world: GameWorld) =
|
fun ActorWithBody.inScreen(world: GameWorld) =
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
|
|||||||
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W
|
import net.torvald.terrarum.realestate.LandUtil.CHUNK_W
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
import kotlin.math.cosh
|
import kotlin.math.cosh
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@@ -50,6 +51,9 @@ object WorldSimulator {
|
|||||||
private val fluidNewMap = Array(DOUBLE_RADIUS) { FloatArray(DOUBLE_RADIUS) }
|
private val fluidNewMap = Array(DOUBLE_RADIUS) { FloatArray(DOUBLE_RADIUS) }
|
||||||
private val fluidNewTypeMap = Array(DOUBLE_RADIUS) { Array(DOUBLE_RADIUS) { Fluid.NULL } }
|
private val fluidNewTypeMap = Array(DOUBLE_RADIUS) { Array(DOUBLE_RADIUS) { Fluid.NULL } }
|
||||||
|
|
||||||
|
// Mask to track tiles that have already been fluid-simulated this frame (for overlap deduplication)
|
||||||
|
private val processedFluidTiles = HashSet<Long>()
|
||||||
|
|
||||||
const val FLUID_MAX_MASS = 1f // The normal, un-pressurized mass of a full water cell
|
const val FLUID_MAX_MASS = 1f // The normal, un-pressurized mass of a full water cell
|
||||||
const val FLUID_MAX_COMP = 0.01f // 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.01f // 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)
|
||||||
@@ -66,6 +70,97 @@ object WorldSimulator {
|
|||||||
/** Bottom-right point */
|
/** Bottom-right point */
|
||||||
var updateYTo = 0
|
var updateYTo = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a rectangular region for world updates.
|
||||||
|
*/
|
||||||
|
data class UpdateRegion(val xFrom: Int, val yFrom: Int, val xTo: Int, val yTo: Int) {
|
||||||
|
fun overlaps(other: UpdateRegion): Boolean {
|
||||||
|
return xFrom <= other.xTo && xTo >= other.xFrom &&
|
||||||
|
yFrom <= other.yTo && yTo >= other.yFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
fun merge(other: UpdateRegion): UpdateRegion {
|
||||||
|
return UpdateRegion(
|
||||||
|
min(xFrom, other.xFrom),
|
||||||
|
min(yFrom, other.yFrom),
|
||||||
|
max(xTo, other.xTo),
|
||||||
|
max(yTo, other.yTo)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val width get() = xTo - xFrom
|
||||||
|
val height get() = yTo - yFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges overlapping regions into non-overlapping ones.
|
||||||
|
* Uses iterative merging until no more merges are possible.
|
||||||
|
*/
|
||||||
|
private fun mergeOverlappingRegions(regions: List<UpdateRegion>): List<UpdateRegion> {
|
||||||
|
if (regions.size <= 1) return regions
|
||||||
|
|
||||||
|
val result = regions.toMutableList()
|
||||||
|
var merged = true
|
||||||
|
while (merged) {
|
||||||
|
merged = false
|
||||||
|
outer@ for (i in result.indices) {
|
||||||
|
for (j in i + 1 until result.size) {
|
||||||
|
if (result[i].overlaps(result[j])) {
|
||||||
|
val mergedRegion = result[i].merge(result[j])
|
||||||
|
result.removeAt(j)
|
||||||
|
result[i] = mergedRegion
|
||||||
|
merged = true
|
||||||
|
break@outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes update regions from all living WorldUpdaters.
|
||||||
|
* Returns a list of non-overlapping merged regions.
|
||||||
|
*/
|
||||||
|
private fun computeUpdateRegions(): List<UpdateRegion> {
|
||||||
|
val worldUpdaters = ingame.worldUpdaters.filter { !it.flagDespawn && !it.despawned }
|
||||||
|
if (worldUpdaters.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
val regions = worldUpdaters.map { updater ->
|
||||||
|
val cx = updater.hitbox.centeredX.div(TILE_SIZE).roundToInt()
|
||||||
|
val cy = updater.hitbox.centeredY.div(TILE_SIZE).roundToInt()
|
||||||
|
UpdateRegion(
|
||||||
|
cx - FLUID_UPDATING_SQUARE_RADIUS,
|
||||||
|
cy - FLUID_UPDATING_SQUARE_RADIUS,
|
||||||
|
cx + FLUID_UPDATING_SQUARE_RADIUS,
|
||||||
|
cy + FLUID_UPDATING_SQUARE_RADIUS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeOverlappingRegions(regions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes individual (unmerged) fluid regions for each WorldUpdater.
|
||||||
|
* Each region is exactly DOUBLE_RADIUS × DOUBLE_RADIUS to fit the fixed fluid arrays.
|
||||||
|
* Overlap deduplication is handled by processedFluidTiles mask during fluidmapToWorld().
|
||||||
|
*/
|
||||||
|
private fun computeIndividualFluidRegions(): List<UpdateRegion> {
|
||||||
|
val worldUpdaters = ingame.worldUpdaters.filter { !it.flagDespawn && !it.despawned }
|
||||||
|
if (worldUpdaters.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
return worldUpdaters.map { updater ->
|
||||||
|
val cx = updater.hitbox.centeredX.div(TILE_SIZE).roundToInt()
|
||||||
|
val cy = updater.hitbox.centeredY.div(TILE_SIZE).roundToInt()
|
||||||
|
UpdateRegion(
|
||||||
|
cx - FLUID_UPDATING_SQUARE_RADIUS,
|
||||||
|
cy - FLUID_UPDATING_SQUARE_RADIUS,
|
||||||
|
cx + FLUID_UPDATING_SQUARE_RADIUS,
|
||||||
|
cy + FLUID_UPDATING_SQUARE_RADIUS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val ingame: TerrarumIngame
|
private val ingame: TerrarumIngame
|
||||||
get() = Terrarum.ingame!! as TerrarumIngame
|
get() = Terrarum.ingame!! as TerrarumIngame
|
||||||
private val world: GameWorld
|
private val world: GameWorld
|
||||||
@@ -82,21 +177,66 @@ object WorldSimulator {
|
|||||||
|
|
||||||
//printdbg(this, "============================")
|
//printdbg(this, "============================")
|
||||||
|
|
||||||
if (player != null) {
|
// Compute non-overlapping merged regions for general simulations
|
||||||
updateXFrom = player.hitbox.centeredX.div(TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundToInt()
|
val mergedRegions = computeUpdateRegions()
|
||||||
updateYFrom = player.hitbox.centeredY.div(TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundToInt()
|
|
||||||
updateXTo = updateXFrom + DOUBLE_RADIUS
|
// Compute individual (unmerged) regions for fluid simulation
|
||||||
updateYTo = updateYFrom + DOUBLE_RADIUS
|
// Each WorldUpdater gets its own fluid region; overlap is handled by processedFluidTiles mask
|
||||||
|
val fluidRegions = computeIndividualFluidRegions()
|
||||||
|
|
||||||
|
// Fallback to player-based region if no WorldUpdaters exist
|
||||||
|
val regionsToProcess = if (mergedRegions.isNotEmpty()) {
|
||||||
|
mergedRegions
|
||||||
|
} else if (player != null) {
|
||||||
|
val px = player.hitbox.centeredX.div(TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundToInt()
|
||||||
|
val py = player.hitbox.centeredY.div(TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundToInt()
|
||||||
|
listOf(UpdateRegion(px, py, px + DOUBLE_RADIUS, py + DOUBLE_RADIUS))
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ingame.terrainChangeQueue.isNotEmpty()) { App.measureDebugTime("WorldSimulator.degrass") { buryGrassImmediately() } }
|
val fluidRegionsToProcess = if (fluidRegions.isNotEmpty()) {
|
||||||
|
fluidRegions
|
||||||
|
} else if (player != null) {
|
||||||
|
val px = player.hitbox.centeredX.div(TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundToInt()
|
||||||
|
val py = player.hitbox.centeredY.div(TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundToInt()
|
||||||
|
listOf(UpdateRegion(px, py, px + DOUBLE_RADIUS, py + DOUBLE_RADIUS))
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// buryGrassImmediately doesn't depend on update region
|
||||||
|
if (ingame.terrainChangeQueue.isNotEmpty()) {
|
||||||
|
App.measureDebugTime("WorldSimulator.degrass") { buryGrassImmediately() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process fluids for each WorldUpdater individually, using mask for overlap deduplication
|
||||||
|
processedFluidTiles.clear()
|
||||||
|
App.measureDebugTime("WorldSimulator.fluids") {
|
||||||
|
for (region in fluidRegionsToProcess) {
|
||||||
|
updateXFrom = region.xFrom
|
||||||
|
updateYFrom = region.yFrom
|
||||||
|
updateXTo = region.xTo
|
||||||
|
updateYTo = region.yTo
|
||||||
|
moveFluids(delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process other simulations using merged non-overlapping regions
|
||||||
|
for (region in regionsToProcess) {
|
||||||
|
updateXFrom = region.xFrom
|
||||||
|
updateYFrom = region.yFrom
|
||||||
|
updateXTo = region.xTo
|
||||||
|
updateYTo = region.yTo
|
||||||
|
|
||||||
App.measureDebugTime("WorldSimulator.growGrass") { growOrKillGrass() }
|
App.measureDebugTime("WorldSimulator.growGrass") { growOrKillGrass() }
|
||||||
App.measureDebugTime("WorldSimulator.fluids") { moveFluids(delta) }
|
|
||||||
App.measureDebugTime("WorldSimulator.fallables") { displaceFallables(delta) }
|
App.measureDebugTime("WorldSimulator.fallables") { displaceFallables(delta) }
|
||||||
App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) }
|
App.measureDebugTime("WorldSimulator.wires") { simulateWires(delta) }
|
||||||
App.measureDebugTime("WorldSimulator.collisionDroppedItem") { collideDroppedItems() }
|
|
||||||
App.measureDebugTime("WorldSimulator.dropTreeLeaves") { dropTreeLeaves() }
|
App.measureDebugTime("WorldSimulator.dropTreeLeaves") { dropTreeLeaves() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// collideDroppedItems doesn't depend on update region (uses actor list)
|
||||||
|
App.measureDebugTime("WorldSimulator.collisionDroppedItem") { collideDroppedItems() }
|
||||||
|
|
||||||
//printdbg(this, "============================")
|
//printdbg(this, "============================")
|
||||||
}
|
}
|
||||||
@@ -502,10 +642,21 @@ object WorldSimulator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Packs world coordinates into a single Long for use as a HashSet key */
|
||||||
|
private fun packFluidCoords(worldX: Int, worldY: Int): Long =
|
||||||
|
(worldX.toLong() shl 32) or (worldY.toLong() and 0xFFFFFFFFL)
|
||||||
|
|
||||||
private fun fluidmapToWorld() {
|
private fun fluidmapToWorld() {
|
||||||
for (y in fluidMap.indices) {
|
for (y in fluidMap.indices) {
|
||||||
for (x in fluidMap[0].indices) {
|
for (x in fluidMap[0].indices) {
|
||||||
world.setFluid(x + updateXFrom, y + updateYFrom, fluidNewTypeMap[y][x], fluidNewMap[y][x])
|
val worldX = x + updateXFrom
|
||||||
|
val worldY = y + updateYFrom
|
||||||
|
val key = packFluidCoords(worldX, worldY)
|
||||||
|
// Only write if this tile hasn't been processed yet (deduplication for overlapping regions)
|
||||||
|
if (key !in processedFluidTiles) {
|
||||||
|
world.setFluid(worldX, worldY, fluidNewTypeMap[y][x], fluidNewMap[y][x])
|
||||||
|
processedFluidTiles.add(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import net.torvald.terrarum.App
|
|||||||
import net.torvald.terrarum.Terrarum
|
import net.torvald.terrarum.Terrarum
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
import net.torvald.terrarum.gameactors.NoSerialise
|
import net.torvald.terrarum.gameactors.NoSerialise
|
||||||
|
import net.torvald.terrarum.gameactors.WorldUpdater
|
||||||
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
import net.torvald.terrarum.itemproperties.ItemRemapTable
|
||||||
import net.torvald.terrarum.itemproperties.ItemTable
|
import net.torvald.terrarum.itemproperties.ItemTable
|
||||||
import net.torvald.terrarum.spriteassembler.ADProperties
|
import net.torvald.terrarum.spriteassembler.ADProperties
|
||||||
@@ -20,7 +21,7 @@ import java.util.*
|
|||||||
* Created by minjaesong on 2015-12-31.
|
* Created by minjaesong on 2015-12-31.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class IngamePlayer : ActorHumanoid, HasAssembledSprite, NoSerialise {
|
class IngamePlayer : ActorHumanoid, HasAssembledSprite, NoSerialise, WorldUpdater {
|
||||||
|
|
||||||
val creationTime = App.getTIME_T()
|
val creationTime = App.getTIME_T()
|
||||||
var lastPlayTime = App.getTIME_T() // cumulative value for the savegame
|
var lastPlayTime = App.getTIME_T() // cumulative value for the savegame
|
||||||
|
|||||||
Reference in New Issue
Block a user