Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/system/ComponentManager.cpp
Show First 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | bool CComponentManager::LoadScript(const VfsPath& filename, bool hotload) | ||||
m_CurrentlyHotloading = false; | m_CurrentlyHotloading = false; | ||||
return ok; | return ok; | ||||
} | } | ||||
void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CmptPrivate* pCmptPrivate, int iid, const std::string& cname, JS::HandleValue ctor, bool reRegister, bool systemComponent) | void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CmptPrivate* pCmptPrivate, int iid, const std::string& cname, JS::HandleValue ctor, bool reRegister, bool systemComponent) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCmptPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCmptPrivate->pCBData); | ||||
ScriptInterface::Request rq(componentManager->m_ScriptInterface); | ScriptRequest rq(componentManager->m_ScriptInterface); | ||||
// Find the C++ component that wraps the interface | // Find the C++ component that wraps the interface | ||||
int cidWrapper = componentManager->GetScriptWrapper(iid); | int cidWrapper = componentManager->GetScriptWrapper(iid); | ||||
if (cidWrapper == CID__Invalid) | if (cidWrapper == CID__Invalid) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError("Invalid interface id"); | ScriptException::Raise(rq, "Invalid interface id"); | ||||
return; | return; | ||||
} | } | ||||
const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper]; | const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper]; | ||||
bool mustReloadComponents = false; // for hotloading | bool mustReloadComponents = false; // for hotloading | ||||
ComponentTypeId cid = componentManager->LookupCID(cname); | ComponentTypeId cid = componentManager->LookupCID(cname); | ||||
if (cid == CID__Invalid) | if (cid == CID__Invalid) | ||||
{ | { | ||||
if (reRegister) | if (reRegister) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError(("ReRegistering component type that was not registered before '" + cname + "'").c_str()); | ScriptException::Raise(rq, "ReRegistering component type that was not registered before '%s'", 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; | ||||
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) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError(("Registering component type with already-registered name '" + cname + "'").c_str()); | ScriptException::Raise(rq, "Registering component type with already-registered name '%s'", cname.c_str()); | ||||
return; | return; | ||||
} | } | ||||
const ComponentType& ctPrevious = componentManager->m_ComponentTypesById[cid]; | const ComponentType& ctPrevious = componentManager->m_ComponentTypesById[cid]; | ||||
// We can only replace scripted component types, not native ones | // We can only replace scripted component types, not native ones | ||||
if (ctPrevious.type != CT_Script) | if (ctPrevious.type != CT_Script) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError(("Loading script component type with same name '" + cname + "' as native component").c_str()); | ScriptException::Raise(rq, "Loading script component type with same name '%s' as native component", cname.c_str()); | ||||
return; | return; | ||||
} | } | ||||
// We don't support changing the IID of a component type (it would require fiddling | // We don't support changing the IID of a component type (it would require fiddling | ||||
// around with m_ComponentsByInterface and being careful to guarantee uniqueness per entity) | // around with m_ComponentsByInterface and being careful to guarantee uniqueness per entity) | ||||
if (ctPrevious.iid != iid) | if (ctPrevious.iid != iid) | ||||
{ | { | ||||
// ...though it only matters if any components exist with this type | // ...though it only matters if any components exist with this type | ||||
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"); | ScriptException::Raise(rq, "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; | std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it; | ||||
for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it) | for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it) | ||||
{ | { | ||||
Show All 11 Lines | else | ||||
} | } | ||||
mustReloadComponents = true; | mustReloadComponents = true; | ||||
} | } | ||||
JS::RootedValue protoVal(rq.cx); | JS::RootedValue protoVal(rq.cx); | ||||
if (!componentManager->m_ScriptInterface.GetProperty(ctor, "prototype", &protoVal)) | if (!componentManager->m_ScriptInterface.GetProperty(ctor, "prototype", &protoVal)) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError("Failed to get property 'prototype'"); | ScriptException::Raise(rq, "Failed to get property 'prototype'"); | ||||
return; | return; | ||||
} | } | ||||
if (!protoVal.isObject()) | if (!protoVal.isObject()) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError("Component has no constructor"); | ScriptException::Raise(rq, "Component has no constructor"); | ||||
return; | return; | ||||
} | } | ||||
std::string schema = "<empty/>"; | std::string schema = "<empty/>"; | ||||
if (componentManager->m_ScriptInterface.HasProperty(protoVal, "Schema")) | if (componentManager->m_ScriptInterface.HasProperty(protoVal, "Schema")) | ||||
componentManager->m_ScriptInterface.GetProperty(protoVal, "Schema", schema); | componentManager->m_ScriptInterface.GetProperty(protoVal, "Schema", schema); | ||||
// Construct a new ComponentType, using the wrapper's alloc functions | // Construct a new ComponentType, using the wrapper's alloc functions | ||||
Show All 10 Lines | void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CmptPrivate* pCmptPrivate, int iid, const std::string& cname, JS::HandleValue ctor, bool reRegister, bool systemComponent) | ||||
componentManager->m_CurrentComponent = cid; // needed by Subscribe | componentManager->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 (!componentManager->m_ScriptInterface.EnumeratePropertyNames(protoVal, false, methods)) | if (!componentManager->m_ScriptInterface.EnumeratePropertyNames(protoVal, false, methods)) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError("Failed to enumerate component properties."); | ScriptException::Raise(rq, "Failed to enumerate component properties."); | ||||
return; | return; | ||||
} | } | ||||
for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it) | for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it) | ||||
{ | { | ||||
// TODO C++17: string_view | // TODO C++17: string_view | ||||
if (strncmp((it->c_str()), "On", 2) != 0) | if (strncmp((it->c_str()), "On", 2) != 0) | ||||
continue; | continue; | ||||
std::string name = (*it).substr(2); // strip the "On" prefix | std::string name = (*it).substr(2); // strip the "On" prefix | ||||
// Handle "OnGlobalFoo" functions specially | // Handle "OnGlobalFoo" functions specially | ||||
bool isGlobal = false; | bool isGlobal = false; | ||||
if (strncmp(name.c_str(), "Global", 6) == 0) | if (strncmp(name.c_str(), "Global", 6) == 0) | ||||
{ | { | ||||
isGlobal = true; | isGlobal = true; | ||||
name = name.substr(6); | name = name.substr(6); | ||||
} | } | ||||
std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name); | std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name); | ||||
if (mit == componentManager->m_MessageTypeIdsByName.end()) | if (mit == componentManager->m_MessageTypeIdsByName.end()) | ||||
{ | { | ||||
componentManager->m_ScriptInterface.ReportError(("Registered component has unrecognized '" + *it + "' message handler method").c_str()); | ScriptException::Raise(rq, "Registered component has unrecognized '%s' message handler method", it->c_str()); | ||||
return; | return; | ||||
} | } | ||||
if (isGlobal) | if (isGlobal) | ||||
componentManager->SubscribeGloballyToMessageType(mit->second); | componentManager->SubscribeGloballyToMessageType(mit->second); | ||||
else | else | ||||
componentManager->SubscribeToMessageType(mit->second); | componentManager->SubscribeToMessageType(mit->second); | ||||
} | } | ||||
Show All 39 Lines | void CComponentManager::Script_RegisterInterface(ScriptInterface::CmptPrivate* pCmptPrivate, const std::string& name) | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCmptPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCmptPrivate->pCBData); | ||||
std::map<std::string, InterfaceId>::iterator it = componentManager->m_InterfaceIdsByName.find(name); | std::map<std::string, InterfaceId>::iterator it = componentManager->m_InterfaceIdsByName.find(name); | ||||
if (it != componentManager->m_InterfaceIdsByName.end()) | if (it != componentManager->m_InterfaceIdsByName.end()) | ||||
{ | { | ||||
// Redefinitions are fine (and just get ignored) when hotloading; otherwise | // Redefinitions are fine (and just get ignored) when hotloading; otherwise | ||||
// 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()); | { | ||||
ScriptRequest rq(componentManager->m_ScriptInterface); | |||||
ScriptException::Raise(rq, "Registering interface with already-registered name '%s'", 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; | ||||
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::CmptPrivate* pCmptPrivate, const std::string& name) | void CComponentManager::Script_RegisterMessageType(ScriptInterface::CmptPrivate* pCmptPrivate, const std::string& name) | ||||
{ | { | ||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCmptPrivate->pCBData); | CComponentManager* componentManager = static_cast<CComponentManager*> (pCmptPrivate->pCBData); | ||||
std::map<std::string, MessageTypeId>::iterator it = componentManager->m_MessageTypeIdsByName.find(name); | std::map<std::string, MessageTypeId>::iterator it = componentManager->m_MessageTypeIdsByName.find(name); | ||||
if (it != componentManager->m_MessageTypeIdsByName.end()) | if (it != componentManager->m_MessageTypeIdsByName.end()) | ||||
{ | { | ||||
// Redefinitions are fine (and just get ignored) when hotloading; otherwise | // Redefinitions are fine (and just get ignored) when hotloading; otherwise | ||||
// 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 message type with already-registered name '" + name + "'").c_str()); | { | ||||
ScriptRequest rq(componentManager->m_ScriptInterface); | |||||
ScriptException::Raise(rq, "Registering message type with already-registered name '%s'", name.c_str()); | |||||
} | |||||
return; | return; | ||||
} | } | ||||
// MTIDs start at 1, so size+1 is the next unused one | // MTIDs start at 1, so size+1 is the next unused one | ||||
size_t id = componentManager->m_MessageTypeIdsByName.size() + 1; | size_t id = componentManager->m_MessageTypeIdsByName.size() + 1; | ||||
componentManager->RegisterMessageType((MessageTypeId)id, name.c_str()); | componentManager->RegisterMessageType((MessageTypeId)id, name.c_str()); | ||||
componentManager->m_ScriptInterface.SetGlobal(("MT_" + name).c_str(), (int)id); | componentManager->m_ScriptInterface.SetGlobal(("MT_" + name).c_str(), (int)id); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 347 Lines • ▼ Show 20 Lines | for (uint32_t i = 0; i < m_ScriptedSystemComponents.size(); ++i) | ||||
AddComponent(m_SystemEntity, m_ScriptedSystemComponents[i], noParam); | AddComponent(m_SystemEntity, m_ScriptedSystemComponents[i], noParam); | ||||
if (!skipAI) | if (!skipAI) | ||||
AddComponent(m_SystemEntity, CID_AIManager, noParam); | AddComponent(m_SystemEntity, CID_AIManager, noParam); | ||||
} | } | ||||
} | } | ||||
IComponent* CComponentManager::ConstructComponent(CEntityHandle ent, ComponentTypeId cid) | IComponent* CComponentManager::ConstructComponent(CEntityHandle ent, ComponentTypeId cid) | ||||
{ | { | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(cid); | std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(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; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 435 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator