Jump to content
  • Advertisement
Sign in to follow this  
Laval B

lightuser data in Lua

This topic is 2099 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone.

 

An application we are working on needs some parts to be scripted. The scripts will only act as callbacks to controle some  part of the execution of some transactions. To do so, it must expose a few objects from the host application. The lifetime of these objects is well controled by the host and they will outlive the execution of the script. The logical choice seems to be the use of lightuser data.

 

We have exposed these objects using functions and lightuser data and it does work. However, lightuser data don't have their individual metatable. Instead, they all share the same so they all share the same metamethods. It would be great though if we could associate specific methods to each object exposed (like it can be done with full user data) so it would be possible to use object oriented programming notations on those objects from the script.

 

At the moment, we have to use a notation like this :


function f(user, logger)

   setName(user, "name")
   setGroup(user, "group")

   output(logger, "User is set.")

end

instead of 

function f(user, logger)

   user:setName("name")
   user:setGroup("group")

   logger:output("User is set.")

end

Is there a way to do this with lightuser data ?

Edited by Laval B

Share this post


Link to post
Share on other sites
Advertisement
I'm not an expert of lua myself, but you can create tables called User and Logger (or something else) containing the methods you need and then write something like the following in your script:

function f(user, logger)

   User.setName(user, "name")
   User.setGroup(user, "group")

   Logger.output(logger, "User is set.")

end
This isn't really what you were asking, but I think the only way to associate methods to data exported to lua is to use full user data. You can't do it using lightdata.

Share this post


Link to post
Share on other sites

tbl.func(tbl, "parameter")

is the same as

tbl:func("parameter")

 

I don't know how this works on the C side, but in Lua, you'd declare and use a class like this:

local User = { };

function User.new()
    return setmetatable({ }, {__index = User});
end

function User:setName(name) -- Same as function User.setName(self, name)
    self.name = name
end


local user = User.new();
user:setName("John");

local user2 = User.new();
user2:setName("Jane");

print(user.name, user2.name); -- John, Jane

 

 

However I don't know if this helps you.

Share this post


Link to post
Share on other sites

 


Is there a way to do this with lightuser data ?
Pretty sure, no. I ended up using the syntax that apatriarca suggests. Here's another example of the same syntax being used due to the choice to use light userdata:

http://bitsquid.blogspot.com.au/2011/06/lightweight-lua-bindings.html

 

 

Thank you, i was pretty sure it wasn't possible, i asked just in case. The method suggested by apatriarca is what we are using, the functions are exposed via a call to luaL_newlib and lua_setglobal so they appear in a "namespace" or library.

Share this post


Link to post
Share on other sites

 


Is there a way to do this with lightuser data ?
Pretty sure, no. I ended up using the syntax that apatriarca suggests. Here's another example of the same syntax being used due to the choice to use light userdata:

http://bitsquid.blogspot.com.au/2011/06/lightweight-lua-bindings.html

 

 

With just light user data, no, but if you're not concerned about allocating a full userdata as a wrapper (edit: you're not, I do this in my games and if you ever get to the point where it's actually a performance problem, you're doing way too much in script), I like to embed the light user data in a normal user data. Any functions called in the user data can then pull the light user data out in native code and work on it.

 

This should be exactly what you are looking for, as you can use the hybrid user data just like a normal lua table as per your second code block in the original post. You can override values, call functions with colon syntax, and only the wrapper will be under lua's memory management. The object pointed to by the wrapper will still be safe after the wrapper is destroyed.

Example:

// to create the lua binding object (in C)
    // push an empty table. This will be the object in lua we will "return" to lua
    lua_newtable(L);

    // put the C object in the "privatecobject" field of the lua object as a light user data
    lua_pushlightuserdata(L, user);
    lua_setfield(L, -1, "privatecobject");

    // do your normal metatable setting here

// then setName() in C would look like this (using your example function)
// this would be called from lua as user:setName("name")
int setName(lua_state* L)
{
    // grab the wrapper from the stack
    lua_getfield(L, 1, "privatecobject");
    User* user = static_cast<User*>(lua_touserdata(L, -1));
    lua_pop(L, 1); // pop the userdata field so the stack is unchanged. Not really needed in this function, but a good habit

    user->setName(lua_tostring(L, 2));
    return 0;
}
Edited by kuroioranda

Share this post


Link to post
Share on other sites

 I like to embed the light user data in a normal user data. Any functions called in the user data can then pull the light user data out in native code and work on it.

That's a very good idea. When i looked at it, i was thinking : why didn't i think about that mellow.png . Thanks alot for sharing.

Edited by Laval B

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!