diff --git a/src/net/torvald/terrarum/blockproperties/WireCodex.kt b/src/net/torvald/terrarum/blockproperties/WireCodex.kt index 40b141cb5..e377f2a94 100644 --- a/src/net/torvald/terrarum/blockproperties/WireCodex.kt +++ b/src/net/torvald/terrarum/blockproperties/WireCodex.kt @@ -151,4 +151,8 @@ class WireCodex { printdbg(this, "Setting prop ${prop.id} ->>\t${prop.nameKey}") } + + fun getAllWiresThatAccepts(accept: String): List> { + return wireProps.filter { it.value.accepts == accept }.toList() + } } \ 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 457429381..ba9bed9fc 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -389,14 +389,14 @@ open class GameWorld( return wiringGraph[blockAddr]?.get(itemID)?.emt } - fun getWireRecvStateOf(x: Int, y: Int, itemID: ItemID): ArrayList? { + fun getWireReceptionStateOf(x: Int, y: Int, itemID: ItemID): ArrayList? { val (x, y) = coerceXY(x, y) val blockAddr = LandUtil.getBlockAddr(this, x, y) - return getWireRecvStateUnsafe(blockAddr, itemID) + return getWireReceptionStateUnsafe(blockAddr, itemID) } - fun getWireRecvStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): ArrayList? { - return wiringGraph[blockAddr]?.get(itemID)?.rcv + fun getWireReceptionStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): ArrayList? { + return wiringGraph[blockAddr]?.get(itemID)?.rcp } fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, cnx: Int) { @@ -429,7 +429,7 @@ open class GameWorld( wiringGraph[blockAddr]!![itemID]!!.emt.set(vector) } - fun addWireRecvStateOf(x: Int, y: Int, itemID: ItemID, state: WireRecvState) { + fun addWireRecvStateOf(x: Int, y: Int, itemID: ItemID, state: WireReceptionState) { val (x, y) = coerceXY(x, y) val blockAddr = LandUtil.getBlockAddr(this, x, y) return addWireRecvStateOfUnsafe(blockAddr, itemID, state) @@ -441,13 +441,13 @@ open class GameWorld( return clearAllWireRecvStateUnsafe(blockAddr) } - fun addWireRecvStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, state: WireRecvState) { + fun addWireRecvStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, state: WireReceptionState) { if (wiringGraph[blockAddr] == null) wiringGraph[blockAddr] = WiringGraphMap() if (wiringGraph[blockAddr]!![itemID] == null) wiringGraph[blockAddr]!![itemID] = WiringSimCell(0) - wiringGraph[blockAddr]!![itemID]!!.rcv.add(state) + wiringGraph[blockAddr]!![itemID]!!.rcp.add(state) } fun getAllWiringGraph(x: Int, y: Int): HashMap? { @@ -462,7 +462,7 @@ open class GameWorld( fun clearAllWireRecvStateUnsafe(blockAddr: BlockAddress) { wiringGraph[blockAddr]?.forEach { - it.value.rcv.clear() + it.value.rcp.clear() } } @@ -654,7 +654,7 @@ open class GameWorld( val ws: SortedArrayList = SortedArrayList() // what could possibly go wrong bloating up the RAM footprint when it's practically infinite these days? ) - data class WireRecvState( + data class WireReceptionState( var dist: Int = -1, // how many tiles it took to traverse var src: Point2i = Point2i(0,0) // xy position // to get the state, use the src to get the state of the source emitter directly, then use dist to apply attenuation @@ -666,7 +666,7 @@ open class GameWorld( data class WiringSimCell( var cnx: Int = 0, // connections. [1, 2, 4, 8] = [RIGHT, DOWN, LEFT, UP] val emt: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power - val rcv: ArrayList = ArrayList() // how far away are the power sources + val rcp: ArrayList = ArrayList() // how far away are the power sources ) fun getTemperature(worldTileX: Int, worldTileY: Int): Float? { diff --git a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt index 5c15c934c..302266bae 100644 --- a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt @@ -469,15 +469,15 @@ object WorldSimulator { /** * @return List of FixtureBases, safe to cast into Electric */ - private fun wiresimGetSourceBlocks(): List = - INGAME.actorContainerActive.filterIsInstance().filter { - it is Electric && it.inUpdateRange(world) && it.wireEmitterTypes.isNotEmpty() + private fun wiresimGetSourceBlocks(): List = + INGAME.actorContainerActive.filterIsInstance().filter { + it.inUpdateRange(world) && it.wireEmitterTypes.isNotEmpty() } private val wireSimMarked = HashSet() private val wireSimPoints = Queue() private val oldTraversedNodes = ArrayList() - private val fixtureCache = HashMap>() // also instance of Electric + private val fixtureCache = HashMap>() // also instance of Electric private fun simulateWires(delta: Float) { // unset old wires before we begin @@ -491,10 +491,10 @@ object WorldSimulator { wiresimGetSourceBlocks().let { sources -> // signal-emitting fixtures must set emitState of its own tiles via update() sources.forEach { - (it as Electric).wireEmitterTypes.forEach { bbi, wireType -> + it.wireEmitterTypes.forEach { bbi, wireType -> val startingPoint = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(bbi) - val signal = (it as Electric).wireEmission[bbi] ?: Vector2(0.0, 0.0) + val signal = it.wireEmission[bbi] ?: Vector2(0.0, 0.0) world.getAllWiringGraph(startingPoint.x, startingPoint.y)?.keys?.filter { WireCodex[it].accepts == wireType }?.forEach { wire -> val simStartingPoint = WireGraphCursor(startingPoint, wire) @@ -553,20 +553,19 @@ object WorldSimulator { if (fixture == null) { INGAME.getActorsAt(point.x * TILE_SIZED, point.y * TILE_SIZED).filterIsInstance().firstOrNull().let { found -> if (found != null) { - val foundFixture = (found as FixtureBase) // get offset from the fixture's origin - tileOffsetFromFixture = foundFixture.intTilewiseHitbox.let { Point2i(it.startX.toInt(), it.startY.toInt()) } - tilePoint + tileOffsetFromFixture = found.intTilewiseHitbox.let { Point2i(it.startX.toInt(), it.startY.toInt()) } - tilePoint // println("$tilePoint; ${found.javaClass.canonicalName}, $tileOffsetFromFixture, ${found.getWireSinkAt(tileOffsetFromFixture!!)}") if (found.getWireSinkAt(tileOffsetFromFixture!!) == emissionType) { - fixtureCache[tilePoint] = foundFixture to emissionType - fixture = foundFixture to emissionType + fixtureCache[tilePoint] = found to emissionType + fixture = found to emissionType } } } } - (fixture?.first as? Electric)?.updateOnWireGraphTraversal(tileOffsetFromFixture!!.x, tileOffsetFromFixture!!.y, fixture!!.second) + fixture?.first?.updateOnWireGraphTraversal(tileOffsetFromFixture!!.x, tileOffsetFromFixture!!.y, fixture!!.second) } } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt index eb045670e..c6d987105 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt @@ -16,18 +16,108 @@ import java.util.* typealias BlockBoxIndex = Int typealias WireEmissionType = String -interface Electric { - val wireEmitterTypes: HashMap - val wireSinkTypes: HashMap - val wireEmission: HashMap - val wireConsumption: HashMap +open class Electric : FixtureBase { - fun onRisingEdge(readFrom: BlockBoxIndex) {} - fun onFallingEdge(readFrom: BlockBoxIndex) {} - fun onSignalHigh(readFrom: BlockBoxIndex, highThreshold: Double = 0.9) {} - fun onSignalLow(readFrom: BlockBoxIndex, lowThreshold: Double = 0.1) {} + protected constructor() : super() { + oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() } + } - fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {} + /** + * Making the sprite: do not address the CommonResourcePool directly; just do it like this snippet: + * + * ```makeNewSprite(FixtureBase.getSpritesheet("basegame", "sprites/fixtures/tiki_torch.tga", 16, 32))``` + */ + constructor( + blockBox0: BlockBox, + blockBoxProps: BlockBoxProps = BlockBoxProps(0), + renderOrder: RenderOrder = RenderOrder.MIDDLE, + nameFun: () -> String, + mainUI: UICanvas? = null, + inventory: FixtureInventory? = null, + id: ActorID? = null + ) : super(renderOrder, PhysProperties.IMMOBILE, id) { + blockBox = blockBox0 + setHitboxDimension(TILE_SIZE * blockBox.width, TILE_SIZE * blockBox.height, 0, 0) + this.blockBoxProps = blockBoxProps + this.renderOrder = renderOrder + this.nameFun = nameFun + this.mainUI = mainUI + this.inventory = inventory + + if (mainUI != null) + App.disposables.add(mainUI) + + oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() } + } + + companion object { + const val ELECTIC_THRESHOLD_HIGH = 0.9 + const val ELECTRIC_THRESHOLD_LOW = 0.1 + const val ELECTRIC_THRESHOLD_EDGE_DELTA = 0.7 + } + + fun getWireEmitterAt(point: Point2i) = if (this is Electric) this.wireEmitterTypes[pointToBlockBoxIndex(point)] else throw IllegalStateException("Fixture is not instance of Electric") + fun getWireEmitterAt(x: Int, y: Int) = if (this is Electric) this.wireEmitterTypes[pointToBlockBoxIndex(x, y)] else throw IllegalStateException("Fixture is not instance of Electric") + fun getWireSinkAt(point: Point2i) = if (this is Electric) this.wireSinkTypes[pointToBlockBoxIndex(point)] else throw IllegalStateException("Fixture is not instance of Electric") + fun getWireSinkAt(x: Int, y: Int) = if (this is Electric) this.wireSinkTypes[pointToBlockBoxIndex(x, y)] else throw IllegalStateException("Fixture is not instance of Electric") + + fun setWireEmitterAt(x: Int, y: Int, type: WireEmissionType) { if (this is Electric) wireEmitterTypes[pointToBlockBoxIndex(x, y)] = type else throw IllegalStateException("Fixture is not instance of Electric") } + fun setWireSinkAt(x: Int, y: Int, type: WireEmissionType) { if (this is Electric) wireSinkTypes[pointToBlockBoxIndex(x, y)] = type else throw IllegalStateException("Fixture is not instance of Electric") } + fun setWireEmissionAt(x: Int, y: Int, emission: Vector2) { if (this is Electric) wireEmission[pointToBlockBoxIndex(x, y)] = emission else throw IllegalStateException("Fixture is not instance of Electric") } + fun setWireConsumptionAt(x: Int, y: Int, consumption: Vector2) { if (this is Electric) wireConsumption[pointToBlockBoxIndex(x, y)] = consumption else throw IllegalStateException("Fixture is not instance of Electric") } + + @Transient val wireEmitterTypes: HashMap = HashMap() + @Transient val wireSinkTypes: HashMap = HashMap() + @Transient val wireEmission: HashMap = HashMap() + @Transient val wireConsumption: HashMap = HashMap() + + /** Edge detection only considers the real component (labeled as 'x') of the vector */ + open fun onRisingEdge(readFrom: BlockBoxIndex) {} + /** Edge detection only considers the real component (labeled as 'x') of the vector */ + open fun onFallingEdge(readFrom: BlockBoxIndex) {} + /** Level detection only considers the real component (labeled as 'x') of the vector */ + open fun onSignalHigh(readFrom: BlockBoxIndex) {} + /** Level detection only considers the real component (labeled as 'x') of the vector */ + open fun onSignalLow(readFrom: BlockBoxIndex) {} + + + private val oldSinkStatus: Array + + open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) { + val index = pointToBlockBoxIndex(offsetX, offsetY) + val old = oldSinkStatus[index] + val wx = offsetX + intTilewiseHitbox.startX.toInt() + val wy = offsetY + intTilewiseHitbox.startY.toInt() + val new = WireCodex.getAllWiresThatAccepts("digital_bit").fold(Vector2()) { acc, (id, _) -> + INGAME.world.getWireEmitStateOf(wx, wy, id).let { + Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0)) + } + } + + if (new.x - old.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTIC_THRESHOLD_HIGH) + onRisingEdge(index) + else if (old.x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW) + onFallingEdge(index) + else if (new.x >= ELECTIC_THRESHOLD_HIGH) + onSignalHigh(index) + else if (new.y <= ELECTRIC_THRESHOLD_LOW) + onSignalLow(index) + + } + + override fun update(delta: Float) { + super.update(delta) + oldSinkStatus.indices.forEach { index -> + val wx = (index % blockBox.width) + intTilewiseHitbox.startX.toInt() + val wy = (index / blockBox.width) + intTilewiseHitbox.startY.toInt() + val new = WireCodex.getAllWiresThatAccepts(getWireSinkAt(index % blockBox.width, index / blockBox.width) ?: "").fold(Vector2()) { acc, (id, _) -> + INGAME.world.getWireEmitStateOf(wx, wy, id).let { + Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0)) + } + } + oldSinkStatus[index].set(new) + } + } } /** @@ -49,16 +139,6 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange { fun pointToBlockBoxIndex(point: Point2i) = point.y * this.blockBox.width + point.x fun pointToBlockBoxIndex(x: Int, y: Int) = y * this.blockBox.width + x - fun getWireEmitterAt(point: Point2i) = if (this is Electric) this.wireEmitterTypes[pointToBlockBoxIndex(point)] else throw IllegalStateException("Fixture is not instance of Electric") - fun getWireEmitterAt(x: Int, y: Int) = if (this is Electric) this.wireEmitterTypes[pointToBlockBoxIndex(x, y)] else throw IllegalStateException("Fixture is not instance of Electric") - fun getWireSinkAt(point: Point2i) = if (this is Electric) this.wireSinkTypes[pointToBlockBoxIndex(point)] else throw IllegalStateException("Fixture is not instance of Electric") - fun getWireSinkAt(x: Int, y: Int) = if (this is Electric) this.wireSinkTypes[pointToBlockBoxIndex(x, y)] else throw IllegalStateException("Fixture is not instance of Electric") - - fun setWireEmitterAt(x: Int, y: Int, type: WireEmissionType) { if (this is Electric) wireEmitterTypes[pointToBlockBoxIndex(x, y)] = type else throw IllegalStateException("Fixture is not instance of Electric") } - fun setWireSinkAt(x: Int, y: Int, type: WireEmissionType) { if (this is Electric) wireSinkTypes[pointToBlockBoxIndex(x, y)] = type else throw IllegalStateException("Fixture is not instance of Electric") } - fun setWireEmissionAt(x: Int, y: Int, emission: Vector2) { if (this is Electric) wireEmission[pointToBlockBoxIndex(x, y)] = emission else throw IllegalStateException("Fixture is not instance of Electric") } - fun setWireConsumptionAt(x: Int, y: Int, consumption: Vector2) { if (this is Electric) wireConsumption[pointToBlockBoxIndex(x, y)] = consumption else throw IllegalStateException("Fixture is not instance of Electric") } - var blockBoxProps: BlockBoxProps = BlockBoxProps(0) @Transient var nameFun: () -> String = { "" } @Transient var mainUI: UICanvas? = null @@ -66,7 +146,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange { protected var actorThatInstalledThisFixture: UUID? = null - private constructor() : super(RenderOrder.BEHIND, PhysProperties.IMMOBILE, null) + protected constructor() : super(RenderOrder.BEHIND, PhysProperties.IMMOBILE, null) + protected constructor(renderOrder: RenderOrder, physProp: PhysProperties, id: ActorID?) : super(renderOrder, physProp, id) /** diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureLogicSignalEmitter.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureLogicSignalEmitter.kt index c3dc9c3d6..b7657f776 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureLogicSignalEmitter.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureLogicSignalEmitter.kt @@ -7,13 +7,7 @@ import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import org.dyn4j.geometry.Vector2 -class FixtureLogicSignalEmitter : FixtureBase, Electric { - - @Transient override val wireEmitterTypes: java.util.HashMap = java.util.HashMap() - @Transient override val wireSinkTypes: java.util.HashMap = java.util.HashMap() - @Transient override val wireEmission: HashMap = HashMap() - @Transient override val wireConsumption: HashMap = HashMap() - +class FixtureLogicSignalEmitter : Electric { constructor() : super( BlockBox(BlockBox.NO_COLLISION, 1, 1), @@ -31,17 +25,11 @@ class FixtureLogicSignalEmitter : FixtureBase, Electric { } actorValue[AVKey.BASEMASS] = MASS - + setWireEmitterAt(0, 0, "digital_bit") setWireEmissionAt(0, 0, Vector2(1.0, 0.0)) } - override fun update(delta: Float) { - // the values does not get preserved on save reload?? - - super.update(delta) - } - override fun dispose() { } companion object { diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureWorldPortal.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureWorldPortal.kt index b537850dd..221469884 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureWorldPortal.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureWorldPortal.kt @@ -1,5 +1,7 @@ package net.torvald.terrarum.modulebasegame.gameactors +import net.torvald.terrarum.INGAME +import net.torvald.terrarum.WireCodex import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory.Companion.CAPACITY_MODE_WEIGHT @@ -12,13 +14,7 @@ import java.util.HashMap /** * Created by minjaesong on 2023-05-28. */ -class FixtureWorldPortal : FixtureBase, Electric { - - @Transient override val wireEmitterTypes: HashMap = HashMap() - @Transient override val wireSinkTypes: HashMap = HashMap() - @Transient override val wireEmission: HashMap = HashMap() - @Transient override val wireConsumption: HashMap = HashMap() - +class FixtureWorldPortal : Electric { constructor() : super( BlockBox(BlockBox.NO_COLLISION, 5, 2), @@ -48,14 +44,6 @@ class FixtureWorldPortal : FixtureBase, Electric { setWireSinkAt(2, 1, "digital_bit") } - override fun update(delta: Float) { - super.update(delta) - } - - override fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) { - println("[FixtureWorldPortal] updateOnWireGraphTraversal! ($offsetX, $offsetY, $sinkType)") - } - override fun onRisingEdge(readFrom: BlockBoxIndex) { println("[FixtureWorldPortal] teleport! ($readFrom)") } diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt index 6bfb12e1f..3e371cb86 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt @@ -51,7 +51,7 @@ class WireGraphDebugger(originalID: ItemID) : GameItem(originalID) { val wireName = WireCodex[itemID].nameKey val emit = simCell.emt - val recv = simCell.rcv + val recv = simCell.rcp sb.append("$connexionIcon $wireName") sb.append("\nE: $emit")