javalualuaj

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


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!


Solution

  • Seems like you are missing asynchronous pattern. If c=35 has to be executed once character occurs at (24,359), then the correct way is to pass function() c=35 end as third argument to walk method and your engine (that performs actual 'walking') will call that callback when appropriate.

    character.walkTo(24, 359, function ()
        c = 35
    end)
    

    Otherwise, walk may schedule walking to engine and yield immediately, resuming on correct event. In this case you have to setup script worker-coroutine (you cannot yield in main state).

    script = coroutine.wrap(function ()
        character.walkTo(24, 359) -- will yield and leave callable global 'script'
        c = 35
    end)
    script() -- resume first time
    -- here script is over
    
    ...
    
    -- this wrapper may be implemented in Lua or host language
    
    function character.walkTo(x, y)
        engine.startActualWalkingTo(x, y)
        coroutine.yield() -- yields to host
        -- coroutine.resume() will continue here
    end
    
    ...
    
    -- somewhere in engine code (pseudo-code here)
    
    for event in eventLoop do
        if character.x == endPoint.x and character.y == endPoint.y then
            script() -- resume again at c=35
        end
    end
    

    You may cancel the script anytime with script=nil.

    yield() has some limitations, consult the manual.