mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
add loading behaviour script asset
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#include "../core/_all.hpp"
|
||||
|
||||
#include <ecs.hpp/ecs.hpp>
|
||||
|
||||
#define SOL_ALL_SAFETIES_ON 1
|
||||
#include <3rdparty/sol/sol.hpp>
|
||||
|
||||
namespace e2d
|
||||
|
||||
@@ -9,12 +9,19 @@
|
||||
#include "../_high.hpp"
|
||||
|
||||
#include "../factory.hpp"
|
||||
#include "../assets/script_asset.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class behaviour final {
|
||||
public:
|
||||
behaviour() = default;
|
||||
behaviour(const script_asset::ptr& script);
|
||||
|
||||
behaviour& script(const script_asset::ptr& value) noexcept;
|
||||
[[nodiscard]] const script_asset::ptr& script() const noexcept;
|
||||
private:
|
||||
script_asset::ptr script_;
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -31,3 +38,18 @@ namespace e2d
|
||||
const collect_context& ctx) const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
inline behaviour::behaviour(const script_asset::ptr& value)
|
||||
: script_(value) {}
|
||||
|
||||
inline behaviour& behaviour::script(const script_asset::ptr& value) noexcept {
|
||||
script_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const script_asset::ptr& behaviour::script() const noexcept {
|
||||
return script_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,38 @@
|
||||
|
||||
#include "_high.hpp"
|
||||
|
||||
#include "script.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class luasol final : public module<luasol> {
|
||||
public:
|
||||
luasol();
|
||||
~luasol() noexcept final;
|
||||
~luasol() noexcept final = default;
|
||||
|
||||
sol::state& lua() noexcept;
|
||||
const sol::state& lua() const noexcept;
|
||||
template < typename F >
|
||||
decltype(auto) with_state(F&& f);
|
||||
template < typename F >
|
||||
decltype(auto) with_state(F&& f) const;
|
||||
|
||||
std::optional<script> load_script(buffer_view src);
|
||||
std::optional<script> load_script(const input_stream_uptr& src);
|
||||
private:
|
||||
sol::state lua_;
|
||||
sol::state state_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
template < typename F >
|
||||
decltype(auto) luasol::with_state(F&& f) {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
return std::invoke(std::forward<F>(f), state_);
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
decltype(auto) luasol::with_state(F&& f) const {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
return std::invoke(std::forward<F>(f), state_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class bad_script_access final : public exception {
|
||||
public:
|
||||
const char* what() const noexcept final {
|
||||
return "bad script access";
|
||||
}
|
||||
};
|
||||
|
||||
class script final {
|
||||
public:
|
||||
script() = default;
|
||||
@@ -21,14 +28,35 @@ namespace e2d
|
||||
script(const script& other);
|
||||
script& operator=(const script& other);
|
||||
|
||||
void clear() noexcept;
|
||||
void swap(script& other) noexcept;
|
||||
script(sol::protected_function&& func) noexcept;
|
||||
script(const sol::protected_function& func);
|
||||
|
||||
script& assign(script&& other) noexcept;
|
||||
script& assign(const script& other);
|
||||
|
||||
script& assign(sol::protected_function&& func) noexcept;
|
||||
script& assign(const sol::protected_function& func);
|
||||
|
||||
void clear() noexcept;
|
||||
void swap(script& other) noexcept;
|
||||
bool empty() const noexcept;
|
||||
|
||||
template < typename... Ret, typename... Args >
|
||||
decltype(auto) call(Args&&... args) const;
|
||||
private:
|
||||
std::optional<sol::protected_function> func_;
|
||||
};
|
||||
|
||||
void swap(script& l, script& r) noexcept;
|
||||
bool operator==(const script& l, const script& r) noexcept;
|
||||
bool operator!=(const script& l, const script& r) noexcept;
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
template < typename... Ret, typename... Args >
|
||||
decltype(auto) script::call(Args&&... args) const {
|
||||
if ( !func_ ) {
|
||||
throw bad_script_access();
|
||||
}
|
||||
return func_->call<Ret...>(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/high/assets/script_asset.hpp>
|
||||
|
||||
#include <enduro2d/high/luasol.hpp>
|
||||
#include <enduro2d/high/assets/binary_asset.hpp>
|
||||
|
||||
namespace
|
||||
@@ -25,8 +27,14 @@ namespace e2d
|
||||
{
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([](const binary_asset::load_result& script_data){
|
||||
script content;
|
||||
return script_asset::create(std::move(content));
|
||||
return the<deferrer>().do_in_main_thread([script_data](){
|
||||
std::optional<script> script_opt = the<luasol>().load_script(
|
||||
script_data->content());
|
||||
if ( !script_opt ) {
|
||||
throw script_asset_loading_exception();
|
||||
}
|
||||
return script_asset::create(std::move(*script_opt));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,29 @@ namespace e2d
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {}
|
||||
"properties" : {
|
||||
"script" : { "$ref": "#/common_definitions/address" }
|
||||
}
|
||||
})json";
|
||||
|
||||
bool factory_loader<behaviour>::operator()(
|
||||
behaviour& component,
|
||||
const fill_context& ctx) const
|
||||
{
|
||||
E2D_UNUSED(component, ctx);
|
||||
if ( ctx.root.HasMember("script") ) {
|
||||
auto script = ctx.dependencies.find_asset<script_asset>(
|
||||
path::combine(ctx.parent_address, ctx.root["script"].GetString()));
|
||||
if ( !script ) {
|
||||
the<debug>().error("BEHAVIOUR: Dependency 'script' is not found:\n"
|
||||
"--> Parent address: %0\n"
|
||||
"--> Dependency address: %1",
|
||||
ctx.parent_address,
|
||||
ctx.root["script"].GetString());
|
||||
return false;
|
||||
}
|
||||
component.script(script);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,7 +42,11 @@ namespace e2d
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const
|
||||
{
|
||||
E2D_UNUSED(dependencies, ctx);
|
||||
if ( ctx.root.HasMember("script") ) {
|
||||
dependencies.add_dependency<script_asset>(
|
||||
path::combine(ctx.parent_address, ctx.root["script"].GetString()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace e2d
|
||||
{
|
||||
luasol::luasol() {
|
||||
lua_.open_libraries(
|
||||
state_.open_libraries(
|
||||
sol::lib::base,
|
||||
sol::lib::package,
|
||||
sol::lib::coroutine,
|
||||
@@ -19,20 +19,38 @@ namespace e2d
|
||||
sol::lib::math,
|
||||
sol::lib::table,
|
||||
sol::lib::utf8);
|
||||
bindings::bind_math(lua_);
|
||||
bindings::bind_utils(lua_);
|
||||
bindings::bind_core(lua_);
|
||||
bindings::bind_high(lua_);
|
||||
bindings::bind_math(state_);
|
||||
bindings::bind_utils(state_);
|
||||
bindings::bind_core(state_);
|
||||
bindings::bind_high(state_);
|
||||
}
|
||||
|
||||
luasol::~luasol() noexcept {
|
||||
std::optional<script> luasol::load_script(buffer_view src) {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
sol::load_result result = state_.load_buffer(
|
||||
reinterpret_cast<const char*>(src.data()),
|
||||
src.size());
|
||||
|
||||
if ( !result.valid() ) {
|
||||
the<debug>().error("LUASOL: Failed to load script buffer:\n"
|
||||
"--> Info: %0",
|
||||
sol::error(result).what());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
sol::state& luasol::lua() noexcept {
|
||||
return lua_;
|
||||
return script(sol::protected_function(result));
|
||||
}
|
||||
|
||||
const sol::state& luasol::lua() const noexcept {
|
||||
return lua_;
|
||||
std::optional<script> luasol::load_script(const input_stream_uptr& src) {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
|
||||
buffer file_data;
|
||||
if ( !streams::try_read_tail(file_data, src) ) {
|
||||
the<debug>().error("LUASOL: Failed to read script stream");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return load_script(file_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,12 @@ namespace e2d
|
||||
return assign(other);
|
||||
}
|
||||
|
||||
void script::clear() noexcept {
|
||||
script::script(sol::protected_function&& func) noexcept {
|
||||
assign(std::move(func));
|
||||
}
|
||||
|
||||
void script::swap(script& other) noexcept {
|
||||
using std::swap;
|
||||
script::script(const sol::protected_function& func) {
|
||||
assign(func);
|
||||
}
|
||||
|
||||
script& script::assign(script&& other) noexcept {
|
||||
@@ -41,11 +42,33 @@ namespace e2d
|
||||
|
||||
script& script::assign(const script& other) {
|
||||
if ( this != &other ) {
|
||||
script s;
|
||||
swap(s);
|
||||
func_ = other.func_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
script& script::assign(sol::protected_function&& func) noexcept {
|
||||
func_ = std::move(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
script& script::assign(const sol::protected_function& func) {
|
||||
func_ = func;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void script::clear() noexcept {
|
||||
func_.reset();
|
||||
}
|
||||
|
||||
void script::swap(script& other) noexcept {
|
||||
using std::swap;
|
||||
swap(func_, other.func_);
|
||||
}
|
||||
|
||||
bool script::empty() const noexcept {
|
||||
return !func_;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
@@ -53,12 +76,4 @@ namespace e2d
|
||||
void swap(script& l, script& r) noexcept {
|
||||
l.swap(r);
|
||||
}
|
||||
|
||||
bool operator==(const script& l, const script& r) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const script& l, const script& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ namespace e2d
|
||||
|
||||
starter::starter(int argc, char *argv[], const parameters& params) {
|
||||
safe_module_initialize<engine>(argc, argv, params.engine_params());
|
||||
safe_module_initialize<luasol>();
|
||||
safe_module_initialize<factory>()
|
||||
.register_component<actor>("actor")
|
||||
.register_component<behaviour>("behaviour")
|
||||
@@ -150,15 +151,14 @@ namespace e2d
|
||||
.register_component<spine_player_evt>("spine_player_evt")
|
||||
.register_component<sprite_renderer>("sprite_renderer");
|
||||
safe_module_initialize<library>(params.library_root(), the<deferrer>());
|
||||
safe_module_initialize<luasol>();
|
||||
safe_module_initialize<world>();
|
||||
}
|
||||
|
||||
starter::~starter() noexcept {
|
||||
modules::shutdown<world>();
|
||||
modules::shutdown<luasol>();
|
||||
modules::shutdown<library>();
|
||||
modules::shutdown<factory>();
|
||||
modules::shutdown<luasol>();
|
||||
modules::shutdown<engine>();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,46 +29,60 @@ TEST_CASE("luasol") {
|
||||
luasol& l = the<luasol>();
|
||||
|
||||
SECTION("vec2/vec3/vec4") {
|
||||
v2f r0 = l.lua().script(R"lua(
|
||||
v2f r0 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local v = v2f.new(1,2)
|
||||
return v2f.new((v + v + 2).y)
|
||||
)lua");
|
||||
v3f r1 = l.lua().script(R"lua(
|
||||
});
|
||||
v3f r1 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local v = v3f.new(1,2,3)
|
||||
return v3f.new((v + v + 2).y)
|
||||
)lua");
|
||||
v4f r2 = l.lua().script(R"lua(
|
||||
});
|
||||
v4f r2 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local v = v4f.new(1,2,3,4)
|
||||
return v4f.new((v + v + 2).y)
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r0 == v2f(6));
|
||||
REQUIRE(r1 == v3f(6));
|
||||
REQUIRE(r2 == v4f(6));
|
||||
}
|
||||
|
||||
SECTION("quat") {
|
||||
v3f r0 = l.lua().script(R"lua(
|
||||
v3f r0 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
return v3f.new(1,2,3) * q4f.make_quat_from_axis_angle(radf.new(10), v3f.new(1,2,3))
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r0 == v3f(1,2,3) * math::make_quat_from_axis_angle(radf(10.f), v3f(1,2,3)));
|
||||
}
|
||||
|
||||
SECTION("mat2/mat2/mat3") {
|
||||
std::pair<m2f, bool> r0 = l.lua().script(R"lua(
|
||||
std::pair<m2f, bool> r0 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local m = m2f.make_scale_matrix2(2,3)
|
||||
local rm, s = m2f.inversed(m)
|
||||
return rm * m2f.identity(), s
|
||||
)lua");
|
||||
std::pair<m3f, bool> r1 = l.lua().script(R"lua(
|
||||
});
|
||||
std::pair<m3f, bool> r1 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local m = m3f.make_rotation_matrix3(degf.new(45),2,3,4)
|
||||
local rm, s = m3f.inversed(m)
|
||||
return rm * m3f.identity(), s
|
||||
)lua");
|
||||
std::pair<m4f, bool> r2 = l.lua().script(R"lua(
|
||||
});
|
||||
std::pair<m4f, bool> r2 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local m = m4f.make_translation_matrix4(2,3,4)
|
||||
local rm, s = m4f.inversed(m)
|
||||
return rm * m4f.identity(), s
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r0.second);
|
||||
REQUIRE(r0.first == math::inversed(math::make_scale_matrix2(2.f,3.f)).first);
|
||||
REQUIRE(r1.second);
|
||||
@@ -78,39 +92,51 @@ TEST_CASE("luasol") {
|
||||
}
|
||||
|
||||
SECTION("rect/aabb") {
|
||||
bool r0 = l.lua().script(R"lua(
|
||||
bool r0 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local b = b2f.unit() * 2
|
||||
return b:inside(v2f.new(1.5,1.5))
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r0);
|
||||
bool r1 = l.lua().script(R"lua(
|
||||
bool r1 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local b = b3f.unit() * 2
|
||||
return b:overlaps(b3f.new(1.5,1.5,1.5,2,2,2))
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r1);
|
||||
}
|
||||
|
||||
SECTION("trs2/trs3") {
|
||||
radf r0 = l.lua().script(R"lua(
|
||||
radf r0 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local t = t2f.make_rotation_trs2(degf.new(45))
|
||||
return t.rotation
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r0 == math::to_rad(degf(45.f)));
|
||||
v3f r1 = l.lua().script(R"lua(
|
||||
v3f r1 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
local t = t3f.make_translation_trs3(v3f.new(1,2,3))
|
||||
return t.translation
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r1 == v3f(1,2,3));
|
||||
}
|
||||
|
||||
SECTION("color/color32") {
|
||||
color r0 = l.lua().script(R"lua(
|
||||
color r0 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
return color.white() * 0.5
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r0 == color(0.5f,0.5f,0.5f,0.5f));
|
||||
color32 r1 = l.lua().script(R"lua(
|
||||
color32 r1 = l.with_state([](sol::state& lua){
|
||||
return lua.script(R"lua(
|
||||
return color32.white() - 1
|
||||
)lua");
|
||||
});
|
||||
REQUIRE(r1 == color32(254,254,254,254));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user