So Ive been delving into LUA the last week or so and really love its possibilities and honestly just as something to play around in.
I have a long standing personal project Ive been working on for about 2 years, (a custom base in C++). Now that I have alot of the base fundamentals (things(Creatures, objects), brains, a world, sql based content pipeline, I really want to delve on the user development aspects, and add life to the game as well.
Over 15 years ago I started on MERC, Circle, SMAUG, and their OLC and MobProg systems really brought the games to life. Games now a days like Aardwolf have robust LUA functionality for their programs, though while not really seeing how it works under the hood, I was hoping there was a different way to go about it.
While I understand the fundamentals of the LUA language now, and the basics of embedding LUA into a C/C++ application, I am still caught up on some of the implementation possibilities and the route one should take.
So some questions if you would indulge me :)
It seems as though alot of implementations on Circle and Aardwolf for example, constantly execute scripts based on triggers. One LUA File to a trigger, and its continuously loaded on use with metatables and userdata being passed to it to gain access to real time variables and methods?
Is it nessacary to constantly load scripts and constantly be pushing metatable/data userdata to the lua stack and deleting it? Or can it stay there and be persistant with the object its linked to (and its script? One file per Entity (its encompassing behavior, movement, combat, entering a room, say phrases etc) is my goal..)
Maybe this can stir up the topic and I can get my head around this more. Ive looked at Nick's code for players and resets, but there doesnt seem to be much else out there.
Well I guess my concern was keeping everythign in one Global State. Ive seen approaches that load a st ate for every entity, but that could be alot of overhead, and you lose the possibility of sharing global variables and metatables.
While I grasp different ways i can do it within a script, I guess my questions are more of an approach stand point, and I guess fundamental activity between the LUA engine and the C code.
For example your bottom piece of code there, would I need to load that code with lua_load everytime I wanted to run it? Or is there a way store that script, attached to a particular entity on the LUA stack, so that its easiy referenced later to execute any scripts in that file without reading in the byte code again with the LUA_LOAD function? In turn these scripts would reference the metatables / userdata saved on a stack for later use..
I guess Im looking to see if there is a persistant way to keep all of these on the lua stack, or loading scripts, over and over (even teh same ones eg: I had a "Wandering Function" it called the wandering function every 5 seconds, do I need to lua_load that script everytime or is there a way to attach that Wandering function to the entity that needs it at that time dynamically)
The scheme that people choose to implement Lua scripting is largely dependent upon their needs, and the qualities Lua has. Like being light-weight to instantiate. This means you can give each player a full scripting environment and expose what you want to them. Like a function to send text to them. I think your answer lies in understanding the fundamentals of how interpreted languages work wrt persistence. There's no magic bullet, instructions rarely have state. And when they do it leaves people scratching their head. (flipflop operator in Ruby). Therefore, when you talk about "loading code" you're really talking about the consequences of running code. Running code may result in the state of the environment being set. These variables have a scope and references. From outside of the environment, in this case in C, you have the interpreter state. This is encapsulated, and just like how you needed to expose things to it, in a similar way you get back stuff based on what was exposed. Usually with callbacks. So I advise you look into how Lua sandboxes code. C doesn't really change things here. Whether you run Lua from within C, or some other language, the same principle of environments apply. I'd be weary of doing things that forfeit the real advantage and power of Lua. What you really want here is safe code that only operates on what you expose to it. I don't see anything wrong with Gammon's paradigm.
It seems as though alot of implementations on Circle and Aardwolf for example, constantly execute scripts based on triggers. One LUA File to a trigger, and its continuously loaded on use with metatables and userdata being passed to it to gain access to real time variables and methods?(…)
I'm sure you're aware that very few non-player scripts need to be executed constantly, and that even the oldest Circle implementations of mobprogs check whether there's any players around before they run most scripts. Timed movement is the only exception I can think of. If you keep a separate index for the kinds of scripts that need to run without players around, then a lot of inefficiency goes away regardless of the scripting language.
Well from my reading Runter, the notion of having a LUA state for every game entity wasnt concidered a well designed approach; also with that said in my case to have over 500 to 1000 states, one for every mob that was running a behavior script.. that seems like it could be troublesome in the end?
Therefore having all of those userdatums loaded, and pointing to their Objects and therefore being globally access by the global state, and being able to share data with each other
Lua isn't an acronym. So LUA is incorrect. Anyways, I don't know what you're talking about with the bit about over 500-1000 states. If you're trying to make the case for using one global scripting environment I think you're using the wrong tool.
Lua states… What ever happened to one simple global state that you pushed data into when required and gc upon completion :P
When I did my lua work last year; I spent all time making just one simple luaVM(or state) and pushed data onto it when required.
So if a function needed to have access to the character list, it would do a pull at that time and create a local metatable for it for processing.
commands/spells/scripts, all are easy possibilities. My core tech was still housed in C++, but there was allot of 'scripts' that were called too.
scripts or mudprogs, however you want to label them, for mobs per-say, were easily called. it was all housed in the C side of it, and then it would just hook into the lua vm and execute the script when the variables came up for it to execute. 1 VM.
But thats me; it all depends on what you are trying to achieve. Personally, looking back on it all now; and the way I did things, I simple would of used LuaBind instead of writing my own interpreter for it. Would of saved quite the headache.
Oh yeah… Use LuaBind… HUGE amounts of time saved in programming. Bind your classes/structures, functions, namespaces, the works with total ease.
In my experience, using multiple states has advantages over one global state. However, it depends on which game-objects you wish to write scripting for. A Mobile, for instance, may have it's own scripting. If that is your motive, then you might assign a Lua state to each Mobile and have it operate whichever scripts that you see fit.
Scripting should only be used when it makes little sense to hard-code C / C++. As far as when to load "this" or "that"; be your own adviser. MUDs serve more of an artistic purpose than half are willing to admit. Unless your purpose is to release the next greatest MUD code-base to the public, you shouldn't worry so much about what we - the mud community - thinks about it.
Unless anyone out there is willing to login and write your coding, it doesn't matter what the "ideal" scripting engine looks like. Write in a way that pleases you. At the end of the day, new machines can handle whatever small errata your program has, which may go against every textbook you own. Even if you make the most backwards application. If it allows you to write a game that rocks, who gives a crap.
The last two posts were great and very helpful, thanks for the insight.
For my application, there is a base class in my game.. 'A Thing' from that derive, npcs, objects, etc.. Technically a thing can move without a controller, brain.. whatever. So for instance I eventually would like to script Rocks.. that roll down a path, (most of a things interaction is done through the base class) Also as well to allow the MUD to execute scripts eg. create a lava flow, raise buildings, grow a forest etc which would most likely be timed events, or possibly even a reset or timed system configured through a lua based config file.
Just some of the direction im trying to go. Could you expand on what advantages multiple lua states could bring to the table, and how could you go about sharing metadata and usertables between the states?