NetworkPrefabProcessor.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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 <Multiplayer/IMultiplayerTools.h>
  9. #include <Multiplayer/Components/NetBindComponent.h>
  10. #include <Multiplayer/MultiplayerConstants.h>
  11. #include <Pipeline/NetworkPrefabProcessor.h>
  12. #include <AzCore/Serialization/Utils.h>
  13. #include <AzFramework/Components/TransformComponent.h>
  14. #include <AzFramework/Spawnable/Spawnable.h>
  15. #include <AzFramework/Spawnable/SpawnableAssetHandler.h>
  16. #include <AzToolsFramework/Prefab/Instance/Instance.h>
  17. #include <AzToolsFramework/Prefab/PrefabDomUtils.h>
  18. #include <Prefab/Spawnable/SpawnableUtils.h>
  19. #include <Source/NetworkEntity/NetworkEntityManager.h>
  20. namespace Multiplayer
  21. {
  22. void NetworkPrefabProcessor::PostProcessSpawnable(const AZStd::string& prefabName, AzFramework::Spawnable& spawnable)
  23. {
  24. if (m_processedNetworkPrefabs.contains(prefabName))
  25. {
  26. AzFramework::Spawnable::EntityList& entityList = spawnable.GetEntities();
  27. uint32_t entityOffset = 0;
  28. for (AZStd::unique_ptr<AZ::Entity>& entity : entityList)
  29. {
  30. NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
  31. if (netBindComponent)
  32. {
  33. PrefabEntityId prefabEntityId = netBindComponent->GetPrefabEntityId();
  34. prefabEntityId.m_entityOffset = entityOffset;
  35. netBindComponent->SetPrefabEntityId(prefabEntityId);
  36. }
  37. ++entityOffset;
  38. }
  39. }
  40. }
  41. NetworkPrefabProcessor::NetworkPrefabProcessor()
  42. : m_postProcessHandler([this](const AZStd::string& prefabName, AzFramework::Spawnable& spawnable){ this->PostProcessSpawnable(prefabName, spawnable); })
  43. {
  44. }
  45. void NetworkPrefabProcessor::Process(AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
  46. {
  47. context.AddPrefabSpawnablePostProcessEventHandler(m_postProcessHandler);
  48. using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument;
  49. IMultiplayerTools* mpTools = AZ::Interface<IMultiplayerTools>::Get();
  50. if (mpTools)
  51. {
  52. mpTools->SetDidProcessNetworkPrefabs(false);
  53. }
  54. bool networkPrefabsAdded = false;
  55. context.ListPrefabs(
  56. [this, &networkPrefabsAdded, &context](PrefabDocument& prefab)
  57. {
  58. if (ProcessPrefab(context, prefab))
  59. {
  60. networkPrefabsAdded = true;
  61. }
  62. });
  63. if (mpTools && networkPrefabsAdded)
  64. {
  65. mpTools->SetDidProcessNetworkPrefabs(true);
  66. }
  67. }
  68. void NetworkPrefabProcessor::Reflect(AZ::ReflectContext* context)
  69. {
  70. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  71. {
  72. serializeContext->Class<NetworkPrefabProcessor, PrefabProcessor>()
  73. ->Version(6)
  74. ;
  75. }
  76. }
  77. static void PopulateNetworkInstance(
  78. AzToolsFramework::Prefab::Instance* sourceInstance,
  79. AzToolsFramework::Prefab::Instance* networkInstance,
  80. AzToolsFramework::Prefab::Instance* rootSourceInstance,
  81. AzToolsFramework::Prefab::Instance* rootNetworkInstance,
  82. const AZStd::string& prefabName,
  83. const AZStd::string& uniqueName,
  84. AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context,
  85. const AZ::Data::AssetId& networkSpawnableAssetId,
  86. uint32_t& networkEntityCount)
  87. {
  88. using AzToolsFramework::Prefab::PrefabConversionUtils::ProcessedObjectStore;
  89. using namespace AzToolsFramework::Prefab;
  90. sourceInstance->GetEntities(
  91. [networkInstance,
  92. rootSourceInstance,
  93. rootNetworkInstance,
  94. prefabName,
  95. uniqueName,
  96. &context,
  97. networkSpawnableAssetId,
  98. &networkEntityCount](AZStd::unique_ptr<AZ::Entity>& sourceEntity)
  99. {
  100. if (!sourceEntity->FindComponent<NetBindComponent>())
  101. {
  102. return true; // return true tells GetEntities to continue iterating over all the entities
  103. }
  104. ++networkEntityCount;
  105. const AZ::Entity* entity = sourceEntity.get();
  106. AZ::Entity* netEntity = SpawnableUtils::CreateEntityAlias(
  107. prefabName,
  108. *rootSourceInstance,
  109. uniqueName,
  110. *rootNetworkInstance,
  111. *networkInstance,
  112. entity->GetId(),
  113. PrefabConversionUtils::EntityAliasType::Replace,
  114. PrefabConversionUtils::EntityAliasSpawnableLoadBehavior::DependentLoad,
  115. NetworkEntityManager::NetworkEntityTag,
  116. context);
  117. AZ_Assert(
  118. netEntity, "Unable to create alias for network entity %s [%zu] from the source prefab instance %s", entity->GetName().c_str(),
  119. aznumeric_cast<AZ::u64>(entity->GetId()),
  120. prefabName.c_str());
  121. netEntity->InvalidateDependencies();
  122. netEntity->EvaluateDependencies();
  123. PrefabEntityId prefabEntityId;
  124. prefabEntityId.m_prefabName = sourceEntity->GetName();
  125. NetBindComponent* netBindComponent = netEntity->FindComponent<NetBindComponent>();
  126. netBindComponent->SetPrefabAssetId(networkSpawnableAssetId);
  127. netBindComponent->SetPrefabEntityId(prefabEntityId);
  128. return true;
  129. });
  130. sourceInstance->GetNestedInstances(
  131. [networkInstance,
  132. rootSourceInstance,
  133. rootNetworkInstance,
  134. prefabName,
  135. uniqueName,
  136. &context,
  137. networkSpawnableAssetId,
  138. &networkEntityCount](AZStd::unique_ptr<Instance>& sourceNestedInstance)
  139. {
  140. // Make a new nested instance for the network prefab instance
  141. AZStd::unique_ptr<Instance> networkNestedInstance =
  142. AZStd::make_unique<Instance>(
  143. InstanceOptionalReference(*rootNetworkInstance),
  144. sourceNestedInstance->GetInstanceAlias(),
  145. EntityIdInstanceRelationship::OneToMany);
  146. Instance& targetNestedInstance = networkInstance->AddInstance(AZStd::move(networkNestedInstance));
  147. PopulateNetworkInstance(
  148. sourceNestedInstance.get(),
  149. &targetNestedInstance,
  150. rootSourceInstance,
  151. rootNetworkInstance,
  152. prefabName,
  153. uniqueName,
  154. context,
  155. networkSpawnableAssetId,
  156. networkEntityCount);
  157. });
  158. }
  159. bool NetworkPrefabProcessor::ProcessPrefab(
  160. AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context,
  161. AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument& prefab)
  162. {
  163. using AzToolsFramework::Prefab::PrefabConversionUtils::ProcessedObjectStore;
  164. using namespace AzToolsFramework::Prefab;
  165. AZStd::string uniqueName = prefab.GetName();
  166. AZStd::string prefabName = prefab.GetName();
  167. uniqueName += NetworkSpawnableFileExtension;
  168. prefabName += NetworkFileExtension;
  169. PrefabConversionUtils::PrefabDocument networkPrefab(prefabName, prefab.GetInstance().GetInstanceAlias());
  170. Instance& sourceInstance = prefab.GetInstance();
  171. Instance& networkInstance = networkPrefab.GetInstance();
  172. AZ::Data::AssetId networkSpawnableAssetId(context.GetSourceUuid(), AzFramework::SpawnableAssetHandler::BuildSubId(uniqueName));
  173. // Grab all net entities with their corresponding Instances to handle nested prefabs correctly
  174. uint32_t networkEntityCount = 0;
  175. PopulateNetworkInstance(
  176. &sourceInstance,
  177. &networkInstance,
  178. &sourceInstance,
  179. &networkInstance,
  180. prefab.GetName(),
  181. prefabName,
  182. context,
  183. networkSpawnableAssetId,
  184. networkEntityCount);
  185. if (networkEntityCount == 0)
  186. {
  187. return false;
  188. }
  189. context.AddPrefab(AZStd::move(networkPrefab));
  190. m_processedNetworkPrefabs.insert(prefabName);
  191. return true;
  192. }
  193. }