diff --git a/binaries/data/mods/public/simulation/helpers/InitGame.js b/binaries/data/mods/public/simulation/helpers/InitGame.js
index 0da8fa9..9106446 100644
a
|
b
|
function InitGame(settings)
|
76 | 76 | cmpAIManager.SetRNGSeed(seed); |
77 | 77 | cmpAIManager.TryLoadSharedComponent(); |
78 | 78 | cmpAIManager.RunGamestateInit(); |
| 79 | |
| 80 | // If there are no AIs in the game, don't bother sending message to AIProxy, which takes a few ms per turn in MP games sometimes. |
| 81 | if (!cmpAIManager.HasActiveAIs()) |
| 82 | Engine.SkipComponent("AIProxy"); |
79 | 83 | } |
80 | 84 | |
81 | 85 | Engine.RegisterGlobal("PreInitGame", PreInitGame); |
diff --git a/source/simulation2/components/CCmpAIManager.cpp b/source/simulation2/components/CCmpAIManager.cpp
index dd210c6..4981595 100644
a
|
b
|
public:
|
1159 | 1159 | } |
1160 | 1160 | } |
1161 | 1161 | |
| 1162 | virtual bool HasActiveAIs() |
| 1163 | { |
| 1164 | return m_Worker.getPlayerSize() > 0; |
| 1165 | } |
| 1166 | |
1162 | 1167 | private: |
1163 | 1168 | std::vector<std::string> m_TemplateNames; |
1164 | 1169 | size_t m_TemplateLoadedIdx; |
diff --git a/source/simulation2/components/ICmpAIManager.cpp b/source/simulation2/components/ICmpAIManager.cpp
index 316618f..5b63213 100644
a
|
b
|
DEFINE_INTERFACE_METHOD_3("AddPlayer", void, ICmpAIManager, AddPlayer, std::wstr
|
29 | 29 | DEFINE_INTERFACE_METHOD_1("SetRNGSeed", void, ICmpAIManager, SetRNGSeed, uint32_t) |
30 | 30 | DEFINE_INTERFACE_METHOD_0("TryLoadSharedComponent", void, ICmpAIManager, TryLoadSharedComponent) |
31 | 31 | DEFINE_INTERFACE_METHOD_0("RunGamestateInit", void, ICmpAIManager, RunGamestateInit) |
| 32 | DEFINE_INTERFACE_METHOD_0("HasActiveAIs", bool, ICmpAIManager, HasActiveAIs) |
32 | 33 | END_INTERFACE_WRAPPER(AIManager) |
33 | 34 | |
34 | 35 | // Implement the static method that finds all AI scripts |
diff --git a/source/simulation2/components/ICmpAIManager.h b/source/simulation2/components/ICmpAIManager.h
index 97d46f7..5f97912 100644
a
|
b
|
public:
|
48 | 48 | virtual void PushCommands() = 0; |
49 | 49 | |
50 | 50 | /** |
| 51 | * Returns true if there are currently any AI registered with the AiManager |
| 52 | */ |
| 53 | virtual bool HasActiveAIs() = 0; |
| 54 | |
| 55 | /** |
51 | 56 | * Returns a vector of {"id":"value-for-AddPlayer", "name":"Human readable name"} |
52 | 57 | * objects, based on all the available AI scripts. |
53 | 58 | */ |
diff --git a/source/simulation2/system/ComponentManager.cpp b/source/simulation2/system/ComponentManager.cpp
index 005b82b..e6d45d5 100644
a
|
b
|
|
26 | 26 | |
27 | 27 | #include "simulation2/MessageTypes.h" |
28 | 28 | #include "simulation2/components/ICmpTemplateManager.h" |
| 29 | #include "simulation2/components/ICmpAiManager.h" |
29 | 30 | |
30 | 31 | #include "lib/utf8.h" |
31 | 32 | #include "ps/CLogger.h" |
… |
… |
CComponentManager::CComponentManager(CSimContext& context, shared_ptr<ScriptRunt
|
74 | 75 | m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterInterface> ("RegisterInterface"); |
75 | 76 | m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_RegisterMessageType> ("RegisterMessageType"); |
76 | 77 | m_ScriptInterface.RegisterFunction<void, std::string, JS::HandleValue, CComponentManager::Script_RegisterGlobal> ("RegisterGlobal"); |
| 78 | m_ScriptInterface.RegisterFunction<void, std::string, CComponentManager::Script_SkipComponent> ("SkipComponent"); |
77 | 79 | m_ScriptInterface.RegisterFunction<IComponent*, int, int, CComponentManager::Script_QueryInterface> ("QueryInterface"); |
78 | 80 | m_ScriptInterface.RegisterFunction<std::vector<int>, int, CComponentManager::Script_GetEntitiesWithInterface> ("GetEntitiesWithInterface"); |
79 | 81 | m_ScriptInterface.RegisterFunction<std::vector<IComponent*>, int, CComponentManager::Script_GetComponentsWithInterface> ("GetComponentsWithInterface"); |
… |
… |
void CComponentManager::Script_RegisterInterface(ScriptInterface::CxPrivate* pCx
|
359 | 361 | componentManager->m_ScriptInterface.SetGlobal(("IID_" + name).c_str(), (int)id); |
360 | 362 | } |
361 | 363 | |
| 364 | void CComponentManager::Script_SkipComponent(ScriptInterface::CxPrivate* pCxPrivate, const std::string& cname) |
| 365 | { |
| 366 | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); |
| 367 | ComponentTypeId cid = componentManager->LookupCID(cname); |
| 368 | if (cid == CID__Invalid) |
| 369 | { |
| 370 | std::string msg("Trying to skip invalid component " + cname); |
| 371 | componentManager->m_ScriptInterface.ReportError(msg.c_str()); |
| 372 | return; |
| 373 | } |
| 374 | componentManager->SkipComponent(cid); |
| 375 | } |
| 376 | |
362 | 377 | void CComponentManager::Script_RegisterMessageType(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name) |
363 | 378 | { |
364 | 379 | CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData); |
… |
… |
void CComponentManager::SetRNGSeed(u32 seed)
|
543 | 558 | m_RNG.seed(seed); |
544 | 559 | } |
545 | 560 | |
| 561 | void CComponentManager::SkipComponent(const ComponentTypeId& ID) |
| 562 | { |
| 563 | // unsubscribe the component from all messages, effectively this is similar to removing it altogether. |
| 564 | for (auto& messageType : m_LocalMessageSubscriptions) |
| 565 | { |
| 566 | std::vector<ComponentTypeId>::iterator component = std::find(messageType.second.begin(),messageType.second.end(), ID); |
| 567 | if (component != messageType.second.end()) |
| 568 | { |
| 569 | // pop and swap, I do not believe we actually care about the order here. |
| 570 | std::swap(*component, messageType.second.back()); |
| 571 | messageType.second.pop_back(); |
| 572 | } |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | |
546 | 577 | void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, |
547 | 578 | const char* name, const std::string& schema) |
548 | 579 | { |
… |
… |
entity_id_t CComponentManager::AddEntity(const std::wstring& templateName, entit
|
874 | 905 | continue; |
875 | 906 | |
876 | 907 | CComponentManager::ComponentTypeId cid = LookupCID(it->first); |
| 908 | |
877 | 909 | if (cid == CID__Invalid) |
878 | 910 | { |
879 | 911 | LOGERROR("Unrecognised component type name '%s' in entity template '%s'", it->first, utf8_from_wstring(templateName)); |
diff --git a/source/simulation2/system/ComponentManager.h b/source/simulation2/system/ComponentManager.h
index 8176dc5..16499ab 100644
a
|
b
|
public:
|
301 | 301 | */ |
302 | 302 | void SetRNGSeed(u32 seed); |
303 | 303 | |
| 304 | /** |
| 305 | * Tells the Component Manager to remove all subscriptions of a given component type, |
| 306 | * effectively making it similar to altogether removing that component (but in a less intrusive way). |
| 307 | * This is called in public mod for AIProxy in player-only games. |
| 308 | * Since AIProxy can end up taking several ms (>3/4) per turn doing nothing useful otherwise |
| 309 | */ |
| 310 | void SkipComponent(const ComponentTypeId& ID); |
| 311 | |
304 | 312 | // Various state serialization functions: |
305 | 313 | bool ComputeStateHash(std::string& outHash, bool quick); |
306 | 314 | bool DumpDebugState(std::ostream& stream, bool includeDebugInfo); |
… |
… |
private:
|
322 | 330 | static void Script_RegisterInterface(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name); |
323 | 331 | static void Script_RegisterMessageType(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name); |
324 | 332 | static void Script_RegisterGlobal(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name, JS::HandleValue value); |
| 333 | static void Script_SkipComponent(ScriptInterface::CxPrivate* pCxPrivate, const std::string& cname); |
325 | 334 | static IComponent* Script_QueryInterface(ScriptInterface::CxPrivate* pCxPrivate, int ent, int iid); |
326 | 335 | static std::vector<int> Script_GetEntitiesWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid); |
327 | 336 | static std::vector<IComponent*> Script_GetComponentsWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid); |
… |
… |
private:
|
385 | 394 | |
386 | 395 | boost::rand48 m_RNG; |
387 | 396 | |
| 397 | bool m_SkipAiProxy = false; |
| 398 | |
388 | 399 | friend class TestComponentManager; |
389 | 400 | }; |
390 | 401 | |