lua-users home
lua-l archive

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


On 2/10/06, Guy Davidson <guy@creative-assembly.co.uk> wrote:
> First post - hi everyone!  My name is Guy.  You might remember me from such products as Rome:Total War where I wrote the scripting language.

Hello, Guy! If you're heading to the GDC, you may be interested in the
Lua roundtable that Dave Dixon and I are doing.

> Firstly, my "batch files" can't do control structures.
> I am merely passing each command to luaL_loadbuffer and lua_pcall
> which means that "for" gets short shrift.

This doesn't make sense to me. The buffer you're passing should be
able to contain a for loop, no problem. I'm probably not understanding
your use case?

> It seems to be the case that the interpreter collects together commands within
> structures and executes them when the structure is complete.  Is that correct?

The way I think of it is that lua_load* return a thunk (function of 0
arguments), and then you call it. The contents of that function are up
to you. Most commonly, it either contains a bunch of function
definitions or a class definition (loading a .lua file) or it contains
some function call (executing a console command).

> Next, we want to use Lua as a scripting language.  Now, we are clearly
> suffering a bit of a semantic cock-up here, as everyone on the team seems
> to have a different idea of what a scripting language is.

Common problem; can't help you here :-). But one key thing to realize
is that as a general purpose tool, Lua can be used in many different
places. It's okay to have more than one lua interpreter running around
your engine (one for config files, one for AI scripting, one for the
console, one for ...), just as it's fine to have many different sorts
of matrices (3x3s for rotation, 4x4s for general transformation, NxN
for least-squares fitting, ...)

> Some things have worried me about this during my investigations.  In Rome the scripting language had a concept of game time, and you could suspend execution for a few seconds while the game did its thing.

No worries. We did a ton of this in Psychonauts, and we were stuck
with Lua 4 which didn't have coroutines. Some of our usage was
informed by experience with UnrealScript (which is both event-based
and blocking). UnrealScript is a little constrained in that you cannot
yield execution at arbitrary points. Anyway, it is perfectly possible
in our system to write code like:

while true do some_work(); sleep(1) end

> it strikes at the heart of the language and suggests I'm in the wrong place.

Nope. You may have to roll your own semantics, but a lot of lua is
like that. The heavy-lifting machinery is all in place for you.

> Additionally, we had interrupts. ... I imagine I would implement this by putting a
> lua_pcall construct at the event dispatch, and calling the polling functions at every tick.

Yes, or something similar (you may find that it's quicker to pcall
once and poll your objects within lua, because of setjmp overhead, but
that's an implementation detail)

> Is it possible to direct Lua to "execute only the next instruction in the script"
> regardless of whether it's in a loop?

This isn't really what you want...

> 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)
			self:setState(nil)
		else
			if coroutine.status(fn) == "dead" then
				self.current_statefunc = nil
			end
		end
	end
end

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.

p