Skip to content

Instantly share code, notes, and snippets.

@dhkatz
Last active May 30, 2024 09:29
Show Gist options
  • Save dhkatz/023301d78ad5cdd660eb3775d97e53a5 to your computer and use it in GitHub Desktop.
Save dhkatz/023301d78ad5cdd660eb3775d97e53a5 to your computer and use it in GitHub Desktop.
Sol2 + RTTR

Sol2 + RTTR Example

This isn't tested, but it's basically what I've gotten working in my own project as of now.

RTTR is really cool and will let you save type information for elsewhere in your project (maybe an editor if it's a game engine), but also using visitors will allow you to automatically integrate with other existing libraries like sol2, chaiscript, etc.

The biggest pain point I found was working with the usertypes generically. The documentation is kind of bad in this case.

I thought I could just do this:

    template <typename T>
    void visit_property(const property_info<T>& info) {
        auto name = info.property_item.get_name().to_string();
        auto table = info.property_item.get_declaring_type().get_name().to_string();

        // Register the property on the usertype!
        lua[table][name] = info.property_accessor;
    }

However, it seems like accessing the usertype through direct indexing doesn't quite work. Indexing in this way uses table proxies and such to let you do fancy chained indexing, lazy evaluation, etc.

Instead, you have to explicitly retrieve the table as a sol::usertype<T>:

  template <typename T>
  void visit_property(const property_info<T>& info) {
      // We can grab the underlying class type here (in this example it's vector3)
      using Class = typename property_info<T>::declaring_type;

      auto name = info.property_item.get_name().to_string();
      auto table = info.property_item.get_declaring_type().get_name().to_string();

      // Explicitly get a sol::usertype<T> from the global table.
      auto usertype = lua.get<sol::usertype<Class>>(table);

      usertype[name] = info.property_accessor;
  }
#include <sol/sol.hpp>
#include "vector3.hpp"
int main() {
sol::state lua{};
lua.open_libraries(sol::lib::base);
script::visitor visitor{lua.globals()};
visitor.visit(rttr::type::get_by_name("vector3"));
lua.script(R"(
local v = vector3.new()
v.x = 10.0
print(v.x)
print(v.y)
print(v.z)
)");
return 0;
}
#include <visitor.hpp>
#include <rttr/registration>
class vector3 {
float x;
float y;
float z;
};
RTTR_REGISTRATION {
rttr::registration::class_<vector3>("vector3")
.constructor<>()
.property("x", &vector3::x)
.property("y", &vector3::y)
.property("z", &vector3::z);
}
#include <rttr/visitor.h>
#include <sol/sol.hpp>
namespace script {
class visitor : public rttr::visitor {
public:
explicit visitor(sol::global_table state): lua(std::move(state)) {}
template <typename T, typename... Bases>
void visit_type_begin(const type_info<T>& info) {
using Class = typename type_info<T>::declaring_type;
auto name = info.type_item.get_name().to_string();
lua.new_usertype<Class>(name);
}
template <typename T, typename... Args>
void visit_constructor(const constructor_info<T>& info) {
}
template <typename T>
void visit_method(const method_info<T>& info) {
using Class = typename method_info<T>::declaring_type;
auto table = info.method_item.get_declaring_type().get_name().to_string();
auto name = info.method_item.get_name().to_string();
auto usertype = lua.get<sol::usertype<Class>>(table);
// You should probably handle sol::meta_function's here too! Such as operators like +, -, etc.
usertype[name] = info.function_ptr;
}
template <typename T>
void visit_property(const property_info<T>& info) {
using Class = typename property_info<T>::declaring_type;
auto name = info.property_item.get_name().to_string();
auto table = info.property_item.get_declaring_type().get_name().to_string();
auto usertype = lua.get<sol::usertype<Class>>(table);
usertype[name] = info.property_accessor;
}
private:
sol::global_table lua;
RTTR_ENABLE(rttr::visitor)
};
RTTR_REGISTER_VISITOR(visitor);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment