Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Gambini

Member Since 11 Apr 2012
Offline Last Active Nov 15 2014 08:48 PM

#5186590 Should i to compile using static library or shared library?

Posted by Gambini on 12 October 2014 - 07:33 PM

I recently came upon this problem in Windows where there were two shared libraries compiling with Lua statically, which caused a crash when passing a lua_State* between the two. It was fixed by linking Lua as a shared library, which is a wonderfully descriptive name for when it is appropriate to use, seeing as it was shared by the two libraries.

 

It will differ per project, and most libraries will say when they are better done as static libraries. If you want some definitive answer, then link everything shared until the library explicitly says to do it static.

 

In the case of choosing static or shared, the difference in code execution speed will not be great enough to make a difference. There are some link-time optimizations that can happen with static libraries, but I wouldn't count on that bringing you from 30fps to 60fps.




#5059297 problem binding a c++ function with luabind

Posted by Gambini on 04 May 2013 - 04:33 PM

http://www.rasterbar.com/products/luabind/docs.html#out-value

 

That explains how your C++ functions can't take non-const ref/pointers if you want to bind them to Lua. So, the out_value function policy will add a return value in Lua code, rather than modifying the input.

Where your C++ code would look like

char* str = "hi";
UCase(str);
std::cout << str; //prints 'HI'

Your Lua code would look like

local str = "hi"
local ucstr = UCase(str)
--// or you can have str = UCase(str)
print(ucstr) //prints 'HI'



#5058689 Porting from Visual C++ 6.0 to Visual Studio Tricks and Tips?

Posted by Gambini on 02 May 2013 - 12:41 PM

To narrow down your errors, you could try some static code analysis tools. If you have a fat wallet, I've heard some decent things about PVS Studio. If you are on more of a budget, then VS2012 (not sure about express) has some integrated static analysis, and there's a few other options if you search around the Internet.




#5051392 [Lua] Installing/compiling and usage of Lua in Windows

Posted by Gambini on 08 April 2013 - 09:39 PM

There's a bit of boilerplate code going on with running your own binding if you are using c++, especially when dealing with object oriented stuff. But after you get that out of the way, you can probably write a script that will parse your .h files and output binding code which would require very little fixing. That's what I've done in my most recent project, and it is always a bit of a pain binding classes, but not so much that I hate myself. http://lua-users.org/wiki/BindingCodeToLua for a place to start.

 

If you don't mind depending on boost, then luabind is the way to go. Boost adds an incredible amount of utilities, with the cost of keeping up with another 3rd party library. I've used luabind previously, and the binding code is simple, and easy to read/write. I'd absolutely recommend luabind if you aren't doing this for purely educational purposes.

 

Make sure to take a look at LuaJIT as well. You specifically said 5.2, but LuaJIT has all of 5.1 and some of 5.2 at the same time.




#5040680 Luabind Property not working when from luabind::globals

Posted by Gambini on 07 March 2013 - 09:51 PM

Typo, change "ts" to "test":

 

...
//Make lua global test equal to local ts
    luabind::globals(l)["test"] = &ts; <- right here, the global variable is named "test", but you try to use it as "ts" in your string
...
//Then, using the variable grom luabind::globals... DOESN'T WORK.

luaL_dostring(l,
        "print(ts.stack)\n"   <- right here, used "ts" rather than "test"
        "ts.stack = 8\n"      <-
        "print(ts.stack)\n");<-

 

A tip: lua will spit out compile/runtime errors. luaL_dostring (http://pgl.yoyo.org/luai/i/luaL_dostring) and all of the other code compiling/executing functions return non-zero if an error occurs. A simple error-reporting function looks like

 

//all of the error messages are pushed on to the stack, so while there are items on the stack, pop and print them
void Report(lua_State* L)

{
    const char* msg = lua_tostring(L,-1);
 
    while(msg)
    {
        lua_pop(L,1);
        std::cout << msg << std::endl;
        msg = lua_tostring(L,-1);
    }
 
}
//usage would be something like
if(luaL_dostring(L,....) != 0)
    Report(L);



#4948021 Delayed execution of behavior functions in Lua/C++

Posted by Gambini on 10 June 2012 - 04:09 PM

This is one heck of a question. I am not familliar with luabind, so I will go over the general ideas, and maybe hit some specifics.

I'm going to make a few assumptions, and some of which might be wrong. I'm assuming that the Lua scripts are on the server, and that the ProcessAI function is called fairly regularly (at least every 100 ms for decent accuracy, up to 1000 ms). I'm also assuming that you are using luabind, rather than rolling your own bindings. I strongly suggest you not do your own bindings unless you really want to learn the Lua C API or have a large timeframe you want to complete the project in.

The ScheduleEvent function is first. Hopefully http://www.rasterbar...g-lua-functions will give you a decent idea as to where to start when calling Lua functions from C++. The interesting part is having timed events. You will need a single container to hold all of the events. It needs to be sequential and have fast random access; linked list seems to fit the bill perfectly.

Overall idea is to have a sorted list, which is done by placing each node in the list to its correct location upon insertion. The next part assumes that you have a running total game time. Each node will have the time at which the event should be fired, which function to call, and any data that needs to be passed to that function. During or before each ProcessAI call, you should go through the list comparing the current time to the time when it should fire. Because it is sorted, you can stop iterating over the list when you find an event that should not be fired. C++ code will look something like this:
//note that this probably won't compile, it is a mix of real C++ and pseudo code
//function is the function to call
//delay is the time in milliseconds from now from when it should be called
//repeat is the number of times to call (bad name?). -1 is a special value for "infinite"
//args is the object to be passed to "function". It can be an actual object or a table of objects.
void ScheduleEvent(luabind::object const& function, int delay, int repeat, luabind::object const& args)
{
	if(repeat < 1) return; //if the user wishes to call the function 0 times, then don't call it.
	long absolute_delay = current_time + delay; //current time is how long it has been since the program started in milliseconds
	ScriptEvent* event = new ScriptEvent(absolute_delay,repeat,delay,function,args);
	//there is a list defined elsewhere named EventList as std::list<ScriptEvent*>
	//insertion sort
	for(itr = iterate over EventList)
	{
		if(event->delay <= (*itr)->delay)
			{ EventList.insert(itr,event); break; }
	}
}

struct ScriptEvent
{
	long delay;
	int repeat;
	int repeat_delay; //the original time passed to the function
	luabind::object function;
	luabind::object args;
	ScriptEvent(long delay,int repeat,int repeat_delay, luabind::object const& function, luabind::object const& args) { set the values}
	ScriptEvent(const ScriptEvent& se) { copy constructor}
}
Simple enough, it does exactly as I explained above. The next snippet is called every ProcessAI or Update or some regular interval.
//I'm going to assume that by now, current_time has been updated
void CheckEvents()
{
	//fire all of the events that should have happened since now.
	for(itr = iterate through EventList)
	{
		if((*itr)->delay >= current_time)
		{
			ScriptEvent* evt = (*itr);
			luabind::call_function(evt->function,evt->args);
			if(evt->repeat == -1) //special case of inifinite
			{
				evt->delay += evt->repeat_delay;
				AddToEventList(evt);
				continue;
			}
			evt->repeat -= 1; //decrement the number of times to fire the event
			if(evt->repeat > 0) //if we should repeat again
			{
				evt->delay += evt->repeat_delay; //set next time to fire
				//insertion to a list while iterating through it does NOT
				//invalidate the iterator
				AddToEventList(evt);
			}
			else
			{
				delete evt;
				evt = NULL;
			}
			//since it has been called, remove it from the list so it won't get
			//called again.
			itr = EventList.erase(itr);
		}
		else
			break; //it is sorted, so no need to go through every item
	}
}

//insertion sort function
void AddToEventList(ScriptEvent* node)
{
	for(finditr = iterate through EventList)
	{
		if(node->delay <= (*finditr)->delay)
			{ EventList.insert(finditr,node); return; }
	}
}
It looks like a lot, but it is just a whole bunch of integer comparisons and pointer dereferencing, so it should not be too expensive other than luabind::call_function.

To answer your second question: The functions are in the same scope as long as they are loaded (luaL_dofile) with the same lua_State. So you can call those functions any time you want. However, I do suggest that you create tables named after each NPC behavior to hold those functions to avoid name conflicts. Example
--Lua code in file Miner.lua or something
--create a table to hold  the NPC behavior functions. This NPC is a "Miner"
Miner = Miner or {} --equivelant to if(Miner == nil) then Miner = {} end, so we do not overwrite a table that has already been created

function Miner.StartConversation1(NPC)
	NPC:DoStuff()
end


--some other file BigBoss.lua
BigBoss = BigBoss or {}
function BigBoss.BargainWithMiner(NPC)
	local miner = BigBoss.FindMiner(NPC) --finds a miner in range of it
	Miner.StartConversation1(miner)
end

It is a lot, and I have probably misunderstood a question. If you need more details on a certain point, just say so.


#4930491 lua_pcall using luaL_loadstring

Posted by Gambini on 11 April 2012 - 11:44 PM

Is there a reason you do not want to execute the code? If they are just function definitions, then I do not see a downside to executing the code. If there are commands outside of a function that you don't want to run, maybe you should move those to a different file or something which you control when it runs. However, maybe you are thinking that compiling does more than it really does.

When you do loadstring, it converts the .lua file in to a Lua binary and puts it on the top of the stack as a function. It only converts. Nothing else. It does not have any effect on the Lua enviornment other than existing as a bunch of 1s and 0s. Think of it as in C++ you create a .dll, but you don't link with it yet.

When you execute that binary from loadstring, it is similar to actually linking with the .dll, and you can use the things defined in it. You have to remember that in Lua, functions are first-class data types similar to numbers and tables. Your add function could also be defined as
add = function(x,y)...your stuff here......end
and would produce the same outcome as you had it before, but this makes it easier to see the following:

When the code is executed, it goes through all of the file and runs all of the code. That seems entirely obvious, but with the function syntax being the way you used it, it isn't exactly easy to see how the functions come in to existence. Maybe the next example will help
--file example.lua
tbl = {}

add = function(x,y)
	return x + y
end

local a = 0
b = 2
c = add(a,b) -- c = 2
So, when that is compiled (loadstring/loadfile), the global table is unchanged. Nothing has been executed, and so nothing can be changed. However, after execution, the global table will look something like this
_G = { tbl = {}, add = function(x,y) return x+y end, b = 2, c = 2 .......whatever else was in _G before }
And the variable 'a' is local, so it isn't defined in the global scope.

There is a way to use loadstring to compile a string to run later, but you lose the advantage of having a named function. For that, look at the docs for luaL_ref.

However, there is really no downside to executing the code if all it does is define a function. It won't execute the function, if that is what you were worried about (unless you actually call the function, like I did with the 'c' variable in the example).

Edit: I see you replied while I was typing this out. I'll leave this here for people who google it later.


#4930367 lua_pcall using luaL_loadstring

Posted by Gambini on 11 April 2012 - 03:15 PM

luaL_loadstring does not run the string, it only compiles it. Because you are only compiling the string, the function hasn't been defined yet for Lua, it is just sitting there in binary form on the stack. Two suggestions:
Do luaL_dostring, which calls luaL_loadstring and then runs the string.
Or, use luaL_dofile which does the same thing as luaL_dostring, but with a file.

After it gets executed, then the function will exist in the global table and you can retrieve it like you expected you could earlier.

If there are more specific questions, then ask away since I didn't go too in-depth on the "why" or "how".


PARTNERS