Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/system/ComponentManager.cpp
Show First 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | if (cid == CID__Invalid) | ||||
if (reRegister) | if (reRegister) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError(("ReRegistering component type that was not registered before '" + cname + "'").c_str()); | componentManager->m_ScriptInterface.ReportError(("ReRegistering component type that was not registered before '" + cname + "'").c_str()); | ||||
return; | return; | ||||
} | } | ||||
// Allocate a new cid number | // Allocate a new cid number | ||||
cid = componentManager->m_NextScriptComponentTypeId++; | cid = componentManager->m_NextScriptComponentTypeId++; | ||||
componentManager->m_ComponentTypeIdsByName[cname] = cid; | componentManager->m_ComponentTypeIdsByName[cname] = cid; | ||||
componentManager->ResizeComponentsByTypeId(cid + 1); | |||||
if (systemComponent) | if (systemComponent) | ||||
componentManager->MarkScriptedComponentForSystemEntity(cid); | componentManager->MarkScriptedComponentForSystemEntity(cid); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Component type is already loaded, so do hotloading: | // Component type is already loaded, so do hotloading: | ||||
if (!componentManager->m_CurrentlyHotloading && !reRegister) | if (!componentManager->m_CurrentlyHotloading && !reRegister) | ||||
Show All 19 Lines | if (ctPrevious.iid != iid) | ||||
if (!componentManager->m_ComponentsByTypeId[cid].empty()) | if (!componentManager->m_ComponentsByTypeId[cid].empty()) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID"); | componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID"); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
// Remove the old component type's message subscriptions | // Remove the old component type's message subscriptions | ||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it; | for (std::pair<MessageTypeId, std::vector<EntCompMap*> >& subscribers : componentManager->m_LocalMessageSubscriptions) | ||||
for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it) | |||||
{ | { | ||||
std::vector<ComponentTypeId>& types = it->second; | std::vector<EntCompMap*>& types = subscribers.second; | ||||
std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid); | EntCompMap* start = componentManager->m_ComponentsByTypeId.data(); | ||||
std::vector<EntCompMap*>::iterator ctit = std::find_if(types.begin(), types.end(), [=](EntCompMap* ptr) { return (ptr - start) == cid; }); | |||||
if (ctit != types.end()) | if (ctit != types.end()) | ||||
types.erase(ctit); | types.erase(ctit); | ||||
} | } | ||||
for (it = componentManager->m_GlobalMessageSubscriptions.begin(); it != componentManager->m_GlobalMessageSubscriptions.end(); ++it) | for (std::pair<MessageTypeId, std::vector<EntCompMap*> >& subscribers : componentManager->m_GlobalMessageSubscriptions) | ||||
elexis: ```
using MessageIt = std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator;
for… | |||||
{ | { | ||||
std::vector<ComponentTypeId>& types = it->second; | std::vector<EntCompMap*>& types = subscribers.second; | ||||
std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid); | EntCompMap* start = componentManager->m_ComponentsByTypeId.data(); | ||||
std::vector<EntCompMap*>::iterator ctit = std::find_if(types.begin(), types.end(), [=](EntCompMap* ptr) { return (ptr - start) == cid; }); | |||||
if (ctit != types.end()) | if (ctit != types.end()) | ||||
types.erase(ctit); | types.erase(ctit); | ||||
} | } | ||||
mustReloadComponents = true; | mustReloadComponents = true; | ||||
} | } | ||||
JS::RootedValue protoVal(cx); | JS::RootedValue protoVal(cx); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it) | ||||
if (isGlobal) | if (isGlobal) | ||||
componentManager->SubscribeGloballyToMessageType(mit->second); | componentManager->SubscribeGloballyToMessageType(mit->second); | ||||
else | else | ||||
componentManager->SubscribeToMessageType(mit->second); | componentManager->SubscribeToMessageType(mit->second); | ||||
} | } | ||||
componentManager->m_CurrentComponent = CID__Invalid; | componentManager->m_CurrentComponent = CID__Invalid; | ||||
if (mustReloadComponents) | |||||
{ | |||||
// For every script component with this cid, we need to switch its | // For every script component with this cid, we need to switch its | ||||
// prototype from the old constructor's prototype property to the new one's | // prototype from the old constructor's prototype property to the new one's | ||||
const std::map<entity_id_t, IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid]; | if (mustReloadComponents) | ||||
std::map<entity_id_t, IComponent*>::const_iterator eit = comps.begin(); | for (const std::pair<entity_id_t, IComponent*>& entComp : componentManager->m_ComponentsByTypeId[cid]) | ||||
for (; eit != comps.end(); ++eit) | |||||
{ | { | ||||
Not Done Inline ActionsDoesn't this copy the pair? (also const?) elexis: Doesn't this copy the pair? (also const?) | |||||
Done Inline ActionsMight be a compilation issue with some of the weirdness I've added, but perhaps. Might be trivial enough that copying over reference is rather equivalent. wraitii: Might be a compilation issue with some of the weirdness I've added, but perhaps. Might be… | |||||
JS::RootedValue instance(cx, eit->second->GetJSInstance()); | JS::RootedValue instance(cx, entComp.second->GetJSInstance()); | ||||
if (!instance.isNull()) | if (!instance.isNull()) | ||||
componentManager->m_ScriptInterface.SetPrototype(instance, protoVal); | componentManager->m_ScriptInterface.SetPrototype(instance, protoVal); | ||||
} | } | ||||
} | } | ||||
} | |||||
void CComponentManager::Script_RegisterComponentType(ScriptInterface::CxPrivate* pCxPrivate, int iid, const std::string& cname, JS::HandleValue ctor) | void CComponentManager::Script_RegisterComponentType(ScriptInterface::CxPrivate* pCxPrivate, int iid, const std::string& cname, JS::HandleValue ctor) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | ||||
componentManager->Script_RegisterComponentType_Common(pCxPrivate, iid, cname, ctor, false, false); | componentManager->Script_RegisterComponentType_Common(pCxPrivate, iid, cname, ctor, false, false); | ||||
componentManager->m_ScriptInterface.SetGlobal(cname.c_str(), ctor, componentManager->m_CurrentlyHotloading); | componentManager->m_ScriptInterface.SetGlobal(cname.c_str(), ctor, componentManager->m_CurrentlyHotloading); | ||||
} | } | ||||
Show All 20 Lines | if (it != componentManager->m_InterfaceIdsByName.end()) | ||||
// they're probably unintentional and should be reported | // they're probably unintentional and should be reported | ||||
if (!componentManager->m_CurrentlyHotloading) | if (!componentManager->m_CurrentlyHotloading) | ||||
componentManager->m_ScriptInterface.ReportError(("Registering interface with already-registered name '" + name + "'").c_str()); | componentManager->m_ScriptInterface.ReportError(("Registering interface with already-registered name '" + name + "'").c_str()); | ||||
return; | return; | ||||
} | } | ||||
// IIDs start at 1, so size+1 is the next unused one | // IIDs start at 1, so size+1 is the next unused one | ||||
size_t id = componentManager->m_InterfaceIdsByName.size() + 1; | size_t id = componentManager->m_InterfaceIdsByName.size() + 1; | ||||
componentManager->m_InterfaceIdsByName[name] = (InterfaceId)id; | componentManager->m_InterfaceIdsByName[name] = (InterfaceId)id; | ||||
Not Done Inline ActionsCan't a function called resize be implemented ? Stan: Can't a function called resize be implemented ? | |||||
Done Inline ActionsCould. TBH I think this can be removed in the new implementation. I need to clean this up slightly wraitii: Could. TBH I think this can be removed in the new implementation. I need to clean this up… | |||||
componentManager->m_ComponentsByInterface.resize(id+1); // add one so we can index by InterfaceId | componentManager->m_ComponentsByInterface.resize(id+1); // add one so we can index by InterfaceId | ||||
componentManager->m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int)id); | componentManager->m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int)id); | ||||
} | } | ||||
void CComponentManager::Script_RegisterMessageType(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name) | void CComponentManager::Script_RegisterMessageType(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | ||||
Show All 26 Lines | IComponent* CComponentManager::Script_QueryInterface(ScriptInterface::CxPrivate* pCxPrivate, int ent, int iid) | ||||
return component; | return component; | ||||
} | } | ||||
std::vector<int> CComponentManager::Script_GetEntitiesWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid) | std::vector<int> CComponentManager::Script_GetEntitiesWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | ||||
std::vector<int> ret; | std::vector<int> ret; | ||||
const InterfaceListUnordered& ents = componentManager->GetEntitiesWithInterfaceUnordered(iid); | for (const std::pair<entity_id_t, IComponent*>& entComp : componentManager->GetEntitiesWithInterfaceUnordered(iid)) | ||||
for (InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it) | if (!ENTITY_IS_LOCAL(entComp.first)) | ||||
if (!ENTITY_IS_LOCAL(it->first)) | ret.push_back(entComp.first); | ||||
ret.push_back(it->first); | |||||
std::sort(ret.begin(), ret.end()); | std::sort(ret.begin(), ret.end()); | ||||
return ret; | return ret; | ||||
} | } | ||||
std::vector<IComponent*> CComponentManager::Script_GetComponentsWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid) | std::vector<IComponent*> CComponentManager::Script_GetComponentsWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
void CComponentManager::ResetState() | void CComponentManager::ResetState() | ||||
{ | { | ||||
// Delete all dynamic message subscriptions | // Delete all dynamic message subscriptions | ||||
m_DynamicMessageSubscriptionsNonsync.clear(); | m_DynamicMessageSubscriptionsNonsync.clear(); | ||||
m_DynamicMessageSubscriptionsNonsyncByComponent.clear(); | m_DynamicMessageSubscriptionsNonsyncByComponent.clear(); | ||||
// Delete all IComponents | // Delete all IComponents | ||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin(); | for (size_t cid = 0; cid < m_ComponentsByTypeId.size(); ++cid) | ||||
for (; iit != m_ComponentsByTypeId.end(); ++iit) | |||||
{ | { | ||||
std::map<entity_id_t, IComponent*>::iterator eit = iit->second.begin(); | for (std::pair<entity_id_t, IComponent*>& entComp : m_ComponentsByTypeId[cid]) | ||||
for (; eit != iit->second.end(); ++eit) | |||||
{ | { | ||||
eit->second->Deinit(); | entComp.second->Deinit(); | ||||
m_ComponentTypesById[iit->first].dealloc(eit->second); | m_ComponentTypesById[cid].dealloc(entComp.second); | ||||
} | } | ||||
} | } | ||||
std::vector<boost::unordered_map<entity_id_t, IComponent*> >::iterator ifcit = m_ComponentsByInterface.begin(); | for (size_t iid = 0; iid < m_ComponentsByInterface.size(); ++iid) | ||||
for (; ifcit != m_ComponentsByInterface.end(); ++ifcit) | m_ComponentsByInterface[iid].clear(); | ||||
ifcit->clear(); | |||||
m_ComponentsByTypeId.clear(); | m_ComponentsByTypeId.clear(); | ||||
// Delete all SEntityComponentCaches | // Delete all SEntityComponentCaches | ||||
std::unordered_map<entity_id_t, SEntityComponentCache*>::iterator ccit = m_ComponentCaches.begin(); | std::unordered_map<entity_id_t, SEntityComponentCache*>::iterator ccit = m_ComponentCaches.begin(); | ||||
for (; ccit != m_ComponentCaches.end(); ++ccit) | for (; ccit != m_ComponentCaches.end(); ++ccit) | ||||
free(ccit->second); | free(ccit->second); | ||||
m_ComponentCaches.clear(); | m_ComponentCaches.clear(); | ||||
Show All 9 Lines | |||||
void CComponentManager::SetRNGSeed(u32 seed) | void CComponentManager::SetRNGSeed(u32 seed) | ||||
{ | { | ||||
m_RNG.seed(seed); | m_RNG.seed(seed); | ||||
} | } | ||||
void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, | void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, | ||||
const char* name, const std::string& schema) | const char* name, const std::string& schema) | ||||
{ | { | ||||
m_ComponentTypeIdsByName[name] = cid; | |||||
ResizeComponentsByTypeId(cid + 1); | |||||
ComponentType c(CT_Native, iid, alloc, dealloc, name, schema, DefPersistentRooted<JS::Value>()); | ComponentType c(CT_Native, iid, alloc, dealloc, name, schema, DefPersistentRooted<JS::Value>()); | ||||
m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | ||||
m_ComponentTypeIdsByName[name] = cid; | |||||
} | } | ||||
void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, | void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, | ||||
DeallocFunc dealloc, const char* name, const std::string& schema) | DeallocFunc dealloc, const char* name, const std::string& schema) | ||||
{ | { | ||||
m_ComponentTypeIdsByName[name] = cid; | |||||
ResizeComponentsByTypeId(cid + 1); | |||||
ComponentType c(CT_ScriptWrapper, iid, alloc, dealloc, name, schema, DefPersistentRooted<JS::Value>()); | ComponentType c(CT_ScriptWrapper, iid, alloc, dealloc, name, schema, DefPersistentRooted<JS::Value>()); | ||||
m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | ||||
m_ComponentTypeIdsByName[name] = cid; | |||||
// TODO: merge with RegisterComponentType | // TODO: merge with RegisterComponentType | ||||
} | } | ||||
void CComponentManager::MarkScriptedComponentForSystemEntity(CComponentManager::ComponentTypeId cid) | void CComponentManager::MarkScriptedComponentForSystemEntity(CComponentManager::ComponentTypeId cid) | ||||
{ | { | ||||
m_ScriptedSystemComponents.push_back(cid); | m_ScriptedSystemComponents.push_back(cid); | ||||
} | } | ||||
void CComponentManager::RegisterMessageType(MessageTypeId mtid, const char* name) | void CComponentManager::RegisterMessageType(MessageTypeId mtid, const char* name) | ||||
{ | { | ||||
m_MessageTypeIdsByName[name] = mtid; | m_MessageTypeIdsByName[name] = mtid; | ||||
m_MessageTypeNamesById[mtid] = name; | m_MessageTypeNamesById[mtid] = name; | ||||
} | } | ||||
void CComponentManager::SubscribeToMessageType(MessageTypeId mtid) | void CComponentManager::SubscribeToMessageType(MessageTypeId mtid) | ||||
{ | { | ||||
// TODO: verify mtid | // TODO: verify mtid | ||||
ENSURE(m_CurrentComponent != CID__Invalid); | ENSURE(m_CurrentComponent != CID__Invalid); | ||||
std::vector<ComponentTypeId>& types = m_LocalMessageSubscriptions[mtid]; | ENSURE(static_cast<ComponentTypeId>(m_ComponentsByTypeId.size()) > m_CurrentComponent); | ||||
types.push_back(m_CurrentComponent); | m_LocalMessageSubscriptions[mtid].push_back(&m_ComponentsByTypeId[m_CurrentComponent]); | ||||
std::sort(types.begin(), types.end()); // TODO: just sort once at the end of LoadComponents | |||||
} | } | ||||
void CComponentManager::SubscribeGloballyToMessageType(MessageTypeId mtid) | void CComponentManager::SubscribeGloballyToMessageType(MessageTypeId mtid) | ||||
{ | { | ||||
// TODO: verify mtid | // TODO: verify mtid | ||||
ENSURE(m_CurrentComponent != CID__Invalid); | ENSURE(m_CurrentComponent != CID__Invalid); | ||||
std::vector<ComponentTypeId>& types = m_GlobalMessageSubscriptions[mtid]; | ENSURE(static_cast<ComponentTypeId>(m_ComponentsByTypeId.size()) > m_CurrentComponent); | ||||
types.push_back(m_CurrentComponent); | m_GlobalMessageSubscriptions[mtid].push_back(&m_ComponentsByTypeId[m_CurrentComponent]); | ||||
std::sort(types.begin(), types.end()); // TODO: just sort once at the end of LoadComponents | } | ||||
void CComponentManager::ResizeComponentsByTypeId(size_t new_size) | |||||
{ | |||||
if (m_ComponentsByTypeId.size() >= new_size) | |||||
return; | |||||
if (m_ComponentsByTypeId.capacity() >= new_size) | |||||
{ | |||||
m_ComponentsByTypeId.resize(new_size); | |||||
return; | |||||
} | |||||
// Message subscriptions keep raw pointers, so when invalidated we must update them. | |||||
// Convert these pointers back to component types IDs through safe pointer arithmetic, | |||||
// resize, then re-update subscriptions. | |||||
// This is somewhat inefficient but that should never be a problem since it happens at initialisation. | |||||
std::unordered_map<MessageTypeId, std::vector<ComponentTypeId> > local, global; | |||||
for (const std::pair<MessageTypeId, std::vector<EntCompMap*>>& subscribers : m_LocalMessageSubscriptions) | |||||
for (EntCompMap* map : subscribers.second) | |||||
local[subscribers.first].push_back(map - m_ComponentsByTypeId.data()); | |||||
for (const std::pair<MessageTypeId, std::vector<EntCompMap*>>& subscribers : m_GlobalMessageSubscriptions) | |||||
for (EntCompMap* map : subscribers.second) | |||||
global[subscribers.first].push_back(map - m_ComponentsByTypeId.data()); | |||||
m_LocalMessageSubscriptions.clear(); | |||||
m_GlobalMessageSubscriptions.clear(); | |||||
m_ComponentsByTypeId.resize(new_size); | |||||
for (const std::pair<MessageTypeId, std::vector<ComponentTypeId> >& new_map : local) | |||||
for (ComponentTypeId cid : new_map.second) | |||||
m_LocalMessageSubscriptions[new_map.first].push_back(&m_ComponentsByTypeId.at(cid)); | |||||
for (const std::pair<MessageTypeId, std::vector<ComponentTypeId> >& new_map : global) | |||||
for (ComponentTypeId cid : new_map.second) | |||||
m_GlobalMessageSubscriptions[new_map.first].push_back(&m_ComponentsByTypeId.at(cid)); | |||||
} | } | ||||
void CComponentManager::FlattenDynamicSubscriptions() | void CComponentManager::FlattenDynamicSubscriptions() | ||||
{ | { | ||||
std::map<MessageTypeId, CDynamicSubscription>::iterator it; | std::map<MessageTypeId, CDynamicSubscription>::iterator it; | ||||
for (it = m_DynamicMessageSubscriptionsNonsync.begin(); | for (it = m_DynamicMessageSubscriptionsNonsync.begin(); | ||||
it != m_DynamicMessageSubscriptionsNonsync.end(); ++it) | it != m_DynamicMessageSubscriptionsNonsync.end(); ++it) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | IComponent* CComponentManager::ConstructComponent(CEntityHandle ent, ComponentTypeId cid) | ||||
if (it == m_ComponentTypesById.end()) | if (it == m_ComponentTypesById.end()) | ||||
{ | { | ||||
LOGERROR("Invalid component id %d", cid); | LOGERROR("Invalid component id %d", cid); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
const ComponentType& ct = it->second; | const ComponentType& ct = it->second; | ||||
ENSURE((size_t)ct.iid < m_ComponentsByInterface.size()); | ENSURE((size_t)ct.iid < m_ComponentsByInterface.size()); | ||||
Not Done Inline ActionsDead code ? Stan: Dead code ? | |||||
boost::unordered_map<entity_id_t, IComponent*>& emap1 = m_ComponentsByInterface[ct.iid]; | EntCompMap& emap1 = m_ComponentsByInterface[ct.iid]; | ||||
if (emap1.find(ent.GetId()) != emap1.end()) | if (emap1.find(ent.GetId()) != emap1.end()) | ||||
{ | { | ||||
LOGERROR("Multiple components for interface %d", ct.iid); | LOGERROR("Multiple components for interface %d", ct.iid); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[cid]; | ResizeComponentsByTypeId(cid + 1); | ||||
EntCompMap& emap2 = m_ComponentsByTypeId[cid]; | |||||
// If this is a scripted component, construct the appropriate JS object first | // If this is a scripted component, construct the appropriate JS object first | ||||
JS::RootedValue obj(cx); | JS::RootedValue obj(cx); | ||||
if (ct.type == CT_Script) | if (ct.type == CT_Script) | ||||
{ | { | ||||
m_ScriptInterface.CallConstructor(ct.ctor.get(), JS::HandleValueArray::empty(), &obj); | m_ScriptInterface.CallConstructor(ct.ctor.get(), JS::HandleValueArray::empty(), &obj); | ||||
if (obj.isNull()) | if (obj.isNull()) | ||||
{ | { | ||||
LOGERROR("Script component constructor failed"); | LOGERROR("Script component constructor failed"); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
} | } | ||||
// Construct the new component | // Construct the new component | ||||
IComponent* component = ct.alloc(m_ScriptInterface, obj); | IComponent* component = ct.alloc(m_ScriptInterface, obj); | ||||
ENSURE(component); | ENSURE(component); | ||||
component->SetEntityHandle(ent); | component->SetEntityHandle(ent); | ||||
component->SetSimContext(m_SimContext); | component->SetSimContext(m_SimContext); | ||||
// Store a reference to the new component | // Store a reference to the new component | ||||
emap1.insert(std::make_pair(ent.GetId(), component)); | emap1.insert_or_assign(ent.GetId(), component); | ||||
emap2.insert(std::make_pair(ent.GetId(), component)); | emap2.insert_or_assign(ent.GetId(), component); | ||||
// TODO: We need to more careful about this - if an entity is constructed by a 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 | // while we're iterating over all components, this will invalidate the iterators and everything | ||||
// will break. | // will break. | ||||
// We probably need some kind of delayed addition, so they get pushed onto a queue and then | // 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.) | // inserted into the world later on. (Be careful about immediation deletion in that case, too.) | ||||
SEntityComponentCache* cache = ent.GetComponentCache(); | SEntityComponentCache* cache = ent.GetComponentCache(); | ||||
ENSURE(cache != NULL && ct.iid < (int)cache->numInterfaces && cache->interfaces[ct.iid] == NULL); | ENSURE(cache != NULL && ct.iid < (int)cache->numInterfaces && cache->interfaces[ct.iid] == NULL); | ||||
cache->interfaces[ct.iid] = component; | cache->interfaces[ct.iid] = component; | ||||
return component; | return component; | ||||
} | } | ||||
void CComponentManager::AddMockComponent(CEntityHandle ent, InterfaceId iid, IComponent& component) | void CComponentManager::AddMockComponent(CEntityHandle ent, InterfaceId iid, IComponent& component) | ||||
{ | { | ||||
// Just add it into the by-interface map, not the by-component-type map, | // Just add it into the by-interface map, not the by-component-type map, | ||||
// so it won't be considered for messages or deletion etc | // so it won't be considered for messages or deletion etc | ||||
boost::unordered_map<entity_id_t, IComponent*>& emap1 = m_ComponentsByInterface.at(iid); | EntCompMap& emap1 = m_ComponentsByInterface.at(iid); | ||||
if (emap1.find(ent.GetId()) != emap1.end()) | if (emap1.find(ent.GetId()) != emap1.end()) | ||||
debug_warn(L"Multiple components for interface"); | debug_warn(L"Multiple components for interface"); | ||||
emap1.insert(std::make_pair(ent.GetId(), &component)); | emap1.insert_or_assign(ent.GetId(), &component); | ||||
SEntityComponentCache* cache = ent.GetComponentCache(); | SEntityComponentCache* cache = ent.GetComponentCache(); | ||||
ENSURE(cache != NULL && iid < (int)cache->numInterfaces && cache->interfaces[iid] == NULL); | ENSURE(cache != NULL && iid < (int)cache->numInterfaces && cache->interfaces[iid] == NULL); | ||||
cache->interfaces[iid] = &component; | cache->interfaces[iid] = &component; | ||||
} | } | ||||
CEntityHandle CComponentManager::AllocateEntityHandle(entity_id_t ent) | CEntityHandle CComponentManager::AllocateEntityHandle(entity_id_t ent) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | for (std::vector<entity_id_t>::iterator it = queue.begin(); it != queue.end(); ++it) | ||||
PostMessage(ent, msg); | PostMessage(ent, msg); | ||||
// Flatten all the dynamic subscriptions to ensure there are no dangling | // Flatten all the dynamic subscriptions to ensure there are no dangling | ||||
// references in the 'removed' lists to components we're going to delete | // references in the 'removed' lists to components we're going to delete | ||||
// Some components may have dynamically unsubscribed following the Destroy message | // Some components may have dynamically unsubscribed following the Destroy message | ||||
FlattenDynamicSubscriptions(); | FlattenDynamicSubscriptions(); | ||||
// Destroy the components, and remove from m_ComponentsByTypeId: | // Destroy the components, and remove from m_ComponentsByTypeId: | ||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin(); | for (size_t cid = 1; cid < m_ComponentsByTypeId.size(); ++cid) | ||||
for (; iit != m_ComponentsByTypeId.end(); ++iit) | |||||
{ | { | ||||
std::map<entity_id_t, IComponent*>::iterator eit = iit->second.find(ent); | EntCompMap::iterator eit = m_ComponentsByTypeId[cid].find(ent); | ||||
if (eit != iit->second.end()) | if (eit != m_ComponentsByTypeId[cid].end()) | ||||
{ | { | ||||
eit->second->Deinit(); | eit->second->Deinit(); | ||||
RemoveComponentDynamicSubscriptions(eit->second); | RemoveComponentDynamicSubscriptions(eit->second); | ||||
m_ComponentTypesById[iit->first].dealloc(eit->second); | m_ComponentTypesById[cid].dealloc(eit->second); | ||||
iit->second.erase(ent); | m_ComponentsByTypeId[cid].erase(ent); | ||||
handle.GetComponentCache()->interfaces[m_ComponentTypesById[iit->first].iid] = NULL; | handle.GetComponentCache()->interfaces[m_ComponentTypesById[cid].iid] = NULL; | ||||
} | } | ||||
} | } | ||||
free(handle.GetComponentCache()); | free(handle.GetComponentCache()); | ||||
m_ComponentCaches.erase(ent); | m_ComponentCaches.erase(ent); | ||||
// Remove from m_ComponentsByInterface | for (size_t iid = 1; iid < m_ComponentsByInterface.size(); ++iid) | ||||
std::vector<boost::unordered_map<entity_id_t, IComponent*> >::iterator ifcit = m_ComponentsByInterface.begin(); | m_ComponentsByInterface[iid].erase(ent); | ||||
for (; ifcit != m_ComponentsByInterface.end(); ++ifcit) | |||||
{ | |||||
ifcit->erase(ent); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
IComponent* CComponentManager::QueryInterface(entity_id_t ent, InterfaceId iid) const | IComponent* CComponentManager::QueryInterface(entity_id_t ent, InterfaceId iid) const | ||||
{ | { | ||||
if ((size_t)iid >= m_ComponentsByInterface.size()) | if ((size_t)iid >= m_ComponentsByInterface.size()) | ||||
{ | { | ||||
// Invalid iid | // Invalid iid | ||||
return NULL; | return NULL; | ||||
} | } | ||||
boost::unordered_map<entity_id_t, IComponent*>::const_iterator eit = m_ComponentsByInterface[iid].find(ent); | EntCompMap::const_iterator eit = m_ComponentsByInterface[iid].find(ent); | ||||
if (eit == m_ComponentsByInterface[iid].end()) | if (eit == m_ComponentsByInterface[iid].end()) | ||||
{ | { | ||||
// This entity doesn't implement this interface | // This entity doesn't implement this interface | ||||
return NULL; | return NULL; | ||||
Not Done Inline Actionsnullptr ? Stan: nullptr ? | |||||
Done Inline ActionsHaven't changed what I didn't need to change, but this could go. wraitii: Haven't changed what I didn't need to change, but this could go. | |||||
} | } | ||||
return eit->second; | return eit->second; | ||||
} | } | ||||
CComponentManager::InterfaceList CComponentManager::GetEntitiesWithInterface(InterfaceId iid) const | CComponentManager::InterfaceList CComponentManager::GetEntitiesWithInterface(InterfaceId iid) const | ||||
{ | { | ||||
std::vector<std::pair<entity_id_t, IComponent*> > ret; | std::vector<std::pair<entity_id_t, IComponent*> > ret; | ||||
if ((size_t)iid >= m_ComponentsByInterface.size()) | if ((size_t)iid >= m_ComponentsByInterface.size()) | ||||
{ | { | ||||
// Invalid iid | // Invalid iid | ||||
return ret; | return ret; | ||||
} | } | ||||
ret.reserve(m_ComponentsByInterface[iid].size()); | ret.reserve(m_ComponentsByInterface[iid].size()); | ||||
boost::unordered_map<entity_id_t, IComponent*>::const_iterator it = m_ComponentsByInterface[iid].begin(); | for (const std::pair<entity_id_t, IComponent*>& entComp : m_ComponentsByInterface[iid]) | ||||
for (; it != m_ComponentsByInterface[iid].end(); ++it) | ret.push_back(entComp); | ||||
ret.push_back(*it); | |||||
std::sort(ret.begin(), ret.end()); // lexicographic pair comparison means this'll sort by entity ID | std::sort(ret.begin(), ret.end()); // lexicographic pair comparison means this'll sort by entity ID | ||||
return ret; | return ret; | ||||
} | } | ||||
static CComponentManager::InterfaceListUnordered g_EmptyEntityMap; | static CComponentManager::InterfaceListUnordered g_EmptyEntityMap; | ||||
const CComponentManager::InterfaceListUnordered& CComponentManager::GetEntitiesWithInterfaceUnordered(InterfaceId iid) const | const CComponentManager::InterfaceListUnordered& CComponentManager::GetEntitiesWithInterfaceUnordered(InterfaceId iid) const | ||||
{ | { | ||||
if ((size_t)iid >= m_ComponentsByInterface.size()) | if ((size_t)iid >= m_ComponentsByInterface.size()) | ||||
{ | { | ||||
// 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); | PROFILE2_IFSPIKE("Post Message", 0.0005); | ||||
PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); | PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); | ||||
// 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; | MessageMap::const_iterator it = m_LocalMessageSubscriptions.find(msg.GetType()); | ||||
it = m_LocalMessageSubscriptions.find(msg.GetType()); | |||||
if (it != m_LocalMessageSubscriptions.end()) | if (it != m_LocalMessageSubscriptions.end()) | ||||
for (EntCompMap* entCompMap : it->second) | |||||
{ | { | ||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin(); | EntCompMap::iterator eit = entCompMap->find(ent); | ||||
for (; ctit != it->second.end(); ++ctit) | if (eit != entCompMap->end()) | ||||
{ | |||||
// 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); | |||||
if (emap == m_ComponentsByTypeId.end()) | |||||
continue; | |||||
// Send the message to all of them | |||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.find(ent); | |||||
if (eit != emap->second.end()) | |||||
eit->second->HandleMessage(msg, false); | eit->second->HandleMessage(msg, false); | ||||
} | } | ||||
} | |||||
SendGlobalMessage(ent, msg); | 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; | MessageMap::const_iterator it = m_LocalMessageSubscriptions.find(msg.GetType()); | ||||
it = m_LocalMessageSubscriptions.find(msg.GetType()); | |||||
if (it != m_LocalMessageSubscriptions.end()) | if (it != m_LocalMessageSubscriptions.end()) | ||||
{ | for (EntCompMap* entCompMap : it->second) | ||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin(); | for (std::pair<entity_id_t, IComponent*>& entComp : *entCompMap) | ||||
for (; ctit != it->second.end(); ++ctit) | entComp.second->HandleMessage(msg, false); | ||||
{ | |||||
// 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); | |||||
if (emap == m_ComponentsByTypeId.end()) | |||||
continue; | |||||
// Send the message to all of them | |||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin(); | |||||
for (; eit != emap->second.end(); ++eit) | |||||
eit->second->HandleMessage(msg, false); | |||||
} | |||||
} | |||||
SendGlobalMessage(INVALID_ENTITY, msg); | SendGlobalMessage(INVALID_ENTITY, msg); | ||||
} | } | ||||
void CComponentManager::SendGlobalMessage(entity_id_t ent, const CMessage& msg) | void CComponentManager::SendGlobalMessage(entity_id_t ent, const CMessage& msg) | ||||
{ | { | ||||
PROFILE2_IFSPIKE("SendGlobalMessage", 0.001); | PROFILE2_IFSPIKE("SendGlobalMessage", 0.001); | ||||
PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); | PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); | ||||
// (Common functionality for PostMessage and BroadcastMessage) | // (Common functionality for PostMessage and BroadcastMessage) | ||||
// Send the message to components of all entities that subscribed globally to this message | // Send the message to components of all entities that subscribed globally to this message | ||||
std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it; | MessageMap::const_iterator it = m_GlobalMessageSubscriptions.find(msg.GetType()); | ||||
it = m_GlobalMessageSubscriptions.find(msg.GetType()); | |||||
if (it != m_GlobalMessageSubscriptions.end()) | if (it != m_GlobalMessageSubscriptions.end()) | ||||
{ | for (EntCompMap* entCompMap : it->second) | ||||
Not Done Inline Actionspointer operator ->? elexis: pointer operator ->? | |||||
Done Inline Actionsprobably regex-modifying gone wrong wraitii: probably regex-modifying gone wrong | |||||
std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin(); | |||||
for (; ctit != it->second.end(); ++ctit) | |||||
{ | { | ||||
// Special case: Messages for local entities shouldn't be sent to script | // Special case: Messages for local entities shouldn't be sent to script | ||||
// components that subscribed globally, so that we don't have to worry about | // components that subscribed globally, so that we don't have to worry about | ||||
// them accidentally picking up non-network-synchronised data. | // them accidentally picking up non-network-synchronised data. | ||||
if (ENTITY_IS_LOCAL(ent)) | if (ENTITY_IS_LOCAL(ent)) | ||||
{ | { | ||||
std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(*ctit); | ComponentTypeId cid = entCompMap - m_ComponentsByTypeId.data(); | ||||
std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(cid); | |||||
if (it != m_ComponentTypesById.end() && it->second.type == CT_Script) | if (it != m_ComponentTypesById.end() && it->second.type == CT_Script) | ||||
continue; | continue; | ||||
} | } | ||||
for (std::pair<entity_id_t, IComponent*>& entComp : *entCompMap) | |||||
// Find the component instances of this type (if any) | entComp.second->HandleMessage(msg, true); | ||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit); | |||||
if (emap == m_ComponentsByTypeId.end()) | |||||
continue; | |||||
// Send the message to all of them | |||||
std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin(); | |||||
for (; eit != emap->second.end(); ++eit) | |||||
eit->second->HandleMessage(msg, true); | |||||
} | |||||
} | } | ||||
// Send the message to component instances that dynamically subscribed to this message | // Send the message to component instances that dynamically subscribed to this message | ||||
std::map<MessageTypeId, CDynamicSubscription>::iterator dit = m_DynamicMessageSubscriptionsNonsync.find(msg.GetType()); | std::map<MessageTypeId, CDynamicSubscription>::iterator dit = m_DynamicMessageSubscriptionsNonsync.find(msg.GetType()); | ||||
if (dit != m_DynamicMessageSubscriptionsNonsync.end()) | if (dit != m_DynamicMessageSubscriptionsNonsync.end()) | ||||
{ | { | ||||
dit->second.Flatten(); | dit->second.Flatten(); | ||||
const std::vector<IComponent*>& dynamic = dit->second.GetComponents(); | const std::vector<IComponent*>& dynamic = dit->second.GetComponents(); | ||||
for (size_t i = 0; i < dynamic.size(); i++) | for (size_t i = 0; i < dynamic.size(); i++) | ||||
▲ Show 20 Lines • Show All 76 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
or perhaps there is EntityComponentMap.iterator_type_something