From bb33d9e38119076d2c188fa577d9ad0cb22416f7 Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Sat, 4 Feb 2017 22:53:36 +0900 Subject: [PATCH] Actually utilising ActorAI interface to support AIs written in Kotlin as well as in Lua Former-commit-id: 53901f5a5d53b33c4254091ec507be82289d57fd Former-commit-id: 86ce8d2a646a1564ee5e33ef07c5affb338c028e --- .../terrarum/gameactors/AIControlled.kt | 4 +- .../terrarum/gameactors/HumanoidNPC.kt | 101 ++-------------- .../gameactors/PlayerBuilderCynthia.kt | 6 +- .../torvald/terrarum/gameactors/ai/ActorAI.kt | 1 + .../terrarum/gameactors/ai/LuaAIWrapper.kt | 113 ++++++++++++++++++ .../terrarum/itemproperties/ItemProp.kt | 9 -- 6 files changed, 133 insertions(+), 101 deletions(-) create mode 100644 src/net/torvald/terrarum/gameactors/ai/LuaAIWrapper.kt delete mode 100644 src/net/torvald/terrarum/itemproperties/ItemProp.kt diff --git a/src/net/torvald/terrarum/gameactors/AIControlled.kt b/src/net/torvald/terrarum/gameactors/AIControlled.kt index 3ac7536c5..bd23d2ccf 100644 --- a/src/net/torvald/terrarum/gameactors/AIControlled.kt +++ b/src/net/torvald/terrarum/gameactors/AIControlled.kt @@ -1,12 +1,14 @@ package net.torvald.terrarum.gameactors +import net.torvald.terrarum.gameactors.ai.ActorAI + /** * Note: AI-controlled actor must be 'Controllable' * * Created by minjaesong on 16-01-31. */ interface AIControlled { - val scriptPath: String + val ai: ActorAI fun moveLeft(amount: Float = 1f) fun moveRight(amount: Float = 1f) diff --git a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt index 456c9e405..0959cfb36 100644 --- a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt +++ b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.gameactors import net.torvald.terrarum.gameactors.ActorHumanoid import net.torvald.terrarum.gameactors.ai.AILuaAPI +import net.torvald.terrarum.gameactors.ai.ActorAI import net.torvald.terrarum.gameitem.EquipPosition import net.torvald.terrarum.gameitem.InventoryItem import org.luaj.vm2.* @@ -16,19 +17,14 @@ import java.io.InputStreamReader import java.io.Reader /** + * @param ai AI class. Use LuaAIWrapper for Lua script + * * Created by minjaesong on 16-01-31. */ -open class HumanoidNPC(override val scriptPath: String, born: GameDate) : ActorHumanoid(born), AIControlled, CanBeAnItem { - - protected val luag: Globals = JsePlatform.standardGlobals() - - /** - * Initialised in init block. - * Use lua function "update(delta)" to step the AI. - */ - protected val luaInstance: LuaValue - - private val aiLuaAPI: AILuaAPI +open class HumanoidNPC( + override val ai: ActorAI, // it's there for written-in-Kotlin, "hard-wired" AIs + born: GameDate +) : ActorHumanoid(born), AIControlled, CanBeAnItem { companion object { val DEFAULT_COLLISION_TYPE = ActorWithSprite.COLLISION_DYNAMIC @@ -36,28 +32,16 @@ open class HumanoidNPC(override val scriptPath: String, born: GameDate) : ActorH init { collisionType = DEFAULT_COLLISION_TYPE - - luag["io"] = LuaValue.NIL - luag["os"] = LuaValue.NIL - luag["luajava"] = LuaValue.NIL - aiLuaAPI = AILuaAPI(luag, this) - // load the script and execute it (initialises target script) - val inputStream = javaClass.getResourceAsStream(scriptPath) - luaInstance = luag.load(InputStreamReader(inputStream), scriptPath.split(Regex("[\\/]")).last()) - luaInstance.call() } // we're having InventoryItem data so that this class could be somewhat universal override var itemData: InventoryItem = object : InventoryItem() { override var id = referenceID - override val equipPosition: Int = EquipPosition.HAND_GRIP - override var mass: Double + override var baseMass: Double get() = actorValue.getAsDouble(AVKey.BASEMASS)!! - set(value) { - actorValue[AVKey.BASEMASS] = value - } - + set(value) { actorValue[AVKey.BASEMASS] = value } + override var baseToolSize: Double? = 0.0 override var scale: Double get() = actorValue.getAsDouble(AVKey.SCALE)!! set(value) { @@ -85,9 +69,7 @@ open class HumanoidNPC(override val scriptPath: String, born: GameDate) : ActorH override fun update(gc: GameContainer, delta: Int) { super.update(gc, delta) - - // run "update()" function in the script - luag.get("update").call(delta.toLuaValue()) + ai.update(delta) } override fun moveLeft(amount: Float) { // hit the buttons on the controller box @@ -121,65 +103,4 @@ open class HumanoidNPC(override val scriptPath: String, born: GameDate) : ActorH // if your NPC should fly, override this throw UnsupportedOperationException("Humans cannot fly :p") } - - var currentExecutionThread = Thread() - var threadRun = false - - fun runCommand(reader: Reader, filename: String) { - if (!threadRun && !flagDespawn) { - currentExecutionThread = Thread(ThreadRunCommand(luag, reader, filename)) - currentExecutionThread.start() - threadRun = true - } - } - - fun runCommand(script: String) { - if (!threadRun && !flagDespawn) { - currentExecutionThread = Thread(ThreadRunCommand(luag, script, "")) - currentExecutionThread.start() - threadRun = true - } - } - - class ThreadRunCommand : Runnable { - - val mode: Int - val arg1: Any - val arg2: String - val lua: Globals - - constructor(luaInstance: Globals, line: String, env: String) { - mode = 0 - arg1 = line - arg2 = env - lua = luaInstance - } - - constructor(luaInstance: Globals, reader: Reader, filename: String) { - mode = 1 - arg1 = reader - arg2 = filename - lua = luaInstance - } - - override fun run() { - try { - val chunk: LuaValue - if (mode == 0) - chunk = lua.load(arg1 as String, arg2) - else if (mode == 1) - chunk = lua.load(arg1 as Reader, arg2) - else - throw IllegalArgumentException("Unsupported mode: $mode") - - - chunk.call() - } - catch (e: LuaError) { - e.printStackTrace(System.err) - } - } - } - - fun Int.toLuaValue(): LuaValue = LuaInteger.valueOf(this) } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/PlayerBuilderCynthia.kt b/src/net/torvald/terrarum/gameactors/PlayerBuilderCynthia.kt index 428f03eca..543f293c5 100644 --- a/src/net/torvald/terrarum/gameactors/PlayerBuilderCynthia.kt +++ b/src/net/torvald/terrarum/gameactors/PlayerBuilderCynthia.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.gameactors import net.torvald.spriteanimation.SpriteAnimation import net.torvald.terrarum.gameactors.ActorHumanoid +import net.torvald.terrarum.gameactors.ai.LuaAIWrapper import net.torvald.terrarum.mapdrawer.FeaturesDrawer /** @@ -11,9 +12,12 @@ object PlayerBuilderCynthia { operator fun invoke(): ActorWithSprite { //val p: Player = Player(GameDate(100, 143)) // random value thrown - val p: HumanoidNPC = HumanoidNPC("/net/torvald/terrarum/gameactors/ai/scripts/PokemonNPCAI.lua", + val p: HumanoidNPC = HumanoidNPC( + LuaAIWrapper("/net/torvald/terrarum/gameactors/ai/scripts/PokemonNPCAI.lua"), GameDate(100, 143)) // random value thrown InjectCreatureRaw(p.actorValue, "CreatureHuman.json") + (p.ai as LuaAIWrapper).attachActor(p) + p.actorValue[AVKey.__PLAYER_QUICKBARSEL] = 0 p.actorValue[AVKey.NAME] = "Cynthia" diff --git a/src/net/torvald/terrarum/gameactors/ai/ActorAI.kt b/src/net/torvald/terrarum/gameactors/ai/ActorAI.kt index ea8b15739..7e30c8d5f 100644 --- a/src/net/torvald/terrarum/gameactors/ai/ActorAI.kt +++ b/src/net/torvald/terrarum/gameactors/ai/ActorAI.kt @@ -4,4 +4,5 @@ package net.torvald.terrarum.gameactors.ai * Created by minjaesong on 16-03-02. */ interface ActorAI { + fun update(delta: Int) } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/ai/LuaAIWrapper.kt b/src/net/torvald/terrarum/gameactors/ai/LuaAIWrapper.kt new file mode 100644 index 000000000..00b41cefb --- /dev/null +++ b/src/net/torvald/terrarum/gameactors/ai/LuaAIWrapper.kt @@ -0,0 +1,113 @@ +package net.torvald.terrarum.gameactors.ai + +import net.torvald.terrarum.gameactors.Actor +import net.torvald.terrarum.gameactors.ActorWithSprite +import org.luaj.vm2.Globals +import org.luaj.vm2.LuaError +import org.luaj.vm2.LuaInteger +import org.luaj.vm2.LuaValue +import org.luaj.vm2.lib.jse.JsePlatform +import java.io.InputStreamReader +import java.io.Reader + +/** + * Created by SKYHi14 on 2017-02-04. + */ +class LuaAIWrapper(private val scriptPath: String) : ActorAI { + + protected val luag: Globals = JsePlatform.standardGlobals() + + /** + * Initialised in init block. + * Use lua function "update(delta)" to step the AI. + */ + protected lateinit var luaInstance: LuaValue + + private lateinit var aiLuaAPI: AILuaAPI + + private lateinit var targetActor: ActorWithSprite + + /** + * The initialiser + * + * Use ```(p.ai as LuaAIWrapper).attachActor(p)``` + */ + fun attachActor(actor: ActorWithSprite) { + targetActor = actor + + luag["io"] = LuaValue.NIL + luag["os"] = LuaValue.NIL + luag["luajava"] = LuaValue.NIL + aiLuaAPI = AILuaAPI(luag, targetActor) + // load the script and execute it (initialises target script) + val inputStream = javaClass.getResourceAsStream(scriptPath) + luaInstance = luag.load(InputStreamReader(inputStream), scriptPath.split(Regex("[\\/]")).last()) + luaInstance.call() + } + + override fun update(delta: Int) { + // run "update()" function in the script + luag.get("update").call(delta.toLuaValue()) + } + + var currentExecutionThread = Thread() + var threadRun = false + + fun runCommand(reader: Reader, filename: String) { + if (!threadRun && !targetActor.flagDespawn) { + currentExecutionThread = Thread(ThreadRunCommand(luag, reader, filename)) + currentExecutionThread.start() + threadRun = true + } + } + + fun runCommand(script: String) { + if (!threadRun && !targetActor.flagDespawn) { + currentExecutionThread = Thread(ThreadRunCommand(luag, script, "")) + currentExecutionThread.start() + threadRun = true + } + } + + class ThreadRunCommand : Runnable { + + val mode: Int + val arg1: Any + val arg2: String + val lua: Globals + + constructor(luaInstance: Globals, line: String, env: String) { + mode = 0 + arg1 = line + arg2 = env + lua = luaInstance + } + + constructor(luaInstance: Globals, reader: Reader, filename: String) { + mode = 1 + arg1 = reader + arg2 = filename + lua = luaInstance + } + + override fun run() { + try { + val chunk: LuaValue + if (mode == 0) + chunk = lua.load(arg1 as String, arg2) + else if (mode == 1) + chunk = lua.load(arg1 as Reader, arg2) + else + throw IllegalArgumentException("Unsupported mode: $mode") + + + chunk.call() + } + catch (e: LuaError) { + e.printStackTrace(System.err) + } + } + } + + fun Int.toLuaValue(): LuaValue = LuaInteger.valueOf(this) +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/itemproperties/ItemProp.kt b/src/net/torvald/terrarum/itemproperties/ItemProp.kt deleted file mode 100644 index 27e348377..000000000 --- a/src/net/torvald/terrarum/itemproperties/ItemProp.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.torvald.terrarum.itemproperties - -/** - * Created by minjaesong on 16-03-18. - */ -internal data class ItemProp ( - var baseMass: Float, - var material: Material -) \ No newline at end of file