From c65b17deecb6175ec877aa5966cdd4625a61a6f9 Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Mon, 24 Oct 2016 13:36:09 +0900 Subject: [PATCH] AI API Former-commit-id: 7821931c73c0d90a883b3732eb5a950c2b2a0402 Former-commit-id: b77ed6d9cc3effd183646a7e0c8411b4e125cfd2 --- src/net/torvald/colourutil/CIELChabUtil.kt | 8 +- src/net/torvald/colourutil/CIELabUtil.kt | 14 ++- src/net/torvald/colourutil/CIELuvUtil.kt | 10 +- src/net/torvald/terrarum/StateInGame.kt | 2 +- .../terrarum/gameactors/AIControlled.kt | 2 +- .../terrarum/gameactors/HumanoidNPC.kt | 96 ++++++++++++++++-- .../terrarum/gameactors/ai/AILuaAPI.kt | 98 +++++++++++++++++++ 7 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt diff --git a/src/net/torvald/colourutil/CIELChabUtil.kt b/src/net/torvald/colourutil/CIELChabUtil.kt index 0faa161b6..f172de786 100644 --- a/src/net/torvald/colourutil/CIELChabUtil.kt +++ b/src/net/torvald/colourutil/CIELChabUtil.kt @@ -1,6 +1,8 @@ package net.torvald.colourutil import com.jme3.math.FastMath +import net.torvald.colourutil.CIELChUtil.toLCh +import net.torvald.colourutil.CIELChUtil.toLab import net.torvald.colourutil.CIELabUtil.toLab import net.torvald.colourutil.CIELabUtil.toRGB import net.torvald.colourutil.CIELabUtil.toXYZ @@ -49,15 +51,15 @@ object CIELChUtil { return CIELab(L, a, b, alpha) } - fun Color.toLCh() = this.toXYZ().toLab().toLCh() - fun CIELCh.toRGB() = this.toLab().toXYZ().toRGB() - private fun Float.sqr() = this * this private fun Float.sqrt() = Math.sqrt(this.toDouble()).toFloat() private fun Float.abs() = FastMath.abs(this) } +fun Color.toLCh() = this.toXYZ().toLab().toLCh() +fun CIELCh.toRGB() = this.toLab().toXYZ().toRGB() + /** * @param L : Luminosity in 0.0 - 1.0 * @param C : Chroma (saturation) in 0.0 - 1.0 diff --git a/src/net/torvald/colourutil/CIELabUtil.kt b/src/net/torvald/colourutil/CIELabUtil.kt index ed825a8e2..ebd682bf5 100644 --- a/src/net/torvald/colourutil/CIELabUtil.kt +++ b/src/net/torvald/colourutil/CIELabUtil.kt @@ -1,6 +1,10 @@ package net.torvald.colourutil import com.jme3.math.FastMath +import net.torvald.colourutil.CIELabUtil.toLab +import net.torvald.colourutil.CIELabUtil.toRGB +import net.torvald.colourutil.CIELabUtil.toRawRGB +import net.torvald.colourutil.CIELabUtil.toXYZ import org.newdawn.slick.Color /** @@ -47,11 +51,6 @@ object CIELabUtil { return CIELab(newL, newA, newB, newAlpha).toRGB() } - fun Color.toLab() = this.toXYZ().toLab() - fun RGB.toLab() = this.toXYZ().toLab() - fun CIELab.toRGB() = this.toXYZ().toRGB() - fun CIELab.toRawRGB() = this.toXYZ().toRawRGB() - fun RGB.toXYZ(): CIEXYZ { val newR = if (r > 0.04045f) ((r + 0.055f) / 1.055f).powerOf(2.4f) @@ -133,6 +132,11 @@ object CIELabUtil { private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp) } +fun Color.toLab() = this.toXYZ().toLab() +fun RGB.toLab() = this.toXYZ().toLab() +fun CIELab.toRGB() = this.toXYZ().toRGB() +fun CIELab.toRawRGB() = this.toXYZ().toRawRGB() + internal val D65 = CIEXYZ(0.95047f, 1.00f, 1.08883f) val epsilon = 216f/24389f val kappa = 24389f/27f diff --git a/src/net/torvald/colourutil/CIELuvUtil.kt b/src/net/torvald/colourutil/CIELuvUtil.kt index 2d090cab9..6f096e04d 100644 --- a/src/net/torvald/colourutil/CIELuvUtil.kt +++ b/src/net/torvald/colourutil/CIELuvUtil.kt @@ -5,6 +5,8 @@ import org.newdawn.slick.Color import net.torvald.colourutil.CIELabUtil.toXYZ import net.torvald.colourutil.CIELabUtil.toRawRGB import net.torvald.colourutil.CIELabUtil.toRGB +import net.torvald.colourutil.CIELuvUtil.toLuv +import net.torvald.colourutil.CIELuvUtil.toXYZ /** * A modification of CIEXYZ that is useful for additive mixtures of lights. @@ -91,14 +93,14 @@ object CIELuvUtil { return CIEXYZ(X, Y, Z, alpha) } - fun Color.toLuv() = this.toXYZ().toLuv() - fun CIELuv.toRawRGB() = this.toXYZ().toRawRGB() - fun CIELuv.toRGB() = this.toXYZ().toRGB() - private fun Float.cbrt() = FastMath.pow(this, 1f / 3f) private fun Float.cube() = this * this * this } +fun Color.toLuv() = this.toXYZ().toLuv() +fun CIELuv.toRawRGB() = this.toXYZ().toRawRGB() +fun CIELuv.toRGB() = this.toXYZ().toRGB() + /** * Range: * L: 0-100.0 diff --git a/src/net/torvald/terrarum/StateInGame.kt b/src/net/torvald/terrarum/StateInGame.kt index 4724b9fd9..a7288ed97 100644 --- a/src/net/torvald/terrarum/StateInGame.kt +++ b/src/net/torvald/terrarum/StateInGame.kt @@ -272,7 +272,7 @@ constructor() : BasicGameState() { // make camara work // - // compensate for zoom. UIs have to be treated specially! (see UIHandler) + // compensate for zoom. UIs must be treated specially! (see UIHandler) g.translate(-MapCamera.cameraX * screenZoom, -MapCamera.cameraY * screenZoom) diff --git a/src/net/torvald/terrarum/gameactors/AIControlled.kt b/src/net/torvald/terrarum/gameactors/AIControlled.kt index 27792ee7d..deff1bb25 100644 --- a/src/net/torvald/terrarum/gameactors/AIControlled.kt +++ b/src/net/torvald/terrarum/gameactors/AIControlled.kt @@ -8,5 +8,5 @@ import net.torvald.terrarum.gameactors.ai.ActorAI * Created by minjaesong on 16-03-14. */ interface AIControlled { - var actorAI: ActorAI + val scriptPath: String } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt index f5a87fe2a..b4e6d2ec9 100644 --- a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt +++ b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt @@ -1,20 +1,41 @@ package net.torvald.terrarum.gameactors import net.torvald.terrarum.console.ActorHumanoid -import net.torvald.terrarum.gameactors.ai.ActorAI -import net.torvald.terrarum.gameactors.faction.Faction import net.torvald.terrarum.gameitem.InventoryItem -import net.torvald.terrarum.realestate.RealEstateUtility.getAbsoluteTileNumber +import org.luaj.vm2.Globals +import org.luaj.vm2.LoadState +import org.luaj.vm2.LuaError +import org.luaj.vm2.LuaValue +import org.luaj.vm2.compiler.LuaC +import org.luaj.vm2.lib.* +import org.luaj.vm2.lib.jse.JseBaseLib +import org.luaj.vm2.lib.jse.JseMathLib import org.newdawn.slick.GameContainer -import java.util.* +import java.io.InputStreamReader +import java.io.Reader /** * Created by minjaesong on 16-03-14. */ -open class HumanoidNPC(born: GameDate) : ActorHumanoid(born), AIControlled, CanBeAnItem { +open class HumanoidNPC(aiFile: String, born: GameDate) : ActorHumanoid(born), AIControlled, CanBeAnItem { - override var actorAI: ActorAI = object : ActorAI { - // TODO fully establish ActorAI so that I can implement AI here + override val scriptPath: String = aiFile + + companion object { + protected val luag = Globals() + + init { + luag.load(JseBaseLib()) + luag.load(TableLib()) + luag.load(StringLib()) + luag.load(TableLib()) + luag.load(CoroutineLib()) + luag.load(Bit32Lib()) + luag.load(PackageLib()) + luag.load(JseMathLib()) + LoadState.install(luag) + LuaC.install(luag) + } } // we're having InventoryItem data so that this class could be somewhat universal @@ -74,4 +95,65 @@ open class HumanoidNPC(born: GameDate) : ActorHumanoid(born), AIControlled, CanB } + init { + val inputStream = javaClass.getResourceAsStream(scriptPath) + runCommand(InputStreamReader(inputStream), scriptPath) + } + + + override fun update(gc: GameContainer, delta: Int) { + super.update(gc, delta) + + } + + 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 + } + } + + 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) + } + } + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt b/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt new file mode 100644 index 000000000..470ce84f0 --- /dev/null +++ b/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt @@ -0,0 +1,98 @@ +package net.torvald.terrarum.gameactors.ai + +import net.torvald.colourutil.CIELab +import net.torvald.colourutil.CIELabUtil +import net.torvald.colourutil.RGB +import net.torvald.colourutil.toLab +import net.torvald.terrarum.gameactors.AVKey +import net.torvald.terrarum.gameactors.ActorWithBody +import net.torvald.terrarum.mapdrawer.LightmapRenderer +import org.luaj.vm2.Globals +import org.luaj.vm2.LuaFunction +import org.luaj.vm2.LuaTable +import org.luaj.vm2.LuaValue +import org.luaj.vm2.lib.ZeroArgFunction + +/** + * Created by minjaesong on 16-10-24. + */ +internal class AILuaAPI(g: Globals, actor: ActorWithBody) { + + init { + // load things. WARNING: THIS IS MANUAL! + g["ai"] = LuaValue.tableOf() + g["ai"]["getNearestActor"] = GetNearestActor() + g["ai"]["getNearestPlayer"] = GetNearestPlayer() + g["ai"]["getX"] = GetX(actor) + g["ai"]["getY"] = GetY(actor) + } + + companion object { + fun composeActorObject(actor: ActorWithBody): LuaTable { + val t = LuaValue.tableOf() + + t["name"] = actor.actorValue.getAsString(AVKey.NAME) + t["posX"] = actor.hitbox.centeredX + t["posY"] = actor.hitbox.centeredY + + t["veloX"] = actor.veloX + t["veloY"] = actor.veloY + + t["width"] = actor.hitbox.width + t["height"] = actor.hitbox.height + + val lumrgb: Int = actor.actorValue.getAsInt(AVKey.LUMINOSITY) ?: 0 + t["luminosity_rgb"] = lumrgb + t["luminosity"] = RGB( // perceived luminosity + lumrgb.div(LightmapRenderer.MUL_2).mod(LightmapRenderer.MUL) / LightmapRenderer.CHANNEL_MAX_FLOAT, + lumrgb.div(LightmapRenderer.MUL_2).mod(LightmapRenderer.MUL) / LightmapRenderer.CHANNEL_MAX_FLOAT, + lumrgb.div(LightmapRenderer.MUL_2).mod(LightmapRenderer.MUL) / LightmapRenderer.CHANNEL_MAX_FLOAT + ).toLab().L.div(100.0) + + return t + } + } + + /** ai.getNearestActor(nullable any criterion, nullable number range) */ + class GetNearestActor() : LuaFunction() { + override fun call(): LuaValue { + return LuaValue.NONE + } + + override fun call(crit: LuaValue): LuaValue { + return LuaValue.NONE + } + + override fun call(crit: LuaValue, range: LuaValue): LuaValue { + return LuaValue.NONE + } + } + + /** ai.getNearestPlayer(nullable any criterion, nullable number range) */ + class GetNearestPlayer() : LuaFunction() { + override fun call(): LuaValue { + return LuaValue.NONE + } + + override fun call(crit: LuaValue): LuaValue { + return LuaValue.NONE + } + + override fun call(crit: LuaValue, range: LuaValue): LuaValue { + return LuaValue.NONE + } + } + + class GetX(val actor: ActorWithBody) : ZeroArgFunction() { + override fun call(): LuaValue { + return LuaValue.valueOf(actor.hitbox.centeredX) + } + } + + class GetY(val actor: ActorWithBody) : ZeroArgFunction() { + override fun call(): LuaValue { + return LuaValue.valueOf(actor.hitbox.centeredY) + } + } + +} \ No newline at end of file