Skip to content

Commit

Permalink
Fix ReactiveSystem compilation error.
Browse files Browse the repository at this point in the history
Fix Matcher_AllOf/AnyOf/NoneOf compilation error when using multiple components.
Fix event trigger on component add/remove on Pool not using the correct Group pointer.
Fix entities being retained by Groups (they were being retained as well using shared_ptr, please use weap_ptr for Groups)
Ensure component destruction when clearing component pools.
Use cache methods for component events in Pool.
Simplify shared_ptr entity destructor handler.
Add bash script file to compile the example main using clang++ in Linux.
Update README with more specific links for the 0.29.0 version of C# Entitas.
  • Loading branch information
JuDelCo committed Jun 21, 2020
1 parent 4f34f4a commit bf5653e
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 72 deletions.
19 changes: 12 additions & 7 deletions EntitasPP/GroupObserver.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand All @@ -8,14 +8,14 @@

namespace EntitasPP
{
GroupObserver::GroupObserver(std::shared_ptr<Group> group, const GroupEventType eventType)
GroupObserver::GroupObserver(std::weak_ptr<Group> group, const GroupEventType eventType)
{
mGroups.push_back(group);
mEventTypes.push_back(eventType);
mAddEntityCache = std::bind(&GroupObserver::AddEntity, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
}

GroupObserver::GroupObserver(std::vector<std::shared_ptr<Group>> groups, std::vector<GroupEventType> eventTypes)
GroupObserver::GroupObserver(std::vector<std::weak_ptr<Group>> groups, std::vector<GroupEventType> eventTypes)
{
mGroups = groups;
mEventTypes = eventTypes;
Expand All @@ -38,7 +38,7 @@ void GroupObserver::Activate()
{
for(unsigned int i = 0, groupCount = mGroups.size(); i < groupCount; ++i)
{
auto g = mGroups[i];
auto g = mGroups[i].lock();
auto eventType = mEventTypes[i];

if(eventType == GroupEventType::OnEntityAdded)
Expand All @@ -64,10 +64,15 @@ void GroupObserver::Activate()

void GroupObserver::Deactivate()
{
for(const auto &g : mGroups)
for(unsigned int i = 0, groupCount = mGroups.size(); i < groupCount; ++i)
{
g->OnEntityAdded -= mAddEntityCache;
g->OnEntityRemoved -= mAddEntityCache;
if (!mGroups[i].expired())
{
auto g = mGroups[i].lock();

g->OnEntityAdded -= mAddEntityCache;
g->OnEntityRemoved -= mAddEntityCache;
}
}

ClearCollectedEntities();
Expand Down
8 changes: 4 additions & 4 deletions EntitasPP/GroupObserver.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand All @@ -18,8 +18,8 @@ class Group;
class GroupObserver
{
public:
GroupObserver(std::shared_ptr<Group> group, const GroupEventType eventType);
GroupObserver(std::vector<std::shared_ptr<Group>> groups, std::vector<GroupEventType> eventTypes);
GroupObserver(std::weak_ptr<Group> group, const GroupEventType eventType);
GroupObserver(std::vector<std::weak_ptr<Group>> groups, std::vector<GroupEventType> eventTypes);
~GroupObserver();

void Activate();
Expand All @@ -31,7 +31,7 @@ class GroupObserver
void AddEntity(std::shared_ptr<Group> group, EntityPtr entity, ComponentId index, IComponent* component);

std::unordered_set<EntityPtr> mCollectedEntities;
std::vector<std::shared_ptr<Group>> mGroups;
std::vector<std::weak_ptr<Group>> mGroups;
std::vector<GroupEventType> mEventTypes;
std::function<void(std::shared_ptr<Group>, EntityPtr, ComponentId, IComponent*)> mAddEntityCache;
};
Expand Down
9 changes: 6 additions & 3 deletions EntitasPP/ISystem.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand Down Expand Up @@ -80,9 +80,12 @@ class IReactiveExecuteSystem : public ISystem
class IReactiveSystem : public IReactiveExecuteSystem
{
public:
virtual ~IReactiveSystem() = default;
virtual ~IReactiveSystem()
{
delete trigger;
};

TriggerOnEvent trigger;
const TriggerOnEvent* trigger;
};

class IMultiReactiveSystem : public IReactiveExecuteSystem
Expand Down
14 changes: 7 additions & 7 deletions EntitasPP/Matcher.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand Down Expand Up @@ -120,19 +120,19 @@ bool Matcher::CompareIndices(const Matcher& matcher) const
return true;
}

auto Matcher::OnEntityAdded() -> const TriggerOnEvent
auto Matcher::OnEntityAdded() -> const TriggerOnEvent*
{
return TriggerOnEvent(*this, GroupEventType::OnEntityAdded);
return new TriggerOnEvent(*this, GroupEventType::OnEntityAdded);
}

auto Matcher::OnEntityRemoved() -> const TriggerOnEvent
auto Matcher::OnEntityRemoved() -> const TriggerOnEvent*
{
return TriggerOnEvent(*this, GroupEventType::OnEntityRemoved);
return new TriggerOnEvent(*this, GroupEventType::OnEntityRemoved);
}

auto Matcher::OnEntityAddedOrRemoved() -> const TriggerOnEvent
auto Matcher::OnEntityAddedOrRemoved() -> const TriggerOnEvent*
{
return TriggerOnEvent(*this, GroupEventType::OnEntityAddedOrRemoved);
return new TriggerOnEvent(*this, GroupEventType::OnEntityAddedOrRemoved);
}

bool Matcher::operator ==(const Matcher right) const
Expand Down
14 changes: 7 additions & 7 deletions EntitasPP/Matcher.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand Down Expand Up @@ -33,9 +33,9 @@ class Matcher
auto GetHashCode() const -> unsigned int;
bool CompareIndices(const Matcher& matcher) const;

auto OnEntityAdded() -> const TriggerOnEvent;
auto OnEntityRemoved() -> const TriggerOnEvent;
auto OnEntityAddedOrRemoved() -> const TriggerOnEvent;
auto OnEntityAdded() -> const TriggerOnEvent*;
auto OnEntityRemoved() -> const TriggerOnEvent*;
auto OnEntityAddedOrRemoved() -> const TriggerOnEvent*;

bool operator ==(const Matcher right) const;

Expand Down Expand Up @@ -81,7 +81,7 @@ namespace
#define FOR_EACH(MODIFIER,...) GET_MACRO(__VA_ARGS__, FUNC_6, FUNC_5, FUNC_4, FUNC_3, FUNC_2, FUNC_1)(MODIFIER, __VA_ARGS__)

#define COMPONENT_GET_TYPE_ID(COMPONENT_CLASS) EntitasPP::ComponentTypeId::Get<COMPONENT_CLASS>()
#define Matcher_AllOf(...) (EntitasPP::Matcher)EntitasPP::Matcher::AllOf(std::vector<EntitasPP::ComponentId>({ FOR_EACH(COMPONENT_GET_TYPE_ID, __VA_ARGS__) }))
#define Matcher_AnyOf(...) (EntitasPP::Matcher)EntitasPP::Matcher::AnyOf(std::vector<EntitasPP::ComponentId>({ FOR_EACH(COMPONENT_GET_TYPE_ID, __VA_ARGS__) }))
#define Matcher_NoneOf(...) (EntitasPP::Matcher)EntitasPP::Matcher::NoneOf(std::vector<EntitasPP::ComponentId>({ FOR_EACH(COMPONENT_GET_TYPE_ID, __VA_ARGS__) }))
#define Matcher_AllOf(...) ((EntitasPP::Matcher)EntitasPP::Matcher::AllOf(std::vector<EntitasPP::ComponentId>({ FOR_EACH(COMPONENT_GET_TYPE_ID, __VA_ARGS__) })))
#define Matcher_AnyOf(...) ((EntitasPP::Matcher)EntitasPP::Matcher::AnyOf(std::vector<EntitasPP::ComponentId>({ FOR_EACH(COMPONENT_GET_TYPE_ID, __VA_ARGS__) })))
#define Matcher_NoneOf(...) ((EntitasPP::Matcher)EntitasPP::Matcher::NoneOf(std::vector<EntitasPP::ComponentId>({ FOR_EACH(COMPONENT_GET_TYPE_ID, __VA_ARGS__) })))
}
38 changes: 18 additions & 20 deletions EntitasPP/Pool.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand All @@ -14,6 +14,9 @@ Pool::Pool(const unsigned int startCreationIndex)
{
mCreationIndex = startCreationIndex;
mOnEntityReleasedCache = std::bind(&Pool::OnEntityReleased, this, std::placeholders::_1);
mOnComponentAddedCache = std::bind(&Pool::UpdateGroupsComponentAddedOrRemoved, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
mOnComponentRemovedCache = std::bind(&Pool::UpdateGroupsComponentAddedOrRemoved, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
mOnComponentReplacedCache = std::bind(&Pool::UpdateGroupsComponentReplaced, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
}

Pool::~Pool()
Expand Down Expand Up @@ -56,9 +59,9 @@ auto Pool::CreateEntity() -> EntityPtr
}
else
{
entity = EntityPtr(new Entity(&mComponentPools), [](void* entity)
entity = EntityPtr(new Entity(&mComponentPools), [](Entity* entity)
{
(static_cast<Entity*>(entity)->OnEntityReleased(static_cast<Entity*>(entity)));
entity->OnEntityReleased(entity);
});
}

Expand All @@ -69,18 +72,9 @@ auto Pool::CreateEntity() -> EntityPtr
mEntities.insert(entity);
mEntitiesCache.clear();

entity->OnComponentAdded += [this](EntityPtr entity, ComponentId index, IComponent* component)
{
UpdateGroupsComponentAddedOrRemoved(entity, index, component);
};
entity->OnComponentRemoved += [this](EntityPtr entity, ComponentId index, IComponent* component)
{
UpdateGroupsComponentAddedOrRemoved(entity, index, component);
};
entity->OnComponentReplaced += [this](EntityPtr entity, ComponentId index, IComponent* previousComponent, IComponent* newComponent)
{
UpdateGroupsComponentReplaced(entity, index, previousComponent, newComponent);
};
entity->OnComponentAdded += mOnComponentAddedCache;
entity->OnComponentRemoved += mOnComponentRemovedCache;
entity->OnComponentReplaced += mOnComponentReplacedCache;

entity->OnEntityReleased.Clear();
entity->OnEntityReleased += mOnEntityReleasedCache;
Expand Down Expand Up @@ -137,7 +131,7 @@ void Pool::DestroyAllEntities()

if (! mRetainedEntities.empty())
{
// Try calling Pool.ClearGroups() and SystemContainer.ClearReactiveSystems() before calling pool.DestroyAllEntities() to avoid memory leaks
// Try calling pool.ClearGroups() and systemContainer.ClearReactiveSystems() before calling pool.DestroyAllEntities() to avoid memory leaks
throw std::runtime_error("Error, pool detected retained entities although all entities got destroyed. Did you release all entities?");
}
}
Expand Down Expand Up @@ -219,6 +213,7 @@ void Pool::ClearComponentPool(const ComponentId index)
{
while(! mComponentPools.at(index).empty())
{
delete mComponentPools.at(index).top();
mComponentPools.at(index).pop();
}
}
Expand Down Expand Up @@ -284,16 +279,19 @@ void Pool::UpdateGroupsComponentAddedOrRemoved(EntityPtr entity, ComponentId ind

if (groups.size() > 0)
{
auto events = std::vector<Group::GroupChanged*>();
auto events = std::vector<std::pair<std::weak_ptr<Group>, Group::GroupChanged*>>();

for (int i = 0, groupsCount = groups.size(); i < groupsCount; ++i)
{
events.push_back(groups[i].lock()->HandleEntity(entity));
events.push_back(std::make_pair(groups[i], groups[i].lock()->HandleEntity(entity)));
}

for (int i = 0, eventsCount = events.size(); i < eventsCount; ++i)
for (const auto &pair : events)
{
(*events[i])(groups[i].lock(), entity, index, component);
if (pair.second != nullptr)
{
(*pair.second)(pair.first.lock(), entity, index, component);
}
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion EntitasPP/Pool.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand Down Expand Up @@ -66,6 +66,9 @@ class Pool

std::vector<EntityPtr> mEntitiesCache;
std::function<void(Entity*)> mOnEntityReleasedCache;
std::function<void(EntityPtr, ComponentId, IComponent*)> mOnComponentAddedCache;
std::function<void(EntityPtr, ComponentId, IComponent*)> mOnComponentRemovedCache;
std::function<void(EntityPtr, ComponentId, IComponent*, IComponent*)> mOnComponentReplacedCache;
};

template <typename T>
Expand Down
6 changes: 3 additions & 3 deletions EntitasPP/ReactiveSystem.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Juan Delgado (JuDelCo)
// Copyright (c) 2020 Juan Delgado (JuDelCo)
// License: MIT License
// MIT License web page: https://opensource.org/licenses/MIT

Expand All @@ -9,7 +9,7 @@
namespace EntitasPP
{
ReactiveSystem::ReactiveSystem(Pool* pool, std::shared_ptr<IReactiveSystem> subsystem) :
ReactiveSystem(pool, subsystem, std::vector<TriggerOnEvent>(1, subsystem->trigger))
ReactiveSystem(pool, subsystem, std::vector<TriggerOnEvent>(1, *subsystem->trigger))
{
}

Expand Down Expand Up @@ -38,7 +38,7 @@ ReactiveSystem::ReactiveSystem(Pool* pool, std::shared_ptr<IReactiveExecuteSyste
}

unsigned int triggersLength = triggers.size();
auto groups = std::vector<std::shared_ptr<Group>>(triggersLength);
auto groups = std::vector<std::weak_ptr<Group>>(triggersLength);
auto eventTypes = std::vector<GroupEventType>(triggersLength);

for(unsigned int i = 0; i < triggersLength; ++i)
Expand Down
26 changes: 6 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
Entitas++
=====================

Entitas++ is a fast Entity Component System Framework (ECS) C++11 port of [Entitas for C# and Unity](https://github.com/sschmid/Entitas-CSharp).
Entitas++ is a fast Entity Component System Framework (ECS) C++11 port of [Entitas v0.29.0 for C# and Unity](https://github.com/sschmid/Entitas-CSharp/tree/0.29.0).

There are some differences between both, so please check the code and notes below !

The framework will follow a [semantic versioning](http://semver.org/).

Any feedback is welcome !

Documentation
Expand Down Expand Up @@ -224,15 +222,15 @@ public class MoveSystem : IExecuteSystem, ISetPool {
###### Entitas++
```cpp
class MoveSystem : public IExecuteSystem, public ISetPool {
std::shared_ptr<Group> _group;
std::weak_ptr<Group> _group;

public:
void SetPool(Pool* pool) {
_group = pool->GetGroup(Matcher_AllOf(Move, Position));
}

void Execute() {
for (auto &e : _group->GetEntities()) {
for (auto &e : _group.lock()->GetEntities()) {
auto move = e->Get<Move>();
auto pos = e->Get<Position>();
e->Replace<Position>(pos->x, pos->y + move->speed, pos->z);
Expand Down Expand Up @@ -262,11 +260,9 @@ public class RenderPositionSystem : IReactiveSystem {
###### Entitas++
```cpp
class RenderPositionSystem : public IReactiveSystem {
TriggerOnEvent trigger;

public:
RenderPositionSystem() {
trigger = Matcher_AllOf(Position, View)->OnEntityAdded();
trigger = Matcher_AllOf(Position, View).OnEntityAdded();
}

void Execute(std::vector<EntityPtr> entities) {
Expand All @@ -290,22 +286,12 @@ Notes
- All 'ToString()' methods were removed. If you need to track identifiers between entities I suggest you to use your own custom Component.
- AERC (Automatic Entity Reference Counting) was implemented using smart pointers. (Yeah! Take that C# :stuck_out_tongue_winking_eye:)

If you need more documentation of the architecture of the framework, please go to [Entitas C# Wiki](https://github.com/sschmid/Entitas-CSharp/wiki) since this framework has a lot on common with the original C# one.
Planned
=====================
- Unit Tests
- *Moar* Unit Tests
- Perfomance Tests
- More robust code (more tested :smile:)
- Examples
- Better Readme.md (suggestions?)
If you need more documentation of the architecture of the framework, please go to [Entitas v0.29.0 C# Wiki](https://github.com/sschmid/Entitas-CSharp/wiki/Home/18f70d987d94be972c179bbd71b3a175263c0f04) since this framework has a lot on common with the original C# one.

The MIT License (MIT)
=====================

Copyright © 2016 Juan Delgado (JuDelCo)
Copyright © 2020 Juan Delgado (JuDelCo)

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
Expand Down
24 changes: 24 additions & 0 deletions clang_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

echo "Build started..."

start=`date +%s`
clang++ -std=c++11 -stdlib=libc++ -g \
EntitasPP/ComponentTypeId.cpp \
EntitasPP/Entity.cpp \
EntitasPP/Group.cpp \
EntitasPP/GroupObserver.cpp \
EntitasPP/Matcher.cpp \
EntitasPP/Pool.cpp \
EntitasPP/ReactiveSystem.cpp \
EntitasPP/SystemContainer.cpp \
main.cpp \
-o bin/main-build
end=`date +%s`
run_time=$((end-start))

echo "Build finished ($run_times)"

read -s -n 1 -p "Press any key to close ..."
echo ""

1 change: 1 addition & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "EntitasPP/Matcher.hpp"
#include "EntitasPP/Pool.hpp"
#include <iostream>
#include <string>

using namespace EntitasPP;

Expand Down

0 comments on commit bf5653e

Please sign in to comment.