Lua Wrapper component can now be serialized
This commit is contained in:
parent
7ff9e21b4d
commit
7d55563ec8
|
@ -7,26 +7,14 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace ecs::lua {
|
namespace ecs::lua {
|
||||||
struct Wrapper : Component {
|
struct Wrapper : TaggedComponent {
|
||||||
Wrapper(std::string _name, sol::table _table) : name(_name), table(_table) {}
|
// @todo Figure out a more elegant way
|
||||||
Wrapper() {}
|
Wrapper(sol::table _table) : TaggedComponent(get_typename<Wrapper>()), table(_table) {}
|
||||||
|
Wrapper() : TaggedComponent(get_typename<Wrapper>()) {}
|
||||||
|
|
||||||
std::string name;
|
|
||||||
sol::table table;
|
sol::table table;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename... Constructor, typename... Args>
|
|
||||||
void register_component(sol::state& lua, sol::table& table, Args... args) {
|
|
||||||
table.new_usertype<T>(get_typename<T>(),
|
|
||||||
"new", sol::factories([](Constructor... constructor) {
|
|
||||||
return std::make_pair(new T(constructor...), get_typename<T>());
|
|
||||||
}), args...
|
|
||||||
);
|
|
||||||
lua.set_function("_internal_to_" + get_typename<T>(), [] (Component* component) {
|
|
||||||
return (T*)component;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(sol::state& lua);
|
void init(sol::state& lua);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#include "ecs-lua.h"
|
#include "ecs-lua.h"
|
||||||
|
|
||||||
#include "ecs.h"
|
#include "ecs.h"
|
||||||
|
|
||||||
|
namespace sol {
|
||||||
|
template<>
|
||||||
|
struct is_container<ecs::View<>> : std::true_type {};
|
||||||
|
};
|
||||||
|
|
||||||
namespace ecs::lua {
|
namespace ecs::lua {
|
||||||
void init(sol::state& lua) {
|
void init(sol::state& lua) {
|
||||||
// Add a preloader that loads all the ecs stuff
|
// Add a preloader that loads all the ecs stuff
|
||||||
|
@ -24,9 +30,19 @@ namespace ecs::lua {
|
||||||
},
|
},
|
||||||
"get_component", [&lua] (Entity* thiz, std::string name) -> sol::object {
|
"get_component", [&lua] (Entity* thiz, std::string name) -> sol::object {
|
||||||
// Convert to the correct component type
|
// Convert to the correct component type
|
||||||
auto f1 = lua["_internal_to_" + name];
|
Component* component = thiz->get_component(ComponentID::get_id({name})[0]);
|
||||||
if (f1.valid()) {
|
if (!component->_tagged()) {
|
||||||
return f1(thiz->get_component(ComponentID::get_id({name})[0]));
|
// @todo Figure out a more elegant way to convert
|
||||||
|
auto f1 = lua["_internal_to_" + name];
|
||||||
|
if (f1.valid()) {
|
||||||
|
return f1(component);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TaggedComponent* tagged_component = (TaggedComponent*)component;
|
||||||
|
auto f1 = lua["_internal_to_" + tagged_component->_tag];
|
||||||
|
if (f1.valid()) {
|
||||||
|
return f1(component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Unknown component");
|
throw std::runtime_error("Unknown component");
|
||||||
}
|
}
|
||||||
|
@ -41,6 +57,14 @@ namespace ecs::lua {
|
||||||
// @todo Allow to construct with given uuid
|
// @todo Allow to construct with given uuid
|
||||||
return thiz->create_entity();
|
return thiz->create_entity();
|
||||||
},
|
},
|
||||||
|
"has_entity", [] (Manager* thiz, std::string uuid) {
|
||||||
|
// @todo Check if valid
|
||||||
|
return thiz->has_entity(uuids::uuid::from_string(uuid).value());
|
||||||
|
},
|
||||||
|
"get_entity", [] (Manager* thiz, std::string uuid) {
|
||||||
|
// @todo Check if valid
|
||||||
|
return thiz->get_entity(uuids::uuid::from_string(uuid).value());
|
||||||
|
},
|
||||||
"view", [] (Manager* thiz, sol::variadic_args args) {
|
"view", [] (Manager* thiz, sol::variadic_args args) {
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
for (std::string name : args) {
|
for (std::string name : args) {
|
||||||
|
@ -50,12 +74,29 @@ namespace ecs::lua {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
register_component<Wrapper, std::string, sol::object>(lua, ecs,
|
return ecs;
|
||||||
"name", &Wrapper::name,
|
};
|
||||||
"table", &Wrapper::table
|
|
||||||
|
preload["ecs.Wrapper"] = [&lua] {
|
||||||
|
sol::table component = lua.create_table();
|
||||||
|
component.new_usertype<Wrapper>("Wrapper",
|
||||||
|
"__index", [] (Wrapper* thiz, std::string key) {
|
||||||
|
return thiz->table[key];
|
||||||
|
},
|
||||||
|
"__newindex", [] (Wrapper* thiz, std::string key, sol::object value) {
|
||||||
|
thiz->table[key] = value;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return ecs;
|
component.set_function("new", sol::factories([](std::string _name, sol::table _table) {
|
||||||
|
return std::make_pair(new Wrapper(_table), _name);
|
||||||
|
}));
|
||||||
|
|
||||||
|
lua.set_function("_internal_to_Wrapper", [] (ecs::Component* component) {
|
||||||
|
return (Wrapper*)component;
|
||||||
|
});
|
||||||
|
|
||||||
|
return component;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,29 @@ namespace ecs::serial {
|
||||||
auto components = entity->get_components();
|
auto components = entity->get_components();
|
||||||
iohelper::write_length(os, components.size());
|
iohelper::write_length(os, components.size());
|
||||||
for (auto [id, component] : components) {
|
for (auto [id, component] : components) {
|
||||||
auto functions = internal::functions.find(id);
|
if (!component->_tagged()) {
|
||||||
if (functions == internal::functions.end()) {
|
auto functions = internal::functions.find(id);
|
||||||
throw std::runtime_error("Unknown id");
|
if (functions == internal::functions.end()) {
|
||||||
}
|
throw std::runtime_error("No known serializer for id");
|
||||||
|
}
|
||||||
|
|
||||||
iohelper::write_length(os, id);
|
iohelper::write_length(os, id);
|
||||||
std::get<0>(internal::functions[id])(os, component);
|
iohelper::write<bool>(os, false);
|
||||||
|
std::get<0>(internal::functions[id])(os, component);
|
||||||
|
} else {
|
||||||
|
TaggedComponent* tagged_component = (TaggedComponent*)component;
|
||||||
|
auto new_id = ComponentID::get_id({tagged_component->_tag})[0];
|
||||||
|
auto functions = internal::functions.find(new_id);
|
||||||
|
|
||||||
|
if (functions == internal::functions.end()) {
|
||||||
|
throw std::runtime_error("No known serializer for id");
|
||||||
|
}
|
||||||
|
|
||||||
|
iohelper::write_length(os, new_id);
|
||||||
|
iohelper::write<bool>(os, true);
|
||||||
|
iohelper::write_length(os, id);
|
||||||
|
std::get<0>(internal::functions[new_id])(os, component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +54,13 @@ namespace ecs::serial {
|
||||||
size_t component_count = iohelper::read_length(is);
|
size_t component_count = iohelper::read_length(is);
|
||||||
// std::cout << "Updating " << component_count << " components in entity: " << uuid << '\n';
|
// std::cout << "Updating " << component_count << " components in entity: " << uuid << '\n';
|
||||||
for (size_t i = 0; i < component_count; ++i) {
|
for (size_t i = 0; i < component_count; ++i) {
|
||||||
size_t id = iohelper::read_length(is);
|
size_t new_id = iohelper::read_length(is);
|
||||||
|
bool tagged = iohelper::read<bool>(is);
|
||||||
|
size_t id = new_id;
|
||||||
|
if (tagged) {
|
||||||
|
id = iohelper::read_length(is);
|
||||||
|
}
|
||||||
|
|
||||||
// @todo We also need to be able to remove components
|
// @todo We also need to be able to remove components
|
||||||
// Sending a component with length 0 -> remove component
|
// Sending a component with length 0 -> remove component
|
||||||
// However we might have components that have no data and are just like tags
|
// However we might have components that have no data and are just like tags
|
||||||
|
@ -49,12 +71,12 @@ namespace ecs::serial {
|
||||||
// Update the component
|
// Update the component
|
||||||
std::cout << "Updating component: " << id << '\n';
|
std::cout << "Updating component: " << id << '\n';
|
||||||
Component* component = entity->get_component(id);
|
Component* component = entity->get_component(id);
|
||||||
std::get<1>(internal::functions[id])(is, component);
|
std::get<1>(internal::functions[new_id])(is, component);
|
||||||
} else {
|
} else {
|
||||||
// Add new component
|
// Add new component
|
||||||
std::cout << "Adding component: " << id << '\n';
|
std::cout << "Adding component: " << id << '\n';
|
||||||
Component* component = std::get<2>(internal::functions[id])();
|
Component* component = std::get<2>(internal::functions[new_id])();
|
||||||
std::get<1>(internal::functions[id])(is, component);
|
std::get<1>(internal::functions[new_id])(is, component);
|
||||||
entity->add_component(id, component);
|
entity->add_component(id, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,10 +86,16 @@ namespace ecs::serial {
|
||||||
size_t component_count = iohelper::read_length(is);
|
size_t component_count = iohelper::read_length(is);
|
||||||
// std::cout << "Creating entity with " << component_count << " components: " << uuid << '\n';
|
// std::cout << "Creating entity with " << component_count << " components: " << uuid << '\n';
|
||||||
for (size_t i = 0; i < component_count; ++i) {
|
for (size_t i = 0; i < component_count; ++i) {
|
||||||
size_t id = iohelper::read_length(is);
|
size_t new_id = iohelper::read_length(is);
|
||||||
|
bool tagged = iohelper::read<bool>(is);
|
||||||
|
size_t id = new_id;
|
||||||
|
if (tagged) {
|
||||||
|
id = iohelper::read_length(is);
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "Adding component: " << id << '\n';
|
std::cout << "Adding component: " << id << '\n';
|
||||||
Component* component = std::get<2>(internal::functions[id])();
|
Component* component = std::get<2>(internal::functions[new_id])();
|
||||||
std::get<1>(internal::functions[id])(is, component);
|
std::get<1>(internal::functions[new_id])(is, component);
|
||||||
entity->add_component(id, component);
|
entity->add_component(id, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,16 @@ namespace ecs {
|
||||||
|
|
||||||
struct Component {
|
struct Component {
|
||||||
virtual ~Component() {}
|
virtual ~Component() {}
|
||||||
|
|
||||||
|
virtual bool _tagged() { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tag stores the real name of a the component for special components that allow duplicates
|
||||||
|
struct TaggedComponent : Component{
|
||||||
|
TaggedComponent(std::string tag) : _tag(tag) {}
|
||||||
|
const std::string _tag;
|
||||||
|
|
||||||
|
bool _tagged() override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entity {
|
class Entity {
|
||||||
|
|
|
@ -16,8 +16,16 @@
|
||||||
#include "ecs.h"
|
#include "ecs.h"
|
||||||
#include "ecs_components.h"
|
#include "ecs_components.h"
|
||||||
|
|
||||||
|
inline void handle_error(sol::optional<std::string> maybe_msg) {
|
||||||
|
std::cerr << "Lua error, aborting!\n";
|
||||||
|
if (maybe_msg) {
|
||||||
|
const std::string& msg = maybe_msg.value();
|
||||||
|
std::cerr << "Error: " << msg << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
sol::state lua;
|
sol::state lua(sol::c_call<decltype(&handle_error), &handle_error>);
|
||||||
lua.open_libraries(sol::lib::base, sol::lib::package);
|
lua.open_libraries(sol::lib::base, sol::lib::package);
|
||||||
|
|
||||||
ecs::lua::init(lua);
|
ecs::lua::init(lua);
|
||||||
|
@ -31,7 +39,7 @@ int main() {
|
||||||
[](std::ostream& os, ecs::Component* component) {
|
[](std::ostream& os, ecs::Component* component) {
|
||||||
ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component;
|
ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component;
|
||||||
|
|
||||||
iohelper::write<std::string>(os, wrapper->name);
|
// iohelper::write<std::string>(os, wrapper->name);
|
||||||
|
|
||||||
// #todo .size() does not work
|
// #todo .size() does not work
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
@ -55,7 +63,8 @@ int main() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sol::type::number:
|
case sol::type::number:
|
||||||
iohelper::write<int32_t>(os, b.as<int32_t>());
|
// @todo These should be doubles instead of floats
|
||||||
|
iohelper::write<float>(os, b.as<float>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sol::type::boolean:
|
case sol::type::boolean:
|
||||||
|
@ -73,11 +82,10 @@ int main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[](std::istream& is, ecs::Component* component) {
|
[&lua](std::istream& is, ecs::Component* component) {
|
||||||
ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component;
|
ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component;
|
||||||
|
// @todo Only do this if table is not created yet
|
||||||
wrapper->name = iohelper::read<std::string>(is);
|
wrapper->table = lua.create_table();
|
||||||
std::cout << wrapper->name << '\n';
|
|
||||||
|
|
||||||
size_t size = iohelper::read_length(is);
|
size_t size = iohelper::read_length(is);
|
||||||
std::cout << "Size: " << size << '\n';
|
std::cout << "Size: " << size << '\n';
|
||||||
|
@ -95,15 +103,16 @@ int main() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sol::type::string:
|
case sol::type::string:
|
||||||
std::cout << "Value: " << iohelper::read<std::string>(is) << '\n';
|
wrapper->table[name] = iohelper::read<std::string>(is);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sol::type::number:
|
case sol::type::number:
|
||||||
std::cout << "Value: " << std::dec << iohelper::read<int32_t>(is) << '\n';
|
// @todo Handle floats
|
||||||
|
wrapper->table[name] = iohelper::read<float>(is);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sol::type::boolean:
|
case sol::type::boolean:
|
||||||
std::cout << "Value: " << std::dec << iohelper::read<bool>(is) << '\n';
|
wrapper->table[name] = iohelper::read<bool>(is);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -120,7 +129,7 @@ int main() {
|
||||||
return manager;
|
return manager;
|
||||||
});
|
});
|
||||||
|
|
||||||
lua.script_file("test.lua");
|
lua.safe_script_file("test.lua");
|
||||||
|
|
||||||
std::cout << "Update position\n";
|
std::cout << "Update position\n";
|
||||||
manager.view<Position, Velocity>().for_each([](ecs::Entity*, Position* pos, Velocity* vel) {
|
manager.view<Position, Velocity>().for_each([](ecs::Entity*, Position* pos, Velocity* vel) {
|
||||||
|
@ -186,6 +195,7 @@ int main() {
|
||||||
// This is needed to avoid id conflicts between clients
|
// This is needed to avoid id conflicts between clients
|
||||||
std::ofstream ids2("ids", std::ios::out | std::ios::trunc);
|
std::ofstream ids2("ids", std::ios::out | std::ios::trunc);
|
||||||
ecs::serial::serialize_ids(ids2);
|
ecs::serial::serialize_ids(ids2);
|
||||||
|
ids2.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -218,5 +228,11 @@ int main() {
|
||||||
std::cout << "x: " << pos->x << '\n';
|
std::cout << "x: " << pos->x << '\n';
|
||||||
std::cout << "y: " << pos->y << '\n';
|
std::cout << "y: " << pos->y << '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
lua.set_function("get_manager", [&manager] () -> ecs::Manager& {
|
||||||
|
return manager;
|
||||||
|
});
|
||||||
|
|
||||||
|
lua.safe_script_file("test2.lua");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ local ecs = require "ecs"
|
||||||
local Position = require "ecs.Position"
|
local Position = require "ecs.Position"
|
||||||
local Velocity = require "ecs.Velocity"
|
local Velocity = require "ecs.Velocity"
|
||||||
local Meta = require "ecs.Meta"
|
local Meta = require "ecs.Meta"
|
||||||
|
local Wrapper = require 'ecs.Wrapper'
|
||||||
|
|
||||||
manager = get_manager()
|
manager = get_manager()
|
||||||
ent = manager:create_entity()
|
ent = manager:create_entity()
|
||||||
|
@ -10,12 +11,13 @@ ent:add_component(Position.new(1.9, 9.7))
|
||||||
ent:add_component(Velocity.new(0.2, 0.3))
|
ent:add_component(Velocity.new(0.2, 0.3))
|
||||||
ent:add_component(Meta.new("Soldier"))
|
ent:add_component(Meta.new("Soldier"))
|
||||||
|
|
||||||
random = {
|
data = {
|
||||||
speed = 10,
|
speed = 10,
|
||||||
something = "Hello, World!",
|
something = "Hello, World!",
|
||||||
alive = true
|
alive = true
|
||||||
}
|
}
|
||||||
ent:add_component(ecs.Wrapper.new("Random", random))
|
ent:add_component(Wrapper.new("LuaData", data))
|
||||||
|
ent:add_component(Wrapper.new("TestThing", { test = 1.23563 }))
|
||||||
|
|
||||||
-- @todo Make this happen...
|
-- @todo Make this happen...
|
||||||
-- stats = {
|
-- stats = {
|
||||||
|
@ -60,20 +62,26 @@ end)
|
||||||
-- print "TEST"
|
-- print "TEST"
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
manager:view("Wrapper"):for_each(function(ent)
|
manager:view("LuaData"):for_each(function(ent)
|
||||||
wrapped = ent:get_component("Wrapper").table
|
d = ent:get_component("LuaData")
|
||||||
|
|
||||||
print(wrapped.speed)
|
print(d.speed)
|
||||||
wrapped.speed = 11
|
d.speed = 11
|
||||||
print(wrapped.speed)
|
print(d.speed)
|
||||||
print(random.speed)
|
print(data.speed)
|
||||||
random.speed = 20
|
data.speed = 20
|
||||||
print(wrapped.speed)
|
print(d.speed)
|
||||||
print(random.speed)
|
print(data.speed)
|
||||||
|
|
||||||
print(wrapped.alive)
|
print(d.alive)
|
||||||
wrapped.alive = false
|
d.alive = false
|
||||||
print(wrapped.alive)
|
print(d.alive)
|
||||||
|
|
||||||
print(wrapped.something)
|
print(d.something)
|
||||||
|
end)
|
||||||
|
|
||||||
|
manager:view("TestThing"):for_each(function(ent)
|
||||||
|
t = ent:get_component("TestThing")
|
||||||
|
|
||||||
|
print(t.test)
|
||||||
end)
|
end)
|
||||||
|
|
21
test/test2.lua
Normal file
21
test/test2.lua
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
manager = get_manager()
|
||||||
|
|
||||||
|
manager:view("LuaData"):for_each(function(ent)
|
||||||
|
-- @todo It would be nice if this could somehow be passed in as function arg
|
||||||
|
data = ent:get_component("LuaData")
|
||||||
|
print("speed: " .. data.speed)
|
||||||
|
print("something: " .. data.something)
|
||||||
|
-- print("alive: " .. data.alive)
|
||||||
|
end)
|
||||||
|
|
||||||
|
manager:view("TestThing"):for_each(function(ent)
|
||||||
|
data = ent:get_component("TestThing")
|
||||||
|
print("test: " .. data.test)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- @todo Allow this
|
||||||
|
-- for i, v in pairs(manager:view("TestThing")) do
|
||||||
|
-- print(i, v)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
print(manager:has_entity("6d58fdb5-6d8c-4e6f-89d4-f7d7b184f463"))
|
Loading…
Reference in New Issue
Block a user