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
new file mode 100644
index 00000000..b544df72
--- /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..c9c5e6f1
--- /dev/null
+++ b/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h
@@ -0,0 +1,121 @@
+/*********************************************************************
+ * \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 "SHpch.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..3ccb7778
--- /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..6005fb01
--- /dev/null
+++ b/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp
@@ -0,0 +1,74 @@
+/*********************************************************************
+ * \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
+ {
+ (void)newParent;
+ //TODO
+ }
+
+ void SHEntity::SetParent(EntityID newParentID) noexcept
+ {
+ (void)newParentID;
+ //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..be78a146
--- /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..4aa38112
--- /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..67d6f781
--- /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