Changeset View
Standalone View
source/simulation2/system/ComponentManager.cpp
Show All 25 Lines | ||||||||||
#include "ps/scripting/JSInterface_VFS.h" | #include "ps/scripting/JSInterface_VFS.h" | |||||||||
#include "scriptinterface/FunctionWrapper.h" | #include "scriptinterface/FunctionWrapper.h" | |||||||||
#include "simulation2/components/ICmpTemplateManager.h" | #include "simulation2/components/ICmpTemplateManager.h" | |||||||||
#include "simulation2/MessageTypes.h" | #include "simulation2/MessageTypes.h" | |||||||||
#include "simulation2/system/DynamicSubscription.h" | #include "simulation2/system/DynamicSubscription.h" | |||||||||
#include "simulation2/system/IComponent.h" | #include "simulation2/system/IComponent.h" | |||||||||
#include "simulation2/system/ParamNode.h" | #include "simulation2/system/ParamNode.h" | |||||||||
#include "simulation2/system/SimContext.h" | #include "simulation2/system/SimContext.h" | |||||||||
#include "simulation2/system/ComponentDataHolder.h" | ||||||||||
/** | /** | |||||||||
* Used for script-only message types. | * Used for script-only message types. | |||||||||
*/ | */ | |||||||||
class CMessageScripted final : public CMessage | class CMessageScripted final : public CMessage | |||||||||
{ | { | |||||||||
public: | public: | |||||||||
virtual int GetType() const { return mtid; } | virtual int GetType() const { return mtid; } | |||||||||
virtual const char* GetScriptHandlerName() const { return handlerName.c_str(); } | virtual const char* GetScriptHandlerName() const { return handlerName.c_str(); } | |||||||||
virtual const char* GetScriptGlobalHandlerName() const { return globalHandlerName.c_str(); } | virtual const char* GetScriptGlobalHandlerName() const { return globalHandlerName.c_str(); } | |||||||||
virtual JS::Value ToJSVal(const ScriptInterface& UNUSED(scriptInterface)) const { return msg.get(); } | virtual JS::Value ToJSVal(const ScriptInterface& UNUSED(scriptInterface)) const { return msg.get(); } | |||||||||
CMessageScripted(const ScriptInterface& scriptInterface, int mtid, const std::string& name, JS::HandleValue msg) : | CMessageScripted(const ScriptInterface& scriptInterface, int mtid, const std::string& name, JS::HandleValue msg) : | |||||||||
mtid(mtid), handlerName("On" + name), globalHandlerName("OnGlobal" + name), msg(scriptInterface.GetGeneralJSContext(), msg) | mtid(mtid), handlerName("On" + name), globalHandlerName("OnGlobal" + name), msg(scriptInterface.GetGeneralJSContext(), msg) | |||||||||
{ | { | |||||||||
} | } | |||||||||
int mtid; | int mtid; | |||||||||
std::string handlerName; | std::string handlerName; | |||||||||
std::string globalHandlerName; | std::string globalHandlerName; | |||||||||
JS::PersistentRootedValue msg; | JS::PersistentRootedValue msg; | |||||||||
}; | }; | |||||||||
CComponentManager::CComponentManager(CSimContext& context, std::shared_ptr<ScriptContext> cx, bool skipScriptFunctions) : | CComponentManager::CComponentManager(CSimContext& context, std::shared_ptr<ScriptContext> cx, bool skipScriptFunctions) : | |||||||||
m_NextScriptComponentTypeId(CID__LastNative), | m_NextScriptComponentTypeId(CID__LastNative), | |||||||||
m_ScriptInterface("Engine", "Simulation", cx), | m_ScriptInterface("Engine", "Simulation", cx), | |||||||||
m_SimContext(context), m_CurrentlyHotloading(false) | m_SimContext(context), m_CurrentlyHotloading(false) | |||||||||
{ | { | |||||||||
context.SetComponentManager(this); | context.SetComponentManager(this); | |||||||||
m_ScriptInterface.SetCallbackData(static_cast<void*> (this)); | m_ScriptInterface.SetCallbackData(static_cast<void*> (this)); | |||||||||
Show All 39 Lines | ||||||||||
#undef INTERFACE | #undef INTERFACE | |||||||||
#undef COMPONENT | #undef COMPONENT | |||||||||
m_ScriptInterface.SetGlobal("INVALID_ENTITY", (int)INVALID_ENTITY); | m_ScriptInterface.SetGlobal("INVALID_ENTITY", (int)INVALID_ENTITY); | |||||||||
m_ScriptInterface.SetGlobal("INVALID_PLAYER", (int)INVALID_PLAYER); | m_ScriptInterface.SetGlobal("INVALID_PLAYER", (int)INVALID_PLAYER); | |||||||||
m_ScriptInterface.SetGlobal("SYSTEM_ENTITY", (int)SYSTEM_ENTITY); | m_ScriptInterface.SetGlobal("SYSTEM_ENTITY", (int)SYSTEM_ENTITY); | |||||||||
m_ComponentsByInterface.resize(IID__LastNative); | m_ComponentsByInterface.resize(IID__LastNative); | |||||||||
m_ComponentDataByInterface.resize(IID__LastNative); | ||||||||||
ResetState(); | ResetState(); | |||||||||
} | } | |||||||||
CComponentManager::~CComponentManager() | CComponentManager::~CComponentManager() | |||||||||
{ | { | |||||||||
ResetState(); | ResetState(); | |||||||||
std::unordered_map<ComponentTypeId, CComponentDataHolder*>::iterator iit = m_ComponentData.begin(); | ||||||||||
for(;iit<m_ComponentData.End();++iit) | ||||||||||
delete *iit; | ||||||||||
} | } | |||||||||
void CComponentManager::LoadComponentTypes() | void CComponentManager::LoadComponentTypes() | |||||||||
{ | { | |||||||||
#define MESSAGE(name) \ | #define MESSAGE(name) \ | |||||||||
RegisterMessageType(MT_##name, #name); | RegisterMessageType(MT_##name, #name); | |||||||||
#define INTERFACE(name) \ | #define INTERFACE(name) \ | |||||||||
extern void RegisterComponentInterface_##name(ScriptInterface&); \ | extern void RegisterComponentInterface_##name(ScriptInterface&); \ | |||||||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | if (Script::HasProperty(rq, protoVal, "Schema")) | |||||||||
Script::GetProperty(rq, protoVal, "Schema", schema); | Script::GetProperty(rq, protoVal, "Schema", schema); | |||||||||
// Construct a new ComponentType, using the wrapper's alloc functions | // Construct a new ComponentType, using the wrapper's alloc functions | |||||||||
ComponentType ct{ | ComponentType ct{ | |||||||||
CT_Script, | CT_Script, | |||||||||
iid, | iid, | |||||||||
ctWrapper.alloc, | ctWrapper.alloc, | |||||||||
ctWrapper.dealloc, | ctWrapper.dealloc, | |||||||||
ctWrapper.size, | ||||||||||
ctWrapper.align, | ||||||||||
cname, | cname, | |||||||||
schema, | schema, | |||||||||
std::make_unique<JS::PersistentRootedValue>(rq.cx, ctor) | std::make_unique<JS::PersistentRootedValue>(rq.cx, ctor) | |||||||||
}; | }; | |||||||||
m_ComponentTypesById[cid] = std::move(ct); | m_ComponentTypesById[cid] = std::move(ct); | |||||||||
m_ComponentDataByInterface[iid] = m_ComponentData[cid] = new CComponentDataHolder(ct.size, ct.align); | ||||||||||
m_CurrentComponent = cid; // needed by Subscribe | m_CurrentComponent = cid; // needed by Subscribe | |||||||||
// Find all the ctor prototype's On* methods, and subscribe to the appropriate messages: | // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages: | |||||||||
std::vector<std::string> methods; | std::vector<std::string> methods; | |||||||||
if (!Script::EnumeratePropertyNames(rq, protoVal, false, methods)) | if (!Script::EnumeratePropertyNames(rq, protoVal, false, methods)) | |||||||||
{ | { | |||||||||
ScriptException::Raise(rq, "Failed to enumerate component properties."); | ScriptException::Raise(rq, "Failed to enumerate component properties."); | |||||||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | if (it != m_InterfaceIdsByName.end()) | |||||||||
} | } | |||||||||
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 = m_InterfaceIdsByName.size() + 1; | size_t id = m_InterfaceIdsByName.size() + 1; | |||||||||
m_InterfaceIdsByName[name] = (InterfaceId)id; | m_InterfaceIdsByName[name] = (InterfaceId)id; | |||||||||
m_ComponentsByInterface.resize(id+1); // add one so we can index by InterfaceId | m_ComponentsByInterface.resize(id+1); // add one so we can index by InterfaceId | |||||||||
m_ComponentDataByInterface.resize(id+1); | ||||||||||
m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int)id); | m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int)id); | |||||||||
} | } | |||||||||
void CComponentManager::Script_RegisterMessageType(const std::string& name) | void CComponentManager::Script_RegisterMessageType(const std::string& name) | |||||||||
{ | { | |||||||||
std::map<std::string, MessageTypeId>::iterator it = m_MessageTypeIdsByName.find(name); | std::map<std::string, MessageTypeId>::iterator it = m_MessageTypeIdsByName.find(name); | |||||||||
if (it != m_MessageTypeIdsByName.end()) | if (it != m_MessageTypeIdsByName.end()) | |||||||||
{ | { | |||||||||
Show All 32 Lines | const CParamNode& CComponentManager::Script_GetTemplate(const std::string& templateName) | |||||||||
const CParamNode* tmpl = cmpTemplateManager->GetTemplate(templateName); | const CParamNode* tmpl = cmpTemplateManager->GetTemplate(templateName); | |||||||||
if (!tmpl) | if (!tmpl) | |||||||||
return nullNode; | return nullNode; | |||||||||
return *tmpl; | return *tmpl; | |||||||||
} | } | |||||||||
std::vector<int> CComponentManager::Script_GetEntitiesWithInterface(int iid) | std::vector<int> CComponentManager::Script_GetEntitiesWithInterface(int iid) | |||||||||
{ | { | |||||||||
std::vector<int> ret; | std::vector<int> ret; | |||||||||
const InterfaceListUnordered& ents = GetEntitiesWithInterfaceUnordered(iid); | SComponentDataGenerator* ents = GetEntitiesWithInterfaceUnordered(iid); | |||||||||
Stan: Should we reserve some space? | ||||||||||
for (InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it) | while(IComponent* cmp = ents->Next()) | |||||||||
Done Inline ActionsCan we get them ordered by id, since we sort them at l419? Stan: Can we get them ordered by id, since we sort them at l419? | ||||||||||
if (!ENTITY_IS_LOCAL(it->first)) | if (!ENTITY_IS_LOCAL(cmp->GetEntityId())) | |||||||||
Done Inline ActionsShould we cache GetEntityId() instead of calling it twice? Stan: Should we cache GetEntityId() instead of calling it twice? | ||||||||||
Done Inline ActionsThe compiler should be able to handle that kind of optimization. Mercury: The compiler should be able to handle that kind of optimization. | ||||||||||
Done Inline ActionsSadly for you we use msvc :) If we'd use clang I'd say yes. But I've seen it not optimize var a = b * c for( i = 0; I b*c; ++i)... https://godbolt.org/z/vaWxv7vr5 Anyway, seems to work in this case, sorry :) Stan: Sadly for you we use msvc :) If we'd use clang I'd say yes. But I've seen it not optimize
var… | ||||||||||
ret.push_back(it->first); | ret.push_back(cmp->GetEntityId()); | |||||||||
Done Inline ActionsWould be nice to not iterate at all in local entities https://github.com/0ad/0ad/blob/f314b5b9d2be852a4d25f4b9ef40ab4acf4f2002/source/simulation2/system/Entity.h#L59 Stan: Would be nice to not iterate at all in local entities https://github. | ||||||||||
std::sort(ret.begin(), ret.end()); | std::sort(ret.begin(), ret.end()); | |||||||||
return ret; | return ret; | |||||||||
} | } | |||||||||
std::vector<IComponent*> CComponentManager::Script_GetComponentsWithInterface(int iid) | std::vector<IComponent*> CComponentManager::Script_GetComponentsWithInterface(int iid) | |||||||||
{ | { | |||||||||
std::vector<IComponent*> ret; | std::vector<IComponent*> ret; | |||||||||
InterfaceList ents = GetEntitiesWithInterface(iid); | const InterfaceList& ents = GetEntitiesWithInterface(iid); | |||||||||
for (InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) | for (InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) | |||||||||
ret.push_back(it->second); // TODO: maybe we should exclude local entities | ret.push_back(it->second); // TODO: maybe we should exclude local entities | |||||||||
return ret; | return ret; | |||||||||
} | } | |||||||||
CMessage* CComponentManager::ConstructMessage(int mtid, JS::HandleValue data) | CMessage* CComponentManager::ConstructMessage(int mtid, JS::HandleValue data) | |||||||||
{ | { | |||||||||
if (mtid == MT__Invalid || mtid > (int)m_MessageTypeIdsByName.size()) // (IDs start at 1 so use '>' here) | if (mtid == MT__Invalid || mtid > (int)m_MessageTypeIdsByName.size()) // (IDs start at 1 so use '>' here) | |||||||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | void CComponentManager::ResetState() | |||||||||
} | } | |||||||||
std::vector<std::unordered_map<entity_id_t, IComponent*> >::iterator ifcit = m_ComponentsByInterface.begin(); | std::vector<std::unordered_map<entity_id_t, IComponent*> >::iterator ifcit = m_ComponentsByInterface.begin(); | |||||||||
for (; ifcit != m_ComponentsByInterface.end(); ++ifcit) | for (; ifcit != m_ComponentsByInterface.end(); ++ifcit) | |||||||||
ifcit->clear(); | ifcit->clear(); | |||||||||
m_ComponentsByTypeId.clear(); | m_ComponentsByTypeId.clear(); | |||||||||
std::unordered_map<ComponentTypeId, CComponentDataHolder*>::iterator it = m_ComponentData.begin(); | ||||||||||
Done Inline Actionsnit: I know we typically avoid auto in the 0AD codebase, but this is one of those places where it's actually pretty useful from a readability PoV. jprahman: nit: I know we typically avoid `auto` in the 0AD codebase, but this is one of those places… | ||||||||||
for(;it != m_ComponentData.end(); it++) | ||||||||||
it->second->ResetState(); | ||||||||||
// 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(); | |||||||||
m_SystemEntity = CEntityHandle(); | m_SystemEntity = CEntityHandle(); | |||||||||
m_DestructionQueue.clear(); | m_DestructionQueue.clear(); | |||||||||
// Reset IDs | // Reset IDs | |||||||||
m_NextEntityId = SYSTEM_ENTITY + 1; | m_NextEntityId = SYSTEM_ENTITY + 1; | |||||||||
m_NextLocalEntityId = FIRST_LOCAL_ENTITY; | m_NextLocalEntityId = FIRST_LOCAL_ENTITY; | |||||||||
} | } | |||||||||
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) | size_t size, size_t align, const char* name, const std::string& schema) | |||||||||
{ | { | |||||||||
ComponentType c{ CT_Native, iid, alloc, dealloc, name, schema, std::unique_ptr<JS::PersistentRootedValue>() }; | ComponentType c{ CT_Native, iid, alloc, dealloc, size, align, name, schema, std::unique_ptr<JS::PersistentRootedValue>() }; | |||||||||
m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | |||||||||
m_ComponentTypeIdsByName[name] = cid; | m_ComponentTypeIdsByName[name] = cid; | |||||||||
m_ComponentDataByInterface[iid] = m_ComponentData[cid] = new CComponentDataHolder(size, align); | ||||||||||
} | } | |||||||||
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, size_t size, size_t align, const char* name, const std::string& schema) | |||||||||
{ | { | |||||||||
ComponentType c{ CT_ScriptWrapper, iid, alloc, dealloc, name, schema, std::unique_ptr<JS::PersistentRootedValue>() }; | ComponentType c{ CT_ScriptWrapper, iid, alloc, dealloc, size, align, name, schema, std::unique_ptr<JS::PersistentRootedValue>() }; | |||||||||
m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); | |||||||||
m_ComponentTypeIdsByName[name] = cid; | m_ComponentTypeIdsByName[name] = cid; | |||||||||
m_ComponentDataByInterface[iid] = m_ComponentData[cid] = new CComponentDataHolder(size, align); | ||||||||||
// 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); | |||||||||
} | } | |||||||||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | if (ct.type == CT_Script) | |||||||||
{ | { | |||||||||
LOGERROR("Script component constructor failed"); | LOGERROR("Script component constructor failed"); | |||||||||
return NULL; | return NULL; | |||||||||
} | } | |||||||||
} | } | |||||||||
// Construct the new component | // Construct the new component | |||||||||
// NB: The unit motion manager relies on components not moving in memory once constructed. | // NB: The unit motion manager relies on components not moving in memory once constructed. | |||||||||
IComponent* component = ct.alloc(m_ScriptInterface, obj); | void* address = m_ComponentData[cid]->Allocate(); | |||||||||
IComponent* component = ct.alloc(address, m_ScriptInterface, obj); | ||||||||||
Done Inline ActionsPer earlier comment, ct.construct may be more accurate now, rather than ct.alloc() since actual allocation takes place in the pool allocator jprahman: Per earlier comment, ct.construct may be more accurate now, rather than ct.alloc() since actual… | ||||||||||
ENSURE(sizeof(*component) <= ct.size); | ||||||||||
Done Inline Actionsstd::byte* ? Stan: std::byte* ? | ||||||||||
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(std::make_pair(ent.GetId(), component)); | |||||||||
emap2.insert(std::make_pair(ent.GetId(), component)); | emap2.insert(std::make_pair(ent.GetId(), component)); | |||||||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | for (std::vector<entity_id_t>::iterator it = queue.begin(); it != queue.end(); ++it) | |||||||||
std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin(); | std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::iterator iit = m_ComponentsByTypeId.begin(); | |||||||||
for (; iit != m_ComponentsByTypeId.end(); ++iit) | for (; iit != m_ComponentsByTypeId.end(); ++iit) | |||||||||
{ | { | |||||||||
std::map<entity_id_t, IComponent*>::iterator eit = iit->second.find(ent); | std::map<entity_id_t, IComponent*>::iterator eit = iit->second.find(ent); | |||||||||
if (eit != iit->second.end()) | if (eit != iit->second.end()) | |||||||||
{ | { | |||||||||
eit->second->Deinit(); | eit->second->Deinit(); | |||||||||
RemoveComponentDynamicSubscriptions(eit->second); | RemoveComponentDynamicSubscriptions(eit->second); | |||||||||
m_ComponentTypesById[iit->first].dealloc(eit->second); | m_ComponentTypesById[iit->first].dealloc(eit->second); | |||||||||
m_ComponentData[iit->first]->Deallocate(eit->second); | ||||||||||
Done Inline Actionsdealloc should probably be renamed to deconstruct, since it only calls the deconstructor. Mercury: dealloc should probably be renamed to deconstruct, since it only calls the deconstructor. | ||||||||||
iit->second.erase(ent); | iit->second.erase(ent); | |||||||||
handle.GetComponentCache()->interfaces[m_ComponentTypesById[iit->first].iid] = NULL; | handle.GetComponentCache()->interfaces[m_ComponentTypesById[iit->first].iid] = NULL; | |||||||||
} | } | |||||||||
} | } | |||||||||
free(handle.GetComponentCache()); | free(handle.GetComponentCache()); | |||||||||
m_ComponentCaches.erase(ent); | m_ComponentCaches.erase(ent); | |||||||||
Show All 30 Lines | 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()); | |||||||||
Done Inline ActionsNo space between > and > only needed for compilers before c++11 Stan: No space between > and > only needed for compilers before c++11 | ||||||||||
std::unordered_map<entity_id_t, IComponent*>::const_iterator it = m_ComponentsByInterface[iid].begin(); | SComponentDataGenerator* gen = new SComponentDataGenerator(m_ComponentDataByInterface[iid]); | |||||||||
for (; it != m_ComponentsByInterface[iid].end(); ++it) | while(IComponent* cmp = gen->Next()) | |||||||||
Done Inline Actions
Stan: | ||||||||||
ret.push_back(*it); | ret.push_back(std::pair<entity_id_t, IComponent*>(cmp->GetEntityId(), cmp)); | |||||||||
Done Inline Actionsthere is no matching delete. why even create it on the heap? phosit: there is no matching delete. why even create it on the heap? | ||||||||||
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; | SComponentDataGenerator* 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 NULL; | |||||||||
Done Inline Actionsnullptr Stan: nullptr | ||||||||||
Done Inline Actionsthis gets dereferenced in SComponentDataGenerator::reset and SComponentDataGenerator::next phosit: this gets dereferenced in `SComponentDataGenerator::reset` and `SComponentDataGenerator::next`… | ||||||||||
Done Inline ActionsThis needs to be tested maybe some dummy js code ?usually replacing a warning by a crash isn't good :) Stan: This needs to be tested maybe some dummy js code ?usually replacing a warning by a crash isn't… | ||||||||||
Done Inline ActionsPreviously it wouldn't give a warning, it would just do nothing. IIRC the engine is not expected to be able to load components after entities have been created so trying to iterate a non existent IID indicates an error somewhere and probably shouldn't fail silently. We could make it print a warning and do nothing, but I think a serious enough error should crash. Mercury: Previously it wouldn't give a warning, it would just do nothing. IIRC the engine is not… | ||||||||||
Done Inline ActionsI need @wraitii's input on this, but I though one was able to add and remove components. Stan: I need @wraitii's input on this, but I though one was able to add and remove components. | ||||||||||
Done Inline ActionsI believe wraitii was the one who told me that was not the case, but it was in IRC so I don't have a quote to paste. FWIW I can't think of a situation where that would be useful. Mercury: I believe wraitii was the one who told me that was not the case, but it was in IRC so I don't… | ||||||||||
Done Inline ActionsPartial entity update. Destroying and Creating entities is slow. E.g in case of promotion / upgrade. Not implemented yet. Stan: Partial entity update. Destroying and Creating entities is //slow//. E.g in case of promotion /… | ||||||||||
Done Inline ActionsSorry but I don't see the connection between partial entity update and loading components after the game has started. Mercury: Sorry but I don't see the connection between partial entity update and loading components after… | ||||||||||
Done Inline ActionsAh I think I understand, this means adding actual components to the game, which can only happen through JavaScript hotloading. Not adding components to the entities in game; Correct? Stan: Ah I think I understand, this means adding actual components to the game, which can only happen… | ||||||||||
Done Inline Actionsyup Mercury: yup | ||||||||||
Not Done Inline ActionsI think this shouldn't crash. You can send a call from JS with an invalid ID fairly easily, and it would be bad that it crashes. Might be handled elsewhere though. wraitii: I think this shouldn't crash. You can send a call from JS with an invalid ID fairly easily, and… | ||||||||||
} | } | |||||||||
return m_ComponentsByInterface[iid]; | return new SComponentDataGenerator(m_ComponentDataByInterface[iid]); | |||||||||
Done Inline Actions
Sorry for the confusion then. Now I wonder what happens if you register a component in JS at runtime :D /** * same as ENSURE in debug mode, does nothing in release mode. * (we don't override the `assert' macro because users may * inadvertently include \<assert.h\> afterwards) * (we do not provide an MFC-style VERIFY macro because the distinction * between ENSURE and VERIFY is unclear. to always run code but only * check for success in debug builds without raising unused-variable warnings, * use ASSERT + UNUSED2.) **/ #define ASSERT(expr) ENSURE(expr) #ifdef NDEBUG # undef ASSERT # define ASSERT(expr) #endif Stan: Sorry for the confusion then. Now I wonder what happens if you register a component in JS at… | ||||||||||
Done Inline Actions
Stan: | ||||||||||
} | } | |||||||||
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; | std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it; | |||||||||
Show All 13 Lines | for (; ctit != it->second.end(); ++ctit) | |||||||||
if (eit != emap->second.end()) | 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) | |||||||||
Done Inline ActionsConst method? Stan: Const method? | ||||||||||
{ | { | |||||||||
// 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()) | |||||||||
{ | { | |||||||||
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); | SComponentDataGenerator* gen = new SComponentDataGenerator(m_ComponentData[*ctit]); | |||||||||
if (emap == m_ComponentsByTypeId.end()) | ||||||||||
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.begin(); | while(IComponent* cmp = gen->Next()) | |||||||||
for (; eit != emap->second.end(); ++eit) | cmp->HandleMessage(msg, false); | |||||||||
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) | |||||||||
Show All 12 Lines | for (; ctit != it->second.end(); ++ctit) | |||||||||
if (ENTITY_IS_LOCAL(ent)) | if (ENTITY_IS_LOCAL(ent)) | |||||||||
{ | { | |||||||||
std::map<ComponentTypeId, ComponentType>::const_iterator cit = m_ComponentTypesById.find(*ctit); | std::map<ComponentTypeId, ComponentType>::const_iterator cit = m_ComponentTypesById.find(*ctit); | |||||||||
if (cit != m_ComponentTypesById.end() && cit->second.type == CT_Script) | if (cit != m_ComponentTypesById.end() && cit->second.type == CT_Script) | |||||||||
continue; | continue; | |||||||||
} | } | |||||||||
// 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); | SComponentDataGenerator* gen = new SComponentDataGenerator(m_ComponentData[*ctit]); | |||||||||
if (emap == m_ComponentsByTypeId.end()) | ||||||||||
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.begin(); | while(IComponent* cmp = gen->Next()) | |||||||||
for (; eit != emap->second.end(); ++eit) | cmp->HandleMessage(msg, true); | |||||||||
Done Inline ActionsShould we have a method that does those three lines of code to remove duplication? Stan: Should we have a method that does those three lines of code to remove duplication? | ||||||||||
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(); | |||||||||
▲ Show 20 Lines • Show All 78 Lines • Show Last 20 Lines |
Should we reserve some space?