NetworkEntityManager.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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 <Source/NetworkEntity/NetworkEntityManager.h>
  9. #include <AzCore/Asset/AssetManager.h>
  10. #include <AzCore/Console/IConsole.h>
  11. #include <AzCore/Console/ILogger.h>
  12. #include <AzCore/Interface/Interface.h>
  13. #include <AzCore/Serialization/SerializeContext.h>
  14. #include <AzCore/Slice/SliceMetadataInfoComponent.h>
  15. #include <AzFramework/Components/TransformComponent.h>
  16. #include <AzFramework/Entity/EntityContextBus.h>
  17. #include <AzFramework/Entity/GameEntityContextBus.h>
  18. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  19. #include <AzFramework/Visibility/EntityBoundsUnionBus.h>
  20. #include <AzFramework/Spawnable/Spawnable.h>
  21. #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
  22. #include <Multiplayer/IMultiplayer.h>
  23. #include <Multiplayer/Components/NetBindComponent.h>
  24. #include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
  25. #include <Multiplayer/Components/NetworkHierarchyRootComponent.h>
  26. AZ_DECLARE_BUDGET(MULTIPLAYER);
  27. namespace Multiplayer
  28. {
  29. AZ_CVAR(bool, net_DebugCheckNetworkEntityManager, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables extra debug checks inside the NetworkEntityManager");
  30. NetworkEntityManager::NetworkEntityManager()
  31. : m_networkEntityAuthorityTracker(*this)
  32. , m_removeEntitiesEvent([this] { RemoveEntities(); }, AZ::Name("NetworkEntityManager remove entities event"))
  33. {
  34. AZ::Interface<INetworkEntityManager>::Register(this);
  35. AzFramework::RootSpawnableNotificationBus::Handler::BusConnect();
  36. AzFramework::SpawnableAssetEventsBus::Handler::BusConnect();
  37. }
  38. NetworkEntityManager::~NetworkEntityManager()
  39. {
  40. AzFramework::SpawnableAssetEventsBus::Handler::BusDisconnect();
  41. AzFramework::RootSpawnableNotificationBus::Handler::BusDisconnect();
  42. AZ::Interface<INetworkEntityManager>::Unregister(this);
  43. }
  44. void NetworkEntityManager::Initialize(const HostId& hostId, AZStd::unique_ptr<IEntityDomain> entityDomain)
  45. {
  46. m_hostId = hostId;
  47. // Configure our vended NetEntityIds so that no two hosts generate the same NetEntityId
  48. {
  49. // Needs more thought
  50. const uint64_t addrPortion = hostId.GetAddress(AzNetworking::ByteOrder::Host);
  51. const uint64_t portPortion = hostId.GetPort(AzNetworking::ByteOrder::Host);
  52. const uint64_t hostIdentifier = (portPortion << 32) | addrPortion;
  53. const AZ::HashValue32 hostHash = AZ::TypeHash32(hostIdentifier);
  54. NetEntityId hostEntityIdOffset = static_cast<NetEntityId>(hostHash) << 32;
  55. m_nextEntityId &= NetEntityId{ 0x0000000000000000FFFFFFFFFFFFFFFF };
  56. m_nextEntityId |= hostEntityIdOffset;
  57. }
  58. m_entityDomain = AZStd::move(entityDomain);
  59. }
  60. bool NetworkEntityManager::IsInitialized() const
  61. {
  62. return m_entityDomain != nullptr;
  63. }
  64. IEntityDomain* NetworkEntityManager::GetEntityDomain() const
  65. {
  66. return m_entityDomain.get();
  67. }
  68. NetworkEntityTracker* NetworkEntityManager::GetNetworkEntityTracker()
  69. {
  70. return &m_networkEntityTracker;
  71. }
  72. NetworkEntityAuthorityTracker* NetworkEntityManager::GetNetworkEntityAuthorityTracker()
  73. {
  74. return &m_networkEntityAuthorityTracker;
  75. }
  76. MultiplayerComponentRegistry* NetworkEntityManager::GetMultiplayerComponentRegistry()
  77. {
  78. return &m_multiplayerComponentRegistry;
  79. }
  80. const HostId& NetworkEntityManager::GetHostId() const
  81. {
  82. return m_hostId;
  83. }
  84. ConstNetworkEntityHandle NetworkEntityManager::GetEntity(NetEntityId netEntityId) const
  85. {
  86. return m_networkEntityTracker.Get(netEntityId);
  87. }
  88. NetEntityId NetworkEntityManager::GetNetEntityIdById(const AZ::EntityId& entityId) const
  89. {
  90. return m_networkEntityTracker.Get(entityId);
  91. }
  92. uint32_t NetworkEntityManager::GetEntityCount() const
  93. {
  94. return static_cast<uint32_t>(m_networkEntityTracker.size());
  95. }
  96. NetworkEntityHandle NetworkEntityManager::AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity)
  97. {
  98. m_networkEntityTracker.Add(netEntityId, entity);
  99. return NetworkEntityHandle(entity, &m_networkEntityTracker);
  100. }
  101. void NetworkEntityManager::RemoveEntityFromEntityMap(NetEntityId netEntityId)
  102. {
  103. m_networkEntityTracker.erase(netEntityId);
  104. }
  105. void NetworkEntityManager::MarkForRemoval(const ConstNetworkEntityHandle& entityHandle)
  106. {
  107. if (entityHandle.Exists())
  108. {
  109. if (net_DebugCheckNetworkEntityManager)
  110. {
  111. AZ_Assert(entityHandle.GetNetBindComponent(), "No NetBindComponent found on networked entity");
  112. }
  113. m_removeList.push_back(entityHandle.GetNetEntityId());
  114. if (!m_removeEntitiesEvent.IsScheduled())
  115. {
  116. m_removeEntitiesEvent.Enqueue(AZ::Time::ZeroTimeMs);
  117. }
  118. }
  119. }
  120. bool NetworkEntityManager::IsMarkedForRemoval(const ConstNetworkEntityHandle& entityHandle) const
  121. {
  122. for (auto removeEntId : m_removeList)
  123. {
  124. if (entityHandle.GetNetEntityId() == removeEntId)
  125. {
  126. return true;
  127. }
  128. }
  129. return false;
  130. }
  131. void NetworkEntityManager::ClearEntityFromRemovalList(const ConstNetworkEntityHandle& entityHandle)
  132. {
  133. for (auto iter = m_removeList.begin(); iter != m_removeList.end(); ++iter)
  134. {
  135. if (*iter == entityHandle.GetNetEntityId())
  136. {
  137. iter = m_removeList.erase(iter);
  138. break;
  139. }
  140. }
  141. }
  142. void NetworkEntityManager::ClearAllEntities()
  143. {
  144. // Note is looping through a hash map not a vector. Could cause performance issues even on shutdown.
  145. for (NetworkEntityTracker::iterator it = m_networkEntityTracker.begin(); it != m_networkEntityTracker.end(); ++it)
  146. {
  147. m_removeList.push_back(it->first);
  148. }
  149. RemoveEntities();
  150. // Keystone has refactored these API's, rewrite required
  151. //AZ::SliceComponent* rootSlice = nullptr;
  152. //{
  153. // AzFramework::EntityContextId gameContextId = AzFramework::EntityContextId::CreateNull();
  154. // AzFramework::GameEntityContextRequestBus::BroadcastResult(gameContextId, &AzFramework::GameEntityContextRequests::GetGameEntityContextId);
  155. // AzFramework::EntityContextRequestBus::BroadcastResult(rootSlice, &AzFramework::EntityContextRequests::GetRootSlice);
  156. // AZ_Assert(rootSlice != nullptr, "Root slice returned was nullptr");
  157. //}
  158. //
  159. //for (AZ::Entity* entity : m_nonNetworkedEntities)
  160. //{
  161. // rootSlice->RemoveEntity(entity);
  162. //}
  163. m_networkEntityTracker.clear();
  164. }
  165. void NetworkEntityManager::AddEntityMarkedDirtyHandler(AZ::Event<>::Handler& entityMarkedDirtyHandler)
  166. {
  167. entityMarkedDirtyHandler.Connect(m_onEntityMarkedDirty);
  168. }
  169. void NetworkEntityManager::AddEntityNotifyChangesHandler(AZ::Event<>::Handler& entityNotifyChangesHandler)
  170. {
  171. entityNotifyChangesHandler.Connect(m_onEntityNotifyChanges);
  172. }
  173. void NetworkEntityManager::AddEntityExitDomainHandler(EntityExitDomainEvent::Handler& entityExitDomainHandler)
  174. {
  175. entityExitDomainHandler.Connect(m_entityExitDomainEvent);
  176. }
  177. void NetworkEntityManager::AddControllersActivatedHandler(ControllersActivatedEvent::Handler& controllersActivatedHandler)
  178. {
  179. controllersActivatedHandler.Connect(m_controllersActivatedEvent);
  180. }
  181. void NetworkEntityManager::AddControllersDeactivatedHandler(ControllersDeactivatedEvent::Handler& controllersDeactivatedHandler)
  182. {
  183. controllersDeactivatedHandler.Connect(m_controllersDeactivatedEvent);
  184. }
  185. void NetworkEntityManager::NotifyEntitiesDirtied()
  186. {
  187. AZ_PROFILE_SCOPE(MULTIPLAYER, "NetworkEntityManager: NotifyEntitiesDirtied");
  188. m_onEntityMarkedDirty.Signal();
  189. }
  190. void NetworkEntityManager::NotifyEntitiesChanged()
  191. {
  192. AZ_PROFILE_SCOPE(MULTIPLAYER, "NetworkEntityManager: NotifyEntitiesChanged");
  193. m_onEntityNotifyChanges.Signal();
  194. }
  195. void NetworkEntityManager::NotifyControllersActivated(const ConstNetworkEntityHandle& entityHandle, EntityIsMigrating entityIsMigrating)
  196. {
  197. m_controllersActivatedEvent.Signal(entityHandle, entityIsMigrating);
  198. }
  199. void NetworkEntityManager::NotifyControllersDeactivated(const ConstNetworkEntityHandle& entityHandle, EntityIsMigrating entityIsMigrating)
  200. {
  201. m_controllersDeactivatedEvent.Signal(entityHandle, entityIsMigrating);
  202. }
  203. void NetworkEntityManager::HandleLocalRpcMessage(NetworkEntityRpcMessage& message)
  204. {
  205. m_localDeferredRpcMessages.emplace_back(AZStd::move(message));
  206. }
  207. void NetworkEntityManager::HandleEntitiesExitDomain(const NetEntityIdSet& entitiesNotInDomain)
  208. {
  209. for (NetEntityId exitingId : entitiesNotInDomain)
  210. {
  211. NetworkEntityHandle entityHandle = m_networkEntityTracker.Get(exitingId);
  212. bool safeToExit = IsHierarchySafeToExit(entityHandle, entitiesNotInDomain);;
  213. // Validate that we aren't already planning to remove this entity
  214. if (safeToExit)
  215. {
  216. for (auto remoteEntityId : m_removeList)
  217. {
  218. if (remoteEntityId == remoteEntityId)
  219. {
  220. safeToExit = false;
  221. }
  222. }
  223. }
  224. if (safeToExit)
  225. {
  226. // Tell all the attached replicators for this entity that it's exited the domain
  227. m_entityExitDomainEvent.Signal(entityHandle);
  228. }
  229. }
  230. }
  231. void NetworkEntityManager::ForceAssumeAuthority(const ConstNetworkEntityHandle& entityHandle)
  232. {
  233. NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent();
  234. if (netBindComponent != nullptr)
  235. {
  236. netBindComponent->ConstructControllers();
  237. }
  238. }
  239. void NetworkEntityManager::MarkAlwaysRelevantToClients(const ConstNetworkEntityHandle& entityHandle, bool alwaysRelevant)
  240. {
  241. if (alwaysRelevant)
  242. {
  243. AZ_Assert(entityHandle.GetNetBindComponent()->IsNetEntityRoleAuthority(), "Marking an entity always relevant can only be done on an authoritative entity");
  244. m_alwaysRelevantToClients.emplace(entityHandle);
  245. }
  246. else
  247. {
  248. m_alwaysRelevantToClients.erase(entityHandle);
  249. }
  250. }
  251. void NetworkEntityManager::MarkAlwaysRelevantToServers(const ConstNetworkEntityHandle& entityHandle, bool alwaysRelevant)
  252. {
  253. if (alwaysRelevant)
  254. {
  255. AZ_Assert(entityHandle.GetNetBindComponent()->IsNetEntityRoleAuthority(), "Marking an entity always relevant can only be done on an authoritative entity");
  256. m_alwaysRelevantToServers.emplace(entityHandle);
  257. }
  258. else
  259. {
  260. m_alwaysRelevantToServers.erase(entityHandle);
  261. }
  262. }
  263. const NetEntityHandleSet& NetworkEntityManager::GetAlwaysRelevantToClientsSet() const
  264. {
  265. return m_alwaysRelevantToClients;
  266. }
  267. const NetEntityHandleSet& NetworkEntityManager::GetAlwaysRelevantToServersSet() const
  268. {
  269. return m_alwaysRelevantToServers;
  270. }
  271. void NetworkEntityManager::SetMigrateTimeoutTimeMs(AZ::TimeMs timeoutTimeMs)
  272. {
  273. m_networkEntityAuthorityTracker.SetTimeoutTimeMs(timeoutTimeMs);
  274. }
  275. void NetworkEntityManager::DebugDraw() const
  276. {
  277. AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
  278. AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId);
  279. AzFramework::DebugDisplayRequests* debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
  280. for (NetworkEntityTracker::const_iterator it = m_networkEntityTracker.begin(); it != m_networkEntityTracker.end(); ++it)
  281. {
  282. AZ::Entity* entity = it->second;
  283. NetBindComponent* netBindComponent = m_networkEntityTracker.GetNetBindComponent(entity);
  284. AZ::Aabb entityBounds = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->GetEntityWorldBoundsUnion(entity->GetId());
  285. if (!entityBounds.IsValid())
  286. {
  287. continue;
  288. }
  289. entityBounds.Expand(AZ::Vector3(0.01f));
  290. if ((netBindComponent != nullptr) && netBindComponent->GetNetEntityRole() == NetEntityRole::Authority)
  291. {
  292. debugDisplay->SetColor(AZ::Colors::Black);
  293. debugDisplay->SetAlpha(0.5f);
  294. }
  295. else
  296. {
  297. debugDisplay->SetColor(AZ::Colors::DeepSkyBlue);
  298. debugDisplay->SetAlpha(0.25f);
  299. }
  300. debugDisplay->DrawWireBox(entityBounds.GetMin(), entityBounds.GetMax());
  301. }
  302. if (m_entityDomain != nullptr)
  303. {
  304. m_entityDomain->DebugDraw();
  305. }
  306. }
  307. void NetworkEntityManager::DispatchLocalDeferredRpcMessages()
  308. {
  309. // Local messages may get queued up while we process other local messages,
  310. // so let @m_localDeferredRpcMessages accumulate,
  311. // while we work on the current messages.
  312. AZStd::deque<NetworkEntityRpcMessage> copy;
  313. copy.swap(m_localDeferredRpcMessages);
  314. for (NetworkEntityRpcMessage& rpcMessage : copy)
  315. {
  316. AZ::Entity* entity = m_networkEntityTracker.GetRaw(rpcMessage.GetEntityId());
  317. if (entity != nullptr)
  318. {
  319. NetBindComponent* netBindComponent = m_networkEntityTracker.GetNetBindComponent(entity);
  320. AZ_Assert(netBindComponent != nullptr, "Attempting to send an RPC to an entity with no NetBindComponent");
  321. switch(rpcMessage.GetRpcDeliveryType())
  322. {
  323. case RpcDeliveryType::AuthorityToClient:
  324. case RpcDeliveryType::AuthorityToAutonomous:
  325. netBindComponent->HandleRpcMessage(nullptr, NetEntityRole::Authority, rpcMessage);
  326. break;
  327. case RpcDeliveryType::AutonomousToAuthority:
  328. netBindComponent->HandleRpcMessage(nullptr, NetEntityRole::Autonomous, rpcMessage);
  329. break;
  330. case RpcDeliveryType::ServerToAuthority:
  331. netBindComponent->HandleRpcMessage(nullptr, NetEntityRole::Server, rpcMessage);
  332. break;
  333. case RpcDeliveryType::None:
  334. break;
  335. }
  336. }
  337. }
  338. }
  339. void NetworkEntityManager::Reset()
  340. {
  341. m_multiplayerComponentRegistry.Reset();
  342. m_removeList.clear();
  343. m_entityDomain = nullptr;
  344. m_entityExitDomainEvent.DisconnectAllHandlers();
  345. m_onEntityMarkedDirty.DisconnectAllHandlers();
  346. m_onEntityNotifyChanges.DisconnectAllHandlers();
  347. m_controllersActivatedEvent.DisconnectAllHandlers();
  348. m_controllersDeactivatedEvent.DisconnectAllHandlers();
  349. m_localDeferredRpcMessages.clear();
  350. }
  351. void NetworkEntityManager::RemoveEntities()
  352. {
  353. AZStd::vector<NetEntityId> removeList;
  354. removeList.swap(m_removeList);
  355. for (NetEntityId entityId : removeList)
  356. {
  357. NetworkEntityHandle removeEntity = m_networkEntityTracker.Get(entityId);
  358. if (removeEntity != nullptr)
  359. {
  360. // If we've spawned entities through @NetworkEntityManager::CreateEntitiesImmediate
  361. // then we destroy those entities here by processing the removal list.
  362. // Note that if we've spawned entities through @NetworkPrefabSpawnerComponent::SpawnPrefab
  363. // we should instead use the SpawnableEntitiesManager to destroy them.
  364. AzFramework::GameEntityContextRequestBus::Broadcast(
  365. &AzFramework::GameEntityContextRequestBus::Events::DestroyGameEntity, removeEntity.GetEntity()->GetId());
  366. m_networkEntityTracker.erase(entityId);
  367. }
  368. }
  369. }
  370. INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(
  371. const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole, const AZ::Transform& transform, AutoActivate autoActivate)
  372. {
  373. INetworkEntityManager::EntityList returnList;
  374. AZ::SerializeContext* serializeContext = nullptr;
  375. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  376. const AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();
  377. size_t entitiesSize = entities.size();
  378. using EntityIdMap = AZStd::unordered_map<AZ::EntityId, AZ::EntityId>;
  379. EntityIdMap originalToCloneIdMap;
  380. for (size_t i = 0; i < entitiesSize; ++i)
  381. {
  382. AZ::Entity* originalEntity = entities[i].get();
  383. // Can't use NetworkEntityTracker to do the lookup since the entity has not activated yet
  384. if (!originalEntity->FindComponent<NetBindComponent>())
  385. {
  386. continue;
  387. }
  388. AZ::Entity* clone = serializeContext->CloneObject(originalEntity);
  389. AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
  390. clone->SetId(AZ::Entity::MakeId());
  391. originalToCloneIdMap[originalEntity->GetId()] = clone->GetId();
  392. // Update TransformComponent parent Id. It is guaranteed for the entities array to be sorted from parent->child here.
  393. auto cloneNetBindComponent = clone->FindComponent<NetBindComponent>();
  394. auto cloneTransformComponent = clone->FindComponent<AzFramework::TransformComponent>();
  395. AZ::EntityId parentId = cloneTransformComponent->GetParentId();
  396. bool removeParent = false;
  397. if (parentId.IsValid())
  398. {
  399. auto it = originalToCloneIdMap.find(parentId);
  400. if (it != originalToCloneIdMap.end())
  401. {
  402. cloneTransformComponent->SetParentRelative(it->second);
  403. }
  404. else
  405. {
  406. // This network entity is referencing a non-network parent
  407. // We need to clear the parent.
  408. // Note: The need to clear the parent will go away once this method replaces serializeContext->CloneObject
  409. // with the standard AzFramework::SpawnableEntitiesInterface::SpawnEntities
  410. removeParent = true;
  411. }
  412. }
  413. PrefabEntityId prefabEntityId;
  414. prefabEntityId.m_prefabName = m_networkPrefabLibrary.GetSpawnableNameFromAssetId(spawnable.GetId());
  415. prefabEntityId.m_entityOffset = aznumeric_cast<uint32_t>(i);
  416. const NetEntityId netEntityId = NextId();
  417. cloneNetBindComponent->PreInit(clone, prefabEntityId, netEntityId, netEntityRole);
  418. cloneTransformComponent->SetWorldTM(transform);
  419. if (autoActivate == AutoActivate::DoNotActivate)
  420. {
  421. clone->SetRuntimeActiveByDefault(false);
  422. }
  423. AzFramework::GameEntityContextRequestBus::Broadcast(
  424. &AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
  425. if (removeParent)
  426. {
  427. cloneTransformComponent->SetParent(AZ::EntityId());
  428. }
  429. returnList.push_back(cloneNetBindComponent->GetEntityHandle());
  430. }
  431. return returnList;
  432. }
  433. INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate
  434. (
  435. const PrefabEntityId& prefabEntryId,
  436. NetEntityRole netEntityRole,
  437. const AZ::Transform& transform,
  438. AutoActivate autoActivate
  439. )
  440. {
  441. return CreateEntitiesImmediate(prefabEntryId, NextId(), netEntityRole, autoActivate, transform);
  442. }
  443. INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate
  444. (
  445. const PrefabEntityId& prefabEntryId,
  446. NetEntityId netEntityId,
  447. NetEntityRole netEntityRole,
  448. AutoActivate autoActivate,
  449. const AZ::Transform& transform
  450. )
  451. {
  452. EntityList returnList;
  453. if (!AZ::Data::AssetManager::IsReady())
  454. {
  455. return returnList;
  456. }
  457. auto spawnableAssetId = m_networkPrefabLibrary.GetAssetIdByName(prefabEntryId.m_prefabName);
  458. // Required for sync-instantiation. Todo: keep the reference in NetworkSpawnableLibrary
  459. auto netSpawnableAsset = AZ::Data::AssetManager::Instance().GetAsset<AzFramework::Spawnable>(spawnableAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
  460. AZ::Data::AssetManager::Instance().BlockUntilLoadComplete(netSpawnableAsset);
  461. AzFramework::Spawnable* netSpawnable = netSpawnableAsset.GetAs<AzFramework::Spawnable>();
  462. if (!netSpawnable)
  463. {
  464. return returnList;
  465. }
  466. const uint32_t entityIndex = prefabEntryId.m_entityOffset;
  467. if (entityIndex == PrefabEntityId::AllIndices)
  468. {
  469. return CreateEntitiesImmediate(*netSpawnable, netEntityRole, transform, autoActivate);
  470. }
  471. const AzFramework::Spawnable::EntityList& entities = netSpawnable->GetEntities();
  472. size_t entitiesSize = entities.size();
  473. if (entityIndex >= entitiesSize)
  474. {
  475. return returnList;
  476. }
  477. AZ::SerializeContext* serializeContext = nullptr;
  478. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  479. AZ::Entity* clone = serializeContext->CloneObject(entities[entityIndex].get());
  480. AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
  481. clone->SetId(AZ::Entity::MakeId());
  482. NetBindComponent* netBindComponent = clone->FindComponent<NetBindComponent>();
  483. if (netBindComponent)
  484. {
  485. netBindComponent->PreInit(clone, prefabEntryId, netEntityId, netEntityRole);
  486. auto* transformComponent = clone->FindComponent<AzFramework::TransformComponent>();
  487. if (transformComponent)
  488. {
  489. transformComponent->SetWorldTM(transform);
  490. }
  491. if (autoActivate == AutoActivate::DoNotActivate)
  492. {
  493. clone->SetRuntimeActiveByDefault(false);
  494. }
  495. AzFramework::GameEntityContextRequestBus::Broadcast(&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
  496. returnList.push_back(netBindComponent->GetEntityHandle());
  497. }
  498. return returnList;
  499. }
  500. Multiplayer::NetEntityId NetworkEntityManager::NextId()
  501. {
  502. const NetEntityId netEntityId = m_nextEntityId++;
  503. return netEntityId;
  504. }
  505. AZStd::unique_ptr<AzFramework::EntitySpawnTicket> NetworkEntityManager::RequestNetSpawnableInstantiation(
  506. const AZ::Data::Asset<AzFramework::Spawnable>& netSpawnable, const AZ::Transform& transform)
  507. {
  508. // Prepare the parameters for the spawning process
  509. AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
  510. optionalArgs.m_priority = AzFramework::SpawnablePriority_High;
  511. const AZ::Name netSpawnableName =
  512. AZ::Interface<INetworkSpawnableLibrary>::Get()->GetSpawnableNameFromAssetId(netSpawnable.GetId());
  513. if (netSpawnableName.IsEmpty())
  514. {
  515. AZ_Error("NetworkEntityManager", false,
  516. "RequestNetSpawnableInstantiation: Requested spawnable %s doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable",
  517. netSpawnable.GetHint().c_str());
  518. return nullptr;
  519. }
  520. // Pre-insertion callback allows us to do network-specific setup for the entities before they are added to the scene
  521. optionalArgs.m_preInsertionCallback = [netSpawnableName, rootTransform = transform]
  522. (AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView entities)
  523. {
  524. const bool shouldUpdateTransform = !rootTransform.IsClose(AZ::Transform::Identity());
  525. for (uint32_t netEntityIndex = 0, entitiesSize = aznumeric_cast<uint32_t>(entities.size());
  526. netEntityIndex < entitiesSize; ++netEntityIndex)
  527. {
  528. AZ::Entity* netEntity = *(entities.begin() + netEntityIndex);
  529. if (shouldUpdateTransform)
  530. {
  531. AzFramework::TransformComponent* netEntityTransform =
  532. netEntity->FindComponent<AzFramework::TransformComponent>();
  533. AZ::Transform worldTm = netEntityTransform->GetWorldTM();
  534. worldTm = rootTransform * worldTm;
  535. netEntityTransform->SetWorldTM(worldTm);
  536. }
  537. PrefabEntityId prefabEntityId;
  538. prefabEntityId.m_prefabName = netSpawnableName;
  539. prefabEntityId.m_entityOffset = netEntityIndex;
  540. AZ::Interface<INetworkEntityManager>::Get()->SetupNetEntity(netEntity, prefabEntityId, NetEntityRole::Authority);
  541. }
  542. };
  543. // Spawn with the newly created ticket. This allows the calling code to manage the lifetime of the constructed entities
  544. auto ticket = AZStd::make_unique<AzFramework::EntitySpawnTicket>(netSpawnable);
  545. AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*ticket, AZStd::move(optionalArgs));
  546. return ticket;
  547. }
  548. void NetworkEntityManager::OnRootSpawnableAssigned(AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable,
  549. [[maybe_unused]] uint32_t generation)
  550. {
  551. auto* multiplayer = GetMultiplayer();
  552. const auto agentType = multiplayer->GetAgentType();
  553. if (agentType == MultiplayerAgentType::Client)
  554. {
  555. multiplayer->SendReadyForEntityUpdates(true);
  556. }
  557. }
  558. void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
  559. {
  560. auto* multiplayer = GetMultiplayer();
  561. const auto agentType = multiplayer->GetAgentType();
  562. if (agentType == MultiplayerAgentType::Client)
  563. {
  564. multiplayer->SendReadyForEntityUpdates(false);
  565. }
  566. }
  567. void NetworkEntityManager::OnResolveAliases(
  568. AzFramework::Spawnable::EntityAliasVisitor& aliases,
  569. [[maybe_unused]] const AzFramework::SpawnableMetaData& metadata,
  570. [[maybe_unused]] const AzFramework::Spawnable::EntityList& entities)
  571. {
  572. auto* multiplayer = GetMultiplayer();
  573. if (!multiplayer->GetShouldSpawnNetworkEntities())
  574. {
  575. aliases.UpdateAliases(NetworkEntityTag, [](
  576. AzFramework::Spawnable::EntityAliasType& aliasType,
  577. [[maybe_unused]] bool& queueLoad,
  578. [[maybe_unused]] const AZ::Data::Asset<AzFramework::Spawnable>& aliasedSpawnable,
  579. [[maybe_unused]] const AZ::Crc32 tag,
  580. [[maybe_unused]] const uint32_t sourceIndex,
  581. [[maybe_unused]] const uint32_t targetIndex)
  582. {
  583. aliasType = AzFramework::Spawnable::EntityAliasType::Disable;
  584. });
  585. }
  586. }
  587. void NetworkEntityManager::SetupNetEntity(AZ::Entity* netEntity, PrefabEntityId prefabEntityId, NetEntityRole netEntityRole)
  588. {
  589. auto* netBindComponent = netEntity->FindComponent<NetBindComponent>();
  590. if (netBindComponent)
  591. {
  592. const NetEntityId netEntityId = NextId();
  593. netBindComponent->PreInit(netEntity, prefabEntityId, netEntityId, netEntityRole);
  594. }
  595. else
  596. {
  597. AZ_Error("NetworkEntityManager", false, "SetupNetEntity called for an entity with no NetBindComponent. Entity: %s",
  598. netEntity->GetName().c_str());
  599. }
  600. }
  601. bool NetworkEntityManager::IsHierarchySafeToExit(NetworkEntityHandle& entityHandle, const NetEntityIdSet& entitiesNotInDomain)
  602. {
  603. bool safeToExit = true;
  604. // We also need special handling for the NetworkHierarchy as well, since related entities need to be migrated together
  605. NetworkHierarchyRootComponentController* hierarchyRootController = entityHandle.FindController<NetworkHierarchyRootComponentController>();
  606. NetworkHierarchyChildComponentController* hierarchyChildController = entityHandle.FindController<NetworkHierarchyChildComponentController>();
  607. AZStd::vector<AZ::Entity*> hierarchicalEntities;
  608. // Get the entities in this hierarchy
  609. if (hierarchyRootController)
  610. {
  611. hierarchicalEntities = hierarchyRootController->GetParent().GetHierarchicalEntities();
  612. }
  613. else if (hierarchyChildController)
  614. {
  615. hierarchicalEntities = hierarchyChildController->GetParent().GetHierarchicalEntities();
  616. }
  617. // Check if *all* entities in the hierarchy are ready to migrate.
  618. // If any are still "in domain", keep the whole hierarchy within the current authority for now
  619. for (AZ::Entity* entity : hierarchicalEntities)
  620. {
  621. NetEntityId netEntityId = GetNetEntityIdById(entity->GetId());
  622. if (netEntityId != InvalidNetEntityId && !entitiesNotInDomain.contains(netEntityId))
  623. {
  624. safeToExit = false;
  625. break;
  626. }
  627. }
  628. return safeToExit;
  629. }
  630. } // namespace Multiplayer