Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/system/ComponentManager.h
Show All 15 Lines | |||||
*/ | */ | ||||
#ifndef INCLUDED_COMPONENTMANAGER | #ifndef INCLUDED_COMPONENTMANAGER | ||||
#define INCLUDED_COMPONENTMANAGER | #define INCLUDED_COMPONENTMANAGER | ||||
#include "ps/Filesystem.h" | #include "ps/Filesystem.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "simulation2/helpers/Player.h" | #include "simulation2/helpers/Player.h" | ||||
#include "simulation2/components/CCmpCinemaManager.h" | |||||
#include "simulation2/components/CCmpCommandQueue.h" | |||||
#include "simulation2/components/CCmpObstructionManager.h" | |||||
#include "simulation2/components/CCmpTemplateManager.h" | |||||
#include "simulation2/components/CCmpParticleManager.h" | |||||
#include "simulation2/components/CCmpPathfinder_Common.h" | |||||
#include "simulation2/components/CCmpProjectileManager.h" | |||||
#include "simulation2/components/CCmpRangeManager.h" | |||||
#include "simulation2/components/CCmpSoundManager.h" | |||||
#include "simulation2/components/CCmpTerrain.h" | |||||
#include "simulation2/components/CCmpTerritoryManager.h" | |||||
#include "simulation2/components/CCmpUnitMotionManager.h" | |||||
#include "simulation2/components/CCmpUnitRenderer.h" | |||||
#include "simulation2/components/CCmpWaterManager.h" | |||||
#include "simulation2/system/Components.h" | #include "simulation2/system/Components.h" | ||||
#include "simulation2/system/Entity.h" | #include "simulation2/system/Entity.h" | ||||
#include "simulation2/system/IComponent.h" | #include "simulation2/system/IComponent.h" | ||||
#include <boost/random/linear_congruential.hpp> | #include <boost/random/linear_congruential.hpp> | ||||
#include <map> | #include <map> | ||||
#include <optional> | |||||
#include <set> | #include <set> | ||||
#include <unordered_map> | #include <unordered_map> | ||||
class IComponent; | class IComponent; | ||||
class CParamNode; | class CParamNode; | ||||
class CMessage; | class CMessage; | ||||
class CSimContext; | class CSimContext; | ||||
class CDynamicSubscription; | class CDynamicSubscription; | ||||
class SystemComponents; | |||||
class CComponentManager | class CComponentManager | ||||
{ | { | ||||
NONCOPYABLE(CComponentManager); | NONCOPYABLE(CComponentManager); | ||||
public: | public: | ||||
// We can't use EInterfaceId/etc directly, since scripts dynamically generate new IDs | // We can't use EInterfaceId/etc directly, since scripts dynamically generate new IDs | ||||
// and casting arbitrary ints to enums is undefined behaviour, so use 'int' typedefs | // and casting arbitrary ints to enums is undefined behaviour, so use 'int' typedefs | ||||
typedef int InterfaceId; | typedef int InterfaceId; | ||||
Show All 22 Lines | struct ComponentType | ||||
InterfaceId iid; | InterfaceId iid; | ||||
AllocFunc alloc; | AllocFunc alloc; | ||||
DeallocFunc dealloc; | DeallocFunc dealloc; | ||||
std::string name; | std::string name; | ||||
std::string schema; // RelaxNG fragment | std::string schema; // RelaxNG fragment | ||||
std::unique_ptr<JS::PersistentRootedValue> ctor; // only valid if type == CT_Script | std::unique_ptr<JS::PersistentRootedValue> ctor; // only valid if type == CT_Script | ||||
}; | }; | ||||
using SystemComponents = std::tuple< | |||||
CCmpTemplateManager, | |||||
CCmpCinemaManager, | |||||
CCmpCommandQueue, | |||||
CCmpObstructionManager, | |||||
CCmpParticleManager, | |||||
CCmpPathfinder, | |||||
CCmpProjectileManager, | |||||
CCmpRangeManager, | |||||
CCmpSoundManager, | |||||
CCmpTerrain, | |||||
CCmpTerritoryManager, | |||||
CCmpUnitMotionManager, | |||||
CCmpUnitRenderer, | |||||
CCmpWaterManager>; | |||||
public: | public: | ||||
CComponentManager(CSimContext&, std::shared_ptr<ScriptContext> cx, bool skipScriptFunctions = false); | CComponentManager(CSimContext&, std::shared_ptr<ScriptContext> cx, bool skipScriptFunctions = false); | ||||
~CComponentManager(); | ~CComponentManager(); | ||||
void LoadComponentTypes(); | void LoadComponentTypes(); | ||||
/** | /** | ||||
* Load a script and execute it in a new function scope. | * Load a script and execute it in a new function scope. | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | public: | ||||
/** | /** | ||||
* Constructs a component of type 'cid', initialised with data 'paramNode', | * Constructs a component of type 'cid', initialised with data 'paramNode', | ||||
* and attaches it to entity 'ent'. | * and attaches it to entity 'ent'. | ||||
* | * | ||||
* @return true on success; false on failure, and logs an error message | * @return true on success; false on failure, and logs an error message | ||||
*/ | */ | ||||
bool AddComponent(CEntityHandle ent, ComponentTypeId cid, const CParamNode& paramNode); | bool AddComponent(CEntityHandle ent, ComponentTypeId cid, const CParamNode& paramNode); | ||||
template<typename Component> | |||||
void AddSystemComponent(Component& component) | |||||
{ | |||||
ScriptRequest rq(m_ScriptInterface); | |||||
const auto it = m_ComponentTypesById.find(Component::typeId); | |||||
if (it == m_ComponentTypesById.end()) | |||||
{ | |||||
LOGERROR("Invalid component id %d", Component::typeId); | |||||
return; | |||||
} | |||||
const ComponentType& ct = it->second; | |||||
ENSURE((size_t)ct.iid < m_ComponentsByInterface.size()); | |||||
std::unordered_map<entity_id_t, IComponent*>& emap1 = m_ComponentsByInterface[ct.iid]; | |||||
if (emap1.count(SYSTEM_ENTITY) != 0) | |||||
{ | |||||
LOGERROR("Multiple components for interface %d", ct.iid); | |||||
return; | |||||
} | |||||
std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[Component::typeId]; | |||||
component.SetEntityHandle(m_SystemEntity); | |||||
component.SetSimContext(m_SimContext); | |||||
// Store a reference to the new component | |||||
emap1.insert({SYSTEM_ENTITY, &component}); | |||||
emap2.insert({SYSTEM_ENTITY, &component}); | |||||
// TODO: We need to more careful about this - if an entity is constructed by a component | |||||
// while we're iterating over all components, this will invalidate the iterators and everything | |||||
// will break. | |||||
// We probably need some kind of delayed addition, so they get pushed onto a queue and then | |||||
// inserted into the world later on. (Be careful about immediation deletion in that case, too.) | |||||
SEntityComponentCache* cache = m_SystemEntity.GetComponentCache(); | |||||
ENSURE(cache != NULL && ct.iid < static_cast<int>(cache->numInterfaces) && | |||||
cache->interfaces[ct.iid] == NULL); | |||||
cache->interfaces[ct.iid] = &component; | |||||
component.Init({}); | |||||
} | |||||
/** | /** | ||||
* Add all system components to the system entity (skip the scripted components or the AI components on demand) | * Add all system components to the system entity (skip the scripted components or the AI components on demand) | ||||
*/ | */ | ||||
void AddSystemComponents(bool skipScriptedComponents, bool skipAI); | void AddSystemComponents(bool skipScriptedComponents, bool skipAI); | ||||
/** | /** | ||||
* Adds an externally-created component, so that it is returned by QueryInterface | * Adds an externally-created component, so that it is returned by QueryInterface | ||||
* but does not get destroyed and does not receive messages from the component manager. | * but does not get destroyed and does not receive messages from the component manager. | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | private: | ||||
ScriptInterface m_ScriptInterface; | ScriptInterface m_ScriptInterface; | ||||
CSimContext& m_SimContext; | CSimContext& m_SimContext; | ||||
CEntityHandle m_SystemEntity; | CEntityHandle m_SystemEntity; | ||||
ComponentTypeId m_CurrentComponent; // used when loading component types | ComponentTypeId m_CurrentComponent; // used when loading component types | ||||
bool m_CurrentlyHotloading; | bool m_CurrentlyHotloading; | ||||
std::optional<SystemComponents> m_SystemComponents; | |||||
// TODO: some of these should be vectors | // TODO: some of these should be vectors | ||||
std::map<ComponentTypeId, ComponentType> m_ComponentTypesById; | std::map<ComponentTypeId, ComponentType> m_ComponentTypesById; | ||||
std::vector<CComponentManager::ComponentTypeId> m_ScriptedSystemComponents; | std::vector<CComponentManager::ComponentTypeId> m_ScriptedSystemComponents; | ||||
std::vector<std::unordered_map<entity_id_t, IComponent*> > m_ComponentsByInterface; // indexed by InterfaceId | std::vector<std::unordered_map<entity_id_t, IComponent*> > m_ComponentsByInterface; // indexed by InterfaceId | ||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> > m_ComponentsByTypeId; | std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> > m_ComponentsByTypeId; | ||||
std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions; | std::map<MessageTypeId, std::vector<ComponentTypeId> > m_LocalMessageSubscriptions; | ||||
std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions; | std::map<MessageTypeId, std::vector<ComponentTypeId> > m_GlobalMessageSubscriptions; | ||||
std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName; | std::map<std::string, ComponentTypeId> m_ComponentTypeIdsByName; | ||||
Show All 24 Lines |
Wildfire Games · Phabricator