some refactoring on FixtureRingBusCore

This commit is contained in:
minjaesong
2025-03-03 22:01:22 +09:00
parent fea4e34733
commit a362ade9af

View File

@@ -4,12 +4,10 @@ import com.badlogic.gdx.utils.Queue
import net.torvald.random.HQRNG
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Point2i
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.BlockBox
import net.torvald.terrarum.modulebasegame.gameactors.Electric
import net.torvald.terrarum.modulebasegame.gameworld.NetFrame
import net.torvald.terrarum.modulebasegame.gameworld.NetRunner
import net.torvald.terrarum.serialise.Common
import net.torvald.terrarum.ui.UICanvas
import org.dyn4j.geometry.Vector2
import kotlin.math.sign
@@ -72,113 +70,118 @@ open class FixtureRingBusCore : Electric {
private var lastAccessTime = -1L
private enum class RingBusState {
NORMAL,
ABORT,
ELECTING,
ELECTED_MONITOR
}
private var currentState = RingBusState.NORMAL
override fun updateSignal() {
val time_t = INGAME.world.worldTime.TIME_T
if (lastAccessTime == -1L) lastAccessTime = time_t
// monitor the input port
val inn = getWireStateAt(1, 0, "10base2")
// if a signal is there
if (inn.x >= SIGNAL_TOO_WEAK_THRESHOLD) {
lastAccessTime = time_t
val frameNumber = (inn.y + (0.5 * inn.y.sign)).toInt()
if (frameNumber != 0) { // frame number must be non-zero
// if not in abort state, process the incoming frames
if (!statusAbort) {
// fetch frame from the world
processFrameBasedOnState(frameNumber)
} else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2())
}
} else {
handleNoSignal(time_t)
}
}
private fun processFrameBasedOnState(frameNumber: Int) {
try {
val frame = getFrameByNumber(frameNumber)
// fast init (voting) cancellation, if applicable
if (activeMonitorStatus == 0 && frame.getFrameType() == "token") {
activeMonitorStatus = 1
when (currentState) {
RingBusState.NORMAL -> handleNormalState(frame, frameNumber)
RingBusState.ABORT -> handleAbortState(frame, frameNumber)
RingBusState.ELECTING -> handleElectingState(frame, frameNumber)
RingBusState.ELECTED_MONITOR -> handleElectedMonitorState(frame, frameNumber)
}
} catch (e: NullPointerException) {
handleFrameLoss()
}
}
// if I have a message to send or the frame should be captured, do something with it
private fun handleNormalState(frame: NetFrame, frameNumber: Int) {
if (msgQueue.notEmpty() || frame.shouldIintercept(mac)) {
// do something with the received frame
val newFrame = doSomethingWithFrame(frame) ?: frameNumber
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, newFrame.toDouble()))
// if the "do something" processs returns a new frame, mark the old frame as to be destroyed
if (newFrame != frameNumber) {
frame.discardFrame()
}
}
// else, just pass it along
else {
} else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, frameNumber.toDouble()))
}
}
// frame lost due to poor savegame migration or something: send out ABORT signal
catch (e: NullPointerException) {
emitNewFrame(NetFrame.makeAbort(mac))
statusAbort = true
}
}
// else, still watch for the new valid token
else {
// fetch frame from the world
try {
val frame = getFrameByNumber(frameNumber)
// not an Active Monitor
if (activeMonitorStatus < 2) {
private fun handleAbortState(frame: NetFrame, frameNumber: Int) {
if (frame.getFrameType() == "token") {
// unlock myself and pass the token
statusAbort = false
currentState = RingBusState.NORMAL
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, frameNumber.toDouble()))
}
else if (frame.getFrameType() == "abort") {
// lock myself (just in case) and pass the token
statusAbort = true
} else if (frame.getFrameType() == "abort") {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, frameNumber.toDouble()))
}
else {
// discard anything that is not a token or yet another abort
} else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2())
}
}
// am Active Monitor
else {
private fun handleElectingState(frame: NetFrame, frameNumber: Int) {
if (frame.getFrameType() == "ballot") {
if (frame.getBallot() < mac) {
frame.setBallot(mac)
}
if (frame.getSender() == mac && frame.getBallot() == mac) {
currentState = RingBusState.ELECTED_MONITOR
val newFrame = emitNewFrame(NetFrame.makeToken(mac))
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, newFrame.toDouble()))
} else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, frameNumber.toDouble()))
}
} else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, frameNumber.toDouble()))
}
}
private fun handleElectedMonitorState(frame: NetFrame, frameNumber: Int) {
if (frame.getFrameType() == "abort") {
// send out a new token
emitNewFrame(NetFrame.makeToken(mac))
statusAbort = false
}
else {
// discard anything that is not an abort
val newFrame = emitNewFrame(NetFrame.makeToken(mac))
currentState = RingBusState.NORMAL
setWireEmissionAt(portEmit.x, portEmit.y, Vector2(1.0, newFrame.toDouble()))
} else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2())
}
}
private fun handleFrameLoss() {
emitNewFrame(NetFrame.makeAbort(mac))
currentState = RingBusState.ABORT
}
// frame lost due to poor savegame migration or something: discard token
catch (e: NullPointerException) {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2())
}
}
}
else {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2())
}
}
// if a signal is not there
else {
private fun handleNoSignal(time_t: Long) {
setWireEmissionAt(portEmit.x, portEmit.y, Vector2())
// if no-signal for 5 in-game minutes (around 5 real-life seconds)
if (time_t - lastAccessTime > INITIAL_LISTENING_TIMEOUT) {
// initialise the voting process
activeMonitorStatus = 0
currentState = RingBusState.ELECTING
emitNewFrame(NetFrame.makeBallot(mac))
lastAccessTime = time_t
}
}
}
protected fun doSomethingWithFrame(incomingFrame: NetFrame): Int? {
return when (incomingFrame.getFrameType()) {