From 1105edb8c21f8c7075eab6867248ccd59c220fab Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Thu, 8 Sep 2022 11:08:23 +0800 Subject: [PATCH 1/2] initial commit --- .../ECS_Base/Components/SHComponent.cpp | 9 + .../Engine/ECS_Base/Components/SHComponent.h | 120 +++++ .../ECS_Base/Components/SHComponentGroup.cpp | 136 +++++ .../ECS_Base/Components/SHComponentGroup.h | 185 +++++++ .../src/Engine/ECS_Base/Entity/SHEntity.cpp | 72 +++ .../src/Engine/ECS_Base/Entity/SHEntity.h | 163 ++++++ .../src/Engine/ECS_Base/General/SHFamily.h | 88 ++++ .../ECS_Base/General/SHHandleGenerator.h | 305 +++++++++++ .../Engine/ECS_Base/General/SHSparseBase.h | 50 ++ .../src/Engine/ECS_Base/General/SHSparseSet.h | 356 +++++++++++++ .../ECS_Base/General/SHSparseSetContainer.h | 248 +++++++++ .../src/Engine/ECS_Base/SHECSMacros.h | 25 + .../ECS_Base/System/SHComponentManager.cpp | 102 ++++ .../ECS_Base/System/SHComponentManager.h | 477 ++++++++++++++++++ .../ECS_Base/System/SHEntityManager.cpp | 232 +++++++++ .../Engine/ECS_Base/System/SHEntityManager.h | 253 ++++++++++ .../src/Engine/ECS_Base/System/SHSystem.h | 55 ++ .../ECS_Base/System/SHSystemManager.cpp | 57 +++ .../Engine/ECS_Base/System/SHSystemManager.h | 102 ++++ 19 files changed, 3035 insertions(+) create mode 100644 SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp create mode 100644 SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp create mode 100644 SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp create mode 100644 SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp create mode 100644 SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp new file mode 100644 index 00000000..e5c640ef --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp @@ -0,0 +1,9 @@ +//#include "SHpch.h" +#include "SHComponent.h" + +namespace SHADE +{ + SHComponent::~SHComponent() + { + } +} diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h new file mode 100644 index 00000000..d3def014 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h @@ -0,0 +1,120 @@ +/********************************************************************* + * \file SHComponent.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the Component abstract base class. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + + +#ifndef SH_COMPONENT_H +#define SH_COMPONENT_H + +#include "../SHECSMacros.h" + +namespace SHADE +{ + + class SHComponentManager; + + class SHComponent + { + friend SHComponentManager; + + private: + //The ID of the entity this component belongs to. + EntityID entityID; + //Whether this entity ID has been set once. + //This prevents the Set function from being able to change the entityID once it has been set + + + protected: + + /*!************************************************************************* + * \brief Construct a new SHComponent object + * Protected default constructor to make this an abstract base class. + ***************************************************************************/ + SHComponent() + :entityID(0),isActive(true) + { + } + + SHComponent(SHComponent const& other) + :entityID(other.entityID), isActive(other.isActive) + { + } + + public: + //Whether or not this component is active. + //Systems using this component should are responsible for checking the active state of the component before running their functionality. + bool isActive; + + /*!************************************************************************* + * \brief + * Getter function for the entityID + * \return uint32_t + * The entityID that this component belongs to. + ***************************************************************************/ + uint32_t GetEID()const + { + return this->entityID; + } + + + /*!************************************************************************* + * \brief Destroy the SHComponent object + * Default destructor for Component Base class + ***************************************************************************/ + virtual ~SHComponent(); + + /*!************************************************************************* + * \brief + * A function that is called when the entity changes its parent. + * This can remain empty if nothing has to be done before the parent changes. + * This does not change the component that the entity belongs to + * The old parent is not passed in here as the old parent might be the root node + * in which case there will be no parent. + * If needed, the old parent should be deduced using this entityID + * \param newParent + * EntityID of the new parent. + ***************************************************************************/ + virtual void ChangeParent(EntityID newParent) + { + (void)newParent; + } + + /************************************************************************** + * \brief + * This is an overloaded function of Change parent when the entity + * changes its parent to the root node. (No parent) + * + ***************************************************************************/ + virtual void ChangeParent() + { + } + + + virtual void OnDestroy() + { + } + + + virtual void OnCreate() + { + } + + SHComponent& operator=(SHComponent const& other) + { + this->entityID = other.GetEID(); + this->isActive = other.isActive; + return *this; + } + + + + + }; +} +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp new file mode 100644 index 00000000..292fbe71 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp @@ -0,0 +1,136 @@ +/********************************************************************* + * \file SHComponent.h + * \author Daniel Chua Yee Chen + * \brief Implementation for the SHComponentGroup class. + * The Component Group aids the engine to sort the components to align + * different component type’s data that corresponds to a single entity + * in the same index. The component group also ensure that all components + * data belonging to the group is moved to the start of the dense array. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +//#include "SHpch.h" +#include "SHComponentGroup.h" +#include "../System/SHComponentManager.h" + + +namespace SHADE +{ + SHComponentGroup::SHComponentGroup() + :ownershipType(OWNERSHIP_TYPE::FULL_OWNERSHIP) + { + componentTypeIDs.reserve(MAX_EID); + ownedComponentTypes.reserve(MAX_EID); + entityInGroup.reserve(MAX_EID); + } + + EntityIndex SHComponentGroup::size() noexcept + { + return (EntityIndex)entityInGroup.size(); + } + + bool SHComponentGroup::IsEntityInGroup(EntityID entityID) noexcept + { + for (auto const& eid : entityInGroup) + { + if (entityID == eid) + { + return true; + } + } + return false; + } + + bool SHComponentGroup::RemoveEntity(EntityID entityID) noexcept + { + if (!IsEntityInGroup(entityID)) + { + // This entity has not been added to the group. Ignore it. + return false; + } + + //This entity is in the group. + //Move the placement of the components in all owned component types to the relevant position and remove it from the group. + for (auto const& ownedID : ownedComponentTypes) + { + if (SHComponentManager::ComponentCount_ID(ownedID) > 2) + { + // There are components that do not belong in the group. Need to swap to the last element + SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size() - 1, entityID, ownedID); + } + } + + for (std::vector::iterator it = entityInGroup.begin(); it != entityInGroup.end(); ++it) + { + if (*it == entityID) + { + entityInGroup.erase(it); + break; + } + } + + return true; + } + + void SHComponentGroup::Clear() noexcept + { + entityInGroup.clear(); + + } + + bool SHComponentGroup::AddComponentCheck(EntityID entityID, uint32_t componentTypeID) noexcept + { + if (IsEntityInGroup(entityID)) + { + return false; + } + + //uint32_t componentID = SHFamilyID::template GetID(); + + //Loops to check if this is one of the owned component type + for (auto const& id : componentTypeIDs) + { + //found it + if (id == componentTypeID) + { + for (auto const& typeID : componentTypeIDs) + { + if (typeID != componentTypeID && !SHComponentManager::HasComponent_ID(entityID, typeID)) + { + //This entity does not contain all other component types in this group so we don't do anything yet + return false; + } + } + //This entity contains all required component types. Add to group and swap in dense + //auto& dense = SHComponentManager::GetDense(); + + //Loop through all the owned component and sort them. + for (auto const& ownedID : ownedComponentTypes) + { + if (SHComponentManager::ComponentCount_ID(ownedID) > entityInGroup.size() + 1) + { + // There are components that do not belong in the group. Need to swap to the last element + SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size(), entityID, ownedID); + + } + } + + // If dense.size() == entityInGroup.size() + 1. + // There is no component that is not in this group for this component type. + // Hence no sorting required. + + //Add this entityID to group + entityInGroup.push_back(entityID); + + return true; + } + } + //This component type is not in this group. + return false; + } + +} + diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h new file mode 100644 index 00000000..3f67aff0 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h @@ -0,0 +1,185 @@ +/********************************************************************* + * \file SHComponent.h + * \author Daniel Chua Yee Chen + * \brief Definition for the SHComponentGroup class. + * The Component Group aids the engine to sort the components to align + * different component type’s data that corresponds to a single entity + * in the same index. The component group also ensure that all components + * data belonging to the group is moved to the start of the dense array. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + + +#ifndef SH_COMPONENT_GROUP +#define SH_COMPONENT_GROUP + +#include "../SHECSMacros.h" +#include "../General/SHFamily.h" +#include "SHComponent.h" + +#include +#include +#include + +namespace SHADE +{ + enum class OWNERSHIP_TYPE + { + FULL_OWNERSHIP = 0, + PARTIAL_OWNERSHIP, + NON_OWNERSHIP, + OWNERSHIP_MAX + }; + + + //template + class SHComponentGroup + { + public: + + + //This vector store the Entity IDs of all entity that belongs to this group. + std::vector entityInGroup; + + + //template<> + //bool CheckAddComponent(); + SHComponentGroup(); + ~SHComponentGroup() = default; + + //friends SHComponentManager to allow ECSCore to create componentgroups + friend class SHComponentManager; + + /************************************************************************** + * \brief + * Get the number of entity in the group. + * \return + * Number of entity in the group. + ***************************************************************************/ + EntityIndex size() noexcept; + + /************************************************************************** + * \brief + * Check if a entity is already in the group. + * \param entityID + * The entity ID of the entity + * \return + * true if the entity belongs to the group + ***************************************************************************/ + bool IsEntityInGroup(EntityID entityID) noexcept; + + + /*!************************************************************************* + * \brief + * Checks whether the entity has fulfilled the requirements to be added into + * the Component Group after adding a specified Component Type. + * @tparam T + * Component type to be added + * \param entityID + * EntityID of the entity to be added + ***************************************************************************/ + bool AddComponentCheck(EntityID entityID, uint32_t componentTypeID) noexcept; + + + /*!************************************************************************* + * \brief + * Check if the Component type is in the component group and if the entity is in the group + * Remove it from the group if found. + * This does not handle the removal from the dense array in the sparse set. + * @tparam T + * Component type to be removed + * \param entityID + * EntityID of the entity + ***************************************************************************/ + template + std::enable_if_t, bool> RemoveComponentCheck(EntityID entityID) noexcept + { + + if (!IsEntityInGroup(entityID)) + { + // This entity has not been added to the group. Ignore it. + return false; + } + bool typeFound = false; + uint32_t componentID = SHFamilyID::template GetID(); + for (auto const& id : componentTypeIDs) + { + if (id == componentID) + { + typeFound = true; + break; + } + } + if (typeFound == false) + { + return false; //This type is not something this group needs to care about. + } + + //This entity is in the group. + //Move the placement of the components in all owned component types to the relevant position and remove it from the group. + for (auto const& ownedID : ownedComponentTypes) + { + if (SHComponentManager::ComponentCount_ID(ownedID) > entityInGroup.size() + 1) + { + // There are components that do not belong in the group. Need to swap to the last element + SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size() - 1, entityID, ownedID); + } + } + + for (std::vector::iterator it = entityInGroup.begin(); it != entityInGroup.end(); ++it) + { + if (*it == entityID) + { + entityInGroup.erase(it); + break; + } + } + + return true; + + } + + /*!************************************************************************* + * \brief + * Checks if this entity is in the Component Group and remove it if found. + * This does not handle the removal from the dense array in the sparse set. + * \param entityID + * EntityID of the entity + ***************************************************************************/ + bool RemoveEntity(EntityID entityID) noexcept; + + + /*!************************************************************************* + * \brief + * Resets the Component Group by clearing all entity in group. + * This will not change the Component Types that belong in the group but + * only clear the entity that belongs to the group. + * This is used for scene transition where all entities are cleared. + ***************************************************************************/ + void Clear() noexcept; + + + private: + OWNERSHIP_TYPE ownershipType; + + protected: + + //This vector stores all IDs of all the component type that belongs to this group. + //This will be assigned when the group gets created and used by the group themselves when they for add/remove components. + std::vector componentTypeIDs; + + //This vector stores the IDs of all the component type that this group owns. + //Each component type can only be owned by one group. + std::vector ownedComponentTypes; + + + + }; + +} + + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp new file mode 100644 index 00000000..5d25c9ec --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp @@ -0,0 +1,72 @@ +/********************************************************************* + * \file SHEntity.cpp + * \author Daniel Chua Yee Chen + * \brief Definition of function used in SHEntity class. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ +//#include "SHpch.h" +#include "SHEntity.h" +#include "../System/SHEntityManager.h" +//#include "Scene/SHSceneGraph.h" +#include "../System/SHComponentManager.h" + +namespace SHADE +{ + + SHEntity::SHEntity() + :entityID(),isActive(true) + { + + } + + SHEntity::~SHEntity() + { + + //SHEntityManager::RemoveEntity(this->entityID); + } + + EntityID SHEntity::GetEID() noexcept + { + return this->entityID; + } + + void SHEntity::SetActive(bool active) noexcept + { + isActive = active; + SHComponentManager::SetActive(entityID, active); + } + + + + void SHEntity::SetParent(SHEntity* newParent) noexcept + { + //TODO + } + + void SHEntity::SetParent(EntityID newParentID) noexcept + { + //TODO + } + + SHEntity* SHEntity::GetParent() noexcept + { + //TODO + return nullptr; + } + + + std::vectorconst& SHEntity::GetChildren() noexcept + { + //TODO + return std::vector{}; + } + + std::vectorconst& SHEntity::GetChildrenID() noexcept + { + return std::vector{}; + } + +} diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h new file mode 100644 index 00000000..d499042c --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h @@ -0,0 +1,163 @@ +/********************************************************************* + * \file SHEntity.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the Entity abstract base class. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_ENTITY_H +#define SH_ENTITY_H + +#include "../SHECSMacros.h" +#include "../Components/SHComponent.h" +#include "../System/SHComponentManager.h" +//#include "../../Scene/SHSceneNode.h" + + + +namespace SHADE +{ + class SHComponentManager; + class SHEntityManager; + + class SHEntity + { + public: + + + /************************************************************************** + * Friends with SHEntityManger. + * This allows SHEntityManager to generate a unique entityID for the entity + * upon creation. + * . + ***************************************************************************/ + friend SHEntityManager; + + + /*!************************************************************************* + * \brief Construct a new SHEntity object + * Default constructor for the Entity Object. + * Entities are given their entityID here. + ***************************************************************************/ + SHEntity(); + + /*!************************************************************************* + * \brief Destroy the SHEntity object + * Default destructor for the Entity object. + * Removes the entityID and queue it for recycling. + ***************************************************************************/ + virtual ~SHEntity(); + + + /*!************************************************************************* + * \brief Get the Component object + * A templated GetComponent_s function that calls GetComponent_s from SHComponentManager. + * This is for ease of use. + * @tparam T + * The type of the Component we are trying to get. + * \return + * A pointer to the Component we are trying to get. + * Returns nullptr if the entity does not have such Component. + ***************************************************************************/ + template + std::enable_if_t, T*> GetComponent() noexcept + { + + return SHComponentManager::GetComponent_s(entityID); + //return nullptr; + } + + + /*!************************************************************************* + * \brief + * Getter function for the entityID + * \return uint32_t + * The entityID of this Entity object. + ***************************************************************************/ + EntityID GetEID() noexcept; + + /*!************************************************************************* + * \brief Set the Active object + * Sets the isActive of all Components in this entity. + * This is done through SHComponentManager and this function is for ease of use. + * If derived classes of Entity overloads this function, they are expected to + * call this function using SHEntity::SetActive(active) to change the active of + * all components + * \param active + * The active state to change all components in this entity. + ***************************************************************************/ + virtual void SetActive(bool active) noexcept; + + + + /************************************************************************** + * \brief + * Change the parent of the entity object in the scene graph. + * This command will be stored in a queue and only applied when + * SHSceneGraph::UpdateHierachy is called. + * \param newParent + * A pointer to the new parent entity. + * Pass a nullptr to attach this entity to the root node instead. + ***************************************************************************/ + void SetParent(SHEntity* newParent = nullptr) noexcept; + + + /************************************************************************** + * \brief + * Change the parent of the entity object in the scene graphj. + * This command will be stored in a queue and only applied when + * SHSceneGraph::UpdateHierachy is called + * This is the overloaded version of the function that takes in a + * EntityID instead. This cannot be used to attach to the root node. + * \param newParentID + * The entityID of the new parent. + ***************************************************************************/ + void SetParent(EntityID newParentID) noexcept; + + /************************************************************************** + * \brief + * Get a pointer to the parent entity. + * \return + * Returns a pointer to the parent entity. + * Returns a nullptr if the parent node is the root node. + ***************************************************************************/ + SHEntity* GetParent() noexcept; + + + /************************************************************************** + * \brief + * Get a vector of SHEntity pointers of the children belonging to this entity. + * \return + * Return a vector of SHEntity pointers of the children belonging to this entity. + ***************************************************************************/ + std::vectorconst& GetChildren() noexcept; + + /************************************************************************** + * \brief + * Get a vector of EntityID of the children belonging to this entity. + * \return + * return a vector of EntityID of the children belonging to this entity. + ***************************************************************************/ + std::vectorconst& GetChildrenID() noexcept; + + + std::string name; + bool isActive; + + + private: + //The identifier of the entity. + //This is split into 2 x 16-bits that represents version and index respectively + //Index is used by the engine to index the entity. + //Version is used by the engine to recycle the index of the entity. + EntityID entityID; + + + }; +} + + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h b/SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h new file mode 100644 index 00000000..f97bbe0e --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h @@ -0,0 +1,88 @@ +/********************************************************************* + * \file SHFamily.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the SHFamily template class. + * This class is to create a unique identifier for each derived class type. + * Example: Each Component type (SHTransformComponent / SHRenderableComponent) + * will have a different identifier generated by this class. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_FAMILY_H +#define SH_FAMILY_H + +#include "../SHECSMacros.h" + + +namespace SHADE +{ + template + class SHFamilyID + { + private: + //this is used to keep track of the new current ID to be assign to a new Derived class type. + static ComponentTypeID currentID; + + /*!************************************************************************* + * \brief Construct a new SHFamilyID object + * Private constructor. + * No objects of this type should be made. + * Only use the static functions of this class + ***************************************************************************/ + SHFamilyID() + { + } + + /*!************************************************************************* + * \brief Destroy the SHFamilyID object + * Private destructor. + * No objects of this type should be made. + * Only use the static functions of this class + ***************************************************************************/ + virtual ~SHFamilyID() + { + } + public: + + /*!************************************************************************* + * \brief + * Checks if this identifier is cuurrently in use / valid. + * \param id + * Identifier to check for. + * \return bool + * true if the identifier is currently in use. + * false if the identifier is not in use. + ***************************************************************************/ + static bool IsValidID(ComponentTypeID id) noexcept + { + return(id < currentID); + } + + /*!************************************************************************* + * \brief + * Get the ID of a derived class type. + * Example of function call to this function should be: + * SHFamily::GetID(); + * @tparam DerivedClass + * The derived class type that we are trying to get the ID of. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept + { + //The first time a new derived class type call this get id, it will initialize id using the currentID from familyID class. + static ComponentTypeID id = currentID++; + return id; + } + }; + //initialize currentID as 0 + template + ComponentTypeID SHFamilyID::currentID = 0; + +} + + + +#endif \ No newline at end of file diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h b/SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h new file mode 100644 index 00000000..48ae2132 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h @@ -0,0 +1,305 @@ +/********************************************************************* + * \file SHHandleGenerator.h + * \author Daniel Chua Yee Chen + * + * \brief Declaration for the SHHandleGenerator class. + * Generates a unique identifier/handle for objects. + * This is different from SHFamily which is meant to generate identifier for object types. + * + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ +#ifndef SH_HANDLE_GENERATOR_H +#define SH_HANDLE_GENERATOR_H + +#include +#include + +#include "../SHECSMacros.h" + + + +namespace SHADE +{ + /********************************************************************* + * \brief + * Generates a unique handle of HandleType type. + * The first half of the bits will be used for version. This is used for recyling the IDs. + * The second half of the bits will be used for the index, this is also used as its ID. + * + * HandleType should always be twice the size of IndexType + *********************************************************************/ + + template + class SHHandleGenerator + { + private: + //List of all the handles in use. Handles that are deleted are still stored here. + std::vector handleList; + //The next handle to be used. + HandleType nextRecycle; + //The total number of handles that are currently deleted and waiting to be recycled. + HandleType recycleCounter; + + //The Mask is variable is used to easily separate the version and index via bit masking (bitwise &). + + + //The index mask is used to identify the index. + //(1<<16) - 1. Shift 1 bit to the left 16 times and -1. This leaves the first 16 bits as 0 and the -1 makes the second 16 bits all 1. + static const HandleType indexMask = (1 << sizeof(IndexType) * 8) - 1; + + //using the bitwise NOT, invert the index mask to get the version mask. + static const HandleType versionMask = ~indexMask; + + public: + /*!************************************************************************* + * \brief Construct a new SHHandleGenerator object + * default constructor for the HandleGenerator object. + ***************************************************************************/ + SHHandleGenerator() + :nextRecycle(0),recycleCounter(0) + { + } + + /*!************************************************************************* + * \brief Destroy the SHHandleGenerator object + * Default destructor for the HandleGenerator object. + ***************************************************************************/ + ~SHHandleGenerator() = default; + + + /*!************************************************************************* + * \brief + * Combines the 16-bit version and 16-bit index to make a 32-bit handle. + * \param verison + * The 16-bit version + * \param index + * The 16-bit index + * \return HandleType + * The resultant Handle + ***************************************************************************/ + static HandleType GetHandle(IndexType version, IndexType index) noexcept + { + return (version << sizeof(IndexType) * 8) | index; + } + + /*!************************************************************************* + * \brief + * Gets the 16-bit version from the 32-bit handle + * \param handle + * The 32-bit handle + * \return IndexType + * The 16-bit version + ***************************************************************************/ + static IndexType GetVersion(HandleType handle) noexcept + { + return handle >> sizeof(IndexType) * 8; + } + + /*!************************************************************************* + * \brief + * Gets the 16-bit index from the 32-bit handle + * \param handle + * The 32-bit handle + * \return IndexType + * The 16-bit index + ***************************************************************************/ + static IndexType GetIndex(HandleType handle) noexcept + { + return handle & indexMask; + } + + /*!************************************************************************* + * \brief + * Checks if the current handle is still valid. This checks if the index + * of the handle is in use, then checks if the version of the current index + * matches the handle we are checking for. + * \param handle + * The handle to check for. + * \return bool + * True if the handle is still valid. False if the handle has been removed + * or not in use. + ***************************************************************************/ + bool IsValid(HandleType handle) noexcept + { + IndexType index = GetIndex(handle); + if (index >= (IndexType)handleList.size()) // handle is out of range of intialized index + { + return false; + } + + return (handleList[index] == handle); // this will check if the current handle at that index has been removed. + } + + /************************************************************************** + * \brief + * Get the number of active handles. + * \return + * Number of active handles. + ***************************************************************************/ + IndexType GetActiveHandleCount() noexcept + { + return (IndexType)(handleList.size() - recycleCounter); + } + + /*!************************************************************************* + * \brief + * Request the Generator for a new handle. This will provide recycled index + * if available + * \return HandleType + * The new handle. + ***************************************************************************/ + HandleType GetNewHandle() noexcept + { + HandleType result; + + //Check if there is any index waiting to be recycled + if (recycleCounter == 0) // nothing to be recycled. Make a new one + { + result = GetHandle(0, (IndexType)handleList.size()); + handleList.push_back(result); + return result; + } + //There is a index waiting to be recycled. + result = nextRecycle; + IndexType index = GetIndex(nextRecycle); + //updates the next recycle. + nextRecycle = handleList[index]; + handleList[index] = result; + --recycleCounter; + return result; + + } + + /*!************************************************************************* + * \brief + * Removes a handle and make it invalid and queue it for recycling. + * \param handle + * The handle to remove. + ***************************************************************************/ + void RemoveHandle(HandleType handle) noexcept + { + if (!IsValid(handle)) + { + return; + } + + IndexType index = GetIndex(handle); + IndexType version = GetVersion(handle); + + //set the handle at the current index to the next thing to be recycled. + handleList[index] = nextRecycle; + + //set the next recycle to be the thing that was just deleted with its version incremented. + nextRecycle = GetHandle(version + 1, index); + ++recycleCounter; + + } + + /*!************************************************************************* + * \brief + * Clears all the handles in use and Resets the handle generation. + ***************************************************************************/ + void ClearAllHandles() noexcept + { + handleList.clear(); + nextRecycle = 0; + recycleCounter = 0; + } + + /************************************************************************** + * \brief + * Attempts to claim a specified handle. If the handle is available, the + * generator will mark it as claimed and return true. + * Updates recycles accordingly when adding extra padding to the handle list. + * + * \param handle + * The handle to claim + * + * \return + * true if the handle is available to claim. + ***************************************************************************/ + bool ClaimHandle(HandleType handle) noexcept + { + IndexType index = GetIndex(handle); + + if (handleList.size() <= index || GetIndex(handleList[index]) != index) + { + //This index is currently not in use + + if (index >= handleList.size()) + { + IndexType size = (IndexType)handleList.size(); + + for (IndexType i = 0; i < index - size; ++i) + { + handleList.push_back((IndexType)handleList.size()); + + HandleType back = handleList.back(); + //set the handle at the current index to the next thing to be recycled. + if (recycleCounter > 0) + handleList.back() = nextRecycle; + else + { + handleList.back() = (HandleType)-1; + } + + //set the next recycle to be the thing that was just deleted with its version incremented. + nextRecycle = GetHandle(0, GetIndex(back)); + ++recycleCounter; + } + handleList.push_back(handle); + + } + else + { + if (index == GetIndex(nextRecycle)) + { + index = GetIndex(nextRecycle); + //updates the next recycle. + nextRecycle = handleList[index]; + handleList[index] = handle; + --recycleCounter; + return true; + } + + if (recycleCounter > 0) + { + HandleType recycle = handleList[index]; + IndexType recycleIndex = GetIndex(nextRecycle); + HandleType i = 0; + while (i < recycleCounter) + { + if (GetIndex(handleList[recycleIndex]) == index) + break; + recycleIndex = GetIndex(handleList[recycleIndex]); + ++i; + } + --recycleCounter; + if (recycleCounter > 0 && recycleIndex < handleList.size()) + handleList[recycleIndex] = recycle; + } + handleList[index] = handle; + } + + + return true; + } + + return false; + + } + + + }; + + + + typedef SHHandleGenerator EntityHandleGenerator; + +} + + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h b/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h new file mode 100644 index 00000000..2deebe74 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h @@ -0,0 +1,50 @@ +/********************************************************************* + * \file SHSparseBase.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the SHSparseBase class. + * This is an abstract class for the SHSparseSet template class. + * This allows the SHSparseSetContainer class to store SparseSet of different types. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_SPARSE_BASE_H +#define SH_SPARSE_BASE_H + +#include "../SHECSMacros.h" + +namespace SHADE +{ + + class SHSparseBase + { + protected: + SHSparseBase() = default; + + public: + virtual ~SHSparseBase() = default; + + virtual void Remove(EntityIndex hash) { (void)hash; }; + + virtual void Clear() {}; + + virtual void Swap(EntityIndex hash1, EntityIndex hash2) { (void)hash1; (void)hash2; }; + + virtual void SwapIndexHash(EntityIndex index1, EntityIndex hash) { (void)index1; (void)hash; }; + + virtual bool Has(EntityIndex hash) = 0; + + virtual void* Get(EntityIndex hash) { (void)hash; return nullptr; }; + + virtual void Add(EntityIndex hash) { (void)hash; }; + + virtual EntityIndex Count() = 0; + + }; + +} + + +#endif \ No newline at end of file diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h b/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h new file mode 100644 index 00000000..3473eb37 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h @@ -0,0 +1,356 @@ +/********************************************************************* + * \file SHSparseSet.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the SHSparseSet template class + * This is a container that allows for fast iteration due to contiguous memory + * storage while having fast lookup time at the cost of memory usage. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ +#ifndef SH_SPARSE_SET_H +#define SH_SPARSE_SET_H + +#include "../SHECSMacros.h" +#include "../General/SHSparseBase.h" +#include "../General/SHHandleGenerator.h" +#include +#include +#include + +namespace SHADE +{ + template + class SHSparseSet: public SHSparseBase + { + private: + //Dense array of type T + std::vector denseArray; + //This array stores the key of the corresponding element in the dense array. (eg. entity ID) + std::vector denseIndexArray; + + //Sparse Array. This array helps with look up + EntityIndex sparseArray[MAX]; + + public: + + /*!************************************************************************* + * \brief Construct a new SHSparseSet object + * Default constructor for the SparseSet class. + ***************************************************************************/ + SHSparseSet() + { + for (EntityIndex i = 0; i < MAX; ++i) + { + sparseArray[i] = UINT16_MAX; + } + + denseArray.reserve(MAX); + denseIndexArray.reserve(MAX); + } + + /*!************************************************************************* + * \brief Destroy the SHSparseSet object + * Default destructor for the SparseSet class. + ***************************************************************************/ + virtual ~SHSparseSet() + { + Clear(); + } + + /*!************************************************************************* + * \brief + * Clears all elements in the current SparseSet and resets the sparseArray. + ***************************************************************************/ + void Clear() noexcept + { + denseArray.clear(); + denseIndexArray.clear(); + for (EntityIndex i = 0; i < MAX; ++i) + { + sparseArray[i] = UINT16_MAX; + } + } + + /*!************************************************************************* + * \brief + * Check is the specified hash is in range of the sparseSet. + * \param hash + * Hash to check for. + * \return bool + * true if the specified hash is in range of the spraseSet. + ***************************************************************************/ + bool IsValid(EntityIndex hash) noexcept + { + return (hash < MAX); + } + + /*!************************************************************************* + * \brief + * Checks if this sparseSet contains an element with specified hash. + * \param hash + * The hash to check for. + * \return bool + * true if the element with this hash is found. false if no such element is found. + ***************************************************************************/ + virtual bool Has(EntityIndex hash) noexcept + { + //Check if the hash passed in is within range. + if (!IsValid(hash) || sparseArray[hash] == UINT16_MAX) + { + return false; + } + return (denseIndexArray[sparseArray[hash]] == hash); + } + + /*!************************************************************************* + * \brief + * Get a pointer to the element with the specified hash. + + * This is the safe version which does a Has() check and return a nullptr + * if it does not have such an Element + * + * \param hash + * The hash of the element to look for. + * \return T* + * returns a pointer to the element with the specified hash if found. + * returns a nullptr if no such element is found. + ***************************************************************************/ + T* GetElement_s(EntityIndex hash) noexcept + { + if (!Has(hash)) + { + return nullptr; + } + + return &denseArray[sparseArray[hash]]; + } + + /*!************************************************************************* + * \brief + * Get a pointer to the element with the specified hash. + + * This bypasses the Has() check and assumes that the hash has a Element + * in the dense array. + * + * \param hash + * The hash of the element to look for. + * \return T* + * returns a pointer to the element with the specified hash if found. + * returns a nullptr if no such element is found. + ***************************************************************************/ + T* GetElement(EntityIndex hash) noexcept + { + return &denseArray[sparseArray[hash]]; + } + + + + /*!************************************************************************* + * \brief + * Operator overload for the subscript operator. + * Gets the element by reference with the hash specified in the subscript. + * This does not handle out of range exceptions. + * \param hash + * The hash of the element we are trying to get + * \return T& + * A reference to the element found. + ***************************************************************************/ + T& operator[](EntityIndex hash) noexcept + { + return denseArray[sparseArray[hash]]; + } + + /*!************************************************************************* + * \brief + * Get the number of elements in the current SparseSet + * \return uint16_t + * The number of elements in the SparseSet. + ***************************************************************************/ + virtual EntityIndex Count() noexcept + { + return (EntityIndex)denseArray.size(); + } + + /*!************************************************************************* + * \brief + * Getter function for the dense array. + * \return std::vector& + * return a reference to the dense array. + ***************************************************************************/ + std::vector& GetDense() noexcept + { + return denseArray; + } + + /*!************************************************************************* + * \brief + * Const getter function for the dense array. + * \return std::vector& + * return a const reference to the dense array. + ***************************************************************************/ + const std::vector GetDense() const noexcept + { + return denseArray; + } + + /*!************************************************************************* + * \brief + * Swaps two elements in the dense array. + * This only swaps their position in the dense array and updates their + * Sparse index reference in the sprase array accordingly. + * This DOES NOT change the hash of the elements. + * \param hash1 + * Hash of the first element + * \param hash2 + * Hash of the second element + ***************************************************************************/ + virtual void Swap(EntityIndex hash1, EntityIndex hash2) noexcept + { + if (!Has(hash1) || !Has(hash2) || hash1 == hash2) + { + return; + } + T tempElement = denseArray[sparseArray[hash1]]; + EntityIndex tempIndex = denseIndexArray[sparseArray[hash1]]; + EntityIndex tempSparse = sparseArray[hash1]; + + denseArray[sparseArray[hash1]] = denseArray[sparseArray[hash2]]; + denseIndexArray[sparseArray[hash1]] = denseIndexArray[sparseArray[hash2]]; + sparseArray[hash1] = sparseArray[hash2]; + + denseArray[sparseArray[hash2]] = tempElement; + denseIndexArray[sparseArray[hash2]] = tempIndex; + sparseArray[hash2] = tempSparse; + + } + + /*!************************************************************************* + * \brief + * Swaps two elements in the dense array. + * This only swaps their position in the dense array and updates their + * Sparse index reference in the sprase array accordingly. + * This swaps using a index(position in the dense array) and a hash (EntityID) + * This DOES NOT change the hash of the elements. + * \param index1 + * The position in the dense array of the first element + * \param hash + * Hash of the second element + ***************************************************************************/ + virtual void SwapIndexHash(EntityIndex index1, EntityIndex hash) noexcept + { + if (index1 >= denseArray.size() || !Has(hash)) + { + return; + } + Swap(denseIndexArray[index1], hash); + } + + /*!************************************************************************* + * \brief + * Adds a new element to the SparseSet. + * \param hash + * The hash of the new element. + * Nothing is added if the SparseSet already contains an element with + * the same hash. + * \param element + * A reference to the element to be added. This will be passed in as a + * copy and the default copy constructor will be used to copy the element + * into the dense array. + ***************************************************************************/ + void Add(EntityIndex hash, T& element) noexcept + { + if (!IsValid(hash) || Has(hash)) + { + return; + } + + denseArray.emplace_back(element); + denseIndexArray.emplace_back (hash); + sparseArray[hash] = EntityIndex(denseIndexArray.size() - 1); + } + + /************************************************************************** + * \brief + * Adds a new element to the SparseSet. + * \param hash + * The hash of the new element. + * Nothing is added if the SparseSet already contains an element with + * the same hash. + * \return + * None + ***************************************************************************/ + void Add(EntityIndex hash) noexcept + { + if (!IsValid(hash) || Has(hash)) + { + return; + } + + denseArray.emplace_back(T()); + denseIndexArray.emplace_back(hash); + sparseArray[hash] = EntityIndex(denseIndexArray.size() - 1); + } + + + + /*!************************************************************************* + * \brief + * Removes an element from the Sparse Set + * \param hash + * + ***************************************************************************/ + virtual void Remove(EntityIndex hash) noexcept + { + if (!Has(hash)) + { + return; + } + + //Get the index of the item to be removed. + EntityIndex index = sparseArray[hash]; + + //Get the sparse index of the last element in the dense array. + EntityIndex lastSparse = denseIndexArray.back(); + + //Copy the contents of the last elements to the replace the element we are trying to remove + //denseArray[index] = denseArray.back(); + //denseIndexArray[index] = denseIndexArray.back(); + + //denseArray.erase(denseArray.begin() + index); + //denseIndexArray.erase(denseIndexArray.begin() + index); + Swap(hash, lastSparse); + + //update the sparse array with the new index of our last element. + sparseArray[lastSparse] = index; + sparseArray[hash] = UINT16_MAX; + + //Pop out the last element since we no longer need it + denseArray.pop_back(); + denseIndexArray.pop_back(); + } + + /************************************************************************** + * \brief + * Get the element specified by a hash. This will be casted to a void + * pointer + * \param hash + * The Index of the element. + * \return + * A void pointer to the element. + ***************************************************************************/ + virtual void* Get(EntityIndex hash) noexcept + { + if (!Has(hash)) + { + //no such element in this sparse set. + return nullptr; + } + return (void*) &denseArray[sparseArray[hash]]; + } + + }; +} + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h b/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h new file mode 100644 index 00000000..8698d1f5 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h @@ -0,0 +1,248 @@ +/********************************************************************* + * \file SHSparseSetContainer.h + * \author Daniel Chua Yee Chen + * \brief Declaration for SHSparseSetContainer template class. + * This is a container for SHSparseSets meant to contain SparseSets of + * different types that are derived from a shared Base class. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_SPARSE_SET_CONTAINER_H +#define SH_SPARSE_SET_CONTAINER_H + +#include "SHSparseSet.h" +#include "SHFamily.h" +#include "../Components/SHComponent.h" +#include + +namespace SHADE +{ + template + class SHSparseSetContainer + { + private: + + + + public: + + //The container of SparseSets. + std::vector container; + + /*!************************************************************************* + * \brief + * Default constructor for the SHSparseSetContainer class + ***************************************************************************/ + SHSparseSetContainer() = default; + + /*!************************************************************************* + * \brief + * Default destructor for the SHSparseSetContainer class. + ***************************************************************************/ + ~SHSparseSetContainer() + { + for (std::vector::iterator it = container.begin(); it != container.end(); ++it) + { + delete (*it); + } + }; + + /*!************************************************************************* + * \brief + * Attempts to create a SparseSet for the specified derived class. + * If a SparseSet of the same class type has already been created, + * nothing is re-created. + * @tparam Derived + * The type of the SparseSet to create. + ***************************************************************************/ + template + ENABLE_IF_DERIVED(void, Base, Derived) CreateSparseSet() noexcept + { + EntityID typeID = SHFamilyID::template GetID(); + + if (container.size() > typeID) + { + if (container[typeID] == nullptr) + { + container[typeID] = (SHSparseBase*)new SHSparseSet(); + } + return; + } + while (container.size() <= typeID) + { + container.push_back(nullptr); + } + container[typeID] = (SHSparseBase*)new SHSparseSet(); + } + + //Cant use ENABLE_IF_DERIVED here because the macro is defined before template is defined. + //Hence the return type that is a templated class will be an issue. + + + /************************************************************************** + * \brief + * Get the sparse set specified by a type. This converts the type to + * a type ID using SHFamilyID and use that as the index. + * This will attempt to Create a sparse set if it doesn't exist. + * \return + * The base class pointer to the sparse set. + ***************************************************************************/ + template + std::enable_if_t< std::is_base_of_v,SHSparseSet* > GetSparseSet() noexcept + { + EntityID typeID = SHFamilyID::template GetID(); + if (container.size() <= typeID || container[typeID] == nullptr) + { + CreateSparseSet(); + } + + return (SHSparseSet*)container[typeID]; + + } + + + /************************************************************************** + * \brief + * Get the sparse set at the specified index. + * \param typeID + * The index of the sparse set to get. + * \return + * The base class pointer to the sparse set. + ***************************************************************************/ + SHSparseBase* GetSparseSet_ID(uint32_t typeID) noexcept + { + //assert(typeID >= container.size()); + + return container[typeID]; + } + + + /*!************************************************************************* + * \brief + * Get the number of elements in the specified SparseSet + * @tparam Derived + * The type of the SparseSet + ***************************************************************************/ + template + inline ENABLE_IF_DERIVED(EntityID, Base, Derived)Count() noexcept + { + return GetSparseSet()->Count(); + } + + /*!************************************************************************* + * \brief + * Get the dense array of the specified SparseSet + * @tparam Derived + * The type of the SparseSet + * \return + * Returns a reference to the dense array of the specified SparseSet + ***************************************************************************/ + template + inline std::enable_if_t < std::is_base_of_v, std::vector& > GetDense() noexcept + { + return GetSparseSet()->GetDense(); + } + + /*!************************************************************************* + * \brief + * Remove all elements with the specified hash from all the SparseSets in + * the container. + * \param hash + * The hash of the elements to remove. + ***************************************************************************/ + void RemoveElements(EntityIndex hash) noexcept + { + for (std::vector::iterator it = container.begin(); it != container.end(); ++it) + { + + if (*it) + { + (*it)->Remove(hash); + } + + } + } + + /*!************************************************************************* + * \brief + * Clear all SparseSets in the container. + ***************************************************************************/ + void ClearAllElements() noexcept + { + for (std::vector::iterator it = container.begin(); it != container.end(); ++it) + { + (*it)->Clear(); + } + } + + /*!************************************************************************* + * \brief + * Sets the isActive variable in the elements with the specified hash + * in all the SparseSets in the container. + * This assuumes that the element types has a isActive boolean. + * \param hash + * hash of the elements + * \param active + * The active state to set to. + ***************************************************************************/ + void SetElementActive(EntityIndex hash, bool active) noexcept + { + (void)active; + for (std::vector::iterator it = container.begin(); it != container.end(); ++it) + { + + if (*it) + { + SHComponent* comp = static_cast((*it)->Get(hash)); + if (comp) + { + comp->isActive = active; + } + + } + + } + } + + + + /************************************************************************** + * \brief + * Get the element of a specified hash from the Sparse set of indicated index. + * \param typeIndex + * The index of the sparse set which we are trying to get from + * \param hash + * The hash that the element belongs to. + * \return + * The address of the element casted to a void* + ***************************************************************************/ + void* GetElement(uint32_t typeIndex, EntityIndex hash) noexcept + { + if (typeIndex >= container.size()) + { + return nullptr; + } + return container[typeIndex]->Get(hash); + } + + /************************************************************************** + * \brief + * Get the size of the SparseSetContainer. + * \return + * The number of sparse sets in this container. + ***************************************************************************/ + + size_t Size() noexcept + { + return container.size(); + } + + + }; +} + + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h b/SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h new file mode 100644 index 00000000..5243e20f --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h @@ -0,0 +1,25 @@ +#ifndef SH_MACROS_H +#define SH_MACROS_H + +#include +#include + + + +typedef uint32_t EntityID; +typedef uint16_t EntityIndex; +typedef uint32_t ComponentTypeID; + + +const EntityIndex MAX_EID = 51000; + + + +#define ENABLE_IF_DERIVED(__RETURN__, __BASE__, __DERIVED__)\ + std::enable_if_t,__RETURN__> + + +#define ENABLE_IF_UINT(_TYPE, _RETURN)\ + typename std::enable_if<(std::is_integral<_TYPE>::value && !std::is_signed<_TYPE>::value),_RETURN>::type + +#endif \ No newline at end of file diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp b/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp new file mode 100644 index 00000000..5bbb71ab --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp @@ -0,0 +1,102 @@ +/********************************************************************* + * \file SHComponentManager.cpp + * \author Daniel Chua Yee Chen + * \brief Definition of functions for the SHComponentManager class. + * This is the interface that the systems are going to use to interacte with + * the components. The SparseSetContainer of components is stored and managed + * here. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ +//#include "SHpch.h" +#include "SHComponentManager.h" +#include "SHEntityManager.h" +#include "SHSystemManager.h" + +namespace SHADE +{ + + SHSparseSetContainer SHComponentManager::componentSet; + std::vector SHComponentManager::componentGroups; + + void SHComponentManager::Exit() noexcept + { + } + + void SHComponentManager::RemoveComponentsOfEntity(EntityID entityID) noexcept + { + + if (!SHEntityManager::IsValidEID(entityID)) + { + return; + } + + for (uint32_t i = 0; i < componentSet.Size(); ++i) + { + SHComponent* comp = (SHComponent*) componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entityID)); + if (comp) + { + comp->OnDestroy(); + } + } + + + + for (auto & grp : componentGroups) + { + grp.RemoveEntity(entityID); + } + + componentSet.RemoveElements(EntityHandleGenerator::GetIndex(entityID)); + + //entityHandle.RemoveHandle(entityID); + + } + + + bool SHComponentManager::HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept + { + return componentSet.GetSparseSet_ID(componentTypeID)->Has(EntityHandleGenerator::GetIndex(entityID)); + } + + + void SHComponentManager::SetActive(EntityID entityID, bool active) noexcept + { + componentSet.SetElementActive(EntityHandleGenerator::GetIndex(entityID), active); + } + + void SHComponentManager::SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept + { + componentSet.GetSparseSet_ID(componentTypeID)->SwapIndexHash(index, EntityHandleGenerator::GetIndex(hash)); + } + + void SHComponentManager::ChangeParent(EntityID entity, EntityID newParent) + { + for (uint32_t i = 0; i < (uint32_t)componentSet.Size(); ++i) + { + SHComponent* component = (SHComponent*)componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entity)); + if (component == nullptr) + { + continue; + } + component->ChangeParent(newParent); + + } + } + + void SHComponentManager::ChangeParent(EntityID entity) + { + for (uint32_t i = 0; i < (uint32_t)componentSet.Size(); ++i) + { + SHComponent* component = (SHComponent*)componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entity)); + if (component == nullptr) + { + continue; + } + component->ChangeParent(); + } + } + +} diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h b/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h new file mode 100644 index 00000000..05a3d1ee --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h @@ -0,0 +1,477 @@ +/********************************************************************* + * \file SHComponentManager.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the SHComponentManager class. + * This is the interface that the systems are going to use to interacte with + * the components. + * The SparseSetContainer of components is stored and managed + * here. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_ENGINE_H +#define SH_ENGINE_H + +#include "../General/SHSparseSetContainer.h" +#include "../Components/SHComponent.h" +#include "../Components/SHComponentGroup.h" +//#include "Scene/SHSceneNode.h" + + +#include + +namespace SHADE +{ + class SHComponentManager + { + private: + + //The SparseSetContainer of components. + static SHSparseSetContainer componentSet; + //The Container of all Componentgroups + static std::vector componentGroups; + + friend class SHSceneNode; + + + + /************************************************************************** + * \brief + * This is called by the SHSceneNode friend class to change the parent + * of an entity. + * This function is privated as it is not for general use. + * \param entity + * The entityID of the entity which to change the parent of. + * \param newParent + * The entityID of the new parent. + ***************************************************************************/ + static void ChangeParent(EntityID entity, EntityID newParent); + + + /************************************************************************** + * \brief + * Overloaded function of Change parent to change the parent of an entity to + * the root node. + * This is called by the SHSceneNode friend class to change the parent + * of an entity. + * This function is privated as it is not for general use. + * \param entity + * The entityID of the entity which to change the parent of. + ***************************************************************************/ + static void ChangeParent(EntityID entity); + + + protected: + + public: + /*!************************************************************************* + * This class is used as a static class. + * No objects of this type should be created + ***************************************************************************/ + SHComponentManager() = delete; + ~SHComponentManager() = delete; + + + + /*!************************************************************************* + * \brief + * Cleans up the memory used in the Engine. + ***************************************************************************/ + static void Exit() noexcept; + + + + /*!************************************************************************* + * \brief + * Creates the SparseSet for the specified Component type + * @tparam T + * Component Type to create. + ***************************************************************************/ + template + static void CreateComponentSparseSet() noexcept + { + componentSet.CreateSparseSet(); + } + + /*!************************************************************************* + * \brief + * Getter for the dense array of a specified Component Type. + * @tparam T + * Component Type + * \return std::vector& + * reference to the dense array from the SparseSet of the Component Type T. + ***************************************************************************/ + template + static std::vector& GetDense() noexcept + { + return componentSet.GetDense(); + } + + + /*!************************************************************************* + * \brief + * Gets the Component of the entity with the specified entityID + * + * This is the safe version of GetComponent_s which does a HasComponent to make + * sure that the entity has such a component and returns nullptr if it doesn't + * + * This safe version also checks if the sparse set of this component type + * has been created in SHComponentManager and creates one if it doesn't + * + * @tparam T + * Type of Component to get. + * \param entityID + * EntityID of the entity that we are trying to get the component of. + * \return + * A pointer to the component of the entity. + * Returns nullptr if the entity does not contain such a component. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(T*, SHComponent, T) GetComponent_s(EntityID entityID) noexcept + { + EntityID typeID = SHFamilyID::template GetID(); + + if (componentSet.container.size() <= typeID) + { + componentSet.CreateSparseSet(); + return nullptr; + } + + + return (componentSet.GetSparseSet()->GetElement_s(EntityHandleGenerator::GetIndex(entityID))); + } + + /*!************************************************************************* + * \brief + * Gets the Component of the entity with the specified entityID + * + * This is the faster unsafe version. + * Use only when sure that the entity has such a Component type. This could + * give garbage value or the component of a different entity if the entity + * does not have the specified component type. This is usually used with + * ComponentGroups + * + * This unsafe version bypass the HasComponent check. + * + * This unsafe version bypass the check for sparseSet creation. + * + * @tparam T + * Type of Component to get. + * \param entityID + * EntityID of the entity that we are trying to get the component of. + * \return + * A pointer to the component of the entity. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(T*,SHComponent, T) GetComponent(EntityID entityID) noexcept + { + //EntityID typeID = SHFamilyID::template GetID(); + + return (componentSet.GetSparseSet()->GetElement(EntityHandleGenerator::GetIndex(entityID))); + } + + + + /*!************************************************************************* + * \brief + * Add a component to the specified entityID + * Nothing is added if the entityID already have a component of the same type. + * @tparam T + * Type of Component to be added. + * @tparam Args + * The args types to pass to the constructor of the Component + * \param entityID + * EntityID to add this component to. + * \param args + * The args to pass to the constructor of the Component + * \return + * None. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(void,SHComponent,T) AddComponent(EntityID entityID) noexcept + { + T element{}; + + componentSet.GetSparseSet_ID(SHFamilyID::GetID())->Add(EntityHandleGenerator::GetIndex(entityID)); + + + SHComponent* comp = (SHComponent*)componentSet.GetElement(SHFamilyID::GetID(), EntityHandleGenerator::GetIndex(entityID)); + comp->entityID = entityID; + + for (auto& grp : componentGroups) + { + grp.AddComponentCheck(entityID, SHFamilyID::GetID()); + } + + + if (comp) + { + comp->OnCreate(); + } + + } + + /************************************************************************** + * \brief + * Add Component using a component type ID. This assumes that the sparse + * set is already created for the component type ID. + * \param entityID + * The entity ID of the entity + * \param componentTypeID + * The Type ID of the Component Type. + * \return + * none + ***************************************************************************/ + static void AddComponent(EntityID entityID, uint32_t componentTypeID) noexcept + { + componentSet.GetSparseSet_ID(componentTypeID)->Add(EntityHandleGenerator::GetIndex(entityID)); + + + SHComponent* comp = (SHComponent*)componentSet.GetElement(componentTypeID, EntityHandleGenerator::GetIndex(entityID)); + comp->entityID = entityID; + + for (auto& grp : componentGroups) + { + grp.AddComponentCheck(entityID,componentTypeID); + } + + + if (comp) + { + comp->OnCreate(); + } + } + + + /*!************************************************************************* + * \brief + * Checks if the specified entityID has a component of specified type. + * @tparam T + * Type of Component to check for. + * \param entityID + * EntityID to check for. + * \return bool + * True if the entity has a component of specified type. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(bool, SHComponent, T) HasComponent(EntityID entityID) noexcept + { + return componentSet.GetSparseSet()->Has(EntityHandleGenerator::GetIndex(entityID)); + } + + + + /*!************************************************************************* + * \brief + * Checks if the specified entityID has a component of specified type. + * The component type is specified by a component type ID + * @tparam T + * Type of Component to check for. + * \param entityID + * EntityID to check for. + * \param componentTypeID + * The component type ID to look for + * \return bool + * True if the entity has a component of specified type. + ***************************************************************************/ + static bool HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept; + + + /*!************************************************************************* + * \brief + * Remove the Component of specified type from the entity. + * @tparam T + * Component type to be removed + * \param entityID + * EntityID of the object to remove the component from. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(void, SHComponent, T) RemoveComponent(EntityID entityID) noexcept + { + if (!HasComponent(entityID)) + { + return; + } + + SHComponent* comp = (SHComponent*)componentSet.GetElement(SHFamilyID::GetID(), EntityHandleGenerator::GetIndex(entityID)); + if (comp) + { + comp->OnDestroy(); + } + + for (auto& grp : componentGroups) + { + grp.RemoveComponentCheck(entityID); + } + + + componentSet.GetSparseSet()->Remove(EntityHandleGenerator::GetIndex(entityID)); + } + + /*!************************************************************************* + * \brief + * Swaps to positioning of two components in their dense array. + * This does not swap the entity that the components belong to + * @tparam T + * Type of the Component to swap. + * \param entityID1 + * entityID of the first entity. + * \param entityID2 + * entityID of the second entity. + * \return + * None. + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(void, SHComponent, T) SwapInDense(EntityID entityID1, EntityID entityID2) noexcept + { + componentSet.GetSparseSet()->Swap(EntityHandleGenerator::GetIndex(entityID1), EntityHandleGenerator::GetIndex(entityID2)); + } + + /************************************************************************** + * \brief + * Swaps to positioning of two components in their dense array. + * This does not swap the entity that the components belong to. + * This is the overloaded function that takes 2 Entity Index + * \param index + * The entity Index of the first entity. + * \param hash + * The entity Index of the second entity. + * \return + * none + ***************************************************************************/ + template + static ENABLE_IF_DERIVED(void, SHComponent, T) SwapInDenseByIndex(EntityIndex index, EntityIndex hash) noexcept + { + componentSet.GetSparseSet()->SwapIndexHash(index, EntityHandleGenerator::GetIndex(hash)); + } + + /************************************************************************** + * \brief + * Swaps to positioning of two components in their dense array. + * This does not swap the entity that the components belong to. + * This swap using a component type ID + * \param index + * The entity Index of the first entity + * \param hash + * The entity ID of the second entity + * \param componentTypeID + * The Type ID of the component type ID + * \return + * + ***************************************************************************/ + static void SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept; + + + + /*!************************************************************************* + * \brief + * Removes and destroy all components tied to an entity. + * entityID + * \param entityID + * entityID of the entity to be removed. + ***************************************************************************/ + static void RemoveComponentsOfEntity(EntityID entityID) noexcept; + + + + /************************************************************************** + * \brief + * Get the number of components in a component sparse set. + * \param componentTypeID + * The type ID of the Component Type. + * \return + * The number of components in the component sparse set. + ***************************************************************************/ + static EntityIndex ComponentCount_ID(uint32_t componentTypeID) + { + return componentSet.GetSparseSet_ID(componentTypeID)->Count(); + } + + + /*!************************************************************************* + * \brief + * Set the isActive boolean of all Components that the entity has + * \param entityID + * The entityID of the entity + * \param active + * The active state to set to + ***************************************************************************/ + static void SetActive(EntityID entityID, bool active) noexcept; + + template + static std::enable_if_t<(... && std::is_base_of_v), uint32_t> CreateComponentGroup(uint32_t numOwningComponents) + { + std::vector templateIDs{ (SHFamilyID::GetID())... }; + + for (auto& g : componentGroups) + { + for (auto const& oID : g.ownedComponentTypes) + { + for (uint32_t i = 0; i < numOwningComponents; ++i) + { + if ((templateIDs[i] == oID)) + { + assert("This Component is owned by another group"); + } + } + } + } + + SHComponentGroup grp; + for (uint32_t i = 0; i < numOwningComponents; ++i) + { + grp.ownedComponentTypes.push_back(templateIDs[i]); + } + for (uint32_t i = 0; i < templateIDs.size(); ++i) + { + grp.componentTypeIDs.push_back(templateIDs[i]); + } + + if (grp.ownedComponentTypes.size() != grp.componentTypeIDs.size()) + { + if (grp.ownedComponentTypes.empty()) + { + grp.ownershipType = OWNERSHIP_TYPE::NON_OWNERSHIP; + } + else + { + grp.ownershipType = OWNERSHIP_TYPE::PARTIAL_OWNERSHIP; + } + } + + componentGroups.push_back(grp); + return (uint32_t)componentGroups.size() - 1; + + } + + /************************************************************************** + * \brief + * Get a reference to the component group. + * \param index + * The index of the component group + * \return + * A reference to the component group. + ***************************************************************************/ + static SHComponentGroup& GetComponentGroup(uint16_t index) noexcept + { + return componentGroups[index]; + } + + static void AddScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept; + + static void RemoveScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept; + + + };// end SHComponentManager + + + + + +} + + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp b/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp new file mode 100644 index 00000000..09fe368a --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp @@ -0,0 +1,232 @@ +/********************************************************************* + * \file SHEntityManager.cpp + * \author Daniel Chua Yee Chen + * \brief Implementation for the SHEntityManager class. + * Entity Manager is the interface class where users of the engine + * and its systems interact with entity data in the engine. This + * includes Creation and Destruction of entities and getting Entity by + * an ID. This manager also ensures that each entity have a unique + * handle using SHHandleGenerator. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ +//#include "SHpch.h" +#include "SHEntityManager.h" +//#include "Scene/SHSceneGraph.h" +//#include "Serialization/SHSerialization.h" + +namespace SHADE +{ + std::vector> SHEntityManager::entityVec; + EntityHandleGenerator SHEntityManager::entityHandle; + + SHEntity* SHEntityManager::GetEntityByID(EntityID entityID) noexcept + { + if (!IsValidEID(entityID)) + { + return nullptr; + } + + EntityIndex eIndex = entityHandle.GetIndex(entityID); + return entityVec[eIndex].get(); + + } + + bool SHEntityManager::IsValidEID(EntityID entityID) noexcept + { + if (!entityHandle.IsValid(entityID)) + return false; + + EntityIndex eIndex = entityHandle.GetIndex(entityID); + if (entityVec.size() <= eIndex || !entityVec[eIndex]) + return false; + + return true; + + } + + EntityIndex SHEntityManager::GetEntityIndex(EntityID entityID) noexcept + { + return entityHandle.GetIndex(entityID); + } + + EntityID SHEntityManager::CreateEntity(std::vectorconst& componentTypeIDs, std::string const& name,EntityID parentEID) + { + EntityID eID = entityHandle.GetNewHandle(); + EntityIndex eIndex = entityHandle.GetIndex(eID); + if (eIndex > entityVec.size()) + { + assert("FATAL ERROR: EntityIndex out of range in Entity Creation"); + } + else if (eIndex == entityVec.size()) + { + entityVec.emplace_back(std::make_unique()); + } + else + { + if (!entityVec[eIndex]) + { + //There is still an entity stored there.Something went wrong + assert("FATAL ERROR: Entity Creation error. Entity Index Conflict"); + } + + //Reset it to a newly constructed entity + entityVec[eIndex].reset(new SHEntity()); + } + + + entityVec[eIndex]->entityID = eID; + entityVec[eIndex]->name = name; + for (auto& id : componentTypeIDs) + { + SHComponentManager::AddComponent(eID, id); + } + + //(SHComponentManager::AddComponent(eID), ...); + /*if (entityHandle.IsValid(parentEID) == false) + { + entityVec[eIndex]->sceneNode.ConnectToRoot(); + } + else + { + entityVec[eIndex]->SetParent(parentEID); + }*/ + + + //TODO Link to Scene graph. + + return eID; + + } + + EntityID SHEntityManager::CreateEntity(std::vectorconst& componentTypeIDs, EntityID desiredEID, std::string const& name, EntityID parentEID) + { + EntityID eID ; + + if (entityHandle.ClaimHandle(desiredEID) == true) + eID = desiredEID; + else + eID = entityHandle.GetNewHandle(); + + + EntityIndex eIndex = entityHandle.GetIndex(eID); + if (eIndex > entityVec.size()) + { + EntityIndex size = (EntityIndex)entityVec.size(); + for (EntityIndex i = 0; i <= eIndex - size; ++i) + { + entityVec.push_back(nullptr); + + } + entityVec[eIndex].reset(new SHEntity()); + } + else if (eIndex == entityVec.size()) + { + entityVec.emplace_back(std::make_unique()); + } + else + { + if (!entityVec[eIndex]) + { + //There is still an entity stored there.Something went wrong + assert("FATAL ERROR: Entity Creation error. Entity Index Conflict"); + } + + //Reset it to a newly constructed entity + entityVec[eIndex].reset(new SHEntity()); + } + + + entityVec[eIndex]->entityID = eID; + entityVec[eIndex]->name = name; + for (auto& id : componentTypeIDs) + { + SHComponentManager::AddComponent(eID, id); + } + + //(SHComponentManager::AddComponent(eID), ...); + + //if (entityHandle.IsValid(parentEID) == false) + //{ + // entityVec[eIndex]->sceneNode.ConnectToRoot(); + //} + //else + //{ + // entityVec[eIndex]->SetParent(parentEID); + //} + + //TODO Link to scene graph. + + + return eID; + + } + + + void SHEntityManager::DestroyEntity(EntityID eID) noexcept + { + if (!IsValidEID(eID)) + { + //Entity does not exist or already destroyed. + return; + } + EntityIndex eIndex = entityHandle.GetIndex(eID); + + //Call all the children to Destroy themselves first before the parent is destroyed. + if (entityVec[eIndex]) + { + //auto& children = entityVec[eIndex]->GetChildrenID(); + //while(!children.empty()) + //{ + // DestroyEntity(children[0]); + //} + + //SHSceneNode* parentNode = entityVec[eIndex]->GetSceneNode()->GetParent(); + + //SHSceneGraph::RemoveChild(parentNode,entityVec[eIndex].get()); + + //TODO remove from parent and recursively delete child. + + + + SHComponentManager::RemoveComponentsOfEntity(eID); + + entityHandle.RemoveHandle(eID); + + entityVec[eIndex].reset(nullptr); + } + + } + + void SHEntityManager::DestroyAllEntity() noexcept + { + for (auto& entity : entityVec) + { + + if (entity) + { + DestroyEntity(entity->GetEID()); + } + } + entityHandle.ClearAllHandles(); + } + + EntityIndex SHEntityManager::GetEntityCount() noexcept + { + return entityHandle.GetActiveHandleCount(); + } + + + /*EntityID SHEntityManager::DuplicateEntity(EntityID eid) noexcept + { + if (entityHandle.IsValid(eid) == false) + return MAX_EID; + + std::string data = SHSerialization::SerializeEntityToString(eid); + return SHSerialization::DeserializeEntityToSceneFromString(data); + }*/ + + +} diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h b/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h new file mode 100644 index 00000000..11e896d5 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h @@ -0,0 +1,253 @@ +/********************************************************************* + * \file SHEntityManger.h + * \author Daniel Chua Yee Chen + * \brief Definition for the SHEntityManager class. + * Entity Manager is the interface class where users of the engine + * and its systems interact with entity data in the engine. This + * includes Creation and Destruction of entities and getting Entity by + * an ID. This manager also ensures that each entity have a unique + * handle using SHHandleGenerator. + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_ENTITY_MANAGER_H +#define SH_ENTITY_MANAGER_H + +#include +#include +#include "../Entity/SHEntity.h" +#include "../Components/SHComponent.h" +#include "../General/SHHandleGenerator.h" +#include "../SHECSMacros.h" + +namespace SHADE +{ + + class SHEntityManager + { + private: + static std::vector> entityVec; + //The handle generator to generate entityIDs. + static EntityHandleGenerator entityHandle; + + public: + SHEntityManager() = delete; + ~SHEntityManager() = delete; + + /************************************************************************** + * \brief + * Get a pointer to the entity using the entityID. + * \param entityID + * The entity ID of the entity + * \return + * A pointer to the entity. + * A nullptr is returned if there is no such entity or if it is destroyed. + ***************************************************************************/ + static SHEntity* GetEntityByID(EntityID entityID) noexcept; + + /************************************************************************** + * \brief + * Checks if the current Entity ID is in use and alive. + * \param entityID + * The entity ID of the entity + * \return + * true if the entity ID is in use and alive. + ***************************************************************************/ + static bool IsValidEID(EntityID entityID) noexcept; + + /************************************************************************** + * \brief + * Get the index portion of the Entity ID. + * \param entityID + * The entity ID of the entity + * \return + * The index of the entity + ***************************************************************************/ + static EntityIndex GetEntityIndex(EntityID entityID) noexcept; + + /************************************************************************** + * \brief + * Template function to Create a new Entity with Components specified + * by the template arguements. + * \param name + * Name of the entity (This is not unique) + * \param parentEID + * The entity ID of the parent. This does not call UpdateHierarchy hence + * the parent of the entity is not updated until UpdateHierarchy is called. + * \return + * EntityID of the new Entity + ***************************************************************************/ + template + static std::enable_if_t<(... && std::is_base_of_v), EntityID> CreateEntity(std::string const& name = "Default", EntityID parentEID = MAX_EID) + { + EntityID eID = entityHandle.GetNewHandle(); + EntityIndex eIndex = entityHandle.GetIndex(eID); + if (eIndex > entityVec.size()) + { + assert("FATAL ERROR: EntityIndex out of range in Entity Creation"); + } + else if (eIndex == entityVec.size()) + { + entityVec.emplace_back(std::make_unique()); + } + else + { + if (!entityVec[eIndex]) + { + //There is still an entity stored there.Something went wrong + assert("FATAL ERROR: Entity Creation error. Entity Index Conflict"); + } + + //Reset it to a newly constructed entity + entityVec[eIndex].reset(new SHEntity()); + } + entityVec[eIndex]->entityID = eID; + entityVec[eIndex]->name = name; + (SHComponentManager::AddComponent(eID),...); + + /*if (entityHandle.IsValid(parentEID) == false) + { + entityVec[eIndex]->sceneNode.ConnectToRoot(); + } + else + { + entityVec[eIndex]->SetParent(parentEID); + }*/ + + //TODO Link up with Scene graph + + return eID; + } + + template + static std::enable_if_t<(... && std::is_base_of_v), EntityID> CreateEntity(EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID) + { + EntityID eID; + if (entityHandle.ClaimHandle(desiredEID) == true) + eID = desiredEID; + else + eID = entityHandle.GetNewHandle(); + EntityIndex eIndex = entityHandle.GetIndex(eID); + if (eIndex > entityVec.size()) + { + EntityIndex size = (EntityIndex)entityVec.size(); + for (EntityIndex i = 0; i <= eIndex - size; ++i) + { + entityVec.push_back(nullptr); + + } + entityVec[eIndex].reset(new SHEntity()); + } + else if (eIndex == entityVec.size()) + { + entityVec.emplace_back(std::make_unique()); + } + else + { + if (!entityVec[eIndex]) + { + //There is still an entity stored there.Something went wrong + assert("FATAL ERROR: Entity Creation error. Entity Index Conflict"); + } + + //Reset it to a newly constructed entity + entityVec[eIndex].reset(new SHEntity()); + } + entityVec[eIndex]->entityID = eID; + entityVec[eIndex]->name = name; + (SHComponentManager::AddComponent(eID), ...); + + /*if (entityHandle.IsValid(parentEID) == false) + { + entityVec[eIndex]->sceneNode.ConnectToRoot(); + } + else + { + entityVec[eIndex]->SetParent(parentEID); + }*/ + + + //Link up with scene graph. + + + return eID; + } + + + + + /************************************************************************** + * \brief + * Create Entity using a vector of ComponentTypeIDs. + * \param componentTypeIDs + * Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called + * for these ComponentTypes. + * \param name + * Name of the Entity (this is not unique) + * \param parentEID + * The entity ID of the parent. This does not call UpdateHierarchy hence + * the parent of the entity is not updated until UpdateHierarchy is called. + * \return + * EntityID of the new Entity + ***************************************************************************/ + static EntityID CreateEntity(std::vectorconst& componentTypeIDs,std::string const& name = "Default", EntityID parentEID = MAX_EID); + + /************************************************************************** + * \brief + * Create Entity using a vector of ComponentTypeIDs. + * \param componentTypeIDs + * Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called + * for these ComponentTypes. + * \param name + * Name of the Entity (this is not unique) + * \param parentEID + * The entity ID of the parent. This does not call UpdateHierarchy hence + * the parent of the entity is not updated until UpdateHierarchy is called. + * \return + * EntityID of the new Entity + ***************************************************************************/ + static EntityID CreateEntity(std::vectorconst& componentTypeIDs, EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID); + + /************************************************************************** + * \brief + * Destroy the entity and all components tied to this entity. + * This calls Destroy Entity for all of its children as well. + * \param eID + * The entity ID of the entity + * \return + * none + ***************************************************************************/ + static void DestroyEntity(EntityID eID) noexcept; + + /************************************************************************** + * \brief + * Destroy all Entities. + * \return + * none + ***************************************************************************/ + static void DestroyAllEntity() noexcept; + + /************************************************************************** + * \brief + * Get the current number of entities. + * \return + * Number of entities. + ***************************************************************************/ + static EntityIndex GetEntityCount() noexcept; + + //static EntityID DuplicateEntity(EntityID eid) noexcept; + + protected: + + + }; + + +} + + + +#endif diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h new file mode 100644 index 00000000..1a304605 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h @@ -0,0 +1,55 @@ +/********************************************************************* + * \file SHSystem.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the SHSytem abstract base class + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + +#ifndef SH_SYSTEM_H +#define SH_SYSTEM_H + +namespace SHADE +{ + class SHSystem + { + protected: + /*!************************************************************************* + * \brief + * Protected default constructor for SHSytem class + ***************************************************************************/ + SHSystem()= default; + + public: + /*!************************************************************************* + * \brief + * Destructor for SHSytem class + ***************************************************************************/ + virtual ~SHSystem() = default; + + /*!************************************************************************* + * \brief + * Pure virtual Init function. Derived class must implement this + ***************************************************************************/ + virtual void Init() = 0; + + /*!************************************************************************* + * \brief + * Pure virtual Run function. Derived class must implement this + * \param dt + * Delta time + ***************************************************************************/ + virtual void Run(float dt) = 0; + + /*!************************************************************************* + * \brief + * Pure virtual Exit function. Derived class must implement this + ***************************************************************************/ + virtual void Exit() = 0; + + }; +} + +#endif \ No newline at end of file diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp new file mode 100644 index 00000000..0a6a7be5 --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp @@ -0,0 +1,57 @@ +/********************************************************************* + * \file SHSystemManager.cpp + * \author Daniel Chua Yee Chen + * \brief Implementation for the SHSystemManager class. + * SHSystemManager is the interface class where users of the engine create + * the systems that gives the components their functionality. This also + * ensures that the Init and Exit functions are ran at the appropriate time + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ +//#include "SHpch.h" +#include "SHSystemManager.h" +#include + +namespace SHADE +{ + SHSystemManager::SystemContainer SHSystemManager::systemContainer; + + + SHSystem* SHSystemManager::GetSystem(std::string name) + { + if (systemContainer.find(name) == systemContainer.end()) + { + assert("Get System Error: No system with such name exist."); + return nullptr; + } + + return systemContainer.find(name)->second.get(); + } + + void SHSystemManager::Init() noexcept + { + for (auto& system : systemContainer) + { + system.second->Init(); +#ifdef _DEBUG + std::cout << system.first << " Init" << std::endl; +#endif + } + } + + void SHSystemManager::Exit() noexcept + { + for (auto& system : systemContainer) + { + system.second->Exit(); + //delete system.second; + } + + systemContainer.clear(); + + } + + +} diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h new file mode 100644 index 00000000..d5a4866d --- /dev/null +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h @@ -0,0 +1,102 @@ +/********************************************************************* + * \file SHSystemManager.h + * \author Daniel Chua Yee Chen + * \brief Declaration for the SHSystemManager class. + * SHSystemManager is the interface class where users of the engine create + * the systems that gives the components their functionality. This also ensures that the Init and Exit functions are ran at the appropriate time + * + * \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction + or disclosure of this file or its contents without the prior written + consent of DigiPen Institute of Technology is prohibited. + *********************************************************************/ + + +#ifndef SH_SYSTEM_MANAGER_H +#define SH_SYSTEM_MANAGER_H + + +#include +#include +#include +#include +#include "../System/SHSystem.h" + + +namespace SHADE +{ + + class SHSystemManager + { + //type definition for the container we use to store our system + using SystemContainer = std::unordered_map>; + + private: + static SystemContainer systemContainer; + + + public: + /*!************************************************************************* + * This class is used as a static class. + * No objects of this type should be created + ***************************************************************************/ + SHSystemManager() = delete; + ~SHSystemManager() = delete; + + /************************************************************************** + * \brief + * Create a system of type T and map it to a name. + * throws an error if a system with the same name already exists. + * \param name + * name of the system + * \return + * none + ***************************************************************************/ + template + static std::enable_if_t, void> CreateSystem(std::string const& name) + { + if (systemContainer.find(name) != systemContainer.end()) + { + assert("System Creation Error: System with the same name already exist."); + } + + systemContainer.emplace(name, std::make_unique()); + + + } + + /************************************************************************** + * \brief + * Get a pointer to the System with a specified name. + * \param name + * Name of the system in the map + * \return + * Base System pointer. + ***************************************************************************/ + static SHSystem* GetSystem(std::string name); + + /************************************************************************** + * \brief + * Call the Init function of all systems. + * \return + * none + ***************************************************************************/ + static void Init() noexcept; + + /************************************************************************** + * \brief + * Call the Exit function of all systems. + * \return + ***************************************************************************/ + static void Exit() noexcept; + + + protected: + + + }; + +} + + + +#endif From cfa7bb812a6face0b8a8928728cf6486fa6f8877 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Thu, 8 Sep 2022 11:15:43 +0800 Subject: [PATCH 2/2] #comment initial commit added use of SHpch --- SHADE_Engine/SHADE_Engine.vcxproj | 19 +++++++++++++++++++ SHADE_Engine/SHADE_Engine.vcxproj.filters | 19 +++++++++++++++++++ .../ECS_Base/Components/SHComponent.cpp | 2 +- .../Engine/ECS_Base/Components/SHComponent.h | 1 + .../ECS_Base/Components/SHComponentGroup.cpp | 2 +- .../src/Engine/ECS_Base/Entity/SHEntity.cpp | 4 +++- .../ECS_Base/System/SHComponentManager.cpp | 2 +- .../ECS_Base/System/SHEntityManager.cpp | 2 +- .../ECS_Base/System/SHSystemManager.cpp | 2 +- 9 files changed, 47 insertions(+), 6 deletions(-) diff --git a/SHADE_Engine/SHADE_Engine.vcxproj b/SHADE_Engine/SHADE_Engine.vcxproj index d89ec12a..f10ed0e7 100644 --- a/SHADE_Engine/SHADE_Engine.vcxproj +++ b/SHADE_Engine/SHADE_Engine.vcxproj @@ -102,10 +102,29 @@ + + + + + + + + + + + + + + + + + + + Create diff --git a/SHADE_Engine/SHADE_Engine.vcxproj.filters b/SHADE_Engine/SHADE_Engine.vcxproj.filters index b16c713b..b4a61bae 100644 --- a/SHADE_Engine/SHADE_Engine.vcxproj.filters +++ b/SHADE_Engine/SHADE_Engine.vcxproj.filters @@ -10,11 +10,30 @@ Engine + + + + + + + + + + + + + Engine + + + + + + \ No newline at end of file diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp index e5c640ef..b544df72 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp @@ -1,4 +1,4 @@ -//#include "SHpch.h" +#include "SHpch.h" #include "SHComponent.h" namespace SHADE diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h index d3def014..c9c5e6f1 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h @@ -12,6 +12,7 @@ #ifndef SH_COMPONENT_H #define SH_COMPONENT_H +#include "SHpch.h" #include "../SHECSMacros.h" namespace SHADE diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp index 292fbe71..3ccb7778 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp +++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp @@ -12,7 +12,7 @@ consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ -//#include "SHpch.h" +#include "SHpch.h" #include "SHComponentGroup.h" #include "../System/SHComponentManager.h" diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp index 5d25c9ec..6005fb01 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp +++ b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp @@ -7,7 +7,7 @@ or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ -//#include "SHpch.h" +#include "SHpch.h" #include "SHEntity.h" #include "../System/SHEntityManager.h" //#include "Scene/SHSceneGraph.h" @@ -43,11 +43,13 @@ namespace SHADE void SHEntity::SetParent(SHEntity* newParent) noexcept { + (void)newParent; //TODO } void SHEntity::SetParent(EntityID newParentID) noexcept { + (void)newParentID; //TODO } diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp b/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp index 5bbb71ab..be78a146 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp @@ -10,7 +10,7 @@ or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ -//#include "SHpch.h" +#include "SHpch.h" #include "SHComponentManager.h" #include "SHEntityManager.h" #include "SHSystemManager.h" diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp b/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp index 09fe368a..4aa38112 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp @@ -12,7 +12,7 @@ or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ -//#include "SHpch.h" +#include "SHpch.h" #include "SHEntityManager.h" //#include "Scene/SHSceneGraph.h" //#include "Serialization/SHSerialization.h" diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp index 0a6a7be5..67d6f781 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp +++ b/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp @@ -10,7 +10,7 @@ or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ -//#include "SHpch.h" +#include "SHpch.h" #include "SHSystemManager.h" #include