Jump to content
  • Advertisement
Sign in to follow this  
Guy Meh

Multiple AIs with one Lua state

This topic is 3397 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want the AIs of my NPCs to be stored in Lua scripts. The design I'm leaning towards is each AI type is defined in a script/file with a standard set of callbacks (e.g. "nextMove()") the engine would call. The script file may also have any global variables it needs if the AI using that script wants any state. This would be easy if each NPC had its own Lua state object. How would I do it with a single Lua state though? That is, how do I avoid function and variable names clashing between the scripts, or have NPCs with different AI state though they use the same script?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Guy Meh
how do I avoid function and variable names clashing between the scripts,

You could use the local keyword which restricts scope.
Quote:
have NPCs with different AI state though they use the same script?
Would you not store state in a table?

Share this post


Link to post
Share on other sites
Organization wise, it would probably look pretty similar to how you would do it without using Lua. You could have one big array (actually a table) at the global scope of the Lua state, called ALL_MY_NPCS or something. Inside this array, there would be a struct (also actually a table) for each NPC, which contains the state specific to that NPC.

Share this post


Link to post
Share on other sites
Quote:
Original post by CmpDev
You could use the local keyword which restricts scope.

Nice. I forgot about that. :)

Quote:
Would you not store state in a table?

Well, I suppose I could. I was originally thinking of each script being independent of each other, and each script could have whatever variables and structures it needs as long as it has the functions the game engine expects. Some AIs might not have any state, such as AIs that just make their NPCs move around randomly.

Quote:
Original post by pinacolada
You could have one big array (actually a table) at the global scope of the Lua state, called ALL_MY_NPCS or something. Inside this array, there would be a struct (also actually a table) for each NPC, which contains the state specific to that NPC.

So in my engine (outside Lua) the NPCs store the index their AI is kept in this Lua array? And each AI stores a table containing a reference to their functions as well as whatever state they have? I make special mention of the functions because the neither the engine nor the AI scripts make any assumptions about the different AIs. All that is known is a standard set of functions each script would have that gets called by the engine, and some of these functions do not necessarily have to do anything when called. I'm using polymorphism in a way, where there is an imaginary, pure abtract AI class and each Lua script is an implementation of this class.

Of course, I may have to rethink how I'll structure the AI scripts if I want to
jam all of them into a single Lua state.

Share this post


Link to post
Share on other sites
thank you. i just read it, but i don 't see how this might help us. they are talking about "more elegant ways" of achieving what we want without having multiple lua states, but they don't give a clear answer how these ways look like :/

Share this post


Link to post
Share on other sites
Sneftel's example towards the end of the thread he linked is how you might do it. It shows how you embed all the variables you need to keep track of in a table, so they don't interfere with any other script objects.

Share this post


Link to post
Share on other sites
I'm not even sure if I fully understand his code.. So let's see. My base class Entity contains the following:

Entity( const string &script )
{
m_strScriptFile = script;

Engine::GetScriptingSystem()->LoadScript( m_strScriptFile );
Engine::GetScriptingSystem()->RunFunction( m_strScriptFile, "Initialize" );
}

~Entity()
{
Engine::GetScriptingSystem()->RunFunction( m_strScriptFile, "Shutdown" );
}

void Update()
{
Engine::GetScriptingSystem()->RunFunction( m_strScriptFile, "Update" );
}


When I derive classes from this base class, i'd like to be able to just provide a different m_strScriptFile, and the Initialize/Shutdown/Update functions from that script file are being run, and the variables defined in this file do not interfere with variables from other files. The scripts should, however, have access to globally defined variables and functions/classes bound from the main executable.

How exactly can I make sure this works? Thank you for your patience.

Share this post


Link to post
Share on other sites
As mentioned you can use the keyword local to create a variable/table/function scoped to only that module ( the script file ), but since Lua has a shared global namespace anything you put into their can be overwritten by any other script ( there are a few ways to make protected tables ). So you can't have multiple script defining the same functions say :

function executeMe(){}

and expect Lua to tell them apart. You'll need to help Lua out and distinguish them in some way. The easiest way I can think of is to declare the function local and register it with some global table, like so:



--this function is only exist in the scope of this file.
local function executeMe(){}

--pushes a function into the global table with unique identifier
local node={source="my unique identifier, full path maybe?",func=function() executeMe(); end};
gGlobalExecuteTable[node.source]=node;

Now when it comes time to execute these execute functions, you can use the unique identifier to distinguish them, like so:

function executeGlobal(identifer)
if (gGlobalExecuteTable[identifer]==nil) then
return;
end
gGlobalExecuteTable[identifer].func();
end





This is just a simple example. That's a simple system and you don't have to mess with creating threads and stuff.

Good Luck!

EDIT:

I didn't see your latest post, but to use a single VM you have to load up the implementation of each script into the current VM using say loadfile and execute it using pcall or something, using the above registration scheme as an example, that will put that scripts main hook functions (Initialize,Shutdown,Update) into the global table, which then u can use the string m_strScriptFile as a unique identifier.

That solve the problem of registering and calling these functions but it doesn't solve the problem of storing away each AI instance state nor prevent the possibility of scripts overwriting each others global functions.

Easiest method is to have each AI instance passed into these functions and don't let the functions keep any persistent data outside of those instances. They should just be pure functions.

As for the problem of scripts overwriting each others global functions, you'll have to organize your code or perhaps look into cloning global tables.

Good Luck!

-ddn

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!