Changeset View
Standalone View
source/simulation2/system/ComponentManager.cpp
Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (!skipScriptFunctions) | ||||
m_ScriptInterface.RegisterFunction<void, int, std::string, JS::HandleValue, CComponentManager::Script_ReRegisterComponentType> ("ReRegisterComponentType"); | m_ScriptInterface.RegisterFunction<void, int, std::string, JS::HandleValue, CComponentManager::Script_ReRegisterComponentType> ("ReRegisterComponentType"); | ||||
m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterInterface> ("RegisterInterface"); | m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterInterface> ("RegisterInterface"); | ||||
m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterMessageType> ("RegisterMessageType"); | m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterMessageType> ("RegisterMessageType"); | ||||
m_ScriptInterface.RegisterFunction<void, std::string, JS::HandleValue, CComponentManager::Script_RegisterGlobal> ("RegisterGlobal"); | m_ScriptInterface.RegisterFunction<void, std::string, JS::HandleValue, CComponentManager::Script_RegisterGlobal> ("RegisterGlobal"); | ||||
m_ScriptInterface.RegisterFunction<IComponent*, int, int, CComponentManager::Script_QueryInterface> ("QueryInterface"); | m_ScriptInterface.RegisterFunction<IComponent*, int, int, CComponentManager::Script_QueryInterface> ("QueryInterface"); | ||||
m_ScriptInterface.RegisterFunction<std::vector<int>, int, CComponentManager::Script_GetEntitiesWithInterface> ("GetEntitiesWithInterface"); | m_ScriptInterface.RegisterFunction<std::vector<int>, int, CComponentManager::Script_GetEntitiesWithInterface> ("GetEntitiesWithInterface"); | ||||
m_ScriptInterface.RegisterFunction<std::vector<IComponent*>, int, CComponentManager::Script_GetComponentsWithInterface> ("GetComponentsWithInterface"); | m_ScriptInterface.RegisterFunction<std::vector<IComponent*>, int, CComponentManager::Script_GetComponentsWithInterface> ("GetComponentsWithInterface"); | ||||
m_ScriptInterface.RegisterFunction<void, int, int, JS::HandleValue, CComponentManager::Script_PostMessage> ("PostMessage"); | m_ScriptInterface.RegisterFunction<void, int, int, JS::HandleValue, CComponentManager::Script_PostMessage> ("PostMessage"); | ||||
m_ScriptInterface.RegisterFunction<void, std::vector<entity_id_t>, int, JS::HandleValue, CComponentManager::Script_DistributeMessage> ("DistributeMessage"); | |||||
m_ScriptInterface.RegisterFunction<void, int, JS::HandleValue, CComponentManager::Script_BroadcastMessage> ("BroadcastMessage"); | m_ScriptInterface.RegisterFunction<void, int, JS::HandleValue, CComponentManager::Script_BroadcastMessage> ("BroadcastMessage"); | ||||
m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddEntity> ("AddEntity"); | m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddEntity> ("AddEntity"); | ||||
m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddLocalEntity> ("AddLocalEntity"); | m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddLocalEntity> ("AddLocalEntity"); | ||||
m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity"); | m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity"); | ||||
m_ScriptInterface.RegisterFunction<void, CComponentManager::Script_FlushDestroyedEntities> ("FlushDestroyedEntities"); | m_ScriptInterface.RegisterFunction<void, CComponentManager::Script_FlushDestroyedEntities> ("FlushDestroyedEntities"); | ||||
} | } | ||||
// Globalscripts may use VFS script functions | // Globalscripts may use VFS script functions | ||||
▲ Show 20 Lines • Show All 343 Lines • ▼ Show 20 Lines | void CComponentManager::Script_PostMessage(ScriptInterface::CxPrivate* pCxPrivate, int ent, int mtid, JS::HandleValue data) | ||||
if (!msg) | if (!msg) | ||||
return; // error | return; // error | ||||
componentManager->PostMessage(ent, *msg); | componentManager->PostMessage(ent, *msg); | ||||
delete msg; | delete msg; | ||||
} | } | ||||
void CComponentManager::Script_DistributeMessage(ScriptInterface::CxPrivate* pCxPrivate, const std::vector<entity_id_t>& entities, int mtid, JS::HandleValue data) | |||||
{ | |||||
if (entities.empty()) | |||||
return; | |||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | |||||
Stan: Wonder if that errors out a lot? | |||||
CMessage* msg = componentManager->ConstructMessage(mtid, data); | |||||
if (!msg) | |||||
return; // error | |||||
componentManager->DistributeMessage(entities, *msg); | |||||
delete msg; | |||||
} | |||||
void CComponentManager::Script_BroadcastMessage(ScriptInterface::CxPrivate* pCxPrivate, int mtid, JS::HandleValue data) | void CComponentManager::Script_BroadcastMessage(ScriptInterface::CxPrivate* pCxPrivate, int mtid, JS::HandleValue data) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | ||||
CMessage* msg = componentManager->ConstructMessage(mtid, data); | CMessage* msg = componentManager->ConstructMessage(mtid, data); | ||||
if (!msg) | if (!msg) | ||||
return; // error | return; // error | ||||
▲ Show 20 Lines • Show All 547 Lines • ▼ Show 20 Lines | const CComponentManager::InterfaceListUnordered& CComponentManager::GetEntitiesWithInterfaceUnordered(InterfaceId iid) const | ||||
{ | { | ||||
// Invalid iid | // Invalid iid | ||||
return g_EmptyEntityMap; | return g_EmptyEntityMap; | ||||
} | } | ||||
return m_ComponentsByInterface[iid]; | return m_ComponentsByInterface[iid]; | ||||
} | } | ||||
void CComponentManager::PostMessage(entity_id_t ent, const CMessage& msg) | void CComponentManager::PostMessage(entity_id_t ent, const CMessage& msg) | ||||
{ | { | ||||
PROFILE2_IFSPIKE("Post Message", 0.0005); | SendMessageTo(ent, msg); | ||||
SendGlobalMessage(ent, msg); | |||||
} | |||||
/** | |||||
* Sends a local message to each of the specified entities and one global message. | |||||
* Since global messages "to" local entities are handled differently than normal, | |||||
* we check if there is at least one non-local entity to send the global message to. | |||||
*/ | |||||
void CComponentManager::DistributeMessage(const std::vector<entity_id_t>& entities, const CMessage& msg) | |||||
{ | |||||
if (entities.empty()) | |||||
return; | |||||
bbUnsubmitted Not Done Inline ActionsActually on a second thought, we should send a global message shouldn't we? The change still happened, just no subscribers, so any global listener should still be notified (the global listener shouldn't care about other listeners, right?) bb: Actually on a second thought, we should send a global message shouldn't we? The change still… | |||||
FreagarachAuthorUnsubmitted Not Done Inline ActionsYep, agreed. Freagarach: Yep, agreed. | |||||
bool globalMessageSent = false; | |||||
for (entity_id_t ent : entities) | |||||
Not Done Inline ActionsWhere did this ENTIY_IS_LOCAL check come from? bb: Where did this ENTIY_IS_LOCAL check come from? | |||||
Not Done Inline ActionsGlobal messages to local entities are handles differently (see L1112), hence if there is at least one non-local entity we should send the global message using that entity. Freagarach: Global messages to local entities are handles differently (see L1112), hence if there is at… | |||||
{ | |||||
SendMessageTo(ent, msg); | |||||
if (!globalMessageSent && !ENTITY_IS_LOCAL(ent)) | |||||
{ | |||||
SendGlobalMessage(ent, msg); | |||||
globalMessageSent = true; | |||||
} | |||||
Done Inline ActionsShould we handle an empty array earlier? Freagarach: Should we handle an empty array earlier? | |||||
Done Inline ActionsI guess you could to save some cycles. Could be profiled. One could also not send message for empty arrays :D Dunno if that should be the responsibility of the caller or the callee. Stan: I guess you could to save some cycles. Could be profiled. One could also not send message for… | |||||
Not Done Inline ActionsEmpty arrays should probably not send a global messages. However there seems to be a problem here: We only send a global message for 1 ent. For example (taking an extreme) using this function to ownershipchange several entities, will just return 1 globalOwnershipchanged. So any component listening to that, will only know of 1 entities change and not of all others... Sounds like trouble, we don't want. In the current implementation I guess one would need to send a global message for every entity. One could change all listeners to allow for several entities, but not sure if we want to go down that road... bb: Empty arrays should probably not send a global messages. However there seems to be a problem… | |||||
Not Done Inline ActionsThe idea is that there can be only one message sent with DistributeMessage, so that needs to be sent globally only once, right? If one would send a global message for every entity in the array, the exact same global message is sent for all of them, which is rather unnecessary. Freagarach: The idea is that there can be only one message sent with `DistributeMessage`, so that needs to… | |||||
} | |||||
// All entities were local, just pick the first one. | |||||
if (!globalMessageSent) | |||||
SendGlobalMessage(entities.front(), msg); | |||||
} | |||||
Not Done Inline ActionsLeftover? Stan: Leftover? | |||||
Not Done Inline ActionsNot sure where I should add the profiler stuff. I could do it in every function? Freagarach: Not sure where I should add the profiler stuff. I could do it in every function?
It is not a… | |||||
Not Done Inline ActionsYep, it does the profiling anyway, but if it's too small it doesn't register it in the graph. I guess you should check at which treshold it becomes relevant to have it. For some functions it's normal to execute in 500us for some it's terrible Stan: Yep, it does the profiling anyway, but if it's too small it doesn't register it in the graph. I… | |||||
void CComponentManager::SendMessageTo(entity_id_t ent, const CMessage& msg) | |||||
{ | |||||
PROFILE2_IFSPIKE("Send Message To", 0.0005); | |||||
PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); | PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); | ||||
Not Done Inline ActionsDo we want to keep this function, if we have a more general one? bb: Do we want to keep this function, if we have a more general one? | |||||
Not Done Inline ActionsI'd say yes. This is needed e.g. for ownership changes, where a global message is to be sent for every single entity. Otherwise one would have to make an array every time one wants to send a message to a single entity, that sounds costly and unnecessary. Freagarach: I'd say yes. This is needed e.g. for ownership changes, where a global message is to be sent… | |||||
// Send the message to components of ent, that subscribed locally to this message | // Send the message to components of ent, that subscribed locally to this message | ||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it; | std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it; | ||||
it = m_LocalMessageSubscriptions.find(msg.GetType()); | it = m_LocalMessageSubscriptions.find(msg.GetType()); | ||||
if (it != m_LocalMessageSubscriptions.end()) | if (it != m_LocalMessageSubscriptions.end()) | ||||
{ | { | ||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin(); | std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin(); | ||||
for (; ctit != it->second.end(); ++ctit) | for (; ctit != it->second.end(); ++ctit) | ||||
{ | { | ||||
// Find the component instances of this type (if any) | // Find the component instances of this type (if any) | ||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); | std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); | ||||
if (emap == m_ComponentsByTypeId.end()) | if (emap == m_ComponentsByTypeId.end()) | ||||
continue; | continue; | ||||
// Send the message to all of them | // Send the message to all of them | ||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.find(ent); | std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.find(ent); | ||||
if (eit != emap->second.end()) | if (eit != emap->second.end()) | ||||
eit->second->HandleMessage(msg, false); | eit->second->HandleMessage(msg, false); | ||||
} | } | ||||
} | } | ||||
SendGlobalMessage(ent, msg); | |||||
} | } | ||||
void CComponentManager::BroadcastMessage(const CMessage& msg) | void CComponentManager::BroadcastMessage(const CMessage& msg) | ||||
{ | { | ||||
// Send the message to components of all entities that subscribed locally to this message | // Send the message to components of all entities that subscribed locally to this message | ||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it; | std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it; | ||||
it = m_LocalMessageSubscriptions.find(msg.GetType()); | it = m_LocalMessageSubscriptions.find(msg.GetType()); | ||||
if (it != m_LocalMessageSubscriptions.end()) | if (it != m_LocalMessageSubscriptions.end()) | ||||
▲ Show 20 Lines • Show All 138 Lines • Show Last 20 Lines |
Wonder if that errors out a lot?