/* * Copyright (C) 2017-2019 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #ifndef ENTITY_GROUP_HPP #define ENTITY_GROUP_HPP #include "component-observer.hpp" #include "component-manager.hpp" #include "entity-group-member.hpp" #include "entity-group-observer.hpp" #include #include #include #include #include enum class ComponentType; /// A set of component types used to filter entities typedef std::set ComponentFilter; /** * Abstract base class for entity groups. */ class EntityGroupBase: protected ComponentObserver { public: /** * Creates a entity group base. * * @param componentManager The component manager with which to associate this entity group. * @param componentFilter Set of component types which an entity must possess in order to join this entity group. */ EntityGroupBase(ComponentManager* componentManager, const ComponentFilter& componentFilter); /// Returns the set of components which an entity must possess in order to join this entity group. const ComponentFilter& getComponentFilter() const; /** * Returns true if the specified entity is registered with this entity group. * * @param entity ID of the entity to check. */ virtual bool isRegistered(EntityID entity) const = 0; private: virtual void componentAdded(EntityID entity, ComponentBase* component); virtual void componentRemoved(EntityID entity, ComponentBase* component); /** * Called each time an entity joins the entity group by obtaining the necessary component types. * * @param entity Entity ID of the new member. */ virtual void registerMember(EntityID entity) = 0; /** * Called each time an entity leaves an the entity group by no longer possessing the necessary component types. * * @param entity Entity ID of the former member. */ virtual void unregisterMember(EntityID entity) = 0; ComponentFilter componentFilter; }; inline const ComponentFilter& EntityGroupBase::getComponentFilter() const { return componentFilter; } /** * A group of entities which share a set of specified component types. * * @tparam T Set of components which are required for group membership. */ template class EntityGroup: public EntityGroupBase { public: typedef EntityGroupMember Member; typedef EntityGroupObserver Observer; /** * Creates a entity group. * * @param componentManager Component manager with which to associate this entity group. */ EntityGroup(ComponentManager* componentManager); /// Destroys a entity group. ~EntityGroup(); /** * Adds a group observer. * * @param observer Observer to add. */ void addGroupObserver(Observer* observer); /** * Removes a group observer. * * @param observer Observer to remove. */ void removeGroupObserver(Observer* observer); /// Removes all group observers. void removeGroupObservers(); /// @copydoc EntityGroupBase::isRegistered(EntityID) const virtual bool isRegistered(EntityID entity) const; /** * Returns the member list. * * @return List of members. */ const std::list* getMembers() const; /** * Returns the member with the specified ID. * * @param entity Entity ID of a group member. * @return Member with the specified ID, or nullptr if an entity with that ID is not registered. */ const Member* getMemberByEntity(EntityID entity) const; private: template typename std::enable_if<(sizeof...(V) == 0), void>::type attachComponents(Member* member) { std::get(member->components) = static_cast(componentManager->getComponent(member->entity, U::TYPE)); } template typename std::enable_if<(sizeof...(V) > 0), void>::type attachComponents(Member* member) { std::get(member->components) = static_cast(componentManager->getComponent(member->entity, U::TYPE)); attachComponents(member); } virtual void registerMember(EntityID entity); virtual void unregisterMember(EntityID entity); std::list members; std::map memberMap; std::list observers; }; template EntityGroup::EntityGroup(ComponentManager* componentManager): EntityGroupBase(componentManager, ComponentFilter({(T::TYPE)...})) {} template EntityGroup::~EntityGroup() { while (!members.empty()) { Member* member = members.back(); members.pop_back(); memberMap.erase(memberMap.find(member->entity)); for (Observer* observer: observers) { observer->memberUnregistered(member); } delete member; } } template void EntityGroup::addGroupObserver(Observer* observer) { observers.push_back(observer); } template void EntityGroup::removeGroupObserver(Observer* observer) { observers.remove(observer); } template void EntityGroup::removeGroupObservers() { observers.clear(); } template inline bool EntityGroup::isRegistered(EntityID entity) const { return (memberMap.find(entity) != memberMap.end()); } template inline const std::list::Member*>* EntityGroup::getMembers() const { return &members; } template inline const typename EntityGroup::Member* EntityGroup::getMemberByEntity(EntityID entity) const { auto it = memberMap.find(entity); if (it != memberMap.end()) { return it->second; } return nullptr; } template void EntityGroup::registerMember(EntityID entity) { Member* member = new Member(); member->entity = entity; attachComponents<0, T...>(member); members.push_back(member); memberMap[entity] = member; for (Observer* observer: observers) { observer->memberRegistered(member); } } template void EntityGroup::unregisterMember(EntityID entity) { auto it = memberMap.find(entity); Member* member = it->second; memberMap.erase(it); members.remove(member); for (Observer* observer: observers) { observer->memberUnregistered(member); } delete member; } #endif // ENTITY_GROUP_HPP