1#include "EntityStore.h"
3#include "Systems/Core/TransformSystem.h"
5#include "Components/Core/RenderComponent.h"
7#include "Systems/Core/SceneSystem.h"
9#include "Services/DeferredNameResolution.h"
11#include "EntityDefinitions.h"
13#include "MemoryContext.h"
15#include "Serialization/AssetReader.h"
17#include "Foundation/Logging/Logger.h"
18#include "Foundation/HashFunctions.h"
19#include "Foundation/Reflection/TypeDatabase.h"
31 entityPool(8192, 8192, context->memory->baseAllocator, MemBlockType::
Entity),
32 entityDataPool(MemBlockType::
Entity)
34 LOG_TRACE(logger,
"Initializing entity store...");
36 this->context = context;
38 LOG_TRACE(logger,
"Initializing entity definitions...");
42 LOG_TRACE(logger,
"Entity definitions initialized.");
47 LOG_DEBUG(logger,
"Cleaning up entities...");
49 entitiesByName.clear();
52 if (entityPool.size()) {
53 LOG_WARNING(logger,
"%zd entities allocated after clear. First N(6) from default scene", entityPool.size());
56 LOG_DEBUG(logger,
"Entity store cleaned up.");
63 if (entityDefinitions.contains(hashCode)) {
64 LOG_WARNING(logger,
"Overwriting existing entity definition for %s.", definition.
name.c_str());
66 LOG_TRACE(logger,
"Adding entity definition for %s.", definition.
name.c_str());
68 entityDefinitions[hashCode] = definition;
74 names.reserve(entityDefinitions.size());
75 for (
const auto & [_, def] : entityDefinitions) {
76 names.emplace_back(def.name);
83 if (
auto * def = getEntityDefinition(name); def) {
84 components.reserve(def->components.size());
85 for (
auto & c : def->components) {
86 components.emplace_back(c);
99 auto fIt = entityDefinitions.find(
id);
101 return fIt != entityDefinitions.end() ? &fIt->second :
nullptr;
106 auto entityPtr = entityPool.create();
107 auto entityData = entityDataPool.create();
110 this->destroyEntityComponents(e);
114 entityPool.destroy(e);
118 auto entityId = entityPool.getHandle(entityPtr);
120 entity->setId(entityId);
122 if (storeOwnership) {
123 entities[entityId] = entity;
127 context->deferredResolution->scheduleRescan();
128 entity->setName(name);
130 if (storeOwnership) {
131 storeNamedEntity(entity, name);
137 entityData->templateId = typeCode;
138 entity->setUserData(entityData);
140 auto definitionIt = entityDefinitions.find(typeCode);
142 if (definitionIt != entityDefinitions.end()) {
143 auto & entityDefinition = definitionIt->second;
145 createEntityComponents(entityDefinition, entity);
149 LOG_WARNING(logger,
"Could not find entity definition for type: %.*s, name:%.*s. No components will be added.", StringViewFormat(type), StringViewFormat(name));
158 createEntities(count, entities, [&](
Entity * e)
160 this->destroyEntityComponents(e);
164 entityPool.destroy(e);
170 entities.resize(count);
173 Entity* entityPtr = entityPool.create();
174 EntityData* entityData = entityDataPool.create();
177 entity =
EntityPtr(entityPtr, destructor);
178 auto entityId = entityPool.getHandle(entityPtr);
180 entity->setId(entityId);
184void Cogs::Core::EntityStore::createEntityComponents(EntityDefinition & entityDefinition,
const EntityPtr & entity)
186 if (!entityDefinition.compiled) {
187 compileEntityDefinition(entityDefinition);
190 for (
auto creator : entityDefinition.creators) {
191 auto component = (*creator)();
193 if (component.resolve()) {
194 entity->addComponent(component);
196 LOG_ERROR(logger,
"Null component returned by system creator.");
201void Cogs::Core::EntityStore::compileEntityDefinition(EntityDefinition & entityDefinition)
203 for (
const std::string& componentName : entityDefinition.components) {
207 LOG_ERROR(logger,
"Type \"%s\" not valid as component.", componentName.c_str());
211 auto creatorIt = creators.find(type.
getTypeId());
213 if (creatorIt != creators.end()) {
214 entityDefinition.creators.push_back(&creators[type.
getTypeId()]);
216 LOG_ERROR(logger,
"No creator function available for components of type %s.", componentName.c_str());
220 entityDefinition.compiled =
true;
225 debug_assert(parent &&
"Invalid parent entity pointer.");
226 debug_assert(entity &&
"Invalid entity cannot be parented.");
227 if (!parent || !entity)
return;
232 bool noTransform =
false;
233 bool noScene =
false;
235 if (transform && parentTransform) {
236 transform->
parent = context->transformSystem->getHandle(parentTransform);
239 context->transformSystem->updateTransformData(*transform);
247 if (sceneComponent && parentSceneComponent) {
248 parentSceneComponent->
children.push_back(entity);
251 sceneComponent->
parent = context->sceneSystem->getHandle(parentSceneComponent);
252 SceneSystem::updateState(*sceneComponent);
257 if (noTransform && noScene) {
258 std::string pid = parent->
getName().empty() ? std::to_string(parent->
getId()) : parent->
getName();
259 std::string cid = entity->getName().empty() ? std::to_string(entity->getId()) : entity->getName();
260 LOG_WARNING(logger,
"addChild failed: Both parent and child must have Scene and Transform components: Parent:%s Child:%s.", pid.c_str(), cid.c_str());
266 addChild(getEntityPtr(parent), getEntity(child));
271 auto & creator = creators[typeId];
275 auto * compPtr = component.resolve();
279 LOG_ERROR(logger,
"Could not create component with type id %d.", typeId);
293 auto component = handle.
resolve();
296 LOG_ERROR(logger,
"Cannot remove empty component handle.");
302 auto & destroyer = destroyers[component->getTypeId()];
304 if (destroyer) destroyer(handle);
310 LOG_ERROR(logger,
"Cannot remove child from null entity.");
315 LOG_ERROR(logger,
"Cannot remove null child from parent.");
323 transform->setChanged();
328 if (!sceneComponent) {
329 LOG_ERROR(logger,
"Cannot remove child from parent without SceneComponent.");
333 auto it = std::find_if(sceneComponent->children.begin(),
334 sceneComponent->children.end(),
335 [=](
const EntityPtr & e) { return e.get() == entity; });
337 if (it != sceneComponent->children.end()) {
338 sceneComponent->children.erase(it);
341 sceneComponent->setChanged();
347 LOG_ERROR(logger,
"Cannot remove children from null entity.");
353 if (!sceneComponent) {
358 for (
auto & child : sceneComponent->children) {
361 if (childTransform) {
363 childTransform->setChanged();
368 if (childSceneComponent) {
369 childSceneComponent->
parent = {};
373 sceneComponent->children.clear();
374 sceneComponent->setChanged();
379 Entity* oldParent = context->store->getEntityParent(child);
380 if (oldParent !=
nullptr && parent ==
nullptr) {
384 removeChild(oldParent, child);
385 if (!entities.contains(child->
getId())) {
386 entities[child->
getId()] = childPtr;
387 storeNamedEntity(childPtr, child->
getName());
390 else if (oldParent !=
nullptr && parent !=
nullptr) {
394 removeChild(oldParent, child);
395 addChild(parent, childPtr);
397 else if (oldParent ==
nullptr && parent !=
nullptr) {
400 destroyEntity(childPtr->getId());
401 addChild(parent, childPtr);
409 auto entityIt = entities.find(
id);
411 if (entityIt != entities.end()) {
412 auto entity = entityIt->second;
414 assert(entity->
getId() ==
static_cast<size_t>(
id) &&
"Registered id does not match internal entity id. Entity store corrupted.");
425 LOG_WARNING(logger,
"Could not erase entity with id %zu. No such entity found in store.",
size_t(
id));
429void Cogs::Core::EntityStore::destroyEntityComponents(
Entity * entity)
432 const Component* component = c.resolve();
434 assert(destroyers.contains(component->
getTypeId()) &&
"No system registered to handle given type.");
440EntityId Cogs::Core::EntityStore::getNextEntityId()
442 static EntityId entityId = 0;
451 auto it = entities.find(entityId);
452 if (it != entities.end()) {
456 if (!onlyRegistered) {
457 for (
const auto& [_, child] : entities) {
458 EntityPtr output = findEntity(entityId, child.get());
466 LOG_ERROR(logger,
"getEntity - unknown Id: %zu",
static_cast<size_t>(entityId));
474 auto it = entitiesByName.find(
Cogs::hash(name));
476 if (it == std::end(entitiesByName)) {
478 LOG_WARNING(logger,
"No entity named '%.*s' found.", StringViewFormat(name));
485 LOG_ERROR(logger,
"Internal Error: Entity erased without removing entry in 'entitiesByName'.");
489 else if (
StringView(ptr->getName()) != name) {
490 LOG_ERROR(logger,
"getEntity: Entity with name: '%s' vs '%.*s' duplicate hash in store.", ptr->getName().c_str(), StringViewFormat(name));
502 if (!sceneComponent) {
508 if (name == child->getName()) {
513 if (child->getName().find(std::string_view(name)) != std::string::npos) {
519 EntityPtr found = findEntity(name, child.get(), find);
528 EntityPtr entity = getEntity(name,
false);
532 if (getEntityParent(entity.get()) ==
nullptr) {
541 for (
const auto& [_, child] : entities) {
546 if (name == child->getName()) {
551 if (child->getName().find(std::string_view(name)) != std::string::npos) {
557 EntityPtr found = findEntity(name, child.get(), find);
574 if (sceneComponent) {
576 if (entityId ==
static_cast<EntityId
>(child->getId())) {
581 output = findEntity(entityId, child.get());
595 if (transformComponent) {
596 auto* parentTransform = transformComponent->
parent.
resolve();
597 if (parentTransform) {
598 auto parent = parentTransform->getContainer();
608 auto it = entities.find(entityPtr->
getId());
609 if (it == entities.end()) {
614 if (!entityPtr->
getName().empty()) {
617 auto oldIt = entitiesByName.find(oldHashCode);
618 if (oldIt == entitiesByName.end()) {
619 LOG_WARNING(logger,
"renameEntity: Failed old name lookup: '%s' in store.", entityPtr->
getName().c_str());
622 entitiesByName.erase(oldIt);
627 storeNamedEntity(it->second, name);
633 context->deferredResolution->scheduleRescan();
641 for (
auto& e : entities) {
642 result += dumpHierarchy(e.second.get());
648 std::string newprefix = prefix +
" ";
652 result.reserve(4000);
654 result += parent->
getName().empty() ?
"<unnamed entity>" : parent->
getName().c_str();
656 if (components.
size()) {
657 const char* sep =
" [";
672 if (sceneComponent) {
674 result += dumpHierarchy(child.get(), newprefix);
683 if (entityId == NoEntity) {
688 LOG_ERROR(logger,
"getEntityPtr: EntityHandle out of range: %zd.",
static_cast<size_t>(entityId));
695 return (entity &&
static_cast<EntityId
>(entity->
getId()) == entityId) ? entity :
nullptr;
700 creators[typeId] = creator;
701 destroyers[typeId] = destroyer;
709 LOG_ERROR(logger,
"Cannot add system using uninitialized type id (Reflection::NoType).");
724 systems[typeId] = system;
725 addSystem(typeId, creator, destroyer);
730 auto entity = createEntity(name, type,
false);
732 addChild(parent, entity);
737void Cogs::Core::EntityStore::getEntitiesWithComponent(std::vector<EntityId>& entities,
Reflection::TypeId componentTypeId)
740 if (
auto it = systems.find(componentTypeId); it != systems.end()) {
741 it->second->addEntitiesWithComponent(entities, componentTypeId);
749 const auto it = entitiesByName.find(hashCode);
750 if (it != entitiesByName.end()) {
751 const EntityPtr oldEntityPtr = it->second.lock();
753 LOG_ERROR(logger,
"Expired Entity with name: '%.*s' in store. Replaced.", StringViewFormat(name));
754 entitiesByName[hashCode] = entity;
756 else if (name == oldEntityPtr->getName())
757 LOG_WARNING_ONCE(logger,
"Entity with name: '%.*s' already exists in store.", StringViewFormat(name));
759 LOG_ERROR(logger,
"Entity with name: '%s' vs '%.*s' duplicate hash in store.", oldEntityPtr->getName().c_str(), StringViewFormat(name));
762 entitiesByName[hashCode] = entity;
A collection of components, held by component handles.
size_t size() const
Get the size of the collection.
Base class for Component instances.
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
ComponentType * getComponent() const
constexpr Reflection::TypeId getTypeId() const
Get the Reflection::TypeId of the component.
Container for components, providing composition of dynamic entities.
void removeComponent(ComponentHandle component)
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
constexpr size_t getId() const noexcept
Get the unique identifier of this entity.
constexpr void setId(const size_t id) noexcept
void getComponents(ComponentCollection< T > &collection) const
Get all the components implementing the templated type.
const std::string & getName() const noexcept
Get the name of this entity.
constexpr void * getUserData() const noexcept
Get user data.
constexpr void setUserData(void *userData) noexcept
void addComponent(ComponentHandle component)
void setName(const StringView &name)
Base class for component systems.
virtual ComponentHandle createComponent()
Create a new component instance.
Reflection::TypeId getComponentType() const
Get the reflected type of the components managed by this system.
virtual void destroyComponent(ComponentHandle)
Destroy the component held by the given handle.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
EntityPtr getEntity(const StringView &name, bool logIfNotFound=true) const
Retrieve a reference to the shared entity pointer to the Entity with the given name.
EntityStore(Context *context)
Construct the store with the given context instance.
ComponentModel::Component * addComponent(ComponentModel::Entity *entity, Reflection::TypeId typeId)
Add a component of the given type to the entity.
void addChild(ComponentModel::Entity *parent, const EntityPtr &entity)
Add a child to the given parent.
void renameEntity(ComponentModel::Entity *entityPtr, StringView name)
Rename the given entity.
void getEntityDefinitionComponents(std::vector< StringView > &components, const StringView &name) const
Get components of a known entity definition.
std::string dumpHierarchy() const
Generates a debug dump of the entire entity hierarchy.
void clear()
Clear out all top level entities owned by the store.
void addSystem(const Reflection::TypeId typeId, ComponentCreator creator, ComponentDestroyer destroyer)
Adds the given creator and destroyer functions for handling components of the given typeId.
void removeChildren(ComponentModel::Entity *entity)
Removes all children from the given entity.
const EntityDefinition * getEntityDefinition(const StringView &name) const
Fetch the entity definition with the given name from the store.
ComponentModel::Entity * getEntityPtr(const EntityId entityId)
Get a raw pointer to the entity with the given id.
void destroyEntity(const EntityId id)
Destroy the entity with the given id.
Cogs::ComponentModel::Entity * getEntityParent(const ComponentModel::Entity *entity) const
Gets the parent of the given entity.
void setEntityParent(ComponentModel::Entity *parent, ComponentModel::Entity *child)
Move Root entity to a parent: Equal to addChild(parent, child) + destroyEntity(child) Move Child enti...
EntityPtr createChildEntity(const StringView &type, ComponentModel::Entity *parent, const StringView &name=StringView())
Create a new Entity, parenting it to the given parent.
EntityPtr createEntity(const StringView &name, const StringView &type, bool storeOwnership=true)
Create a new Entity.
void addEntityDefinition(const EntityDefinition &definition)
Add the given entity definition to the store.
void removeChild(ComponentModel::Entity *parent, const ComponentModel::Entity *entity)
Remove the parent-child relationship between parent and entity.
EntityPtr findEntity(const StringView &name, const ComponentModel::Entity *root=nullptr, EntityFind findOptions=EntityFind::Default) const
Finds an entity with the given name.
void getEntityDefinitions(std::vector< StringView > &names) const
Get names of currently known entity definitions.
void createEntities(size_t count, std::vector< EntityPtr > &entities)
Allocates and initializes a collection of empty entities.
Contains information on how the entity behaves in the scene.
std::vector< EntityPtr > children
Contains all child entities owned by this component.
ComponentModel::ComponentHandle parent
Handle to the scene component of the parent entity.
Log implementation class.
static const Type & getType()
Get the Type of the given template argument.
Represents a discrete type definition, describing a native type class.
constexpr const Name & getName() const
Get the unique name of the type.
constexpr bool isValid() const
Gets if the type is considered a valid, registered type.
constexpr TypeId getTypeId() const
Get the unique Reflection::TypeId of this instance.
Provides a weakly referenced view over the contents of a string.
constexpr size_t size() const noexcept
Get the size of the string.
constexpr bool empty() const noexcept
Check if the string is empty.
uint32_t ElementHandle
Handle type for elements.
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
void applyFieldValues(class Context *context, std::span< FieldValue > entityDefinition, ComponentModel::Entity *entity)
Apply defaults from the given entityDefinition to the given entity.
void COGSCORE_DLL_API createDefaultEntityDefinitions(class EntityStore *entityStore)
Create the default entity definitions supported by Cogs.
EntityFind
Options to findEntity/getEntityFull.
@ NonRecursive
Do not search recursively.
@ PartialNameMatch
Search for the first entity that partially contains the specified name.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains reflection support.
uint16_t TypeId
Built in type used to uniquely identify a single type instance.
constexpr TypeId NoType
Definition of no type.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Handle to a Component instance.
COGSFOUNDATION_API class Component * resolve() const
Resolve the handle, returning a pointer to the held Component instance.
static ComponentHandle Empty()
Returns an empty, invalid handle. Will evaluate to false if tested against using operator bool().
Holds extra housekeeping data for an Entity instance.
Defines how to construct entities of a certain type by a list of components to instantiate and defaul...
const std::string & getName() const
Get the string name. This can be empty, even in valid instances of Name.