I have used SWIG to bind a set of classes to lua. I know C++ itself doesn't support monkey patching, and I'm not trying to modify my C++ objects, merely their lua representations. The problem comes if I want to start monkey patching the lua tables and objects exported by SWIG, so that I can modify the API presented on the lua side.
e.g. the following lua code:
game.GetEnemies1 = game.GetEnemies2
does not work as expected. The behaviour after that line is still consistent with the original GetEnemies1 not GetEnemies2.
how do I combat this problem?
I've successfully monkeypatched lua userdata by adding and replacing existing methods. It involved modifying their metatables.
Here's a sample of what I had to do in order to add a couple methods to an existing userdata object.
As you can see, instead of modifying the object iself, I had to modify its metatable.
This solution will only work if your userdata objects are set up so their metatables "point to themselves": mt.__index = mt.
Regards!
Swig generates lua wrappers from c++ functions, it does not inject lua functions into c++. If GetEnemies1 is a c++ function, called from other c++ functions, monkey patching wont work.
You will have to rewrite your c++ code so that the code which executes GetEnemies1 looks for some sort of callback which you can wrap with swig.
Related
---Context---
I want to have a class called "fileProcessor". This class is completely static and merely serves as a convinient namespace (within my normal library namespace) for some global function. This is a basic blueprint of the class with only the relevant stuff
class fileProcessor{
private:
lua_State* LUA_state;
public:
static std::variant<type1,type2> processFile(const char* filePath,const char* processorScript);
}
Please note again that I ommitted most of the stuff from the class so if anything seems odd ignore it.
What process file is supposed to do is:
Read the filePath file, storing all directives including it (this is my own filetype or style of syntax. This is already handeled correctly). The directives are stored with strings, one for the command and one for everything after it.
Read the script file and check if it has a commented out fileProcessor line at the top. This is to make sure that the lua script loaded is relevant and not some random behaviour script
Load and compile the lua script.
Make all read directives available (they are saved in a struct of 2 strings as mentioned before)
Run the file and recieve a object back. The object should only be of types that I listed in the return type (variant)
I am having problems with step 4 and one vital part of the scripting.
---Question---
How can I make the creation of a full new object of type1 or type2 possible within lua, write to it from within lua and then get it back from the lua stack into c++ and still know if its type1 or type2?
---No example provided since this question is more general and the only reason I provided my class is for context.---
It seems like you are trying to do it the other way around. I quote a part of this answer:
...you are expecting Lua to be the primary language, and C++ to be the client. The problem is, that the Lua C interface is not designed to work like that, Lua is meant to be the client, and all the hard work is meant to be written in C so that Lua can call it effortlessly.
If you are convinced there is no other way that doing it other way around you can follow the workaround that answer has given. Otherwise I think you can achieve what you need by using LUA as it meant to be.
LUA has 8 basic types (nil, boolean, number, string, userdata, function, thread, and table). But you can add new types as you require by creating a class as the new type in native C++ and registering it with LUA.
You can register by either:
Using some LUA helper for C++ like luna.h (as shown in this tutorial).
Pushing a new lua table with the C++ class (check this answer).
Class object instance is created in your native C++ code and passed to LUA. LUA then makes use of the methods given by the class interface.
I'm using Lua for scripts in my C++ game. I want to be able to attach scripts to entities, and based on which functions are defined in the script, register for callbacks which will run the script functions at the appropriate time.
I believe that I can encapsulate different scripts from each other, by making the "script" into a table. Basically, ... lua source code ... would become ScriptName = { ... lua source code ... }. Then instead of calling func(), I'd call ScriptName.func(), and thus two scripts defining the same function (aka registering for the same event) wouldn't trample over each other.
My problem now is in encapsulating different entities sharing the same script. Obviously I don't want them to be sharing variables, but with what I'm doing now, any variable defined by a script would be shared by every instance of that script, which is just really bad. I could maybe try something similar to my above solution on the source level, by wrapping every script with EntityID.ScriptName = { ... } before compiling it. Something tells me there's a better way, though, I just don't know it.
Another factor is that scripts need to be able to reference entities and scripts/components relative to a specific entity. If I use the above method the best solution to this would be passing entity IDs around as strings which could reference the table specific to that entity, I think? At this point I really have no idea what I'm doing.
In order for a script to interact with a C++ object, the typical approach is to have the C++ code expose the object to Lua as a userdata (a wrapper for a pointer) and provide C++ functions that the script can call, passing the userdata as parameter. In the C++ code, that userdata gives you the object that the function should to operate on. It's equivalent to a "this" pointer.
You usually do this by putting the C++ functions into a metatable associated with the userdata, so they can be called like methods in the Lua code (i.e. objectIGotFromCpp:someMethod('foo').
ScriptName.func(), and thus two scripts defining the same function (aka registering for the same event) wouldn't trample over each other.
Rather than relying on accessing globals or naming conventions, ect. it's much cleaner to simply provide a callback that Lua scripts can use to register for events.
If I use the above method the best solution to this would be passing entity IDs around as strings
No reason. An entity in your C++ code is a pointer to an object on the heap. You can pass that pointer directly to Lua as userdata. Lua can pass that back to your C++ code and give you direct access to the object, rather than going through some object-to-ID mapping.
I finally got into a problem that I can't find a solution here. I'm using a Lua Wrapper Class found in here http://lua-users.org/wiki/CppConvenientLuaWrapperClass. We've been able to expose a complete API plus more other funcionalities like serial communication and on.
The concept behind this Lua Wrapper is that you expose every method before compiling so when you're running your programm all methods will be added to the Lua Stack and in that way you can execute them. The idea now is to build kind of a Dll in order to complete this process of exposing methods. This way you won't needed to release a version with all exposed methods instead you load them trough multiple dll files.
I've tried to create another table and register other methods in that table, but with that, previous exposed methods stop working.
The other way around I can think of, is to create a dll but in C that contains all desirable methods and load it directly to Lua. But I think the other way would be better.
Have you been able to do something similar ? Am I having some wrong concept?
Thanks
Humm... I really don't want to change our wrapper at this time. I think I could manage to do it, sort of. Instead of adding a new table for the plugin functions, I've added a new sub-table tha will contain the functions names and cClosures to be called from Lua.
So at the end we should have:
application.functionName()
application.plugin.functionName()
Even if it work this way it will do fine.
Now I wonder how can we reference the lua_settable when exposing the functions to be added to application[plugin][pluginFunction] instead of aplication[pluginFunction]?!
This is how the normal functions are exposed:
//mState is a pointer to a Lua_State
lua_pushstring( mState, functionName );
//methodDesc is a pointer to an object that describes the function arguments/returns
lua_pushlightuserdata( mState, methodDesc );
//exposeMethodProxy is the method that is responsible for conneting lua c-calls to the c-functions
lua_pushcclosure( mState, exposedMethodProxy, 1 );
//mMethodTableIndex is a member variable that contains the index of the table tha hold all exposed functions
lua_settable( mState, mMethodTableIndex );
Any ideas on how I could achieve adding the cclosures not to the main table(at mMethodTableIndex) as mainTable[functionName] but at maintable[plugin][functionNane].?
I'm not sure, you're clear on what you want to do. A typical way to extend lua is to write a DLL with a single method that uses the Lua API to register your C++ types and C functions. To conviniently bind C++ functions and classes, you could use LuaBridge. An example of such binding is here: https://github.com/d-led/xerceslua
The header for the DLL of the xerceslua module contains only one function:
#include <lua.hpp>
void register_xerceslua (lua_State* L);
inside the implementation LuaBridge is used to bind to C++:
#include "xerceslua_lib.h"
#include <lua.hpp>
#include <LuaBridge.h>
void register_xerceslua (lua_State* L) {
...
luabridge::getGlobalNamespace(L)
.beginNamespace("xerces")
.addVariable("version",&version,false)
...
in Lua you can then access the exposed C++ API:
assert(require 'xerceslua')
local parser=xerces.XercesDOMParser()
parser:loadGrammar("Employee.dtd",xerces.GrammarType.DTDGrammarType)
You can use Lua both as an embedded scripting language, where you can execute lua from within your software, or you could use it as an extensible scripting language, extending it using the method shown above. Both are valid, but you have to consider, what exactly you are trying to do.
I have a function which exposes all of my required C++ functions to Lua, there are various tables representing different aspects of my "Scripting API", what I wish to do is use doxygen to make a scripting reference using the C++ code that exposes these script functions.
I have tried to make 'fake' classes in the body of the function, which successfully makes a new entry with the name I have given it, for instance if I make a table named 'Math' which has several functions exposed on it, how would I also make 'fake' member functions in this 'fake' class, I have tried to simply pass in \fn defining the function, however it does not show up as they are not actually real members to add a description to. How would I create this sort of effect in doxygen without hand righting a verbatim definition of every class, but instead treat the comment block as if it were a real class with real members?
It sounds like you're trying to document Lua code as if they were C++. Maybe it's possible, but it's probably more trouble than it's worth.
If you're trying to document Lua code with doxygen, maybe you could try doxygen-lua.
If your Lua API is small, you could just write a page by hand, with \ref's to the relavent C++ code. (Kind of hacky, but I've done this before.)
You could also consider using some other doc generator for your Lua API, such as LuaDoc, or anything else listed on the lua-users wiki DocumentingLuaCode.
I ended up writing a fake .doxy file which had typenames similar to lua values, apparently doxygen will document any type to throw at it.
I'm exporting some c++ classes to Lua with SWIG. I have declared boost::filesystem::path in the SWIG interface file like this:
namespace boost
{
namespace filesystem
{
class path {};
}
}
Now I want to call a function declared in a lua script which should take a boost::filesystem::path& as parameter to pass it to another object. I only need to be able to pass the path to the object. I don't need to use any functionality from the path object.
function on_path_selected(the_path)
another_object:set_path(the_path)
end
I am going to call the Lua function from c++ using it's index.
lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_index);
lua_push[SOMETHING](L, path_object); // <-- HOW TO ?
lua_pcall(L,1,0,0)
THE QUESTION: How to push a boost::filesystem::path as a parameter to the Lua function?
This is actually fairly complicated. The expected use of SWIG is to create modules for Lua. The Lua script should be the one deciding what gets called and what doesn't. It isn't really meant for embedded use, where you use SWIG to expose some C++ objects and then call Lua code directly from your application.
That's not to say that it's impossible, just complicated.
All SWIG-based C++ objects are passed through Lua as pointers. Thus ownership is a question; you can't just shove a pointer to a stack object into Lua.
The safest way to do this is to pass a new copy of the object to Lua. That way, Lua owns the pointer. SWIG will know that Lua owns the pointer, and will attach a proper garbage collection mechanism to it to clean it up. So everything should be fine, memory wise.
But doing this requires properly "boxing" (for want of a better term) that object the way that SWIG wants it done. This requires using certain SWIG macros.
Given how you have bound the path type to SWIG, you would do something like this to stick it onto a Lua stack:
swig_type_info *pathType = SWIG_TypeQuery("boost::filesystem::path *");
boost::filesystem::path *pArg = new boost::filesystem::path(the_path);
SWIG_NewPointerObj(L, pArg, pathType, 1);
SWIG_TypeQuery fetches the type of any object that has been bound by SWIG to Lua. This type info object is needed for SWIG_NewPointerObj, which takes a pointer to that type. Both of these are macros. SWIG_NewPointerObj gives Lua ownership of the pointer; Lua's garbage collector will delete it thanks to SWIG's metatables. Also SWIG_NewPointerObj pushes the object onto the lua_State stack.
Once it's on the stack, you can pretty much do whatever you want with it. Return it from a function to Lua, pass it to a Lua function as an argument, stick it in a global variable, etc. It's a Lua value.
Now, if you type this code into your project, odds are good that you'll get a compile error when the compiler sees swig_type_info. This type is defined internally within the source file generated by SWIG's command-line.
You have two options:
Put this source code into the .swig file itself. Yes, really. You can define regular C++ functions there, within verbatum sections (the %{ %} delimited blocks). These functions will be copied directly into SWIG's generated code. You can access them by putting prototypes in headers. This is the simplest and easiest way to work. This is often used for creating special interfaces, where a pre-existing C++ function isn't appropriate for a Lua API (or simply doesn't exist).
You can generate an appropriate header that contains these definitions with the -external-runtime argument. This has to be a different SWIG execution step from the step that generates the .cpp file. See, it doesn't actually process the SWIG file or anything. All it needs is the target language (-lua) and whether you're using C++ (-c++).So just have a command that does swig -c++ -lua -external-runtime someheader.h, and that's all you need to get the types and macros.
Include that header in whatever source you want to attach SWIG-bound objects to Lua in.