NetworkHierarchyRootComponent.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Component/Entity.h>
  9. #include <AzCore/Component/TransformBus.h>
  10. #include <AzCore/Console/ILogger.h>
  11. #include <AzCore/Interface/Interface.h>
  12. #include <AzCore/Serialization/EditContext.h>
  13. #include <AzFramework/Components/TransformComponent.h>
  14. #include <Multiplayer/IMultiplayer.h>
  15. #include <Multiplayer/Components/NetBindComponent.h>
  16. #include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
  17. #include <Multiplayer/Components/NetworkHierarchyRootComponent.h>
  18. AZ_CVAR(uint32_t, bg_hierarchyEntityMaxLimit, 16, nullptr, AZ::ConsoleFunctorFlags::Null,
  19. "Maximum allowed size of network entity hierarchies, including top level entity.");
  20. static constexpr int CommonHierarchyEntityMaxLimit = 16; // Should match @bg_hierarchyEntityMaxLimit
  21. namespace Multiplayer
  22. {
  23. void NetworkHierarchyRootComponent::Reflect(AZ::ReflectContext* context)
  24. {
  25. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  26. if (serializeContext)
  27. {
  28. serializeContext->Class<NetworkHierarchyRootComponent, NetworkHierarchyRootComponentBase>()
  29. ->Version(1);
  30. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  31. {
  32. editContext->Class<NetworkHierarchyRootComponent>(
  33. "Network Hierarchy Root", "Marks the entity as the root of an entity hierarchy.")
  34. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  35. ->Attribute(AZ::Edit::Attributes::Category, "Multiplayer")
  36. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
  37. ;
  38. }
  39. }
  40. NetworkHierarchyRootComponentBase::Reflect(context);
  41. }
  42. void NetworkHierarchyRootComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  43. {
  44. required.push_back(AZ_CRC_CE("NetworkTransformComponent"));
  45. }
  46. void NetworkHierarchyRootComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  47. {
  48. provided.push_back(AZ_CRC_CE("NetworkHierarchyRootComponent"));
  49. provided.push_back(AZ_CRC_CE("MultiplayerInputDriver"));
  50. }
  51. void NetworkHierarchyRootComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  52. {
  53. incompatible.push_back(AZ_CRC_CE("NetworkHierarchyChildComponent"));
  54. incompatible.push_back(AZ_CRC_CE("NetworkHierarchyRootComponent"));
  55. }
  56. NetworkHierarchyRootComponent::NetworkHierarchyRootComponent()
  57. : m_childChangedHandler([this](AZ::ChildChangeType type, AZ::EntityId child) { OnChildChanged(type, child); })
  58. , m_parentChangedHandler([this](AZ::EntityId oldParent, AZ::EntityId parent) { OnParentChanged(oldParent, parent); })
  59. {
  60. }
  61. void NetworkHierarchyRootComponent::OnInit()
  62. {
  63. }
  64. void NetworkHierarchyRootComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  65. {
  66. m_isHierarchyEnabled = true;
  67. m_hierarchicalEntities.push_back(GetEntity());
  68. NetworkHierarchyRequestBus::Handler::BusConnect(GetEntityId());
  69. if (AzFramework::TransformComponent* transformComponent = GetEntity()->FindComponent<AzFramework::TransformComponent>())
  70. {
  71. transformComponent->BindChildChangedEventHandler(m_childChangedHandler);
  72. transformComponent->BindParentChangedEventHandler(m_parentChangedHandler);
  73. }
  74. }
  75. void NetworkHierarchyRootComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  76. {
  77. m_isHierarchyEnabled = false;
  78. if (m_rootEntity)
  79. {
  80. // Tell parent to re-build the hierarchy
  81. if (NetworkHierarchyRootComponent* root = m_rootEntity->FindComponent<NetworkHierarchyRootComponent>())
  82. {
  83. root->RebuildHierarchy();
  84. }
  85. }
  86. else
  87. {
  88. // Notify children that the hierarchy is disbanding
  89. AZStd::vector<AZ::EntityId> allChildren;
  90. AZ::TransformBus::EventResult(allChildren, GetEntityId(), &AZ::TransformBus::Events::GetChildren);
  91. for (const AZ::EntityId& childEntityId : allChildren)
  92. {
  93. if (const AZ::Entity* childEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(childEntityId))
  94. {
  95. SetRootForEntity(GetEntity(), nullptr, childEntity);
  96. }
  97. }
  98. }
  99. m_childChangedHandler.Disconnect();
  100. m_parentChangedHandler.Disconnect();
  101. NetworkHierarchyRequestBus::Handler::BusDisconnect();
  102. m_hierarchicalEntities.clear();
  103. m_rootEntity = nullptr;
  104. }
  105. bool NetworkHierarchyRootComponent::IsHierarchyEnabled() const
  106. {
  107. return m_isHierarchyEnabled;
  108. }
  109. bool NetworkHierarchyRootComponent::IsHierarchicalRoot() const
  110. {
  111. return GetHierarchyRoot() == InvalidNetEntityId;
  112. }
  113. bool NetworkHierarchyRootComponent::IsHierarchicalChild() const
  114. {
  115. return !IsHierarchicalRoot();
  116. }
  117. AZStd::vector<AZ::Entity*> NetworkHierarchyRootComponent::GetHierarchicalEntities() const
  118. {
  119. return m_hierarchicalEntities;
  120. }
  121. AZ::Entity* NetworkHierarchyRootComponent::GetHierarchicalRoot() const
  122. {
  123. if (m_rootEntity)
  124. {
  125. return m_rootEntity;
  126. }
  127. return GetEntity();
  128. }
  129. void NetworkHierarchyRootComponent::BindNetworkHierarchyChangedEventHandler(NetworkHierarchyChangedEvent::Handler& handler)
  130. {
  131. handler.Connect(m_networkHierarchyChangedEvent);
  132. }
  133. void NetworkHierarchyRootComponent::BindNetworkHierarchyLeaveEventHandler(NetworkHierarchyLeaveEvent::Handler& handler)
  134. {
  135. handler.Connect(m_networkHierarchyLeaveEvent);
  136. }
  137. void NetworkHierarchyRootComponent::OnChildChanged([[maybe_unused]] AZ::ChildChangeType type, [[maybe_unused]] AZ::EntityId child)
  138. {
  139. if (IsHierarchicalRoot())
  140. {
  141. // Parent-child notifications are not reliable enough to avoid duplicate notifications,
  142. // so we will rebuild from scratch to avoid duplicate entries in @m_hierarchicalEntities.
  143. RebuildHierarchy();
  144. }
  145. else if (NetworkHierarchyRootComponent* root = GetHierarchicalRoot()->FindComponent<NetworkHierarchyRootComponent>())
  146. {
  147. root->RebuildHierarchy();
  148. }
  149. }
  150. static AZStd::tuple<NetworkHierarchyRootComponent*, NetworkHierarchyChildComponent*> GetHierarchyComponents(const AZ::Entity* entity)
  151. {
  152. NetworkHierarchyChildComponent* childComponent = nullptr;
  153. NetworkHierarchyRootComponent* rootComponent = nullptr;
  154. for (AZ::Component* component : entity->GetComponents())
  155. {
  156. if (component->GetUnderlyingComponentType() == NetworkHierarchyChildComponent::TYPEINFO_Uuid())
  157. {
  158. childComponent = static_cast<NetworkHierarchyChildComponent*>(component);
  159. break;
  160. }
  161. if (component->GetUnderlyingComponentType() == NetworkHierarchyRootComponent::TYPEINFO_Uuid())
  162. {
  163. rootComponent = static_cast<NetworkHierarchyRootComponent*>(component);
  164. break;
  165. }
  166. }
  167. return AZStd::tie(rootComponent, childComponent);
  168. }
  169. void NetworkHierarchyRootComponent::OnParentChanged([[maybe_unused]] AZ::EntityId oldParent, AZ::EntityId newParent)
  170. {
  171. // If the parent is part of a hierarchy, it will detect this entity as a new child and rebuild hierarchy.
  172. // Thus, we only need to take care of a case when the parent is not part of a hierarchy,
  173. // in which case, this entity will be a new root of a new hierarchy.
  174. if (AZ::Entity* parentEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(newParent))
  175. {
  176. auto [rootComponent, childComponent] = GetHierarchyComponents(parentEntity);
  177. if (rootComponent == nullptr && childComponent == nullptr)
  178. {
  179. SetRootForEntity(nullptr, nullptr, GetEntity());
  180. }
  181. else
  182. {
  183. m_hierarchicalEntities.clear();
  184. }
  185. }
  186. else
  187. {
  188. // Detached from parent
  189. SetRootForEntity(nullptr, nullptr, GetEntity());
  190. }
  191. }
  192. void NetworkHierarchyRootComponent::RebuildHierarchy()
  193. {
  194. AZStd::vector<AZ::Entity*> previousEntities;
  195. m_hierarchicalEntities.swap(previousEntities);
  196. m_hierarchicalEntities.reserve(bg_hierarchyEntityMaxLimit);
  197. InternalBuildHierarchyList(GetEntity());
  198. bool hierarchyChanged = false;
  199. // Send out join and leave events.
  200. for (AZ::Entity* currentEntity : m_hierarchicalEntities)
  201. {
  202. const auto prevEntityIterator = AZStd::find(previousEntities.begin(), previousEntities.end(), currentEntity);
  203. if (prevEntityIterator != previousEntities.end())
  204. {
  205. // This entity was here before the build of the hierarchy.
  206. previousEntities.erase(prevEntityIterator);
  207. }
  208. else
  209. {
  210. // This is a newly added entity to the network hierarchy.
  211. hierarchyChanged = true;
  212. SetRootForEntity(nullptr, GetEntity(), currentEntity);
  213. }
  214. }
  215. // These entities were removed since last rebuild.
  216. for (const AZ::Entity* previousEntity : previousEntities)
  217. {
  218. SetRootForEntity(GetEntity(), nullptr, previousEntity);
  219. }
  220. if (!previousEntities.empty())
  221. {
  222. hierarchyChanged = true;
  223. }
  224. if (hierarchyChanged)
  225. {
  226. m_networkHierarchyChangedEvent.Signal(GetEntityId());
  227. }
  228. }
  229. void NetworkHierarchyRootComponent::InternalBuildHierarchyList(AZ::Entity* underEntity)
  230. {
  231. AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
  232. AZStd::deque<AZ::Entity*, AZStd::allocator, CommonHierarchyEntityMaxLimit> candidates;
  233. candidates.push_back(underEntity);
  234. while (!candidates.empty())
  235. {
  236. AZ::Entity* candidate = candidates.front();
  237. candidates.pop_front();
  238. if (candidate)
  239. {
  240. auto [hierarchyRootComponent, hierarchyChildComponent] = GetHierarchyComponents(candidate);
  241. if ((hierarchyChildComponent && hierarchyChildComponent->IsHierarchyEnabled()) ||
  242. (hierarchyRootComponent && hierarchyRootComponent->IsHierarchyEnabled()))
  243. {
  244. m_hierarchicalEntities.push_back(candidate);
  245. if (m_hierarchicalEntities.size() >= bg_hierarchyEntityMaxLimit)
  246. {
  247. AZLOG_WARN("Network hierarchy size exceeded, current limit is %d, root entity was %s",
  248. static_cast<int>(bg_hierarchyEntityMaxLimit),
  249. GetEntity()->GetName().c_str());
  250. return;
  251. }
  252. AZStd::vector<AZ::EntityId> allChildren;
  253. if (candidate->GetTransform())
  254. {
  255. allChildren = candidate->GetTransform()->GetChildren();
  256. }
  257. else
  258. {
  259. // Child entities may not be in the Active state so skip for now.
  260. // They will notify when ready causing another rebuild.
  261. continue;
  262. }
  263. for (const AZ::EntityId& newChildId : allChildren)
  264. {
  265. candidates.push_back(componentApplicationRequests->FindEntity(newChildId));
  266. }
  267. }
  268. }
  269. }
  270. }
  271. void NetworkHierarchyRootComponent::SetRootForEntity(AZ::Entity* previousKnownRoot, AZ::Entity* newRoot, const AZ::Entity* childEntity)
  272. {
  273. auto [hierarchyRootComponent, hierarchyChildComponent] = GetHierarchyComponents(childEntity);
  274. if (hierarchyChildComponent)
  275. {
  276. hierarchyChildComponent->SetTopLevelHierarchyRootEntity(previousKnownRoot, newRoot);
  277. }
  278. else if (hierarchyRootComponent)
  279. {
  280. hierarchyRootComponent->SetTopLevelHierarchyRootEntity(previousKnownRoot, newRoot);
  281. }
  282. }
  283. void NetworkHierarchyRootComponent::SetTopLevelHierarchyRootEntity(AZ::Entity* previousHierarchyRoot, AZ::Entity* newHierarchyRoot)
  284. {
  285. if (newHierarchyRoot)
  286. {
  287. if (m_rootEntity != newHierarchyRoot)
  288. {
  289. m_rootEntity = newHierarchyRoot;
  290. const NetEntityId netRootId = GetNetworkEntityManager()->GetNetEntityIdById(m_rootEntity->GetId());
  291. TrySetControllerRoot(netRootId);
  292. GetNetBindComponent()->SetOwningConnectionId(m_rootEntity->FindComponent<NetBindComponent>()->GetOwningConnectionId());
  293. m_networkHierarchyChangedEvent.Signal(m_rootEntity->GetId());
  294. }
  295. }
  296. else if ((previousHierarchyRoot && m_rootEntity == previousHierarchyRoot) || !previousHierarchyRoot)
  297. {
  298. m_rootEntity = nullptr;
  299. TrySetControllerRoot(InvalidNetEntityId);
  300. GetNetBindComponent()->SetOwningConnectionId(m_previousOwningConnectionId);
  301. m_networkHierarchyLeaveEvent.Signal();
  302. // We lost the parent hierarchical entity, so as a root we need to re-build our own hierarchy.
  303. RebuildHierarchy();
  304. }
  305. }
  306. void NetworkHierarchyRootComponent::TrySetControllerRoot([[maybe_unused]] const NetEntityId rootNetId)
  307. {
  308. #if AZ_TRAIT_SERVER
  309. if (HasController() && GetNetBindComponent()->GetNetEntityRole() == NetEntityRole::Authority)
  310. {
  311. NetworkHierarchyRootComponentController* controller = static_cast<NetworkHierarchyRootComponentController*>(GetController());
  312. controller->SetHierarchyRoot(rootNetId);
  313. }
  314. #endif
  315. }
  316. void NetworkHierarchyRootComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId)
  317. {
  318. NetworkHierarchyRootComponentBase::SetOwningConnectionId(connectionId);
  319. if (IsHierarchicalChild() == false)
  320. {
  321. m_previousOwningConnectionId = connectionId;
  322. }
  323. }
  324. NetworkHierarchyRootComponentController::NetworkHierarchyRootComponentController(NetworkHierarchyRootComponent& parent)
  325. : NetworkHierarchyRootComponentControllerBase(parent)
  326. {
  327. }
  328. void NetworkHierarchyRootComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  329. {
  330. }
  331. void NetworkHierarchyRootComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  332. {
  333. }
  334. Multiplayer::MultiplayerController::InputPriorityOrder NetworkHierarchyRootComponentController::GetInputOrder() const
  335. {
  336. return Multiplayer::MultiplayerController::InputPriorityOrder::SubEntities;
  337. }
  338. void NetworkHierarchyRootComponentController::CreateInput(Multiplayer::NetworkInput& input, float deltaTime)
  339. {
  340. NetworkHierarchyRootComponent& component = GetParent();
  341. if (!component.IsHierarchicalRoot())
  342. {
  343. return;
  344. }
  345. INetworkEntityManager* networkEntityManager = AZ::Interface<INetworkEntityManager>::Get();
  346. AZ_Assert(networkEntityManager, "NetworkEntityManager must be created.");
  347. const AZStd::vector<AZ::Entity*>& entities = component.m_hierarchicalEntities;
  348. auto* networkInput = input.FindComponentInput<NetworkHierarchyRootComponentNetworkInput>();
  349. networkInput->m_childInputs.clear();
  350. networkInput->m_childInputs.reserve(entities.size());
  351. for (AZ::Entity* child : entities)
  352. {
  353. if (child == component.GetEntity())
  354. {
  355. continue; // Avoid infinite recursion
  356. }
  357. NetEntityId childNetEntitydId = networkEntityManager->GetNetEntityIdById(child->GetId());
  358. AZ_Assert(childNetEntitydId != InvalidNetEntityId, "Unable to find the hierarchy entity in Network Entity Manager");
  359. ConstNetworkEntityHandle childEntityHandle = networkEntityManager->GetEntity(childNetEntitydId);
  360. NetBindComponent* netComp = childEntityHandle.GetNetBindComponent();
  361. AZ_Assert(netComp, "No NetBindComponent, this should be impossible");
  362. // Validate we still have a controller and we aren't in the middle of removing them
  363. if (netComp->HasController())
  364. {
  365. NetworkInputChild subInput;
  366. subInput.Attach(childEntityHandle);
  367. subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId());
  368. netComp->CreateInput(subInput.GetNetworkInput(), deltaTime);
  369. // make sure our input sub commands have the same time as the original
  370. subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId());
  371. networkInput->m_childInputs.emplace_back(subInput);
  372. }
  373. }
  374. }
  375. void NetworkHierarchyRootComponentController::ProcessInput(Multiplayer::NetworkInput& input, float deltaTime)
  376. {
  377. if (auto* networkInput = input.FindComponentInput<NetworkHierarchyRootComponentNetworkInput>())
  378. {
  379. INetworkEntityManager* networkEntityManager = AZ::Interface<INetworkEntityManager>::Get();
  380. AZ_Assert(networkEntityManager, "NetworkEntityManager must be created.");
  381. // Build a set of Net IDs for the children
  382. NetEntityIdSet currentChildren;
  383. NetworkHierarchyRootComponent& component = GetParent();
  384. for (AZ::Entity* child : component.m_hierarchicalEntities)
  385. {
  386. if (child == component.GetEntity()) // Skip the root entity
  387. {
  388. continue;
  389. }
  390. NetEntityId childNetEntitydId = networkEntityManager->GetNetEntityIdById(child->GetId());
  391. AZ_Assert(childNetEntitydId != InvalidNetEntityId, "Unable to find the hierarchy entity in Network Entity Manager");
  392. currentChildren.insert(childNetEntitydId);
  393. }
  394. // Process the input for the child entities
  395. for (NetworkInputChild& subInput : networkInput->m_childInputs)
  396. {
  397. const ConstNetworkEntityHandle& inputOwnerHandle = subInput.GetOwner();
  398. NetEntityId inputOwnerNetEntitydId = inputOwnerHandle.GetNetEntityId();
  399. if (currentChildren.count(inputOwnerNetEntitydId) == 0)
  400. {
  401. // Skip the input for entities which are not a part of this hierarchy
  402. continue;
  403. }
  404. ConstNetworkEntityHandle localEntityHandle = networkEntityManager->GetEntity(inputOwnerNetEntitydId);
  405. if (localEntityHandle.Exists())
  406. {
  407. auto* netComp = localEntityHandle.GetNetBindComponent();
  408. AZ_Assert(netComp, "No NetBindComponent, this should be impossible");
  409. // We do not rewind entity role changes, so make sure we are the correct role prior to processing
  410. if (netComp->HasController())
  411. {
  412. subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId());
  413. netComp->ProcessInput(subInput.GetNetworkInput(), deltaTime);
  414. }
  415. }
  416. }
  417. }
  418. }
  419. bool NetworkHierarchyRootComponent::SerializeEntityCorrection(AzNetworking::ISerializer& serializer)
  420. {
  421. bool result = true;
  422. INetworkEntityManager* networkEntityManager = AZ::Interface<INetworkEntityManager>::Get();
  423. AZ_Assert(networkEntityManager, "NetworkEntityManager must be created.");
  424. for (AZ::Entity* child : m_hierarchicalEntities)
  425. {
  426. if (child == GetEntity())
  427. {
  428. // Skip the root entity
  429. continue;
  430. }
  431. NetEntityId childNetEntitydId = networkEntityManager->GetNetEntityIdById(child->GetId());
  432. AZ_Assert(childNetEntitydId != InvalidNetEntityId, "Unable to find the hierarchy entity in Network Entity Manager");
  433. ConstNetworkEntityHandle childEntityHandle = networkEntityManager->GetEntity(childNetEntitydId);
  434. NetBindComponent* netBindComponent = childEntityHandle.GetNetBindComponent();
  435. AZ_Assert(netBindComponent, "No NetBindComponent, this should be impossible");
  436. result = result && netBindComponent->SerializeEntityCorrection(serializer);
  437. }
  438. return result;
  439. }
  440. }