KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaMessageHandlerComponent.kt

80 lines
1.9 KiB
Kotlin

package ru.dbotthepony.kstarbound.lua
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.util.ActionPacer
import ru.dbotthepony.kstarbound.util.sbIntern
class LuaMessageHandlerComponent(val lua: LuaThread, val nameProvider: () -> String) {
private val handlers = HashMap<String, LuaHandle>()
private fun setHandler(args: LuaThread.ArgStack): Int {
val name = args.nextString()
val peek = args.peek()
if (peek.isNothing) {
handlers.remove(name)?.close()
} else if (peek == LuaType.FUNCTION) {
args.lua.dup(2)
val handle = args.lua.createHandle()
handlers.put(name.sbIntern(), handle)?.close()
}
return 0
}
init {
lua.pushTable()
lua.dup()
lua.storeGlobal("message")
lua.setTableValue("setHandler", ::setHandler)
lua.pop()
}
val logPacer = ActionPacer(1, 5)
fun lookupHandler(name: String): LuaHandle? {
return handlers[name]
}
inline fun handle(message: String, isLocal: Boolean, arguments: LuaThread.() -> Int): JsonElement? {
val handler = lookupHandler(message) ?: return null
val top = lua.stackTop
try {
lua.push(handler)
lua.push(isLocal)
val amountOfArguments = arguments(lua)
check(amountOfArguments >= 0) { "Invalid amount of arguments to pass to Lua handler: $amountOfArguments" }
lua.call(amountOfArguments + 1, 1)
return lua.getJson()
} catch (err: Throwable) {
if (logPacer.consumeAndReturnDeadline() <= 0L)
LOGGER.error("${nameProvider.invoke()}: Exception while handling message '$message'", err)
throw err
} finally {
lua.setTop(top)
}
}
fun handle(message: String, isLocal: Boolean, arguments: JsonArray): JsonElement? {
return handle(message, isLocal) {
ensureExtraCapacity(arguments.size() + 4)
for (argument in arguments) {
push(argument)
}
arguments.size()
}
}
companion object {
val LOGGER = LogManager.getLogger()
}
}