Move all Lua code to separate classes, expose most TransformComponent's methods
This commit is contained in:
parent
51206d60d4
commit
db0cdf32a1
|
@ -11,6 +11,7 @@
|
||||||
#include "simpleengine/gfx/model.h"
|
#include "simpleengine/gfx/model.h"
|
||||||
#include "simpleengine/gfx/renderer.h"
|
#include "simpleengine/gfx/renderer.h"
|
||||||
#include "simpleengine/gfx/texture.h"
|
#include "simpleengine/gfx/texture.h"
|
||||||
|
#include "simpleengine/scripting/scripting_system.h"
|
||||||
#include "simpleengine/vector.h"
|
#include "simpleengine/vector.h"
|
||||||
#include <glm/gtx/string_cast.hpp>
|
#include <glm/gtx/string_cast.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -29,9 +30,6 @@
|
||||||
#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>
|
||||||
|
@ -47,215 +45,25 @@
|
||||||
#include <sol/load_result.hpp>
|
#include <sol/load_result.hpp>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btStaticPlaneShape.h>
|
#include <BulletCollision/CollisionShapes/btStaticPlaneShape.h>
|
||||||
|
|
||||||
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;
|
||||||
int frame_count_input;
|
int frame_count_input = 0;
|
||||||
|
|
||||||
double last_frame_time_tps;
|
double last_frame_time_tps;
|
||||||
int frame_count_tps;
|
int frame_count_tps = 0;
|
||||||
|
|
||||||
double last_frame_time_render;
|
double last_frame_time_render;
|
||||||
int frame_count_render;
|
int frame_count_render = 0;
|
||||||
|
|
||||||
FPSCounterEvent() : se::Renderable() {
|
FPSCounterEvent() : se::Renderable(), last_frame_time_input(glfwGetTime()),
|
||||||
last_frame_time_input = glfwGetTime();
|
last_frame_time_tps(glfwGetTime()), last_frame_time_render(glfwGetTime()) {
|
||||||
frame_count_input = 0;
|
|
||||||
|
|
||||||
last_frame_time_tps = glfwGetTime();
|
|
||||||
frame_count_tps = 0;
|
|
||||||
|
|
||||||
last_frame_time_render = glfwGetTime();
|
|
||||||
frame_count_render = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update(const float &delta_time) {
|
virtual void update(const float &delta_time) {
|
||||||
|
@ -364,8 +172,9 @@ int main(int argc, char *argv[]) {
|
||||||
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>();
|
auto script_sys = std::make_shared<simpleengine::scripting::ScriptingSystem>(registry);
|
||||||
game.add_renderable(lua_script);
|
script_sys->add_lua_engine();
|
||||||
|
game.add_renderable(script_sys);
|
||||||
|
|
||||||
/* game.set_enable_vsync(false);
|
/* game.set_enable_vsync(false);
|
||||||
game.set_fps_limit(100); */
|
game.set_fps_limit(100); */
|
||||||
|
|
|
@ -125,10 +125,16 @@ namespace simpleengine::ecs {
|
||||||
return rotation_matrix(degrees, glm::vec3(0, 0, 1));
|
return rotation_matrix(degrees, glm::vec3(0, 0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void rotate(float degrees, glm::vec3 rotation_axis) {
|
virtual void rotate_axis(float degrees, glm::vec3 rotation_axis) {
|
||||||
transform_matrix = rotation_matrix(degrees, rotation_axis);
|
transform_matrix = rotation_matrix(degrees, rotation_axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void rotate(float x_degrees, float y_degrees, float z_degrees) {
|
||||||
|
transform_matrix = rotation_x_matrix(x_degrees);
|
||||||
|
transform_matrix = rotation_y_matrix(y_degrees);
|
||||||
|
transform_matrix = rotation_z_matrix(z_degrees);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void rotate_x(float degrees) {
|
virtual void rotate_x(float degrees) {
|
||||||
transform_matrix = rotation_x_matrix(degrees);
|
transform_matrix = rotation_x_matrix(degrees);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -5,42 +5,48 @@
|
||||||
|
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
[[nodiscard]] entt::id_type get_type_id(const sol::table &obj) {
|
namespace simpleengine::scripting {
|
||||||
const auto f = obj["type_id"].get<sol::function>();
|
class EnttMetaHelper {
|
||||||
assert(f.valid() && "type_id not exposed to lua!");
|
public:
|
||||||
return f.valid() ? f().get<entt::id_type>() : -1;
|
|
||||||
}
|
[[nodiscard]] static 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) {
|
template <typename T> [[nodiscard]] static entt::id_type deduce_type(T &&obj) {
|
||||||
switch (obj.get_type()) {
|
switch (obj.get_type()) {
|
||||||
// in lua: registry:has(e, Transform.type_id())
|
// in lua: registry:has(e, Transform.type_id())
|
||||||
case sol::type::number:
|
case sol::type::number:
|
||||||
return obj.template as<entt::id_type>();
|
return obj.template as<entt::id_type>();
|
||||||
// in lua: registry:has(e, Transform)
|
// in lua: registry:has(e, Transform)
|
||||||
case sol::type::table:
|
case sol::type::table:
|
||||||
return get_type_id(obj);
|
return get_type_id(obj);
|
||||||
default:
|
default:
|
||||||
// TODO: Dont assert here. Maybe an exception could be thrown and caught by the ScriptingSystem?
|
// TODO: Dont assert here. Maybe an exception could be thrown and caught by the ScriptingSystem?
|
||||||
assert(false);
|
assert(false);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @see
|
// @see
|
||||||
// https://github.com/skypjack/entt/wiki/Crash-Course:-runtime-reflection-system
|
// https://github.com/skypjack/entt/wiki/Crash-Course:-runtime-reflection-system
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline auto invoke_meta_func(entt::meta_type meta_type, entt::id_type function_id, Args &&...args) {
|
inline static auto invoke_meta_func(entt::meta_type meta_type, entt::id_type function_id, Args &&...args) {
|
||||||
if (!meta_type) {
|
if (!meta_type) {
|
||||||
// TODO: Warning message
|
// TODO: Warning message
|
||||||
} else {
|
} else {
|
||||||
if (auto meta_function = meta_type.func(function_id); meta_function)
|
if (auto meta_function = meta_type.func(function_id); meta_function)
|
||||||
return meta_function.invoke({}, std::forward<Args>(args)...);
|
return meta_function.invoke({}, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
return entt::meta_any{};
|
return entt::meta_any{};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline auto invoke_meta_func(entt::id_type type_id, entt::id_type function_id, Args &&...args) {
|
inline static 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)...);
|
return invoke_meta_func(entt::resolve(type_id), function_id, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
#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>
|
||||||
|
#include <sol/state_view.hpp>
|
||||||
|
#include <sol/types.hpp>
|
||||||
|
|
||||||
|
namespace simpleengine::scripting::lua {
|
||||||
|
class ECSBindings {
|
||||||
|
private:
|
||||||
|
template <typename Component> static auto is_valid(const entt::registry *registry, entt::entity entity) {
|
||||||
|
assert(registry);
|
||||||
|
return registry->valid(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
static 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> static 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> static bool has_component(entt::registry *registry, entt::entity entity) {
|
||||||
|
assert(registry);
|
||||||
|
return registry->any_of<Component>(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component> static auto remove_component(entt::registry *registry, entt::entity entity) {
|
||||||
|
assert(registry);
|
||||||
|
return registry->remove<Component>(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component> static void clear_component(entt::registry *registry) {
|
||||||
|
assert(registry);
|
||||||
|
registry->clear<Component>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component> static 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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 EnttMetaHelper::deduce_type(obj); });
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// This binds ALL of the ECS to Lua under the `ecs` table
|
||||||
|
static sol::table bind_full_ecs(sol::this_state s);
|
||||||
|
|
||||||
|
/// This binds an entt registry to lua. It binds the registry type as `ecs.registry`
|
||||||
|
static sol::table bind_registry(sol::this_state s);
|
||||||
|
/// Bind all components to Lua. This will put all components under `ecs.component.*`
|
||||||
|
static sol::table bind_components(sol::this_state s);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../scripting_engine.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
namespace simpleengine::ecs {
|
||||||
|
class Registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace simpleengine::scripting::lua {
|
||||||
|
class LuaScriptingEngine : public ScriptingEngine {
|
||||||
|
private:
|
||||||
|
sol::state lua;
|
||||||
|
std::vector<sol::protected_function_result> script_results;
|
||||||
|
public:
|
||||||
|
LuaScriptingEngine(std::shared_ptr<ecs::Registry> entity_registry);
|
||||||
|
|
||||||
|
static void lua_panic_handler(sol::optional<std::string> maybe_msg);
|
||||||
|
static int lua_exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description);
|
||||||
|
static sol::protected_function_result lua_protected_function_handler(lua_State* lstate, sol::protected_function_result result);
|
||||||
|
|
||||||
|
virtual void setup_language() override;
|
||||||
|
virtual void expose_simpleengine() override;
|
||||||
|
|
||||||
|
// TODO: Add some way for the user to get a reference to a script so they can stop it from running
|
||||||
|
virtual void run_script(std::string lua_code) override;
|
||||||
|
virtual void run_script_file(std::string path) override;
|
||||||
|
|
||||||
|
virtual void update(const float& delta_time) override;
|
||||||
|
virtual void input_update(const float& delta_time) override;
|
||||||
|
virtual void render(const float& interpolate_alpha, const float& frame_time) override;
|
||||||
|
virtual void destroy() override;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace simpleengine::ecs {
|
||||||
|
class Registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace simpleengine::scripting {
|
||||||
|
class ScriptingEngine {
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<ecs::Registry> entity_registry;
|
||||||
|
public:
|
||||||
|
ScriptingEngine(std::shared_ptr<ecs::Registry> entity_registry) : entity_registry(entity_registry) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Setup the scripting language VM
|
||||||
|
virtual void setup_language() = 0;
|
||||||
|
|
||||||
|
/// Expose simpleengine to the scripting language
|
||||||
|
virtual void expose_simpleengine() = 0;
|
||||||
|
|
||||||
|
virtual void run_script(std::string lua_code) = 0;
|
||||||
|
virtual void run_script_file(std::string path) = 0;
|
||||||
|
|
||||||
|
virtual void update(const float& delta_time) = 0;
|
||||||
|
virtual void input_update(const float& delta_time) = 0;
|
||||||
|
virtual void render(const float& interpolate_alpha, const float& frame_time) = 0;
|
||||||
|
virtual void destroy() = 0;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../ecs/system/system.h"
|
||||||
|
#include "scripting_engine.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace simpleengine::scripting {
|
||||||
|
class ScriptingSystem : public simpleengine::ecs::system::System {
|
||||||
|
private:
|
||||||
|
std::unordered_map<const char*, std::unique_ptr<simpleengine::scripting::ScriptingEngine>> scripting_engines;
|
||||||
|
public:
|
||||||
|
ScriptingSystem(std::shared_ptr<simpleengine::ecs::Registry> entity_registry);
|
||||||
|
|
||||||
|
void add_lua_engine();
|
||||||
|
|
||||||
|
virtual void update(const float& delta_time) override;
|
||||||
|
virtual void input_update(const float& delta_time) override;
|
||||||
|
virtual void render(const float& interpolate_alpha, const float& frame_time) override;
|
||||||
|
virtual void destroy() override;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
#include "scripting/lua/ecs_bindings.h"
|
||||||
|
|
||||||
|
#include "ecs/component/transform_component.h"
|
||||||
|
#include "scripting/entt_meta_helper.h"
|
||||||
|
|
||||||
|
#include <glm/detail/type_quat.hpp>
|
||||||
|
#include <glm/fwd.hpp>
|
||||||
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
#include <sol/overload.hpp>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace simpleengine::scripting::lua {
|
||||||
|
sol::table ECSBindings::bind_full_ecs(sol::this_state s) {
|
||||||
|
sol::table ecs_table = bind_registry(s);
|
||||||
|
bind_components(s);
|
||||||
|
|
||||||
|
return ecs_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::table ECSBindings::bind_registry(sol::this_state s) {
|
||||||
|
sol::state_view lua{s};
|
||||||
|
auto ecs_module = lua["ecs"].get_or_create<sol::table>();
|
||||||
|
|
||||||
|
ecs_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;
|
||||||
|
|
||||||
|
ecs_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 = EnttMetaHelper::invoke_meta_func(EnttMetaHelper::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 = EnttMetaHelper::invoke_meta_func(EnttMetaHelper::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 = EnttMetaHelper::invoke_meta_func(EnttMetaHelper::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 = EnttMetaHelper::invoke_meta_func(EnttMetaHelper::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) {
|
||||||
|
EnttMetaHelper::invoke_meta_func(EnttMetaHelper::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 ecs_module;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::table ECSBindings::bind_components(sol::this_state s) {
|
||||||
|
sol::state_view lua{s};
|
||||||
|
auto ecs_module = lua["ecs"].get_or_create<sol::table>();
|
||||||
|
auto comp_module = ecs_module["component"].get_or_create<sol::table>();
|
||||||
|
|
||||||
|
// TransformComponent
|
||||||
|
register_meta_component<ecs::TransformComponent>();
|
||||||
|
comp_module.new_usertype<simpleengine::ecs::TransformComponent>("TransformComponent",
|
||||||
|
"type_id", &entt::type_hash<simpleengine::ecs::TransformComponent>::value,
|
||||||
|
|
||||||
|
sol::call_constructor, sol::factories(
|
||||||
|
[](float px, float py, float pz) {
|
||||||
|
return simpleengine::ecs::TransformComponent(glm::vec3(px, py, pz));
|
||||||
|
},
|
||||||
|
[](float px, float py, float pz, float rx, float ry, float rz) {
|
||||||
|
return simpleengine::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 simpleengine::ecs::TransformComponent(glm::vec3(px, py, pz), glm::vec3(rx, ry, rz), glm::vec3(sx, sy, sz));
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
"decompose_matrix", [](const ecs::TransformComponent& self) {
|
||||||
|
glm::vec3 pos, scale;
|
||||||
|
glm::quat rot;
|
||||||
|
|
||||||
|
self.decompose_matrix(pos, rot, scale);
|
||||||
|
|
||||||
|
return std::tuple(pos, rot, scale);
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: Implement glm::vec3
|
||||||
|
/* "get_pos", &ecs::TransformComponent::get_pos,
|
||||||
|
"get_scale", &ecs::TransformComponent::get_scale,
|
||||||
|
"get_rotation_quat", &ecs::TransformComponent::get_rotation_quat, */
|
||||||
|
// combine_transform(const glm::mat4& transform_matrix)
|
||||||
|
// combine_transform(const TransformComponent& transformable)
|
||||||
|
|
||||||
|
"translate", sol::overload([](ecs::TransformComponent& self, float x, float y, float z) {
|
||||||
|
self.translate(x, y, z);
|
||||||
|
}), // TODO: Implement glm::vec3 translate
|
||||||
|
|
||||||
|
"rotate", &ecs::TransformComponent::rotate,
|
||||||
|
"rotate_x", &ecs::TransformComponent::rotate_x,
|
||||||
|
"rotate_y", &ecs::TransformComponent::rotate_y,
|
||||||
|
"rotate_z", &ecs::TransformComponent::rotate_z,
|
||||||
|
|
||||||
|
"scale", sol::overload([](ecs::TransformComponent& self, float scalar) {
|
||||||
|
self.scale(scalar);
|
||||||
|
}, [](ecs::TransformComponent& self, float x_scalar, float y_scalar, float z_scalar) {
|
||||||
|
self.scale(glm::vec3(x_scalar, y_scalar, z_scalar));
|
||||||
|
}), // TODO: Implement glm::vec3 scale
|
||||||
|
|
||||||
|
sol::meta_function::to_string, [](const ecs::TransformComponent& self) {
|
||||||
|
return glm::to_string(self.transform_matrix);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return comp_module;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
#include "scripting/lua/lua_scripting_engine.h"
|
||||||
|
#include "scripting/lua/ecs_bindings.h"
|
||||||
|
#include "scripting/entt_meta_helper.h"
|
||||||
|
#include "ecs/registry.h"
|
||||||
|
#include "log/logger.h"
|
||||||
|
|
||||||
|
#include "ecs/component/transform_component.h"
|
||||||
|
#include "scripting/lua/ecs_bindings.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
|
||||||
|
#define AUTO_ARG(x) decltype(x), x
|
||||||
|
|
||||||
|
namespace simpleengine::scripting::lua {
|
||||||
|
LuaScriptingEngine::LuaScriptingEngine(std::shared_ptr<ecs::Registry> entity_registry) : ScriptingEngine(entity_registry) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LuaScriptingEngine::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::protected_function_result LuaScriptingEngine::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());
|
||||||
|
}
|
||||||
|
|
||||||
|
SE_ERROR("Lua ScriptingEngine", "{}", err);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::setup_language() {
|
||||||
|
std::cout << "Setup" << std::endl;
|
||||||
|
|
||||||
|
lua = sol::state{sol::c_call<decltype(&LuaScriptingEngine::lua_panic_handler),
|
||||||
|
&LuaScriptingEngine::lua_panic_handler>};
|
||||||
|
lua.set_exception_handler(&LuaScriptingEngine::lua_exception_handler);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Open all libraries built into sol2. There is ffi and jit, but these are only available
|
||||||
|
// when using LuaJIT.
|
||||||
|
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::coroutine,
|
||||||
|
sol::lib::string, sol::lib::os, sol::lib::math, sol::lib::table, sol::lib::debug,
|
||||||
|
sol::lib::bit32, sol::lib::io, sol::lib::utf8);
|
||||||
|
//lua.require("registry", sol::c_call<AUTO_ARG(&simpleengine::scripting::lua::bindings::bind_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", "[Lua Output] {}", msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::expose_simpleengine() {
|
||||||
|
// Make registry available to lua
|
||||||
|
lua["registry"] = std::ref(entity_registry->get_inner());
|
||||||
|
|
||||||
|
// Registry TransformComponent
|
||||||
|
//bindings::bind_registry();
|
||||||
|
lua.require("ecs", sol::c_call<AUTO_ARG(&simpleengine::scripting::lua::ECSBindings::bind_full_ecs)>, false); // create registry type
|
||||||
|
//lua.require("registry", sol::c_call<AUTO_ARG(&simpleengine::scripting::lua::bindings::bind_registry)>, false); // create registry type
|
||||||
|
|
||||||
|
|
||||||
|
entt::entity en = entity_registry->get_inner().create();
|
||||||
|
lua["dog"] = en;
|
||||||
|
|
||||||
|
run_script(R"LUA(
|
||||||
|
print('start')
|
||||||
|
--local dog = registry:create()
|
||||||
|
local cat = registry:create()
|
||||||
|
print('created dog and cat')
|
||||||
|
|
||||||
|
print('Dog is ' .. dog .. ', and registry size is ' .. registry:size())
|
||||||
|
print('Cat is ' .. cat .. ', and cat size is ' .. registry:size())
|
||||||
|
|
||||||
|
registry:emplace(dog, ecs.component.TransformComponent(5, 6, 3))
|
||||||
|
|
||||||
|
assert(registry:has(dog, ecs.component.TransformComponent))
|
||||||
|
assert(registry:has(dog, ecs.component.TransformComponent.type_id()))
|
||||||
|
|
||||||
|
assert(not registry:any_of(dog, -1, -2, -3))
|
||||||
|
|
||||||
|
function update(delta_time)
|
||||||
|
transform = registry:get(dog, ecs.component.TransformComponent)
|
||||||
|
print('Dog position = ' .. tostring(transform))
|
||||||
|
transform:translate(0, 0, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
print('Lua script loaded!')
|
||||||
|
)LUA");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::run_script(std::string lua_code) {
|
||||||
|
script_results.emplace_back(lua.script(lua_code, &LuaScriptingEngine::lua_protected_function_handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::run_script_file(std::string path) {
|
||||||
|
script_results.emplace_back(lua.script_file(path, &LuaScriptingEngine::lua_protected_function_handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::update(const float& delta_time) {
|
||||||
|
for (const auto& res : script_results) {
|
||||||
|
if (res.valid()) {
|
||||||
|
sol::function lua_update = lua["update"];
|
||||||
|
|
||||||
|
if (lua_update.valid()) {
|
||||||
|
lua_update(delta_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::input_update(const float& delta_time) {
|
||||||
|
for (const auto& res : script_results) {
|
||||||
|
if (res.valid()) {
|
||||||
|
sol::function lua_input_update = lua["input_update"];
|
||||||
|
|
||||||
|
if (lua_input_update.valid()) {
|
||||||
|
lua_input_update(delta_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::render(const float& interpolate_alpha, const float& frame_time) {
|
||||||
|
for (const auto& res : script_results) {
|
||||||
|
if (res.valid()) {
|
||||||
|
sol::function lua_render = lua["render"];
|
||||||
|
|
||||||
|
if (lua_render.valid()) {
|
||||||
|
lua_render(interpolate_alpha, frame_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaScriptingEngine::destroy() {
|
||||||
|
std::cout << "Destroy" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "scripting/scripting_system.h"
|
||||||
|
#include "ecs/system/system.h"
|
||||||
|
|
||||||
|
#include "scripting/lua/lua_scripting_engine.h"
|
||||||
|
|
||||||
|
namespace simpleengine::scripting {
|
||||||
|
|
||||||
|
ScriptingSystem::ScriptingSystem(std::shared_ptr<simpleengine::ecs::Registry> entity_registry) : simpleengine::ecs::system::System(entity_registry) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingSystem::add_lua_engine() {
|
||||||
|
auto lua = std::make_unique<lua::LuaScriptingEngine>(entity_registry);
|
||||||
|
|
||||||
|
lua->setup_language();
|
||||||
|
lua->expose_simpleengine();
|
||||||
|
|
||||||
|
scripting_engines.emplace("lua", std::move(lua));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingSystem::update(const float& delta_time) {
|
||||||
|
for (const auto& [key, val] : scripting_engines) {
|
||||||
|
val->update(delta_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingSystem::input_update(const float& delta_time) {
|
||||||
|
for (const auto& [key, val] : scripting_engines) {
|
||||||
|
val->input_update(delta_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingSystem::render(const float& interpolate_alpha, const float& frame_time) {
|
||||||
|
for (const auto& [key, val] : scripting_engines) {
|
||||||
|
val->render(interpolate_alpha, frame_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingSystem::destroy() {
|
||||||
|
std::cout << "Scripting system destroyed!" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue