Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/system/ComponentManager.h
Show All 18 Lines | |||||
#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/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 "simulation2/system/ComponentDataHolder.h" | |||||
#include <boost/random/linear_congruential.hpp> | #include <boost/random/linear_congruential.hpp> | ||||
#include <map> | #include <map> | ||||
#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 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; | ||||
typedef int ComponentTypeId; | typedef int ComponentTypeId; | ||||
typedef int MessageTypeId; | typedef int MessageTypeId; | ||||
private: | private: | ||||
using AllocFunc = IComponent::AllocFunc; | using AllocFunc = IComponent::AllocFunc; | ||||
using DeallocFunc = IComponent::DeallocFunc; | using DestructFunc = IComponent::DestructFunc; | ||||
// ComponentTypes come in three types: | // ComponentTypes come in three types: | ||||
// Native: normal C++ component | // Native: normal C++ component | ||||
// ScriptWrapper: C++ component that wraps a JS component implementation | // ScriptWrapper: C++ component that wraps a JS component implementation | ||||
// Script: a ScriptWrapper linked to a specific JS component implementation | // Script: a ScriptWrapper linked to a specific JS component implementation | ||||
enum EComponentTypeType | enum EComponentTypeType | ||||
{ | { | ||||
CT_Native, | CT_Native, | ||||
CT_ScriptWrapper, | CT_ScriptWrapper, | ||||
CT_Script | CT_Script | ||||
}; | }; | ||||
// Representation of a component type, to be used when instantiating components | // Representation of a component type, to be used when instantiating components | ||||
struct ComponentType | struct ComponentType | ||||
{ | { | ||||
EComponentTypeType type; | EComponentTypeType type; | ||||
InterfaceId iid; | InterfaceId iid; | ||||
AllocFunc alloc; | AllocFunc alloc; | ||||
jprahman: nit: Should AllocFunc -> ConstructFunc for symmetry and precision (since allocation is not… | |||||
DeallocFunc dealloc; | DestructFunc destruct; | ||||
size_t size; | |||||
size_t align; | |||||
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 | ||||
}; | }; | ||||
std::unordered_map<ComponentTypeId, CComponentDataHolder> m_ComponentData; | |||||
Done Inline ActionsThese are owning pointer right? Why not storing the actual objects? phosit: These are owning pointer right? Why not storing the actual objects? | |||||
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. | ||||
* @param filename VFS path to load | * @param filename VFS path to load | ||||
* @param hotload set to true if this script has been loaded before, and redefinitions of | * @param hotload set to true if this script has been loaded before, and redefinitions of | ||||
* existing components should not be considered errors | * existing components should not be considered errors | ||||
*/ | */ | ||||
bool LoadScript(const VfsPath& filename, bool hotload = false); | bool LoadScript(const VfsPath& filename, bool hotload = false); | ||||
void RegisterMessageType(MessageTypeId mtid, const char* name); | void RegisterMessageType(MessageTypeId mtid, const char* name); | ||||
void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); | void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DestructFunc, size_t size, size_t align, const char*, const std::string& schema); | ||||
void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); | void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DestructFunc, size_t size, size_t align, const char*, const std::string& schema); | ||||
void MarkScriptedComponentForSystemEntity(CComponentManager::ComponentTypeId cid); | void MarkScriptedComponentForSystemEntity(CComponentManager::ComponentTypeId cid); | ||||
/** | /** | ||||
* Subscribe the current component type to the given message type. | * Subscribe the current component type to the given message type. | ||||
* Each component's HandleMessage will be called on any BroadcastMessage of this message type, | * Each component's HandleMessage will be called on any BroadcastMessage of this message type, | ||||
* or on any PostMessage of this type targeted at the component's entity. | * or on any PostMessage of this type targeted at the component's entity. | ||||
* Must only be called by a component type's ClassInit. | * Must only be called by a component type's ClassInit. | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | public: | ||||
void FlushDestroyedComponents(); | void FlushDestroyedComponents(); | ||||
IComponent* QueryInterface(entity_id_t ent, InterfaceId iid) const; | IComponent* QueryInterface(entity_id_t ent, InterfaceId iid) const; | ||||
using InterfacePair = std::pair<entity_id_t, IComponent*>; | using InterfacePair = std::pair<entity_id_t, IComponent*>; | ||||
using InterfaceList = std::vector<InterfacePair>; | using InterfaceList = std::vector<InterfacePair>; | ||||
using InterfaceListUnordered = std::unordered_map<entity_id_t, IComponent*>; | using InterfaceListUnordered = std::unordered_map<entity_id_t, IComponent*>; | ||||
InterfaceList GetEntitiesWithInterface(InterfaceId iid) const; | InterfaceList GetComponentsByInterface(InterfaceId iid) const; | ||||
const InterfaceListUnordered& GetEntitiesWithInterfaceUnordered(InterfaceId iid) const; | SComponentDataGenerator GetComponentsByInterfaceUnordered(InterfaceId iid) const; | ||||
/** | /** | ||||
* Send a message, targeted at a particular entity. The message will be received by any | * Send a message, targeted at a particular entity. The message will be received by any | ||||
* components of that entity which subscribed to the message type, and by any other components | * components of that entity which subscribed to the message type, and by any other components | ||||
* that subscribed globally to the message type. | * that subscribed globally to the message type. | ||||
*/ | */ | ||||
void PostMessage(entity_id_t ent, const CMessage& msg); | void PostMessage(entity_id_t ent, const CMessage& msg); | ||||
/** | /** | ||||
* Send a message, not targeted at any particular entity. The message will be received by any | * Send a message, not targeted at any particular entity. The message will be received by any | ||||
* components responding to a givent interface id. | |||||
*/ | |||||
void BroadcastMessageToInterface(const CMessage& msg, InterfaceId iid, bool global) const; | |||||
/** | |||||
* Send a message, not targeted at any particular entity. The message will be received by any | |||||
* components that subscribed (either globally or not) to the message type. | * components that subscribed (either globally or not) to the message type. | ||||
*/ | */ | ||||
void BroadcastMessage(const CMessage& msg); | void BroadcastMessage(const CMessage& msg); | ||||
/** | /** | ||||
* Resets the dynamic simulation state (deletes all entities, resets entity ID counters; | * Resets the dynamic simulation state (deletes all entities, resets entity ID counters; | ||||
* doesn't unload/reload component scripts). | * doesn't unload/reload component scripts). | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | private: | ||||
ComponentTypeId m_CurrentComponent; // used when loading component types | ComponentTypeId m_CurrentComponent; // used when loading component types | ||||
bool m_CurrentlyHotloading; | bool m_CurrentlyHotloading; | ||||
// 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::vector<CComponentDataHolder*> m_ComponentDataByInterface; // 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; | ||||
std::map<std::string, MessageTypeId> m_MessageTypeIdsByName; | std::map<std::string, MessageTypeId> m_MessageTypeIdsByName; | ||||
std::map<MessageTypeId, std::string> m_MessageTypeNamesById; | std::map<MessageTypeId, std::string> m_MessageTypeNamesById; | ||||
std::map<std::string, InterfaceId> m_InterfaceIdsByName; | std::map<std::string, InterfaceId> m_InterfaceIdsByName; | ||||
Show All 20 Lines |
Wildfire Games · Phabricator
nit: Should AllocFunc -> ConstructFunc for symmetry and precision (since allocation is not handled by the pool allocator)?