/* This file is part of Daydream Engine. Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung Daydream Engine is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Daydream Engine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Daydream Engine. If not, see . */ #ifndef World_h__ #define World_h__ #include #include #include #include #include #include #include #include #include "Util/Factory.h" #include "Entity.h" #include "Component.h" #include "System.h" #include "EventBroker.h" #include "EComponentCreated.h" #include "ResourceManager.h" namespace dd { /** The entity manager. Governs over the lifetime of entities. */ class World { public: World(std::shared_ptr eventBroker) : EventBroker(eventBroker) , m_LastEntityID(0) { } ~World() { } /** Initialize the world. */ virtual void Initialize(); /** Register world systems. Called by Initialize. Implemented to register systems with the systemfactory before adding them to the world. */ virtual void RegisterSystems() {} /** Add systems to the world. Called by Initialize. Implemented to fill the world with the desired systems. */ virtual void AddSystems() {} /** Register components with the world. Implemented to register World-global components. @deprecated Components are now registered through individual Systems. */ // TODO: Get rid of this virtual void RegisterComponents() {} /** Add a system to the World */ template void AddSystem() { m_Systems[typeid(T).name()] = std::shared_ptr(SystemFactory.Create()); } /** Fetch a system by type. @tparam T The type of the system to fetch. */ template std::shared_ptr GetSystem(); /** Creates an empty entity. @param parent The parent of the entity. */ EntityID CreateEntity(EntityID parent = 0); /** Recursively clones an entity and all of its components and children. @param entity The entity to clone. @param parent The new parent of the clone. */ EntityID CloneEntity(EntityID entity, EntityID parent = 0); /** Removes an entity and all its children from the world. */ void RemoveEntity(EntityID entity); /** Check if an entity is valid and exists in the world. Returns FALSE if the entity doesn't exist or is in queue to be removed. @returns Whether the entity exists or not. */ bool ValidEntity(EntityID entity); /** Get the parent of an entity. */ EntityID GetEntityParent(EntityID entity); /** Get the top level parent of an entity. Gets the top level parent of an entity. Loops through the scene graph to find the first entity with the world as its parent. */ EntityID GetEntityBaseParent(EntityID entity); /** Get the children of an entity. @returns A list of entities parented to this entity. */ std::list GetEntityChildren(EntityID entity); /** Set the parent of an entity. @param entity The entity to reparent. @param newParent The new parent of the entity. */ void SetEntityParent(EntityID entity, EntityID newParent); /** Get a property field of an entity by name. @tparam T The type of the property. @param entity The entity. @param property The name of the property to fetch. */ template T GetProperty(EntityID entity, std::string property) { if(m_EntityProperties.find(entity) == m_EntityProperties.end()) return T(); if(m_EntityProperties[entity].find(property) == m_EntityProperties[entity].end()) return T(); return boost::any_cast(m_EntityProperties[entity][property]); } /** Set a property field of an entity. @param entity The entity. @param property The name of the property to set. @param value The value of the property. */ void SetProperty(EntityID entity, std::string property, boost::any value) { m_EntityProperties[entity][property] = value; } /** Set a string property field of an entity. Helper function to be able to set string properties easier. @param entity The entity. @param property The name of the property to set. @param value The value of the property. */ void SetProperty(EntityID entity, std::string property, char* value) { m_EntityProperties[entity][property] = std::string(value); } /** Create and attach component to an entity. @tparam T The type of component to attach. @param entity The entity to attach the component to. @returns The newly attached component. */ template std::shared_ptr AddComponent(EntityID entity); /** Remove a component from an entity. @tparam T The type of the component to remove. @param entity The entity to remove the component from. */ template void RemoveComponent(EntityID entity); /** Fetch a component of an entity. @tparam T The type of component to fetch. @param entity The entity to fetch the component from. */ template T* GetComponent(EntityID entity); // Triggers commit events in systems // TODO: Replace completely by EComponentCreated? void CommitEntity(EntityID entity); /** Get all components of a specific type. @tparam T The type of component to query. @returns A list of components of type T in the World. */ template std::list>* GetComponentsOfType(); /*std::vector GetEntityChildren(EntityID entity);*/ /** Moves the world simulation forward one tick. @param dt Time since last frame in seconds. */ virtual void Update(double dt); // Recursively update through the scene graph // TODO: Private? void RecursiveUpdate(std::shared_ptr system, double dt, EntityID parentEntity); /** Fetch the scene graph. @returns An std::unordered_map of entities to their parents. */ std::unordered_map* GetEntities() { return &m_EntityParents; } dd::SystemFactory SystemFactory; dd::ComponentFactory ComponentFactory; protected: std::shared_ptr EventBroker; std::shared_ptr ResourceManager; std::unordered_map> m_Systems; EntityID m_LastEntityID; std::stack m_RecycledEntityIDs; std::unordered_map m_EntityParents; // child -> parent std::unordered_map> m_EntityChildren; // parent -> child std::unordered_map> m_EntityProperties; std::unordered_map>> m_ComponentsOfType; std::unordered_map>> m_EntityComponents; // Internal: Add a component to an entity void AddComponent(EntityID entity, std::string componentType, std::shared_ptr component); std::set m_EntitiesToRemove; void ProcessEntityRemovals(); EntityID GenerateEntityID(); void RecycleEntityID(EntityID id); }; template std::list>* World::GetComponentsOfType() { const char* componentType = typeid(T).name(); auto it = m_ComponentsOfType.find(componentType); if (it == m_ComponentsOfType.end()) return nullptr; return &it->second; } template std::shared_ptr World::GetSystem() { const char* systemType = typeid(T).name(); if (m_Systems.find(systemType) == m_Systems.end()) { LOG_WARNING("Tried to get pointer to unregistered system \"%s\"!", systemType); return nullptr; } return std::static_pointer_cast(m_Systems.at(systemType)); } template std::shared_ptr World::AddComponent(EntityID entity) { const char* componentType = typeid(T).name(); std::shared_ptr component = std::shared_ptr(static_cast(ComponentFactory.Create())); if (component == nullptr) { LOG_ERROR("Failed to attach invalid component \"%s\" to entity #%i", componentType, entity); return nullptr; } AddComponent(entity, componentType, component); return component; } template void World::RemoveComponent(EntityID entity) { const char* componentType = typeid(T).name(); auto it = m_EntityComponents[entity].find(componentType); if (it == m_EntityComponents[entity].end()) return; auto component = it->second; component->Entity = 0; m_ComponentsOfType[componentType].remove(component); m_EntityComponents[entity].erase(it); for (auto pair : m_Systems) { auto system = pair.second; system->OnComponentRemoved(entity, componentType, component.get()); } } template T* World::GetComponent(EntityID entity) { auto components = m_EntityComponents[entity]; auto it = components.find(typeid(T).name()); if (it != components.end()) { return static_cast(it->second.get()); } else { return nullptr; } } } #endif // World_h__