]> code.bitgloo.com Git - clyne/entityx.git/commitdiff
Performance improvements + emitting events from Python.
authorAlec Thomas <alec@swapoff.org>
Wed, 4 Sep 2013 23:36:31 +0000 (19:36 -0400)
committerAlec Thomas <alec@swapoff.org>
Wed, 4 Sep 2013 23:36:31 +0000 (19:36 -0400)
22 files changed:
CMakeLists.txt
README.md
entityx/Benchmarks_test.cc
entityx/Entity.cc
entityx/Entity.h
entityx/Entity_test.cc
entityx/Event.cc
entityx/Event.h
entityx/Event_test.cc
entityx/Manager.h
entityx/ReferenceCounted.h [new file with mode: 0644]
entityx/System.h
entityx/System_test.cc
entityx/config.h.in
entityx/python/PythonSystem.cc
entityx/python/PythonSystem.h
entityx/python/PythonSystem_test.cc
entityx/python/README.md
entityx/python/entityx/__init__.py
entityx/python/entityx/tests/event_emit_test.py [new file with mode: 0644]
entityx/python/entityx/tests/update_test.py
entityx/tags/TagsComponent.h

index 667549ffa4686b2bac8ec598167d4f877f7d640d..761a031284e1985c19cfbde7b8d8de16ba24833e 100644 (file)
@@ -16,6 +16,7 @@ set(ENTITYX_USE_CPP11_STDLIB false CACHE BOOL "For Clang, specify whether to use
 set(ENTITYX_USE_STD_SHARED_PTR false CACHE BOOL "Use std::shared_ptr<T> rather than boost::shared_ptr<T>?")
 set(ENTITYX_BUILD_SHARED true CACHE BOOL "Build shared libraries?")
 set(ENTITYX_BUILD_PYTHON true CACHE BOOL "Build entityx::python?")
+set(ENTITYX_BOOST_SP_DISABLE_THREADS false CACHE BOOL "Disable multi-threading support in boost::shared_ptr")
 
 include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
 include(CheckCXXSourceCompiles)
@@ -27,6 +28,12 @@ set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
 set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
 
+
+if (ENTITYX_BOOST_SP_DISABLE_THREADS)
+    message("-- Disabled multi-threading support in Boost (see http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm)")
+    add_definitions(-DBOOST_SP_DISABLE_THREADS=1)
+endif ()
+
 # C++11 feature checks
 include(CheckCXX11Features.cmake)
 
index 49b03c61aa78f1dd0761fcfcb084a13ae2d01634..f60897b174435a0b13787f67568b8dc0ac9ce8e0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -38,8 +38,8 @@ An `Entity` is a convenience class wrapping an opaque `uint64_t` value allocated
 Creating an entity is as simple as:
 
 ```c++
-entityx::shared_ptr<EventManager> events = EventManager::make();
-entityx::shared_ptr<EntityManager> entities = EntityManager::make(events);
+entityx::ptr<EventManager> events = EventManager::make();
+entityx::ptr<EntityManager> entities = EntityManager::make(events);
 
 Entity entity = entities->create();
 ```
@@ -57,6 +57,7 @@ entity.destroy();
 - When an entity is destroyed the manager adds its ID to a free list and invalidates the Entity handle.
 - When an entity is created IDs are recycled from the free list before allocating new ones.
 - An Entity ID contains an index and a version. When an entity is destroyed, the version associated with the index is incremented, invalidating all previous entities referencing the previous ID.
+- EntityX uses a reference counting smart pointer`entityx::ptr<T>` to manage object lifetimes. As a general rule, passing a pointer to any EntityX method will convert to a smart pointer and take ownership. To maintain your own reference to the pointer you will need to wrap it in `entityx::ptr<T>`.
 
 ### Components (entity data)
 
@@ -94,7 +95,7 @@ entity.assign<Position>(1.0f, 2.0f);
 You can also assign existing instances of components:
 
 ```c++
-entityx::shared_ptr<Position> position = entityx::make_shared<Position>(1.0f, 2.0f);
+entityx::ptr<Position> position = new Position(1.0f, 2.0f);
 entity.assign(position);
 ```
 
@@ -104,8 +105,8 @@ To query all entities with a set of components assigned, use ``EntityManager::en
 
 ```c++
 for (auto entity : entities->entities_with_components<Position, Direction>()) {
-  entityx::shared_ptr<Position> position = entity.component<Position>();
-  entityx::shared_ptr<Direction> direction = entity.component<Direction>();
+  entityx::ptr<Position> position = entity.component<Position>();
+  entityx::ptr<Direction> direction = entity.component<Direction>();
 
   // Do things with entity, position and direction.
 }
@@ -114,7 +115,7 @@ for (auto entity : entities->entities_with_components<Position, Direction>()) {
 To retrieve a component associated with an entity use ``Entity::component<C>()``:
 
 ```c++
-entityx::shared_ptr<Position> position = entity.component<Position>();
+entityx::ptr<Position> position = entity.component<Position>();
 if (position) {
   // Do stuff with position
 }
@@ -133,10 +134,10 @@ A basic movement system might be implemented with something like the following:
 
 ```c++
 struct MovementSystem : public System<MovementSystem> {
-  void update(entityx::shared_ptr<EntityManager> es, entityx::shared_ptr<EventManager> events, double dt) override {
+  void update(entityx::ptr<EntityManager> es, entityx::ptr<EventManager> events, double dt) override {
     for (auto entity : es->entities_with_components<Position, Direction>()) {
-      entityx::shared_ptr<Position> position = entity.component<Position>();
-      entityx::shared_ptr<Direction> direction = entity.component<Direction>();
+      entityx::ptr<Position> position = entity.component<Position>();
+      entityx::ptr<Direction> direction = entity.component<Direction>();
 
       position->x += direction->x * dt;
       position->y += direction->y * dt;
@@ -171,10 +172,10 @@ Next we implement our collision system, which emits ``Collision`` objects via an
 ```c++
 class CollisionSystem : public System<CollisionSystem> {
  public:
-  void update(entityx::shared_ptr<EntityManager> es, entityx::shared_ptr<EventManager> events, double dt) override {
-    entityx::shared_ptr<Position> left_position, right_position;
-    for (auto left_entity : es.entities_with_components<Position>()) {
-      for (auto right_entity : es.entities_with_components<Position>()) {
+  void update(entityx::ptr<EntityManager> es, entityx::ptr<EventManager> events, double dt) override {
+    entityx::ptr<Position> left_position, right_position;
+    for (auto left_entity : es.entities_with_components<Position>(left_position)) {
+      for (auto right_entity : es.entities_with_components<Position>(right_position)) {
         if (collide(left_position, right_position)) {
           events.emit<Collision>(left_entity, right_entity);
         }
@@ -190,8 +191,8 @@ Objects interested in receiving collision information can subscribe to ``Collisi
 
 ```c++
 struct DebugSystem : public System<DebugSystem>, Receiver<DebugSystem> {
-  void configure(EventManager &event_manager) {
-    event_manager.subscribe<Collision>(*this);
+  void configure(entityx::ptr<EventManager> event_manager) {
+    event_manager->subscribe<Collision>(*this);
   }
 
   void receive(const Collision &collision) {
@@ -210,7 +211,7 @@ Several events are emitted by EntityX itself:
   - `Entity entity` - Entity about to be destroyed.
 - `ComponentAddedEvent<T>` - emitted when a new component is added to an entity.
   - `Entity entity` - Entity that component was added to.
-  - `entityx::shared_ptr<T> component` - The component added.
+  - `entityx::ptr<T> component` - The component added.
 
 #### Implementation notes
 
index d02896a6772e68ecf647927d76f4f4eb5e9c0442..f469c3729cd5c18fb1523fbf11704d08ee373768 100644 (file)
@@ -9,10 +9,10 @@ using namespace entityx;
 
 class BenchmarksTest : public ::testing::Test {
 protected:
- BenchmarksTest() : ev(EventManager::make()), em(EntityManager::make(ev)) {}
 BenchmarksTest() : ev(EventManager::make()), em(EntityManager::make(ev)) {}
 
entityx::shared_ptr<EventManager> ev;
entityx::shared_ptr<EntityManager> em;
 ptr<EventManager> ev;
 ptr<EntityManager> em;
 };
 
 
@@ -97,8 +97,8 @@ TEST_F(BenchmarksTest, TestEntityIteration) {
   cout << "iterating over " << count << " entities with a component 10 times" << endl;
 
   for (int i = 0; i < 10; ++i) {
-    for (auto e : em->entities_with_components<Position>()) {
-      entityx::shared_ptr<Position> position = e.component<Position>();
+    ptr<Position> position;
+    for (auto e : em->entities_with_components<Position>(position)) {
       position.get();
     }
   }
index 31eb254145724706495afa75a610523c145f9309..dfc6bb5f6a45442ef1c881f2977a183189157ca5 100644 (file)
@@ -31,6 +31,12 @@ bool Entity::valid() const {
   return !manager_.expired() && manager_.lock()->valid(id_);
 }
 
+EntityManager::EntityManager(ptr<EventManager> event_manager) : event_manager_(event_manager) {
+}
+
+EntityManager::~EntityManager() {
+}
+
 void EntityManager::destroy_all() {
   entity_components_.clear();
   entity_component_mask_.clear();
@@ -39,4 +45,4 @@ void EntityManager::destroy_all() {
 }
 
 
-}
+}  // namespace entityx
index 09cff223e91d22c266aa26b7917e452eeab24384..abb35528a4b53b2021517582bc636992d3a5607a 100644 (file)
@@ -53,12 +53,12 @@ public:
     bool operator != (const Id &other) const { return id_ != other.id_; }
     bool operator < (const Id &other) const { return id_ < other.id_; }
 
-  private:
-    friend class EntityManager;
-
     uint32_t index() const { return id_ & 0xffffffffUL; }
     uint32_t version() const { return id_ >> 32; }
 
+  private:
+    friend class EntityManager;
+
     uint64_t id_;
   };
 
@@ -76,12 +76,12 @@ public:
   /**
    * Check if Entity handle is invalid.
    */
-  bool operator !() const {
-    return !valid();
+  operator bool () const {
+    return valid();
   }
 
   bool operator == (const Entity &other) const {
-    return other.manager_.lock() == manager_.lock() && other.id_ == id_;
+    return other.manager_ == manager_ && other.id_ == id_;
   }
 
   bool operator != (const Entity &other) const {
@@ -109,20 +109,20 @@ public:
   Id id() const { return id_; }
 
   template <typename C>
-  entityx::shared_ptr<C> assign(entityx::shared_ptr<C> component);
+  ptr<C> assign(ptr<C> component);
   template <typename C, typename ... Args>
-  entityx::shared_ptr<C> assign(Args && ... args);
+  ptr<C> assign(Args && ... args);
 
   template <typename C>
-  entityx::shared_ptr<C> remove();
+  ptr<C> remove();
 
   template <typename C>
-  entityx::shared_ptr<C> component();
+  ptr<C> component();
 
   template <typename A>
-  void unpack(entityx::shared_ptr<A> &a);
+  void unpack(ptr<A> &a);
   template <typename A, typename B, typename ... Args>
-  void unpack(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args);
+  void unpack(ptr<A> &a, ptr<B> &b, Args && ... args);
 
   /**
    * Destroy and invalidate this Entity.
@@ -132,9 +132,9 @@ public:
  private:
   friend class EntityManager;
 
-  Entity(entityx::shared_ptr<EntityManager> manager, Entity::Id id) : manager_(manager), id_(id) {}
+  Entity(ptr<EntityManager> manager, Entity::Id id) : manager_(manager), id_(id) {}
 
-  entityx::weak_ptr<EntityManager> manager_;
+  weak_ptr<EntityManager> manager_;
   Entity::Id id_ = INVALID;
 };
 
@@ -216,11 +216,11 @@ struct EntityDestroyedEvent : public Event<EntityDestroyedEvent> {
  */
 template <typename T>
 struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
-  ComponentAddedEvent(Entity entity, entityx::shared_ptr<T> component) :
+  ComponentAddedEvent(Entity entity, ptr<T> component) :
       entity(entity), component(component) {}
 
   Entity entity;
-  entityx::shared_ptr<T> component;
+  ptr<T> component;
 };
 
 /**
@@ -228,43 +228,52 @@ struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
  */
 template <typename T>
 struct ComponentRemovedEvent : public Event<ComponentRemovedEvent<T>> {
-  ComponentRemovedEvent(Entity entity, entityx::shared_ptr<T> component) :
+  ComponentRemovedEvent(Entity entity, ptr<T> component) :
       entity(entity), component(component) {}
 
   Entity entity;
-  entityx::shared_ptr<T> component;
+  ptr<T> component;
 };
 
 /**
  * Manages Entity::Id creation and component assignment.
  */
-class EntityManager : public entityx::enable_shared_from_this<EntityManager>, boost::noncopyable {
+class EntityManager : boost::noncopyable, public enable_shared_from_this<EntityManager> {
  public:
   typedef std::bitset<entityx::MAX_COMPONENTS> ComponentMask;
 
-  static entityx::shared_ptr<EntityManager> make(entityx::shared_ptr<EventManager> event_manager) {
-    return entityx::shared_ptr<EntityManager>(new EntityManager(event_manager));
+  explicit EntityManager(ptr<EventManager> event_manager);
+  virtual ~EntityManager();
+
+  static ptr<EntityManager> make(ptr<EventManager> event_manager) {
+    return ptr<EntityManager>(new EntityManager(event_manager));
   }
 
   class View {
    public:
-    typedef boost::function<bool (entityx::shared_ptr<EntityManager>, Entity::Id)> Predicate;
+    typedef boost::function<bool (const ptr<EntityManager> &, const Entity::Id &)> Predicate;
 
     /// A predicate that matches valid entities with the given component mask.
     class ComponentMaskPredicate {
      public:
-      ComponentMaskPredicate(const std::vector<ComponentMask> &entity_id, ComponentMask mask) : entity_id_(entity_id), mask_(mask) {}
+      ComponentMaskPredicate(const std::vector<ComponentMask> &entity_components, ComponentMask mask)
+          : entity_components_(entity_components), mask_(mask) {}
 
-      bool operator()(entityx::shared_ptr<EntityManager> entities, Entity::Id entity) {
-        return entities->entity_version_.at(entity.index()) == entity.version()
-            && (entity_id_.at(entity.index()) & mask_) == mask_;
+      bool operator()(const ptr<EntityManager> &entities, const Entity::Id &entity) {
+        return entities->entity_version_[entity.index()] == entity.version()
+            && (entity_components_[entity.index()] & mask_) == mask_;
       }
 
      private:
-      const std::vector<ComponentMask> &entity_id_;
+      const std::vector<ComponentMask> &entity_components_;
       ComponentMask mask_;
     };
 
+    struct BaseUnpacker {
+      virtual ~BaseUnpacker() {}
+      virtual void unpack(const Entity::Id &id) = 0;
+    };
+
     /// An iterator over a view of the entities in an EntityManager.
     class Iterator : public std::iterator<std::input_iterator_tag, Entity::Id> {
      public:
@@ -275,40 +284,47 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
       }
       bool operator == (const Iterator& rhs) const { return i_ == rhs.i_; }
       bool operator != (const Iterator& rhs) const { return i_ != rhs.i_; }
-      Entity operator * () { return Entity(view_.manager_, view_.manager_->create_id(i_)); }
-      const Entity operator * () const { return Entity(view_.manager_, view_.manager_->create_id(i_)); }
+      Entity operator * () { return Entity(manager_, manager_->create_id(i_)); }
+      const Entity operator * () const { return Entity(manager_, manager_->create_id(i_)); }
 
      private:
       friend class View;
 
-      Iterator(const View &view, uint32_t index) : view_(view), i_(index) {
+      Iterator(ptr<EntityManager> manager,
+               std::vector<Predicate> predicates,
+               std::vector<ptr<BaseUnpacker>> unpackers,
+               uint32_t index)
+          : manager_(manager), predicates_(predicates), unpackers_(unpackers), i_(index), capacity_(manager_->capacity()) {
         next();
       }
 
       void next() {
-        while (i_ < view_.manager_->capacity() && !predicate()) {
+        while (i_ < capacity_ && !predicate()) {
           ++i_;
         }
-        if (i_ < view_.manager_->capacity() && !view_.unpackers_.empty()) {
-          Entity::Id id = view_.manager_->create_id(i_);
-          for (auto &unpacker : view_.unpackers_) {
-            unpacker(id);
+        if (i_ < capacity_ && !unpackers_.empty()) {
+          Entity::Id id = manager_->create_id(i_);
+          for (auto &unpacker : unpackers_) {
+            unpacker->unpack(id);
           }
         }
       }
 
       bool predicate() {
-        Entity::Id id = view_.manager_->create_id(i_);
-        for (auto &p : view_.predicates_) {
-          if (!p(view_.manager_, id)) {
+        Entity::Id id = manager_->create_id(i_);
+        for (auto &p : predicates_) {
+          if (!p(manager_, id)) {
             return false;
           }
         }
         return true;
       }
 
-      const View &view_;
+      ptr<EntityManager> manager_;
+      std::vector<Predicate> predicates_;
+      std::vector<ptr<BaseUnpacker>> unpackers_;
       uint32_t i_;
+      size_t capacity_;
     };
 
     // Create a sub-view with an additional predicate.
@@ -316,19 +332,19 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
       predicates_.push_back(predicate);
     }
 
-    Iterator begin() { return Iterator(*this, 0); }
-    Iterator end() { return Iterator(*this, manager_->size()); }
-    const Iterator begin() const { return Iterator(*this, 0); }
-    const Iterator end() const { return Iterator(*this, manager_->size()); }
+    Iterator begin() { return Iterator(manager_, predicates_, unpackers_, 0); }
+    Iterator end() { return Iterator(manager_, predicates_, unpackers_, manager_->size()); }
+    const Iterator begin() const { return Iterator(manager_, predicates_, unpackers_, 0); }
+    const Iterator end() const { return Iterator(manager_, predicates_, unpackers_, manager_->size()); }
 
     template <typename A>
-    View &unpack_to(entityx::shared_ptr<A> &a) {
-      unpackers_.push_back(Unpacker<A>(manager_, a));
+    View &unpack_to(ptr<A> &a) {
+      unpackers_.push_back(ptr<Unpacker<A>>(new Unpacker<A>(manager_, a)));
       return *this;
     }
 
     template <typename A, typename B, typename ... Args>
-    View &unpack_to(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
+    View &unpack_to(ptr<A> &a, ptr<B> &b, Args && ... args) {
       unpack_to<A>(a);
       return unpack_to<B, Args ...>(b, args ...);
     }
@@ -337,25 +353,25 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
     friend class EntityManager;
 
     template <typename T>
-    struct Unpacker {
-      Unpacker(entityx::shared_ptr<EntityManager> manager, entityx::shared_ptr<T> &c) : manager_(manager), c(c) {}
+    struct Unpacker : BaseUnpacker {
+      Unpacker(ptr<EntityManager> manager, ptr<T> &c) : manager_(manager), c(c) {}
 
-      void operator()(Entity::Id id) {
+      void unpack(const Entity::Id &id) {
         c = manager_->component<T>(id);
       }
 
      private:
-      entityx::shared_ptr<EntityManager> manager_;
-      entityx::shared_ptr<T> &c;
+      ptr<EntityManager> manager_;
+      ptr<T> &c;
     };
 
-    View(entityx::shared_ptr<EntityManager> manager, Predicate predicate) : manager_(manager) {
+    View(ptr<EntityManager> manager, Predicate predicate) : manager_(manager) {
       predicates_.push_back(predicate);
     }
 
-    entityx::shared_ptr<EntityManager> manager_;
+    ptr<EntityManager> manager_;
     std::vector<Predicate> predicates_;
-    std::vector<boost::function<void(Entity::Id)>> unpackers_;
+    std::vector<ptr<BaseUnpacker>> unpackers_;
   };
 
   /**
@@ -372,7 +388,7 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    * Return true if the given entity ID is still valid.
    */
   bool valid(Entity::Id id) {
-    return id.index() < entity_version_.size() && entity_version_.at(id.index()) == id.version();
+    return id.index() < entity_version_.size() && entity_version_[id.index()] == id.version();
   }
 
   /**
@@ -385,11 +401,11 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
     if (free_list_.empty()) {
       index = index_counter_++;
       accomodate_entity(index);
-      version = entity_version_.at(index) = 1;
+      version = entity_version_[index] = 1;
     } else {
       index = free_list_.front();
       free_list_.pop_front();
-       version = entity_version_.at(index);
+       version = entity_version_[index];
     }
     Entity entity(shared_from_this(), Entity::Id(index, version));
     event_manager_->emit<EntityCreatedEvent>(entity);
@@ -403,18 +419,18 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    */
   void destroy(Entity::Id entity) {
     assert(entity.index() < entity_component_mask_.size() && "Entity::Id ID outside entity vector range");
-    assert(entity_version_.at(entity.index()) == entity.version() && "Attempt to destroy Entity using a stale Entity::Id");
+    assert(entity_version_[entity.index()] == entity.version() && "Attempt to destroy Entity using a stale Entity::Id");
     event_manager_->emit<EntityDestroyedEvent>(Entity(shared_from_this(), entity));
     for (auto &components : entity_components_) {
-      components.at(entity.index()).reset();
+      components[entity.index()].reset();
     }
-    entity_component_mask_.at(entity.index()) = 0;
-    entity_version_.at(entity.index())++;
+    entity_component_mask_[entity.index()] = 0;
+    entity_version_[entity.index()]++;
     free_list_.push_back(entity.index());
   }
 
   Entity get(Entity::Id id) {
-    assert(entity_version_.at(id.index()) != id.version() && "Attempt to get() with stale Entity::Id");
+    assert(entity_version_[id.index()] != id.version() && "Attempt to get() with stale Entity::Id");
     return Entity(shared_from_this(), id);
   }
 
@@ -425,7 +441,7 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    * fail if the ID is invalid.
    */
   Entity::Id create_id(uint32_t index) const {
-    return Entity::Id(index, entity_version_.at(index));
+    return Entity::Id(index, entity_version_[index]);
   }
 
   /**
@@ -434,11 +450,11 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    * @returns component
    */
   template <typename C>
-  entityx::shared_ptr<C> assign(Entity::Id id, entityx::shared_ptr<C> component) {
-    entityx::shared_ptr<BaseComponent> base = entityx::static_pointer_cast<BaseComponent>(component);
+  ptr<C> assign(Entity::Id id, ptr<C> component) {
+    ptr<BaseComponent> base(static_pointer_cast<BaseComponent>(component));
     accomodate_component(C::family());
-    entity_components_.at(C::family()).at(id.index()) = base;
-    entity_component_mask_.at(id.index()) |= uint64_t(1) << C::family();
+    entity_components_[C::family()][id.index()] = base;
+    entity_component_mask_[id.index()] |= uint64_t(1) << C::family();
 
     event_manager_->emit<ComponentAddedEvent<C>>(Entity(shared_from_this(), id), component);
     return component;
@@ -447,13 +463,13 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
   /**
    * Assign a Component to an Entity::Id, optionally passing through Component constructor arguments.
    *
-   *   shared_ptr<Position> position = em.assign<Position>(e, x, y);
+   *     ptr<Position> position = em.assign<Position>(e, x, y);
    *
    * @returns Newly created component.
    */
   template <typename C, typename ... Args>
-  entityx::shared_ptr<C> assign(Entity::Id entity, Args && ... args) {
-    return assign<C>(entity, entityx::make_shared<C>(args ...));
+  ptr<C> assign(Entity::Id entity, Args && ... args) {
+    return assign<C>(entity, ptr<C>(new C(args ...)));
   }
 
   /**
@@ -462,10 +478,10 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    * Emits a ComponentRemovedEvent<C> event.
    */
   template <typename C>
-  entityx::shared_ptr<C> remove(Entity::Id id) {
-    entityx::shared_ptr<C> component = entityx::static_pointer_cast<C>(entity_components_.at(C::family()).at(id.index()));
-    entity_components_.at(C::family()).at(id.index()).reset();
-    entity_component_mask_.at(id.index()) &= ~(uint64_t(1) << C::family());
+  ptr<C> remove(const Entity::Id &id) {
+    ptr<C> component(static_pointer_cast<C>(entity_components_[C::family()][id.index()]));
+    entity_components_[C::family()][id.index()].reset();
+    entity_component_mask_[id.index()] &= ~(uint64_t(1) << C::family());
     if (component)
       event_manager_->emit<ComponentRemovedEvent<C>>(Entity(shared_from_this(), id), component);
     return component;
@@ -474,16 +490,16 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
   /**
    * Retrieve a Component assigned to an Entity::Id.
    *
-   * @returns Component instance, or empty shared_ptr<> if the Entity::Id does not have that Component.
+   * @returns Component instance, or empty ptr<> if the Entity::Id does not have that Component.
    */
   template <typename C>
-  entityx::shared_ptr<C> component(Entity::Id id) {
+  ptr<C> component(const Entity::Id &id) {
     // We don't bother checking the component mask, as we return a nullptr anyway.
     if (C::family() >= entity_components_.size()) {
-      return entityx::shared_ptr<C>();
+      return ptr<C>();
     }
-    entityx::shared_ptr<BaseComponent> c = entity_components_.at(C::family()).at(id.index());
-    return entityx::static_pointer_cast<C>(c);
+    ptr<BaseComponent> c = entity_components_[C::family()][id.index()];
+    return ptr<C>(static_pointer_cast<C>(c));
   }
 
   /**
@@ -499,7 +515,7 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    * Find Entities that have all of the specified Components.
    */
   template <typename C, typename ... Components>
-  View entities_with_components(entityx::shared_ptr<C> &c, Components && ... args) {
+  View entities_with_components(ptr<C> &c, Components && ... args) {
     auto mask = component_mask(c, args ...);
     return
         View(shared_from_this(), View::ComponentMaskPredicate(entity_component_mask_, mask))
@@ -513,12 +529,12 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    *
    * Useful for fast bulk iterations.
    *
-   * entityx::shared_ptr<Position> p;
-   * entityx::shared_ptr<Direction> d;
+   * ptr<Position> p;
+   * ptr<Direction> d;
    * unpack<Position, Direction>(e, p, d);
    */
   template <typename A>
-  void unpack(Entity::Id id, entityx::shared_ptr<A> &a) {
+  void unpack(Entity::Id id, ptr<A> &a) {
     a = component<A>(id);
   }
 
@@ -529,12 +545,12 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
    *
    * Useful for fast bulk iterations.
    *
-   * entityx::shared_ptr<Position> p;
-   * entityx::shared_ptr<Direction> d;
+   * ptr<Position> p;
+   * ptr<Direction> d;
    * unpack<Position, Direction>(e, p, d);
    */
   template <typename A, typename B, typename ... Args>
-  void unpack(Entity::Id id, entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
+  void unpack(Entity::Id id, ptr<A> &a, ptr<B> &b, Args && ... args) {
     unpack<A>(id, a);
     unpack<B, Args ...>(id, b, args ...);
   }
@@ -545,9 +561,6 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
   void destroy_all();
 
  private:
-  explicit EntityManager(entityx::shared_ptr<EventManager> event_manager) : event_manager_(event_manager) {}
-
-
   template <typename C>
   ComponentMask component_mask() {
     ComponentMask mask;
@@ -561,12 +574,12 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
   }
 
   template <typename C>
-  ComponentMask component_mask(const entityx::shared_ptr<C> &c) {
+  ComponentMask component_mask(const ptr<C> &c) {
     return component_mask<C>();
   }
 
   template <typename C1, typename C2, typename ... Components>
-  ComponentMask component_mask(const entityx::shared_ptr<C1> &c1, const entityx::shared_ptr<C2> &c2, Components && ... args) {
+  ComponentMask component_mask(const ptr<C1> &c1, const ptr<C2> &c2, Components && ... args) {
     return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
   }
 
@@ -591,9 +604,9 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
 
   uint32_t index_counter_ = 0;
 
-  entityx::shared_ptr<EventManager> event_manager_;
+  ptr<EventManager> event_manager_;
   // A nested array of: components = entity_components_[family][entity]
-  std::vector<std::vector<entityx::shared_ptr<BaseComponent>>> entity_components_;
+  std::vector<std::vector<ptr<BaseComponent>>> entity_components_;
   // Bitmask of components associated with each entity. Index into the vector is the Entity::Id.
   std::vector<ComponentMask> entity_component_mask_;
   // Vector of entity version numbers. Incremented each time an entity is destroyed
@@ -610,37 +623,37 @@ BaseComponent::Family Component<C>::family() {
 }
 
 template <typename C>
-entityx::shared_ptr<C> Entity::assign(entityx::shared_ptr<C> component) {
+ptr<C> Entity::assign(ptr<C> component) {
   assert(valid());
   return manager_.lock()->assign<C>(id_, component);
 }
 
 template <typename C, typename ... Args>
-entityx::shared_ptr<C> Entity::assign(Args && ... args) {
+ptr<C> Entity::assign(Args && ... args) {
   assert(valid());
   return manager_.lock()->assign<C>(id_, args ...);
 }
 
 template <typename C>
-entityx::shared_ptr<C> Entity::remove(){
+ptr<C> Entity::remove() {
   assert(valid() && component<C>());
   return manager_.lock()->remove<C>(id_);
 }
 
 template <typename C>
-entityx::shared_ptr<C> Entity::component() {
+ptr<C> Entity::component() {
   assert(valid());
   return manager_.lock()->component<C>(id_);
 }
 
 template <typename A>
-void Entity::unpack(entityx::shared_ptr<A> &a) {
+void Entity::unpack(ptr<A> &a) {
   assert(valid());
   manager_.lock()->unpack(id_, a);
 }
 
 template <typename A, typename B, typename ... Args>
-void Entity::unpack(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
+void Entity::unpack(ptr<A> &a, ptr<B> &b, Args && ... args) {
   assert(valid());
   manager_.lock()->unpack(id_, a, b, args ...);
 }
index e207adedaf2559487bc0ea4978fee250a2ced805..701c15b207d3c673e268259597c725c209439279 100644 (file)
@@ -66,8 +66,8 @@ class EntityManagerTest : public ::testing::Test {
  protected:
   EntityManagerTest() : ev(EventManager::make()), em(EntityManager::make(ev)) {}
 
-  entityx::shared_ptr<EventManager> ev;
-  entityx::shared_ptr<EntityManager> em;
+  ptr<EventManager> ev;
+  ptr<EntityManager> em;
 
   virtual void SetUp() {
   }
@@ -125,7 +125,6 @@ TEST_F(EntityManagerTest, TestEntityReuse) {
 TEST_F(EntityManagerTest, TestComponentConstruction) {
   auto e = em->create();
   auto p = e.assign<Position>(1, 2);
-  // auto p = em->assign<Position>(e, 1, 2);
   auto cp = e.component<Position>();
   ASSERT_EQ(p, cp);
   ASSERT_FLOAT_EQ(1.0, cp->x);
@@ -134,7 +133,7 @@ TEST_F(EntityManagerTest, TestComponentConstruction) {
 
 TEST_F(EntityManagerTest, TestComponentCreationWithObject) {
   auto e = em->create();
-  auto p = e.assign(entityx::make_shared<Position>(1.0, 2.0));
+  auto p = e.assign(ptr<Position>(new Position(1.0, 2.0)));
   auto cp = e.component<Position>();
   ASSERT_EQ(p, cp);
   ASSERT_FLOAT_EQ(1.0, cp->x);
@@ -149,7 +148,7 @@ TEST_F(EntityManagerTest, TestDestroyEntity) {
   e.assign<Direction>();
   f.assign<Direction>();
 
-  ASSERT_EQ(2, ep.use_count());
+  ASSERT_EQ(2, use_count(ep));
   ASSERT_TRUE(e.valid());
   ASSERT_TRUE(f.valid());
   ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
@@ -163,7 +162,7 @@ TEST_F(EntityManagerTest, TestDestroyEntity) {
   ASSERT_TRUE(f.valid());
   ASSERT_TRUE(static_cast<bool>(f.component<Position>()));
   ASSERT_TRUE(static_cast<bool>(f.component<Direction>()));
-  ASSERT_EQ(1, ep.use_count());
+  ASSERT_EQ(1, use_count(ep));
 }
 
 TEST_F(EntityManagerTest, TestGetEntitiesWithComponent) {
@@ -198,7 +197,7 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
   Entity e = em->create();
   Entity f = em->create();
   Entity g = em->create();
-  std::vector<std::pair<entityx::shared_ptr<Position>, entityx::shared_ptr<Direction>>> position_directions;
+  std::vector<std::pair<ptr<Position>, ptr<Direction>>> position_directions;
   position_directions.push_back(std::make_pair(
           e.assign<Position>(1.0f, 2.0f),
           e.assign<Direction>(3.0f, 4.0f)));
@@ -208,8 +207,8 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
   g.assign<Position>(5.0f, 6.0f);
   int i = 0;
 
-  entityx::shared_ptr<Position> position;
-  entityx::shared_ptr<Direction> direction;
+  ptr<Position> position;
+  ptr<Direction> direction;
   for (auto unused_entity : em->entities_with_components(position, direction)) {
     (void)unused_entity;
     ASSERT_TRUE(static_cast<bool>(position));
@@ -227,26 +226,25 @@ TEST_F(EntityManagerTest, TestUnpack) {
   auto p = e.assign<Position>();
   auto d = e.assign<Direction>();
 
-  entityx::shared_ptr<Position> up;
-  entityx::shared_ptr<Direction> ud;
+  ptr<Position> up;
+  ptr<Direction> ud;
   e.unpack<Position, Direction>(up, ud);
   ASSERT_EQ(p, up);
   ASSERT_EQ(d, ud);
 }
 
 // gcc 4.7.2 does not allow this struct to be declared locally inside the TEST_F.
-struct NullDeleter {template<typename T> void operator()(T *unused) {} };
 
-TEST_F(EntityManagerTest, TestUnpackNullMissing) {
-  Entity e = em->create();
-  auto p = e.assign<Position>();
+// TEST_F(EntityManagerTest, TestUnpackNullMissing) {
+//   Entity e = em->create();
+//   auto p = e.assign<Position>();
 
-  entityx::shared_ptr<Position> up(reinterpret_cast<Position*>(0Xdeadbeef), NullDeleter());
-  entityx::shared_ptr<Direction> ud(reinterpret_cast<Direction*>(0Xdeadbeef), NullDeleter());
-  e.unpack<Position, Direction>(up, ud);
-  ASSERT_EQ(p, up);
-  ASSERT_EQ(entityx::shared_ptr<Direction>(), ud);
-}
+//   ptr<Position> up(reinterpret_cast<Position*>(0Xdeadbeef), NullDeleter());
+//   ptr<Direction> ud(reinterpret_cast<Direction*>(0Xdeadbeef), NullDeleter());
+//   e.unpack<Position, Direction>(up, ud);
+//   ASSERT_EQ(p, up);
+//   ASSERT_EQ(ptr<Direction>(), ud);
+// }
 
 TEST_F(EntityManagerTest, TestComponentIdsDiffer) {
   ASSERT_NE(Position::family(), Direction::family());
@@ -341,7 +339,7 @@ TEST_F(EntityManagerTest, TestComponentRemovedEvent) {
       removed = event.component;
     }
 
-    entityx::shared_ptr<Direction> removed;
+    ptr<Direction> removed;
   };
 
   ComponentRemovedReceiver receiver;
index 1dba40c579adf8680d0949fcecf6b8f9407dc3b6..db73d7907fbec6d434452d1d46d7c9a4d12e65b0 100644 (file)
 
 namespace entityx {
 
-BaseEvent::Family BaseEvent::family_counter_ = 0;
+BaseEvent::Family BaseEvent::family_counter_ = 1;
 
+EventManager::EventManager() {
 }
+
+EventManager::~EventManager() {
+}
+
+void EventManager::emit(const BaseEvent &event) {
+  auto sig = signal_for(event.my_family());
+  sig->emit(&event);
+}
+
+}  // namespace entityx
index e6f8fbe4f16d2560a3709cf87d67b2d57693214c..c375aa185373404d45b41e4109e210cd681a4bb9 100644 (file)
@@ -27,19 +27,20 @@ namespace entityx {
 /// Used internally by the EventManager.
 class BaseEvent {
  public:
-  typedef entityx::shared_ptr<BaseEvent> Ptr;
   typedef uint64_t Family;
 
   virtual ~BaseEvent() {}
 
+  virtual Family my_family() const = 0;
+
  protected:
   static Family family_counter_;
 };
 
 
 typedef Simple::Signal<void (const BaseEvent*)> EventSignal;
-typedef entityx::shared_ptr<EventSignal> EventSignalPtr;
-typedef entityx::weak_ptr<EventSignal> EventSignalWeakPtr;
+typedef ptr<EventSignal> EventSignalPtr;
+typedef weak_ptr<EventSignal> EventSignalWeakPtr;
 
 
 /**
@@ -53,13 +54,13 @@ typedef entityx::weak_ptr<EventSignal> EventSignalWeakPtr;
 template <typename Derived>
 class Event : public BaseEvent {
  public:
-  typedef entityx::shared_ptr<Event<Derived>> Ptr;
-
   /// Used internally for registration.
   static Family family() {
     static Family family = family_counter_++;
     return family;
   }
+
+  virtual Family my_family() const override { return Derived::family(); }
 };
 
 
@@ -103,10 +104,13 @@ class Receiver : public BaseReceiver {
  *
  * Subscriptions are automatically removed when receivers are destroyed..
  */
-class EventManager : public entityx::enable_shared_from_this<EventManager>, boost::noncopyable {
+class EventManager : boost::noncopyable {
  public:
-  static entityx::shared_ptr<EventManager> make() {
-    return entityx::shared_ptr<EventManager>(new EventManager());
+  EventManager();
+  virtual ~EventManager();
+
+  static ptr<EventManager> make() {
+    return ptr<EventManager>(new EventManager());
   }
 
   /**
@@ -116,13 +120,13 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
    *
    * eg.
    *
-   * struct ExplosionReceiver : public Receiver<ExplosionReceiver> {
-   *   void receive(const Explosion &explosion) {
-   *   }
-   * };
+   *     struct ExplosionReceiver : public Receiver<ExplosionReceiver> {
+   *       void receive(const Explosion &explosion) {
+   *       }
+   *     };
    *
-   * ExplosionReceiver receiver;
-   * em.subscribe<Explosion>(receiver);
+   *     ExplosionReceiver receiver;
+   *     em.subscribe<Explosion>(receiver);
    */
   template <typename E, typename Receiver>
   void subscribe(Receiver &receiver) {  //NOLINT
@@ -134,6 +138,17 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
       std::make_pair(EventSignalWeakPtr(sig), connection));
   }
 
+  void emit(const BaseEvent &event);
+
+  /**
+   * Emit an already constructed event.
+   */
+  template <typename E>
+  void emit(ptr<E> event) {
+    auto sig = signal_for(E::family());
+    sig->emit(static_cast<BaseEvent*>(event.get()));
+  }
+
   /**
    * Emit an event to receivers.
    *
@@ -141,7 +156,7 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
    *
    * eg.
    *
-   * entityx::shared_ptr<EventManager> em(entityx::make_shared<EventManager>());
+   * ptr<EventManager> em = new EventManager();
    * em->emit<Explosion>(10);
    *
    */
@@ -161,12 +176,10 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
   }
 
  private:
-  EventManager() {}
-
   EventSignalPtr signal_for(int id) {
     auto it = handlers_.find(id);
     if (it == handlers_.end()) {
-      EventSignalPtr sig(entityx::make_shared<EventSignal>());
+      EventSignalPtr sig(new EventSignal());
       handlers_.insert(std::make_pair(id, sig));
       return sig;
     }
index 2e6528c64e895cff858a4c5f584120ca7e84993a..7986526d28307b419cb670869d3d2ddac8138fc8 100644 (file)
@@ -42,6 +42,17 @@ TEST(EventManagerTest, TestEmitReceive) {
 }
 
 
+TEST(EventManagerTest, TestUntypedEmitReceive) {
+  auto em = EventManager::make();
+  ExplosionSystem explosion_system;
+  em->subscribe<Explosion>(explosion_system);
+  ASSERT_EQ(0, explosion_system.damage_received);
+  Explosion explosion(10);
+  em->emit(explosion);
+  ASSERT_EQ(10, explosion_system.damage_received);
+}
+
+
 TEST(EventManagerTest, TestReceiverExpired) {
   auto em = EventManager::make();
   {
index 93de090227ca2198e9a25d4ae155f0d31f1d8abe..5151df5535c2351292e625d22a8b9c324ea89f39 100644 (file)
@@ -19,10 +19,6 @@ namespace entityx {
 
 class Manager {
  public:
-  Manager() :
-    event_manager(EventManager::make()),
-    entity_manager(EntityManager::make(event_manager)),
-    system_manager(SystemManager::make(entity_manager, event_manager)) {}
   virtual ~Manager() {}
 
   void start();
@@ -30,6 +26,11 @@ class Manager {
   void stop();
 
  protected:
+  Manager() :
+    event_manager(EventManager::make()),
+    entity_manager(EntityManager::make(event_manager)),
+    system_manager(SystemManager::make(entity_manager, event_manager)) {}
+
   /**
    * Configure the world.
    *
@@ -52,13 +53,13 @@ class Manager {
    */
   virtual void update(double dt) = 0;
 
-  entityx::shared_ptr<EventManager> event_manager;
-  entityx::shared_ptr<EntityManager> entity_manager;
-  entityx::shared_ptr<SystemManager> system_manager;
+  ptr<EventManager> event_manager;
+  ptr<EntityManager> entity_manager;
+  ptr<SystemManager> system_manager;
 
  private:
   boost::timer timer_;
   bool running_ = false;
 };
 
-}
+}  // namespace entityx
diff --git a/entityx/ReferenceCounted.h b/entityx/ReferenceCounted.h
new file mode 100644 (file)
index 0000000..e69de29
index 473fd55a9f2f5f6c2c82d31b7a90fc51ce9b0b43..e4dcfec03ea5ba93781e9cd1fae7721b765969e2 100644 (file)
 #pragma once
 
 
-#include <stdint.h>
-#include <cassert>
 #include <boost/noncopyable.hpp>
 #include <boost/unordered_map.hpp>
+#include <stdint.h>
+#include <cassert>
 #include "entityx/config.h"
 #include "entityx/Entity.h"
 #include "entityx/Event.h"
@@ -36,14 +36,14 @@ class BaseSystem : boost::noncopyable {
    *
    * Typically used to set up event handlers.
    */
-  virtual void configure(entityx::shared_ptr<EventManager> events) {}
+  virtual void configure(ptr<EventManager> events) {}
 
   /**
    * Apply System behavior.
    *
    * Called every game step.
    */
-  virtual void update(entityx::shared_ptr<EntityManager> entities, entityx::shared_ptr<EventManager> events, double dt) = 0;
+  virtual void update(ptr<EntityManager> entities, ptr<EventManager> events, double dt) = 0;
 
   static Family family_counter_;
 
@@ -55,7 +55,7 @@ class BaseSystem : boost::noncopyable {
  * Use this class when implementing Systems.
  *
  * struct MovementSystem : public System<MovementSystem> {
- *   void update(entityx::shared_ptr<EntityManager> entities, EventManager &events, double dt) {
+ *   void update(ptr<EntityManager> entities, EventManager &events, double dt) {
  *     // Do stuff to/with entities...
  *   }
  * }
@@ -72,11 +72,16 @@ class System : public BaseSystem {
 };
 
 
-class SystemManager : public entityx::enable_shared_from_this<SystemManager>, boost::noncopyable {
+class SystemManager : boost::noncopyable, public enable_shared_from_this<SystemManager> {
  public:
-  static entityx::shared_ptr<SystemManager> make(entityx::shared_ptr<EntityManager> entity_manager,
-                  entityx::shared_ptr<EventManager> event_manager) {
-    return entityx::shared_ptr<SystemManager>(new SystemManager(entity_manager, event_manager));
+  SystemManager(ptr<EntityManager> entity_manager,
+                ptr<EventManager> event_manager) :
+                entity_manager_(entity_manager),
+                event_manager_(event_manager) {}
+
+  static ptr<SystemManager> make(ptr<EntityManager> entity_manager,
+                  ptr<EventManager> event_manager) {
+    return ptr<SystemManager>(new SystemManager(entity_manager, event_manager));
   }
 
   /**
@@ -85,11 +90,11 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
    * Must be called before Systems can be used.
    *
    * eg.
-   * entityx::shared_ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
+   * ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
    * system.add(movement);
    */
   template <typename S>
-  void add(entityx::shared_ptr<S> system) {
+  void add(ptr<S> system) {
     systems_.insert(std::make_pair(S::family(), system));
   }
 
@@ -102,8 +107,8 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
    * auto movement = system.add<MovementSystem>();
    */
   template <typename S, typename ... Args>
-  entityx::shared_ptr<S> add(Args && ... args) {
-    entityx::shared_ptr<S> s = entityx::make_shared<S>(args ...);
+  ptr<S> add(Args && ... args) {
+    ptr<S> s(new S(args ...));
     add(s);
     return s;
   }
@@ -111,17 +116,17 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
   /**
    * Retrieve the registered System instance, if any.
    *
-   *   entityx::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
+   *   ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
    *
    * @return System instance or empty shared_ptr<S>.
    */
   template <typename S>
-  entityx::shared_ptr<S> system() {
+  ptr<S> system() {
     auto it = systems_.find(S::family());
     assert(it != systems_.end());
     return it == systems_.end()
-        ? entityx::shared_ptr<S>()
-        : entityx::static_pointer_cast<S>(it->second);
+        ? ptr<S>()
+        : ptr<S>(static_pointer_cast<S>(it->second));
   }
 
   /**
@@ -130,7 +135,7 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
   template <typename S>
   void update(double dt) {
     assert(initialized_ && "SystemManager::configure() not called");
-    entityx::shared_ptr<S> s = system<S>();
+    ptr<S> s = system<S>();
     s->update(entity_manager_, event_manager_, dt);
   }
 
@@ -142,15 +147,10 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
   void configure();
 
  private:
-  SystemManager(entityx::shared_ptr<EntityManager> entity_manager,
-                entityx::shared_ptr<EventManager> event_manager) :
-                entity_manager_(entity_manager),
-                event_manager_(event_manager) {}
-
   bool initialized_ = false;
-  entityx::shared_ptr<EntityManager> entity_manager_;
-  entityx::shared_ptr<EventManager> event_manager_;
-  boost::unordered_map<BaseSystem::Family, entityx::shared_ptr<BaseSystem>> systems_;
+  ptr<EntityManager> entity_manager_;
+  ptr<EventManager> event_manager_;
+  boost::unordered_map<BaseSystem::Family, ptr<BaseSystem>> systems_;
 };
 
-}
+}  // namespace entityx
index a68a0329e8c06ffaac21c23a9a3b66c5f8edac33..0d82df5b8b7500682d3cffd231215b65b9b3387a 100644 (file)
@@ -35,12 +35,12 @@ struct Direction : Component<Direction> {
 
 class MovementSystem : public System<MovementSystem> {
  public:
-  MovementSystem(string label = "") : label(label) {}
+  explicit MovementSystem(string label = "") : label(label) {}
 
-  void update(entityx::shared_ptr<EntityManager> es, entityx::shared_ptr<EventManager> events, double) override {
+  void update(ptr<EntityManager> es, ptr<EventManager> events, double) override {
     EntityManager::View entities = es->entities_with_components<Position, Direction>();
-    entityx::shared_ptr<Position> position;
-    entityx::shared_ptr<Direction> direction;
+    ptr<Position> position;
+    ptr<Direction> direction;
     for (auto entity : entities) {
       entity.unpack<Position, Direction>(position, direction);
       position->x += direction->x;
@@ -56,8 +56,8 @@ class TestManager : public entityx::Manager {
  public:
   std::vector<Entity> entities;
 
-  entityx::shared_ptr<SystemManager> sm() { return system_manager; }
-  entityx::shared_ptr<EntityManager> em() { return entity_manager; }
+  ptr<SystemManager> sm() { return system_manager; }
+  ptr<EntityManager> em() { return entity_manager; }
 
  protected:
   void configure() override {
@@ -102,8 +102,8 @@ TEST_F(SystemManagerTest, TestApplySystem) {
   manager.sm()->configure();
 
   manager.sm()->update<MovementSystem>(0.0);
-  entityx::shared_ptr<Position> position;
-  entityx::shared_ptr<Direction> direction;
+  ptr<Position> position;
+  ptr<Direction> direction;
   for (auto entity : manager.entities) {
     entity.unpack<Position, Direction>(position, direction);
     if (position && direction) {
index 9722cf46647f77afb360c313133c2c5e59e4bc05..de43e8339e1694a05cf3a8633eba3fd750f35c9c 100644 (file)
@@ -9,6 +9,14 @@
 #cmakedefine ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION "@ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION@"
 
 #include <stdint.h>
+#include "entityx/config.h"
+
+namespace entityx {
+
+static const uint64_t MAX_COMPONENTS = ENTITYX_MAX_COMPONENTS;
+
+}  // namespace entityx
+
 
 // Which shared_ptr implementation should we use?
 #if (ENTITYX_HAVE_STD_SHARED_PTR && ENTITYX_USE_STD_SHARED_PTR)
 #include <memory>
 
 namespace entityx {
-using std::make_shared;
-using std::shared_ptr;
-using std::static_pointer_cast;
-using std::weak_ptr;
-using std::enable_shared_from_this;
+
+template <typename T>
+using ptr = std::shared_ptr<T>;
+template <typename T>
+using weak_ptr = std::weak_ptr<T>;
+template <typename T, typename U>
+ptr<U> static_pointer_cast(const ptr<T> &ptr) {
+  return std::static_pointer_cast<U>(ptr);
 }
+template <typename T>
+using enable_shared_from_this = std::enable_shared_from_this<T>;
+
+}  // namespace entityx
 
 #elif ENTITYX_HAVE_BOOST_SHARED_PTR
 
-#include <boost/enable_shared_from_this.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/weak_ptr.hpp>
-#include <boost/make_shared.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
 
 namespace entityx {
-using boost::shared_ptr;
-using boost::make_shared;
-using boost::static_pointer_cast;
-using boost::weak_ptr;
-using boost::enable_shared_from_this;
+
+template <typename T>
+using ptr = boost::shared_ptr<T>;
+template <typename T>
+using weak_ptr = boost::weak_ptr<T>;
+template <typename T, typename U>
+ptr<U> static_pointer_cast(const ptr<T> &ptr) {
+  return boost::static_pointer_cast<U>(ptr);
 }
+template <typename T>
+using enable_shared_from_this = boost::enable_shared_from_this<T>;
+
+}  // namespace entityx
+
+#else
+
+#warning "Don't have a boost or std shared_ptr implementation to use"
 
 #endif
 
+
 namespace entityx {
-static const uint64_t MAX_COMPONENTS = ENTITYX_MAX_COMPONENTS;
+
+template <typename T>
+bool operator == (const weak_ptr<T> &a, const weak_ptr<T> &b) {
+  return a.lock() == b.lock();
 }
+
+template <typename T>
+int use_count(const ptr<T> &ptr) {
+  return ptr.use_count();
+}
+
+}  // namespace entityx
index 0abdde6f5e4d066576d2a3e124c13e7b8d5e4409..bb59e7d949ef188d659828d15c7fe5196b015a56 100644 (file)
@@ -16,8 +16,6 @@
 #include <sstream>
 #include "entityx/python/PythonSystem.h"
 
-using namespace std;
-using namespace boost;
 namespace py = boost::python;
 
 namespace entityx {
@@ -41,31 +39,56 @@ class PythonEntityXLogger {
 public:
   PythonEntityXLogger() {}
   explicit PythonEntityXLogger(PythonSystem::LoggerFunction logger) : logger_(logger) {}
+  ~PythonEntityXLogger() { flush(true); }
 
   void write(const std::string &text) {
-    logger_(text);
+    line_ += text;
+    flush();
   }
+
 private:
+  void flush(bool force = false) {
+    size_t offset;
+    while ((offset = line_.find('\n')) != std::string::npos) {
+      std::string text = line_.substr(0, offset);
+      logger_(text);
+      line_ = line_.substr(offset + 1);
+    }
+    if (force && line_.size()) {
+      logger_(line_);
+      line_ = "";
+    }
+  }
+
   PythonSystem::LoggerFunction logger_;
+  std::string line_;
 };
 
 
 struct PythonEntity {
-  explicit PythonEntity(Entity entity) : _entity(entity) {}
+  PythonEntity(Entity entity) : _entity(entity) {}  // NOLINT
 
   void destroy() {
     _entity.destroy();
   }
 
-  void update(float dt) {}
+  operator Entity () const { return _entity; }
+
+  void update(float dt, int frame) {}
 
   Entity _entity;
 };
 
+static std::string python_entity_repr(const PythonEntity &entity) {
+  std::stringstream repr;
+  repr << "<Entity " << entity._entity.id().index() << "." << entity._entity.id().version() << ">";
+  return repr.str();
+}
+
 
 static std::string entity_repr(Entity entity) {
-  stringstream repr;
-  repr << "<Entity::Id " << entity.id() << ">";
+  std::stringstream repr;
+  repr << "<Entity::Id " << entity.id().index() << "." << entity.id().version() << ">";
   return repr.str();
 }
 
@@ -80,39 +103,49 @@ BOOST_PYTHON_MODULE(_entityx) {
   py::class_<PythonEntityXLogger>("Logger", py::no_init)
     .def("write", &PythonEntityXLogger::write);
 
+  py::class_<BaseEvent, ptr<BaseEvent>, boost::noncopyable>("BaseEvent", py::no_init);
+
   py::class_<PythonEntity>("Entity", py::init<Entity>())
     .def_readonly("_entity", &PythonEntity::_entity)
     .def("update", &PythonEntity::update)
-    .def("destroy", &PythonEntity::destroy);
+    .def("destroy", &PythonEntity::destroy)
+    .def("__repr__", &python_entity_repr);
 
   py::class_<Entity>("RawEntity", py::no_init)
     .add_property("id", &Entity::id)
     .def("__eq__", &entity_eq)
     .def("__repr__", &entity_repr);
 
-  py::class_<PythonComponent, entityx::shared_ptr<PythonComponent>>("PythonComponent", py::init<py::object>())
+  py::class_<PythonComponent, ptr<PythonComponent>>("PythonComponent", py::init<py::object>())
     .def("assign_to", &assign_to<PythonComponent>)
     .def("get_component", &get_component<PythonComponent>)
     .staticmethod("get_component");
 
-  py::class_<EntityManager, entityx::shared_ptr<EntityManager>, boost::noncopyable>("EntityManager", py::no_init)
+  py::class_<EntityManager, ptr<EntityManager>, boost::noncopyable>("EntityManager", py::no_init)
     .def("create", &EntityManager::create);
+
+  void (EventManager::*emit)(const BaseEvent &) = &EventManager::emit;
+
+  py::class_<EventManager, ptr<EventManager>, boost::noncopyable>("EventManager", py::no_init)
+    .def("emit", emit);
+
+  py::implicitly_convertible<PythonEntity, Entity>();
 }
 
 
 static void log_to_stderr(const std::string &text) {
-  cerr << "python stderr: " << text << endl;
+  std::cerr << "python stderr: " << text << std::endl;
 }
 
 static void log_to_stdout(const std::string &text) {
-  cout << "python stdout: " << text << endl;
+  std::cout << "python stdout: " << text << std::endl;
 }
 
 // PythonSystem below here
 
 bool PythonSystem::initialized_ = false;
 
-PythonSystem::PythonSystem(entityx::shared_ptr<EntityManager> entity_manager)
+PythonSystem::PythonSystem(ptr<EntityManager> entity_manager)
     : entity_manager_(entity_manager), stdout_(log_to_stdout), stderr_(log_to_stderr) {
   if (!initialized_) {
     initialize_python_module();
@@ -125,6 +158,20 @@ PythonSystem::PythonSystem(entityx::shared_ptr<EntityManager> entity_manager)
 }
 
 PythonSystem::~PythonSystem() {
+  try {
+    py::object entityx = py::import("_entityx");
+    entityx.attr("_entity_manager").del();
+    entityx.attr("_event_manager").del();
+    py::object sys = py::import("sys");
+    sys.attr("stdout").del();
+    sys.attr("stderr").del();
+    py::object gc = py::import("gc");
+    gc.attr("collect")();
+  } catch(...) {
+    PyErr_Print();
+    PyErr_Clear();
+    throw;
+  }
   // FIXME: It would be good to do this, but it is not supported by boost::python:
   // http://www.boost.org/doc/libs/1_53_0/libs/python/todo.html#pyfinalize-safety
   // Py_Finalize();
@@ -142,7 +189,7 @@ void PythonSystem::initialize_python_module() {
   assert(PyImport_AppendInittab("_entityx", init_entityx) != -1 && "Failed to initialize _entityx Python module");
 }
 
-void PythonSystem::configure(entityx::shared_ptr<EventManager> event_manager) {
+void PythonSystem::configure(ptr<EventManager> event_manager) {
   event_manager->subscribe<EntityDestroyedEvent>(*this);
   event_manager->subscribe<ComponentAddedEvent<PythonComponent>>(*this);
 
@@ -162,8 +209,8 @@ void PythonSystem::configure(entityx::shared_ptr<EventManager> event_manager) {
     }
 
     py::object entityx = py::import("_entityx");
-    entityx.attr("_entity_manager") = entity_manager_;
-    // entityx.attr("event_manager") = boost::ref(event_manager);
+    entityx.attr("_entity_manager") = entity_manager_.lock();
+    entityx.attr("_event_manager") = event_manager;
   } catch(...) {
     PyErr_Print();
     PyErr_Clear();
@@ -171,18 +218,19 @@ void PythonSystem::configure(entityx::shared_ptr<EventManager> event_manager) {
   }
 }
 
-void PythonSystem::update(entityx::shared_ptr<EntityManager> entity_manager, entityx::shared_ptr<EventManager> event_manager, double dt) {
+void PythonSystem::update(ptr<EntityManager> entity_manager, ptr<EventManager> event_manager, double dt) {
   for (auto entity : entity_manager->entities_with_components<PythonComponent>()) {
-    shared_ptr<PythonComponent> python = entity.component<PythonComponent>();
+    ptr<PythonComponent> python = entity.component<PythonComponent>();
 
     try {
-      python->object.attr("update")(dt);
+      python->object.attr("update")(dt, frame_);
     } catch(...) {
       PyErr_Print();
       PyErr_Clear();
       throw;
     }
   }
+  frame_++;
 }
 
 void PythonSystem::log_to(LoggerFunction stdout, LoggerFunction stderr) {
index b64e46c9c3c60a1730db45afaff957a1b3375c24..3009c6c2c8f25f737e48fd6aeeed44e69ffc57f5 100644 (file)
 
 // http://docs.python.org/2/extending/extending.html
 #include <Python.h>
-
+#include <boost/python.hpp>
+#include <boost/function.hpp>
+#include <list>
+#include <vector>
+#include <string>
+#include "entityx/System.h"
+#include "entityx/Entity.h"
+#include "entityx/Event.h"
 #include "entityx/config.h"
 
 // boost::python smart pointer adapter for std::shared_ptr<T>
-#if (ENTITYX_HAVE_STD_SHARED_PTR && ENTITYX_USE_STD_SHARED_PTR)
+#ifdef ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION
 
-#include <boost/python.hpp>
 #include <memory>
 
-#ifdef ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION
 
 namespace std {
 
@@ -30,46 +35,25 @@ template <class T> inline T * get_pointer(const std::shared_ptr<T> &p) {
   return p.get();
 }
 
-}
+}  // namespace std
 
-#endif
-
-namespace boost {
-namespace python {
-
-template <typename T> struct pointee<std::shared_ptr<T> > {
-  typedef T type;
-};
-
-}
-}
 
 #endif
 
-#include <list>
-#include <vector>
-#include <string>
-#include <boost/python.hpp>
-#include <boost/function.hpp>
-#include "entityx/System.h"
-#include "entityx/Entity.h"
-#include "entityx/Event.h"
-
 
 namespace entityx {
 namespace python {
 
-
 /**
  * An EntityX component that represents a Python script.
  */
 class PythonComponent : public entityx::Component<PythonComponent> {
 public:
   /**
-   * Create a new PythonComponent from a Python class.
+   * Create a new PythonComponent from a Python Entity class.
    *
    * @param module The Python module where the Entity subclass resides.
-   * @param cls The Class within the module.
+   * @param cls The Class within the module. Must inherit from entityx.Entity.
    * @param args The *args to pass to the Python constructor.
    */
   template <typename ...Args>
@@ -160,7 +144,7 @@ private:
  * A helper function for class_ to assign a component to an entity.
  */
 template <typename Component>
-void assign_to(entityx::shared_ptr<Component> component, Entity &entity) {  // NOLINT
+void assign_to(ptr<Component> component, Entity &entity) {  // NOLINT
   entity.assign<Component>(component);
 }
 
@@ -170,7 +154,7 @@ void assign_to(entityx::shared_ptr<Component> component, Entity &entity) {  // N
  * entity.
  */
 template <typename Component>
-entityx::shared_ptr<Component> get_component(Entity &entity) {  // NOLINT
+ptr<Component> get_component(Entity &entity) {  // NOLINT
   return entity.component<Component>();
 }
 
@@ -206,7 +190,7 @@ class PythonSystem : public entityx::System<PythonSystem>, public entityx::Recei
 public:
   typedef boost::function<void (const std::string &)> LoggerFunction;
 
-  PythonSystem(entityx::shared_ptr<EntityManager> entity_manager);  // NOLINT
+  PythonSystem(ptr<EntityManager> entity_manager);  // NOLINT
   virtual ~PythonSystem();
 
   /**
@@ -234,11 +218,11 @@ public:
     return python_paths_;
   }
 
-  virtual void configure(entityx::shared_ptr<EventManager> event_manager) override;
-  virtual void update(entityx::shared_ptr<EntityManager> entities, entityx::shared_ptr<EventManager> event_manager, double dt) override;
+  virtual void configure(ptr<EventManager> event_manager) override;
+  virtual void update(ptr<EntityManager> entities, ptr<EventManager> event_manager, double dt) override;
 
   /**
-   * Set functions that writes to sys.stdout/sys.stderr will be passed to.
+   * Set line-based (not including \n) logger for stdout and stderr.
    */
   void log_to(LoggerFunction stdout, LoggerFunction stderr);
 
@@ -246,32 +230,34 @@ public:
    * Proxy events of type Event to any Python entity with a handler_name method.
    */
   template <typename Event>
-  void add_event_proxy(entityx::shared_ptr<EventManager> event_manager, const std::string &handler_name) {
-    auto proxy = entityx::make_shared<BroadcastPythonEventProxy<Event>>(handler_name);
-    event_manager->subscribe<Event>(*proxy);
-    event_proxies_.push_back(entityx::static_pointer_cast<PythonEventProxy>(proxy));
+  void add_event_proxy(ptr<EventManager> event_manager, const std::string &handler_name) {
+    ptr<BroadcastPythonEventProxy<Event>> proxy(new BroadcastPythonEventProxy<Event>(handler_name));
+    event_manager->subscribe<Event>(*proxy.get());
+    event_proxies_.push_back(static_pointer_cast<PythonEventProxy>(proxy));
   }
 
   /**
    * Proxy events of type Event using the given PythonEventProxy implementation.
    */
   template <typename Event, typename Proxy>
-  void add_event_proxy(entityx::shared_ptr<EventManager> event_manager, entityx::shared_ptr<Proxy> proxy) {
+  void add_event_proxy(ptr<EventManager> event_manager, ptr<Proxy> proxy) {
     event_manager->subscribe<Event>(*proxy);
-    event_proxies_.push_back(entityx::static_pointer_cast<PythonEventProxy>(proxy));
+    event_proxies_.push_back(static_pointer_cast<PythonEventProxy>(proxy));
   }
 
   void receive(const EntityDestroyedEvent &event);
   void receive(const ComponentAddedEvent<PythonComponent> &event);
+
 private:
   void initialize_python_module();
 
-  entityx::shared_ptr<EntityManager> entity_manager_;
+  weak_ptr<EntityManager> entity_manager_;
   std::vector<std::string> python_paths_;
   LoggerFunction stdout_, stderr_;
   static bool initialized_;
-  std::vector<entityx::shared_ptr<PythonEventProxy>> event_proxies_;
+  std::vector<ptr<PythonEventProxy>> event_proxies_;
+  int frame_ = 0;
 };
 
-}
-}
+}  // namespace python
+}  // namespace entityx
index f516830ce3178a5b97f299cecbb833f2c9217043..1d0c8fda7df4ca7fad5f3691fe7d21f1e6eb458c 100644 (file)
@@ -19,8 +19,6 @@
 #include "entityx/Event.h"
 #include "entityx/python/PythonSystem.h"
 
-using namespace std;
-using namespace boost;
 namespace py = boost::python;
 using namespace entityx;
 using namespace entityx::python;
@@ -62,19 +60,21 @@ struct CollisionEventProxy : public PythonEventProxy, public Receiver<CollisionE
 
 
 BOOST_PYTHON_MODULE(entityx_python_test) {
-  py::class_<Position, entityx::shared_ptr<Position>>("Position", py::init<py::optional<float, float>>())
+  py::class_<Position, ptr<Position>>("Position", py::init<py::optional<float, float>>())
     .def("assign_to", &assign_to<Position>)
     .def("get_component", &get_component<Position>)
     .staticmethod("get_component")
     .def_readwrite("x", &Position::x)
     .def_readwrite("y", &Position::y);
-  py::class_<Direction, entityx::shared_ptr<Direction>>("Direction", py::init<py::optional<float, float>>())
+
+  py::class_<Direction, ptr<Direction>>("Direction", py::init<py::optional<float, float>>())
     .def("assign_to", &assign_to<Direction>)
     .def("get_component", &get_component<Direction>)
     .staticmethod("get_component")
     .def_readwrite("x", &Direction::x)
     .def_readwrite("y", &Direction::y);
-  py::class_<CollisionEvent>("Collision", py::init<Entity, Entity>())
+
+  py::class_<CollisionEvent, ptr<CollisionEvent>, py::bases<BaseEvent>>("Collision", py::init<Entity, Entity>())
     .def_readonly("a", &CollisionEvent::a)
     .def_readonly("b", &CollisionEvent::b);
 }
@@ -87,29 +87,30 @@ protected:
   }
 
   void SetUp() {
-    ev = EventManager::make();
-    em = EntityManager::make(ev);
-    vector<string> paths;
-    paths.push_back(ENTITYX_PYTHON_TEST_DATA);
-    system = entityx::make_shared<PythonSystem>(em);
-    system->add_paths(paths);
+    ev.reset(new EventManager());
+    em.reset(new EntityManager(ev));
+    system.reset(new PythonSystem(em));
+    system->add_path(ENTITYX_PYTHON_TEST_DATA);
     if (!initialized) {
       initentityx_python_test();
       initialized = true;
     }
-    system->add_event_proxy<CollisionEvent>(ev, entityx::make_shared<CollisionEventProxy>());
+    system->add_event_proxy<CollisionEvent, CollisionEventProxy>(ev, ptr<CollisionEventProxy>(new CollisionEventProxy()));
     system->configure(ev);
   }
 
   void TearDown() {
+    weak_ptr<EventManager> v = ev;
+    weak_ptr<EntityManager> e = em;
+    em->destroy_all();
     system.reset();
     em.reset();
     ev.reset();
   }
 
-  entityx::shared_ptr<PythonSystem> system;
-  entityx::shared_ptr<EventManager> ev;
-  entityx::shared_ptr<EntityManager> em;
+  ptr<PythonSystem> system;
+  ptr<EventManager> ev;
+  ptr<EntityManager> em;
   static bool initialized;
 };
 
@@ -123,7 +124,7 @@ TEST_F(PythonSystemTest, TestSystemUpdateCallsEntityUpdate) {
     ASSERT_FALSE(py::extract<bool>(script->object.attr("updated")));
     system->update(em, ev, 0.1);
     ASSERT_TRUE(py::extract<bool>(script->object.attr("updated")));
-  } catch (...) {
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
@@ -135,15 +136,15 @@ TEST_F(PythonSystemTest, TestComponentAssignmentCreationInPython) {
   try {
     Entity e = em->create();
     auto script = e.assign<PythonComponent>("entityx.tests.assign_test", "AssignTest");
-    ASSERT_TRUE(bool(e.component<Position>()));
+    ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
     ASSERT_TRUE(script->object);
     ASSERT_TRUE(script->object.attr("test_assign_create"));
     script->object.attr("test_assign_create")();
     auto position = e.component<Position>();
-    ASSERT_TRUE(bool(position));
+    ASSERT_TRUE(static_cast<bool>(position));
     ASSERT_EQ(position->x, 1.0);
     ASSERT_EQ(position->y, 2.0);
-  } catch (...) {
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
@@ -156,15 +157,15 @@ TEST_F(PythonSystemTest, TestComponentAssignmentCreationInCpp) {
     Entity e = em->create();
     e.assign<Position>(2, 3);
     auto script = e.assign<PythonComponent>("entityx.tests.assign_test", "AssignTest");
-    ASSERT_TRUE(bool(e.component<Position>()));
+    ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
     ASSERT_TRUE(script->object);
     ASSERT_TRUE(script->object.attr("test_assign_existing"));
     script->object.attr("test_assign_existing")();
     auto position = e.component<Position>();
-    ASSERT_TRUE(bool(position));
+    ASSERT_TRUE(static_cast<bool>(position));
     ASSERT_EQ(position->x, 3.0);
     ASSERT_EQ(position->y, 4.0);
-  } catch (...) {
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
@@ -177,10 +178,10 @@ TEST_F(PythonSystemTest, TestEntityConstructorArgs) {
     Entity e = em->create();
     auto script = e.assign<PythonComponent>("entityx.tests.constructor_test", "ConstructorTest", 4.0, 5.0);
     auto position = e.component<Position>();
-    ASSERT_TRUE(bool(position));
+    ASSERT_TRUE(static_cast<bool>(position));
     ASSERT_EQ(position->x, 4.0);
     ASSERT_EQ(position->y, 5.0);
-  } catch (...) {
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
@@ -203,7 +204,7 @@ TEST_F(PythonSystemTest, TestEventDelivery) {
     ev->emit<CollisionEvent>(e, f);
     ASSERT_TRUE(scriptf->object.attr("collided"));
     ASSERT_TRUE(scripte->object.attr("collided"));
-  } catch (...) {
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
@@ -222,7 +223,7 @@ TEST_F(PythonSystemTest, TestDeepEntitySubclass) {
     auto script2 = e2.assign<PythonComponent>("entityx.tests.deep_subclass_test", "DeepSubclassTest2");
     ASSERT_TRUE(script2->object.attr("test_deeper_subclass"));
     script2->object.attr("test_deeper_subclass")();
-  } catch (...) {
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
@@ -234,7 +235,37 @@ TEST_F(PythonSystemTest, TestEntityCreationFromPython) {
   try {
     py::object test = py::import("entityx.tests.create_entities_from_python_test");
     test.attr("create_entities_from_python_test")();
-  } catch (...) {
+  } catch(...) {
+    PyErr_Print();
+    PyErr_Clear();
+    ASSERT_FALSE(true) << "Python exception.";
+  }
+}
+
+
+TEST_F(PythonSystemTest, TestEventEmissionFromPython) {
+  try {
+    struct CollisionReceiver : public Receiver<CollisionReceiver> {
+      void receive(const CollisionEvent &event) {
+        a = event.a;
+        b = event.b;
+      }
+
+      Entity a, b;
+    };
+
+    CollisionReceiver receiver;
+    ev->subscribe<CollisionEvent>(receiver);
+
+    ASSERT_FALSE(receiver.a);
+    ASSERT_FALSE(receiver.b);
+
+    py::object test = py::import("entityx.tests.event_emit_test");
+    test.attr("emit_collision_from_python")();
+
+    ASSERT_TRUE(receiver.a);
+    ASSERT_TRUE(receiver.b);
+  } catch(...) {
     PyErr_Print();
     PyErr_Clear();
     ASSERT_FALSE(true) << "Python exception.";
index 9b069037a84c8400c0dd4984c0b35a8ae89f13bc..e206a053e89f4858dda6c23952061325994c44c0 100644 (file)
@@ -28,6 +28,7 @@ To add scripting support to your system, something like the following steps shou
 5. Create a `PythonSystem`, passing in the list of paths to add to Python's import search path.
 6. Optionally attach any event proxies.
 7. Create an entity and associate it with a Python script by assigning `PythonComponent`, passing it the package name, class name, and any constructor arguments.
+8. When finished, call `EntityManager::destroy_all()`.
 
 ## Interfacing with Python
 
@@ -49,7 +50,7 @@ struct Position : public Component<Position> {
 };
 
 void export_position_to_python() {
-  py::class_<PythonPosition, entityx::shared_ptr<PythonPosition>>("Position", py::init<py::optional<float, float>>())
+  py::class_<PythonPosition, entityx::ptr<PythonPosition>>("Position", py::init<py::optional<float, float>>())
     .def("assign_to", &entityx::python::assign_to<Position>)
     .def("get_component", &entityx::python::get_component<Position>)
     .staticmethod("get_component")
@@ -137,9 +138,8 @@ Then create and destroy `PythonSystem` as necessary:
 vector<string> paths;
 paths.push_back(MYGAME_PYTHON_PATH);
 // +any other Python paths...
-auto script_system = make_shared<PythonSystem>(paths);
+entityx::ptr<PythonSystem> script_system = new PythonSystem(paths);
 
 // Add any Event proxies.
-script_system->add_event_proxy<CollisionEvent>(
-    ev, entityx::make_shared<CollisionEventProxy>());
+script_system->add_event_proxy<CollisionEvent>(ev, new CollisionEventProxy());
 ```
index cdac6a60b393025213d3d02a8cae73b085798b04..8f5057bd637e71687d0b0f05f2290ce8b41e8d29 100644 (file)
@@ -11,7 +11,7 @@ They allow you to declare your entities and components in an intuitive way:
         direction = Component(Direction)
         sprite = Component(Sprite, 'player.png')  # Sprite component with constructor argument
 
-        def update(self, dt):
+        def update(self, dt, frame):
             self.position.x += self.direction.x * dt
             self.position.x += self.direction.y * dt
 
@@ -100,3 +100,11 @@ class Entity(_entityx.Entity):
         self = Entity.__new__(cls, raw_entity=raw_entity)
         cls.__init__(self, *args, **kwargs)
         return self
+
+
+def emit(event):
+    """Emit an event.
+
+    :param event: A Python-exposed C++ subclass of entityx::BaseEvent.
+    """
+    return _entityx._event_manager.emit(event)
diff --git a/entityx/python/entityx/tests/event_emit_test.py b/entityx/python/entityx/tests/event_emit_test.py
new file mode 100644 (file)
index 0000000..9a726ba
--- /dev/null
@@ -0,0 +1,14 @@
+from entityx import Entity, emit
+from entityx_python_test import Collision
+
+
+class AnEntity(Entity):
+    pass
+
+
+def emit_collision_from_python():
+    a = AnEntity()
+    b = AnEntity()
+    collision = Collision(a, b)
+    print a, b, collision
+    emit(Collision(a, b))
index 3c05d6a4e2903dbb810ab14290b619f6e3559a7f..7585aa6ebfb3397f75509d874e5ddcc10b85b5ce 100644 (file)
@@ -4,5 +4,5 @@ import entityx
 class UpdateTest(entityx.Entity):
     updated = False
 
-    def update(self, dt):
+    def update(self, dt, frame):
         self.updated = True
index 6598f6184e307116102dbc15ee066cd46b4bb0e8..b208c63dc00accd9270343865ec4e3f70ec87cb5 100644 (file)
@@ -10,8 +10,8 @@
 
 #pragma once
 
-#include <string>
 #include <boost/unordered_set.hpp>
+#include <string>
 #include "entityx/Entity.h"
 
 namespace entityx {
@@ -22,11 +22,11 @@ namespace tags {
  */
 class TagsComponent : public Component<TagsComponent> {
   struct TagsPredicate {
-    TagsPredicate(const std::string &tag) : tag(tag) {}
+    explicit TagsPredicate(const std::string &tag) : tag(tag) {}
 
-    bool operator () (entityx::shared_ptr<EntityManager> manager, Entity::Id id) {
+    bool operator() (ptr<EntityManager> manager, Entity::Id id) {
       auto tags = manager->component<TagsComponent>(id);
-      return tags != nullptr && tags->tags.find(tag) != tags->tags.end();
+      return tags && tags->tags.find(tag) != tags->tags.end();
     }
 
     std::string tag;
@@ -64,5 +64,5 @@ class TagsComponent : public Component<TagsComponent> {
   }
 };
 
-}
-}
+}  // namespace tags
+}  // namespace entityx