Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to execute a single lua statement from a host program?

Tags:

java

lua

luaj

I am trying to embed a lua-based script system into my game engine. I would like the scripting to be able to have both blocking and non-blocking commands, for example:

character.walkTo(24, 359);  // Blocks until character arrives
c = 35; // Non blocking, execution goes on to the next statement

Since the "walkTo" needs to be "active" for more than 1 frame of execution, I would like to be able to run 1 statement at time from the Java host instead of the whole function. This is because it would be overkill to have real multithreading, which is not needed.

If I could execute just 1 statement, and keep the execution state "paused" until next statement execution, I would be able to implement blocking commands like "walkTo" by checking if the command is finished in the host, and if it is, go on to the next statement, otherwise, wait until the next frame iteration.

Is there any way to execute 1 statement a time from the Java host with LuaJ(or with any other Lua api), or am I forced to develop my own script engine with lex and yacc?

Any good idea is welcome, thanks!

like image 618
Lake Avatar asked Dec 21 '14 10:12

Lake


1 Answers

Bonus answer for everyone who is sticking with this problem.

Here is my exact solution:

-- test.lua --

onLookAt = function()
    character:walkTo(234, 35)
    print("Arrived!")
end

-- LuaTest.java --

public static void luaTest() {
    Globals g = JsePlatform.standardGlobals();
    g.load(new CoroutineLib());

    g.set("character", CoerceJavaToLua.coerce(new Character(g)));
    g.load(Gdx.files.internal("test.lua").reader(), "test.lua").call();
    g.load("co = coroutine.wrap(onLookAt)").call();
    g.get("co").call();
    try {
        // Simulate time that passes while the script is paused
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    g.get("co").call();
}

public static class Character{
    Globals g;

    public Character(Globals g){
        this.g = g;
    }

    public void walkTo(int x, int y) {
        System.out.println("Started walking.");
        g.yield(LuaValue.NONE);
    }
}

-- Output --

Started walking.

(2 seconds later)

Arrived!

One thing you should be very careful about:

  • Do NOT use java's ScriptEngine interface if you want to accomplish this. ScriptEngine interface doesn't provide API for obtaining the implicitly allocated Globals instance that you need for yielding, and making a new instance of Globals and using that for yielding is obviously pointless.
like image 54
Lake Avatar answered Oct 07 '22 21:10

Lake