That said, I'm in favour of other approaches to this problem - using (i.e. generating) Lua bytecode itself as a way of maintaining state, and then pushing things around while having a good understanding of llimits.h seems to be quite important ..
That said, I'm in favour of other approaches to this problem - using (i.e. generating) Lua bytecode itself as a way of maintaining state, and then pushing things around while having a good understanding of llimits.h seems to be quite important ..
I have written an entire (popular) game engine that tightly integrated Lua and used custom-generated C++ bindings. I had to dig pretty deep into the Lua VM to accomplish that.
Heck, I found and fixed a bug in the LuaJIT 1.x series -- my fix integrated by Mike Pall, with a credit on the changes page.
The thing is if you encode game state into the program state, like using coroutines for complex, long-running AI tasks, for instance, then there's no way to save or restore that state if you're using LuaJIT. And Pluto saves the state in an opaque manner.
And as another commenter pointed out, if you want to update the game with new behaviors, god knows how that will interact with save states that have huge call stacks in them. And bug fixes? Yeah, since you're saving the whole program state at this point, bug fixes won't be incorporated in the restored image.
Most of the games and engines I've ever worked on that have dialog systems expressly avoid encoding things into the program state as much as reasonably possible. This is not only for restoring state, but also making for a saner experience editing and changing things during development. Very rarely does the format you encode things like dialog stay the same during a dev cycle unless you're using a canned engine and don't make any serious changes.
Using Lua program state itself seems like a way to drive yourself mad by the end of the dev cycle, and make it incredible unfriendly to work with writers and other content creators. People who work with asset pipelines often do a lot of cruel and unusual data conversions and munging to bridge how different people and systems need to work, but eventually things in the actual game engine are best kept as simple data that can be read in and reproduced at any time. Moreover, as a developer, I should be able to load up any state of my game at any point in the game just by providing the necessary input data as possible, and like a pure function, it should produce the same game state every time if possible. Let's also not forget other things like internationalization and localization.
As far as interfacing with Lua, I've mostly done it in the last few decades in a simple way where we handed entity component-style data that is just pure data, i.e. no function pointers and crazy stuff, and either let Lua do the rest with that state, or send pure data back to the C++ when needed. As for the data format itself, I've seen everything from XML to custom binary formats to CSV and Excel used for dialog. I think I'd sooner murder someone if game dialog lived in code, even in a Lua script.
A few reasons why in C++, C, and Lua, and in general in most game programming languages code is not the same as data:
- Tends not to be editor friendly
- Requires heavy meta programming to achieve the same as other formats
- Requires compilation and/or interpretation
- Is not necessarily idempotent depending on compiler options and platform. The same data should be the same cross-platform, and code is almost definitely not because at a minimum level, it can generate vastly different assembly depending on compiler flags or processor targets.
- Purely composite. I would argue that as much as we try, it's hard to compose a lot of code properly and without considerable effort in games. Conversely, composing data can be quite easy.
- Cannot on its own be serialized/deserialized easy while in a runtime state
- Not network transparent
- Cannot be compressed/decompressed in real-time as easily
See my points in other posts in this thread. I am assuming you downvoted me, which is ridiculous and childish, especially given your brief response without any reasoning or evidence despite being contrary to all computer science research.
Composition: see meta-tables. Repeat until completion.
It's telling that all the major game engines and a large portion of papers and talks disagree with you. If Lua was the solution to data-driven development, people wouldn't bend over backwards looking for solutions like entity component systems. Lua is nice, but not suitable for most professional game development as a primary language. As such, it makes it completely unsuitable because Lua data, especially things that depend on runtime state are utterly useless.
Your shipping comment also makes no sense in this context. Tons of other languages have more games shipped than Lua. There aren't too many people relying on Lua for composition and data-driven development in games, because it doesn't work. Even Lisp doesn't work in this context putting speed and other things aside, because of so many reasons I've already listed. Code in the context of game development is not data by the definition of data I am referencing.
"Proper use of byte code generators" -- at that point you're not writing Lua any more, any more than Scala or Clojure targeting the JVM is "writing Java." The article is about using Lua for AI, which is what my comments are about, and my comments all stand.
Arguing about whether the VM is good enough to support a state machine is orthogonal to whether it's a good idea to use Lua coroutines as suggested by the article.
[1] http://www.mobygames.com/developer/sheet/view/developerId,13...
For a similar problem of making the AI code for a bullet hell shmup, I thought it was very important to be able to edit the AI code easily to try out a lot of stuff. I've had decent experiences using BulletML and Lua for this, but both of them provide no path forward if I want to update the game and load an old save. Like, because I was not asked to explicitly name every single state in my "AI program", I cannot create a mapping between the possible old states and the possible new states to use when running the updated software against an old save. Then again, the fact that I was not asked to explicitly name every single state in my program feels like a pretty central component of the short iteration time I was after to begin with.
For shmup AI this maybe ends up being acceptable because the game doesn't need to run new behaviors against old save files. But if I did need that, maybe I should be using two systems, one for experimentation and another one for making something upgradable?