Advertisement

Implementing a wait in LUA

Started by June 26, 2004 07:10 AM
2 comments, last by Monder 20 years, 4 months ago
I'm writing a 2D RPG engine in C using LUA for scripting and I want to implement a function in LUA that when called pauses script execution until a specified event occurs e.g. NPCMove(NPC1, 20, 20) waitForNPCMove(NPC1) It wouldn't look exactly like that but you should get the idea. At first I thought I could implement this with coroutines, however there is a snag, if I did do it with coroutines I'd have to create a new thread with lua_newthread( ) and then call a function, the waitForNPCMove statement would then be in that function and would do add the script to a list of scripts waiting for something and then do a lua_yield( ), when the event happened scripting execution would continue using lua_resume( ). I'd don't like this way of doing things though because it means I cannot shove a waitForNPCMove call anywhere in a LUA script, I'd have to explicitly call a function to create a new thread and execute a function that had the waitForNPCMove call in it and creating a new thread creates a new lua_state which means the thread function could not alter stuff in the main script (well not easily and transparently anyway). Can anyone think of a better way to acomplish this?
Altering stuff in the main script should be easy because separate threads share the globals with the original state. All your shared info just has to go into the globals area, which I doubt would be difficult. If you make all scripts run in their own thread, it should be quite simple and you can use those calls anywhere.
Advertisement
I have been investigating this.

Basically what you cannot do, is call yield from a C/C++ function. However, you can have a lua function which wraps it and calls yield.

Here is my current prototype. The lua function actions() is called with the "me" parameter containing a reference to the NPC object (which is a luabind bound C++ object pointer)

function actions(me)        me:walkTo(42,99) -- returns immediately        while (not me:hasArrived()) do          print("Not there yet")          coroutine.yield()        end        print("Yay, got there")end


When the NPC is created, they will initially create a coroutine object by calling the lua function startroutine(me).

Then when something interesting happens, we want to tell lua about, it calls resumeroutine, passing in the coroutine as a param...

function startroutine(me)        local co = coroutine.create(actions)        coroutine.resume(co,me)        return coendfunction resumeroutine(co)        coroutine.resume(co)end


The C++ will keep the result of calling startroutine() in a luabind::object variable, which wraps the coroutine.

Note that this will not busy-wait, as long as we don't call resumeroutine when nothing interesting is happening.

Mark
Quote: Altering stuff in the main script should be easy because separate threads share the globals with the original state. All your shared info just has to go into the globals area, which I doubt would be difficult. If you make all scripts run in their own thread, it should be quite simple and you can use those calls anywhere.


Just read the docs again, and it appears I misread them, I thought it created a copy of the global environment, when it actually shares it. [smile]

In which case I think I'll implement it like this, currently every loaded script has it's own lua_state and when calling a function in the lua script I just use lua_pcall. I will alter this so that when I want to call a lua function from c it creates a new thread and runs the function in that, then I use lua_yield and lua_resume from c and I can easily implement stuff such as waitForNPCMove.

I guess this just teaches me to read the documentation more carefully next time, thanks for the help. [smile]

This topic is closed to new replies.

Advertisement