Create a PoC version of the scripting engine
This commit is contained in:
parent
50c668c467
commit
51206d60d4
|
@ -0,0 +1,14 @@
|
|||
# Get the sol2 header libraries.
|
||||
include(FetchContent)
|
||||
message("Downloading sol2 library...")
|
||||
set(SOL2_ENABLE_INSTALL OFF)
|
||||
set(SOL2_BUILD_LUA FALSE)
|
||||
set(SOL2_LUA_VERSION "5.2")
|
||||
FetchContent_Declare(
|
||||
sol2
|
||||
GIT_REPOSITORY https://github.com/ThePhD/sol2.git
|
||||
GIT_TAG v3.3.0
|
||||
)
|
||||
FetchContent_MakeAvailable(sol2)
|
||||
message("Downloaded sol2 library to: ${sol2_SOURCE_DIR}")
|
||||
set(sol2_INCLUDE_DIR ${sol2_SOURCE_DIR}/src)
|
|
@ -8,6 +8,7 @@ include(CMake/GetEnTT.cmake)
|
|||
|
||||
# Add some CMake options:
|
||||
option(SIMPLE_ENGINE_BUILD_EXAMPLES "Build example projects" ON)
|
||||
option(SIMPLE_ENGINE_DOWNLOAD_SOL2 "Download sol2 from github. I fits off, SimpleEngine will try to find it in the system." ON)
|
||||
|
||||
# By default use OpenGL GLVND
|
||||
option(SIMPLE_ENGINE_USE_GL_LEGACY "Use OpenGL legacy, or use BLVND" OFF)
|
||||
|
@ -17,6 +18,16 @@ else()
|
|||
set(OpenGL_GL_PREFERENCE "GLVND")
|
||||
endif()
|
||||
|
||||
# Download sol2 or search the system. We also search for lua since we have to include it for the linker
|
||||
find_package(Lua 5.4 REQUIRED)
|
||||
if (SIMPLE_ENGINE_DOWNLOAD_SOL2)
|
||||
set(SOL2_BUILD_LUA FALSE)
|
||||
set(SOL2_LUA_VERSION 5.4.4)
|
||||
include(CMake/Getsol2.cmake)
|
||||
else()
|
||||
find_package(sol2 REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(GLEW REQUIRED)
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
|
@ -25,6 +36,7 @@ find_package(fmt CONFIG REQUIRED)
|
|||
find_package(spdlog CONFIG REQUIRED)
|
||||
find_package(assimp CONFIG REQUIRED)
|
||||
find_package(Bullet REQUIRED)
|
||||
find_package(RTTR CONFIG REQUIRED Core)
|
||||
|
||||
# Link sources
|
||||
file(GLOB_RECURSE source_list src/*.cpp)
|
||||
|
@ -51,6 +63,9 @@ target_link_libraries(simpleengine PUBLIC glfw)
|
|||
target_link_libraries(simpleengine PUBLIC ${GLM_LIBRARIES})
|
||||
target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(simpleengine PUBLIC ${BULLET_LIBRARIES})
|
||||
target_link_libraries(simpleengine PUBLIC ${LUA_LIBRARIES})
|
||||
target_link_libraries(simpleengine PUBLIC RTTR::Core)
|
||||
target_link_libraries(simpleengine PUBLIC sol2::sol2)
|
||||
if(WIN32)
|
||||
target_link_libraries(simpleengine PUBLIC assimp::assimp)
|
||||
target_link_libraries(simpleengine PUBLIC fmt::fmt)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
cmake_minimum_required (VERSION 3.6)
|
||||
project(DevTesting DESCRIPTION "A testing project for engine developers.")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-Og")
|
||||
|
||||
add_executable(dev_testing src/main.cpp)
|
||||
|
||||
# Link headers and source files.
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "simpleengine/gfx/renderer.h"
|
||||
#include "simpleengine/gfx/texture.h"
|
||||
#include "simpleengine/vector.h"
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <optional>
|
||||
#include <semaphore.h>
|
||||
#include <simpleengine/ecs/component/model_component.h>
|
||||
#include <simpleengine/ecs/component/rotating_component.h>
|
||||
|
@ -27,6 +29,9 @@
|
|||
#include <simpleengine/log/logger.h>
|
||||
#include <simpleengine/physics/physics_system.h>
|
||||
|
||||
#include <simpleengine/scripting/ecs_bindings.h>
|
||||
#include <simpleengine/scripting/entt_meta_helper.h>
|
||||
|
||||
#include "entt/entity/fwd.hpp"
|
||||
|
||||
#include <assimp/material.h>
|
||||
|
@ -38,6 +43,8 @@
|
|||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sol/error.hpp>
|
||||
#include <sol/load_result.hpp>
|
||||
#include <spdlog/common.h>
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
|
@ -46,6 +53,189 @@
|
|||
|
||||
namespace se = simpleengine;
|
||||
|
||||
#define AUTO_ARG(x) decltype(x), x
|
||||
|
||||
class LuaTestScriptEvent : public se::Renderable {
|
||||
public:
|
||||
sol::state lua;
|
||||
sol::protected_function_result script_res;
|
||||
entt::registry registry;
|
||||
|
||||
static void lua_panic_handler(sol::optional<std::string> maybe_msg) {
|
||||
std::cerr << "Lua panic: ";
|
||||
if(maybe_msg) {
|
||||
std::cerr << maybe_msg->c_str();
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
static int lua_exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description) {
|
||||
std::cerr << "Lua Exception: ";
|
||||
if(maybe_exception) {
|
||||
const std::exception& ex = *maybe_exception;
|
||||
std::cerr << ex.what();
|
||||
} else {
|
||||
std::cerr.write(description.data(), description.size());
|
||||
}
|
||||
|
||||
std::cerr << std::endl;
|
||||
|
||||
return sol::stack::push(L, description);
|
||||
}
|
||||
|
||||
static std::string lua_error_handler(lua_State* lstate, std::string msg) {
|
||||
std::cerr << "Lua error: " << msg << std::endl;
|
||||
return msg;
|
||||
}
|
||||
|
||||
static sol::protected_function_result lua_protected_function_handler(lua_State* lstate, sol::protected_function_result result) {
|
||||
std::cerr << "Lua protected function error" << std::endl;
|
||||
|
||||
sol::type t = sol::type_of(lstate, result.stack_index());
|
||||
std::string err = "sol: ";
|
||||
err += to_string(result.status());
|
||||
err += " error";
|
||||
|
||||
std::exception_ptr eptr = std::current_exception();
|
||||
if (eptr) {
|
||||
err += " with a ";
|
||||
try {
|
||||
std::rethrow_exception(eptr);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
err += "std::exception -- ";
|
||||
err.append(ex.what());
|
||||
}
|
||||
catch (const std::string& message) {
|
||||
err += "thrown message -- ";
|
||||
err.append(message);
|
||||
}
|
||||
catch (const char* message) {
|
||||
err += "thrown message -- ";
|
||||
err.append(message);
|
||||
}
|
||||
catch (...) {
|
||||
err.append("thrown but unknown type, cannot serialize into error message");
|
||||
}
|
||||
}
|
||||
|
||||
if (t == sol::type::string) {
|
||||
err += ": ";
|
||||
std::string_view serr = sol::stack::unqualified_get<std::string_view>(lstate, result.stack_index());
|
||||
err.append(serr.data(), serr.size());
|
||||
}
|
||||
|
||||
std::cerr << err << std::endl;
|
||||
/* sol::state_view lua(lstate);
|
||||
std::string traceback = lua.script("debug.traceback()");
|
||||
std::cout << "Traceback: " << traceback << std::endl; */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LuaTestScriptEvent() : se::Renderable(), lua(sol::c_call<decltype(&LuaTestScriptEvent::lua_panic_handler),
|
||||
&LuaTestScriptEvent::lua_panic_handler>), registry({})/* , script_res(std::nullopt_t) */ {
|
||||
register_meta_component<se::ecs::TransformComponent>();
|
||||
|
||||
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::string, sol::lib::debug);
|
||||
lua.require("registry", sol::c_call<AUTO_ARG(&open_registry)>, false); // create registry type
|
||||
// Overwrite the Lua print function to use a logger
|
||||
lua.globals().set_function("print", [](std::string msg) {
|
||||
SE_DEBUG("Lua ScriptingEngine", "{}", msg);
|
||||
});
|
||||
|
||||
// Make registry available to lua
|
||||
lua["registry"] = std::ref(this->registry);
|
||||
|
||||
// Registry TransformComponent
|
||||
lua.new_usertype<se::ecs::TransformComponent>("TransformComponent",
|
||||
"type_id", &entt::type_hash<se::ecs::TransformComponent>::value,
|
||||
|
||||
sol::call_constructor, sol::factories(
|
||||
[](float px, float py, float pz) {
|
||||
return se::ecs::TransformComponent(glm::vec3(px, py, pz));
|
||||
},
|
||||
[](float px, float py, float pz, float rx, float ry, float rz) {
|
||||
return se::ecs::TransformComponent(glm::vec3(px, py, pz), glm::vec3(rx, ry, rz));
|
||||
},
|
||||
[](float px, float py, float pz, float rx, float ry, float rz, float sx, float sy, float sz) {
|
||||
return se::ecs::TransformComponent(glm::vec3(px, py, pz), glm::vec3(rx, ry, rz), glm::vec3(sx, sy, sz));
|
||||
}
|
||||
),
|
||||
|
||||
sol::meta_function::to_string, [](const se::ecs::TransformComponent& self) {
|
||||
return glm::to_string(self.transform_matrix);
|
||||
} //&Transform::to_string
|
||||
);
|
||||
|
||||
lua.set_exception_handler(&LuaTestScriptEvent::lua_exception_handler);
|
||||
|
||||
try {
|
||||
script_res = lua.safe_script(R"LUA(
|
||||
print('start')
|
||||
local dog = registry:create()
|
||||
local cat = registry:create()
|
||||
print('created cat and cat')
|
||||
|
||||
print('Dog is ' .. dog .. ', and registry size is ' .. registry:size())
|
||||
print('Cat is ' .. cat .. ', and cat size is ' .. registry:size())
|
||||
|
||||
assert(dog == 0 and cat == 1 and registry:size() == 2)
|
||||
|
||||
registry:emplace(dog, TransformComponent(5, 6, 3))
|
||||
|
||||
assert(registry:has(dog, TransformComponent))
|
||||
assert(registry:has(dog, TransformComponent.type_id()))
|
||||
|
||||
assert(not registry:any_of(dog, -1, -2, -3))
|
||||
|
||||
function update(delta_time)
|
||||
transform = registry:get(dog, TransformComponent)
|
||||
print('Dog position = ' .. tostring(transform))
|
||||
end
|
||||
|
||||
print('Lua script loaded!')
|
||||
)LUA", &LuaTestScriptEvent::lua_protected_function_handler);
|
||||
} catch (sol::error e) {
|
||||
std::cerr << "Ran into sol2 error: " << e.what() << std::endl;
|
||||
} catch (std::exception e) {
|
||||
std::cerr << "Ran into std::exception: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
std::cerr << "Ran into something :shrug:" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void update(const float &delta_time) {
|
||||
if (script_res.valid()) {
|
||||
sol::function lua_update = lua["update"];
|
||||
|
||||
if (lua_update.valid()) {
|
||||
lua_update(delta_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void input_update(const float &delta_time) {
|
||||
if (script_res.valid()) {
|
||||
sol::function lua_input_update = lua["input_update"];
|
||||
|
||||
if (lua_input_update.valid()) {
|
||||
lua_input_update(delta_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void render(const float& interpolate_alpha, const float& frame_time) {
|
||||
if (script_res.valid()) {
|
||||
sol::function lua_render = lua["render"];
|
||||
|
||||
if (lua_render.valid()) {
|
||||
lua_render(interpolate_alpha, frame_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FPSCounterEvent : public se::Renderable {
|
||||
public:
|
||||
double last_frame_time_input;
|
||||
|
@ -151,7 +341,8 @@ int main(int argc, char *argv[]) {
|
|||
transform_comp.translate(4.f, 0.f, 0.f); */
|
||||
|
||||
se::ecs::Entity brick_e = scene->create_entity();
|
||||
brick_e.add_component<se::ecs::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx");
|
||||
//brick_e.add_component<se::ecs::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx");
|
||||
registry->get_inner().emplace<se::ecs::ModelComponent>(brick_e.get_inner(), "examples/dev_testing/resources/bricks/bricks.fbx");
|
||||
brick_e.add_component<se::ecs::TransformComponent>(glm::vec3(6.f, 6.f, 0.f));
|
||||
brick_e.add_component<se::ecs::BoxColliderComponent>(1.f, 1.f, 1.f);
|
||||
brick_e.add_component<se::ecs::RigidBodyComponent>(1.f, se::Vectorf(6.f, 6.f, 0.1f));
|
||||
|
@ -162,13 +353,20 @@ int main(int argc, char *argv[]) {
|
|||
floor.add_component<se::ecs::BoxColliderComponent>(1.f, 1.f, 1.f);
|
||||
floor.add_component<se::ecs::RigidBodyComponent>(0.f, se::Vectorf(6.f, -6.f, 0.f));
|
||||
|
||||
|
||||
// Add TransformComponent using Lua
|
||||
//register_met
|
||||
|
||||
|
||||
auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f));
|
||||
game.add_event(light);
|
||||
|
||||
// TODO: Fix, for some reason it crashes
|
||||
auto fps_counter = std::make_shared<FPSCounterEvent>();
|
||||
game.add_renderable(fps_counter);
|
||||
|
||||
auto lua_script = std::make_shared<LuaTestScriptEvent>();
|
||||
game.add_renderable(lua_script);
|
||||
|
||||
/* game.set_enable_vsync(false);
|
||||
game.set_fps_limit(100); */
|
||||
int res = game.run();
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "entt/entity/fwd.hpp"
|
||||
#include <entt/entity/fwd.hpp>
|
||||
#include <cstddef>
|
||||
#include <entt/entt.hpp>
|
||||
#include <rttr/registration.h>
|
||||
#include <utility>
|
||||
|
||||
#include <rttr/registration>
|
||||
|
||||
namespace simpleengine::ecs {
|
||||
class Entity {
|
||||
RTTR_ENABLE()
|
||||
private:
|
||||
entt::registry& registry;
|
||||
entt::entity inner;
|
||||
|
@ -19,6 +23,10 @@ namespace simpleengine::ecs {
|
|||
|
||||
}
|
||||
|
||||
entt::entity& get_inner() {
|
||||
return inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an identifier refers to a valid entity.
|
||||
*
|
||||
|
@ -114,7 +122,12 @@ namespace simpleengine::ecs {
|
|||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) add_component(Args&&... args) {
|
||||
return registry.emplace<Component>(inner, std::forward<Args>(args)...);
|
||||
return registry.emplace<Component>(inner, std::forward<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
Component& add_component_copy(Component comp) {
|
||||
return registry.emplace<Component>(inner, comp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,7 +148,7 @@ namespace simpleengine::ecs {
|
|||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) add_or_replace_component(Args&&... args) {
|
||||
return registry.emplace_or_replace<Component>(inner, std::forward<Args>(args)...);
|
||||
return registry.emplace_or_replace<Component>(inner, std::forward<Args&&>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,7 +169,7 @@ namespace simpleengine::ecs {
|
|||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) replace_component(Args&&... args) {
|
||||
return registry.replace<Component>(inner, std::forward<Args>(args)...);
|
||||
return registry.replace<Component>(inner, std::forward<Args&&>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,4 +276,40 @@ namespace simpleengine::ecs {
|
|||
return registry.orphan(inner);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
RTTR_REGISTRATION {
|
||||
using simpleengine::ecs::Entity;
|
||||
rttr::registration::class_<Entity>("Entity")
|
||||
.constructor<entt::registry&, entt::entity>()
|
||||
.method("is_valid", &Entity::is_valid)
|
||||
.method("current_version", &Entity::current_version)
|
||||
|
||||
// TODO: This version_type needs to be changed to something the scripting system could access
|
||||
.method("release", static_cast<entt::registry::version_type (Entity::*)()>(&Entity::release))
|
||||
.method("release", static_cast<entt::registry::version_type (Entity::*)(entt::registry::version_type version)>(&Entity::release))
|
||||
.method("destroy", static_cast<entt::registry::version_type (Entity::*)()>(&Entity::destroy))
|
||||
.method("destroy", static_cast<entt::registry::version_type (Entity::*)(entt::registry::version_type version)>(&Entity::destroy))
|
||||
|
||||
// TODO: implement
|
||||
//.method("add_component", &Entity::add_component<simpleengine::ecs::BoxColliderComponent>)
|
||||
//.method("add_component", &Entity::add_component_copy)
|
||||
//.method("add_or_replace_component", &Entity::add_or_replace_component)
|
||||
//.method("replace_component", &Entity::replace_component)
|
||||
//.method("patch", &Entity::patch)
|
||||
//.method("remove_components", &Entity::remove_components)
|
||||
//.method("erase", &Entity::erase)
|
||||
//.method("has_all_of", &Entity::has_all_of)
|
||||
//.method("has_any_of", &Entity::has_any_of)
|
||||
|
||||
.method("has_any_components", &Entity::has_any_components)
|
||||
|
||||
;
|
||||
|
||||
/* rttr::registration::class_<Sprite>("Sprite")
|
||||
.constructor()
|
||||
.method("Move", &Sprite::move)
|
||||
.method("Draw", &Sprite::draw)
|
||||
.property("x", &Sprite::x)
|
||||
.property("y", &Sprite::y); */
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "entt/signal/fwd.hpp"
|
||||
#include <entt/signal/fwd.hpp>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
#include <rttr/rttr_enable.h>
|
||||
|
||||
namespace simpleengine::ecs {
|
||||
class Entity;
|
||||
|
||||
class Registry {
|
||||
RTTR_ENABLE()
|
||||
|
||||
entt::registry inner;
|
||||
//entt::dispatcher dispatcher;
|
||||
public:
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include <rttr/rttr_enable.h>
|
||||
|
||||
namespace simpleengine {
|
||||
// fwd decl
|
||||
class Camera;
|
||||
|
@ -15,6 +17,7 @@ namespace simpleengine {
|
|||
|
||||
namespace system {
|
||||
class SceneSystem : public System {
|
||||
RTTR_ENABLE()
|
||||
protected:
|
||||
std::shared_ptr<gfx::Renderer> renderer;
|
||||
std::shared_ptr<Camera> camera;
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
|
||||
#include "../../renderable.h"
|
||||
|
||||
#include <rttr/rttr_enable.h>
|
||||
|
||||
namespace simpleengine::ecs {
|
||||
class Entity;
|
||||
class Registry;
|
||||
|
||||
namespace system {
|
||||
class System : public simpleengine::Renderable {
|
||||
RTTR_ENABLE()
|
||||
protected:
|
||||
std::shared_ptr<Registry> entity_registry;
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
#pragma once
|
||||
|
||||
#include "entt_meta_helper.h"
|
||||
|
||||
#include <entt/entity/fwd.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/runtime_view.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
template <typename Component> auto is_valid(const entt::registry *registry, entt::entity entity) {
|
||||
assert(registry);
|
||||
return registry->valid(entity);
|
||||
}
|
||||
template <typename Component>
|
||||
auto emplace_component(entt::registry *registry, entt::entity entity, const sol::table& instance, sol::this_state s) {
|
||||
assert(registry);
|
||||
auto& comp =
|
||||
registry->emplace_or_replace<Component>(entity, instance.valid() ? instance.as<Component>() : Component{});
|
||||
return sol::make_reference(s, std::ref(comp));
|
||||
}
|
||||
template <typename Component> auto get_component(entt::registry *registry, entt::entity entity, sol::this_state s) {
|
||||
assert(registry);
|
||||
auto& comp = registry->get_or_emplace<Component>(entity);
|
||||
return sol::make_reference(s, std::ref(comp));
|
||||
}
|
||||
template <typename Component> bool has_component(entt::registry *registry, entt::entity entity) {
|
||||
assert(registry);
|
||||
return registry->any_of<Component>(entity);
|
||||
}
|
||||
template <typename Component> auto remove_component(entt::registry *registry, entt::entity entity) {
|
||||
assert(registry);
|
||||
return registry->remove<Component>(entity);
|
||||
}
|
||||
template <typename Component> void clear_component(entt::registry *registry) {
|
||||
assert(registry);
|
||||
registry->clear<Component>();
|
||||
}
|
||||
|
||||
template <typename Component> void register_meta_component() {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<Component>()
|
||||
.type()
|
||||
.template func<&is_valid<Component>>("valid"_hs)
|
||||
.template func<&emplace_component<Component>>("emplace"_hs)
|
||||
.template func<&get_component<Component>>("get"_hs)
|
||||
.template func<&has_component<Component>>("has"_hs)
|
||||
.template func<&clear_component<Component>>("clear"_hs)
|
||||
.template func<&remove_component<Component>>("remove"_hs);
|
||||
}
|
||||
|
||||
auto collect_types(const sol::variadic_args& va) {
|
||||
std::set<entt::id_type> types;
|
||||
std::transform(va.cbegin(), va.cend(), std::inserter(types, types.begin()),
|
||||
[](const auto& obj) { return deduce_type(obj); });
|
||||
return types;
|
||||
}
|
||||
|
||||
sol::table open_registry(sol::this_state s) {
|
||||
// To create a registry inside a script: entt.registry.new()
|
||||
|
||||
sol::state_view lua{s};
|
||||
auto entt_module = lua["entt"].get_or_create<sol::table>();
|
||||
|
||||
entt_module.new_usertype<entt::runtime_view>("runtime_view", sol::no_constructor,
|
||||
"size_hint", &entt::runtime_view::size_hint, "contains",
|
||||
&entt::runtime_view::contains, "each",
|
||||
[](const entt::runtime_view& self, const sol::function& callback) {
|
||||
if (!callback.valid()) {
|
||||
return;
|
||||
}
|
||||
for (auto entity : self) {
|
||||
callback(entity);
|
||||
}
|
||||
});
|
||||
|
||||
using namespace entt::literals;
|
||||
|
||||
entt_module.new_usertype<entt::registry>(
|
||||
"registry", sol::meta_function::construct, sol::factories([] { return entt::registry{}; }),
|
||||
|
||||
"size", &entt::registry::size,
|
||||
|
||||
"alive", &entt::registry::alive,
|
||||
|
||||
"valid", &entt::registry::valid, "current", &entt::registry::current,
|
||||
|
||||
"create", [](entt::registry& self) { return self.create(); },
|
||||
"destroy", [](entt::registry& self, entt::entity entity) { return self.destroy(entity); },
|
||||
|
||||
"emplace",
|
||||
[](entt::registry& self, entt::entity entity, const sol::table& comp, sol::this_state s) -> sol::object {
|
||||
if (!comp.valid())
|
||||
return sol::lua_nil_t{};
|
||||
|
||||
const auto maybe_any = invoke_meta_func(get_type_id(comp), "emplace"_hs, &self, entity, comp, s);
|
||||
return maybe_any ? maybe_any.cast<sol::reference>() : sol::lua_nil_t{};
|
||||
},
|
||||
|
||||
"remove",
|
||||
[](entt::registry& self, entt::entity entity, const sol::object& type_or_id) {
|
||||
const auto maybe_any = invoke_meta_func(deduce_type(type_or_id), "remove"_hs, &self, entity);
|
||||
return maybe_any ? maybe_any.cast<size_t>() : 0;
|
||||
},
|
||||
|
||||
"has",
|
||||
[](entt::registry& self, entt::entity entity, const sol::object& type_or_id) {
|
||||
const auto maybe_any = invoke_meta_func(deduce_type(type_or_id), "has"_hs, &self, entity);
|
||||
return maybe_any ? maybe_any.cast<bool>() : false;
|
||||
},
|
||||
|
||||
"any_of",
|
||||
[](const sol::table& self, entt::entity entity, const sol::variadic_args& va) {
|
||||
const auto types = collect_types(va);
|
||||
const auto has = self["has"].get<sol::function>();
|
||||
return std::any_of(types.cbegin(), types.cend(),
|
||||
[&](auto type_id) { return has(self, entity, type_id).template get<bool>(); });
|
||||
},
|
||||
|
||||
"get",
|
||||
[](entt::registry& self, entt::entity entity, const sol::object& type_or_id, sol::this_state s) {
|
||||
const auto maybe_any = invoke_meta_func(deduce_type(type_or_id), "get"_hs, &self, entity, s);
|
||||
return maybe_any ? maybe_any.cast<sol::reference>() : sol::lua_nil_t{};
|
||||
},
|
||||
|
||||
"clear",
|
||||
sol::overload(&entt::registry::clear<>, [](entt::registry& self, sol::object type_or_id) {
|
||||
invoke_meta_func(deduce_type(type_or_id), "clear"_hs, &self);
|
||||
}),
|
||||
|
||||
"orphan", &entt::registry::orphan,
|
||||
|
||||
"runtime_view",
|
||||
[](entt::registry& self, const sol::variadic_args& va) {
|
||||
const std::set<uint32_t> types = collect_types(va);
|
||||
|
||||
entt::runtime_view view{};
|
||||
for (const auto& type : types) {
|
||||
entt::sparse_set& storage = self.storage(type)->second;
|
||||
view.iterate(storage);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
);
|
||||
|
||||
return entt_module;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
[[nodiscard]] entt::id_type get_type_id(const sol::table &obj) {
|
||||
const auto f = obj["type_id"].get<sol::function>();
|
||||
assert(f.valid() && "type_id not exposed to lua!");
|
||||
return f.valid() ? f().get<entt::id_type>() : -1;
|
||||
}
|
||||
|
||||
template <typename T> [[nodiscard]] entt::id_type deduce_type(T &&obj) {
|
||||
switch (obj.get_type()) {
|
||||
// in lua: registry:has(e, Transform.type_id())
|
||||
case sol::type::number:
|
||||
return obj.template as<entt::id_type>();
|
||||
// in lua: registry:has(e, Transform)
|
||||
case sol::type::table:
|
||||
return get_type_id(obj);
|
||||
default:
|
||||
// TODO: Dont assert here. Maybe an exception could be thrown and caught by the ScriptingSystem?
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// @see
|
||||
// https://github.com/skypjack/entt/wiki/Crash-Course:-runtime-reflection-system
|
||||
|
||||
template <typename... Args>
|
||||
inline auto invoke_meta_func(entt::meta_type meta_type, entt::id_type function_id, Args &&...args) {
|
||||
if (!meta_type) {
|
||||
// TODO: Warning message
|
||||
} else {
|
||||
if (auto meta_function = meta_type.func(function_id); meta_function)
|
||||
return meta_function.invoke({}, std::forward<Args>(args)...);
|
||||
}
|
||||
return entt::meta_any{};
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline auto invoke_meta_func(entt::id_type type_id, entt::id_type function_id, Args &&...args) {
|
||||
return invoke_meta_func(entt::resolve(type_id), function_id, std::forward<Args>(args)...);
|
||||
}
|
|
@ -14,5 +14,8 @@ pkgs.mkShell {
|
|||
assimp
|
||||
spdlog
|
||||
bullet
|
||||
rttr
|
||||
lua5_4
|
||||
(callPackage ./sol2.nix { })
|
||||
];
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, fetchFromGitHub
|
||||
, cmake
|
||||
, clang
|
||||
, llvm
|
||||
, pkgs
|
||||
}:
|
||||
|
||||
let
|
||||
stdenv = pkgs.clangStdenv;
|
||||
in stdenv.mkDerivation rec {
|
||||
version = "v3.3.0";
|
||||
pname = "sol2";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "ThePhD";
|
||||
repo = pname;
|
||||
rev = version;
|
||||
sha256 = "sha256-NACIWXy1GHuYNf7e3Go+S4PSQqitzgErOvqkmXQVuLw=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ cmake clang pkgs.lua5_4 ];
|
||||
|
||||
depsBuildBuild = [ pkgs.lua5_4 ];
|
||||
|
||||
# stdenv = pkgs.clangStdenv;
|
||||
cmakeFlags = [ "-DSOL2_BUILD_LUA=FALSE" "-DSOL2_LUA_VERSION='5.4.4'" ];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
cmake --build . --target install --config Release
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "sol2 is a C++ library binding to Lua.";
|
||||
homepage = "https://github.com/ThePhD/sol2";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.unix;
|
||||
maintainers = with maintainers; [ seanomik ];
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue