More native Lua work
This commit is contained in:
parent
d46ffdb66b
commit
f9b339c0e4
@ -1,6 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.defs.actor.behavior
|
package ru.dbotthepony.kstarbound.defs.actor.behavior
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
|
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,4 +17,5 @@ data class BehaviorNodeDefinition(
|
|||||||
*/
|
*/
|
||||||
val properties: ImmutableMap<String, NodeParameter> = ImmutableMap.of(),
|
val properties: ImmutableMap<String, NodeParameter> = ImmutableMap.of(),
|
||||||
val output: ImmutableMap<String, NodeOutput> = ImmutableMap.of(),
|
val output: ImmutableMap<String, NodeOutput> = ImmutableMap.of(),
|
||||||
|
val script: AssetPath? = null,
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,7 @@ import ru.dbotthepony.kstarbound.lua.userdata.NodeParameterType
|
|||||||
data class NodeOutput(val type: NodeParameterType, val key: String? = null, val ephemeral: Boolean = false) {
|
data class NodeOutput(val type: NodeParameterType, val key: String? = null, val ephemeral: Boolean = false) {
|
||||||
fun push(lua: LuaThread) {
|
fun push(lua: LuaThread) {
|
||||||
lua.pushTable(hashSize = 3)
|
lua.pushTable(hashSize = 3)
|
||||||
lua.setTableValue("type", type.ordinal)
|
lua.setTableValue("type", type.ordinal + 1)
|
||||||
|
|
||||||
if (key != null)
|
if (key != null)
|
||||||
lua.setTableValue("key", key)
|
lua.setTableValue("key", key)
|
||||||
|
@ -20,7 +20,7 @@ data class NodeParameter(val type: NodeParameterType, val value: NodeParameterVa
|
|||||||
|
|
||||||
fun push(lua: LuaThread) {
|
fun push(lua: LuaThread) {
|
||||||
lua.pushTable(hashSize = 3)
|
lua.pushTable(hashSize = 3)
|
||||||
lua.setTableValue("type", type.ordinal)
|
lua.setTableValue("type", type.ordinal + 1)
|
||||||
|
|
||||||
if (value.key != null) {
|
if (value.key != null) {
|
||||||
lua.setTableValue("key", value.key)
|
lua.setTableValue("key", value.key)
|
||||||
|
@ -18,6 +18,7 @@ import ru.dbotthepony.kstarbound.math.Line2d
|
|||||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||||
import ru.dbotthepony.kstarbound.math.vector.Vector2f
|
import ru.dbotthepony.kstarbound.math.vector.Vector2f
|
||||||
import ru.dbotthepony.kstarbound.math.vector.Vector2i
|
import ru.dbotthepony.kstarbound.math.vector.Vector2i
|
||||||
|
import ru.dbotthepony.kstarbound.util.floorToInt
|
||||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||||
|
|
||||||
// TODO: error reporting when argument was provided, but it is malformed
|
// TODO: error reporting when argument was provided, but it is malformed
|
||||||
@ -223,18 +224,20 @@ fun LuaThread.getVector2i(stackIndex: Int = -1): Vector2i? {
|
|||||||
push(1)
|
push(1)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val x = getLong()
|
// FIXME: original engine parity, where it casts doubles into ints
|
||||||
|
// while it seems okay, it can cause undesired side effects
|
||||||
|
val x = getDouble()
|
||||||
pop()
|
pop()
|
||||||
x ?: return null
|
x ?: return null
|
||||||
|
|
||||||
push(2)
|
push(2)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val y = getLong()
|
val y = getDouble()
|
||||||
pop()
|
pop()
|
||||||
y ?: return null
|
y ?: return null
|
||||||
|
|
||||||
return Vector2i(x.toInt(), y.toInt())
|
return Vector2i(x.floorToInt(), y.floorToInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LuaThread.ArgStack.nextVector2i(position: Int = this.position++): Vector2i {
|
fun LuaThread.ArgStack.nextVector2i(position: Int = this.position++): Vector2i {
|
||||||
@ -262,31 +265,31 @@ fun LuaThread.getColor(stackIndex: Int = -1): RGBAColor? {
|
|||||||
push(1)
|
push(1)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val x = getLong()
|
val x = getFloat()
|
||||||
pop()
|
pop()
|
||||||
x ?: return null
|
x ?: return null
|
||||||
|
|
||||||
push(2)
|
push(2)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val y = getLong()
|
val y = getFloat()
|
||||||
pop()
|
pop()
|
||||||
y ?: return null
|
y ?: return null
|
||||||
|
|
||||||
push(3)
|
push(3)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val z = getLong()
|
val z = getFloat()
|
||||||
pop()
|
pop()
|
||||||
z ?: return null
|
z ?: return null
|
||||||
|
|
||||||
push(4)
|
push(4)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val w = getLong() ?: 255L
|
val w = getFloat() ?: 255f
|
||||||
pop()
|
pop()
|
||||||
|
|
||||||
return RGBAColor(x.toInt(), y.toInt(), z.toInt(), w.toInt())
|
return RGBAColor(x / 255f, y / 255f, z / 255f, w / 255f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LuaThread.ArgStack.nextColor(position: Int = this.position++): RGBAColor {
|
fun LuaThread.ArgStack.nextColor(position: Int = this.position++): RGBAColor {
|
||||||
@ -365,32 +368,33 @@ fun LuaThread.getAABBi(stackIndex: Int = -1): AABBi? {
|
|||||||
push(1)
|
push(1)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val x = getLong()
|
// FIXME: original engine parity
|
||||||
|
val x = getDouble()
|
||||||
pop()
|
pop()
|
||||||
x ?: return null
|
x ?: return null
|
||||||
|
|
||||||
push(2)
|
push(2)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val y = getLong()
|
val y = getDouble()
|
||||||
pop()
|
pop()
|
||||||
y ?: return null
|
y ?: return null
|
||||||
|
|
||||||
push(3)
|
push(3)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val z = getLong()
|
val z = getDouble()
|
||||||
pop()
|
pop()
|
||||||
z ?: return null
|
z ?: return null
|
||||||
|
|
||||||
push(4)
|
push(4)
|
||||||
loadTableValue(abs)
|
loadTableValue(abs)
|
||||||
|
|
||||||
val w = getLong()
|
val w = getDouble()
|
||||||
pop()
|
pop()
|
||||||
w ?: return null
|
w ?: return null
|
||||||
|
|
||||||
return AABBi(Vector2i(x.toInt(), y.toInt()), Vector2i(z.toInt(), w.toInt()))
|
return AABBi(Vector2i(x.floorToInt(), y.floorToInt()), Vector2i(z.floorToInt(), w.floorToInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LuaThread.ArgStack.nextAABBi(position: Int = this.position++): AABBi {
|
fun LuaThread.ArgStack.nextAABBi(position: Int = this.position++): AABBi {
|
||||||
|
@ -18,4 +18,4 @@ const val LUA_ERRERR = 5
|
|||||||
class InvalidLuaSyntaxException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)
|
class InvalidLuaSyntaxException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||||
class LuaMemoryAllocException(message: String? = null, cause: Throwable? = null) : Error(message, cause)
|
class LuaMemoryAllocException(message: String? = null, cause: Throwable? = null) : Error(message, cause)
|
||||||
class LuaException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)
|
class LuaException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||||
class LuaRuntimeException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)
|
class LuaRuntimeException(message: String? = null, cause: Throwable? = null, writeStackTrace: Boolean = true) : RuntimeException(message, cause, true, writeStackTrace)
|
||||||
|
@ -60,7 +60,7 @@ class LuaSharedState(val handlesThread: LuaThread, private val cleanable: Cleana
|
|||||||
)
|
)
|
||||||
|
|
||||||
handlesThread.push {
|
handlesThread.push {
|
||||||
//it.lua.push(it.nextObject<Throwable>().stackTraceToString())
|
//it.lua.push(it.nextObject<Throwable?>(-1)?.stackTraceToString() ?: it.nextObject<Any?>(-1).toString())
|
||||||
it.lua.push(it.nextObject<Any?>().toString())
|
it.lua.push(it.nextObject<Any?>().toString())
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ class LuaSharedState(val handlesThread: LuaThread, private val cleanable: Cleana
|
|||||||
|
|
||||||
if (obj is Throwable && obj !is LuaRuntimeException) {
|
if (obj is Throwable && obj !is LuaRuntimeException) {
|
||||||
it.lua.traceback(obj.toString(), 1)
|
it.lua.traceback(obj.toString(), 1)
|
||||||
val err = LuaRuntimeException(it.lua.getString(), cause = obj)
|
val err = LuaRuntimeException(it.lua.getString(), cause = obj, writeStackTrace = false)
|
||||||
it.lua.push(err)
|
it.lua.push(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,10 @@ class LuaThread private constructor(
|
|||||||
this.storeGlobal("math")
|
this.storeGlobal("math")
|
||||||
LuaJNR.INSTANCE.luaopen_utf8(this.pointer)
|
LuaJNR.INSTANCE.luaopen_utf8(this.pointer)
|
||||||
this.storeGlobal("utf8")
|
this.storeGlobal("utf8")
|
||||||
|
LuaJNR.INSTANCE.luaopen_debug(this.pointer)
|
||||||
|
this.storeGlobal("debug")
|
||||||
|
LuaJNR.INSTANCE.luaopen_os(this.pointer)
|
||||||
|
this.storeGlobal("os")
|
||||||
|
|
||||||
sharedState.initializeHandles(this)
|
sharedState.initializeHandles(this)
|
||||||
|
|
||||||
@ -819,8 +823,8 @@ class LuaThread private constructor(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
keyVisitor(this, abs + 1)
|
keyVisitor(this, top)
|
||||||
valueVisitor(this, abs + 2)
|
valueVisitor(this, top + 1)
|
||||||
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -843,7 +847,7 @@ class LuaThread private constructor(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
values.add(keyVisitor(this, abs + 1))
|
values.add(keyVisitor(this, top))
|
||||||
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -866,7 +870,7 @@ class LuaThread private constructor(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
values.add(valueVisitor(this, abs + 2))
|
values.add(valueVisitor(this, top + 1))
|
||||||
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -889,7 +893,7 @@ class LuaThread private constructor(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) {
|
||||||
values.add(keyVisitor(this, abs + 1) to valueVisitor(this, abs + 2))
|
values.add(keyVisitor(this, top) to valueVisitor(this, top + 1))
|
||||||
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
LuaJNR.INSTANCE.lua_settop(this.pointer, top)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -1233,7 +1237,7 @@ class LuaThread private constructor(
|
|||||||
check(value >= 0) { "Internal JVM error: ${function::class.qualifiedName} returned incorrect number of arguments to be popped from stack by Lua" }
|
check(value >= 0) { "Internal JVM error: ${function::class.qualifiedName} returned incorrect number of arguments to be popped from stack by Lua" }
|
||||||
return value
|
return value
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
push(err)
|
realLuaState.push(err)
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1436,6 +1440,17 @@ class LuaThread private constructor(
|
|||||||
LuaJNR.INSTANCE.lua_copy(pointer, fromIndex, toIndex)
|
LuaJNR.INSTANCE.lua_copy(pointer, fromIndex, toIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun swap(indexA: Int, indexB: Int) {
|
||||||
|
if (indexA == indexB) return
|
||||||
|
val absA = if (indexA < 0) indexA - 1 else indexA
|
||||||
|
val absB = if (indexB < 0) indexB - 1 else indexB
|
||||||
|
push()
|
||||||
|
copy(absA, -1)
|
||||||
|
copy(absB, absA)
|
||||||
|
copy(-1, absB)
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
|
||||||
fun dup() {
|
fun dup() {
|
||||||
push()
|
push()
|
||||||
copy(-2, -1)
|
copy(-2, -1)
|
||||||
|
@ -41,13 +41,13 @@ class LuaUpdateComponent(val lua: LuaThread, val name: Any) {
|
|||||||
lua.callConditional {
|
lua.callConditional {
|
||||||
val type = loadGlobal("update")
|
val type = loadGlobal("update")
|
||||||
|
|
||||||
if (type != lastType) {
|
/*if (type != lastType) {
|
||||||
lastType = type
|
lastType = type
|
||||||
|
|
||||||
if (type != LuaType.FUNCTION) {
|
if (type != LuaType.FUNCTION) {
|
||||||
LOGGER.warn("Lua environment for $name has $type as global 'update', script update wasn't called")
|
LOGGER.warn("Lua environment for $name has $type as global 'update', script update wasn't called")
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (type == LuaType.FUNCTION) {
|
if (type == LuaType.FUNCTION) {
|
||||||
preRun()
|
preRun()
|
||||||
|
@ -100,12 +100,12 @@ private fun setDropPool(self: MonsterEntity, args: LuaThread.ArgStack): Int {
|
|||||||
|
|
||||||
private fun toAbsolutePosition(self: MonsterEntity, args: LuaThread.ArgStack): Int {
|
private fun toAbsolutePosition(self: MonsterEntity, args: LuaThread.ArgStack): Int {
|
||||||
args.lua.push(self.movement.getAbsolutePosition(args.nextVector2d()))
|
args.lua.push(self.movement.getAbsolutePosition(args.nextVector2d()))
|
||||||
return 0
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mouthPosition(self: MonsterEntity, args: LuaThread.ArgStack): Int {
|
private fun mouthPosition(self: MonsterEntity, args: LuaThread.ArgStack): Int {
|
||||||
args.lua.push(self.mouthPosition)
|
args.lua.push(self.mouthPosition)
|
||||||
return 0
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// This callback is registered here rather than in
|
// This callback is registered here rather than in
|
||||||
|
@ -160,91 +160,89 @@ private fun printJson(args: LuaThread.ArgStack): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun provideUtilityBindings(lua: LuaThread) {
|
fun provideUtilityBindings(lua: LuaThread) {
|
||||||
with(lua) {
|
lua.push {
|
||||||
push {
|
LuaThread.LOGGER.info(it.nextString())
|
||||||
LuaThread.LOGGER.info(it.nextString())
|
0
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__print")
|
|
||||||
|
|
||||||
push {
|
|
||||||
LuaThread.LOGGER.warn(it.nextString())
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__print_warn")
|
|
||||||
|
|
||||||
push {
|
|
||||||
LuaThread.LOGGER.error(it.nextString())
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__print_error")
|
|
||||||
|
|
||||||
push {
|
|
||||||
LuaThread.LOGGER.fatal(it.nextString())
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__print_fatal")
|
|
||||||
|
|
||||||
push {
|
|
||||||
val path = it.nextString()
|
|
||||||
|
|
||||||
try {
|
|
||||||
load(Starbound.readLuaScript(path).join(), "@$path")
|
|
||||||
1
|
|
||||||
} catch (err: Exception) {
|
|
||||||
LuaThread.LOGGER.error("Exception loading Lua script $path", err)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__require")
|
|
||||||
|
|
||||||
push {
|
|
||||||
push(random.nextDouble())
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__random_double")
|
|
||||||
|
|
||||||
push {
|
|
||||||
push(random.nextLong(it.nextLong(), it.nextLong()))
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__random_long")
|
|
||||||
|
|
||||||
push {
|
|
||||||
random = random(it.nextLong())
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("__random_seed")
|
|
||||||
|
|
||||||
push {
|
|
||||||
push(it.lua.getNamedHandle(it.nextString()))
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("gethandle")
|
|
||||||
|
|
||||||
push {
|
|
||||||
val find = it.lua.findNamedHandle(it.nextString())
|
|
||||||
|
|
||||||
if (find == null) {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
push(find)
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storeGlobal("findhandle")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__print")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
LuaThread.LOGGER.warn(it.nextString())
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__print_warn")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
LuaThread.LOGGER.error(it.nextString())
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__print_error")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
LuaThread.LOGGER.fatal(it.nextString())
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__print_fatal")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
val path = it.nextString()
|
||||||
|
|
||||||
|
try {
|
||||||
|
it.lua.load(Starbound.readLuaScript(path).join(), "@$path")
|
||||||
|
1
|
||||||
|
} catch (err: Exception) {
|
||||||
|
LuaThread.LOGGER.error("Exception loading Lua script $path", err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__require")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
it.lua.push(it.lua.random.nextDouble())
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__random_double")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
it.lua.push(it.lua.random.nextLong(it.nextLong(), it.nextLong()))
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__random_long")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
it.lua.random = random(it.nextLong())
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("__random_seed")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
it.lua.push(it.lua.getNamedHandle(it.nextString()))
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("gethandle")
|
||||||
|
|
||||||
|
lua.push {
|
||||||
|
val find = it.lua.findNamedHandle(it.nextString())
|
||||||
|
|
||||||
|
if (find == null) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
it.lua.push(find)
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua.storeGlobal("findhandle")
|
||||||
|
|
||||||
lua.pushTable()
|
lua.pushTable()
|
||||||
lua.dup()
|
lua.dup()
|
||||||
lua.storeGlobal("sb")
|
lua.storeGlobal("sb")
|
||||||
|
@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.lua.bindings
|
|||||||
|
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import ru.dbotthepony.kommons.util.KOptional
|
import ru.dbotthepony.kommons.util.KOptional
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.EntityType
|
import ru.dbotthepony.kstarbound.defs.EntityType
|
||||||
@ -96,7 +97,17 @@ private data class CallScriptData(
|
|||||||
|
|
||||||
private fun LuaThread.ArgStack.getScriptData(): CallScriptData? {
|
private fun LuaThread.ArgStack.getScriptData(): CallScriptData? {
|
||||||
if (peek() == LuaType.STRING) {
|
if (peek() == LuaType.STRING) {
|
||||||
return CallScriptData(nextString(), nextJson().asJsonArray, nextJson())
|
val name = nextString()
|
||||||
|
val nextJson = nextJson()
|
||||||
|
val expected = nextJson()
|
||||||
|
|
||||||
|
if (nextJson is JsonObject && nextJson.size() == 0) {
|
||||||
|
return CallScriptData(name, JsonArray(), expected)
|
||||||
|
} else if (nextJson is JsonArray) {
|
||||||
|
return CallScriptData(name, nextJson, expected)
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException("Invalid script arguments to use (expected to be an array): $nextJson")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
skip(3)
|
skip(3)
|
||||||
return null
|
return null
|
||||||
|
@ -29,7 +29,7 @@ private fun name(self: WorldObject, args: LuaThread.ArgStack): Int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun directions(self: WorldObject, args: LuaThread.ArgStack): Int {
|
private fun direction(self: WorldObject, args: LuaThread.ArgStack): Int {
|
||||||
args.lua.push(self.direction.numericalValue)
|
args.lua.push(self.direction.numericalValue)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@ -320,7 +320,7 @@ fun provideWorldObjectBindings(self: WorldObject, lua: LuaThread) {
|
|||||||
lua.storeGlobal("object")
|
lua.storeGlobal("object")
|
||||||
|
|
||||||
lua.pushBinding(self, "name", ::name)
|
lua.pushBinding(self, "name", ::name)
|
||||||
lua.pushBinding(self, "directions", ::directions)
|
lua.pushBinding(self, "direction", ::direction)
|
||||||
lua.pushBinding(self, "position", ::position)
|
lua.pushBinding(self, "position", ::position)
|
||||||
lua.pushBinding(self, "setInteractive", ::setInteractive)
|
lua.pushBinding(self, "setInteractive", ::setInteractive)
|
||||||
lua.pushBinding(self, "uniqueId", ::uniqueId)
|
lua.pushBinding(self, "uniqueId", ::uniqueId)
|
||||||
|
@ -29,7 +29,7 @@ private fun replaceBehaviorTag(parameter: NodeParameterValue, treeParameters: Ma
|
|||||||
if (parameter.key != null)
|
if (parameter.key != null)
|
||||||
str = parameter.key
|
str = parameter.key
|
||||||
|
|
||||||
// original engine does this, and i don't know why this make any sense
|
// FIXME: original engine does this, and i don't know why this make any sense
|
||||||
else if (parameter.value is JsonPrimitive && parameter.value.isString)
|
else if (parameter.value is JsonPrimitive && parameter.value.isString)
|
||||||
str = parameter.value.asString
|
str = parameter.value.asString
|
||||||
|
|
||||||
@ -144,7 +144,12 @@ private fun createNode(
|
|||||||
functions.add(name)
|
functions.add(name)
|
||||||
|
|
||||||
val outputConfig = data.get("output") { JsonObject() }
|
val outputConfig = data.get("output") { JsonObject() }
|
||||||
val output = LinkedHashMap(Registries.behaviorNodes.getOrThrow(name).value.output)
|
val node = Registries.behaviorNodes.getOrThrow(name).value
|
||||||
|
val output = LinkedHashMap(node.output)
|
||||||
|
|
||||||
|
// original engine doesn't do this
|
||||||
|
if (node.script != null)
|
||||||
|
scripts.add(node.script.fullPath)
|
||||||
|
|
||||||
for ((k, v) in output.entries) {
|
for ((k, v) in output.entries) {
|
||||||
val replaced = replaceOutputBehaviorTag(outputConfig[k]?.asString ?: v.key, treeParameters)
|
val replaced = replaceOutputBehaviorTag(outputConfig[k]?.asString ?: v.key, treeParameters)
|
||||||
@ -263,14 +268,12 @@ private fun createBehaviorTree(args: LuaThread.ArgStack): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handles.add(blackboard)
|
handles.add(blackboard)
|
||||||
|
|
||||||
args.lua.ensureExtraCapacity(40)
|
args.lua.ensureExtraCapacity(40)
|
||||||
|
|
||||||
|
mergedParams.scripts.forEach { scripts.add(it.fullPath) }
|
||||||
val root = createNode(args.lua, mergedParams.root, mergedParams.mappedParameters, blackboard, scripts, functions, handles)
|
val root = createNode(args.lua, mergedParams.root, mergedParams.mappedParameters, blackboard, scripts, functions, handles)
|
||||||
handles.add(root)
|
handles.add(root)
|
||||||
|
|
||||||
args.lua.loadGlobal("require")
|
|
||||||
|
|
||||||
scripts.forEach {
|
scripts.forEach {
|
||||||
args.lua.call {
|
args.lua.call {
|
||||||
loadGlobal("require")
|
loadGlobal("require")
|
||||||
@ -289,9 +292,11 @@ private fun createBehaviorTree(args: LuaThread.ArgStack): Int {
|
|||||||
handle.push(this)
|
handle.push(this)
|
||||||
push("bake")
|
push("bake")
|
||||||
check(loadTableValue() == LuaType.FUNCTION) { "BehaviorTree.bake is not a Lua function" }
|
check(loadTableValue() == LuaType.FUNCTION) { "BehaviorTree.bake is not a Lua function" }
|
||||||
handle.push(this)
|
swap(-2, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args.lua.push(handle)
|
||||||
|
|
||||||
handle.close()
|
handle.close()
|
||||||
handles.forEach { it.close() }
|
handles.forEach { it.close() }
|
||||||
return 1
|
return 1
|
||||||
|
@ -51,6 +51,7 @@ import ru.dbotthepony.kstarbound.world.api.MutableTileState
|
|||||||
import ru.dbotthepony.kstarbound.world.api.TileColor
|
import ru.dbotthepony.kstarbound.world.api.TileColor
|
||||||
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
|
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.NPCEntity
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -232,7 +233,8 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk<ServerWorld, Server
|
|||||||
|
|
||||||
for (obj in world.storage.loadEntities(pos).await()) {
|
for (obj in world.storage.loadEntities(pos).await()) {
|
||||||
try {
|
try {
|
||||||
obj.joinWorld(world)
|
if (obj !is NPCEntity)
|
||||||
|
obj.joinWorld(world)
|
||||||
} catch (err: Exception) {
|
} catch (err: Exception) {
|
||||||
LOGGER.error("Exception while spawning entity $obj in world", err)
|
LOGGER.error("Exception while spawning entity $obj in world", err)
|
||||||
}
|
}
|
||||||
|
@ -122,18 +122,16 @@ abstract class SystemWorld(val location: Vector3i, val clock: JVMClock, val univ
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun compatCoordinateSeed(coordinate: UniversePos, seedMix: String): Long {
|
fun compatCoordinateSeed(coordinate: UniversePos, seedMix: String): Long {
|
||||||
// original code is utterly broken here
|
// FIXME: original code is utterly broken here
|
||||||
|
// consider the following:
|
||||||
// consider the following:
|
// auto satellite = coordinate.isSatelliteBody() ? coordinate.orbitNumber() : 0;
|
||||||
// auto satellite = coordinate.isSatelliteBody() ? coordinate.orbitNumber() : 0;
|
// auto planet = coordinate.isSatelliteBody() ? coordinate.parent().orbitNumber() : coordinate.isPlanetaryBody() && coordinate.orbitNumber() || 0;
|
||||||
// auto planet = coordinate.isSatelliteBody() ? coordinate.parent().orbitNumber() : coordinate.isPlanetaryBody() && coordinate.orbitNumber() || 0;
|
// first obvious problem: coordinate.isPlanetaryBody() && coordinate.orbitNumber() || 0
|
||||||
|
// this "coalesces" planet orbit into either 0 or 1
|
||||||
// first obvious problem: coordinate.isPlanetaryBody() && coordinate.orbitNumber() || 0
|
// then, we have coordinate.parent().orbitNumber(), which is correct, but only if we are orbiting a satellite
|
||||||
// this "coalesces" planet orbit into either 0 or 1
|
|
||||||
// then, we have coordinate.parent().orbitNumber(), which is correct, but only if we are orbiting a satellite
|
|
||||||
|
|
||||||
// TODO: Use correct logic when there are no legacy clients in this system
|
// TODO: Use correct logic when there are no legacy clients in this system
|
||||||
// Correct logic properly randomizes starting planet orbits, and they feel much more natural
|
// Correct logic properly randomizes starting planet orbits, and they feel much more natural
|
||||||
|
|
||||||
return staticRandom64(coordinate.location.x, coordinate.location.y, coordinate.location.z, if (coordinate.isPlanet) 1 else coordinate.planetOrbit, coordinate.satelliteOrbit, seedMix)
|
return staticRandom64(coordinate.location.x, coordinate.location.y, coordinate.location.z, if (coordinate.isPlanet) 1 else coordinate.planetOrbit, coordinate.satelliteOrbit, seedMix)
|
||||||
}
|
}
|
||||||
|
@ -406,10 +406,10 @@ class MonsterEntity(val variant: MonsterVariant, level: Double? = null) : ActorE
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
/*luaUpdate.update(delta) {
|
luaUpdate.update(delta) {
|
||||||
luaMovement.clearControlsIfNeeded()
|
luaMovement.clearControlsIfNeeded()
|
||||||
forceRegions.clear()
|
forceRegions.clear()
|
||||||
}*/
|
}
|
||||||
} catch (err: Exception) {
|
} catch (err: Exception) {
|
||||||
LOGGER.error("Exception while ticking $this", err)
|
LOGGER.error("Exception while ticking $this", err)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ local function blackboardSet(self, t, key, value)
|
|||||||
local mappings = self.vectorNumberInput[key]
|
local mappings = self.vectorNumberInput[key]
|
||||||
|
|
||||||
if mappings then
|
if mappings then
|
||||||
for _, pair in pairs(input) do
|
for _, pair in pairs(mappings) do
|
||||||
local index = pair[1]
|
local index = pair[1]
|
||||||
local tab = pair[2]
|
local tab = pair[2]
|
||||||
tab[index] = value
|
tab[index] = value
|
||||||
@ -107,12 +107,12 @@ function blackboardPrototype:parameters(parameters, nodeID)
|
|||||||
|
|
||||||
if not typeInput then
|
if not typeInput then
|
||||||
typeInput = {}
|
typeInput = {}
|
||||||
self.input[i][pKey] = typeInput
|
self.input[t][pKey] = typeInput
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(typeInput, {parameterName, tab})
|
table.insert(typeInput, {parameterName, tab})
|
||||||
tab[parameterName] = self.board[t][pKey]
|
tab[parameterName] = self.board[t][pKey]
|
||||||
elseif pValue then
|
elseif pValue ~= nil then
|
||||||
if t == 4 then -- vec2
|
if t == 4 then -- vec2
|
||||||
-- dumb special case for allowing a vec2 of blackboard number keys
|
-- dumb special case for allowing a vec2 of blackboard number keys
|
||||||
if type(pValue) ~= 'table' then
|
if type(pValue) ~= 'table' then
|
||||||
@ -132,7 +132,7 @@ function blackboardPrototype:parameters(parameters, nodeID)
|
|||||||
end
|
end
|
||||||
|
|
||||||
table.insert(typeInput, {i, vector})
|
table.insert(typeInput, {i, vector})
|
||||||
vector[i] = self.board[5][key] -- number
|
vector[i] = self.board[5][vValue] -- number
|
||||||
else
|
else
|
||||||
vector[i] = vValue
|
vector[i] = vValue
|
||||||
end
|
end
|
||||||
@ -142,8 +142,6 @@ function blackboardPrototype:parameters(parameters, nodeID)
|
|||||||
else
|
else
|
||||||
tab[parameterName] = pValue
|
tab[parameterName] = pValue
|
||||||
end
|
end
|
||||||
else
|
|
||||||
error(string.format('parameter %s of type %s for node %s has no key nor value', parameterName, parameter.type, nodeID))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -183,7 +181,7 @@ function blackboardPrototype:clearEphemerals(ephemerals)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Blackboard()
|
function Blackboard()
|
||||||
return setmetatable({}, blackboardPrototype):ctor()
|
return setmetatable({}, blackboardPrototype):ctor()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -204,6 +202,19 @@ local function runAndReset(self, ...)
|
|||||||
return status
|
return status
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function reconstructTree(stack)
|
||||||
|
local top = #stack
|
||||||
|
if top == 0 then return '' end
|
||||||
|
|
||||||
|
local result = {'\nbehavior tree traceback:'}
|
||||||
|
|
||||||
|
for i = top, 1, -1 do
|
||||||
|
table.insert(result, string.format('%s%d. - %q', string.rep(' ', top - i + 1), top - i + 1, stack[i]))
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(result, '\n')
|
||||||
|
end
|
||||||
|
|
||||||
-- ActionNode
|
-- ActionNode
|
||||||
|
|
||||||
local actionNode = {}
|
local actionNode = {}
|
||||||
@ -221,10 +232,10 @@ function actionNode:ctor(name, parameters, outputs)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function actionNode:bake()
|
function actionNode:bake()
|
||||||
self.callable = _G[self.name]
|
self.callable = _ENV[self.name]
|
||||||
|
|
||||||
if type(callable) ~= 'function' then
|
if type(self.callable) ~= 'function' then
|
||||||
error('expected global ' .. self.name .. ' to be a function, but got ' .. type(callable))
|
error('expected global ' .. self.name .. ' to be a function, but got ' .. type(self.callable))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -233,7 +244,8 @@ do
|
|||||||
local resume = coroutine.resume
|
local resume = coroutine.resume
|
||||||
local status = coroutine.status
|
local status = coroutine.status
|
||||||
|
|
||||||
function actionNode:run(delta, blackboard)
|
function actionNode:run(delta, blackboard, stack)
|
||||||
|
--table.insert(stack, self.name)
|
||||||
self.calls = self.calls + 1
|
self.calls = self.calls + 1
|
||||||
local status, nodeStatus, nodeExtra
|
local status, nodeStatus, nodeExtra
|
||||||
|
|
||||||
@ -246,11 +258,13 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not status then
|
if not status then
|
||||||
sb.logError('Behavior ActionNode %q failed: %s', self.name, nodeStatus)
|
sb.logError(debug.traceback(self.coroutine, string.format('Behavior ActionNode %q failed: %s%s', self.name, nodeStatus, reconstructTree(stack))))
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
end
|
end
|
||||||
|
|
||||||
if result == nil then
|
if nodeStatus == nil then
|
||||||
|
--table.remove(stack)
|
||||||
return RUNNING
|
return RUNNING
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -258,6 +272,8 @@ do
|
|||||||
blackboard:setOutput(self, nodeExtra)
|
blackboard:setOutput(self, nodeExtra)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--table.remove(stack)
|
||||||
|
|
||||||
if nodeStatus then
|
if nodeStatus then
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
else
|
else
|
||||||
@ -297,10 +313,10 @@ function decoratorNode:ctor(name, parameters, child)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function decoratorNode:bake()
|
function decoratorNode:bake()
|
||||||
self.callable = _G[self.name]
|
self.callable = _ENV[self.name]
|
||||||
|
|
||||||
if type(callable) ~= 'function' then
|
if type(self.callable) ~= 'function' then
|
||||||
error('expected global ' .. self.name .. ' to be a function, but got ' .. type(callable))
|
error('expected global ' .. self.name .. ' to be a function, but got ' .. type(self.callable))
|
||||||
end
|
end
|
||||||
|
|
||||||
self.child:bake()
|
self.child:bake()
|
||||||
@ -311,7 +327,8 @@ do
|
|||||||
local resume = coroutine.resume
|
local resume = coroutine.resume
|
||||||
local coroutine_status = coroutine.status
|
local coroutine_status = coroutine.status
|
||||||
|
|
||||||
function decoratorNode:run(delta, blackboard)
|
function decoratorNode:run(delta, blackboard, stack)
|
||||||
|
--table.insert(stack, self.name)
|
||||||
self.calls = self.calls + 1
|
self.calls = self.calls + 1
|
||||||
|
|
||||||
if not self.coroutine then
|
if not self.coroutine then
|
||||||
@ -320,7 +337,8 @@ do
|
|||||||
local status, nodeStatus = resume(coroutine, parameters, blackboard, self.nodeID, delta)
|
local status, nodeStatus = resume(coroutine, parameters, blackboard, self.nodeID, delta)
|
||||||
|
|
||||||
if not status then
|
if not status then
|
||||||
sb.logError('Behavior DecoratorNode %q failed: %s', self.name, nodeStatus)
|
sb.logError(debug.traceback(coroutine, string.format('Behavior DecoratorNode %q failed: %s%s', self.name, nodeStatus, reconstructTree(stack))))
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -329,38 +347,44 @@ do
|
|||||||
|
|
||||||
if s == 'dead' then
|
if s == 'dead' then
|
||||||
-- quite unexpected, but whatever
|
-- quite unexpected, but whatever
|
||||||
|
--table.remove(stack)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
else
|
else
|
||||||
self.coroutine = coroutine
|
self.coroutine = coroutine
|
||||||
end
|
end
|
||||||
elseif nodeStatus then
|
elseif nodeStatus then
|
||||||
|
--table.remove(stack)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
else
|
else
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local childStatus = runAndReset(self.child, delta, blackboard)
|
local childStatus = runAndReset(self.child, delta, blackboard, stack)
|
||||||
|
|
||||||
if childStatus == RUNNING then
|
if childStatus == RUNNING then
|
||||||
|
table.remove(stack)
|
||||||
return RUNNING
|
return RUNNING
|
||||||
end
|
end
|
||||||
|
|
||||||
local status, nodeStatus = resume(self.coroutine, childStatus)
|
local status, nodeStatus = resume(self.coroutine, childStatus)
|
||||||
|
|
||||||
if not status then
|
if not status then
|
||||||
sb.logError('Behavior DecoratorNode %q failed: %s', self.name, nodeStatus)
|
sb.logError(debug.traceback(coroutine, string.format('Behavior DecoratorNode %q failed: %s%s', self.name, nodeStatus, reconstructTree(stack))))
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
end
|
end
|
||||||
|
|
||||||
if nodeStatus == nil then
|
if nodeStatus == nil then
|
||||||
-- another yield OR unexpected return?
|
-- another yield OR unexpected return?
|
||||||
|
|
||||||
local s = coroutine_status(coroutine)
|
local s = coroutine_status(self.coroutine)
|
||||||
|
|
||||||
if s == 'dead' then
|
if s == 'dead' then
|
||||||
self.coroutine = nil
|
self.coroutine = nil
|
||||||
|
--table.remove(stack)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -368,8 +392,10 @@ do
|
|||||||
self.coroutine = nil
|
self.coroutine = nil
|
||||||
|
|
||||||
if nodeStatus then
|
if nodeStatus then
|
||||||
|
--table.remove(stack)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
else
|
else
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -407,20 +433,29 @@ function seqNode:ctor(children, isSelector)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function seqNode:run(delta, blackboard)
|
function seqNode:run(delta, blackboard, stack)
|
||||||
self.calls = self.calls + 1
|
self.calls = self.calls + 1
|
||||||
local size = self.size
|
local size = self.size
|
||||||
local isSelector = self.isSelector
|
local isSelector = self.isSelector
|
||||||
|
|
||||||
|
--[[if isSelector then
|
||||||
|
table.insert(stack, 'SelectorNode')
|
||||||
|
else
|
||||||
|
table.insert(stack, 'SequenceNode')
|
||||||
|
end]]
|
||||||
|
|
||||||
while self.index <= size do
|
while self.index <= size do
|
||||||
local child = self.children[self.index]
|
local child = self.children[self.index]
|
||||||
local status = runAndReset(child, delta, blackboard)
|
local status = runAndReset(child, delta, blackboard, stack)
|
||||||
|
|
||||||
if status == RUNNING then
|
if status == RUNNING then
|
||||||
|
--table.remove(stack)
|
||||||
return RUNNING
|
return RUNNING
|
||||||
elseif isSelector and status == SUCCESS then
|
elseif isSelector and status == SUCCESS then
|
||||||
|
--table.remove(stack)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
elseif not isSelector and status == FAILURE then
|
elseif not isSelector and status == FAILURE then
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -464,13 +499,13 @@ parallelNode.__index = parallelNode
|
|||||||
function parallelNode:ctor(parameters, children)
|
function parallelNode:ctor(parameters, children)
|
||||||
self.children = children
|
self.children = children
|
||||||
|
|
||||||
if type(parameters.success) == 'number' then
|
if type(parameters.success) == 'number' and parameters.success >= 0 then
|
||||||
self.successLimit = parameters.success
|
self.successLimit = parameters.success
|
||||||
else
|
else
|
||||||
self.successLimit = #children
|
self.successLimit = #children
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(parameters.fail) == 'number' then
|
if type(parameters.fail) == 'number' and parameters.fail >= 0 then
|
||||||
self.failLimit = parameters.fail
|
self.failLimit = parameters.fail
|
||||||
else
|
else
|
||||||
self.failLimit = #children
|
self.failLimit = #children
|
||||||
@ -483,15 +518,17 @@ function parallelNode:ctor(parameters, children)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function parallelNode:run(delta, blackboard)
|
function parallelNode:run(delta, blackboard, stack)
|
||||||
self.calls = self.calls + 1
|
self.calls = self.calls + 1
|
||||||
local failed = 0
|
local failed = 0
|
||||||
local succeeded = 0
|
local succeeded = 0
|
||||||
local failLimit = self.failLimit
|
local failLimit = self.failLimit
|
||||||
local successLimit = self.successLimit
|
local successLimit = self.successLimit
|
||||||
|
|
||||||
|
--table.insert(stack, 'ParallelNode')
|
||||||
|
|
||||||
for _, node in ipairs(self.children) do
|
for _, node in ipairs(self.children) do
|
||||||
local status = runAndReset(node, delta, blackboard)
|
local status = runAndReset(node, delta, blackboard, stack)
|
||||||
|
|
||||||
if status == SUCCESS then
|
if status == SUCCESS then
|
||||||
succeeded = succeeded + 1
|
succeeded = succeeded + 1
|
||||||
@ -502,16 +539,19 @@ function parallelNode:run(delta, blackboard)
|
|||||||
if failed >= failLimit then
|
if failed >= failLimit then
|
||||||
self.lastFailed = failed
|
self.lastFailed = failed
|
||||||
self.lastSucceed = succeeded
|
self.lastSucceed = succeeded
|
||||||
|
--table.remove(stack)
|
||||||
return FAILURE
|
return FAILURE
|
||||||
elseif succeeded >= successLimit then
|
elseif succeeded >= successLimit then
|
||||||
self.lastFailed = failed
|
self.lastFailed = failed
|
||||||
self.lastSucceed = succeeded
|
self.lastSucceed = succeeded
|
||||||
|
--table.remove(stack)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.lastFailed = failed
|
self.lastFailed = failed
|
||||||
self.lastSucceed = succeeded
|
self.lastSucceed = succeeded
|
||||||
|
--table.remove(stack)
|
||||||
return RUNNING
|
return RUNNING
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -550,11 +590,12 @@ function dynNode:ctor(children)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function dynNode:run(delta, blackboard)
|
function dynNode:run(delta, blackboard, stack)
|
||||||
self.calls = self.calls + 1
|
self.calls = self.calls + 1
|
||||||
|
--table.insert(stack, 'DynamicNode')
|
||||||
|
|
||||||
for i, node in ipairs(self.children) do
|
for i, node in ipairs(self.children) do
|
||||||
local status = runAndReset(node, delta, blackboard)
|
local status = runAndReset(node, delta, blackboard, stack)
|
||||||
|
|
||||||
if stauts == FAILURE and self.index == i then
|
if stauts == FAILURE and self.index == i then
|
||||||
self.index = self.index + 1
|
self.index = self.index + 1
|
||||||
@ -564,10 +605,12 @@ function dynNode:run(delta, blackboard)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if status == SUCCESS or self.index > self.size then
|
if status == SUCCESS or self.index > self.size then
|
||||||
|
--table.remove(stack)
|
||||||
return status
|
return status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--table.remove(stack)
|
||||||
return RUNNING
|
return RUNNING
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -605,7 +648,7 @@ function randNode:ctor(children)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function randNode:run(delta, blackboard)
|
function randNode:run(delta, blackboard, stack)
|
||||||
self.calls = self.calls + 1
|
self.calls = self.calls + 1
|
||||||
|
|
||||||
if self.index == -1 and self.size ~= 0 then
|
if self.index == -1 and self.size ~= 0 then
|
||||||
@ -615,7 +658,10 @@ function randNode:run(delta, blackboard)
|
|||||||
if self.index == -1 then
|
if self.index == -1 then
|
||||||
return FAILURE
|
return FAILURE
|
||||||
else
|
else
|
||||||
return runAndReset(self.children[self.index], delta, blackboard)
|
--table.insert(stack, 'RandomNode')
|
||||||
|
local value = runAndReset(self.children[self.index], delta, blackboard, stack)
|
||||||
|
--table.remove(stack)
|
||||||
|
return value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -654,19 +700,20 @@ function statePrototype:ctor(blackboard, root)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function statePrototype:run(delta)
|
function statePrototype:run(delta)
|
||||||
|
local stack = {}
|
||||||
local ephemerals = self._blackboard:takeEphemerals()
|
local ephemerals = self._blackboard:takeEphemerals()
|
||||||
local status = runAndReset(self.root, delta, self._blackboard)
|
local status = runAndReset(self.root, delta, self._blackboard, stack)
|
||||||
self._blackboard:clearEphemerals(ephemerals)
|
self._blackboard:clearEphemerals(ephemerals)
|
||||||
|
|
||||||
return status
|
return status
|
||||||
end
|
end
|
||||||
|
|
||||||
function statePrototype:clear()
|
function statePrototype:clear()
|
||||||
self.tree:reset()
|
self.root:reset()
|
||||||
end
|
end
|
||||||
|
|
||||||
function statePrototype:bake()
|
function statePrototype:bake()
|
||||||
self.tree:bake()
|
self.root:bake()
|
||||||
end
|
end
|
||||||
|
|
||||||
function statePrototype:blackboard()
|
function statePrototype:blackboard()
|
||||||
|
@ -385,4 +385,72 @@ function mergeJson(base, with)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local line = ''
|
||||||
|
|
||||||
|
local function puts(f, ...)
|
||||||
|
line = line .. string.format(f, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function flush()
|
||||||
|
if line ~= '' then
|
||||||
|
sb.logInfo(line)
|
||||||
|
line = ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printTable(input, level)
|
||||||
|
level = level or 0
|
||||||
|
|
||||||
|
if not next(input) then
|
||||||
|
puts('{ --[[ empty table ]] }')
|
||||||
|
if level == 0 then flush() end
|
||||||
|
else
|
||||||
|
local prefix = string.rep(' ', level + 1)
|
||||||
|
|
||||||
|
puts('{')
|
||||||
|
flush()
|
||||||
|
|
||||||
|
for k, v in pairs(input) do
|
||||||
|
if type(k) == 'string' then
|
||||||
|
puts('%s[%q] = ', prefix, k)
|
||||||
|
else
|
||||||
|
puts('%s[%s] = ', prefix, k)
|
||||||
|
end
|
||||||
|
|
||||||
|
printValue(v, level + 1)
|
||||||
|
puts(',')
|
||||||
|
flush()
|
||||||
|
end
|
||||||
|
|
||||||
|
puts('%s}', string.rep(' ', level))
|
||||||
|
if level == 0 then flush() end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function printValue(input, level)
|
||||||
|
level = level or 0
|
||||||
|
|
||||||
|
local t = type(input)
|
||||||
|
|
||||||
|
if t == 'nil' then
|
||||||
|
puts('%s', 'nil')
|
||||||
|
if level == 0 then flush() end
|
||||||
|
elseif t == 'number' then
|
||||||
|
puts('%f', input)
|
||||||
|
if level == 0 then flush() end
|
||||||
|
elseif t == 'string' then
|
||||||
|
puts('%q', tostring(input))
|
||||||
|
if level == 0 then flush() end
|
||||||
|
elseif t == 'boolean' then
|
||||||
|
puts('%s', tostring(input))
|
||||||
|
if level == 0 then flush() end
|
||||||
|
elseif t == 'table' then
|
||||||
|
printTable(input, level)
|
||||||
|
else
|
||||||
|
puts('unknown value type %q', t)
|
||||||
|
if level == 0 then flush() end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ local function entityTypeNamesToIntegers(input, fullName)
|
|||||||
error('invalid entity type ' .. tostring(v) .. ' for ' .. fullName .. ' in types table at index ' .. i, 3)
|
error('invalid entity type ' .. tostring(v) .. ' for ' .. fullName .. ' in types table at index ' .. i, 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
entityTypes[i] = lookup
|
input[i] = lookup
|
||||||
end
|
end
|
||||||
|
|
||||||
return input
|
return input
|
||||||
|
@ -13,19 +13,22 @@ object LuaTests {
|
|||||||
val lua = LuaThread()
|
val lua = LuaThread()
|
||||||
|
|
||||||
lua.push {
|
lua.push {
|
||||||
throw IllegalArgumentException("test!")
|
throw IllegalArgumentException("This is error message")
|
||||||
}
|
}
|
||||||
|
|
||||||
lua.storeGlobal("test")
|
lua.storeGlobal("test")
|
||||||
|
|
||||||
val results = lua.call(5) {
|
lua.call {
|
||||||
lua.load("""
|
lua.load("""
|
||||||
return 1, 4, 4.0, 4.1, {a = 71}
|
local function errornous()
|
||||||
|
test()
|
||||||
|
end
|
||||||
|
|
||||||
|
local cor = coroutine.create(errornous)
|
||||||
|
print(coroutine.resume(cor))
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
println(results)
|
|
||||||
println(results.last().toJson())
|
|
||||||
lua.close()
|
lua.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user