Procedural Prefabs: Stable transform component ID (#6227)
* Set Procedural Prefab Transform ComponentId to the hash of the file path. Procedural prefabs needs to have a deterministic transform component ID in order for saved patches still work when the prefab is regenerated. Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Switch to Cityhash instead of XXHash since prefab system is using that elsewhere Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Added unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Fix missing include Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>
This commit is contained in:
+15
-2
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Utils/TypeHash.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
|
||||
#include <Prefab/PrefabSystemComponentInterface.h>
|
||||
@@ -73,12 +74,24 @@ namespace AzToolsFramework::Prefab
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(result, &AzToolsFramework::ToolsApplicationRequestBus::Events::FindCommonRootInactive,
|
||||
entities, commonRoot, &topLevelEntities);
|
||||
|
||||
|
||||
auto containerEntity = AZStd::make_unique<AZ::Entity>();
|
||||
containerEntity->CreateComponent<Components::TransformComponent>();
|
||||
|
||||
containerEntity->CreateComponent<Components::EditorLockComponent>();
|
||||
containerEntity->CreateComponent<Components::EditorVisibilityComponent>();
|
||||
containerEntity->CreateComponent<Prefab::EditorPrefabComponent>();
|
||||
|
||||
{
|
||||
auto transformComponent = containerEntity->CreateComponent<Components::TransformComponent>();
|
||||
// Because procedural prefabs need to be deterministic we need to set the component ID to something unique and non-random
|
||||
// The prefab that references the proc prefab will store a patch that references the transform component by it's component ID
|
||||
// If this ID is not stable, the proc prefab will lose its position, parenting, etc data next time it is regenerated
|
||||
auto hash = TypeHash64(reinterpret_cast<const uint8_t*>(filePath.data()), filePath.length(), AZ::HashValue64{0});
|
||||
|
||||
transformComponent->SetId(static_cast<AZ::ComponentId>(hash));
|
||||
|
||||
}
|
||||
|
||||
for (AZ::Entity* entity : topLevelEntities)
|
||||
{
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
@@ -92,7 +105,7 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(
|
||||
entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)), AZStd::move(containerEntity));
|
||||
|
||||
|
||||
if (!prefab)
|
||||
{
|
||||
AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str());
|
||||
|
||||
@@ -48,11 +48,45 @@ namespace UnitTest
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PrefabScriptingTest, CreatePrefabTemplate_GeneratesContainerWithStableTransformComponentId)
|
||||
{
|
||||
AZ::EntityId entityId;
|
||||
AzToolsFramework::EntityUtilityBus::BroadcastResult(entityId, &AzToolsFramework::EntityUtilityBus::Events::CreateEditorReadyEntity, "test");
|
||||
TemplateId templateId1;
|
||||
PrefabSystemScriptingBus::BroadcastResult(templateId1, &PrefabSystemScriptingBus::Events::CreatePrefabTemplate, AZStd::vector{ entityId }, "test.prefab");
|
||||
|
||||
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
|
||||
auto instance1 = prefabSystemComponentInterface->InstantiatePrefab(templateId1);
|
||||
|
||||
// Clear all templates to reset the system
|
||||
prefabSystemComponentInterface->RemoveAllTemplates();
|
||||
|
||||
TemplateId templateId2;
|
||||
PrefabSystemScriptingBus::BroadcastResult(templateId2, &PrefabSystemScriptingBus::Events::CreatePrefabTemplate, AZStd::vector{ entityId }, "test.prefab");
|
||||
|
||||
auto instance2 = prefabSystemComponentInterface->InstantiatePrefab(templateId2);
|
||||
|
||||
auto referenceWrapper1 = instance1->GetContainerEntity();
|
||||
auto referenceWrapper2 = instance2->GetContainerEntity();
|
||||
|
||||
ASSERT_TRUE(referenceWrapper1);
|
||||
ASSERT_TRUE(referenceWrapper2);
|
||||
|
||||
auto transformComponent1 = referenceWrapper1->get().FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
auto transformComponent2 = referenceWrapper2->get().FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
ASSERT_NE(transformComponent1, nullptr);
|
||||
ASSERT_NE(transformComponent2, nullptr);
|
||||
|
||||
ASSERT_EQ(transformComponent1->GetId(), transformComponent2->GetId());
|
||||
}
|
||||
|
||||
TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
@@ -76,7 +110,7 @@ namespace UnitTest
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
@@ -99,7 +133,7 @@ namespace UnitTest
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
@@ -119,7 +153,7 @@ namespace UnitTest
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
@@ -132,7 +166,7 @@ namespace UnitTest
|
||||
g_globalPrefabString = my_result:GetValue()
|
||||
end
|
||||
)LUA");
|
||||
|
||||
|
||||
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
prefabSystemComponentInterface->RemoveAllTemplates();
|
||||
|
||||
@@ -169,5 +203,5 @@ namespace UnitTest
|
||||
|
||||
g_globalPrefabString.set_capacity(0); // Free all memory
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user