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 { var value: KOptional = 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> { var value: KOptional = 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 { val x = index(table, 1, "x") val y = index(table, 2, "y") var value = KOptional.empty() 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 } } }