diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/BehaviorNodeDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/BehaviorNodeDefinition.kt index 1493f436..54d6e1d2 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/BehaviorNodeDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/BehaviorNodeDefinition.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.kstarbound.defs.actor.behavior import com.google.common.collect.ImmutableMap +import ru.dbotthepony.kstarbound.defs.AssetPath import ru.dbotthepony.kstarbound.json.builder.JsonFactory /** @@ -16,4 +17,5 @@ data class BehaviorNodeDefinition( */ val properties: ImmutableMap = ImmutableMap.of(), val output: ImmutableMap = ImmutableMap.of(), + val script: AssetPath? = null, ) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeOutput.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeOutput.kt index c253d8d0..4487a824 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeOutput.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeOutput.kt @@ -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) { fun push(lua: LuaThread) { lua.pushTable(hashSize = 3) - lua.setTableValue("type", type.ordinal) + lua.setTableValue("type", type.ordinal + 1) if (key != null) lua.setTableValue("key", key) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeParameter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeParameter.kt index 25b1eee1..01af9660 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeParameter.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/actor/behavior/NodeParameter.kt @@ -20,7 +20,7 @@ data class NodeParameter(val type: NodeParameterType, val value: NodeParameterVa fun push(lua: LuaThread) { lua.pushTable(hashSize = 3) - lua.setTableValue("type", type.ordinal) + lua.setTableValue("type", type.ordinal + 1) if (value.key != null) { lua.setTableValue("key", value.key) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Conversions.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Conversions.kt index 9b10e4da..d0360c98 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Conversions.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Conversions.kt @@ -18,6 +18,7 @@ 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.util.floorToInt import ru.dbotthepony.kstarbound.world.physics.Poly // TODO: error reporting when argument was provided, but it is malformed @@ -223,18 +224,20 @@ fun LuaThread.getVector2i(stackIndex: Int = -1): Vector2i? { push(1) 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() x ?: return null push(2) loadTableValue(abs) - val y = getLong() + val y = getDouble() pop() y ?: return null - return Vector2i(x.toInt(), y.toInt()) + return Vector2i(x.floorToInt(), y.floorToInt()) } fun LuaThread.ArgStack.nextVector2i(position: Int = this.position++): Vector2i { @@ -262,31 +265,31 @@ fun LuaThread.getColor(stackIndex: Int = -1): RGBAColor? { push(1) loadTableValue(abs) - val x = getLong() + val x = getFloat() pop() x ?: return null push(2) loadTableValue(abs) - val y = getLong() + val y = getFloat() pop() y ?: return null push(3) loadTableValue(abs) - val z = getLong() + val z = getFloat() pop() z ?: return null push(4) loadTableValue(abs) - val w = getLong() ?: 255L + val w = getFloat() ?: 255f 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 { @@ -365,32 +368,33 @@ fun LuaThread.getAABBi(stackIndex: Int = -1): AABBi? { push(1) loadTableValue(abs) - val x = getLong() + // FIXME: original engine parity + val x = getDouble() pop() x ?: return null push(2) loadTableValue(abs) - val y = getLong() + val y = getDouble() pop() y ?: return null push(3) loadTableValue(abs) - val z = getLong() + val z = getDouble() pop() z ?: return null push(4) loadTableValue(abs) - val w = getLong() + val w = getDouble() pop() 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 { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Errors.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Errors.kt index b37f7d78..54288ec2 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Errors.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Errors.kt @@ -18,4 +18,4 @@ const val LUA_ERRERR = 5 class InvalidLuaSyntaxException(message: String? = null, cause: Throwable? = null) : RuntimeException(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 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) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaSharedState.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaSharedState.kt index faaf7b06..e29f7f9f 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaSharedState.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaSharedState.kt @@ -60,7 +60,7 @@ class LuaSharedState(val handlesThread: LuaThread, private val cleanable: Cleana ) handlesThread.push { - //it.lua.push(it.nextObject().stackTraceToString()) + //it.lua.push(it.nextObject(-1)?.stackTraceToString() ?: it.nextObject(-1).toString()) it.lua.push(it.nextObject().toString()) 1 } @@ -79,7 +79,7 @@ class LuaSharedState(val handlesThread: LuaThread, private val cleanable: Cleana if (obj is Throwable && obj !is LuaRuntimeException) { 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) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaThread.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaThread.kt index 7d4bc3f9..9e17ee37 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaThread.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaThread.kt @@ -90,6 +90,10 @@ class LuaThread private constructor( this.storeGlobal("math") LuaJNR.INSTANCE.luaopen_utf8(this.pointer) this.storeGlobal("utf8") + LuaJNR.INSTANCE.luaopen_debug(this.pointer) + this.storeGlobal("debug") + LuaJNR.INSTANCE.luaopen_os(this.pointer) + this.storeGlobal("os") sharedState.initializeHandles(this) @@ -819,8 +823,8 @@ class LuaThread private constructor( try { while (LuaJNR.INSTANCE.lua_next(this.pointer, abs) != 0) { - keyVisitor(this, abs + 1) - valueVisitor(this, abs + 2) + keyVisitor(this, top) + valueVisitor(this, top + 1) LuaJNR.INSTANCE.lua_settop(this.pointer, top) } } finally { @@ -843,7 +847,7 @@ class LuaThread private constructor( try { 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) } } finally { @@ -866,7 +870,7 @@ class LuaThread private constructor( try { 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) } } finally { @@ -889,7 +893,7 @@ class LuaThread private constructor( try { 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) } } 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" } return value } catch (err: Throwable) { - push(err) + realLuaState.push(err) return -1 } } @@ -1436,6 +1440,17 @@ class LuaThread private constructor( 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() { push() copy(-2, -1) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaUpdateComponent.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaUpdateComponent.kt index c053fcdd..c07356f1 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaUpdateComponent.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/LuaUpdateComponent.kt @@ -41,13 +41,13 @@ class LuaUpdateComponent(val lua: LuaThread, val name: Any) { lua.callConditional { val type = loadGlobal("update") - if (type != lastType) { + /*if (type != lastType) { lastType = type if (type != LuaType.FUNCTION) { LOGGER.warn("Lua environment for $name has $type as global 'update', script update wasn't called") } - } + }*/ if (type == LuaType.FUNCTION) { preRun() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/MonsterBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/MonsterBindings.kt index e050dbe8..0da722cf 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/MonsterBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/MonsterBindings.kt @@ -100,12 +100,12 @@ private fun setDropPool(self: MonsterEntity, args: LuaThread.ArgStack): Int { private fun toAbsolutePosition(self: MonsterEntity, args: LuaThread.ArgStack): Int { args.lua.push(self.movement.getAbsolutePosition(args.nextVector2d())) - return 0 + return 1 } private fun mouthPosition(self: MonsterEntity, args: LuaThread.ArgStack): Int { args.lua.push(self.mouthPosition) - return 0 + return 1 } // This callback is registered here rather than in diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/UtilityBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/UtilityBindings.kt index 76a8f80d..330b57c4 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/UtilityBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/UtilityBindings.kt @@ -160,91 +160,89 @@ private fun printJson(args: LuaThread.ArgStack): Int { } fun provideUtilityBindings(lua: LuaThread) { - with(lua) { - push { - LuaThread.LOGGER.info(it.nextString()) - 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.push { + LuaThread.LOGGER.info(it.nextString()) + 0 } + 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.dup() lua.storeGlobal("sb") diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt index f564374a..330c0280 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.lua.bindings import com.google.gson.JsonArray import com.google.gson.JsonElement +import com.google.gson.JsonObject import ru.dbotthepony.kommons.util.KOptional import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.defs.EntityType @@ -96,7 +97,17 @@ private data class CallScriptData( private fun LuaThread.ArgStack.getScriptData(): CallScriptData? { 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 { skip(3) return null diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldObjectBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldObjectBindings.kt index 2c7cd805..c5427184 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldObjectBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldObjectBindings.kt @@ -29,7 +29,7 @@ private fun name(self: WorldObject, args: LuaThread.ArgStack): Int { 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) return 1 } @@ -320,7 +320,7 @@ fun provideWorldObjectBindings(self: WorldObject, lua: LuaThread) { lua.storeGlobal("object") lua.pushBinding(self, "name", ::name) - lua.pushBinding(self, "directions", ::directions) + lua.pushBinding(self, "direction", ::direction) lua.pushBinding(self, "position", ::position) lua.pushBinding(self, "setInteractive", ::setInteractive) lua.pushBinding(self, "uniqueId", ::uniqueId) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/userdata/BehaviorState.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/userdata/BehaviorState.kt index 42e266c4..b4c3518f 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/userdata/BehaviorState.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/userdata/BehaviorState.kt @@ -29,7 +29,7 @@ private fun replaceBehaviorTag(parameter: NodeParameterValue, treeParameters: Ma if (parameter.key != null) 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) str = parameter.value.asString @@ -144,7 +144,12 @@ private fun createNode( functions.add(name) 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) { val replaced = replaceOutputBehaviorTag(outputConfig[k]?.asString ?: v.key, treeParameters) @@ -263,14 +268,12 @@ private fun createBehaviorTree(args: LuaThread.ArgStack): Int { } handles.add(blackboard) - args.lua.ensureExtraCapacity(40) + mergedParams.scripts.forEach { scripts.add(it.fullPath) } val root = createNode(args.lua, mergedParams.root, mergedParams.mappedParameters, blackboard, scripts, functions, handles) handles.add(root) - args.lua.loadGlobal("require") - scripts.forEach { args.lua.call { loadGlobal("require") @@ -289,9 +292,11 @@ private fun createBehaviorTree(args: LuaThread.ArgStack): Int { handle.push(this) push("bake") check(loadTableValue() == LuaType.FUNCTION) { "BehaviorTree.bake is not a Lua function" } - handle.push(this) + swap(-2, -1) } + args.lua.push(handle) + handle.close() handles.forEach { it.close() } return 1 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerChunk.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerChunk.kt index 1ebad4d8..63a2b7c0 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerChunk.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerChunk.kt @@ -51,6 +51,7 @@ import ru.dbotthepony.kstarbound.world.api.MutableTileState import ru.dbotthepony.kstarbound.world.api.TileColor import ru.dbotthepony.kstarbound.world.entities.AbstractEntity import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity +import ru.dbotthepony.kstarbound.world.entities.NPCEntity import java.util.concurrent.CompletableFuture import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.TimeUnit @@ -232,7 +233,8 @@ class ServerChunk(world: ServerWorld, pos: ChunkPos) : Chunk= 0 then self.successLimit = parameters.success else self.successLimit = #children end - if type(parameters.fail) == 'number' then + if type(parameters.fail) == 'number' and parameters.fail >= 0 then self.failLimit = parameters.fail else self.failLimit = #children @@ -483,15 +518,17 @@ function parallelNode:ctor(parameters, children) return self end -function parallelNode:run(delta, blackboard) +function parallelNode:run(delta, blackboard, stack) self.calls = self.calls + 1 local failed = 0 local succeeded = 0 local failLimit = self.failLimit local successLimit = self.successLimit + --table.insert(stack, 'ParallelNode') + for _, node in ipairs(self.children) do - local status = runAndReset(node, delta, blackboard) + local status = runAndReset(node, delta, blackboard, stack) if status == SUCCESS then succeeded = succeeded + 1 @@ -502,16 +539,19 @@ function parallelNode:run(delta, blackboard) if failed >= failLimit then self.lastFailed = failed self.lastSucceed = succeeded + --table.remove(stack) return FAILURE elseif succeeded >= successLimit then self.lastFailed = failed self.lastSucceed = succeeded + --table.remove(stack) return SUCCESS end end self.lastFailed = failed self.lastSucceed = succeeded + --table.remove(stack) return RUNNING end @@ -550,11 +590,12 @@ function dynNode:ctor(children) return self end -function dynNode:run(delta, blackboard) +function dynNode:run(delta, blackboard, stack) self.calls = self.calls + 1 + --table.insert(stack, 'DynamicNode') 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 self.index = self.index + 1 @@ -564,10 +605,12 @@ function dynNode:run(delta, blackboard) end if status == SUCCESS or self.index > self.size then + --table.remove(stack) return status end end + --table.remove(stack) return RUNNING end @@ -605,7 +648,7 @@ function randNode:ctor(children) return self end -function randNode:run(delta, blackboard) +function randNode:run(delta, blackboard, stack) self.calls = self.calls + 1 if self.index == -1 and self.size ~= 0 then @@ -615,7 +658,10 @@ function randNode:run(delta, blackboard) if self.index == -1 then return FAILURE 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 @@ -654,19 +700,20 @@ function statePrototype:ctor(blackboard, root) end function statePrototype:run(delta) + local stack = {} 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) return status end function statePrototype:clear() - self.tree:reset() + self.root:reset() end function statePrototype:bake() - self.tree:bake() + self.root:bake() end function statePrototype:blackboard() diff --git a/src/main/resources/scripts/global.lua b/src/main/resources/scripts/global.lua index a7a2be90..b410bed2 100644 --- a/src/main/resources/scripts/global.lua +++ b/src/main/resources/scripts/global.lua @@ -385,4 +385,72 @@ function mergeJson(base, with) 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 diff --git a/src/main/resources/scripts/world.lua b/src/main/resources/scripts/world.lua index ebf25d2c..0accd486 100644 --- a/src/main/resources/scripts/world.lua +++ b/src/main/resources/scripts/world.lua @@ -99,7 +99,7 @@ local function entityTypeNamesToIntegers(input, fullName) error('invalid entity type ' .. tostring(v) .. ' for ' .. fullName .. ' in types table at index ' .. i, 3) end - entityTypes[i] = lookup + input[i] = lookup end return input diff --git a/src/test/kotlin/ru/dbotthepony/kstarbound/test/LuaTests.kt b/src/test/kotlin/ru/dbotthepony/kstarbound/test/LuaTests.kt index 50a71ea6..a5fea6fc 100644 --- a/src/test/kotlin/ru/dbotthepony/kstarbound/test/LuaTests.kt +++ b/src/test/kotlin/ru/dbotthepony/kstarbound/test/LuaTests.kt @@ -13,19 +13,22 @@ object LuaTests { val lua = LuaThread() lua.push { - throw IllegalArgumentException("test!") + throw IllegalArgumentException("This is error message") } lua.storeGlobal("test") - val results = lua.call(5) { + lua.call { 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()) } - println(results) - println(results.last().toJson()) lua.close() } }