lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Paul Du Bois wrote:
Is it possible to re-enter a script with a prior context so that the lua_State of
one function can be used as the lua_State of another?

Yes; read up on coroutines. For example, this is what we do in our
engine right now:

function Ob:onTick(dt)
	local fn = rawget(self, 'current_statefunc')
	if fn then
		local bSuccess, result = coroutine.resume(fn, self, dt)
		if not bSuccess then
			Tracef("Error running state '%s':\n%s", self.current_state, result)
			if coroutine.status(fn) == "dead" then
				self.current_statefunc = nil

onTick gets called every frame/update/whatever. Often, anyway. An
object can call self:setState() on itself, which among other things,
sets up a particular function to be resumed every tick. The function
runs to completion or until it yields. The net effect is a system
where every object can pretend it has its own thread of execution.

Almost all of our object/script system is implemented in lua at the
moment (a switch from Psychonauts, which did stack manipulation and a
bunch of other stuff). This is very nice, as it allows you to play
with various semantics and implementation strategies. When you have
something you like, you can "freeze" it into C/C++ if you like, and if
it's worth it.


In our game, the dispatcher is written in C++. I handle both a Preemptive and Cooperative multitasking within the same script. For Cooperative, i have functions bound that call lua_yield on the coroutine, and can either yield for X seconds or N frames (at a later date, also yield until X condition). For preemptive, i use lua_hooks. I break into C++ every N instructions, check to see if the quantum is up, and yield if it is.

I can switch between both runmodels in the same script, so, for example, if block of script needs to execute atomically (as in, on the same frame), i change the runmodel to cooperative, and then change it back to preemptive.

An advantage of having this system is that I can pause a script, make it start again, reload it, and kill it without a problem.

Also, an implementation note: in the cooperative runmodel, i also use lua_Hook to make sure that the script doesn't do infinite loops and freeze the game. If it executes without yielding for more than X time, assert and then pause the script.

The concept of this was inspired by Matthew Harmon, from eV Interactive Corporation, and was featured in Game Programming Gems 5.

Hope this helps.

// David Morris-Oliveros
// Camera & Lua Coder