Преглед изворни кода

Merge pull request #671 from aws-lumberyard-dev/Prefabs/AssetPreload

Asset Preload fix for json serialization and prefab game mode
sconel пре 4 година
родитељ
комит
2e32b2ee57

+ 9 - 9
Code/Framework/AzCore/AzCore/Asset/AssetCommon.h

@@ -18,6 +18,7 @@
 #include <AzCore/RTTI/RTTI.h>
 #include <AzCore/Memory/SystemAllocator.h>
 #include <AzCore/Math/Uuid.h>
+#include <AzCore/Preprocessor/Enum.h>
 #include <AzCore/std/containers/bitset.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/string_view.h>
@@ -216,16 +217,14 @@ namespace AZ
         /**
          * Setting for each reference (Asset<T>) to control loading of referenced assets during serialization.
          */
-        enum class AssetLoadBehavior : u8
-        {
-            PreLoad     = 0,        ///< Serializer will "Pre load" dependencies, asset containers may load in parallel but will not signal AssetReady
-            QueueLoad   = 1,        ///< Serializer will queue an asynchronous load of the referenced asset and return the object to the user. User code should use the \ref AZ::Data::AssetBus to monitor for when it's ready.
-            NoLoad      = 2,        ///< Serializer will load reference information, but asset loading will be left to the user. User code should call Asset<T>::QueueLoad and use the \ref AZ::Data::AssetBus to monitor for when it's ready.
-                                    ///< AssetContainers will skip NoLoad dependencies
-            
+        AZ_ENUM_WITH_UNDERLYING_TYPE(AssetLoadBehavior, u8,
+            (PreLoad, 0),          ///< Serializer will "Pre load" dependencies, asset containers may load in parallel but will not signal AssetReady
+            (QueueLoad, 1),        ///< Serializer will queue an asynchronous load of the referenced asset and return the object to the user. User code should use the \ref AZ::Data::AssetBus to monitor for when it's ready.
+            (NoLoad, 2),           ///< Serializer will load reference information, but asset loading will be left to the user. User code should call Asset<T>::QueueLoad and use the \ref AZ::Data::AssetBus to monitor for when it's ready.
+                                   ///< AssetContainers will skip NoLoad dependencies
             Count,
-            Default = QueueLoad,
-        };
+            (Default, QueueLoad)
+        );
 
         struct AssetFilterInfo
         {
@@ -1222,6 +1221,7 @@ namespace AZ
         } // namespace ProductDependencyInfo
     }  // namespace Data
 
+    AZ_TYPE_INFO_SPECIALIZE(Data::AssetLoadBehavior, "{DAF9ECED-FEF3-4D7A-A220-8CFD6A5E6DA1}");
     AZ_TYPE_INFO_TEMPLATE_WITH_NAME(AZ::Data::Asset, "Asset", "{C891BF19-B60C-45E2-BFD0-027D15DDC939}", AZ_TYPE_INFO_CLASS);
 
 }   // namespace AZ

+ 47 - 2
Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.cpp

@@ -70,6 +70,17 @@ namespace AZ
                 }
             }
 
+            {
+                const AZ::Data::AssetLoadBehavior autoLoadBehavior = instance->GetAutoLoadBehavior();
+                const AZ::Data::AssetLoadBehavior defaultAutoLoadBehavior = defaultInstance ?
+                    defaultInstance->GetAutoLoadBehavior() : AZ::Data::AssetLoadBehavior::Default;
+
+                result.Combine(
+                    ContinueStoringToJsonObjectField(outputValue, "loadBehavior",
+                        &autoLoadBehavior, &defaultAutoLoadBehavior,
+                        azrtti_typeid<Data::AssetLoadBehavior>(), context));
+            }
+
             {
                 ScopedContextPath subPathHint(context, "m_assetHint");
                 const AZStd::string* hint = &instance->GetHint();
@@ -100,14 +111,28 @@ namespace AZ
             AssetId id;
             JSR::ResultCode result(JSR::Tasks::ReadField);
 
+            SerializedAssetTracker* assetTracker =
+                context.GetMetadata().Find<SerializedAssetTracker>();
+
+            {
+                Data::AssetLoadBehavior loadBehavior = instance->GetAutoLoadBehavior();
+
+                result =
+                    ContinueLoadingFromJsonObjectField(&loadBehavior,
+                        azrtti_typeid<Data::AssetLoadBehavior>(),
+                        inputValue, "loadBehavior", context);
+
+                instance->SetAutoLoadBehavior(loadBehavior);
+            }
+
             auto it = inputValue.FindMember("assetId");
             if (it != inputValue.MemberEnd())
             {
                 ScopedContextPath subPath(context, "assetId");
-                result = ContinueLoading(&id, azrtti_typeid<AssetId>(), it->value, context);
+                result.Combine(ContinueLoading(&id, azrtti_typeid<AssetId>(), it->value, context));
                 if (!id.m_guid.IsNull())
                 {
-                    *instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), AssetLoadBehavior::NoLoad);
+                    *instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), instance->GetAutoLoadBehavior());
 
 
                     result.Combine(context.Report(result, "Successfully created Asset<T> with id."));
@@ -142,6 +167,11 @@ namespace AZ
                     "The asset hint is missing for Asset<T>, so it will be left empty."));
             }
 
+            if (assetTracker)
+            {
+                assetTracker->AddAsset(*instance);
+            }
+
             bool success = result.GetOutcome() <= JSR::Outcomes::PartialSkip;
             bool defaulted = result.GetOutcome() == JSR::Outcomes::DefaultsUsed || result.GetOutcome() == JSR::Outcomes::PartialDefaults;
             AZStd::string_view message =
@@ -150,5 +180,20 @@ namespace AZ
                 "Not enough information was available to create an instance of Asset<T> or data was corrupted.";
             return context.Report(result, message);
         }
+
+        void SerializedAssetTracker::AddAsset(Asset<AssetData>& asset)
+        {
+            m_serializedAssets.emplace_back(asset);
+        }
+
+        const AZStd::vector<Asset<AssetData>>& SerializedAssetTracker::GetTrackedAssets() const
+        {
+            return m_serializedAssets;
+        }
+
+        AZStd::vector<Asset<AssetData>>& SerializedAssetTracker::GetTrackedAssets()
+        {
+            return m_serializedAssets;
+        }
     } // namespace Data
 } // namespace AZ

+ 14 - 0
Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.h

@@ -13,6 +13,7 @@
 #pragma once
 
 #include <AzCore/Memory/Memory.h>
+#include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Serialization/Json/BaseJsonSerializer.h>
 
 namespace AZ
@@ -37,5 +38,18 @@ namespace AZ
         private:
             JsonSerializationResult::Result LoadAsset(void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context);
         };
+
+        class SerializedAssetTracker final
+        {
+        public:
+            AZ_RTTI(SerializedAssetTracker, "{1E067091-8C0A-44B1-A455-6E97663F6963}");
+
+            void AddAsset(Asset<AssetData>& asset);
+            AZStd::vector<Asset<AssetData>>& GetTrackedAssets();
+            const AZStd::vector<Asset<AssetData>>& GetTrackedAssets() const;
+
+        private:
+            AZStd::vector<Asset<AssetData>> m_serializedAssets;
+        };
     } // namespace Data
 } // namespace AZ

+ 8 - 1
Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp

@@ -13,7 +13,7 @@
 #include <AzCore/Asset/AssetJsonSerializer.h>
 #include <AzCore/Asset/AssetManagerComponent.h>
 #include <AzCore/Asset/AssetManagerBus.h>
-#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Preprocessor/EnumReflectUtils.h>
 #include <AzCore/Serialization/EditContext.h>
 #include <AzCore/RTTI/BehaviorContext.h>
 #include <AzCore/Asset/AssetManager.h>
@@ -24,6 +24,11 @@
 
 namespace AZ
 {
+    namespace Data
+    {
+        AZ_ENUM_DEFINE_REFLECT_UTILITIES(AssetLoadBehavior);
+    }
+
     //=========================================================================
     // AssetDatabaseComponent
     // [6/25/2012]
@@ -99,6 +104,8 @@ namespace AZ
 
         if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
         {
+            AZ::Data::AssetLoadBehaviorReflect(*serializeContext);
+
             serializeContext->RegisterGenericType<Data::Asset<Data::AssetData>>();
 
             serializeContext->Class<AssetManagerComponent, AZ::Component>()

+ 0 - 2
Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h

@@ -14,8 +14,6 @@
 
 #include <limits>
 
-#include <AzCore/Asset/AssetCommon.h>
-
 #include <AzCore/Memory/OSAllocator.h>
 #include <AzCore/Memory/SystemAllocator.h>
 

+ 2 - 0
Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp

@@ -135,6 +135,7 @@ namespace JsonSerializationTests
             auto instance = AZStd::make_shared<Asset>();
             instance->Create(id, false);
             instance->SetHint("TestFile");
+            instance->SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
             return instance;
         }
 
@@ -158,6 +159,7 @@ namespace JsonSerializationTests
                         "guid": "{BBEAC89F-8BAD-4A9D-BF6E-D0DF84A8DFD6}",
                         "subId": 1
                     },
+                    "loadBehavior": "PreLoad",
                     "assetHint": "TestFile"
                 })";
         }

+ 66 - 1
Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp

@@ -13,6 +13,7 @@
 #include <AzCore/Component/Entity.h>
 #include <AzCore/Component/TransformBus.h>
 #include <AzCore/Script/ScriptSystemBus.h>
+#include <AzCore/Serialization/Utils.h>
 #include <AzFramework/API/ApplicationAPI.h>
 #include <AzFramework/Entity/GameEntityContextBus.h>
 #include <AzFramework/Spawnable/RootSpawnableInterface.h>
@@ -342,6 +343,65 @@ namespace AzToolsFramework
         m_validateEntitiesCallback = AZStd::move(validateEntitiesCallback);
     }
 
+    void PrefabEditorEntityOwnershipService::LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets)
+    {
+        // Start our loads on all assets by calling GetAsset from the AssetManager
+        for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
+        {
+            if (!asset.GetId().IsValid())
+            {
+                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
+                continue;
+            }
+
+            const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
+
+            if (loadBehavior == AZ::Data::AssetLoadBehavior::NoLoad)
+            {
+                continue;
+            }
+
+            AZ::Data::AssetId assetId = asset.GetId();
+            AZ::Data::AssetType assetType = asset.GetType();
+
+            asset = AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, loadBehavior);
+
+            if (!asset.GetId().IsValid())
+            {
+                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
+                continue;
+            }
+        }
+
+        // For all Preload assets we block until they're ready
+        // We do this as a seperate pass so that we don't interrupt queuing up all other asset loads
+        for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
+        {
+            if (!asset.GetId().IsValid())
+            {
+                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
+                continue;
+            }
+
+            const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
+
+            if (loadBehavior != AZ::Data::AssetLoadBehavior::PreLoad)
+            {
+                continue;
+            }
+
+            asset.BlockUntilLoadComplete();
+
+            if (asset.IsError())
+            {
+                AZ_Error("Prefab", false, "Asset with id %s failed to preload while entering game mode",
+                    asset.GetId().ToString<AZStd::string>().c_str());
+
+                continue;
+            }
+        }
+    }
+
     void PrefabEditorEntityOwnershipService::StartPlayInEditor()
     {
         // This is a workaround until the replacement for GameEntityContext is done
@@ -381,16 +441,21 @@ namespace AzToolsFramework
                                 rootSpawnableIndex = m_playInEditorData.m_assets.size();
                             }
 
+                            LoadReferencedAssets(product.GetReferencedAssets());
+
                             AZ::Data::AssetInfo info;
                             info.m_assetId = product.GetAsset().GetId();
                             info.m_assetType = product.GetAssetType();
                             info.m_relativePath = product.GetId();
 
                             AZ::Data::AssetCatalogRequestBus::Broadcast(
-                                &AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, product.GetAsset().GetId(), info);
+                                &AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, info.m_assetId, info);
                             m_playInEditorData.m_assets.emplace_back(product.ReleaseAsset().release(), AZ::Data::AssetLoadBehavior::Default);
                         }
 
+                        // make sure that PRE_NOTIFY assets get their notify before we activate, so that we can preserve the order of 
+                        // (load asset) -> (notify) -> (init) -> (activate)
+                        AZ::Data::AssetManager::Instance().DispatchEvents();
 
                         if (rootSpawnableIndex != NoRootSpawnable)
                         {

+ 2 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h

@@ -199,6 +199,8 @@ namespace AzToolsFramework
 
         void OnEntityRemoved(AZ::EntityId entityId);
 
+        void LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
+
         OnEntitiesAddedCallback m_entitiesAddedCallback;
         OnEntitiesRemovedCallback m_entitiesRemovedCallback;
         ValidateEntitiesCallback m_validateEntitiesCallback;

+ 44 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp

@@ -11,8 +11,10 @@
 */
 
 #include <AzCore/Asset/AssetManager.h>
+#include <AzCore/Asset/AssetJsonSerializer.h>
 #include <AzCore/JSON/prettywriter.h>
 #include <AzCore/Serialization/Json/JsonSerialization.h>
+
 #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
 #include <AzToolsFramework/Prefab/PrefabDomUtils.h>
 #include <AzToolsFramework/Prefab/Instance/Instance.h>
@@ -115,6 +117,48 @@ namespace AzToolsFramework
                 return true;
             }
 
+            bool LoadInstanceFromPrefabDom(
+                Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets, LoadInstanceFlags flags)
+            {
+                // When entities are rebuilt they are first destroyed. As a result any assets they were exclusively holding on to will
+                // be released and reloaded once the entities are built up again. By suspending asset release temporarily the asset reload
+                // is avoided.
+                AZ::Data::AssetManager::Instance().SuspendAssetRelease();
+
+                InstanceEntityIdMapper entityIdMapper;
+                entityIdMapper.SetLoadingInstance(instance);
+                if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
+                {
+                    entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
+                }
+
+                AZ::JsonDeserializerSettings settings;
+                // The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is
+                // specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta
+                // data has strict typing and doesn't look for inheritance both have to be explicitly added so they're found both locations.
+                settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
+                settings.m_metadata.Add(&entityIdMapper);
+                settings.m_metadata.Create<AZ::Data::SerializedAssetTracker>();
+
+                AZ::JsonSerializationResult::ResultCode result =
+                    AZ::JsonSerialization::Load(instance, prefabDom, settings);
+
+                AZ::Data::AssetManager::Instance().ResumeAssetRelease();
+
+                if (result.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
+                {
+                    AZ_Error("Prefab", false,
+                        "Failed to de-serialize Prefab Instance from Prefab DOM. "
+                        "Unable to proceed.");
+
+                    return false;
+                }
+                AZ::Data::SerializedAssetTracker* assetTracker = settings.m_metadata.Find<AZ::Data::SerializedAssetTracker>();
+
+                referencedAssets = AZStd::move(assetTracker->GetTrackedAssets());
+                return true;
+            }
+
             bool LoadInstanceFromPrefabDom(
                 Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom, LoadInstanceFlags flags)
             {

+ 18 - 5
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h

@@ -13,6 +13,7 @@
 #pragma once
 
 #include <AzCore/std/optional.h>
+#include <AzCore/Asset/AssetCommon.h>
 #include <AzToolsFramework/Prefab/Instance/Instance.h>
 #include <AzToolsFramework/Prefab/PrefabDomTypes.h>
 
@@ -42,7 +43,7 @@ namespace AzToolsFramework
             /**
             * Stores a valid Prefab Instance within a Prefab Dom. Useful for generating Templates
             * @param instance The instance to store
-            * @param prefabDom the prefabDom that will be used to store the Instance data
+            * @param prefabDom The prefabDom that will be used to store the Instance data
             * @return bool on whether the operation succeeded
             */
             bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom);
@@ -60,20 +61,32 @@ namespace AzToolsFramework
             /**
             * Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
             * @param instance The Instance to load.
-            * @param prefabDom the prefabDom that will be used to load the Instance data.
-            * @param shouldClearContainers whether to clear containers in Instance while loading.
+            * @param prefabDom The prefabDom that will be used to load the Instance data.
+            * @param shouldClearContainers Whether to clear containers in Instance while loading.
             * @return bool on whether the operation succeeded.
             */
             bool LoadInstanceFromPrefabDom(
                 Instance& instance, const PrefabDom& prefabDom, LoadInstanceFlags flags = LoadInstanceFlags::None);
 
+            /**
+            * Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
+            * @param instance The Instance to load.
+            * @param referencedAssets AZ::Assets discovered during json load are added to this list
+            * @param prefabDom The prefabDom that will be used to load the Instance data.
+            * @param shouldClearContainers Whether to clear containers in Instance while loading.
+            * @return bool on whether the operation succeeded.
+            */
+            bool LoadInstanceFromPrefabDom(
+                Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets,
+                LoadInstanceFlags flags = LoadInstanceFlags::None);
+
             /**
             * Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
             * @param instance The Instance to load.
             * @param newlyAddedEntities The new instances added during deserializing the instance. These are the entities found
             *       in the prefabDom.
-            * @param prefabDom the prefabDom that will be used to load the Instance data.
-            * @param shouldClearContainers whether to clear containers in Instance while loading.
+            * @param prefabDom The prefabDom that will be used to load the Instance data.
+            * @param shouldClearContainers Whether to clear containers in Instance while loading.
             * @return bool on whether the operation succeeded.
             */
             bool LoadInstanceFromPrefabDom(

+ 1 - 1
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp

@@ -63,7 +63,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
             AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer));
         AZ_Assert(spawnable, "Failed to create a new spawnable.");
 
-        bool result = SpawnableUtils::CreateSpawnable(*spawnable, prefab);
+        bool result = SpawnableUtils::CreateSpawnable(*spawnable, prefab, object.GetReferencedAssets());
         if (result)
         {
             AzFramework::Spawnable::EntityList& entities = spawnable->GetEntities();

+ 10 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.cpp

@@ -56,6 +56,16 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
         return *m_asset;
     }
 
+    AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& ProcessedObjectStore::GetReferencedAssets()
+    {
+        return m_referencedAssets;
+    }
+
+    const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& ProcessedObjectStore::GetReferencedAssets() const
+    {
+        return m_referencedAssets;
+    }
+
     AZStd::unique_ptr<AZ::Data::AssetData> ProcessedObjectStore::ReleaseAsset()
     {
         return AZStd::move(m_asset);

+ 5 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h

@@ -48,6 +48,10 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
         AZ::Data::AssetData& GetAsset();
         AZStd::unique_ptr<AZ::Data::AssetData> ReleaseAsset();
 
+        AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetReferencedAssets();
+        const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetReferencedAssets() const;
+
+
         const AZStd::string& GetId() const;
 
     private:
@@ -55,6 +59,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
 
         SerializerFunction m_assetSerializer;
         AZStd::unique_ptr<AZ::Data::AssetData> m_asset;
+        AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> m_referencedAssets;
         AZStd::string m_uniqueId;
     };
 

+ 9 - 2
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/SpawnableUtils.cpp

@@ -28,16 +28,23 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
     AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom)
     {
         AzFramework::Spawnable spawnable;
-        [[maybe_unused]] bool result = CreateSpawnable(spawnable, prefabDom);
+        AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> referencedAssets;
+        [[maybe_unused]] bool result = CreateSpawnable(spawnable, prefabDom, referencedAssets);
         AZ_Assert(result,
             "Failed to Load Prefab Instance from given Prefab DOM while Spawnable creation.");
         return spawnable;
     }
 
     bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom)
+    {
+        AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> referencedAssets;
+        return CreateSpawnable(spawnable, prefabDom, referencedAssets);
+    }
+
+    bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets)
     {
         Instance instance;
-        if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom,
+        if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom, referencedAssets,
             Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
                                                                               // going to be used to create clones of the entities.
         {

+ 1 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h

@@ -19,6 +19,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
 {
     AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom);
     bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom);
+    bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
 
     void SortEntitiesByTransformHierarchy(AzFramework::Spawnable& spawnable);
 } // namespace AzToolsFramework::Prefab::SpawnableUtils