wire branching traversal itself works, but fetches wrong signal status

This commit is contained in:
minjaesong
2021-08-12 11:38:48 +09:00
parent 884c129837
commit a6d082fb7d
6 changed files with 96 additions and 76 deletions

View File

@@ -71,9 +71,9 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
val actorContainerInactive = SortedArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE) val actorContainerInactive = SortedArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
// FIXME queues will not work; input processing (blocks will queue) and queue consuming cannot be synchronised // FIXME queues will not work; input processing (blocks will queue) and queue consuming cannot be synchronised
protected val terrainChangeQueue = ArrayList<BlockChangeQueueItem>() //protected val terrainChangeQueue = ArrayList<BlockChangeQueueItem>()
protected val wallChangeQueue = ArrayList<BlockChangeQueueItem>() //protected val wallChangeQueue = ArrayList<BlockChangeQueueItem>()
protected val wireChangeQueue = ArrayList<BlockChangeQueueItem>() // if 'old' is set and 'new' is blank, it's a wire cutter //protected val wireChangeQueue = ArrayList<BlockChangeQueueItem>() // if 'old' is set and 'new' is blank, it's a wire cutter
override fun hide() { override fun hide() {
} }
@@ -153,15 +153,14 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
* Queueing schema is used to make sure things are synchronised. * Queueing schema is used to make sure things are synchronised.
*/ */
open fun queueTerrainChangedEvent(old: ItemID, new: ItemID, x: Int, y: Int) { open fun queueTerrainChangedEvent(old: ItemID, new: ItemID, x: Int, y: Int) {
printdbg(this, "Terrain change enqueued: ${BlockChangeQueueItem(old, new, x, y)}") //printdbg(this, terrainChangeQueue)
printdbg(this, terrainChangeQueue)
} }
/** /**
* Wall version of terrainChanged() event * Wall version of terrainChanged() event
*/ */
open fun queueWallChangedEvent(old: ItemID, new: ItemID, x: Int, y: Int) { open fun queueWallChangedEvent(old: ItemID, new: ItemID, x: Int, y: Int) {
wallChangeQueue.add(BlockChangeQueueItem(old, new, x, y)) //wallChangeQueue.add(BlockChangeQueueItem(old, new, x, y))
} }
/** /**
@@ -171,7 +170,7 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
* @param new current settings of conduits in bit set format. * @param new current settings of conduits in bit set format.
*/ */
open fun queueWireChangedEvent(wire: ItemID, isRemoval: Boolean, x: Int, y: Int) { open fun queueWireChangedEvent(wire: ItemID, isRemoval: Boolean, x: Int, y: Int) {
wireChangeQueue.add(BlockChangeQueueItem(if (isRemoval) wire else "", if (isRemoval) "" else wire, x, y)) //wireChangeQueue.add(BlockChangeQueueItem(if (isRemoval) wire else "", if (isRemoval) "" else wire, x, y))
} }

View File

@@ -16,6 +16,8 @@ import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.BlockBoxIndex import net.torvald.terrarum.modulebasegame.gameactors.BlockBoxIndex
import net.torvald.terrarum.modulebasegame.gameactors.Electric import net.torvald.terrarum.modulebasegame.gameactors.Electric
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
import net.torvald.util.IntArrayStack
import org.dyn4j.geometry.Vector2
import org.khelekore.prtree.* import org.khelekore.prtree.*
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@@ -200,44 +202,38 @@ object WorldSimulator {
// displace fallables (TODO implement blocks with fallable supports e.g. scaffolding) // displace fallables (TODO implement blocks with fallable supports e.g. scaffolding)
// only displace SINGLE BOTTOMMOST block on single X-coord (this doesn't mean they must fall only one block) // only displace SINGLE BOTTOMMOST block on single X-coord (this doesn't mean they must fall only one block)
// so that the "falling" should be visible to the end user // so that the "falling" should be visible to the end user
if (!DEBUG_STEPPING_MODE || DEBUG_STEPPING_MODE && KeyToggler.isOn (Input.Keys.PERIOD)) { for (x in updateXFrom..updateXTo) {
for (x in updateXFrom..updateXTo) { var fallDownCounter = 0
var fallDownCounter = 0 var fallableStackProcessed = false
var fallableStackProcessed = false // one "stack" is a contiguous fallable blocks, regardless of the actual block number
// one "stack" is a contiguous fallable blocks, regardless of the actual block number // when you are simulating the gradual falling, it is natural to process all the "stacks" at the same run,
// when you are simulating the gradual falling, it is natural to process all the "stacks" at the same run, // otherwise you'll get an artefact.
// otherwise you'll get an artefact. for (y in updateYTo downTo updateYFrom) {
for (y in updateYTo downTo updateYFrom) { val currentTile = world.getTileFromTerrain(x, y)
val currentTile = world.getTileFromTerrain(x, y) val prop = BlockCodex[currentTile]
val prop = BlockCodex[currentTile] val isAir = currentTile == Block.AIR
val isAir = currentTile == Block.AIR val support = prop.maxSupport
val support = prop.maxSupport val isFallable = support != -1
val isFallable = support != -1
// mark the beginnig of the new "stack" // mark the beginnig of the new "stack"
if (fallableStackProcessed && !isFallable) { if (fallableStackProcessed && !isFallable) {
fallableStackProcessed = false fallableStackProcessed = false
} // do not chain with "else if" } // do not chain with "else if"
// process the gradual falling of the selected "stack" // process the gradual falling of the selected "stack"
if (!fallableStackProcessed && fallDownCounter != 0 && isFallable) { if (!fallableStackProcessed && fallDownCounter != 0 && isFallable) {
// replace blocks // replace blocks
world.setTileTerrain(x, y, Block.AIR, true) world.setTileTerrain(x, y, Block.AIR, true)
world.setTileTerrain(x, y + fallDownCounter, currentTile, true) world.setTileTerrain(x, y + fallDownCounter, currentTile, true)
fallableStackProcessed = true fallableStackProcessed = true
} }
else if (!isAir) { else if (!isAir) {
fallDownCounter = 0 fallDownCounter = 0
} }
else if (!isFallable && fallDownCounter < FALLABLE_MAX_FALL_SPEED) { else if (!isFallable && fallDownCounter < FALLABLE_MAX_FALL_SPEED) {
fallDownCounter += 1 fallDownCounter += 1
}
} }
}
if (DEBUG_STEPPING_MODE) {
KeyToggler.forceSet(Input.Keys.PERIOD, false)
} }
} }
@@ -491,9 +487,14 @@ object WorldSimulator {
var terminate = false var terminate = false
fun dequeue() { fun dequeue() {
//printdbg(this, "points before deq: $points")
points.removeAt(0) points.removeAt(0)
//printdbg(this, "points after deq: $points")
if (points.size == 0) terminate = true if (points.size == 0) terminate = true
else point = points[0] else {
point = points[0]
//printdbg(this, "new point: $point")
}
} }
points.add(point.copy()) points.add(point.copy())
@@ -510,7 +511,7 @@ object WorldSimulator {
world.getAllWiringGraph(point.x, point.y)?.get(wire)?.let { node -> world.getAllWiringGraph(point.x, point.y)?.get(wire)?.let { node ->
val signal = node.emitState val signal = Vector2(1.0, 0.0)//node.emitState // FIXME branching wires somehow fetches wrong signal value
val cnx = node.connections.toInt() // 1-15 val cnx = node.connections.toInt() // 1-15
val nextDirBit = cnx and (15 - point.fromWhere) // cnx minus where the old cursur was; also 1-15 val nextDirBit = cnx and (15 - point.fromWhere) // cnx minus where the old cursur was; also 1-15
//printdbg(this, "(${point.x}, ${point.y}) from ${point.fromWhere} to $nextDirBit") //printdbg(this, "(${point.x}, ${point.y}) from ${point.fromWhere} to $nextDirBit")
@@ -526,7 +527,7 @@ object WorldSimulator {
else { else {
when (nextDirBit.bitCount()) { when (nextDirBit.bitCount()) {
in 4..64 -> { throw IllegalArgumentException("Bad nextDirBit: $nextDirBit") } in 5..64 -> { throw IllegalArgumentException("Bad nextDirBit: $nextDirBit") }
// nowhere to go // nowhere to go
0 -> { 0 -> {
dequeue() dequeue()
@@ -539,17 +540,35 @@ object WorldSimulator {
// propagate the signal to next position // propagate the signal to next position
world.setWireEmitStateOf(point.x, point.y, wire, signal) world.setWireEmitStateOf(point.x, point.y, wire, signal)
} }
// two or three directions to go // two, three or four (starting point only) directions to go
else -> { else -> {
return
// propagate the signal
// mark this branch // mark this branch
points.add(point.copy()) //branchesVisited.add(point.copy())
// move the "cursor" by try right, down, left then up // spawn and move the "cursor" by try right, down, left then up
val movableDirs = IntArrayStack(4)
for (s in 3 downTo 0) { // so that top of the stack holds lowest of the direction-number
(nextDirBit and (1 shl s)).let {
if (it != 0) movableDirs.push(it)
}
}
//printdbg(this, movableDirs.depth) // stack size is correct..?
// take top of the stack as mine
val mine = movableDirs.pop()
while (movableDirs.isNotEmpty()) {
// obviously 'point' must not me altered beforehand
movableDirs.pop().let { dir ->
points.add(point.copy().moveOneCell(dir))
}
}
//printdbg(this, points) // and points are also correct...
// finally move the cursor of mine
point.moveOneCell(mine)
// propagate the signal to next position
world.setWireEmitStateOf(point.x, point.y, wire, signal)
} }
} }
} }
@@ -563,6 +582,11 @@ object WorldSimulator {
} }
} }
private const val RIGHT = 1
private const val DOWN = 2
private const val LEFT = 4
private const val UP = 8
private fun getNearbyTilesPos(x: Int, y: Int): Array<Point2i> { private fun getNearbyTilesPos(x: Int, y: Int): Array<Point2i> {
return arrayOf( return arrayOf(
Point2i(x + 1, y), Point2i(x + 1, y),
@@ -580,15 +604,17 @@ object WorldSimulator {
) { ) {
constructor(point2i: Point2i): this(point2i.x, point2i.y, 0, 0) constructor(point2i: Point2i): this(point2i.x, point2i.y, 0, 0)
fun moveOneCell(dir: Int) { fun moveOneCell(dir: Int): WireGraphCursor {
when (dir) { when (dir) {
1 -> { x += 1; fromWhere = 4 } 1 -> { x += 1; fromWhere = LEFT }
2 -> { y += 1; fromWhere = 8 } 2 -> { y += 1; fromWhere = UP }
4 -> { x -= 1; fromWhere = 1 } 4 -> { x -= 1; fromWhere = RIGHT }
8 -> { y -= 1; fromWhere = 2 } 8 -> { y -= 1; fromWhere = DOWN }
else -> throw IllegalArgumentException("Unacceptable direction: $dir") else -> throw IllegalArgumentException("Unacceptable direction: $dir")
} }
len += 1 len += 1
return this
} }
} }
} }

View File

@@ -589,6 +589,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
if (!paused) { if (!paused) {
//hypothetical_input_capturing_function_if_you_finally_decided_to_forgo_gdx_input_processor_and_implement_your_own_to_synchronise_everything()
WorldSimulator.resetForThisFrame() WorldSimulator.resetForThisFrame()
/////////////////////////// ///////////////////////////
@@ -635,13 +637,12 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
// world click events (e.g. opening the UI that a fixture has) must go here // world click events (e.g. opening the UI that a fixture has) must go here
ingameController.update(delta) ingameController.update(delta)
if (!paused) { /*if (!paused) {
printdbg(this, "Clear tile change queues")
// completely consume block change queues because why not // completely consume block change queues because why not
terrainChangeQueue.clear() terrainChangeQueue.clear()
wallChangeQueue.clear() wallChangeQueue.clear()
wireChangeQueue.clear() wireChangeQueue.clear()
} }*/
//////////////////////// ////////////////////////
@@ -876,13 +877,13 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
} }
} }
if (it is CuedByTerrainChange) { /*if (it is CuedByTerrainChange) {
printdbg(this, "actor is CuedByTerrainChange: ${terrainChangeQueue}") printdbg(this, "actor is CuedByTerrainChange: ${terrainChangeQueue}")
terrainChangeQueue.forEach { cue -> terrainChangeQueue.forEach { cue ->
printdbg(this, "Ingame actors terrainChangeCue: ${cue}") printdbg(this, "Ingame actors terrainChangeCue: ${cue}")
it.updateForWorldChange(cue) it.updateForWorldChange(cue)
} }
} }*/
} }
} }
actorNowPlaying?.update(delta) actorNowPlaying?.update(delta)

View File

@@ -145,18 +145,8 @@ open class FixtureBase(
this.isVisible = false this.isVisible = false
} }
/** override fun update(delta: Float) {
* Fired by world's BlockChanged event (fired when blocks are placed/removed). super.update(delta)
* The flooding check must run on every frame. use updateSelf() for that.
*
* E.g. if a fixture block that is inside of BlockBox is missing, destroy and drop self.
*/
override fun updateForWorldChange(cue: IngameInstance.BlockChangeQueueItem) {
printdbg(this, "updateForWorldChange ${nameFun()}")
// check for marker blocks.
// if at least one of them is missing, destroy all the markers and drop self as an item
// you need to implement Dropped Item first to satisfyingly implement this function
val posX = worldBlockPos!!.x val posX = worldBlockPos!!.x
val posY = worldBlockPos!!.y val posY = worldBlockPos!!.y
@@ -182,9 +172,10 @@ open class FixtureBase(
} }
// TODO drop self as an item (instance of DroppedItem) // TODO drop self as an item (instance of DroppedItem)
} }
} }
} }
interface CuedByTerrainChange { interface CuedByTerrainChange {
@@ -194,7 +185,7 @@ interface CuedByTerrainChange {
* *
* E.g. if a fixture block that is inside of BlockBox is missing, destroy and drop self. * E.g. if a fixture block that is inside of BlockBox is missing, destroy and drop self.
*/ */
fun updateForWorldChange(cue: IngameInstance.BlockChangeQueueItem) //fun updateForWorldChange(cue: IngameInstance.BlockChangeQueueItem)
} }
/** /**

View File

@@ -264,7 +264,7 @@ internal object BlocksDrawer {
} }
/** /**
* Writes to buffer. Actual draw code must be called after this operation. * Autotiling; writes to buffer. Actual draw code must be called after this operation.
* *
* @param drawModeTilesBlendMul If current drawing mode is MULTIPLY. Doesn't matter if mode is FLUID. * @param drawModeTilesBlendMul If current drawing mode is MULTIPLY. Doesn't matter if mode is FLUID.
* @param wire coduitTypes bit that is selected to be drawn. Must be the power of two. * @param wire coduitTypes bit that is selected to be drawn. Must be the power of two.

View File

@@ -18,6 +18,9 @@ class IntArrayStack {
private lateinit var data: IntArray private lateinit var data: IntArray
fun isEmpty() = depth == 0
fun isNotEmpty() = depth > 0
constructor(stackSize: Int) { constructor(stackSize: Int) {
data = IntArray(stackSize) data = IntArray(stackSize)
} }