62 lines
2.0 KiB
Kotlin
62 lines
2.0 KiB
Kotlin
package ru.dbotthepony.kstarbound.lua
|
|
|
|
import com.google.gson.JsonArray
|
|
import com.google.gson.JsonElement
|
|
import com.google.gson.JsonNull
|
|
import org.apache.logging.log4j.LogManager
|
|
import org.classdump.luna.ByteString
|
|
import org.classdump.luna.exec.CallPausedException
|
|
import org.classdump.luna.runtime.LuaFunction
|
|
import ru.dbotthepony.kommons.util.Either
|
|
import ru.dbotthepony.kstarbound.util.ActionPacer
|
|
import ru.dbotthepony.kstarbound.util.sbIntern
|
|
import ru.dbotthepony.kstarbound.world.World
|
|
|
|
class LuaMessageHandlerComponent(val lua: LuaEnvironment, val nameProvider: () -> String) {
|
|
private val handlers = HashMap<String, LuaFunction<*, *, *, *, *>>()
|
|
|
|
init {
|
|
val table = lua.newTable()
|
|
lua.globals["message"] = table
|
|
|
|
table["setHandler"] = luaFunction { message: ByteString, handler: LuaFunction<*, *, *, *, *>? ->
|
|
if (handler == null) {
|
|
handlers.remove(message.decode())
|
|
} else {
|
|
handlers[message.decode().sbIntern()] = handler
|
|
}
|
|
}
|
|
}
|
|
|
|
private val logPacer = ActionPacer(1, 5)
|
|
|
|
fun handle(message: String, isLocal: Boolean, arguments: JsonArray): JsonElement {
|
|
val handler = handlers[message] ?: throw World.MessageCallException("No registered handler for $message")
|
|
|
|
try {
|
|
val unpack = arguments.map { lua.from(it) }.toTypedArray()
|
|
val result = lua.executor.call(lua, handler, isLocal, *unpack)
|
|
|
|
if (result.isEmpty()) {
|
|
return JsonNull.INSTANCE
|
|
} else {
|
|
return toJsonFromLua(result[0])
|
|
}
|
|
} catch (err: CallPausedException) {
|
|
if (logPacer.consumeAndReturnDeadline() <= 0L)
|
|
LOGGER.error("${nameProvider.invoke()}: '$message' handler attempted to yield across C boundary", err)
|
|
|
|
throw World.MessageCallException("$message handler attempted to yield across C boundary")
|
|
} catch (err: Throwable) {
|
|
if (logPacer.consumeAndReturnDeadline() <= 0L)
|
|
LOGGER.error("${nameProvider.invoke()}: Exception while handling message '$message'", err)
|
|
|
|
throw err
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private val LOGGER = LogManager.getLogger()
|
|
}
|
|
}
|