Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

384 Neutral

About Gambini

  • Rank
  1. 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.
  2. Gambini

    Arrgh openGL!

    You should have a directory with all of your .lib files in it. Then, in the project properties (make sure you do this for Release and Debug), put that directory in to Linker->General->Additional Library Directories. The directory you give should be relative to the .vcproj file (or absolute), or another option is to use the built-in VS macros to define it relative to your solution directory by doing something like "$(SolutionDir)../lib;". Then head over to Linker->Input->Additional Dependencies and list your .lib files spearated by semicolons (or one per line if you use the drop-down menu and hit the <Edit...> option) . Make sure to hit "Apply" at the bottom right instead of just pressing "Ok". Example for the Additional dependencies, part of mine looks like "glew32.lib;opengl32.lib;glu32.lib;"     opengl32.lib should be provided by the system, so you don't have to give a specific directory for that, you should just be able to add it to the Additional Dependencies.
  3. It looks like out_value doesn't work well with MSVC (here).   You'll have to either re-think the function or use Lua's "string.upper" function.   Another option is to make your own string class with UCase as a member function. That would bind perfectly fine to Lua, since UCase wouldn't need to take any parameters and only modify the object data.
  4. 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'
  5. 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.
  6. luaL_ref is what you are looking for. As long as you don't destroy/close the lua_State that the ref was made in, the function will exist until you call luaL_unref. lua_ref is a macro that will make the ref in the global registry if you don't want to specify a table yourself.
  7. 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.
  8. May I suggest that you don't? I'll give an example specifically for openal-soft:   I tried to run Euro Truck Simulator 2, but it would crash immediately on startup. I remembered that this happened for one specific version of openal soft when working on my own game, so I was able to replace ETS2's dll with a newer one, which stopped the crashing. It took a few hours of reinstalling and trying everything under the sun before I realized it, but I would not have been able to play if they had linked it statically.     That said... Compiling (which you said you did, and cmake probably did the right thing): Go to openAL-soft's config.h (should be in the directory where the other openal projects are generated), and make AL_API and ALC_API defined as nothing. Then, go in to the OpenAL32 project in VS -> Properties -> General -> Configuration Type set to static library. Of course, do this for all release/debug/whatever else. Build OpenAL like that.   Linking: In the project that you intend to statically link openAL in to, have AL_LIBTYPE_STATIC defined (Project-> Properties-> C/C++ ->Preprocessor -> Preprocessor Definitions). Found that in al.h line 9.
  9. Gambini

    Individual scripts per object in Lua

    You can wrap all of the <scripts> tags with return function() <scripts> contents end when you load them, and set the function environment for those. If you are using 5.1, then getfenv and setfenv are what you are looking for. If you are using 5.2, then the function will have an _ENV variable. I haven't used them myself, so I can't really get any more specific, but maybe that will help direct your search.
  10. 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);
  11. Gambini

    libRocket, GWEN, or something else for GUI?

    I'll share my experience with libRocket, which I have both used and have contributed Lua bindings to. If you have experience with HTML4/CSS, then you should use Rocket just because it is something you are familiar with. However, it also comes with the inflexibility of HTML and CSS, and things like animations will have to have special element types that you make yourself. However, almost anything is possible without too much work. It does come out of the box with its own look and CSS page for its 'Invaders' demo which gives you a good starting point to branch off from. The thing that sets Rocket apart is the in-game debug window where you can inspect elements and see its parents,children,style sheet, line numbers, files, templates, classes, and the like. It is something that I haven't seen in other libraries, and I have found it incredibly useful. I could go on, and if you want to know about a certain aspect then I can answer your question. But to sum it up, it is a mature and easily extendable library that does what it sets out to do, and does it fairly well. Just to be clear, it is very far from perfect; I only pointed out the good in this post. However, your issues will more than likely stem from your misunderstanding rather than a bug in the library, which is something that I take comfort in.
  12. Sorry to take so long to reply, but I have been looking for an example of some other library having a scripting/behavior system without explicit namespacing, and I have yet to find one. If you could point me to an example (if you know of one), then it shouldn't be too hard to reason around it. I like the idea, and I wouldn't mind using it myself somewhere. And yes, keep the number of lua_State-s to one. Only break that rule when you figure out why, and even then it is questionable except for having one lua_State per thread. It gets complex quickly when dealing with more than one.
  13. 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.
  14. Gambini

    lua_pcall using luaL_loadstring

    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.
  15. Gambini

    lua_pcall using luaL_loadstring

    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".
  • 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!