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? { 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 { 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? { if (position !in 1 ..this.top) return null return lua.getVector2iOrAABB(position) } fun LuaThread.getRegistryID(stackIndex: Int = -1): Either? { 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 { 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? { 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()) }) } }