On 1/13/2010 3:38 AM, Jerome Vuarand wrote:
2010/1/8 Christopher Eykamp<email@example.com>:I'm the lead developer for Bitfighter (http://bitfighter.org), written in C++ and Lunar, and have been working on creating Lua scripted robot players for a while. There is one script per robot, and several robots could be running the same script, or each could be running a different one. Typically, I would expect no more than 10 robots would exist at any time. Currently, management is quite easy: we create a single Lua instance for each robot, each with a function that gets called one per game-cycle. Because they are running in their own instance, there is no possibility of one robot mucking up the environment of another, and it seems a very clean solution. When a robot is removed from the game, we simply delete the instance, and everything associated with that robot is gone. Lately, however, I've been thinking about adding event listeners to the robots, in the form of a series of functions with a name like "onPlayerAdded(player)", "onShipKilled(ship, killer)", etc. that would be called from C++ as needed. This complicates things a bit because instead of calling each script once per game cycle, we might be calling different functions within the same script a dozen times each cycle. Multiplied over the number of robots, this becomes a lot of calls, and I'm afraid of the increasing overhead this might incur. So I've been rethinking my original design, and am wondering if it might make sense to have the robots all running in a single process, which would get called once per event, with some sort of Lua management script calling the event handlers in each robot. Furthermore, management of timers and keeping track of which robots implement which listeners might be easier, as there could be one timer management script for all robots, rather than the current practice of one-per-robot. And it seems that keeping track of which robots implement which listener would be easier in Lua than in C++, which would also argue against the one-instance-per-bot design. So the question is what is the best architecture for this sort of problem? My two key goals are maintaining adequate performance, and making the bot scripting as simple as possible, which would seem to imply that each robot should feel like it has it's own global namespace. How have others addressed this issue?Whether you dispatch the event to the multiple listeners (the robots) in C or in some Lua script, the same amount of functions will be called. I can't tell which language would be the fastest to do it, but I suspect the difference is pretty small. So in the end it might not be worth giving up your clean robot separation for that little (if any) speed improvement.
My current thinking is that I would structure it like this:When a level starts, the C++ makes a list of all the robots that need to be created for the level, would tell lua to load the code (in one or may instances, yet to be decided). It would also launch a lua event handler which would examine each robot to see what events it listened for. (For example, if it were listening for a scoring event, it would have a function called onScore(player, score).) Not all robots would be listening for that, of course, and those bots would omit the function.
When a scoring event occurs, C++ would call the lua event handler, and tell it to fire the onScore event. The handler, having its list of bots that listen for that function, would call each bot's onScore function in turn.
Now what you are suggesting is that it doesn't really matter if the event manager is a lua script or resides in C++, that the multiple calls to lua would have little performance impact (and, given the small number of potential listeners, you are probably right).
It seems that if the event manager were in lua, that would require that all the robots run in the same instance -- I do not think that a script can call a function in different instance. If all the robots were running in the same instance, that would require managing the environment, which is an additional complexity. However, the tradeoff is that the C++ code would be simpler with a single event handler, and the managing of which robots were listening for which events would be easier to do in lua than in C++. Also, the timer events could be handled centrally rather than on a per-robot basis.
On balance, it seems that the additional complexity of running all the robots in one instance might be worth it, even if the performance gains are minimal.
On the downside, I'm still not sure exactly how to manage the environment (especially with setfenv being deprecated in 5.2), and I already have the bots working in separate instances, so I'll have to redesign something that is already working.
Does anyone know where I can find a good (simple) example of how to manage the environment so as to have multiple scripts running in single Lua instance, each in (nearly) complete isolation from one another?
Thanks for your help!