More native Lua work
This commit is contained in:
parent
fb1aea8803
commit
dd990becf4
@ -4,6 +4,7 @@ import com.kenai.jffi.Closure;
|
|||||||
import jnr.ffi.LibraryLoader;
|
import jnr.ffi.LibraryLoader;
|
||||||
import jnr.ffi.Pointer;
|
import jnr.ffi.Pointer;
|
||||||
import jnr.ffi.Runtime;
|
import jnr.ffi.Runtime;
|
||||||
|
import jnr.ffi.annotations.IgnoreError;
|
||||||
import jnr.ffi.annotations.LongLong;
|
import jnr.ffi.annotations.LongLong;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -28,8 +29,11 @@ public interface LuaJNR {
|
|||||||
* LUA_ERRERR: error while running the message handler.
|
* LUA_ERRERR: error while running the message handler.
|
||||||
* LUA_ERRGCMM: error while running a __gc metamethod. For such errors, Lua does not call the message handler (as this kind of error typically has no relation with the function being called).
|
* LUA_ERRGCMM: error while running a __gc metamethod. For such errors, Lua does not call the message handler (as this kind of error typically has no relation with the function being called).
|
||||||
*/
|
*/
|
||||||
|
@IgnoreError
|
||||||
public int lua_pcallk(@NotNull Pointer luaState, int numArgs, int numResults, int msgh, @LongLong long ctx, @LongLong long callback);
|
public int lua_pcallk(@NotNull Pointer luaState, int numArgs, int numResults, int msgh, @LongLong long ctx, @LongLong long callback);
|
||||||
|
@IgnoreError
|
||||||
public int lua_callk(@NotNull Pointer luaState, int numArgs, int numResults, @LongLong long ctx, @LongLong long callback);
|
public int lua_callk(@NotNull Pointer luaState, int numArgs, int numResults, @LongLong long ctx, @LongLong long callback);
|
||||||
|
@IgnoreError
|
||||||
public long lua_atpanic(@NotNull Pointer luaState, @LongLong long fn);
|
public long lua_atpanic(@NotNull Pointer luaState, @LongLong long fn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,10 +42,14 @@ public interface LuaJNR {
|
|||||||
* There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object.
|
* There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object.
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@IgnoreError
|
||||||
public Pointer lua_newthread(@NotNull Pointer luaState);
|
public Pointer lua_newthread(@NotNull Pointer luaState);
|
||||||
|
|
||||||
|
@IgnoreError
|
||||||
public int luaL_ref(@NotNull Pointer luaState, int stackIndex);
|
public int luaL_ref(@NotNull Pointer luaState, int stackIndex);
|
||||||
|
@IgnoreError
|
||||||
public void lua_copy(@NotNull Pointer luaState, int fromIndex, int toIndex);
|
public void lua_copy(@NotNull Pointer luaState, int fromIndex, int toIndex);
|
||||||
|
@IgnoreError
|
||||||
public int lua_xmove(@NotNull Pointer from, @NotNull Pointer to, int amount);
|
public int lua_xmove(@NotNull Pointer from, @NotNull Pointer to, int amount);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -49,30 +57,44 @@ public interface LuaJNR {
|
|||||||
public void lua_close(@NotNull Pointer luaState);
|
public void lua_close(@NotNull Pointer luaState);
|
||||||
|
|
||||||
// Стандартные библиотеки
|
// Стандартные библиотеки
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_base(@NotNull Pointer luaState);
|
public void luaopen_base(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_package(@NotNull Pointer luaState);
|
public void luaopen_package(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_coroutine(@NotNull Pointer luaState);
|
public void luaopen_coroutine(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_table(@NotNull Pointer luaState);
|
public void luaopen_table(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_io(@NotNull Pointer luaState);
|
public void luaopen_io(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_os(@NotNull Pointer luaState);
|
public void luaopen_os(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_string(@NotNull Pointer luaState);
|
public void luaopen_string(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_math(@NotNull Pointer luaState);
|
public void luaopen_math(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_utf8(@NotNull Pointer luaState);
|
public void luaopen_utf8(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void luaopen_debug(@NotNull Pointer luaState);
|
public void luaopen_debug(@NotNull Pointer luaState);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@IgnoreError
|
||||||
public Pointer lua_tolstring(@NotNull Pointer luaState, int index, @LongLong long statusCodeReturnPtr);
|
public Pointer lua_tolstring(@NotNull Pointer luaState, int index, @LongLong long statusCodeReturnPtr);
|
||||||
|
|
||||||
|
@IgnoreError
|
||||||
public int lua_load(@NotNull Pointer luaState, @LongLong long reader, long userData, @NotNull String chunkName, @NotNull String mode);
|
public int lua_load(@NotNull Pointer luaState, @LongLong long reader, long userData, @NotNull String chunkName, @NotNull String mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pops a table from the stack and sets it as the new metatable for the value at the given index.
|
* Pops a table from the stack and sets it as the new metatable for the value at the given index.
|
||||||
*/
|
*/
|
||||||
|
@IgnoreError
|
||||||
public void lua_setmetatable(@NotNull Pointer luaState, int stackIndex);
|
public void lua_setmetatable(@NotNull Pointer luaState, int stackIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes onto the stack the field e from the metatable of the object at index obj and returns the type of the pushed value. If the object does not have a metatable, or if the metatable does not have this field, pushes nothing and returns LUA_TNIL.
|
* Pushes onto the stack the field e from the metatable of the object at index obj and returns the type of the pushed value. If the object does not have a metatable, or if the metatable does not have this field, pushes nothing and returns LUA_TNIL.
|
||||||
*/
|
*/
|
||||||
|
@IgnoreError
|
||||||
public int luaL_getmetafield(@NotNull Pointer luaState, int stackIndex, @LongLong long stringPtr);
|
public int luaL_getmetafield(@NotNull Pointer luaState, int stackIndex, @LongLong long stringPtr);
|
||||||
|
|
||||||
public interface lua_CFunction extends Closure {
|
public interface lua_CFunction extends Closure {
|
||||||
@ -104,53 +126,81 @@ public interface LuaJNR {
|
|||||||
|
|
||||||
// Операции над стаком
|
// Операции над стаком
|
||||||
// загрузка значений из Java на стек
|
// загрузка значений из Java на стек
|
||||||
|
@IgnoreError
|
||||||
public void lua_createtable(@NotNull Pointer luaState, int arraySize, int hashSize);
|
public void lua_createtable(@NotNull Pointer luaState, int arraySize, int hashSize);
|
||||||
|
@IgnoreError
|
||||||
public void lua_pushnil(@NotNull Pointer luaState);
|
public void lua_pushnil(@NotNull Pointer luaState);
|
||||||
|
@IgnoreError
|
||||||
public void lua_pushnumber(@NotNull Pointer luaState, double value);
|
public void lua_pushnumber(@NotNull Pointer luaState, double value);
|
||||||
|
@IgnoreError
|
||||||
public void lua_pushinteger(@NotNull Pointer luaState, @LongLong long value);
|
public void lua_pushinteger(@NotNull Pointer luaState, @LongLong long value);
|
||||||
|
@IgnoreError
|
||||||
public void lua_pushboolean(@NotNull Pointer luaState, int value);
|
public void lua_pushboolean(@NotNull Pointer luaState, int value);
|
||||||
|
@IgnoreError
|
||||||
public void lua_pushglobaltable(@NotNull Pointer luaState);
|
public void lua_pushglobaltable(@NotNull Pointer luaState);
|
||||||
|
|
||||||
// NUL терминированная строка
|
// NUL терминированная строка
|
||||||
|
@IgnoreError
|
||||||
public void lua_pushstring(@NotNull Pointer luaState, @NotNull String value);
|
public void lua_pushstring(@NotNull Pointer luaState, @NotNull String value);
|
||||||
|
|
||||||
// двоичная строка
|
// двоичная строка
|
||||||
|
@IgnoreError
|
||||||
public long lua_pushlstring(@NotNull Pointer luaState, @LongLong long stringPointer, @LongLong long length);
|
public long lua_pushlstring(@NotNull Pointer luaState, @LongLong long stringPointer, @LongLong long length);
|
||||||
|
|
||||||
// Загрузка Lua значений на стек
|
// Загрузка Lua значений на стек
|
||||||
|
@IgnoreError
|
||||||
public int lua_getglobal(@NotNull Pointer luaState, @NotNull String name);
|
public int lua_getglobal(@NotNull Pointer luaState, @NotNull String name);
|
||||||
|
|
||||||
// запись значений со стека
|
// запись значений со стека
|
||||||
|
@IgnoreError
|
||||||
public void lua_settable(@NotNull Pointer luaState, int stackIndex);
|
public void lua_settable(@NotNull Pointer luaState, int stackIndex);
|
||||||
|
@IgnoreError
|
||||||
public void lua_setglobal(@NotNull Pointer luaState, @NotNull String name);
|
public void lua_setglobal(@NotNull Pointer luaState, @NotNull String name);
|
||||||
|
|
||||||
// проверка стека
|
// проверка стека
|
||||||
|
@IgnoreError
|
||||||
public int lua_checkstack(@NotNull Pointer luaState, int value);
|
public int lua_checkstack(@NotNull Pointer luaState, int value);
|
||||||
|
@IgnoreError
|
||||||
public int lua_absindex(@NotNull Pointer luaState, int value);
|
public int lua_absindex(@NotNull Pointer luaState, int value);
|
||||||
|
@IgnoreError
|
||||||
public int lua_iscfunction(@NotNull Pointer luaState, int index);
|
public int lua_iscfunction(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_isinteger(@NotNull Pointer luaState, int index);
|
public int lua_isinteger(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_isnumber(@NotNull Pointer luaState, int index);
|
public int lua_isnumber(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_isstring(@NotNull Pointer luaState, int index);
|
public int lua_isstring(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_isuserdata(@NotNull Pointer luaState, int index);
|
public int lua_isuserdata(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
|
@IgnoreError
|
||||||
public int lua_toboolean(@NotNull Pointer luaState, int index);
|
public int lua_toboolean(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_tocfunction(@NotNull Pointer luaState, int index);
|
public int lua_tocfunction(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_toclose(@NotNull Pointer luaState, int index);
|
public int lua_toclose(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_gettable(@NotNull Pointer luaState, int index);
|
public int lua_gettable(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
@LongLong
|
@LongLong
|
||||||
|
@IgnoreError
|
||||||
public long lua_tointegerx(@NotNull Pointer luaState, int index, @LongLong long successCode);
|
public long lua_tointegerx(@NotNull Pointer luaState, int index, @LongLong long successCode);
|
||||||
|
@IgnoreError
|
||||||
public double lua_tonumberx(@NotNull Pointer luaState, int index, @LongLong long successCode);
|
public double lua_tonumberx(@NotNull Pointer luaState, int index, @LongLong long successCode);
|
||||||
|
|
||||||
|
@IgnoreError
|
||||||
public int lua_settop(@NotNull Pointer luaState, int index);
|
public int lua_settop(@NotNull Pointer luaState, int index);
|
||||||
|
|
||||||
|
@IgnoreError
|
||||||
public int lua_next(@NotNull Pointer luaState, int index);
|
public int lua_next(@NotNull Pointer luaState, int index);
|
||||||
|
@IgnoreError
|
||||||
public int lua_type(@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.
|
||||||
* Because indices start at 1, this result is equal to the number of elements in the stack; in particular, 0 means an empty stack.
|
* Because indices start at 1, this result is equal to the number of elements in the stack; in particular, 0 means an empty stack.
|
||||||
*/
|
*/
|
||||||
|
@IgnoreError
|
||||||
public int lua_gettop(@NotNull Pointer luaState);
|
public int lua_gettop(@NotNull Pointer luaState);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -83,6 +83,7 @@ import ru.dbotthepony.kstarbound.util.ScheduledCoroutineExecutor
|
|||||||
import ru.dbotthepony.kstarbound.util.random.AbstractPerlinNoise
|
import ru.dbotthepony.kstarbound.util.random.AbstractPerlinNoise
|
||||||
import ru.dbotthepony.kstarbound.util.random.nextRange
|
import ru.dbotthepony.kstarbound.util.random.nextRange
|
||||||
import ru.dbotthepony.kstarbound.util.random.random
|
import ru.dbotthepony.kstarbound.util.random.random
|
||||||
|
import ru.dbotthepony.kstarbound.util.supplyAsync
|
||||||
import ru.dbotthepony.kstarbound.world.SystemWorldLocation
|
import ru.dbotthepony.kstarbound.world.SystemWorldLocation
|
||||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||||
import java.io.*
|
import java.io.*
|
||||||
@ -99,6 +100,7 @@ import java.util.concurrent.ForkJoinWorkerThread
|
|||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
import java.util.function.Supplier
|
||||||
import java.util.random.RandomGenerator
|
import java.util.random.RandomGenerator
|
||||||
import kotlin.NoSuchElementException
|
import kotlin.NoSuchElementException
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
@ -116,6 +118,12 @@ object Starbound : BlockableEventLoop("Universe Thread"), Scheduler, ISBFileLoca
|
|||||||
const val DEDUP_CELL_STATES = true
|
const val DEDUP_CELL_STATES = true
|
||||||
const val USE_CAFFEINE_INTERNER = false
|
const val USE_CAFFEINE_INTERNER = false
|
||||||
const val USE_INTERNER = true
|
const val USE_INTERNER = true
|
||||||
|
|
||||||
|
// at most this amount of dynamically loaded json assets will be kept in memory
|
||||||
|
const val JSON_CACHE_SIZE = 16_000L
|
||||||
|
// at most this amount of script sources will be kept in memory
|
||||||
|
const val LUA_SCRIPT_CACHE_SIZE = 4_000L
|
||||||
|
|
||||||
// enables a fuckton of runtime checks for data which doesn't make much sense
|
// enables a fuckton of runtime checks for data which doesn't make much sense
|
||||||
// especially for data which will explode legacy client
|
// especially for data which will explode legacy client
|
||||||
// also changes some constants
|
// also changes some constants
|
||||||
@ -288,8 +296,25 @@ object Starbound : BlockableEventLoop("Universe Thread"), Scheduler, ISBFileLoca
|
|||||||
return scriptCache.computeIfAbsent(path, ::loadScript0)
|
return scriptCache.computeIfAbsent(path, ::loadScript0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compileScriptChunk(name: String, chunk: String): ChunkFactory {
|
private val luaScriptCache = Caffeine.newBuilder()
|
||||||
return loader.compileTextChunk(name, chunk)
|
.maximumSize(LUA_SCRIPT_CACHE_SIZE)
|
||||||
|
.expireAfterAccess(Duration.ofHours(1L))
|
||||||
|
.scheduler(this)
|
||||||
|
.executor(EXECUTOR)
|
||||||
|
.buildAsync(AsyncCacheLoader<String, KOptional<String>> { key, executor ->
|
||||||
|
IO_EXECUTOR.supplyAsync {
|
||||||
|
val file = locate(key)
|
||||||
|
|
||||||
|
if (!file.isFile) {
|
||||||
|
KOptional()
|
||||||
|
} else {
|
||||||
|
KOptional(file.readToString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
fun readLuaScript(path: String): CompletableFuture<String> {
|
||||||
|
return luaScriptCache[path].thenApply { it.orThrow { NoSuchElementException("No such file $path") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
val ELEMENTS_ADAPTER = InternedJsonElementAdapter(STRINGS)
|
val ELEMENTS_ADAPTER = InternedJsonElementAdapter(STRINGS)
|
||||||
@ -447,7 +472,7 @@ object Starbound : BlockableEventLoop("Universe Thread"), Scheduler, ISBFileLoca
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val jsonAssetsCache = Caffeine.newBuilder()
|
private val jsonAssetsCache = Caffeine.newBuilder()
|
||||||
.maximumSize(4096L)
|
.maximumSize(JSON_CACHE_SIZE)
|
||||||
.expireAfterAccess(Duration.ofMinutes(5L))
|
.expireAfterAccess(Duration.ofMinutes(5L))
|
||||||
.scheduler(this)
|
.scheduler(this)
|
||||||
.executor(EXECUTOR)
|
.executor(EXECUTOR)
|
||||||
|
@ -457,6 +457,29 @@ fun TableFactory.tableFrom(collection: Collection<Any?>): Table {
|
|||||||
return alloc
|
return alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: error reporting when argument was provided, but it is malformed
|
||||||
|
// currently, invalid data gets silently discarded, and treated as "no value" aka null
|
||||||
|
fun LuaThread.getPoly(stackIndex: Int = -1): Poly? {
|
||||||
|
return readTableValues(stackIndex) {
|
||||||
|
getVector2d(it) ?: throw IllegalArgumentException("Provided poly table contains invalid points")
|
||||||
|
}?.let { Poly(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getPoly(position: Int = this.position++): Poly {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
throw IllegalArgumentException("Bad argument #$position: Poly expected, got nil")
|
||||||
|
|
||||||
|
return lua.getPoly(position)
|
||||||
|
?: throw IllegalArgumentException("Bad argument #$position: Poly expected, got ${lua.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getPolyOrNull(position: Int = this.position++): Poly? {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return lua.getPoly(position)
|
||||||
|
}
|
||||||
|
|
||||||
fun LuaThread.getLine2d(stackIndex: Int = -1): Line2d? {
|
fun LuaThread.getLine2d(stackIndex: Int = -1): Line2d? {
|
||||||
val abs = this.absStackIndex(stackIndex)
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
@ -485,7 +508,14 @@ fun LuaThread.ArgStack.getLine2d(position: Int = this.position++): Line2d {
|
|||||||
throw IllegalArgumentException("Bad argument #$position: Line2d expected, got nil")
|
throw IllegalArgumentException("Bad argument #$position: Line2d expected, got nil")
|
||||||
|
|
||||||
return lua.getLine2d(position)
|
return lua.getLine2d(position)
|
||||||
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: Line2d expected, got ${lua.typeAt(position)}")
|
?: throw IllegalArgumentException("Bad argument #$position: Line2d expected, got ${lua.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getLine2dOrNull(position: Int = this.position++): Line2d? {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return lua.getLine2d(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LuaThread.getVector2d(stackIndex: Int = -1): Vector2d? {
|
fun LuaThread.getVector2d(stackIndex: Int = -1): Vector2d? {
|
||||||
@ -516,7 +546,7 @@ fun LuaThread.ArgStack.getVector2d(position: Int = this.position++): Vector2d {
|
|||||||
throw IllegalArgumentException("Bad argument #$position: Vector2d expected, got nil")
|
throw IllegalArgumentException("Bad argument #$position: Vector2d expected, got nil")
|
||||||
|
|
||||||
return lua.getVector2d(position)
|
return lua.getVector2d(position)
|
||||||
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: Vector2d expected, got ${lua.typeAt(position)}")
|
?: throw IllegalArgumentException("Bad argument #$position: Vector2d expected, got ${lua.typeAt(position)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LuaThread.getVector2i(stackIndex: Int = -1): Vector2i? {
|
fun LuaThread.getVector2i(stackIndex: Int = -1): Vector2i? {
|
||||||
@ -547,7 +577,171 @@ fun LuaThread.ArgStack.getVector2i(position: Int = this.position++): Vector2i {
|
|||||||
throw IllegalArgumentException("Bad argument #$position: Vector2i expected, got nil")
|
throw IllegalArgumentException("Bad argument #$position: Vector2i expected, got nil")
|
||||||
|
|
||||||
return lua.getVector2i(position)
|
return lua.getVector2i(position)
|
||||||
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: Vector2i expected, got ${lua.typeAt(position)}")
|
?: throw IllegalArgumentException("Bad argument #$position: Vector2i expected, got ${lua.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getVector2iOrNull(position: Int = this.position++): Vector2i? {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
return null
|
||||||
|
|
||||||
|
lua.typeAt(position).isTableOrNothing { "Bad argument #$position: optional Vector2i expected, got nil" }
|
||||||
|
|
||||||
|
return lua.getVector2i(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.getColor(stackIndex: Int = -1): RGBAColor? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
push(1)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val x = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
x ?: return null
|
||||||
|
|
||||||
|
push(2)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val y = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
y ?: return null
|
||||||
|
|
||||||
|
push(3)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val z = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
z ?: return null
|
||||||
|
|
||||||
|
push(4)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val w = getLong(abs + 1) ?: 255L
|
||||||
|
pop()
|
||||||
|
|
||||||
|
return RGBAColor(x.toInt(), y.toInt(), z.toInt(), w.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getColor(position: Int = this.position++): RGBAColor {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
throw IllegalArgumentException("Bad argument #$position: RGBAColor expected, got nil")
|
||||||
|
|
||||||
|
return lua.getColor(position)
|
||||||
|
?: throw IllegalArgumentException("Bad argument #$position: RGBAColor expected, got ${lua.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getColorOrNull(position: Int = this.position++): RGBAColor? {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return lua.getColor(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.getAABB(stackIndex: Int = -1): AABB? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
push(1)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val x = getDouble(abs + 1)
|
||||||
|
pop()
|
||||||
|
x ?: return null
|
||||||
|
|
||||||
|
push(2)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val y = getDouble(abs + 1)
|
||||||
|
pop()
|
||||||
|
y ?: return null
|
||||||
|
|
||||||
|
push(3)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val z = getDouble(abs + 1)
|
||||||
|
pop()
|
||||||
|
z ?: return null
|
||||||
|
|
||||||
|
push(4)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val w = getDouble(abs + 1)
|
||||||
|
pop()
|
||||||
|
w ?: return null
|
||||||
|
|
||||||
|
return AABB(Vector2d(x, y), Vector2d(z, w))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getAABB(position: Int = this.position++): AABB {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
throw IllegalArgumentException("Bad argument #$position: RGBAColor expected, got nil")
|
||||||
|
|
||||||
|
return lua.getAABB(position)
|
||||||
|
?: throw IllegalArgumentException("Bad argument #$position: RGBAColor expected, got ${lua.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getAABBOrNull(position: Int = this.position++): AABB? {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return lua.getAABB(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.getAABBi(stackIndex: Int = -1): AABBi? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
push(1)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val x = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
x ?: return null
|
||||||
|
|
||||||
|
push(2)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val y = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
y ?: return null
|
||||||
|
|
||||||
|
push(3)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val z = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
z ?: return null
|
||||||
|
|
||||||
|
push(4)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val w = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
w ?: return null
|
||||||
|
|
||||||
|
return AABBi(Vector2i(x.toInt(), y.toInt()), Vector2i(z.toInt(), w.toInt()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getAABBi(position: Int = this.position++): AABBi {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
throw IllegalArgumentException("Bad argument #$position: RGBAColor expected, got nil")
|
||||||
|
|
||||||
|
return lua.getAABBi(position)
|
||||||
|
?: throw IllegalArgumentException("Bad argument #$position: RGBAColor expected, got ${lua.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun LuaThread.ArgStack.getAABBiOrNull(position: Int = this.position++): AABBi? {
|
||||||
|
if (position !in 1 ..this.top)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return lua.getAABBi(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LuaThread.push(value: IStruct4i) {
|
fun LuaThread.push(value: IStruct4i) {
|
||||||
|
@ -24,7 +24,6 @@ import java.lang.ref.Cleaner
|
|||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import kotlin.properties.Delegates
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@ -452,6 +451,95 @@ class LuaThread private constructor(
|
|||||||
return pairs
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun iterateTable(stackIndex: Int = -1, keyVisitor: LuaThread.(stackIndex: Int) -> Unit, valueVisitor: LuaThread.(stackIndex: Int) -> Unit) {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return
|
||||||
|
|
||||||
|
this.push()
|
||||||
|
val top = this.stackTop
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
|
keyVisitor(this, abs + 1)
|
||||||
|
valueVisitor(this, abs + 2)
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> readTableKeys(stackIndex: Int = -1, keyVisitor: LuaThread.(stackIndex: Int) -> T): MutableList<T>? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val values = ArrayList<T>()
|
||||||
|
|
||||||
|
this.push()
|
||||||
|
val top = this.stackTop
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
|
values.add(keyVisitor(this, abs + 1))
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> readTableValues(stackIndex: Int = -1, valueVisitor: LuaThread.(stackIndex: Int) -> T): MutableList<T>? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val values = ArrayList<T>()
|
||||||
|
|
||||||
|
this.push()
|
||||||
|
val top = this.stackTop
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
|
values.add(valueVisitor(this, abs + 2))
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K, V> readTable(stackIndex: Int = -1, keyVisitor: LuaThread.(stackIndex: Int) -> K, valueVisitor: LuaThread.(stackIndex: Int) -> V): MutableList<Pair<K, V>>? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val values = ArrayList<Pair<K, V>>()
|
||||||
|
|
||||||
|
this.push()
|
||||||
|
val top = this.stackTop
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
|
values.add(keyVisitor(this, abs + 1) to valueVisitor(this, abs + 2))
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
fun getTableValue(stackIndex: Int = -2, limit: Long = DEFAULT_STRING_LIMIT): JsonElement? {
|
fun getTableValue(stackIndex: Int = -2, limit: Long = DEFAULT_STRING_LIMIT): JsonElement? {
|
||||||
this.loadTableValue(stackIndex)
|
this.loadTableValue(stackIndex)
|
||||||
return this.getJson(limit = limit)
|
return this.getJson(limit = limit)
|
||||||
|
@ -13,18 +13,143 @@ import ru.dbotthepony.kstarbound.lua.LuaThread.Companion.LUA_TTHREAD
|
|||||||
import ru.dbotthepony.kstarbound.lua.LuaThread.Companion.LUA_TUSERDATA
|
import ru.dbotthepony.kstarbound.lua.LuaThread.Companion.LUA_TUSERDATA
|
||||||
|
|
||||||
enum class LuaType {
|
enum class LuaType {
|
||||||
NONE,
|
NONE {
|
||||||
NIL,
|
override val isNothing: Boolean
|
||||||
BOOLEAN,
|
get() = true
|
||||||
LIGHTUSERDATA,
|
},
|
||||||
NUMBER,
|
NIL {
|
||||||
STRING,
|
override val isNothing: Boolean
|
||||||
TABLE,
|
get() = true
|
||||||
|
},
|
||||||
|
BOOLEAN {
|
||||||
|
override val isBoolean: Boolean
|
||||||
|
get() = true
|
||||||
|
},
|
||||||
|
LIGHTUSERDATA ,
|
||||||
|
NUMBER {
|
||||||
|
override val isNumber: Boolean
|
||||||
|
get() = true
|
||||||
|
},
|
||||||
|
STRING {
|
||||||
|
override val isString: Boolean
|
||||||
|
get() = true
|
||||||
|
},
|
||||||
|
TABLE {
|
||||||
|
override val isTable: Boolean
|
||||||
|
get() = true
|
||||||
|
},
|
||||||
FUNCTION,
|
FUNCTION,
|
||||||
USERDATA,
|
USERDATA,
|
||||||
THREAD,
|
THREAD {
|
||||||
|
override val isThread: Boolean
|
||||||
|
get() = true
|
||||||
|
},
|
||||||
UMTYPES;
|
UMTYPES;
|
||||||
|
|
||||||
|
open val isNothing: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
open val isBoolean: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
open val isTable: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
open val isNumber: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
open val isString: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
open val isThread: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
val isBooleanOrNothing: Boolean get() = isBoolean || isNothing
|
||||||
|
val isTableOrNothing: Boolean get() = isTable || isNothing
|
||||||
|
val isNumberOrNothing: Boolean get() = isNumber || isNothing
|
||||||
|
val isStringOrNothing: Boolean get() = isString || isNothing
|
||||||
|
val isThreadOrNothing: Boolean get() = isThread || isNothing
|
||||||
|
|
||||||
|
inline fun isBooleanOrNothing(formatter: LuaType.() -> String) {
|
||||||
|
if (!isBooleanOrNothing) {
|
||||||
|
throw IllegalArgumentException(formatter.invoke(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun isTableOrNothing(formatter: LuaType.() -> String) {
|
||||||
|
if (!isTableOrNothing) {
|
||||||
|
throw IllegalArgumentException(formatter.invoke(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun isNumberOrNothing(formatter: LuaType.() -> String) {
|
||||||
|
if (!isNumberOrNothing) {
|
||||||
|
throw IllegalArgumentException(formatter.invoke(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun isStringOrNothing(formatter: LuaType.() -> String) {
|
||||||
|
if (!isStringOrNothing) {
|
||||||
|
throw IllegalArgumentException(formatter.invoke(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun isThreadOrNothing(formatter: LuaType.() -> String) {
|
||||||
|
if (!isThreadOrNothing) {
|
||||||
|
throw IllegalArgumentException(formatter.invoke(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isBooleanOrNothing(expected: String, argumentNumber: Int): Boolean {
|
||||||
|
if (argumentNumber == -1) {
|
||||||
|
return isBooleanOrNothing
|
||||||
|
} else if (!isBooleanOrNothing) {
|
||||||
|
throw IllegalArgumentException("bad argument $argumentNumber: $expected expected, got $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
return isBooleanOrNothing
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isTableOrNothing(expected: String, argumentNumber: Int): Boolean {
|
||||||
|
if (argumentNumber == -1) {
|
||||||
|
return isTableOrNothing
|
||||||
|
} else if (!isTableOrNothing) {
|
||||||
|
throw IllegalArgumentException("bad argument $argumentNumber: $expected expected, got $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
return isTableOrNothing
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isNumberOrNothing(expected: String, argumentNumber: Int): Boolean {
|
||||||
|
if (argumentNumber == -1) {
|
||||||
|
return isNumberOrNothing
|
||||||
|
} else if (!isNumberOrNothing) {
|
||||||
|
throw IllegalArgumentException("bad argument $argumentNumber: $expected expected, got $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
return isNumberOrNothing
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isStringOrNothing(expected: String, argumentNumber: Int): Boolean {
|
||||||
|
if (argumentNumber == -1) {
|
||||||
|
return isStringOrNothing
|
||||||
|
} else if (!isStringOrNothing) {
|
||||||
|
throw IllegalArgumentException("bad argument $argumentNumber: $expected expected, got $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
return isStringOrNothing
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isThreadOrNothing(expected: String, argumentNumber: Int): Boolean {
|
||||||
|
if (argumentNumber == -1) {
|
||||||
|
return isThreadOrNothing
|
||||||
|
} else if (!isThreadOrNothing) {
|
||||||
|
throw IllegalArgumentException("bad argument $argumentNumber: $expected expected, got $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
return isThreadOrNothing
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun valueOf(value: Int): LuaType {
|
fun valueOf(value: Int): LuaType {
|
||||||
return when (value) {
|
return when (value) {
|
||||||
|
Loading…
Reference in New Issue
Block a user