KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/lua/StateMachine.kt
2024-02-08 20:23:40 +07:00

104 lines
2.5 KiB
Kotlin

package ru.dbotthepony.kstarbound.lua
import org.classdump.luna.LuaRuntimeException
import org.classdump.luna.Table
import org.classdump.luna.runtime.Dispatch
import org.classdump.luna.runtime.ExecutionContext
import org.classdump.luna.runtime.Resumable
import org.classdump.luna.runtime.UnresolvedControlThrowable
import ru.dbotthepony.kommons.util.KOptional
import ru.dbotthepony.kommons.vector.Vector2i
import java.util.function.Supplier
class StateMachine : Resumable {
private val states = ArrayDeque<(ExecutionContext) -> Unit>()
fun add(state: (ExecutionContext) -> Unit): StateMachine {
states.add(state)
return this
}
fun mergeInto(other: StateMachine): StateMachine {
states.addAll(other.states)
return other
}
fun mergeFrom(other: StateMachine): StateMachine {
other.mergeInto(this)
return this
}
override fun resume(context: ExecutionContext, suspendedState: Any) {
run(context, this, this)
}
fun run(context: ExecutionContext): Boolean = run(context, this, this)
fun run(context: ExecutionContext, resumable: Resumable, suspendState: Any): Boolean {
if (states.isEmpty())
return false
while (states.isNotEmpty()) {
val next = states.removeFirst()
try {
next.invoke(context)
} catch (err: UnresolvedControlThrowable) {
throw err.resolve(resumable, suspendState)
}
}
return true
}
fun index(table: Table, vararg indexes: Any): Supplier<Any> {
var value: KOptional<Any> = KOptional.empty()
for (index in indexes) {
add {
if (!value.isPresent) {
value = KOptional.ofNullable(Dispatch.index(it, table, index))
}
}
}
return Supplier {
if (!value.isPresent) {
throw LuaRuntimeException("Unable to locate value in table using following keys: ${indexes.joinToString()}")
}
}
}
fun optionalIndex(table: Table, vararg indexes: Any): Supplier<KOptional<Any>> {
var value: KOptional<Any> = KOptional.empty()
for (index in indexes) {
add {
if (!value.isPresent) {
value = KOptional.ofNullable(Dispatch.index(it, table, index))
}
}
}
return Supplier { value }
}
fun loadVector2i(table: Table): Supplier<Vector2i> {
val x = index(table, 1, "x")
val y = index(table, 2, "y")
var value = KOptional.empty<Vector2i>()
add {
val ix = x.get()
val iy = y.get()
if (ix !is Number) throw LuaRuntimeException("Invalid 'x' value for vector: ${x.get()}")
if (iy !is Number) throw LuaRuntimeException("Invalid 'y' value for vector: ${x.get()}")
value = KOptional(Vector2i(ix.toInt(), iy.toInt()))
}
return Supplier { value.value }
}
}