#include <ginseng/ginseng.hpp>
#include <sol.hpp>
auto create_ginseng_usertype(sol::state_view& lua) -> sol::simple_usertype<ginseng::database> {
using ginseng::database;
using ent_id = database::ent_id;
auto usertype = lua.create_simple_usertype<database>();
usertype.set("create_entity", &database::create_entity);
usertype.set("destroy_entity", &database::destroy_entity);
usertype.set("add_component", [](database& db, ent_id eid, sol::userdata com) {
return com["_add_component"](db, eid, com);
});
usertype.set("remove_component", [](database& db, ent_id eid, sol::table com_type){
return com_type["_remove_component"](db, eid);
});
usertype.set("get_component", [](database& db, ent_id eid, sol::table com_type){
return com_type["_get_component"](db, eid);
});
usertype.set("has_component", [](database& db, ent_id eid, sol::table com_type){
return com_type["_has_component"](db, eid);
});
usertype.set("visit", [](database& db, sol::protected_function func){
db.visit([&func](ent_id eid) {
auto result = func(eid);
if (!result.valid()) {
throw result.get<sol::error>();
}
});
});
return usertype;
}
{
auto lua = sol::state{};
lua.set_usertype("ginseng_database", create_ginseng_usertype(lua));
}
function create_entity(db)
local ent = db:create_entity()
db:add_component(ent, components.position.new(0, 0))
db:add_component(ent, components.sprite.new('goomba'))
return ent
end
function draw_sprites(db)
db:visit(function (ent)
local position = db:get_component(ent, components.position)
local sprite = db:get_component(ent, components.sprite)
draw_sprite_at(position.x, position.y, sprite.name)
end)
end
template <typename T>
struct is_tag : std::false_type {};
template <typename T>
struct is_tag<ginseng::tag<T>> : std::true_type {};
namespace _detail {
using database = ginseng::database;
using ent_id = database::ent_id;
using com_id = database::com_id;
template <typename T>
void add_component(database& db, ent_id eid, T com) {
db.add_component(eid, std::move(com));
}
template <typename T>
void remove_component(database& db, ent_id eid) {
if (!db.has_component<T>(eid)) {
auto name = std::string(meta::getName<T>());
auto id = std::to_string(eid.get_index());
throw std::runtime_error("Bad component removal: " + name + " from entity " + id);
}
db.remove_component<T>(eid);
}
template <typename T>
auto get_component(database& db, ent_id eid) -> T& {
if (!db.has_component<T>(eid)) {
auto name = std::string(meta::getName<T>());
auto id = std::to_string(eid.get_index());
throw std::runtime_error("Bad component access: " + name + " from entity " + id);
}
return db.get_component<T>(eid);
}
template <typename T>
auto has_component(database& db, ent_id eid) -> bool {
return db.has_component<T>(eid);
}
} //namespace _detail
template <typename T>
auto create_component_usertype(sol::state_view& lua) -> sol::simple_usertype<T> {
if constexpr (!is_tag<T>::value) {
usertype.set("_get_component", &_detail::get_component<T>);
}
usertype.set("_add_component", &_detail::add_component<T>);
usertype.set("_remove_component", &_detail::remove_component<T>);
usertype.set("_has_component", &_detail::has_component<T>);
}
struct position {
position() = default;
position(float x, float y) : x(x), y(y) {}
float x, y;
};
void register_position_usertype(sol::state_view& lua) {
auto usertype = create_component_usertype<position>(lua);
usertype.set("new", sol::constructors<
position(),
position(const position&),
position(float x, float y)>{});
usertype.set("x", &position::x);
usertype.set("y", &position::y);
lua.set_usertype("position", usertype);
}