Получение значений из Lua
This commit is contained in:
parent
1fdb8d9a10
commit
61b21a595f
@ -70,6 +70,7 @@ public interface LuaJNR {
|
|||||||
public void lua_pushnumber(@NotNull Pointer luaState, double value);
|
public void lua_pushnumber(@NotNull Pointer luaState, double value);
|
||||||
public void lua_pushinteger(@NotNull Pointer luaState, @LongLong long value);
|
public void lua_pushinteger(@NotNull Pointer luaState, @LongLong long value);
|
||||||
public void lua_pushboolean(@NotNull Pointer luaState, int value);
|
public void lua_pushboolean(@NotNull Pointer luaState, int value);
|
||||||
|
public void lua_pushglobaltable(@NotNull Pointer luaState);
|
||||||
|
|
||||||
// NUL терминированная строка
|
// NUL терминированная строка
|
||||||
public void lua_pushstring(@NotNull Pointer luaState, @NotNull String value);
|
public void lua_pushstring(@NotNull Pointer luaState, @NotNull String value);
|
||||||
@ -84,8 +85,27 @@ public interface LuaJNR {
|
|||||||
public void lua_settable(@NotNull Pointer luaState, int stackIndex);
|
public void lua_settable(@NotNull Pointer luaState, int stackIndex);
|
||||||
public void lua_setglobal(@NotNull Pointer luaState, @NotNull String name);
|
public void lua_setglobal(@NotNull Pointer luaState, @NotNull String name);
|
||||||
|
|
||||||
|
// проверка стека
|
||||||
public int lua_checkstack(@NotNull Pointer luaState, int value);
|
public int lua_checkstack(@NotNull Pointer luaState, int value);
|
||||||
public int lua_absindex(@NotNull Pointer luaState, int value);
|
public int lua_absindex(@NotNull Pointer luaState, int value);
|
||||||
|
public int lua_iscfunction(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_isinteger(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_isnumber(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_isstring(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_isuserdata(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
|
public int lua_toboolean(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_tocfunction(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_toclose(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
|
@LongLong
|
||||||
|
public long lua_tointegerx(@NotNull Pointer luaState, int index, @LongLong long successCode);
|
||||||
|
public double lua_tonumberx(@NotNull Pointer luaState, int index, @LongLong long successCode);
|
||||||
|
|
||||||
|
public int lua_settop(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
|
public int lua_next(@NotNull Pointer luaState, int index);
|
||||||
|
public int lua_type(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the index of the top element in the stack.
|
* Returns the index of the top element in the stack.
|
||||||
|
@ -28,6 +28,19 @@ import java.util.zip.Inflater
|
|||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
if (true) {
|
||||||
|
val lua = LuaState()
|
||||||
|
|
||||||
|
lua.load("return {lemon = 'Bouncy', [4] = 'four', [3] = 'watermelon', h = {h = 'h!'}}")
|
||||||
|
lua.call(numResults = 1)
|
||||||
|
|
||||||
|
val a = lua.popTable()!!
|
||||||
|
|
||||||
|
println("${a["lemon"]} $a")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val starbound = Starbound()
|
val starbound = Starbound()
|
||||||
LOGGER.info("Running LWJGL ${Version.getVersion()}")
|
LOGGER.info("Running LWJGL ${Version.getVersion()}")
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class InternedJsonElementAdapter(val stringInterner: Interner<String>) : TypeAda
|
|||||||
return when (val p = `in`.peek()) {
|
return when (val p = `in`.peek()) {
|
||||||
JsonToken.STRING -> JsonPrimitive(stringInterner.intern(`in`.nextString()))
|
JsonToken.STRING -> JsonPrimitive(stringInterner.intern(`in`.nextString()))
|
||||||
JsonToken.NUMBER -> JsonPrimitive(LazilyParsedNumber(`in`.nextString()))
|
JsonToken.NUMBER -> JsonPrimitive(LazilyParsedNumber(`in`.nextString()))
|
||||||
JsonToken.BOOLEAN -> if (`in`.nextBoolean()) _true else _false
|
JsonToken.BOOLEAN -> if (`in`.nextBoolean()) TRUE else FALSE
|
||||||
JsonToken.NULL -> JsonNull.INSTANCE
|
JsonToken.NULL -> JsonNull.INSTANCE
|
||||||
JsonToken.BEGIN_ARRAY -> {
|
JsonToken.BEGIN_ARRAY -> {
|
||||||
val output = JsonArray()
|
val output = JsonArray()
|
||||||
@ -43,8 +43,10 @@ class InternedJsonElementAdapter(val stringInterner: Interner<String>) : TypeAda
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val _true = JsonPrimitive(true)
|
val TRUE = JsonPrimitive(true)
|
||||||
private val _false = JsonPrimitive(false)
|
val FALSE = JsonPrimitive(false)
|
||||||
|
|
||||||
|
fun of(value: Boolean) = if (value) TRUE else FALSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,9 @@ import com.kenai.jffi.Type
|
|||||||
import jnr.ffi.Memory
|
import jnr.ffi.Memory
|
||||||
import jnr.ffi.NativeType
|
import jnr.ffi.NativeType
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.lwjgl.system.MemoryStack
|
||||||
import org.lwjgl.system.MemoryUtil
|
import org.lwjgl.system.MemoryUtil
|
||||||
|
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
@ -33,12 +35,18 @@ private fun stringToBuffer(str: String): ByteBuffer {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
class LuaState : Closeable {
|
class LuaState : Closeable {
|
||||||
private val pointer = LuaJNR.INSTANCE.luaL_newstate() ?: throw OutOfMemoryError("Unable to allocate new LuaState")
|
private val pointer = LuaJNR.INSTANCE.luaL_newstate() ?: throw OutOfMemoryError("Unable to allocate new LuaState")
|
||||||
private val cleanable: Cleaner.Cleanable
|
private val cleanable: Cleaner.Cleanable
|
||||||
private val sharedStringBufferPtr = MemoryIO.getInstance().allocateMemory(2L shl 16, false)
|
private val sharedStringBufferPtr = MemoryIO.getInstance().allocateMemory(2L shl 16, false)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (sharedStringBufferPtr == 0L) {
|
||||||
|
LuaJNR.INSTANCE.lua_close(pointer)
|
||||||
|
throw OutOfMemoryError("Unable to allocate new string shared buffer")
|
||||||
|
}
|
||||||
|
|
||||||
val pointer = pointer
|
val pointer = pointer
|
||||||
val sharedStringBufferPtr = sharedStringBufferPtr
|
val sharedStringBufferPtr = sharedStringBufferPtr
|
||||||
|
|
||||||
@ -91,7 +99,10 @@ class LuaState : Closeable {
|
|||||||
/**
|
/**
|
||||||
* Converts the acceptable index idx into an equivalent absolute index (that is, one that does not depend on the stack size).
|
* Converts the acceptable index idx into an equivalent absolute index (that is, one that does not depend on the stack size).
|
||||||
*/
|
*/
|
||||||
fun absoluteIndex(index: Int): Int {
|
fun absStackIndex(index: Int): Int {
|
||||||
|
if (index >= 0)
|
||||||
|
return index
|
||||||
|
|
||||||
return LuaJNR.INSTANCE.lua_absindex(pointer, index)
|
return LuaJNR.INSTANCE.lua_absindex(pointer, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,15 +138,15 @@ class LuaState : Closeable {
|
|||||||
val status = LuaJNR.INSTANCE.lua_pcallk(pointer, numArgs, numResults, 0, 0L, 0L)
|
val status = LuaJNR.INSTANCE.lua_pcallk(pointer, numArgs, numResults, 0, 0L, 0L)
|
||||||
|
|
||||||
if (status == LUA_ERRRUN) {
|
if (status == LUA_ERRRUN) {
|
||||||
throw LuaRuntimeException(popString())
|
throw LuaRuntimeException(getString())
|
||||||
}
|
}
|
||||||
|
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
fun popString(index: Int = -1, limit: Long = 2 shl 16): String? {
|
fun getString(stackIndex: Int = -1, limit: Long = 2 shl 16): String? {
|
||||||
val len = Memory.allocateDirect(LuaJNR.RUNTIME, NativeType.SLONGLONG)
|
val len = Memory.allocateDirect(LuaJNR.RUNTIME, NativeType.SLONGLONG)
|
||||||
val p = LuaJNR.INSTANCE.lua_tolstring(pointer, absoluteIndex(index), len) ?: return null
|
val p = LuaJNR.INSTANCE.lua_tolstring(pointer, absStackIndex(stackIndex), len) ?: return null
|
||||||
|
|
||||||
if (len.getLong(0L) == 0L) {
|
if (len.getLong(0L) == 0L) {
|
||||||
return ""
|
return ""
|
||||||
@ -150,6 +161,169 @@ class LuaState : Closeable {
|
|||||||
return readBytes.toString(charset = Charsets.UTF_8)
|
return readBytes.toString(charset = Charsets.UTF_8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isCFunction(stackIndex: Int = -1): Boolean = LuaJNR.INSTANCE.lua_iscfunction(pointer, absStackIndex(stackIndex)) > 0
|
||||||
|
fun isFunction(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.FUNCTION
|
||||||
|
fun isInteger(stackIndex: Int = -1): Boolean = LuaJNR.INSTANCE.lua_isinteger(pointer, absStackIndex(stackIndex)) > 0
|
||||||
|
fun isLightUserdata(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.LIGHTUSERDATA
|
||||||
|
fun isNil(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.NIL
|
||||||
|
fun isNone(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.NONE
|
||||||
|
fun isNoneOrNil(stackIndex: Int = -1): Boolean = typeAt(stackIndex).let { it == LuaType.NIL || it == LuaType.NONE }
|
||||||
|
fun isNumber(stackIndex: Int = -1): Boolean = LuaJNR.INSTANCE.lua_isnumber(pointer, absStackIndex(stackIndex)) > 0
|
||||||
|
fun isString(stackIndex: Int = -1): Boolean = LuaJNR.INSTANCE.lua_isstring(pointer, absStackIndex(stackIndex)) > 0
|
||||||
|
fun isTable(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.TABLE
|
||||||
|
fun isThread(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.THREAD
|
||||||
|
fun isUserdata(stackIndex: Int = -1): Boolean = LuaJNR.INSTANCE.lua_isuserdata(pointer, absStackIndex(stackIndex)) > 0
|
||||||
|
fun isBoolean(stackIndex: Int = -1): Boolean = typeAt(stackIndex) == LuaType.BOOLEAN
|
||||||
|
|
||||||
|
fun getBoolean(stackIndex: Int = -1): Boolean? {
|
||||||
|
if (!isBoolean(stackIndex))
|
||||||
|
return null
|
||||||
|
|
||||||
|
return LuaJNR.INSTANCE.lua_toboolean(pointer, stackIndex) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLong(stackIndex: Int = -1): Long? {
|
||||||
|
if (!isInteger(stackIndex))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val stack = MemoryStack.stackPush()
|
||||||
|
val status = stack.mallocInt(1)
|
||||||
|
val value = LuaJNR.INSTANCE.lua_tointegerx(pointer, stackIndex, MemoryUtil.memAddress(status))
|
||||||
|
val b = status[0] > 0
|
||||||
|
stack.close()
|
||||||
|
|
||||||
|
if (!b)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDouble(stackIndex: Int = -1): Double? {
|
||||||
|
if (!isNumber(stackIndex))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val stack = MemoryStack.stackPush()
|
||||||
|
val status = stack.mallocInt(1)
|
||||||
|
val value = LuaJNR.INSTANCE.lua_tonumberx(pointer, stackIndex, MemoryUtil.memAddress(status))
|
||||||
|
val b = status[0] > 0
|
||||||
|
stack.close()
|
||||||
|
|
||||||
|
if (!b)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun typeAt(stackIndex: Int = -1): LuaType {
|
||||||
|
return when (val value = LuaJNR.INSTANCE.lua_type(pointer, stackIndex)) {
|
||||||
|
LUA_TNONE -> LuaType.NONE
|
||||||
|
LUA_TNIL -> LuaType.NIL
|
||||||
|
LUA_TBOOLEAN -> LuaType.BOOLEAN
|
||||||
|
LUA_TLIGHTUSERDATA -> LuaType.LIGHTUSERDATA
|
||||||
|
LUA_TNUMBER -> LuaType.NUMBER
|
||||||
|
LUA_TSTRING -> LuaType.STRING
|
||||||
|
LUA_TTABLE -> LuaType.TABLE
|
||||||
|
LUA_TFUNCTION -> LuaType.FUNCTION
|
||||||
|
LUA_TUSERDATA -> LuaType.USERDATA
|
||||||
|
LUA_TTHREAD -> LuaType.THREAD
|
||||||
|
LUA_NUMTYPES -> LuaType.UMTYPES
|
||||||
|
else -> throw RuntimeException("Invalid Lua type: $value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getValue(stackIndex: Int = -1): JsonElement? {
|
||||||
|
val abs = absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (abs == 0)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return when (typeAt(abs)) {
|
||||||
|
LuaType.NONE -> null
|
||||||
|
LuaType.NIL -> JsonNull.INSTANCE
|
||||||
|
LuaType.BOOLEAN -> InternedJsonElementAdapter.of(getBoolean(abs)!!)
|
||||||
|
LuaType.LIGHTUSERDATA -> null
|
||||||
|
LuaType.NUMBER -> JsonPrimitive(if (isInteger(abs)) getLong(abs)!! else getDouble(abs)!!)
|
||||||
|
LuaType.STRING -> JsonPrimitive(getString(abs))
|
||||||
|
LuaType.TABLE -> getTable(abs)!!
|
||||||
|
LuaType.FUNCTION -> null
|
||||||
|
LuaType.USERDATA -> null
|
||||||
|
LuaType.THREAD -> null
|
||||||
|
LuaType.UMTYPES -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTable(stackIndex: Int = -1): JsonObject? {
|
||||||
|
val abs = absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val pairs = JsonObject()
|
||||||
|
push()
|
||||||
|
|
||||||
|
while (LuaJNR.INSTANCE.lua_next(pointer, abs) != 0) {
|
||||||
|
val key = getValue(abs + 1)
|
||||||
|
val value = getValue(abs + 2)
|
||||||
|
|
||||||
|
if (key is JsonPrimitive && value != null) {
|
||||||
|
pairs.add(key.asString, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
return pairs
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popBoolean(): Boolean? {
|
||||||
|
try {
|
||||||
|
return getBoolean()
|
||||||
|
} finally {
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popLong(): Long? {
|
||||||
|
try {
|
||||||
|
return getLong()
|
||||||
|
} finally {
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popDouble(): Double? {
|
||||||
|
try {
|
||||||
|
return getDouble()
|
||||||
|
} finally {
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popValue(): JsonElement? {
|
||||||
|
try {
|
||||||
|
return getValue()
|
||||||
|
} finally {
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popTable(): JsonObject? {
|
||||||
|
try {
|
||||||
|
return getTable()
|
||||||
|
} finally {
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pop(amount: Int = 1): Int {
|
||||||
|
if (amount == 0) return 0
|
||||||
|
check(amount > 0) { "Invalid amount to pop: $amount" }
|
||||||
|
val old = stackTop
|
||||||
|
val new = (old - amount).coerceAtLeast(0)
|
||||||
|
LuaJNR.INSTANCE.lua_settop(pointer, new)
|
||||||
|
return old - new
|
||||||
|
}
|
||||||
|
|
||||||
fun storeGlobal(name: String) {
|
fun storeGlobal(name: String) {
|
||||||
LuaJNR.INSTANCE.lua_setglobal(pointer, name)
|
LuaJNR.INSTANCE.lua_setglobal(pointer, name)
|
||||||
}
|
}
|
||||||
@ -287,5 +461,20 @@ class LuaState : Closeable {
|
|||||||
thread.priority = 1
|
thread.priority = 1
|
||||||
thread
|
thread
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const val LUA_TNONE = -1
|
||||||
|
|
||||||
|
const val LUA_TNIL = 0
|
||||||
|
const val LUA_TBOOLEAN = 1
|
||||||
|
const val LUA_TLIGHTUSERDATA = 2
|
||||||
|
const val LUA_TNUMBER = 3
|
||||||
|
const val LUA_TSTRING = 4
|
||||||
|
const val LUA_TTABLE = 5
|
||||||
|
const val LUA_TFUNCTION = 6
|
||||||
|
const val LUA_TUSERDATA = 7
|
||||||
|
const val LUA_TTHREAD = 8
|
||||||
|
|
||||||
|
const val LUA_NUMTYPES = 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaType.kt
Normal file
15
src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaType.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.lua
|
||||||
|
|
||||||
|
enum class LuaType {
|
||||||
|
NONE,
|
||||||
|
NIL,
|
||||||
|
BOOLEAN,
|
||||||
|
LIGHTUSERDATA,
|
||||||
|
NUMBER,
|
||||||
|
STRING,
|
||||||
|
TABLE,
|
||||||
|
FUNCTION,
|
||||||
|
USERDATA,
|
||||||
|
THREAD,
|
||||||
|
UMTYPES;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user