InstanceEntityIdMapper.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <AzCore/Component/Entity.h>
  8. #include <AzCore/Math/Sfmt.h>
  9. #include <AzCore/StringFunc/StringFunc.h>
  10. #include <AzCore/Utils/TypeHash.h>
  11. #include <AzToolsFramework/Prefab/Instance/Instance.h>
  12. #include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
  13. #include <AzToolsFramework/Prefab/Instance/InstanceEntityMapper.h>
  14. namespace AzToolsFramework
  15. {
  16. namespace Prefab
  17. {
  18. AZ::JsonSerializationResult::Result InstanceEntityIdMapper::MapJsonToId(AZ::EntityId& outputValue,
  19. const rapidjson::Value& inputValue, AZ::JsonDeserializerContext& context)
  20. {
  21. namespace JSR = AZ::JsonSerializationResult;
  22. if (!m_loadingInstance)
  23. {
  24. AZ_Assert(false,
  25. "Attempted to map an EntityId in Prefab Instance without setting the Loading Prefab Instance");
  26. return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed,
  27. "Attempted to map an EntityId in Prefab Instance without setting the Loading Prefab Instance");
  28. }
  29. AZ::EntityId mappedValue(AZ::EntityId::InvalidEntityId);
  30. EntityAlias inputAlias;
  31. if (inputValue.IsString())
  32. {
  33. inputAlias = EntityAlias(inputValue.GetString(), inputValue.GetStringLength());
  34. }
  35. if (!inputAlias.empty())
  36. {
  37. AliasPath absoluteEntityPath = m_loadingInstance->GetAbsoluteInstanceAliasPath();
  38. absoluteEntityPath.Append(inputAlias);
  39. absoluteEntityPath = absoluteEntityPath.LexicallyNormal();
  40. mappedValue = GenerateEntityIdForAliasPath(absoluteEntityPath, m_randomSeed);
  41. if (!m_isEntityReference)
  42. {
  43. if (!m_loadingInstance->RegisterEntity(mappedValue, inputAlias))
  44. {
  45. mappedValue = AZ::EntityId(AZ::EntityId::InvalidEntityId);
  46. context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed,
  47. "Unable to register entity Id with prefab instance during load. Using default invalid id");
  48. }
  49. }
  50. }
  51. outputValue = mappedValue;
  52. return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully mapped Entity Id For Prefab Instance load");
  53. }
  54. AZ::JsonSerializationResult::Result InstanceEntityIdMapper::MapIdToJson(rapidjson::Value& outputValue,
  55. const AZ::EntityId& inputValue, AZ::JsonSerializerContext& context)
  56. {
  57. namespace JSR = AZ::JsonSerializationResult;
  58. if (!m_storingInstance)
  59. {
  60. return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed,
  61. "Attempted to map an EntityId in Prefab Instance without setting the Storing Prefab Instance");
  62. }
  63. EntityAlias mappedValue;
  64. if (inputValue.IsValid())
  65. {
  66. if (m_isEntityReference)
  67. {
  68. mappedValue = ResolveReferenceId(inputValue);
  69. }
  70. else
  71. {
  72. auto idMapIter = m_storingInstance->m_instanceToTemplateEntityIdMap.find(inputValue);
  73. if (idMapIter != m_storingInstance->m_instanceToTemplateEntityIdMap.end())
  74. {
  75. mappedValue = idMapIter->second;
  76. }
  77. else
  78. {
  79. AZStd::string defaultErrorMessage =
  80. "Entity with Id " + inputValue.ToString() +
  81. " could not be found within its owning instance. Defaulting to invalid Id for Store.";
  82. context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, defaultErrorMessage);
  83. }
  84. }
  85. }
  86. outputValue.SetString(rapidjson::StringRef(mappedValue.c_str(), mappedValue.length()), context.GetJsonAllocator());
  87. return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Success, "Successfully mapped Entity Id For Prefab Instance store");
  88. }
  89. void InstanceEntityIdMapper::SetEntityIdGenerationApproach(EntityIdGenerationApproach approach)
  90. {
  91. m_entityIdGenerationApproach = approach;
  92. if (m_entityIdGenerationApproach == EntityIdGenerationApproach::Hashed)
  93. {
  94. m_randomSeed = SeedKey;
  95. }
  96. else if (m_entityIdGenerationApproach == EntityIdGenerationApproach::Random)
  97. {
  98. m_randomSeed = AZ::Sfmt::GetInstance().Rand64();
  99. // Sanity check to avoid collision with hashed mode
  100. if (m_randomSeed == SeedKey)
  101. {
  102. m_randomSeed++;
  103. }
  104. }
  105. else
  106. {
  107. AZ_Assert(false, "Unsupported option in EntityIdGenerationApproach encountered."
  108. " Defaulting to Hashed");
  109. m_randomSeed = SeedKey;
  110. }
  111. }
  112. void InstanceEntityIdMapper::SetStoringInstance(const Instance& storingInstance)
  113. {
  114. m_storingInstance = &storingInstance;
  115. m_instanceAbsolutePath = m_storingInstance->GetAbsoluteInstanceAliasPath();
  116. }
  117. void InstanceEntityIdMapper::SetLoadingInstance(Instance& loadingInstance)
  118. {
  119. m_loadingInstance = &loadingInstance;
  120. }
  121. EntityAlias InstanceEntityIdMapper::ResolveReferenceId(const AZ::EntityId& entityId)
  122. {
  123. // Acquire the owning instance of our entity
  124. InstanceOptionalReference owningInstanceReference = m_storingInstance->m_instanceEntityMapper->FindOwningInstance(entityId);
  125. // Start with an empty alias to build out our reference path
  126. // If we can't resolve this id we'll return a new alias based on the entity ID instead of a reference path
  127. AliasPath relativeEntityAliasPath;
  128. if (!owningInstanceReference)
  129. {
  130. AZ_Warning("Prefabs", false,
  131. "Prefab - EntityIdMapper: Entity with Id %s has no registered owning instance",
  132. entityId.ToString().c_str());
  133. return {};
  134. }
  135. Instance* owningInstance = &(owningInstanceReference->get());
  136. // Build out the absolute path of this alias
  137. // so we can compare it to the absolute path of our currently scoped instance
  138. relativeEntityAliasPath = owningInstance->GetAbsoluteInstanceAliasPath();
  139. relativeEntityAliasPath.Append(owningInstance->GetEntityAlias(entityId)->get());
  140. return relativeEntityAliasPath.LexicallyRelative(m_instanceAbsolutePath).String();
  141. }
  142. AZ::EntityId InstanceEntityIdMapper::GenerateEntityIdForAliasPath(const AliasPathView& aliasPath, uint64_t seedKey)
  143. {
  144. const AZ::HashValue64 seed = aznumeric_cast<AZ::HashValue64>(seedKey);
  145. return AZ::EntityId(aznumeric_cast<AZ::u64>((AZ::TypeHash64(aliasPath.Native().data(), seed))));
  146. }
  147. }
  148. }