Repository navigation
Question #62
Description
Activity
Thanks for the support !
Will try to answer the questions one by one.
- When pushing a C++ pointer to Lua is it possible to dynamically choose what exposed class to use?
Yes, if the types have been registered with LuaBridge, than it's a matter of casting to your right type (the best cast depends on the usa case and object types, static or dynamic) before sending the pointer/reference into lua (via stack push or function calls from C++).
So if you registered both
class Aandclass B : public A(as derivedClass from A) then it's possible youdynamic_cast<B*>(my_a_pointer)in C++ and send it into luabridge, using normal RTTI in C++.See https://kunitoki.github.io/LuaBridge3/Manual#23---class-objects for more info on how to recreate your C++ class hierarchies to be exposed to lua.
- Can C++ exposed classes be extended in Lua?
Yes ! And only in LuaBridge3 (not in vanilla luabridge). For enabling that support, there is some boilerplate needed, but it will also allow better flexibility once you build one of such "extensible" classes. Have a look at the
addIndexMetamethodandaddNewIndexMetamethodwhich allows to expose a C++ class viabeginClassand still overload__indexand___newindexlua metamethods to store and retrieve "dynamic" parameters (you should write the storage yourself in C++). https://kunitoki.github.io/LuaBridge3/Manual#27---index-and-new-index-metamethods-fallback- Security on possible malicious Lua scripts.
I personally have a strict way to setup my environment, and i carefully select and block environments from exposing functions i do not want a scripter to use. But there is nothing in luabridge for that, you need to do it yourself in lua at the moment. Will try to see if i can extract some of these utils and make them part of the library.
You could have a look at how i do coroutines sandboxed "envs" using LuaBridge3
getNamespaceFromStackin order to have separate env tables for each lua thread (coroutine). So a script running in a lua thread can see only what is exposed in that env table, instead of the global namespace, also a global variable in the env will not leak into the global namespace and interfere with other coroutines.See > https://github.com/kunitoki/LuaBridge3/blob/master/Tests/Source/CoroutineTests.cpp#L82
- What are your future plans with LuaBridge3?
Some things on the roadmap are explicited here #54 (comment)
Thank you for the answer. I've read carefully through it.
The ability to hook into __index sounds awesome. I am just in the process of migrating from the vanilla LB to LB3 here. Once that's done I will look into dynamic class extensions.
I do have one more question tho:
I am writing a Lua wrapper around a pretty big library. The library itself manages all allocation of objects and it's lifetime with a garbage collector. It is impossible to modify the existing library's classes to useRefCountedObjectPtr. I also don't really want to let Lua control the lifetime at all.
So what I did was adding a special version of the classUserdata. Instead ofvoid* m_pI am storing a weak reference to the library objects. Furthermore I've modified all function and property calls from and to Lua to check whether the weak ref is still alive. If it was collected by the GC and is dead a Lua error is thrown.It's pretty ugly right now. So I was wondering if you know a better alternative. I've looked into ContainerTraits but that doesn't seem to work for me. I still need to be able to push and get raw pointers.
You could maybe look into having lightuserdata (http://www.lua.org/pil/28.5.html) to stored full userdata objects in a weak table in the registry (https://www.lua.org/pil/17.html), you only need to register and unregister your real C++ objects into this table, but then give away lightuserdata pointers indexes into the table. If you can find a lightuserdata into the weak table, then you could access the full userdata to it, and if you don't find it, object lifetime ended on the c++ side.
The problem is what to do if your full userdata is garbage collected by C++ while you hold a local reference to it in lua:
- you have the lightuserdata in Lua
- query the table, got the object in Lua
- use the object on the Lua side, which calls back into C++
- some C++ callback triggers the garbage collector which deletes the object
- use again the previously used object in Lua
- boom!
To get back on the index extension feature.
-
Are the
add*MetaMethodfunctions called on derived classes when it's registered on the base class? -
When using your example it sometime crashes when trying call a value as a function.
MyObject.abc = true MyObject:abc() MyObject:xyz()
luabridge::LuaRef indexMetaMethodFunction2(MyVector& x, const luabridge::LuaRef& key, lua_State* L) { UE_LOG(LogTemp, Warning, TEXT("indexMetaMethodFunction")); if (key.tostring() == "xyz") { if (!luabridge::push(L, "123")) lua_pushnil(L); } else { auto it = data.find(key); if (it != data.end()) return it->second; lua_pushnil(L); } return luabridge::LuaRef::fromStack(L); }
Assertion failed: equalstates(L, m_L) [LuaBridge.h] [Line: 6530] lua_topointer() [] std::_Hash<std::_Umap_traits<luabridge::LuaRef,luabridge::LuaRef,std::_Uhash_compare<luabridge::LuaRef,std::hash<luabridge::LuaRef>,std::equal_to<luabridge::LuaRef> >,std::allocator<std::pair<luabridge::LuaRef const ,luabridge::LuaR() indexMetaMethodFunction2() [LuaTest.cpp:558] luabridge::detail::invoke_proxy_function<luabridge::LuaRef (__cdecl*)(MyVector &,luabridge::LuaRef const &,lua_State *)>() [LuaBridge.h:5949] lua_yieldk() luaD_precall() luaM_toobig() lua_callk() luabridge::detail::index_metamethod() [LuaBridge.h:5497]-
Are you working with multiple lua threads (i see a call to yield from the stack trace) ? Beware of stored LuaRef in separate lua threads (coroutines) they have different lua_State pointers (that's why equalstates assertion fails). See if moving the reference to the current thread solves it https://github.com/kunitoki/LuaBridge3/blob/master/Distribution/LuaBridge/LuaBridge.h#L7062
No but I was using a global variable and forgot to reset that. So a new luastate caused that problem.
Anyway I think it is normal that
addIndexMetaMethodmust be registered on the base class and won't work if it is registered in aderivedClassright? If so you should add that to the docs please.Is it normal that when doing the following with your basic test code:
local bc = MyBaseClass(3) bc.test = function(Value) print("Value: ", Value); end bc:test("ok")
The test function will not print the string "ok" but it prints the userdata of
bc.It is normal, as you are calling via
:the first argument is self, so you need to add that explicitly in the function signatureAbout the methods being used in derived classes i'm not sure that will work, i would keep it simple to avoid confusion when calling c++ methods or dynamic methods from lua (use one or the other).
Take a look here http://tpcg.io/_2N67Y8
I am aksing because it is so inconsistent with Userdata. Because for normal registered Userdatas it's the opposite:
MyUserdataObject:MyFunction(p1, p2, p3)
or
MyUserdataObject.MyFunction(MyUserdataObject, p1, p2, p3)
I don't get it, in lua this:
object:func(1)
will be rewritten as
object.func(object, 1)
Sorry for the confusion, you are absolutely right.
- Repository owner locked and limited conversation to collaborators
on Apr 1, 2023
Thank you for your work on this project.
I have some questions and would be very thankful to have some answers.
Let's assume I have exposed multiple classes to Lua with LuaBridge3. They include simple structs like Vectors where lifetime is managed by Lua but also pointers to objects where the host manages lifetime.
When pushing a C++ pointer to Lua is it possible to dynamically choose what exposed class to use?
I often do not know the exact type at compile time.
class A
class B : A // B inherits A
Let's say I have a pointer of type A but it's actually an instance of class B and I want to push the pointer as if it was B.
I think it would require a dynamic database or something of the class keys in ClassInfo.h.
Is something like this possible with LuaBridge3?
Can C++ exposed classes be extended in Lua?
I would like to add functions to C++ exposed classes in Lua. Ideally one could even override existing C++ functions and also call the function of the parent class.
I know that userdata types cannot be extended in Lua but is there some other way to achieve that? Or am I wrong?
Security on possible malicious Lua scripts.
Let's assume we only expose known safe functions to Lua and forbid bytecode. Did you do some research or tests on LuaBridge3 whether it is safe to run unknown Lua code.
What are your future plans with LuaBridge3?
Would be nice if you could share your plan on features etc. you might be working on in the future.
Thank you again for your work and time.