🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Lua tables for data driven object types

Started by
3 comments, last by x_gamer_x 19 years, 11 months ago
I am going to use lua as a scripting system for my project, and one of the things I want to do with it is define object types. For example:

Resource["Iron"] = {
PriceMin = 10,
PriceMax = 25,
Rarity = 80,
SpawnTime = 180,
Diffuculty = 3,
Level1 = "Impure Iron Ore",
Level2 = "Common Iron Ore",
Level3 = "Pure Iron Ore",
Failure = "Failed to aquire any ",
Success = "placed in Cargo Hold.",
Description = "A common ore found throughout the galaxy."
}

Resource["AnotherResource"] = {
PriceMin = 10,
PriceMax = 25,
Rarity = 20,
SpawnTime = 180,
Diffuculty = 3,
Level1 = "Impure AnotherResource",
Level2 = "Common AnotherResource",
Level3 = "Pure AnotherResource",
Failure = "Failed to aquire any ",
Success = "placed in Cargo Hold.",
Description = "A rare resource used for whatever."
}






First I need to know, is this is a valid way to store the data? I saw a post by someone else using this method of creating a table. And if it is, I'm not exactly sure on how this table is being stored in memory by lua, and thus I can't quite figure out how the data would be read in with c++. I've read over the manual a few times, trying to figure out exactly how this should work, can't quite get my head around it, so any help is apreciated.
-------------------------Rayoom Sledge Hammer Productions - Programmer
Advertisement
Well an easy way would be to use Luabind and have a constructor for your resource object take a Lua table, like this:
#include <string>#include <luabind/luabind.hpp>#include <luabind/object.hpp>using namespace luabind;class Resource {public:    // a Resource constructor that takes a Lua    // table as an argument.    Resource( const luabind::object& t ) {        priceMin = object_cast<int>(t["PriceMin"]);        priceMax = object_cast<int>(t["PriceMax"]);        level1 = object_cast<std::string>(t["Level1"]);        // ... and so on    }private:    int priceMin, priceMax;    std::string level1 // ...};// call this function during your init so Lua knows about// Resource objectsvoid bindResourceToLua(lua_State* L) {    module(L)    [        class_<Resource>("Resource")            .def(constructor<const luabind::object&>())    ];}

So then in a Lua script whose job is to init all the resource types, assuming you have a "Resource" table filled with all your various data, you simply do something like:
for k,v in pairs(Resource) do    newRes = Resource(v)    someCfunctionToAddResource(newRes)end

All in all it's pretty simple, and the fact is once you have it up and running you have a completely data-driven design, which rocks.
Thanks ktw, thats exactly what I'm looking for. I read up on luabind last night so I understand how all that is working. I'm not quite sure I get this part though:

for k,v in pairs(Resource) do    newRes = Resource(v)    someCfunctionToAddResource(newRes)end


First, What is k (the loop control variable?) and what is v?

Not sure what 'in pairs(Resource)' does either.

Thanks for the help!


*edit - Found the answer to my own question in the manual, in case anyone else is wondering:
Quote:
• pairs (t)
Returns the next function and the table t (plus a nil), so that the construction
for k,v in pairs(t) do ... end
will iterate over all key–value pairs of table t.
-------------------------Rayoom Sledge Hammer Productions - Programmer
I should mention something else. I got tripped up bigtime when I started constructing C++ objects within Lua and then passing them back to C++, because Lua was still garbage collecting them and then the C++ pointers would become invalid. So say you have a class that takes pointers to those Resource objects:
class ResourceManager {public:    AddResource(std::string name, Resource* res) {        resourceMap[name] = res;    }private:    std::map<std::string, Resource*> resourceMap;};

So you would expose the ResourceManager to Lua, construct some Resources, and then "give" them to the ResourceManager via AddResource, where they could be used by your game. But the problem I mentioned above is a big one...the solution, though, is right in the Luabind manual, if not being entirely obvious. You have to tell Luabind to "transfer the ownership" of the pointer (meaning Lua will not garbage collect the object).

What you do is a simple parameter in the "module" definition. For the above class it would look like this:
#include <luabind/luabind.hpp>#include <luabind/adopt_policy.hpp> // don't forget this include!using namespace luabind;void registerResourceManager(lua_State* L) {    module(L)    [        class_<ResourceManager>("ResourceManager")            .def("AddResource",&ResourceManager::AddResource, adopt(_2) )    ];}

In "adopt", _1, _2, _3, _4, ... are arguments. In the latest version of Luabind (the CVS development branch) _1 is always the implied "self" object when calling a class, so _2 would be the argument you want. If you're using an older build then adopt(self) would be the class object and _1 would be the first argument--you might have to experiment to see which works for you, _1 or _2.

Luabind really makes crossing the language barrier easy--maybe a bit TOO easy...so think carefully about your design before you go crazy with bindings everywhere. Good luck!
Thanks for the tip!

Was already aware of this from reading the docs but if I hadn't I know it would have saved me a lot of trouble. Plus you explained it better than the docs ;).
-------------------------Rayoom Sledge Hammer Productions - Programmer

This topic is closed to new replies.

Advertisement