Archived

This topic is now archived and is closed to further replies.

Lua - limiting available functions

This topic is 5141 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

The thing I want to do is simple. Limit the C functions that can be called from a certain script. For example script1 can use functions 1 through 10 and script2 can use 11 through 15. The reason is simple enough. I don''t want my AI scripts to be able to do things my game scripts can do and same with menus. I haven''t seen this mentioned anywhere in the docs or from other resources, but it may have slipped by me. Basically I want the user (end) to be able to script things themselves such as AI scripting (ala BG) except not be able to do things they shouldn''t like create items and generally cheat (also like in BG) Thanks in advance.

Share this post


Link to post
Share on other sites
Personally, I use the tolua package for automatically generating the Lua bindings for my code. The way tolua works is that entities for export (functions, class definitions, constants, globals, enums, etc.) are declared in a package file, which is processed by the tolua executable to construct a .CPP file to be compiled and linked with the application.

The way this generated code is used is that tolua generates two functions--tolua_PACKAGENAME_open() and tolua_PACKAGENAME_close()--which are used to load and unload the various bindings.

In my game, I implement functionality hiding by calling tolua_XXX_open() and tolua_XXX_close() at appropriate times. For instance, all map generation is performed via script. During the map generation phase of level loading, I execute the function tolua_MapBuilding_open() to expose the map generation library to script. After the map is constructed, tolua_MapBuilding_close() will undo the bindings so that AI and event scripts can not (accidentally or intentionally) call MapBuilding functions and fuxxor the map.

Alternatively, you could make use of multiple Lua states, each state possessing a portion of the script interface, and each state associated with some task of the game. In my game, were I to use such a method, I would have one Lua state associated with MapBuilding, one associated with monster AI, and so on. I have not experimented with this method at all, so I honestly can not say how well it would work. Theoretically, I would say it should work just fine, but...


Josh
vertexnormal AT linuxmail DOT org


Check out Golem: Lands of Shadow, an isometrically rendered hack-and-slash inspired equally by Nethack and Diablo.

Share this post


Link to post
Share on other sites
Cool.
Well tolua seems to do everything I want it to do, but I'm having a little trouble with it as it doesn't generate a _close function for a package.

EDIT: I'm just about to use tolua++
Hopefully it'll fix this.
I was using tolua because I couldn't get the the ++ site because of ISP problems.
It's still not working but I managed to get it from a friend. I'll report back later today

[edited by - Wormy Hellcar on November 12, 2003 11:01:11 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Wormy Hellcar
Well tolua seems to do everything I want it to do, but I''m having a little trouble with it as it doesn''t generate a _close function for a package.



Hmmm... I dunno why not.

Truthfully, I am using Lua 4.0, as my project was far too advanced by the time 5 came out, for me to relish the thought of switching. I can not honestly say whether or not tolua for 5 does things differently.

However (and again, this is speaking from the perspective of 4.0) it shouldn''t be too difficult (just laborious) to write your own close function. Basically, tolua creates a bunch of usertypes for the entities you export, and tolua_XXX_open() registers all of these various user types. All tolua_XXX_close() consists of is a long list of

lua_pushnil(tolua_S); lua_setglobal(tolua_S,"USERTYPENAMEHERE");


statements, one for each user data registered. If nothing else, you could do this by hand. (Very tedious, especially as your script interface increases in complexity; a macro would save some time, but still a major PITA.)

Anyway, good luck, and keep us posted on how it goes for you.


Josh
vertexnormal AT linuxmail DOT org


Check out Golem: Lands of Shadow, an isometrically rendered hack-and-slash inspired equally by Nethack and Diablo.

Share this post


Link to post
Share on other sites
Well I''ve made a couple of discoveries.
I compiled two versions of the lua lib, aux lib, tolua lib and tolua exe for both versions 4 and 5.

Version 4
Generates the close function as expected.

Version 5
Does not generate the close function.

Furthermore writing some closing code for version 5 still lets you call that function from lua even though you closed it.

ie.
using lua_pushnil(tolua_S); lua_setglobal(tolua_S,"GetMenu");
then doing dostring(L, "GetMenu();"); will enter the GetMenu() function in your code while in 4.0 it doesn''t.

So I guess it''s 4.0 for me.

Thanks for the help.

Share this post


Link to post
Share on other sites
While it's not really completely on topic it doesn't really warrant starting a new one.

I'm having a little problem with using tolua and default values.

Basically I have a class 'obj' and a constant instance called 'obj_self'. Now if I have a function like this

void DoSomething(obj = obj_self);

In the package and I use tolua it generates the code, but I have to manually go through and change certain lines from

*((obj*) tolua_getusertype(tolua_S,1,(void*)&obj_self));
to
*((obj*) tolua_getusertype(tolua_S,1,obj_self));

I can use a replace all to do it but it still is pretty annoying. Do you have any idea why this would be happening?

Here's the code relating to this.

Package file code

class obj {};

const obj obj_self;

void DoSomething(obj = obj_self);


C++ header

class obj {
public:
...
};

extern const obj obj_self;

With obj_self being declared in a cpp file.

EDIT: Fixed up code tags (hopefully!)

[edited by - Wormy Hellcar on November 14, 2003 6:46:57 AM]

[edited by - Wormy Hellcar on November 14, 2003 6:51:06 AM]

Share this post


Link to post
Share on other sites
I fixed the problem in the last post by just declaring obj_self etc as void* and adding a void* constructor to the obj class. Not very safe but easier than editting the tolua source.

Now I have another problem.

If I do something such as
foo(bar)
where foo has been declared as
void foo(obj)
and bar has not been declared, tolua 'crashes' because it tries to dereference a null pointer.
From what I can see it shouldn't do this as it does a check with tolua_noobj which I would have thought would return true if the userdata pointer was null. I guess I'll have to check the source and see what's up with it.

EDIT: It seemed to be occuring only on functions with default values. ie
decleration: foo(bar = default)
usage: foo(jim)
Where jim hasn't been used (ie, a nil value) would return a null pointer and then be dereferenced. I simply put a check for a nil value in the tolua_touserdata function (not tolua_noobj as I originally, mistakenly thought). Hopefully there won't be any side effects.


The immediate thing that came to mind when I thought of side effects were char* strings.

ie with the function void DoSomething(char* name = "jim")

But with the following code in a script it acts as it should


Command -> value - text
------------------------------------
DoSomething(""); -> nonnull - ""
DoSomething(bar); -> null - ""
bar = "foo";
DoSomething(bar); -> nonnull - "foo"
DoSomething(); -> nonnull - "jim"


EDIT2: Fixed up table (I never learn...)

[edited by - Wormy Hellcar on November 14, 2003 11:47:54 PM]

[edited by - Wormy Hellcar on November 14, 2003 11:49:07 PM]

Share this post


Link to post
Share on other sites
Heh heh. Looks like it''s easier not to reply to this thread, but to just sit back and watch you as you work it out.

Anyway, I''m glad you''re getting it figured out. Keep us posted on how it goes.



Josh
vertexnormal AT linuxmail DOT org


Check out Golem: Lands of Shadow, an isometrically rendered hack-and-slash inspired equally by Nethack and Diablo.

Share this post


Link to post
Share on other sites
Well I have tolua and lua working pretty much as I'd like it to bar two problems.

The first is a memory leak with tolua. I'm using Paul "Midnight" Nettle's memory manager (http://www.flipcode.com/askmid/archives.shtml) which is a bit old and has a few bugs but nothing I can't work around easily.

Now, basically any functions that return a class by value cause a memory leak.
eg in the tolua pkg file

obj Blah();

Will cause an obj to be floating around in the ether when the program exits. I'm pretty sure I'm closing down properly and I saw something about this in another thread (http://www.gamedev.net/community/forums/topic.asp?topic_id=163092) but with no definite answer. I'm going to try asking on the lua mailing list but I figured I'd ask here as well.

I see from your site you have a working game so I figured you might have fixed this memory leak and could help me.
I'm assuming you're using tolua for that project and not something else. Also I made a small test project using tolua 5.0 and lua 5.0 and the memory leak still occured.

I really don't want to have to do things by reference
ie have void Blah(obj&);
in the package then use
something = Blah(something) in the lua code. That just looks horrible for a simple return value.

Here's a sample from the memleaks.log file with one memory leak at exit.

Alloc. Addr Size Addr Size BreakOn BreakOn
Number Reported Reported Actual Actual Unused Method Dealloc Realloc Allocated by
------ ---------- ---------- ---------- ---------- ---------- -------- ------- ------- ----------------
000147 0x04978470 0x00000008 0x04978460 0x00000028 0x00000000 new N N ai.cpp(00147)::??

And the code at that line

void* toluaI_clone = new obj(toluaI_ret);

So basically it creates an obj to push onto the stack as userdata, yet doesn't clean it up later on.

Note that the size difference is just due to padding (I think)


The other problem is that I want to overload a classes operator, but it doesn't seem to want to let me do it.
I basically want to be able to compare one tolua class instance with another tolua class instance and have it enter C code.
ie. I have a constant obj classe obj_invalid and an obj obj_self.
If I do

if(obj_self == obj_invalid) then
-- blah
end

I want it to enter the overloaded function I specify. However tolua doesn't seem to let you overload == or != functions and I couldn't find much info on how to go about using tags from the lua docs. I know I can implement it in a different way such as
obj_self:compare(obj_invalid) but I'm trying to make the scripting as simple as possible and that looks much worse than a simple ==.


Well hopefully you (or anyone else) can help a lua-newb like myself or point me in the right direction
Thanks again in advance.


Oh and I figured out how to fix the void* problem elegently. I just added a void* operator (duh!)
I don't know why I didn't think of that when I was replacing obj_self with (void*)&obj_self (they were around the wrong way in ony of my previous posts)

Now I just select my package project, click build all (then click yes to all those annoying file changed dialogues!) and switch back and can run without having to do lots of replaces.
When I get my scripting syntax complete I'll probably remove the void* operator though to avoid any accidental conversions.

EDIT: I don't think I'll ever get away with a single post that's ever correctly formatted. Why don't these boards have a preview button? Or do they and I'm just completely clueless?

EDIT: Third time lucky...

[edited by - Wormy Hellcar on November 15, 2003 8:17:17 AM]

[edited by - Wormy Hellcar on November 15, 2003 8:18:10 AM]

[EDIT: fixed formatting, it was messing with the page]

[edited by - Andrew Russell on November 16, 2003 8:40:18 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Wormy Hellcar
The first is a memory leak with tolua. I''m using Paul "Midnight" Nettle''s memory manager (http://www.flipcode.com/askmid/archives.shtml) which is a bit old and has a few bugs but nothing I can''t work around easily.

Now, basically any functions that return a class by value cause a memory leak.
eg in the tolua pkg file

obj Blah();

Will cause an obj to be floating around in the ether when the program exits. I''m pretty sure I''m closing down properly and I saw something about this in another thread (http://www.gamedev.net/community/forums/topic.asp?topic_id=163092) but with no definite answer. I''m going to try asking on the lua mailing list but I figured I''d ask here as well.

*snip*



That memory leak has never been a problem for me, as I don''t have anything that returns an object by value. All object creation in my game is handled by centralized allocators, which manage lists of objects and maintain pools of unused objects, to avoid constant allocation and deletion. Any exported function to the script interface calls these allocators to obtain a pointer to a created object.

quote:

The other problem is that I want to overload a classes operator, but it doesn''t seem to want to let me do it.
I basically want to be able to compare one tolua class instance with another tolua class instance and have it enter C code.
ie. I have a constant obj classe obj_invalid and an obj obj_self.



From what I understand, there is no way to do this purely through the tolua interface, though I could be wrong. Instead, what you have to do is implement tag methods in script assigned to the tags of your defined types. Even then, you are limited to tag methods for addition, subtraction, multiplication, division, and power for mathematical operations; that is, there is no tag method corresponding to +=, ++, !=, == or anything like that.

That is just a limitation you have to accept in exchange for a simple and lightweight embedded language such as Lua, I''m afraid. More complicated features mean larger executables, steeper learning curve, etc... If you wish your embedded language to have all the features of C++, you might as well just embed C++.

Anyway, good luck and I hope you continue to get this figured out.

Josh
vertexnormal AT linuxmail DOT org


Check out Golem: Lands of Shadow, an isometrically rendered hack-and-slash inspired equally by Nethack and Diablo.

Share this post


Link to post
Share on other sites
Hmm, I feel a bit silly.
I''m using lua and tolua 5.0 now for a few reasons.
The memory leak *is* fixed in 5.0. It was 3am when I did the test so that''s my excuse


According to tolua 5.0 it does support overloading the == operator and according to lua 5.0 it supports the eq metatable method. However in practise this doesn''t seem to be the case.
If I overload both the == and + operators only the + one is actually called by lua. Infact with the == operator the tolua generated code isn''t even called.
Tolua binds these with

tolua_function(tolua_S,".eq",tolua_ai_obj_operator_eq00);
tolua_function(tolua_S,".add",tolua_ai_obj_operator_add00);

So from what I can tell it''s a lua problem.

There''s also a small bug with adding the const modifier to the package file as it still thinks that ''self'' should be just an "obj" instead of a "const obj".
There''s also a problem with returning a const object.
It tries to do
void* ret = new const obj(...);
Both minor annoyances.


The other ''problem'' is to do with the close function. According to the creator of tolua it''s not meant to generate a close function because of the way it exports the features to a module and it can be easily overwritten.
The problem is that I can''t work out how to do this.


I guess I''m down to three minor problems/annoyances. If I could get them sorted it''d be great. But even with them things are still looking good.


There are two other things that I''d like to do.
Be able to force lua_dofile() to only work on compiled files and also work out how to force it so it doesn''t allow things outside functions like C. Then I could define my own entry point for different scripts as well as ease of passing variables.

I think I could probably do the first but I have no idea about the second, not that it''s vital however.

Share this post


Link to post
Share on other sites
It boggles my mind that everyone seems to use toLua for their interfacing, and they jump through so many hoops to do so. Just do it yourself.


"Sneftel is correct, if rather vulgar." --Flarelocke

Share this post


Link to post
Share on other sites
quote:
Original post by Sneftel
It boggles my mind that everyone seems to use toLua for their interfacing, and they jump through so many hoops to do so. Just do it yourself.



Heh. Yeah. Right now, tolua works pretty simply and is "sufficient" for my needs, as I am keeping the interface simple and I can automate the re-processing of my binding code in my makefiles. As soon as I have to start jumping through hoops, or doing anything inconvenient, I''ll start doing more things by hand. But for the most part, I tend to adhere to the Rule of Generation.


Josh
vertexnormal AT linuxmail DOT org


Check out Golem: Lands of Shadow, an isometrically rendered hack-and-slash inspired equally by Nethack and Diablo.

Share this post


Link to post
Share on other sites