Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411474 Posts in 69369 Topics- by 58423 Members - Latest Member: antkind

April 23, 2024, 01:16:40 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Lunar Instances in Lua
Pages: [1]
Print
Author Topic: Lunar Instances in Lua  (Read 2784 times)
jeb
Level 5
*****


Bling bling


View Profile WWW
« on: February 11, 2008, 01:48:45 AM »

Hey hey, I'm experimenting with Lua in C++ for Harvest, but haven't really grasped the whole concept yet. goldbuick helped me a lot, but still I have a problem with Lunar object instances that I pass to Lua. I've tried googling this, but either I'm not using the correct key words, or I'm first in the world with this problem...

Anyway, what I want to do is to create a Lua script which contains an "init" and an "update" method. Both methods take an "instance" parameter, which is the Lunar object (of a Harvest building). This works fine, and the instance is reported as userdata.

The problem is that I want to be able to add variables to these instances independently of each other. This simply wont work. I've noticed that I can get a metatable for the userdata, but that metatable is shared for all instances of the class (ie, if I add a variable, such as "instance.newValue = 666", it is added and set for ALL instances of the class, like a static member).

Another solution I pondered was to list variables in the C++ code, and add a "addVariable", "setVariable" etc methods. This doesn't feel so "lua-like", though.

So then I tried to create a method called "getPrivates()" which would work as a lua table. That would allow users to dynamically manipulate the table in lua. But that gave me new problems... As I said, Lua is still new to me, so the concept of the stack is a bit confusing. All the examples I found that handled tables on the C++ side used the "newtable" method. This creates a table on the stack, which I can refer to, but I don't seem to be able to extract it so that it will remain between calls.

Sooo... What I did then was to look at the Aquaria scripts, and they look like as if each entity had its own lua state altogether. I'm probably mistaken about this, but that way it's easy to add variables to the scripts... simply place them as globals. This works fine, but the overhead must be huge, right? Especially considering there may be several hundreds of buildings in Harvest.

Anyway, I'd prefer if the lua script could look like this:
Code:
function init(instance)
   instance.testValue = 666
end
function update(instance,timestep)
   instance.testValue = instance.testValue - timestep
   if instance.testValue < 0 then
      instance:die()
   end
end

Or like this:
Code:
function init(instance)
   vars = instance:getPrivates()
   vars.testValue = 666
end
function update(instance,timestep)
   vars = instance:getPrivates()
   vars.testValue = vars.testValue - timestep
   if vars.testValue < 0 then
      instance:die()
   end
end

(The script looks like this now, with a Lua state for each building:)

Code:
testValue = 666

function update(instance,timestep)
   testValue = testValue - timestep
   if testValue < 0 then
      instance:die()
   end
end

Help?  Shocked Embarrassed Grin
Logged

birdcloud
Level 0
**



View Profile
« Reply #1 on: February 11, 2008, 05:13:24 PM »

All the examples I found that handled tables on the C++ side used the "newtable" method. This creates a table on the stack, which I can refer to, but I don't seem to be able to extract it so that it will remain between calls.

I'll just answer this. From the Lua 5.1 Reference Manual:

    
Lua provides a registry, a pre-defined table that can be used by any C code to store whatever Lua value it needs to store. This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it should take care to choose keys different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name or a light userdata with the address of a C object in your code.

So if you've got a table you want to hang on to at the top of the stack (of some lua_State *L), just say:
    lua_setfield(L, LUA_REGISTRYINDEX, "jebHarvestLib.superSpecialTable");
This'll pop the table from the stack. To get that table back later, say:
    lua_getfield(L, LUA_REGISTRYINDEX, "jebHarvestLib.superSpecialTable");
and hey! it's back on top of the stack again. Do note that you shouldn't use integers as keys in the registry. These are reserved for the reference system: instead of making up long string keys and hoping for no conflicts with whatever other C libraries might be putting in the registry, just say:
    int specialRef = luaL_ref(L, LUA_REGISTRYINDEX);
This pops whatever is on top of L's stack and stores in the registry under a unique integer key. The return value is that key, so save it somewhere. When you want the table (or whatever you stored) back, just say:
    lua_rawgeti(L, LUA_REGISTRYINDEX, specialRef);
When you're done with whatever you saved, you can turn the key back over to the reference system by saying:
    luaL_unref(L, LUA_REGISTRYINDEX, specialRef);
As for fitting this into your larger design: because your Lua scripts play with object data so much, why not let each C++ object store all its data (or all its game-logic data) in a Lua table? In the constructor, call lua_newtable(lua_State*),  then put the table in the registry and only save the key on the C++ side.

(Just one option, of course. I didn't follow your explanation too well, so maybe you wanted something else?)
Logged
jeb
Level 5
*****


Bling bling


View Profile WWW
« Reply #2 on: February 12, 2008, 01:31:26 AM »

As for fitting this into your larger design: because your Lua scripts play with object data so much, why not let each C++ object store all its data (or all its game-logic data) in a Lua table? In the constructor, call lua_newtable(lua_State*),  then put the table in the registry and only save the key on the C++ side.

(Just one option, of course. I didn't follow your explanation too well, so maybe you wanted something else?)

That is exactly what I wanted to do, but I couldn't figure out how to push and pop Lua tables to/from the stack (without using createtable every time I wanted to push the entity data). I'll check out that registry thingie and see if it helps... Thanks a lot for the info!
Logged

goldbuick
Level 1
*


where am I?


View Profile
« Reply #3 on: February 13, 2008, 12:04:30 PM »

oligophagy was totally right about using the registry.

You can get it to work with the vars = instance:getPrivates() approach

1. the C++ object has an int specialRef variable. Initially -1.
So the first time getPrivates is called. And the specialRef is -1 then you can call
lua_newtable(); to create the table to hold the private variables.
2. Then you use specialRef = luaL_ref(L, LUA_REGISTRYINDEX); This will put the table into the registry where you can get at it. this will also pop the new table off the stack.

3. You start with this step if specialRef is != -1.
lua_rawgeti(L, LUA_REGISTRYINDEX, specialRef ); This will pull the variables table onto the stack so that when getPrivates() returns it will get passed into the vars variable.

ie:

::getPrivates() {

   if ( specialRef == -1 ) {
      lua_newtable();
      specialRef = luaL_ref(L, LUA_REGISTRYINDEX);
   }

   lua_rawgeti(L, LUA_REGISTRYINDEX, specialRef );
   return 1;
}

Post-Note: When you destruct the C++ class, make sure to call
luaL_unref(L, LUA_REGISTRYINDEX, specialRef);
This will free up the memory used and allow it to be garbage collected.


Logged

--== AHHHHHHHHHHHHHH ==--
jeb
Level 5
*****


Bling bling


View Profile WWW
« Reply #4 on: February 13, 2008, 01:05:44 PM »

Yeah, I got it to work, thanks Smiley I was gonna post about it as soon as my write/read function worked too, heh. Which is does now... but it doesn't save sub-tables properly. I need to think about that some more Smiley
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic