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() 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() } }