Commit 51bb74f6 authored by Florian Oetke's avatar Florian Oetke
Browse files

fixed ECS

parent bae09edd
Pipeline #2315 failed with stage
in 2 minutes and 9 seconds
......@@ -74,6 +74,8 @@ namespace mirrage::ecs {
namespace detail {
extern auto get_entity_facet(Entity_manager&, Entity_handle) -> util::maybe<Entity_facet>;
/**
* Non-template base class for components that know their entity
*/
......@@ -87,7 +89,10 @@ namespace mirrage::ecs {
MIRRAGE_INVARIANT(_owner, "invalid component");
return _owner;
}
auto owner(Entity_manager& manager) const -> Entity_facet { return {manager, owner_handle()}; }
auto owner(Entity_manager& manager) const -> util::maybe<Entity_facet>
{
return get_entity_facet(manager, owner_handle());
}
protected:
Entity_handle _owner;
......
......@@ -37,9 +37,9 @@ namespace mirrage::ecs {
constexpr Entity_id id() const noexcept { return _data >> 4; }
constexpr void id(Entity_id id) noexcept { _data = id << 4 | revision(); }
constexpr uint8_t revision() const noexcept { return _data & 0xf; }
constexpr uint8_t revision() const noexcept { return _data & 0xfu; }
constexpr void revision(uint8_t revision) noexcept { _data = id() << 4 | (revision & 0xfu); }
void increment_revision() noexcept { _data = (_data & (~0xfu)) | ((_data + 1) & 0xfu); }
void increment_revision() noexcept { revision(revision() + 1); }
constexpr packed_t pack() const noexcept { return _data; }
static constexpr Entity_handle unpack(packed_t d) noexcept { return Entity_handle{d}; }
......@@ -92,16 +92,31 @@ namespace mirrage::ecs {
// thread-safe
auto get_new() -> Entity_handle
{
auto tries = 0;
Entity_handle h;
if(_free.try_dequeue(h)) {
while(_free.try_dequeue(h)) {
auto& rev = util::at(_slots, static_cast<std::size_t>(h.id() - 1));
auto expected_rev = static_cast<uint8_t>(h.revision() | Entity_handle::free_rev);
h.revision(static_cast<uint8_t>(rev & ~Entity_handle::free_rev)); // mark as used
bool success = rev.compare_exchange_strong(expected_rev, h.revision());
MIRRAGE_INVARIANT(success, "My handle got stolen :(");
return h;
auto success = true;
auto cas = expected_rev;
do {
cas = expected_rev;
success = rev.compare_exchange_strong(cas, h.revision());
if(!success && expected_rev == cas) {
LOG(plog::debug) << "Spurious CAS failure in ECS handle generator.";
}
} while(!success && expected_rev == cas);
if(success)
return h;
else if(tries++ >= 4) {
LOG(plog::warning) << "My handle got stolen: expected="
<< int(h.revision() | Entity_handle::free_rev)
<< ", found=" << int(expected_rev) << ", rev=" << int(rev.load());
break;
}
}
auto slot = _next_free_slot++;
......
......@@ -57,7 +57,6 @@ namespace mirrage::ecs {
class Entity_facet {
public:
Entity_facet() : _manager(nullptr), _owner(invalid_entity) {}
Entity_facet(Entity_manager& manager, Entity_handle owner);
template <typename T>
util::maybe<T&> get();
......@@ -88,6 +87,10 @@ namespace mirrage::ecs {
void reset() { _owner = invalid_entity; }
private:
friend class Entity_manager;
Entity_facet(Entity_manager& manager, Entity_handle owner);
Entity_manager* _manager;
Entity_handle _owner;
};
......
#include <mirrage/ecs/component.hpp>
#include <mirrage/ecs/entity_manager.hpp>
namespace mirrage::ecs {
namespace detail {
auto get_entity_facet(Entity_manager& manager, Entity_handle h) -> util::maybe<Entity_facet>
{
return manager.get(h);
}
} // namespace detail
void Sparse_index_policy::attach(Entity_id owner, Component_index comp)
{
if(owner != invalid_entity_id)
......
......@@ -30,16 +30,16 @@ namespace mirrage::ecs {
~Blueprint() noexcept;
Blueprint& operator=(Blueprint&&) noexcept;
void detach(Entity_facet target) const;
void detach(Entity_handle target) const;
void on_reload();
mutable std::vector<Entity_facet> users;
mutable std::vector<Blueprint*> children;
std::string id;
std::string content;
asset::Ptr<Blueprint> parent;
asset::Asset_manager* asset_mgr;
mutable Entity_manager* entity_manager = nullptr;
mutable std::vector<std::tuple<Entity_handle, Entity_manager*>> users;
mutable std::vector<Blueprint*> children;
std::string id;
std::string content;
asset::Ptr<Blueprint> parent;
asset::Asset_manager* asset_mgr;
mutable Entity_manager* entity_manager = nullptr;
};
......@@ -109,13 +109,20 @@ namespace mirrage::ecs {
c->on_reload();
}
for(auto&& u : users) {
MIRRAGE_INVARIANT(u.valid(), "dead entity in blueprint.users");
apply(*this, u);
for(auto&& [u, manager] : users) {
auto facet = manager->get(u);
if(facet.is_some()) {
apply(*this, facet.get_or_throw());
} else {
LOG(plog::error) << "dead entity in blueprint.";
}
}
}
void Blueprint::detach(Entity_facet target) const { util::erase_fast(users, target); }
void Blueprint::detach(Entity_handle target) const
{
util::erase_if(users, [&](auto& e) { return std::get<0>(e) == target; });
}
} // namespace
} // namespace mirrage::ecs
......@@ -153,7 +160,7 @@ namespace mirrage::ecs {
~Blueprint_component()
{
if(blueprint) {
blueprint->detach(owner(*_manager));
blueprint->detach(owner_handle());
blueprint.reset();
}
}
......@@ -161,7 +168,7 @@ namespace mirrage::ecs {
void set(asset::Ptr<Blueprint> blueprint)
{
if(this->blueprint) {
this->blueprint->detach(owner(*_manager));
this->blueprint->detach(owner_handle());
}
this->blueprint = std::move(blueprint);
......@@ -183,8 +190,9 @@ namespace mirrage::ecs {
AID{"blueprint"_strid, blueprintName}); // TODO: could/should be async
comp.set(blueprint);
auto owner = comp.owner(comp.manager());
blueprint->users.push_back(owner);
auto owner = comp.owner(comp.manager())
.get_or_throw("instanciated Blueprint_component on dead entity");
blueprint->users.emplace_back(owner, &comp.manager());
blueprint->entity_manager = &comp.manager();
apply(*blueprint, owner);
}
......@@ -255,7 +263,7 @@ namespace mirrage::ecs {
else
e.get<Blueprint_component>().get_or_throw().set(b);
b->users.push_back(e);
b->users.emplace_back(e.handle(), &e.manager());
apply(*b, e);
}
......
......@@ -216,7 +216,7 @@ namespace mirrage::renderer {
auto active = static_cast<Camera_comp*>(nullptr);
for(auto& camera : *_cameras) {
if(camera.priority() > max_prio) {
if(camera.priority() > max_prio && camera.owner(*_entity_manager).is_some()) {
max_prio = camera.priority();
active = &camera;
}
......@@ -225,6 +225,7 @@ namespace mirrage::renderer {
if(active) {
const auto& viewport = _factory->_window.viewport();
auto& transform = active->owner(*_entity_manager)
.get_or_throw()
.get<ecs::components::Transform_comp>()
.get_or_throw("Camera without transform component!");
_active_camera = Camera_state(*active, transform, viewport);
......
......@@ -21,25 +21,28 @@ namespace mirrage::renderer {
{
for(auto& model : _loading_models) {
if(model.model().ready()) {
auto owner = model.owner(_ecs);
owner.emplace<Model_comp>(model.model());
owner.erase<Model_loading_comp>();
model.owner(_ecs).process([&](auto& owner) {
owner.template emplace<Model_comp>(model.model());
owner.template erase<Model_loading_comp>();
});
}
}
}
void Loading_system::_load(Model_unloaded_comp& model)
{
auto owner = model.owner(_ecs);
owner.emplace<Model_loading_comp>(_assets.load<Model>(model.model_aid()));
owner.erase<Model_unloaded_comp>();
model.owner(_ecs).process([&](auto& owner) {
owner.template emplace<Model_loading_comp>(_assets.load<Model>(model.model_aid()));
owner.template erase<Model_unloaded_comp>();
});
}
void Loading_system::_unload(Model_comp& model)
{
auto owner = model.owner(_ecs);
owner.emplace<Model_unloaded_comp>(model.model_aid());
owner.erase<Model_comp>();
model.owner(_ecs).process([&](auto& owner) {
owner.template emplace<Model_unloaded_comp>(model.model_aid());
owner.template erase<Model_comp>();
});
}
void Loading_system::_update(util::Time)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment