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

690 lines
16 KiB
Kotlin

package ru.dbotthepony.kstarbound.lua
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.util.Either
import ru.dbotthepony.kommons.util.IStruct2d
import ru.dbotthepony.kommons.util.IStruct2f
import ru.dbotthepony.kommons.util.IStruct2i
import ru.dbotthepony.kommons.util.IStruct3d
import ru.dbotthepony.kommons.util.IStruct3f
import ru.dbotthepony.kommons.util.IStruct3i
import ru.dbotthepony.kommons.util.IStruct4d
import ru.dbotthepony.kommons.util.IStruct4f
import ru.dbotthepony.kommons.util.IStruct4i
import ru.dbotthepony.kstarbound.Registry
import ru.dbotthepony.kstarbound.math.AABB
import ru.dbotthepony.kstarbound.math.AABBi
import ru.dbotthepony.kstarbound.math.Line2d
import ru.dbotthepony.kstarbound.math.vector.Vector2d
import ru.dbotthepony.kstarbound.math.vector.Vector2f
import ru.dbotthepony.kstarbound.math.vector.Vector2i
import ru.dbotthepony.kstarbound.world.physics.Poly
// 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.nextPoly(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.nextOptionalPoly(position: Int = this.position++): Poly? {
if (position !in 1 ..this.top)
return null
return lua.getPoly(position)
}
fun LuaThread.getLine2d(stackIndex: Int = -1): Line2d? {
val abs = this.absStackIndex(stackIndex)
if (!this.isTable(abs))
return null
push(1)
loadTableValue(abs)
val x = getVector2d()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getVector2d()
pop()
y ?: return null
return Line2d(x, y)
}
fun LuaThread.ArgStack.nextLine2d(position: Int = this.position++): Line2d {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: Line2d expected, got nil")
return lua.getLine2d(position)
?: throw IllegalArgumentException("bad argument #$position: Line2d expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalLine2d(position: Int = this.position++): Line2d? {
if (position !in 1 ..this.top)
return null
return lua.getLine2d(position)
}
fun LuaThread.getVector2d(stackIndex: Int = -1): Vector2d? {
val abs = this.absStackIndex(stackIndex)
if (!this.isTable(abs))
return null
push(1)
loadTableValue(abs)
val x = getDouble()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getDouble()
pop()
y ?: return null
return Vector2d(x, y)
}
fun LuaThread.ArgStack.nextVector2d(position: Int = this.position++): Vector2d {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: Vector2d expected, got nil")
return lua.getVector2d(position)
?: throw IllegalArgumentException("bad argument #$position: Vector2d expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalVector2d(position: Int = this.position++): Vector2d? {
if (position !in 1 ..this.top)
return null
return lua.getVector2d(position)
}
fun LuaThread.getVector2f(stackIndex: Int = -1): Vector2f? {
val abs = this.absStackIndex(stackIndex)
if (!this.isTable(abs))
return null
push(1)
loadTableValue(abs)
val x = getFloat()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getFloat()
pop()
y ?: return null
return Vector2f(x, y)
}
fun LuaThread.ArgStack.nextVector2f(position: Int = this.position++): Vector2f {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: Vector2f expected, got nil")
return lua.getVector2f(position)
?: throw IllegalArgumentException("bad argument #$position: Vector2f expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalVector2f(position: Int = this.position++): Vector2f? {
if (position !in 1 ..this.top)
return null
return lua.getVector2f(position)
}
fun LuaThread.getVector2iOrAABB(stackIndex: Int = -1): Either<Vector2i, AABB>? {
val abs = this.absStackIndex(stackIndex)
if (!this.isTable(abs))
return null
push(3)
val type = loadTableValue(abs)
pop()
if (type == LuaType.NUMBER) {
return Either.right(getAABB() ?: return null)
} else {
return Either.left(getVector2i() ?: return null)
}
}
fun LuaThread.ArgStack.nextVector2iOrAABB(position: Int = this.position++): Either<Vector2i, AABB> {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: Vector2d expected, got nil")
return lua.getVector2iOrAABB(position)
?: throw IllegalArgumentException("bad argument #$position: Vector2d or AABB expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalVector2iOrAABB(position: Int = this.position++): Either<Vector2i, AABB>? {
if (position !in 1 ..this.top)
return null
return lua.getVector2iOrAABB(position)
}
fun LuaThread.getRegistryID(stackIndex: Int = -1): Either<String, Int>? {
val abs = absStackIndex(stackIndex)
when (typeAt(abs)) {
LuaType.NUMBER -> return Either.right(getLong(stackIndex)!!.toInt())
LuaType.STRING -> return Either.left(getString(stackIndex)!!)
else -> return null
}
}
fun LuaThread.ArgStack.nextRegistryID(position: Int = this.position++): Either<String, Int> {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: Vector2d expected, got nil")
return lua.getRegistryID(position)
?: throw IllegalArgumentException("bad argument #$position: Vector2d or AABB expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalRegistryID(position: Int = this.position++): Either<String, Int>? {
if (position !in 1 ..this.top)
return null
return lua.getRegistryID(position)
}
fun LuaThread.getVector2i(stackIndex: Int = -1): Vector2i? {
val abs = this.absStackIndex(stackIndex)
if (!this.isTable(abs))
return null
push(1)
loadTableValue(abs)
val x = getLong()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getLong()
pop()
y ?: return null
return Vector2i(x.toInt(), y.toInt())
}
fun LuaThread.ArgStack.nextVector2i(position: Int = this.position++): Vector2i {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: Vector2i expected, got nil")
return lua.getVector2i(position)
?: throw IllegalArgumentException("bad argument #$position: Vector2i expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalVector2i(position: Int = this.position++): Vector2i? {
if (position !in 1 ..this.top)
return null
lua.typeAt(position).isTableOrNothing { "bad argument #$position: optional Vector2i expected, got $this" }
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()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getLong()
pop()
y ?: return null
push(3)
loadTableValue(abs)
val z = getLong()
pop()
z ?: return null
push(4)
loadTableValue(abs)
val w = getLong() ?: 255L
pop()
return RGBAColor(x.toInt(), y.toInt(), z.toInt(), w.toInt())
}
fun LuaThread.ArgStack.nextColor(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.nextOptionalColor(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()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getDouble()
pop()
y ?: return null
push(3)
loadTableValue(abs)
val z = getDouble()
pop()
z ?: return null
push(4)
loadTableValue(abs)
val w = getDouble()
pop()
w ?: return null
return AABB(Vector2d(x, y), Vector2d(z, w))
}
fun LuaThread.ArgStack.nextAABB(position: Int = this.position++): AABB {
if (position !in 1 ..this.top)
throw IllegalArgumentException("bad argument #$position: AABB expected, got nil")
return lua.getAABB(position)
?: throw IllegalArgumentException("bad argument #$position: AABB expected, got ${lua.typeAt(position)}")
}
fun LuaThread.ArgStack.nextOptionalAABB(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()
pop()
x ?: return null
push(2)
loadTableValue(abs)
val y = getLong()
pop()
y ?: return null
push(3)
loadTableValue(abs)
val z = getLong()
pop()
z ?: return null
push(4)
loadTableValue(abs)
val w = getLong()
pop()
w ?: return null
return AABBi(Vector2i(x.toInt(), y.toInt()), Vector2i(z.toInt(), w.toInt()))
}
fun LuaThread.ArgStack.nextAABBi(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.nextOptionalAABBi(position: Int = this.position++): AABBi? {
if (position !in 1 ..this.top)
return null
return lua.getAABBi(position)
}
fun LuaThread.push(value: IStruct4i?) {
value ?: return push()
pushTable(arraySize = 4)
val table = stackTop
val (x, y, z, w) = value
push(1)
push(x.toLong())
setTableValue(table)
push(2)
push(y.toLong())
setTableValue(table)
push(3)
push(z.toLong())
setTableValue(table)
push(4)
push(w.toLong())
setTableValue(table)
}
fun LuaThread.push(value: IStruct3i?) {
value ?: return push()
pushTable(arraySize = 3)
val table = stackTop
val (x, y, z) = value
push(1)
push(x.toLong())
setTableValue(table)
push(2)
push(y.toLong())
setTableValue(table)
push(3)
push(z.toLong())
setTableValue(table)
}
fun LuaThread.push(value: IStruct2i?) {
value ?: return push()
pushTable(arraySize = 2)
val table = stackTop
val (x, y) = value
push(1)
push(x.toLong())
setTableValue(table)
push(2)
push(y.toLong())
setTableValue(table)
}
fun LuaThread.push(value: IStruct4f?) {
value ?: return push()
pushTable(arraySize = 4)
val table = stackTop
val (x, y, z, w) = value
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
push(3)
push(z)
setTableValue(table)
push(4)
push(w)
setTableValue(table)
}
fun LuaThread.push(value: IStruct3f?) {
value ?: return push()
pushTable(arraySize = 3)
val table = stackTop
val (x, y, z) = value
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
push(3)
push(z)
setTableValue(table)
}
fun LuaThread.push(value: IStruct2f?) {
value ?: return push()
pushTable(arraySize = 2)
val table = stackTop
val (x, y) = value
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
}
fun LuaThread.push(value: IStruct4d?) {
value ?: return push()
pushTable(arraySize = 4)
val table = stackTop
val (x, y, z, w) = value
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
push(3)
push(z)
setTableValue(table)
push(4)
push(w)
setTableValue(table)
}
fun LuaThread.push(value: IStruct3d?) {
value ?: return push()
pushTable(arraySize = 3)
val table = stackTop
val (x, y, z) = value
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
push(3)
push(z)
setTableValue(table)
}
fun LuaThread.push(value: IStruct2d?) {
value ?: return push()
pushTable(arraySize = 2)
val table = stackTop
val (x, y) = value
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
}
fun LuaThread.setTableValue(key: String, value: IStruct2i?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct3i?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct4i?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct2d?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct3d?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct4d?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct2f?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct3f?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: String, value: IStruct4f?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct2i?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct3i?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct4i?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct2d?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct3d?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct4d?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct2f?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct3f?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: IStruct4f?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct2i?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct3i?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct4i?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct2d?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct3d?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct4d?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct2f?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct3f?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: IStruct4f?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.push(value: AABB?) {
value ?: return push()
pushTable(arraySize = 4)
val table = stackTop
val (x, y) = value.mins
val (z, w) = value.maxs
push(1)
push(x)
setTableValue(table)
push(2)
push(y)
setTableValue(table)
push(3)
push(z)
setTableValue(table)
push(4)
push(w)
setTableValue(table)
}
fun LuaThread.push(value: AABBi?) {
value ?: return push()
pushTable(arraySize = 4)
val table = stackTop
val (x, y) = value.mins
val (z, w) = value.maxs
push(1)
push(x.toLong())
setTableValue(table)
push(2)
push(y.toLong())
setTableValue(table)
push(3)
push(z.toLong())
setTableValue(table)
push(4)
push(w.toLong())
setTableValue(table)
}
fun LuaThread.push(value: Poly?) {
value ?: return push()
pushTable(value.vertices.size)
for ((i, vertex) in value.vertices.withIndex())
setTableValue(i + 1L, vertex)
}
fun LuaThread.setTableValue(key: String, value: Poly?) { push(key); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Int, value: Poly?) { push(key.toLong()); push(value); setTableValue() }
fun LuaThread.setTableValue(key: Long, value: Poly?) { push(key); push(value); setTableValue() }
fun LuaThread.push(value: Registry.Ref<*>, preferStringsIDs: Boolean = true) {
if (value.isPresent) {
if (preferStringsIDs || value.entry!!.id == null) {
push(value.entry!!.key)
} else {
push(value.entry!!.id!!.toLong())
}
} else {
value.key.map({ push(it) }, { push(it.toLong()) })
}
}