Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -245,7 +245,7 @@ this.FinishOrder(); return; } - +Engine.DistributeMessage([this.entity], MT_Attacked, { "attacker": this.entity }); // Stop moving immediately. this.StopMoving(); this.FinishOrder(); Index: source/simulation2/Simulation2.h =================================================================== --- source/simulation2/Simulation2.h +++ source/simulation2/Simulation2.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -202,6 +202,7 @@ IComponent* QueryInterface(entity_id_t ent, int iid) const; void PostMessage(entity_id_t ent, const CMessage& msg) const; + void DistributeMessage(const std::vector& entities, const CMessage& msg) const; void BroadcastMessage(const CMessage& msg) const; using InterfaceList = Index: source/simulation2/Simulation2.cpp =================================================================== --- source/simulation2/Simulation2.cpp +++ source/simulation2/Simulation2.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -710,6 +710,11 @@ m->m_ComponentManager.PostMessage(ent, msg); } +void CSimulation2::DistributeMessage(const std::vector& entities, const CMessage& msg) const +{ + m->m_ComponentManager.DistributeMessage(entities, msg); +} + void CSimulation2::BroadcastMessage(const CMessage& msg) const { m->m_ComponentManager.BroadcastMessage(msg); Index: source/simulation2/docs/SimulationDocs.h =================================================================== --- source/simulation2/docs/SimulationDocs.h +++ source/simulation2/docs/SimulationDocs.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -565,22 +565,26 @@ For one-to-many communication, you can send indirect messages to components. -From C++, use CComponentManager::PostMessage to send a message to a specific entity, and +From C++, use CComponentManager::PostMessage to send a message to a specific entity, +CComponentManager::DistributeMessage to send to an array of entities and CComponentManager::BroadcastMessage to send to all entities. (In all cases, messages will only be received by components that subscribed to the corresponding message type). @code CMessageExample msg(10, 20); GetSimContext().GetComponentManager().PostMessage(ent, msg); +GetSimContext().GetComponentManager().DistributeMessage(entities, msg); GetSimContext().GetComponentManager().BroadcastMessage(msg); @endcode -From JS, use @ref CComponentManager::Script_PostMessage "Engine.PostMessage" and +From JS, use @ref CComponentManager::Script_PostMessage "Engine.PostMessage", +@ref CComponentManager::Script_DistributeMessage "Engine.DistributeMessage" and @ref CComponentManager::Script_BroadcastMessage "Engine.BroadcastMessage", using the @c MT_* constants to identify the message type: @code Engine.PostMessage(ent, MT_Example, { x: 10, y: 20 }); +Engine.PostMessage(entities, MT_Example, { x: 10, y: 20 }); Engine.BroadcastMessage(MT_Example, { x: 10, y: 20 }); @endcode Index: source/simulation2/system/ComponentManager.h =================================================================== --- source/simulation2/system/ComponentManager.h +++ source/simulation2/system/ComponentManager.h @@ -244,6 +244,13 @@ void PostMessage(entity_id_t ent, const CMessage& msg); /** + * Send a message, targeted at the particular entities. The message will be received by any + * components of those entities which subscribed to the message type, and by any other components + * that subscribed globally to the message type. + */ + void DistributeMessage(const std::vector& entities, const CMessage& msg); + + /** * Send a message, not targeted at any particular entity. The message will be received by any * components that subscribed (either globally or not) to the message type. */ @@ -285,6 +292,7 @@ static std::vector Script_GetEntitiesWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid); static std::vector Script_GetComponentsWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid); static void Script_PostMessage(ScriptInterface::CxPrivate* pCxPrivate, int ent, int mtid, JS::HandleValue data); + static void Script_DistributeMessage(ScriptInterface::CxPrivate* pCxPrivate, const std::vector& entities, int mtid, JS::HandleValue data); static void Script_BroadcastMessage(ScriptInterface::CxPrivate* pCxPrivate, int mtid, JS::HandleValue data); static int Script_AddEntity(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName); static int Script_AddLocalEntity(ScriptInterface::CxPrivate* pCxPrivate, const std::string& templateName); @@ -292,6 +300,7 @@ static void Script_FlushDestroyedEntities(ScriptInterface::CxPrivate* pCxPrivate); CMessage* ConstructMessage(int mtid, JS::HandleValue data); + void SendMessageTo(entity_id_t ent, const CMessage& msg); void SendGlobalMessage(entity_id_t ent, const CMessage& msg); void FlattenDynamicSubscriptions(); Index: source/simulation2/system/ComponentManager.cpp =================================================================== --- source/simulation2/system/ComponentManager.cpp +++ source/simulation2/system/ComponentManager.cpp @@ -78,6 +78,7 @@ m_ScriptInterface.RegisterFunction, int, CComponentManager::Script_GetEntitiesWithInterface> ("GetEntitiesWithInterface"); m_ScriptInterface.RegisterFunction, int, CComponentManager::Script_GetComponentsWithInterface> ("GetComponentsWithInterface"); m_ScriptInterface.RegisterFunction ("PostMessage"); + m_ScriptInterface.RegisterFunction, int, JS::HandleValue, CComponentManager::Script_DistributeMessage> ("DistributeMessage"); m_ScriptInterface.RegisterFunction ("BroadcastMessage"); m_ScriptInterface.RegisterFunction ("AddEntity"); m_ScriptInterface.RegisterFunction ("AddLocalEntity"); @@ -437,6 +438,19 @@ delete msg; } +void CComponentManager::Script_DistributeMessage(ScriptInterface::CxPrivate* pCxPrivate, const std::vector& entities, int mtid, JS::HandleValue data) +{ + CComponentManager* componentManager = static_cast (pCxPrivate->pCBData); + + CMessage* msg = componentManager->ConstructMessage(mtid, data); + if (!msg) + return; // error + + componentManager->DistributeMessage(entities, *msg); + + delete msg; +} + void CComponentManager::Script_BroadcastMessage(ScriptInterface::CxPrivate* pCxPrivate, int mtid, JS::HandleValue data) { CComponentManager* componentManager = static_cast (pCxPrivate->pCBData); @@ -1002,7 +1016,24 @@ void CComponentManager::PostMessage(entity_id_t ent, const CMessage& msg) { - PROFILE2_IFSPIKE("Post Message", 0.0005); + SendMessageTo(ent, msg); + SendGlobalMessage(ent, msg); +} + +void CComponentManager::DistributeMessage(const std::vector& entities, const CMessage& msg) +{ + for (entity_id_t ent : entities) + SendMessageTo(ent, msg); + +// Check all entities and if at least one is not local, send the global message with that, +// since the actual ent used to send the message is not important. Else just use the last entity. +// Or something like that,,, +// SendGlobalMessage(ent, msg); +} + +void CComponentManager::SendMessageTo(entity_id_t ent, const CMessage& msg) +{ + PROFILE2_IFSPIKE("Send Message To", 0.0005); PROFILE2_ATTR("%s", msg.GetScriptHandlerName()); // Send the message to components of ent, that subscribed locally to this message std::map >::const_iterator it; @@ -1023,8 +1054,6 @@ eit->second->HandleMessage(msg, false); } } - - SendGlobalMessage(ent, msg); } void CComponentManager::BroadcastMessage(const CMessage& msg)