# LUA scripts

## Recommended Posts

Hi there! I am new to LUA and I am embbeding it into my engine. Please answer me this two questions: 1) Can I define a function name with dots in the name? In my C++ functions I have defined for Lua: "Mesh3D.New" and so I want to add another function in LUA called "Mesh3D.PaintRed". Can I do that in LUA, like this? Note that Mesh3D is not a class in LUA.
function Mesh3D.PaintRed(x)
return 2*x;
end

2) I am working with pointers in LUA to find my objects and I am scared that the guys who writes the script (or even myself) passes a wrong type of pointer to the parameter (e.g: he passes a Texture pointer to an Object3d pointer parameter). If that occurs I will get a C++ access violation error and everything will crash, and it will be very difficult to find the bug on the LUA script. Therefore I proposed the following solution:
function SafePointer(myPointer, myPointerType)
return {Pointer = myPointer, PointerType = myPointerType);
end

TYPE_3ds =1000; -->Constant

function Mesh3D.New3ds(Filepath,p1,p2)

local     tempPointer = Mesh3D.Unsafe_New3ds(p1,p2);
return SafePointer(tempPointer ,  TYPE_3ds};

end

function Render.3ds(My3ds, p1,p2,p3)
if (My3ds.PointerType= TYPE_3ds) then
Render.3ds(My3ds.Pointer,p1,p2,p3);
else
Debug.MessageBox("Render.3ds was called by passing incorrect object. Only My3ds object should be passed. A pointer of type " .. My3ds.PointerType .. "was passed.");

end

end


And my question is: if the user passes to the Render.3ds function a parameter that is not a table (like SafePointer), will the statement (My3ds.PointerType= TYPE_3ds) return NIL or will LUA crash with an error? If it's the second case, how do I check if My3ds is of SafePointer type? Thank you so much in advance! I really appreciate all your feedback! Rod [Edited by - Kylotan on March 7, 2007 5:28:00 AM]

##### Share on other sites
(1): No I don't believe you can do that in Lua. The reason is that Lua uses "." as an operator, to access elements of a table for instance (table1.table2.my_key = 5). I believe Lua function syntax is: first letter must be a case-insensitive letter, followed by any number of letters, numbers, or underscores.

(2): This seems like overkill to me. You want to check each and every function parameter to ensure its correctness? That adds a small penalty cost for one function, but to put it in all your functions the penalty cost will add up linearly to the # of calls you make.

I think the answer depends on what binding library (if any) you are choosing to use in your game. For example, Luabind uses an exception handling mechanism: link. Using existing functionality like that seems like a much less painful idea to me.

Hope that some of what I said helps.

##### Share on other sites
1.) Yes this is possible Mesh3d would be a table in lua and because a function is a valid data type in lua this would be legal. The code below would also give you the same results

function chode(x)
return 2*x
end

Mesh3D.PaintRed = chode

Hopefully this helps.

2.)

I'm slightly confused as your safe pointer function doesn't actually check anything. I would actually suggest looking into a c++ solution where you have a class that encapsulates your pointer and the type and then all the objects that you actually pass around in lua will be pointers to a single class type. Then when you get the object in c++ you can do something like this.

// suto code below

CLuaSafePointer * pLSP = getdata();
if(pLSP.type == LSP_TYPEIWANT)
{
// do something
}
else
// throw error or ignore

##### Share on other sites
Quote:
 Original post by Namatsu1.) Yes this is possible Mesh3d would be a table in lua and because a function is a valid data type in lua this would be legal. The code below would also give you the same resultsfunction chode(x) return 2*xendMesh3D.PaintRed = chodeHopefully this helps.2.) I'm slightly confused as your safe pointer function doesn't actually check anything. I would actually suggest looking into a c++ solution where you have a class that encapsulates your pointer and the type and then all the objects that you actually pass around in lua will be pointers to a single class type. Then when you get the object in c++ you can do something like this.// suto code belowCLuaSafePointer * pLSP = getdata();if(pLSP.type == LSP_TYPEIWANT){ // do something}else // throw error or ignore

Thanks! The C++ encapsulation class seems like a great solution! I will implement that, it seems excellent.

About No. 1) Could you please explain the table approach in order to define my functions with a dot in the middle like Mesh3D.PaintRed ? I am new to lua and I don't really get what you are saying...

did you previously define Mesh3D = {}? What about PaintRed?
or did you define Mesh3D = {PaintRed= myFunction} ?

Thanks so much everyone!
Cheers!
Rpd

##### Share on other sites
THinking again... it's not a so good idea, since even though it's easy to pass from LUA the pointer of the encapsulation class to C++, I have some C++ that push poitners to LUA. In order for this to work, I would have to maintain new instances of these "encapsulation" objects, and that would consume a lot of memory. I don't want to duplicate my data.

Therefore my idea of implementing SafePointer was that it returns a table with two values, the pointer, and the pointer type, so that i make the structure in LUA for every C++ pointer returning function, and then check the pointer parameters in LUA checking if the PointerType of that structure is the one that corresponds.

Quote:
 2): This seems like overkill to me. You want to check each and every function parameter to ensure its correctness? That adds a small penalty cost for one function, but to put it in all your functions the penalty cost will add up linearly to the # of calls you make.I think the answer depends on what binding library (if any) you are choosing to use in your game. For example, Luabind uses an exception handling mechanism: link. Using existing functionality like that seems like a much less painful idea to me.

Thanks Roots for your answer :). No I just want to check the parameters that are passed as pointers, no more. All the other parameters are left unchecked, and it is used only in functions that use pointer parameters.

Could you explain me more what do you mind by "binding library"? I am using LUA 5.1. Are you proposing me to catch C++ errors with LUA? the thing is that if I pass a bad pointer to the C++ function, there is no check in C++ to see if the parameter is right, so the code would "throw" no error, but crash the program instead. This is because I would never expect in C++ to pass a parameter of other type to a pointer (in C++ you would get compile error, while from LUA as I am using pMYObject* = (static_cast) LuaGetuserData(s,1), anything can be passed).
Note: I don't have my project with me now, the syntax of the previous function surely is different, but you get the idea :)

What do you suggest?!

Rod

P.S: The use of my solution would be like this:

TYPE_3ds =1000; -->Constantfunction SafePointer(myPointer, myPointerType)      return {Pointer = myPointer, PointerType = myPointerType);endfunction Mesh3D.New3ds(Filepath,p1,p2)     local     tempPointer = Mesh3D.Unsafe_New3ds(p1,p2);      return SafePointer(tempPointer ,  TYPE_3ds};endfunction Render.3ds(My3ds, p1,p2,p3)if (My3ds.PointerType= TYPE_3ds) thenRender.3ds(My3ds.Pointer,p1,p2,p3);else     Debug.MessageBox("Render.3ds was called by passing incorrect object. Only My3ds object should be passed. A pointer of type " .. My3ds.PointerType .. "was passed.");            endendAirplaneMesh= Mesh3D.New3ds("MyPlane.3ds",34,2);Render.3ds(AirplaneMesh, 5,2,3); --> I am sure that AirplaneMesh is of type 3ds since I can check it's "PointerType" parameter.

##### Share on other sites
Quote:
 Original post by Anonymous PosterAbout No. 1) Could you please explain the table approach in order to define my functions with a dot in the middle like Mesh3D.PaintRed ? I am new to lua and I don't really get what you are saying...did you previously define Mesh3D = {}? What about PaintRed?or did you define Mesh3D = {PaintRed= myFunction} ?Thanks so much everyone!Cheers!Rpd

as far as I know you cant have a '.' in a variable name, you are actually accessing a variable inside a table when you call Mesh3D.new in your script. having defined Mesh3D.new in c++, Mesh3D should be a table already. but if you were defining something purely in lua you would have to do the Mesh3D = {} first. Hopefully this explains things better.

##### Share on other sites
Quote:
 Original post by Namatsuas far as I know you cant have a '.' in a variable name, you are actually accessing a variable inside a table when you call Mesh3D.new in your script. having defined Mesh3D.new in c++, Mesh3D should be a table already. but if you were defining something purely in lua you would have to do the Mesh3D = {} first. Hopefully this explains things better.

Yes Mesh3D.New is already defined in C++, so as you say Mesh3D it should be a table already. Since it is a table, then we agree that I don't have to define Mesh3D = {}, but how do I tell LUA that the new function PaintRed (not defined in C++) is a member of Table Mesh3D?

Like previous example : Mesh3D.PaintRed()?

Thanks so much!
Cheers!
Rod

##### Share on other sites
correct

function Mesh3d.PaintRed(x)
return 2*x
end

should work

##### Share on other sites
Quote:
 Original post by Namatsucorrect function Mesh3d.PaintRed(x) return 2*xendshould work

wow that's what I wanted! thanks!

Oh, one more thing!:
In the following example, would LUA asume a.Fruit= nil, and call DoSomething or would LUA produce a runtime error?

local NewStructure = {Fruit = "banana", Color = "yellow");
local a = 4; --> simple number

if(a.Fruit ~= "banana")
DoSomething()
end

What about if a was not defined at all?

Thanks so much in advance!!!! This is all really helpful! Thanks :)

Cheers!
Rod

##### Share on other sites
local a = 4if(a.Fruit ~= "banana") then	a=7end

This will give you a error similar to this at runtime.

'attempting to index 'a' (a number)' or
'attempting to index 'a' (a nil value)'
if a was a nil value

I believe you would need to do something similar to this.

if type(a) == "table" then	if a.Fruit ~= "banana" then		a=7	endend

##### Share on other sites
Quote:
 Original post by NamatsuThis will give you a error similar to this at runtime.'attempting to index 'a' (a number)' or'attempting to index 'a' (a nil value)'if a was a nil valueI believe you would need to do something similar to this.***

Thanks! :) I didn't know about type().
Is there a way to check the table type, like for example what happens if
a = {Fruit= "banana", Color= "Yellow"} -->Fruit table/structureb = {Animal = "Rat", NumberOfLegs = 4} --> Animal Table/structureif type(b) == "table" then	if b.Fruit ~= "banana" then 		b=7	endend

In this case b is also a table, but does not have the member Fruit. Will LUA return a runtime error or nil? How do I check if a is a Fruit table/structure or an Animal table/Structure?!

Thanks so much!!!! :)
Cheers!
Rod

##### Share on other sites
a = {Fruit= "banana", Color= "Yellow"} -->Fruit table/structureb = {Animal = "Rat", NumberOfLegs = 4} --> Animal Table/structureif type(b) == "table" then	if b.Fruit ~= "banana" then 		b=7	endend

yes this code is valid. the second 'if' statement would fail because b.Fruit is a nil value. You could do something like this to let you know if an invalid table was passed in. assuming you have a logger class bound to lua.

a = {Fruit= "banana", Color= "Yellow"} -->Fruit table/structureb = {Animal = "Rat", NumberOfLegs = 4} --> Animal Table/structureif type(b) == "table" then	if b.Fruit ~= "banana" then 		b=7	else		Logger.Error("blah")	endend

##### Share on other sites
Thank you so much! :)
Cheers!
Rod

##### Share on other sites
Oh.. by the way:

Should I call from C++

RenderElements::Mesh3D_ASE_Node *tempASE_Node = 		static_cast<RenderElements::Mesh3D_ASE_Node*>(lua_touserdata(s,1));ORRenderElements::Mesh3D_ASE_Node *tempASE_Node = 		(RenderElements::Mesh3D_ASE_Node*)(lua_touserdata(s,1));

In other words, should I call a static cast, or a simple cast?!
I saw it both ways on the internet.

Thanks so much!
Cheers!
Rod

##### Share on other sites
both should work as far as I know. Maybe someone else has a bit more insight on this subject than me.

##### Share on other sites
Thanks Namatsu! :)

I managed that to work! Thank you so much!

However, I got another problem now...

Quote:
 -->Constants for Pointer TypesTYPE_ASE = 1000;TYPE_3ds=1001;TYPE_Texture=1002;TYPE_DisplayList=1003;TYPE_Object3D=1004;-->function SafePointer(myPointer, myPointerType) if (myPointer~= nil) then return {Pointer = myPointer, PointerType = myPointerType}; else --> Debug.MessageBox("Problem!"); return nil; end endfunction CheckPointer(FunctionName, DesiredPointerType, VariableToTest) if (type(VariableToTest) == "table") then if (VariableToTest.PointerType == DesiredPointerType) then return true; else --> Debug.MessageBox("Incorrect parameter passed in ".. FunctionName .. ". A Safe Pointer must be passed of type " .. DesiredPointerType .. ". Parameter passed was of type ' " .. type(VariableToTest) .. " '.", "Incorrect parameter passed in " .. FunctionName); return false; endelse --> Debug.MessageBox("Incorrect parameter passed in ".. FunctionName .. ". A Safe Pointer was NOT passed", "Incorrect parameter passed in " .. FunctionName); return false; endendfunction Mesh3D.NewASE(Filepath,TextureFilter,p1,p2,p3) local tempPointer =Mesh3D.UnsafeNewASE(Filepath, TextureFilter, p1,p2,p3,done); LastSafePointer = SafePointer(tempPointer , TYPE_ASE);return LastSafePointer; endfunction Render.ASE(SafePointer_ASE,p1, p2, p3, p4) if CheckPointer("Render.ASE", TYPE_ASE, SafePointer_ASE) then Render.UnsafeASE(SafePointer_ASE.Pointer, p1, p2,p3,p4,done); end end(This is not really a quote but I haven't found how to do the code tag. [code] does not work ;)

So I first call:

mySafePointerTableASE =Mesh3D.NewASE("MyFile",1,2,3)
Render.ASE(mySafePointerTableASE, 4,5,6,7);

expecting that mySafePointerTableASE gets stored a table of type:
{Pointer = myPointer, PointerType = myPointerType}.
However when I call Render.ASE I get the following error:

"Attempt to index local 'SafePointer_ASE' (a userdata value)"
function Render.ASE(SafePointer_ASE,p1, p2, p3, p4)  if  CheckPointer("Render.ASE", TYPE_ASE,  SafePointer_ASE) then        Render.UnsafeASE(SafePointer_ASE.Pointer, p1, p2,p3,p4,done);    end       end

So yes... it's a userdata value (so the SafePointer structure got stored), but what's the problem with trying to access SafePointer_ASE.Pointer?!!?

Cheers
Rod

##### Share on other sites
try changing it to this just to test.

function SafePointer(myPointer, myPointerType)
if (myPointer ~= nil) then
local retval = {Pointer = myPointer, PointerType = myPointerType}
return retval
else
...

##### Share on other sites
[ source ] is what you want

I hate to arrive to the party a little late, but I think all of these safe wrappers are a bit overkill.

There is actually a safe way to do this built into the language. The idea is that you create a userdata for each of your objects, like you are doing now. However, you also assign each a metatable. There would be a metatable for each object type. Then to check the type of an object, you simply check the userdata's metatable. This may be a bit over the top, however, it does allow you to treat your userdata like real objects. I think it is going to let you use Mesh3D.PaintRed act the way you want. I assume that Mesh3D is a class in C++ and you have mutlipule instances of this class. If this is not the case, then what I am suggesting is most likely over kill, otherwise, it is most likely the cleanest solution. So what exactly are you trying to do here? Are there many instances of the same C++ class that you would like to expose to Lua? Or is it mostly singleton type classes with only one instance?

##### Share on other sites
Quote:
 Original post by Namatsutry changing it to this just to test.function SafePointer(myPointer, myPointerType) if (myPointer ~= nil) then local retval = {Pointer = myPointer, PointerType = myPointerType} return retval else...

Thanks so much Namatsu!!!
I got it fixed! I found another error in my code too, I was passing a wrong variable too. However applying this two fixes now it works :)

Cheres!
Rod

##### Share on other sites
Quote:
 Original post by Dwiel[ source ] is what you wantI hate to arrive to the party a little late, but I think all of these safe wrappers are a bit overkill.There is actually a safe way to do this built into the language. The idea is that you create a userdata for each of your objects, like you are doing now. However, you also assign each a metatable. There would be a metatable for each object type. Then to check the type of an object, you simply check the userdata's metatable. This may be a bit over the top, however, it does allow you to treat your userdata like real objects. I think it is going to let you use Mesh3D.PaintRed act the way you want. I assume that Mesh3D is a class in C++ and you have mutlipule instances of this class. If this is not the case, then what I am suggesting is most likely over kill, otherwise, it is most likely the cleanest solution. So what exactly are you trying to do here? Are there many instances of the same C++ class that you would like to expose to Lua? Or is it mostly singleton type classes with only one instance?

Hi Dwiel!
Thanks for joining the party! :)

I read your design proposal, and it seems interesting, although I am not understanding some points: How do I do this "Then to check the type of an object, you simply check the userdata's metatable."?

I guess that what you are proposing is to use "classes" in LUA using metatables and assigning functions to each of these classes right? I read a lot about this but didn't get it well yet. Could you provide me a simple example?

By the way, this is what I am trying to do:
I got in C++ many linked lists that contain objects. For example I have a linked list of 'ASE' objects. In LUA I am trying to create a new nodes and then pass this pointer nodes to another functions to manipulate them. Sometimes I need to call object's member functions and sometimes I have to pass the object's pointer to another functions. Most of the times I don't need to delete the nodes explicitly since all the linked list gets deleted at the end of the program, so I don't really need to explicitly call the deconstructor as it's managed by the linked list. So if I have to delete a node I don't want it to be implicit, but explicitly through another function like DeleteBlah()...

Maybe your class simple example will enlighten me... ;)

Cheers!
Rod

##### Share on other sites
ok, so even a simple example ends up not being too simple. Here is an example which creates OO datatypes in LUA without C:

local Stick = {}function newStick()	local stick = {}	setmetatable(stick, Stick)	return stickendfunction isStick(stick)	if getmetatable(stick) == Stick then		return true	else		return false	endendfunction Person_throwStick(person)	assert( isPerson(person) )	if person.stick ~= nil then		print(person.name .. " threw a stick")		person.stick = nil	else		print(person.name .. " must hold a stick before throwing it")	endendfunction Person_holdStick(person, stick)	assert( isPerson(person) )	assert( isStick(stick) )	person.stick = stick	print( person.name .. " is now holding a stick ")endlocal Person = {__index = {throwStick = Person_throwStick, holdStick = Person_holdStick}}function isPerson(person)	if getmetatable(person) == Person then		return true	else		return false	endendfunction newPerson(name)	assert( type(name) == "string" )	local person = {}	setmetatable(person, Person)	person.name = name	return personend-- how it can be usedlocal p = newPerson("bob")local s = newStick()p:holdStick(s)p:throwStick()p:throwStick()-- results in:-- bob is now holding a stick -- bob threw a stick-- bob must hold a stick before throwing it

So, this is a nice sample using just lua. In your case, the Person table, the Stick table, the Person_ functions, etc would all be done in C. This way, the metatable would point to cfunctions instead of lua functions. Keep in mind that the p:holdStick(s) <==> p.holdStick(p, s)

define the metatables like this:
// these are the methods that MidiOut objects havestatic const luaL_reg MidiOut_meta[] = {	{"__gc",	MidiOut_gc},	{"noteOn",	MidiOut_noteOn},	{"noteOff",	MidiOut_noteOff},	{"sendMessage", MidiOut_sendMessage},	{NULL, 		NULL}};static int MidiOut_register(lua_State* L){	luaL_newmetatable(L, MIDIOUT);	lua_pushliteral(L, "__index");	lua_newtable(L);	luaL_openlib(L, 0, MidiOut_meta, 0);	lua_rawset(L, -3);	lua_pop(L, 1);	return 1;}

this is from my midi module which had a MidiOut object with the member functions noteOn, noteOff, and sendMessage. MidiOut_noteOn, etc are all defined and coded as you would expect as a typical C/Lua wrapper function.

here are some wrapper functions for creating new objects, pushing them onto the stack, safely pulling them off of the stack, etc.

#define MIDIOUT "MidiOut"// some helper methods for accessing RtMidiOut:static RtMidiOut* toMidiOut(lua_State *L, int index){	RtMidiOut **midiout = (RtMidiOut**)lua_touserdata(L, index);	if(midiout == NULL)		luaL_typerror(L, index, MIDIOUT);	return *midiout;}static RtMidiOut* checkMidiOut(lua_State* L, int index){	RtMidiOut** midiout;	RtMidiOut* ret;	luaL_checktype(L, index, LUA_TUSERDATA);	midiout = (RtMidiOut**)luaL_checkudata(L, index, MIDIOUT);	if(midiout == NULL)		luaL_typerror(L, index, MIDIOUT);	ret = *midiout;	if(!ret)		luaL_error(L, "null RtMidiOut*");	return ret;}static RtMidiOut** pushMidiOut(lua_State* L, RtMidiOut* mo){	RtMidiOut** midiout = (RtMidiOut**)lua_newuserdata(L, sizeof(RtMidiOut*));	*midiout = mo;	luaL_getmetatable(L, MIDIOUT);	lua_setmetatable(L, -2);	return midiout;}static int MidiOut_noteOn(lua_State *L){	RtMidiOut* midiout = checkMidiOut(L, 1);	midiout->noteOn( ... );	return 0;}

Let me know if you have any more questions. I only recently figured all of this stuff out, so it will definitely help me get a clearer understanding of it all.

##### Share on other sites
Quote:
 Original post by Dwielok, so even a simple example ends up not being too simple. Here is an example which creates OO datatypes in LUA without C:*** Source Snippet Removed ***So, this is a nice sample using just lua. In your case, the Person table, the Stick table, the Person_ functions, etc would all be done in C. This way, the metatable would point to cfunctions instead of lua functions. Keep in mind that the p:holdStick(s) <==> p.holdStick(p, s)define the metatables like this:*** Source Snippet Removed ***this is from my midi module which had a MidiOut object with the member functions noteOn, noteOff, and sendMessage. MidiOut_noteOn, etc are all defined and coded as you would expect as a typical C/Lua wrapper function.here are some wrapper functions for creating new objects, pushing them onto the stack, safely pulling them off of the stack, etc.*** Source Snippet Removed ***Let me know if you have any more questions. I only recently figured all of this stuff out, so it will definitely help me get a clearer understanding of it all.

Hi Dwiel!

I understood really well how LUA example code! Thank you very much!

Regarding the C++ example I found it more complicated.
I am not familiar with the commands:
lua_pushliteral(L, "__index");
lua_rawset(L, -3);
lua_pop(L, 1);
or lua_setmetatable(L, -2);

Could you point me as to where did you learn this? Information seems to be very scarce and succinct.

Thank you so much!
CHeers
Rod

##### Share on other sites
Yeah, no problem. I get most of my information from a few sources:

I use this many times a day as a good reference:
http://www.lua.org/manual/5.1/

I use this if I want something more than a reference. It's got some techniques and more explanation:
http://www.lua.org/pil/

Here is a little tutorial about the C/lua API:
http://lua-users.org/wiki/SimpleLuaApiExample

there are quite a few good tutorials on the wiki:
http://lua-users.org/wiki/
and tutorial section:
http://lua-users.org/wiki/TutorialDirectory

Glad to be able to help!

[Edited by - Dwiel on March 22, 2007 8:31:54 PM]

##### Share on other sites
Dwiel thanks for all the info!!! :)

Thanks Namatsu, Roots, and Dwiel for all the help received up to now :)

I have a problem now I can't find the solution anywhere..
Let's see if anyone can help me:

I am trying to use a function that returns multiple parameters (with no success yet!):

this is my code in C++
Quote:
 static int LUA_Object3D_GetPosition(lua_State* s){ Object3D * tempObject = (Object3D *) (lua_touserdata(s,1)); lua_pushnumber(s,tempObject->Position_Now.x); lua_pushnumber(s,tempObject->Position_Now.y); lua_pushnumber(s,tempObject->Position_Now.z); return (3);}

and this is my code in LUA:
Quote:
 local x;local y;local z;x,y,z = Object3D.GetPosition( Iterator1_Object3D); Font.PrintCentered(0.1,"Position x:" .. x .."y:" .. y .. "z:" ..z );

.. and I am receiving that x, y , and z contain nil values.
"Cannot concatenate nil values"
What am I doing wrong?

Thanks so much everyone in advance!!!
Cheers,
Rod

##### Share on other sites
Thats really strange. That is exactly how you should do it as far as I can tell. I don't see any obvious bugs. Have you tried adjusting that exact code without the sendond and third pushnumber and returning 1 just to test to make sure that nothing else is causing problems?

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628373
• Total Posts
2982306

• 10
• 9
• 13
• 24
• 11