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:
|
# Add some CMake options:
|
||||||
option(SIMPLE_ENGINE_BUILD_EXAMPLES "Build example projects" ON)
|
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
|
# By default use OpenGL GLVND
|
||||||
option(SIMPLE_ENGINE_USE_GL_LEGACY "Use OpenGL legacy, or use BLVND" OFF)
|
option(SIMPLE_ENGINE_USE_GL_LEGACY "Use OpenGL legacy, or use BLVND" OFF)
|
||||||
|
@ -17,6 +18,16 @@ else()
|
||||||
set(OpenGL_GL_PREFERENCE "GLVND")
|
set(OpenGL_GL_PREFERENCE "GLVND")
|
||||||
endif()
|
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(GLEW REQUIRED)
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
@ -25,6 +36,7 @@ find_package(fmt CONFIG REQUIRED)
|
||||||
find_package(spdlog CONFIG REQUIRED)
|
find_package(spdlog CONFIG REQUIRED)
|
||||||
find_package(assimp CONFIG REQUIRED)
|
find_package(assimp CONFIG REQUIRED)
|
||||||
find_package(Bullet REQUIRED)
|
find_package(Bullet REQUIRED)
|
||||||
|
find_package(RTTR CONFIG REQUIRED Core)
|
||||||
|
|
||||||
# Link sources
|
# Link sources
|
||||||
file(GLOB_RECURSE source_list src/*.cpp)
|
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 ${GLM_LIBRARIES})
|
||||||
target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
|
target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
|
||||||
target_link_libraries(simpleengine PUBLIC ${BULLET_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)
|
if(WIN32)
|
||||||
target_link_libraries(simpleengine PUBLIC assimp::assimp)
|
target_link_libraries(simpleengine PUBLIC assimp::assimp)
|
||||||
target_link_libraries(simpleengine PUBLIC fmt::fmt)
|
target_link_libraries(simpleengine PUBLIC fmt::fmt)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
cmake_minimum_required (VERSION 3.6)
|
cmake_minimum_required (VERSION 3.6)
|
||||||
project(DevTesting DESCRIPTION "A testing project for engine developers.")
|
project(DevTesting DESCRIPTION "A testing project for engine developers.")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "-Og")
|
||||||
|
|
||||||
add_executable(dev_testing src/main.cpp)
|
add_executable(dev_testing src/main.cpp)
|
||||||
|
|
||||||
# Link headers and source files.
|
# Link headers and source files.
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "simpleengine/gfx/renderer.h"
|
#include "simpleengine/gfx/renderer.h"
|
||||||
#include "simpleengine/gfx/texture.h"
|
#include "simpleengine/gfx/texture.h"
|
||||||
#include "simpleengine/vector.h"
|
#include "simpleengine/vector.h"
|
||||||
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
#include <optional>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <simpleengine/ecs/component/model_component.h>
|
#include <simpleengine/ecs/component/model_component.h>
|
||||||
#include <simpleengine/ecs/component/rotating_component.h>
|
#include <simpleengine/ecs/component/rotating_component.h>
|
||||||
|
@ -27,6 +29,9 @@
|
||||||
#include <simpleengine/log/logger.h>
|
#include <simpleengine/log/logger.h>
|
||||||
#include <simpleengine/physics/physics_system.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 "entt/entity/fwd.hpp"
|
||||||
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
@ -38,6 +43,8 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sol/error.hpp>
|
||||||
|
#include <sol/load_result.hpp>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -46,6 +53,189 @@
|
||||||
|
|
||||||
namespace se = simpleengine;
|
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 {
|
class FPSCounterEvent : public se::Renderable {
|
||||||
public:
|
public:
|
||||||
double last_frame_time_input;
|
double last_frame_time_input;
|
||||||
|
@ -151,7 +341,8 @@ int main(int argc, char *argv[]) {
|
||||||
transform_comp.translate(4.f, 0.f, 0.f); */
|
transform_comp.translate(4.f, 0.f, 0.f); */
|
||||||
|
|
||||||
se::ecs::Entity brick_e = scene->create_entity();
|
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::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::BoxColliderComponent>(1.f, 1.f, 1.f);
|
||||||
brick_e.add_component<se::ecs::RigidBodyComponent>(1.f, se::Vectorf(6.f, 6.f, 0.1f));
|
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::BoxColliderComponent>(1.f, 1.f, 1.f);
|
||||||
floor.add_component<se::ecs::RigidBodyComponent>(0.f, se::Vectorf(6.f, -6.f, 0.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));
|
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);
|
game.add_event(light);
|
||||||
|
|
||||||
// TODO: Fix, for some reason it crashes
|
|
||||||
auto fps_counter = std::make_shared<FPSCounterEvent>();
|
auto fps_counter = std::make_shared<FPSCounterEvent>();
|
||||||
game.add_renderable(fps_counter);
|
game.add_renderable(fps_counter);
|
||||||
|
|
||||||
|
auto lua_script = std::make_shared<LuaTestScriptEvent>();
|
||||||
|
game.add_renderable(lua_script);
|
||||||
|
|
||||||
/* game.set_enable_vsync(false);
|
/* game.set_enable_vsync(false);
|
||||||
game.set_fps_limit(100); */
|
game.set_fps_limit(100); */
|
||||||
int res = game.run();
|
int res = game.run();
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "entt/entity/fwd.hpp"
|
#include <entt/entity/fwd.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
#include <rttr/registration.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <rttr/registration>
|
||||||
|
|
||||||
namespace simpleengine::ecs {
|
namespace simpleengine::ecs {
|
||||||
class Entity {
|
class Entity {
|
||||||
|
RTTR_ENABLE()
|
||||||
private:
|
private:
|
||||||
entt::registry& registry;
|
entt::registry& registry;
|
||||||
entt::entity inner;
|
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.
|
* @brief Checks if an identifier refers to a valid entity.
|
||||||
*
|
*
|
||||||
|
@ -114,7 +122,12 @@ namespace simpleengine::ecs {
|
||||||
*/
|
*/
|
||||||
template<typename Component, typename... Args>
|
template<typename Component, typename... Args>
|
||||||
decltype(auto) add_component(Args&&... 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>
|
template<typename Component, typename... Args>
|
||||||
decltype(auto) add_or_replace_component(Args&&... 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>
|
template<typename Component, typename... Args>
|
||||||
decltype(auto) replace_component(Args&&... 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)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,3 +277,39 @@ namespace simpleengine::ecs {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "entt/signal/fwd.hpp"
|
#include <entt/signal/fwd.hpp>
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
|
||||||
|
#include <rttr/rttr_enable.h>
|
||||||
|
|
||||||
namespace simpleengine::ecs {
|
namespace simpleengine::ecs {
|
||||||
class Entity;
|
class Entity;
|
||||||
|
|
||||||
class Registry {
|
class Registry {
|
||||||
|
RTTR_ENABLE()
|
||||||
|
|
||||||
entt::registry inner;
|
entt::registry inner;
|
||||||
//entt::dispatcher dispatcher;
|
//entt::dispatcher dispatcher;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
|
#include <rttr/rttr_enable.h>
|
||||||
|
|
||||||
namespace simpleengine {
|
namespace simpleengine {
|
||||||
// fwd decl
|
// fwd decl
|
||||||
class Camera;
|
class Camera;
|
||||||
|
@ -15,6 +17,7 @@ namespace simpleengine {
|
||||||
|
|
||||||
namespace system {
|
namespace system {
|
||||||
class SceneSystem : public System {
|
class SceneSystem : public System {
|
||||||
|
RTTR_ENABLE()
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<gfx::Renderer> renderer;
|
std::shared_ptr<gfx::Renderer> renderer;
|
||||||
std::shared_ptr<Camera> camera;
|
std::shared_ptr<Camera> camera;
|
||||||
|
|
|
@ -2,12 +2,15 @@
|
||||||
|
|
||||||
#include "../../renderable.h"
|
#include "../../renderable.h"
|
||||||
|
|
||||||
|
#include <rttr/rttr_enable.h>
|
||||||
|
|
||||||
namespace simpleengine::ecs {
|
namespace simpleengine::ecs {
|
||||||
class Entity;
|
class Entity;
|
||||||
class Registry;
|
class Registry;
|
||||||
|
|
||||||
namespace system {
|
namespace system {
|
||||||
class System : public simpleengine::Renderable {
|
class System : public simpleengine::Renderable {
|
||||||
|
RTTR_ENABLE()
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<Registry> entity_registry;
|
std::shared_ptr<Registry> entity_registry;
|
||||||
public:
|
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
|
assimp
|
||||||
spdlog
|
spdlog
|
||||||
bullet
|
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