Procházet zdrojové kódy

Finishing required work to support Spawnable buses in Lua

Signed-off-by: Mikhail Naumov <[email protected]>
Mikhail Naumov před 3 roky
rodič
revize
cfbce4bd83
20 změnil soubory, kde provedl 473 přidání a 285 odebrání
  1. 91 0
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableAssetRef.cpp
  2. 8 8
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableAssetRef.h
  3. 55 0
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableBus.h
  4. 8 3
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.cpp
  5. 40 0
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableNotificationsHandler.h
  6. 157 2
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp
  7. 30 1
      Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.h
  8. 5 0
      Code/Framework/AzFramework/AzFramework/azframework_files.cmake
  9. 1 1
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.ScriptCanvasNodeable.xml
  10. 7 2
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.cpp
  11. 2 2
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h
  12. 11 38
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.cpp
  13. 6 10
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.h
  14. 13 75
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp
  15. 5 15
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.h
  16. 0 116
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnableAsset.cpp
  17. 34 9
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/Spawning.cpp
  18. 0 1
      Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/Spawning.h
  19. 0 1
      Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake
  20. 0 1
      Gems/ScriptCanvas/Code/scriptcanvasgem_headers.cmake

+ 91 - 0
Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableAssetRef.cpp

@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzCore/RTTI/BehaviorContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
+#include <AzFramework/Spawnable/SpawnableAssetRef.h>
+#include <AzFramework/StringFunc/StringFunc.h>
+
+namespace AzFramework
+{
+    void SpawnableAssetRef::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext
+                ->Class<SpawnableAssetRef>()
+                ->Field("Asset", &SpawnableAssetRef::m_asset);
+
+            serializeContext->RegisterGenericType<AZStd::vector<SpawnableAssetRef>>();
+            serializeContext->RegisterGenericType<AZStd::unordered_map<AZStd::string, SpawnableAssetRef>>();
+            serializeContext->RegisterGenericType<AZStd::unordered_map<double, SpawnableAssetRef>>(); // required to support Map<Number, SpawnableAssetRef> in Script Canvas
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext
+                    ->Class<SpawnableAssetRef>("SpawnableAssetRef", "A wrapper around spawnable asset to be used as a variable in Script Canvas.")
+                    // m_asset
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &SpawnableAssetRef::m_asset, "m_asset", "")
+                    ->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, false)
+                    ->Attribute(AZ::Edit::Attributes::HideProductFilesInAssetPicker, true)
+                    ->Attribute(AZ::Edit::Attributes::AssetPickerTitle, "Spawnable Asset")
+                    ->Attribute(AZ::Edit::Attributes::ChangeNotify, &SpawnableAssetRef::OnSpawnAssetChanged);
+            }
+        }
+
+        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext
+                ->Class<SpawnableAssetRef>("SpawnableAssetRef")
+                ->Constructor()
+                ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+                ->Attribute(AZ::Script::Attributes::Category, "Prefab/Spawning")
+                ->Attribute(AZ::Script::Attributes::Module, "prefabs")
+                ->Property("m_asset", BehaviorValueProperty(&SpawnableAssetRef::m_asset));
+        }
+    }
+
+    SpawnableAssetRef::SpawnableAssetRef(const SpawnableAssetRef& rhs)
+        : m_asset(rhs.m_asset)
+    {
+    }
+
+    SpawnableAssetRef& SpawnableAssetRef::operator=(const SpawnableAssetRef& rhs)
+    {
+        m_asset = rhs.m_asset;
+        return *this;
+    }
+
+    void SpawnableAssetRef::OnSpawnAssetChanged()
+    {
+        if (m_asset.GetId().IsValid())
+        {
+            AZStd::string rootSpawnableFile;
+            StringFunc::Path::GetFileName(m_asset.GetHint().c_str(), rootSpawnableFile);
+
+            rootSpawnableFile += Spawnable::DotFileExtension;
+
+            AZ::u32 rootSubId = SpawnableAssetHandler::BuildSubId(move(rootSpawnableFile));
+
+            if (m_asset.GetId().m_subId != rootSubId)
+            {
+                AZ::Data::AssetId rootAssetId = m_asset.GetId();
+                rootAssetId.m_subId = rootSubId;
+
+                m_asset = AZ::Data::AssetManager::Instance().FindOrCreateAsset<Spawnable>(
+                    rootAssetId, AZ::Data::AssetLoadBehavior::Default);
+            }
+            else
+            {
+                m_asset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::Default);
+            }
+        }
+    }
+}

+ 8 - 8
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnableAsset.h → Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableAssetRef.h

@@ -14,20 +14,20 @@
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Asset/AssetCommon.h>
 #include <AzFramework/Spawnable/Spawnable.h>
 #include <AzFramework/Spawnable/Spawnable.h>
 
 
-namespace ScriptCanvas::Nodeables::Spawning
+namespace AzFramework
 {
 {
-    //! A wrapper around Spawnable that can be used by Script Canvas
-    struct SpawnableAsset final
+    //! A wrapper around Spawnable asset that can be used by Script Canvas and Lua
+    struct SpawnableAssetRef final
     {
     {
-        AZ_RTTI(SpawnableAsset, "{A96A5037-AD0D-43B6-9948-ED63438C4A52}");
+        AZ_RTTI(SpawnableAssetRef, "{A96A5037-AD0D-43B6-9948-ED63438C4A52}");
         static void Reflect(AZ::ReflectContext* context);
         static void Reflect(AZ::ReflectContext* context);
 
 
-        SpawnableAsset() = default;
-        SpawnableAsset(const SpawnableAsset& rhs);
-        SpawnableAsset& operator=(const SpawnableAsset& rhs);
+        SpawnableAssetRef() = default;
+        SpawnableAssetRef(const SpawnableAssetRef& rhs);
+        SpawnableAssetRef& operator=(const SpawnableAssetRef& rhs);
 
 
         void OnSpawnAssetChanged();
         void OnSpawnAssetChanged();
 
 
-        AZ::Data::Asset<AzFramework::Spawnable> m_asset;
+        AZ::Data::Asset<Spawnable> m_asset;
     };
     };
 }
 }

+ 55 - 0
Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableBus.h

@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/EBus/EBus.h>
+#include <AzCore/Math/Vector3.h>
+#include <AzFramework/Spawnable/SpawnableAssetRef.h>
+#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
+
+namespace AzFramework
+{
+    class SpawnableRequests
+        : public AZ::EBusTraits
+    {
+    public:
+        // Only a single handler is allowed
+        static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+
+        virtual EntitySpawnTicket CreateSpawnTicket(const SpawnableAssetRef& spawnableAsset) = 0;
+
+        virtual bool Spawn(
+            EntitySpawnTicket spawnTicket,
+            AZ::EntityId parentId,
+            AZ::Vector3 translation,
+            AZ::Vector3 rotation,
+            float scale) = 0;
+
+        virtual bool Despawn(EntitySpawnTicket spawnTicket) = 0;
+    };
+
+    using SpawnableRequestsBus = AZ::EBus<SpawnableRequests>;
+
+    class SpawnableNotifications
+        : public AZ::EBusTraits
+    {
+    public:
+        // EBusTraits overrides
+        using BusIdType = EntitySpawnTicket::Id;
+        static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
+
+        virtual void OnSpawn(
+            [[maybe_unused]] EntitySpawnTicket spawnTicket,
+            [[maybe_unused]] AZStd::vector<AZ::EntityId> entityList) {}
+
+        virtual void OnDespawn([[maybe_unused]] EntitySpawnTicket spawnTicket) {}
+    };
+    
+    using SpawnableNotificationsBus = AZ::EBus<SpawnableNotifications>;
+} // namespace AzFramework

+ 8 - 3
Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.cpp

@@ -362,7 +362,11 @@ namespace AzFramework
         {
         {
             serializeContext
             serializeContext
                 ->Class<EntitySpawnTicket>();
                 ->Class<EntitySpawnTicket>();
-            
+
+            serializeContext->RegisterGenericType<AZStd::vector<EntitySpawnTicket>>();
+            serializeContext->RegisterGenericType<AZStd::unordered_map<AZStd::string, EntitySpawnTicket>>();
+            serializeContext->RegisterGenericType<AZStd::unordered_map<double, EntitySpawnTicket>>(); // required to support Map<Number, EntitySpawnTicket> in Script Canvas
+
             if (AZ::EditContext* editContext = serializeContext->GetEditContext())
             if (AZ::EditContext* editContext = serializeContext->GetEditContext())
             {
             {
                 editContext->Class<EntitySpawnTicket>(
                 editContext->Class<EntitySpawnTicket>(
@@ -378,8 +382,9 @@ namespace AzFramework
                 ->Constructor<AZ::Data::Asset<Spawnable>>()
                 ->Constructor<AZ::Data::Asset<Spawnable>>()
                 ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
                 ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
                 ->Attribute(AZ::Script::Attributes::Category, "Prefab/Spawning")
                 ->Attribute(AZ::Script::Attributes::Category, "Prefab/Spawning")
-                ->Attribute(AZ::Script::Attributes::Module, "Prefabs")
-                ->Attribute(AZ::Script::Attributes::EnableAsScriptEventParamType, true);
+                ->Attribute(AZ::Script::Attributes::Module, "prefabs")
+                ->Method("GetId", &EntitySpawnTicket::GetId);
+            ;
         }
         }
     }
     }
 
 

+ 40 - 0
Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableNotificationsHandler.h

@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzFramework/Spawnable/SpawnableBus.h>
+#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
+
+namespace AzFramework
+{
+    //! Behavior Context forwarder for SpawnableNotificationsBus
+    struct SpawnableNotificationsHandler final
+        : public SpawnableNotificationsBus::Handler
+        , public AZ::BehaviorEBusHandler
+    {
+        AZ_EBUS_BEHAVIOR_BINDER(
+            SpawnableNotificationsHandler,
+            "{3403D10A-9541-46A1-97CD-F994FF9E52C2}",
+            AZ::SystemAllocator,
+            OnSpawn,
+            OnDespawn);
+
+        void OnSpawn(
+            EntitySpawnTicket spawnTicket,
+            AZStd::vector<AZ::EntityId> entityList) override
+        {
+            Call(FN_OnSpawn, spawnTicket, entityList);
+        }
+
+        virtual void OnDespawn(EntitySpawnTicket spawnTicket)
+        {
+            Call(FN_OnDespawn, spawnTicket);
+        }
+    };
+} // namespace AzFramework

+ 157 - 2
Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp

@@ -9,10 +9,13 @@
 #include <AzCore/Asset/AssetManager.h>
 #include <AzCore/Asset/AssetManager.h>
 #include <AzCore/Asset/AssetSerializer.h>
 #include <AzCore/Asset/AssetSerializer.h>
 #include <AzCore/Component/ComponentApplicationLifecycle.h>
 #include <AzCore/Component/ComponentApplicationLifecycle.h>
-#include <AzCore/Settings/SettingsRegistry.h>
-#include <AzCore/Serialization/SerializeContext.h>
 #include <AzCore/Serialization/EditContext.h>
 #include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Settings/SettingsRegistry.h>
+#include <AzFramework/Components/TransformComponent.h>
+#include <AzFramework/Spawnable/SpawnableAssetRef.h>
 #include <AzFramework/Spawnable/SpawnableMetaData.h>
 #include <AzFramework/Spawnable/SpawnableMetaData.h>
+#include <AzFramework/Spawnable/SpawnableNotificationsHandler.h>
 #include <AzFramework/Spawnable/SpawnableSystemComponent.h>
 #include <AzFramework/Spawnable/SpawnableSystemComponent.h>
 
 
 namespace AzFramework
 namespace AzFramework
@@ -22,12 +25,30 @@ namespace AzFramework
         Spawnable::Reflect(context);
         Spawnable::Reflect(context);
         SpawnableMetaData::Reflect(context);
         SpawnableMetaData::Reflect(context);
         EntitySpawnTicket::Reflect(context);
         EntitySpawnTicket::Reflect(context);
+        SpawnableAssetRef::Reflect(context);
 
 
         if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
         if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
         {
         {
             serializeContext->Class<SpawnableSystemComponent, AZ::Component>();
             serializeContext->Class<SpawnableSystemComponent, AZ::Component>();
             serializeContext->RegisterGenericType<AZ::Data::Asset<Spawnable>>();
             serializeContext->RegisterGenericType<AZ::Data::Asset<Spawnable>>();
         }
         }
+
+        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->EBus<SpawnableRequestsBus>("SpawnableRequestsBus")
+                ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+                ->Attribute(AZ::Script::Attributes::Category, "Prefab/Spawning")
+                ->Attribute(AZ::Script::Attributes::Module, "prefabs")
+                ->Event("CreateSpawnTicket", &SpawnableRequests::CreateSpawnTicket)
+                ->Event("Spawn", &SpawnableRequests::Spawn)
+                ->Event("Despawn", &SpawnableRequests::Despawn);
+
+            behaviorContext->EBus<SpawnableNotificationsBus>("SpawnableNotificationsBus")
+                ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+                ->Attribute(AZ::Script::Attributes::Category, "Prefab/Spawning")
+                ->Attribute(AZ::Script::Attributes::Module, "prefabs")
+                ->Handler<SpawnableNotificationsHandler>();
+        }
     }
     }
 
 
     void SpawnableSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
     void SpawnableSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
@@ -50,6 +71,9 @@ namespace AzFramework
     {
     {
         ProcessSpawnableQueue();
         ProcessSpawnableQueue();
         RootSpawnableNotificationBus::ExecuteQueuedEvents();
         RootSpawnableNotificationBus::ExecuteQueuedEvents();
+
+        ProcessDespawnedResults();
+        ProcessSpawnedResults();
     }
     }
 
 
     int SpawnableSystemComponent::GetTickOrder()
     int SpawnableSystemComponent::GetTickOrder()
@@ -146,6 +170,92 @@ namespace AzFramework
         AZ_TracePrintf("Spawnables", "Generation %i of the root spawnable has been released.\n", generation);
         AZ_TracePrintf("Spawnables", "Generation %i of the root spawnable has been released.\n", generation);
     }
     }
 
 
+    EntitySpawnTicket SpawnableSystemComponent::CreateSpawnTicket(const SpawnableAssetRef& spawnableAsset)
+    {
+        return EntitySpawnTicket(spawnableAsset.m_asset);
+    }
+
+    bool SpawnableSystemComponent::Spawn(
+        EntitySpawnTicket spawnTicket,
+        AZ::EntityId parentId,
+        AZ::Vector3 translation,
+        AZ::Vector3 rotation,
+        float scale)
+    {
+        if (!spawnTicket.IsValid())
+        {
+            AZ_Error("Spawnables", false, "EntitySpawnTicket used for spawning is invalid.");
+            return false;
+        }
+
+        auto preSpawnCB = [this, parentId, translation, rotation, scale](
+                              [[maybe_unused]] EntitySpawnTicket::Id ticketId,
+            SpawnableEntityContainerView view)
+        {
+            AZStd::lock_guard lock(m_mutex);
+
+            AZ::Entity* rootEntity = *view.begin();
+            TransformComponent* entityTransform = rootEntity->FindComponent<TransformComponent>();
+
+            if (entityTransform)
+            {
+                AZ::Vector3 rotationCopy = rotation;
+                AZ::Quaternion rotationQuat = AZ::Quaternion::CreateFromEulerAnglesDegrees(rotationCopy);
+
+                TransformComponentConfiguration transformConfig;
+                transformConfig.m_parentId = parentId;
+                transformConfig.m_localTransform = AZ::Transform(translation, rotationQuat, scale);
+                entityTransform->SetConfiguration(transformConfig);
+            }
+        };
+
+        auto spawnCompleteCB =
+            [this,
+             spawnTicket]([[maybe_unused]] EntitySpawnTicket::Id ticketId, SpawnableConstEntityContainerView view)
+        {
+            AZStd::lock_guard lock(m_mutex);
+
+            SpawnableResult spawnableResult;
+            // SpawnTicket instance is cached instead of SpawnTicketId to simplify managing its lifecycle on Script Canvas
+            // and to provide easier access to it in OnSpawnCompleted callback
+            spawnableResult.m_spawnTicket = spawnTicket;
+            spawnableResult.m_entityList.reserve(view.size());
+            for (const AZ::Entity* entity : view)
+            {
+                spawnableResult.m_entityList.emplace_back(entity->GetId());
+            }
+            m_spawnedResults.push_back(spawnableResult);
+        };
+
+        SpawnAllEntitiesOptionalArgs optionalArgs;
+        optionalArgs.m_preInsertionCallback = AZStd::move(preSpawnCB);
+        optionalArgs.m_completionCallback = AZStd::move(spawnCompleteCB);
+        SpawnableEntitiesInterface::Get()->SpawnAllEntities(spawnTicket, AZStd::move(optionalArgs));
+        return true;
+    }
+
+    bool SpawnableSystemComponent::Despawn(EntitySpawnTicket spawnTicket)
+    {
+        if (!spawnTicket.IsValid())
+        {
+            AZ_Error("Spawnables", false, "EntitySpawnTicket used for despawning is invalid.");
+            return false;
+        }
+
+        auto despawnCompleteCB = [this, spawnTicket]([[maybe_unused]] EntitySpawnTicket::Id ticketId)
+        {
+            AZStd::lock_guard lock(m_mutex);
+            // SpawnTicket instance is cached instead of SpawnTicketId to simplify managing its lifecycle on Script Canvas
+            // and to provide easier access to it in OnDespawn callback
+            m_despawnedResults.push_back(spawnTicket);
+        };
+
+        DespawnAllEntitiesOptionalArgs optionalArgs;
+        optionalArgs.m_completionCallback = AZStd::move(despawnCompleteCB);
+        SpawnableEntitiesInterface::Get()->DespawnAllEntities(spawnTicket, AZStd::move(optionalArgs));
+        return true;
+    }
+
     void SpawnableSystemComponent::Activate()
     void SpawnableSystemComponent::Activate()
     {
     {
         // Register with AssetDatabase
         // Register with AssetDatabase
@@ -172,6 +282,7 @@ namespace AzFramework
 
 
         RootSpawnableNotificationBus::Handler::BusConnect();
         RootSpawnableNotificationBus::Handler::BusConnect();
         AZ::TickBus::Handler::BusConnect();
         AZ::TickBus::Handler::BusConnect();
+        SpawnableRequestsBus::Handler::BusConnect();
 
 
         m_registryChangeHandler = settingsRegistry->RegisterNotifier([this](AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/)
         m_registryChangeHandler = settingsRegistry->RegisterNotifier([this](AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/)
             {
             {
@@ -184,12 +295,20 @@ namespace AzFramework
 
 
     void SpawnableSystemComponent::Deactivate()
     void SpawnableSystemComponent::Deactivate()
     {
     {
+        m_spawnedResults.clear(); // clears any cached SpawnTickets that may remain so everything despawns
+        m_spawnedResults.shrink_to_fit();
+
+        m_despawnedResults.clear(); // clears any cached SpawnTickets that may remain so everything despawns
+        m_despawnedResults.shrink_to_fit();
+
         ProcessSpawnableQueue();
         ProcessSpawnableQueue();
 
 
         m_registryChangeHandler.Disconnect();
         m_registryChangeHandler.Disconnect();
 
 
         AZ::TickBus::Handler::BusDisconnect();
         AZ::TickBus::Handler::BusDisconnect();
         RootSpawnableNotificationBus::Handler::BusDisconnect();
         RootSpawnableNotificationBus::Handler::BusDisconnect();
+        SpawnableRequestsBus::Handler::BusDisconnect();
+
         // Unregister Lifecycle event handler
         // Unregister Lifecycle event handler
         m_criticalAssetsHandler = {};
         m_criticalAssetsHandler = {};
 
 
@@ -272,4 +391,40 @@ namespace AzFramework
             ReleaseRootSpawnable();
             ReleaseRootSpawnable();
         }
         }
     }
     }
+
+    void SpawnableSystemComponent::ProcessSpawnedResults()
+    {
+        AZStd::vector<SpawnableResult> swappedSpawnedResults;
+        {
+            AZStd::lock_guard lock(m_mutex);
+            swappedSpawnedResults.swap(m_spawnedResults);
+        }
+
+        for (const auto& spawnResult : swappedSpawnedResults)
+        {
+            if (spawnResult.m_entityList.empty())
+            {
+                continue;
+            }
+            SpawnableNotificationsBus::Event(
+                spawnResult.m_spawnTicket.GetId(),
+                &SpawnableNotifications::OnSpawn,
+                spawnResult.m_spawnTicket,
+                move(spawnResult.m_entityList));
+        }
+    }
+
+    void SpawnableSystemComponent::ProcessDespawnedResults()
+    {
+        AZStd::vector<EntitySpawnTicket> swappedDespawnedResults;
+        {
+            AZStd::lock_guard lock(m_mutex);
+            swappedDespawnedResults.swap(m_despawnedResults);
+        }
+
+        for (const auto& spawnTicket : swappedDespawnedResults)
+        {
+            SpawnableNotificationsBus::Event(spawnTicket.GetId(), &SpawnableNotifications::OnDespawn, spawnTicket);
+        }
+    }
 } // namespace AzFramework
 } // namespace AzFramework

+ 30 - 1
Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.h

@@ -15,6 +15,7 @@
 #include <AzFramework/Spawnable/RootSpawnableInterface.h>
 #include <AzFramework/Spawnable/RootSpawnableInterface.h>
 #include <AzFramework/Spawnable/Spawnable.h>
 #include <AzFramework/Spawnable/Spawnable.h>
 #include <AzFramework/Spawnable/SpawnableAssetHandler.h>
 #include <AzFramework/Spawnable/SpawnableAssetHandler.h>
+#include <AzFramework/Spawnable/SpawnableBus.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesContainer.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesContainer.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesManager.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesManager.h>
 
 
@@ -26,6 +27,7 @@ namespace AzFramework
         , public AZ::SystemTickBus::Handler
         , public AZ::SystemTickBus::Handler
         , public RootSpawnableInterface::Registrar
         , public RootSpawnableInterface::Registrar
         , public RootSpawnableNotificationBus::Handler
         , public RootSpawnableNotificationBus::Handler
+        , public SpawnableRequestsBus::Handler
     {
     {
     public:
     public:
         AZ_COMPONENT(SpawnableSystemComponent, "{12D0DA52-BB86-4AC3-8862-9493E0D0E207}");
         AZ_COMPONENT(SpawnableSystemComponent, "{12D0DA52-BB86-4AC3-8862-9493E0D0E207}");
@@ -76,7 +78,20 @@ namespace AzFramework
         void OnRootSpawnableAssigned(AZ::Data::Asset<Spawnable> rootSpawnable, uint32_t generation) override;
         void OnRootSpawnableAssigned(AZ::Data::Asset<Spawnable> rootSpawnable, uint32_t generation) override;
         void OnRootSpawnableReady(AZ::Data::Asset<Spawnable> rootSpawnable, uint32_t generation) override;
         void OnRootSpawnableReady(AZ::Data::Asset<Spawnable> rootSpawnable, uint32_t generation) override;
         void OnRootSpawnableReleased(uint32_t generation) override;
         void OnRootSpawnableReleased(uint32_t generation) override;
-        
+
+        //
+        // SpawnableRequestsBus
+        //
+
+        EntitySpawnTicket CreateSpawnTicket(const SpawnableAssetRef& spawnableAsset) override;
+        bool Spawn(
+            EntitySpawnTicket spawnTicket,
+            AZ::EntityId parentId,
+            AZ::Vector3 translation,
+            AZ::Vector3 rotation,
+            float scale) override;
+        bool Despawn(EntitySpawnTicket spawnTicket) override;
+
     protected:
     protected:
         void Activate() override;
         void Activate() override;
         void Deactivate() override;
         void Deactivate() override;
@@ -90,5 +105,19 @@ namespace AzFramework
 
 
         AZ::Data::AssetId m_rootSpawnableId;
         AZ::Data::AssetId m_rootSpawnableId;
         AZ::SettingsRegistryInterface::NotifyEventHandler m_criticalAssetsHandler;
         AZ::SettingsRegistryInterface::NotifyEventHandler m_criticalAssetsHandler;
+
+    private:
+        struct SpawnableResult
+        {
+            AZStd::vector<AZ::EntityId> m_entityList;
+            EntitySpawnTicket m_spawnTicket;
+        };
+
+        void ProcessSpawnedResults();
+        void ProcessDespawnedResults();
+
+        AZStd::vector<SpawnableResult> m_spawnedResults;
+        AZStd::vector<AzFramework::EntitySpawnTicket> m_despawnedResults;
+        AZStd::recursive_mutex m_mutex;
     };
     };
 } // namespace AzFramework
 } // namespace AzFramework

+ 5 - 0
Code/Framework/AzFramework/AzFramework/azframework_files.cmake

@@ -290,6 +290,9 @@ set(FILES
     Spawnable/SpawnableAssetBus.h
     Spawnable/SpawnableAssetBus.h
     Spawnable/SpawnableAssetHandler.h
     Spawnable/SpawnableAssetHandler.h
     Spawnable/SpawnableAssetHandler.cpp
     Spawnable/SpawnableAssetHandler.cpp
+    Spawnable/SpawnableAssetRef.cpp
+    Spawnable/SpawnableAssetRef.h
+    Spawnable/SpawnableBus.h
     Spawnable/SpawnableEntitiesContainer.h
     Spawnable/SpawnableEntitiesContainer.h
     Spawnable/SpawnableEntitiesContainer.cpp
     Spawnable/SpawnableEntitiesContainer.cpp
     Spawnable/SpawnableEntitiesInterface.h
     Spawnable/SpawnableEntitiesInterface.h
@@ -300,6 +303,8 @@ set(FILES
     Spawnable/SpawnableMetaData.h
     Spawnable/SpawnableMetaData.h
     Spawnable/SpawnableMonitor.h
     Spawnable/SpawnableMonitor.h
     Spawnable/SpawnableMonitor.cpp
     Spawnable/SpawnableMonitor.cpp
+    Spawnable/SpawnableMonitor.cpp
+    Spawnable/SpawnableNotificationsHandler.h
     Spawnable/SpawnableSystemComponent.h
     Spawnable/SpawnableSystemComponent.h
     Spawnable/SpawnableSystemComponent.cpp
     Spawnable/SpawnableSystemComponent.cpp
     SurfaceData/SurfaceData.h
     SurfaceData/SurfaceData.h

+ 1 - 1
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.ScriptCanvasNodeable.xml

@@ -13,7 +13,7 @@
          Description="Creates a spawn ticket using provided prefab">
          Description="Creates a spawn ticket using provided prefab">
 
 
     <Input Name="Create Ticket" OutputName="Ticket Created">
     <Input Name="Create Ticket" OutputName="Ticket Created">
-        <Parameter Name="Prefab" Type="const ScriptCanvas::Nodeables::Spawning::SpawnableAsset&amp;" Description="Prefab source asset to spawn"/>
+        <Parameter Name="Prefab" Type="const AzFramework::SpawnableAssetRef&amp;" Description="Prefab source asset to spawn"/>
         <Return Name="SpawnTicket" Type="AzFramework::EntitySpawnTicket" Shared="true"/>
         <Return Name="SpawnTicket" Type="AzFramework::EntitySpawnTicket" Shared="true"/>
     </Input>
     </Input>
   </Class>
   </Class>

+ 7 - 2
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.cpp

@@ -6,12 +6,17 @@
  *
  *
  */
  */
 
 
+#include <AzFramework/Spawnable/SpawnableBus.h>
 #include <ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h>
 #include <ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h>
 
 
 namespace ScriptCanvas::Nodeables::Spawning
 namespace ScriptCanvas::Nodeables::Spawning
 {
 {
-    AzFramework::EntitySpawnTicket CreateSpawnTicketNodeable::CreateTicket(const SpawnableAsset& Prefab)
+    AzFramework::EntitySpawnTicket CreateSpawnTicketNodeable::CreateTicket(const AzFramework::SpawnableAssetRef& Prefab)
     {
     {
-        return AzFramework::EntitySpawnTicket(Prefab.m_asset);
+        using namespace AzFramework;
+
+        EntitySpawnTicket spawnTicket;
+        SpawnableRequestsBus::BroadcastResult(spawnTicket, &SpawnableRequests::CreateSpawnTicket, Prefab);
+        return spawnTicket;
     }
     }
 }
 }

+ 2 - 2
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h

@@ -8,12 +8,12 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AzFramework/Spawnable/SpawnableAssetRef.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
+#include <Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.generated.h>
 #include <ScriptCanvas/CodeGen/NodeableCodegen.h>
 #include <ScriptCanvas/CodeGen/NodeableCodegen.h>
 #include <ScriptCanvas/Core/Node.h>
 #include <ScriptCanvas/Core/Node.h>
 #include <ScriptCanvas/Core/Nodeable.h>
 #include <ScriptCanvas/Core/Nodeable.h>
-#include <Libraries/Spawning/SpawnableAsset.h>
-#include <Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.generated.h>
 
 
 namespace ScriptCanvas::Nodeables::Spawning
 namespace ScriptCanvas::Nodeables::Spawning
 {
 {

+ 11 - 38
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.cpp

@@ -20,54 +20,27 @@ namespace ScriptCanvas::Nodeables::Spawning
         // this method is required by Script Canvas, left intentionally blank to avoid copying m_despawnedTicketList
         // this method is required by Script Canvas, left intentionally blank to avoid copying m_despawnedTicketList
         return *this;
         return *this;
     }
     }
-
-    void DespawnNodeable::OnInitializeExecutionState()
-    {
-        if (!AZ::TickBus::Handler::BusIsConnected())
-        {
-            AZ::TickBus::Handler::BusConnect();
-        }
-    }
-
+    
     void DespawnNodeable::OnDeactivate()
     void DespawnNodeable::OnDeactivate()
     {
     {
-        AZ::TickBus::Handler::BusDisconnect();
-        m_despawnedTicketList.clear(); // clears any cached SpawnTickets that may remain so everything despawns
-        m_despawnedTicketList.shrink_to_fit();
+        AzFramework::SpawnableNotificationsBus::Handler::BusDisconnect();
     }
     }
 
 
-    void DespawnNodeable::OnTick([[maybe_unused]] float delta, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
+    void DespawnNodeable::OnDespawn(AzFramework::EntitySpawnTicket spawnTicket)
     {
     {
-        AZStd::vector<AzFramework::EntitySpawnTicket> swappedDespawnedTicketList;
-        {
-            AZStd::lock_guard lock(m_mutex);
-            swappedDespawnedTicketList.swap(m_despawnedTicketList);
-        }
-
-        for (const auto& spawnTicket : swappedDespawnedTicketList)
-        {
-            CallOnDespawn(spawnTicket);
-        }
+        AzFramework::SpawnableNotificationsBus::Handler::BusDisconnect(spawnTicket.GetId());
+        CallOnDespawn(spawnTicket);
     }
     }
 
 
     void DespawnNodeable::RequestDespawn(AzFramework::EntitySpawnTicket spawnTicket)
     void DespawnNodeable::RequestDespawn(AzFramework::EntitySpawnTicket spawnTicket)
     {
     {
-        if (!spawnTicket.IsValid())
-        {
-            AZ_Error("DespawnNodeable", false, "EntitySpawnTicket used for despawning is invalid (make sure the slot is connected).")
-            return;
-        }
+        using namespace AzFramework;
 
 
-        auto despawnCompleteCB = [this, spawnTicket]([[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId)
+        bool result = false;
+        SpawnableRequestsBus::BroadcastResult(result, &SpawnableRequests::Despawn, spawnTicket);
+        if (result)
         {
         {
-            AZStd::lock_guard lock(m_mutex);
-            // SpawnTicket instance is cached instead of SpawnTicketId to simplify managing its lifecycle on Script Canvas
-            // and to provide easier access to it in OnDespawn callback
-            m_despawnedTicketList.push_back(spawnTicket);
-        };
-
-        AzFramework::DespawnAllEntitiesOptionalArgs optionalArgs;
-        optionalArgs.m_completionCallback = AZStd::move(despawnCompleteCB);
-        AzFramework::SpawnableEntitiesInterface::Get()->DespawnAllEntities(spawnTicket, AZStd::move(optionalArgs));
+            SpawnableNotificationsBus::Handler::BusConnect(spawnTicket.GetId());
+        }
     }
     }
 } // namespace ScriptCanvas::Nodeables::Spawning
 } // namespace ScriptCanvas::Nodeables::Spawning

+ 6 - 10
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.h

@@ -9,18 +9,19 @@
 #pragma once
 #pragma once
 
 
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Component/TickBus.h>
+#include <AzFramework/Spawnable/SpawnableBus.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
+#include <Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.generated.h>
 #include <ScriptCanvas/CodeGen/NodeableCodegen.h>
 #include <ScriptCanvas/CodeGen/NodeableCodegen.h>
 #include <ScriptCanvas/Core/Node.h>
 #include <ScriptCanvas/Core/Node.h>
 #include <ScriptCanvas/Core/Nodeable.h>
 #include <ScriptCanvas/Core/Nodeable.h>
-#include <Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.generated.h>
 
 
 namespace ScriptCanvas::Nodeables::Spawning
 namespace ScriptCanvas::Nodeables::Spawning
 {
 {
     //! Node for despawning entities
     //! Node for despawning entities
     class DespawnNodeable
     class DespawnNodeable
-        : public ScriptCanvas::Nodeable
-        , public AZ::TickBus::Handler
+        : public Nodeable
+        , public AzFramework::SpawnableNotificationsBus::Handler
     {
     {
         SCRIPTCANVAS_NODE(DespawnNodeable);
         SCRIPTCANVAS_NODE(DespawnNodeable);
     public:
     public:
@@ -29,14 +30,9 @@ namespace ScriptCanvas::Nodeables::Spawning
         DespawnNodeable& operator=(const DespawnNodeable& rhs);
         DespawnNodeable& operator=(const DespawnNodeable& rhs);
 
 
         // ScriptCanvas::Nodeable  overrides ...
         // ScriptCanvas::Nodeable  overrides ...
-        void OnInitializeExecutionState() override;
         void OnDeactivate() override;
         void OnDeactivate() override;
 
 
-        // AZ::TickBus::Handler overrides ...
-        void OnTick(float delta, AZ::ScriptTimePoint timePoint) override;
-        
-    private:
-        AZStd::vector<AzFramework::EntitySpawnTicket> m_despawnedTicketList;
-        AZStd::recursive_mutex m_mutex;
+        // AzFramework::SpawnableNotificationsBus::Handler overrides ...
+        void OnDespawn(AzFramework::EntitySpawnTicket spawnTicket) override;
     };
     };
 }
 }

+ 13 - 75
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp

@@ -21,40 +21,18 @@ namespace ScriptCanvas::Nodeables::Spawning
         // this method is required by Script Canvas, left intentionally blank to avoid copying m_completionResults
         // this method is required by Script Canvas, left intentionally blank to avoid copying m_completionResults
         return *this;
         return *this;
     }
     }
-
-    void SpawnNodeable::OnInitializeExecutionState()
-    {
-        if (!AZ::TickBus::Handler::BusIsConnected())
-        {
-            AZ::TickBus::Handler::BusConnect();
-        }
-    }
-
+    
     void SpawnNodeable::OnDeactivate()
     void SpawnNodeable::OnDeactivate()
     {
     {
-        AZ::TickBus::Handler::BusDisconnect();
-        m_completionResults.clear(); // clears any cached SpawnTickets that may remain so everything despawns
-        m_completionResults.shrink_to_fit();
+        AzFramework::SpawnableNotificationsBus::Handler::BusDisconnect();
     }
     }
 
 
-    void SpawnNodeable::OnTick([[maybe_unused]] float delta, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
+    void SpawnNodeable::OnSpawn(AzFramework::EntitySpawnTicket spawnTicket, AZStd::vector<AZ::EntityId> entityList)
     {
     {
-        AZStd::vector<SpawnableResult> swappedCompletionResults;
-        {
-            AZStd::lock_guard lock(m_mutex);
-            swappedCompletionResults.swap(m_completionResults);
-        }
-
-        for (const auto& spawnResult : swappedCompletionResults)
-        {
-            if (spawnResult.m_entityList.empty())
-            {
-                continue;
-            }
-            CallOnSpawnCompleted(spawnResult.m_spawnTicket, move(spawnResult.m_entityList));
-        }
+        AzFramework::SpawnableNotificationsBus::Handler::BusDisconnect(spawnTicket.GetId());
+        CallOnSpawnCompleted(spawnTicket, move(entityList));
     }
     }
-
+    
     void SpawnNodeable::RequestSpawn(
     void SpawnNodeable::RequestSpawn(
         AzFramework::EntitySpawnTicket spawnTicket,
         AzFramework::EntitySpawnTicket spawnTicket,
         AZ::EntityId parentId,
         AZ::EntityId parentId,
@@ -62,54 +40,14 @@ namespace ScriptCanvas::Nodeables::Spawning
         Data::Vector3Type rotation,
         Data::Vector3Type rotation,
         Data::NumberType scale)
         Data::NumberType scale)
     {
     {
-        if (!spawnTicket.IsValid())
-        {
-            AZ_Error("SpawnNodeable", false, "EntitySpawnTicket used for despawning is invalid (make sure the slot is connected).")
-            return;
-        }
+        using namespace AzFramework;
 
 
-        auto preSpawnCB = [this, parentId, translation, rotation, scale](
-            [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId,
-            AzFramework::SpawnableEntityContainerView view)
+        bool result = false;
+        SpawnableRequestsBus::BroadcastResult(result, &SpawnableRequests::Spawn,
+            spawnTicket, parentId, translation, rotation, aznumeric_cast<float>(scale));
+        if (result)
         {
         {
-            AZStd::lock_guard lock(m_mutex);
-
-            AZ::Entity* rootEntity = *view.begin();
-            AzFramework::TransformComponent* entityTransform = rootEntity->FindComponent<AzFramework::TransformComponent>();
-
-            if (entityTransform)
-            {
-                AZ::Vector3 rotationCopy = rotation;
-                AZ::Quaternion rotationQuat = AZ::Quaternion::CreateFromEulerAnglesDegrees(rotationCopy);
-
-                AzFramework::TransformComponentConfiguration transformConfig;
-                transformConfig.m_parentId = parentId;
-                transformConfig.m_localTransform = AZ::Transform(translation, rotationQuat, aznumeric_cast<float>(scale));
-                entityTransform->SetConfiguration(transformConfig);
-            }
-        };
-
-        auto spawnCompleteCB = [this, spawnTicket](
-            [[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId,
-            AzFramework::SpawnableConstEntityContainerView view)
-        {
-            AZStd::lock_guard lock(m_mutex);
-
-            SpawnableResult spawnableResult;
-            // SpawnTicket instance is cached instead of SpawnTicketId to simplify managing its lifecycle on Script Canvas
-            // and to provide easier access to it in OnSpawnCompleted callback
-            spawnableResult.m_spawnTicket = spawnTicket;
-            spawnableResult.m_entityList.reserve(view.size());
-            for (const AZ::Entity* entity : view)
-            {
-                spawnableResult.m_entityList.emplace_back(entity->GetId());
-            }
-            m_completionResults.push_back(spawnableResult);
-        };
-
-        AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
-        optionalArgs.m_preInsertionCallback = AZStd::move(preSpawnCB);
-        optionalArgs.m_completionCallback = AZStd::move(spawnCompleteCB);
-        AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(spawnTicket, AZStd::move(optionalArgs));
+            SpawnableNotificationsBus::Handler::BusConnect(spawnTicket.GetId());
+        }
     }
     }
 } // namespace ScriptCanvas::Nodeables::Spawning
 } // namespace ScriptCanvas::Nodeables::Spawning

+ 5 - 15
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.h

@@ -9,18 +9,19 @@
 #pragma once
 #pragma once
 
 
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Component/TickBus.h>
+#include <AzFramework/Spawnable/SpawnableBus.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
+#include <Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.generated.h>
 #include <ScriptCanvas/CodeGen/NodeableCodegen.h>
 #include <ScriptCanvas/CodeGen/NodeableCodegen.h>
 #include <ScriptCanvas/Core/Node.h>
 #include <ScriptCanvas/Core/Node.h>
 #include <ScriptCanvas/Core/Nodeable.h>
 #include <ScriptCanvas/Core/Nodeable.h>
-#include <Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.generated.h>
 
 
 namespace ScriptCanvas::Nodeables::Spawning
 namespace ScriptCanvas::Nodeables::Spawning
 {
 {
     //! Node for spawning entities
     //! Node for spawning entities
     class SpawnNodeable
     class SpawnNodeable
         : public Nodeable
         : public Nodeable
-        , public AZ::TickBus::Handler
+        , public AzFramework::SpawnableNotificationsBus::Handler
     {
     {
         SCRIPTCANVAS_NODE(SpawnNodeable);
         SCRIPTCANVAS_NODE(SpawnNodeable);
     public:
     public:
@@ -29,20 +30,9 @@ namespace ScriptCanvas::Nodeables::Spawning
         SpawnNodeable& operator=(const SpawnNodeable& rhs);
         SpawnNodeable& operator=(const SpawnNodeable& rhs);
 
 
         // ScriptCanvas::Nodeable  overrides ...
         // ScriptCanvas::Nodeable  overrides ...
-        void OnInitializeExecutionState() override;
         void OnDeactivate() override;
         void OnDeactivate() override;
 
 
-        // AZ::TickBus::Handler overrides ...
-        void OnTick(float delta, AZ::ScriptTimePoint timePoint) override;
-        
-    private:
-        struct SpawnableResult
-        {
-            AZStd::vector<Data::EntityIDType> m_entityList;
-            AzFramework::EntitySpawnTicket m_spawnTicket;
-        };
-        
-        AZStd::vector<SpawnableResult> m_completionResults;
-        AZStd::recursive_mutex m_mutex;
+        // AzFramework::SpawnableNotificationsBus::Handler overrides ...
+        void OnSpawn(AzFramework::EntitySpawnTicket spawnTicket, AZStd::vector<AZ::EntityId> entityList) override;
     };
     };
 }
 }

+ 0 - 116
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnableAsset.cpp

@@ -1,116 +0,0 @@
-/*
- * 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.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/RTTI/BehaviorContext.h>
-#include <AzCore/Serialization/SerializeContext.h>
-#include <AzCore/Serialization/EditContext.h>
-#include <AzFramework/StringFunc/StringFunc.h>
-#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
-#include <ScriptCanvas/Libraries/Core/ContainerTypeReflection.h>
-#include <ScriptCanvas/Libraries/Spawning/SpawnableAsset.h>
-
-namespace ScriptCanvas::Nodeables::Spawning
-{
-    void SpawnableAsset::Reflect(AZ::ReflectContext* context)
-    {
-        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
-        {
-            serializeContext
-                ->Class<SpawnableAsset>()
-                ->Field("Asset", &SpawnableAsset::m_asset);
-
-            serializeContext->RegisterGenericType<AZStd::vector<SpawnableAsset>>();
-            serializeContext->RegisterGenericType<AZStd::unordered_map<Data::StringType, SpawnableAsset>>();
-            serializeContext->RegisterGenericType<AZStd::unordered_map<Data::NumberType, SpawnableAsset>>();
-
-            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
-            {
-                editContext
-                    ->Class<SpawnableAsset>("SpawnableAsset", "A wrapper around spawnable asset to be used as a variable in Script Canvas.")
-                    // m_asset
-                    ->DataElement(AZ::Edit::UIHandlers::Default, &SpawnableAsset::m_asset, "m_asset", "")
-                    ->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, false)
-                    ->Attribute(AZ::Edit::Attributes::HideProductFilesInAssetPicker, true)
-                    ->Attribute(AZ::Edit::Attributes::AssetPickerTitle, "Spawnable Asset")
-                    ->Attribute(AZ::Edit::Attributes::ChangeNotify, &SpawnableAsset::OnSpawnAssetChanged);
-            }
-        }
-
-        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
-        {
-            behaviorContext
-                ->Class<SpawnableAsset>("SpawnableAsset")
-                ->Constructor()
-                ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
-                ->Attribute(AZ::Script::Attributes::Category, "Spawning")
-                ->Attribute(AZ::Script::Attributes::Module, "Spawning")
-                ->Property("m_asset", BehaviorValueProperty(&SpawnableAsset::m_asset));
-
-            behaviorContext->Class<ContainerTypeReflection::BehaviorClassReflection<SpawnableAsset>>("ReflectOnDemandTargets_SpawnableAsset")
-                ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
-                ->Attribute(AZ::Script::Attributes::Ignore, true)
-                // required to support Array<SpawnableAsset> variable type in Script Canvas
-                ->Method(
-                    "ReflectVector",
-                    [](const AZStd::vector<SpawnableAsset>&)
-                    {
-                    })
-                // required to support Map<String, SpawnableAsset> variable type in Script Canvas
-                ->Method(
-                    "MapStringToSpawnableAsset",
-                    [](const AZStd::unordered_map<Data::StringType, SpawnableAsset>&)
-                    {
-                    })
-                // required to support Map<Number, SpawnableAsset> variable type in Script Canvas
-                ->Method(
-                    "MapNumberToSpawnableAsset",
-                    [](const AZStd::unordered_map<Data::NumberType, SpawnableAsset>&)
-                    {
-                    });
-        }
-
-        ContainerTypeReflection::HashContainerReflector<SpawnableAsset>::Reflect(context);
-    }
-
-    SpawnableAsset::SpawnableAsset(const SpawnableAsset& rhs)
-        : m_asset(rhs.m_asset)
-    {
-    }
-
-    SpawnableAsset& SpawnableAsset::operator=(const SpawnableAsset& rhs)
-    {
-        m_asset = rhs.m_asset;
-        return *this;
-    }
-
-    void SpawnableAsset::OnSpawnAssetChanged()
-    {
-        if (m_asset.GetId().IsValid())
-        {
-            AZStd::string rootSpawnableFile;
-            AzFramework::StringFunc::Path::GetFileName(m_asset.GetHint().c_str(), rootSpawnableFile);
-
-            rootSpawnableFile += AzFramework::Spawnable::DotFileExtension;
-
-            AZ::u32 rootSubId = AzFramework::SpawnableAssetHandler::BuildSubId(move(rootSpawnableFile));
-
-            if (m_asset.GetId().m_subId != rootSubId)
-            {
-                AZ::Data::AssetId rootAssetId = m_asset.GetId();
-                rootAssetId.m_subId = rootSubId;
-
-                m_asset = AZ::Data::AssetManager::Instance().FindOrCreateAsset<AzFramework::Spawnable>(
-                    rootAssetId, AZ::Data::AssetLoadBehavior::Default);
-            }
-            else
-            {
-                m_asset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::Default);
-            }
-        }
-    }
-}

+ 34 - 9
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/Spawning.cpp

@@ -6,10 +6,11 @@
  *
  *
  */
  */
 
 
+#include <AzFramework/Spawnable/SpawnableAssetRef.h>
+#include <AzFramework/Spawnable/SpawnableEntitiesInterface.cpp>
 #include <ScriptCanvas/Libraries/Libraries.h>
 #include <ScriptCanvas/Libraries/Libraries.h>
-#include <ScriptCanvas/Libraries/Spawning/Spawning.h>
 #include <ScriptCanvas/Libraries/Core/ContainerTypeReflection.h>
 #include <ScriptCanvas/Libraries/Core/ContainerTypeReflection.h>
-#include <AzFramework/Spawnable/SpawnableEntitiesInterface.cpp>
+#include <ScriptCanvas/Libraries/Spawning/Spawning.h>
 
 
 namespace ScriptCanvas
 namespace ScriptCanvas
 {
 {
@@ -19,19 +20,15 @@ namespace ScriptCanvas
         {
         {
             using namespace AzFramework;
             using namespace AzFramework;
             using namespace ContainerTypeReflection;
             using namespace ContainerTypeReflection;
-
-            Nodeables::Spawning::SpawnableAsset::Reflect(reflection);
-
+            
             if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
             if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
             {
             {
                 serializeContext->Class<Spawning, LibraryDefinition>()
                 serializeContext->Class<Spawning, LibraryDefinition>()
                     ->Version(1)
                     ->Version(1)
                     ;
                     ;
 
 
-                CreateTypeAsMapValueHelper<Data::StringType, EntitySpawnTicket>::ReflectClassInfo(serializeContext);
-                CreateTypeAsMapValueHelper<Data::NumberType, EntitySpawnTicket>::ReflectClassInfo(serializeContext);
-
-                serializeContext->RegisterGenericType<AZStd::vector<EntitySpawnTicket>>();
+                //CreateTypeAsMapValueHelper<Data::StringType, EntitySpawnTicket>::ReflectClassInfo(serializeContext);
+                //CreateTypeAsMapValueHelper<Data::NumberType, EntitySpawnTicket>::ReflectClassInfo(serializeContext);
                 serializeContext->RegisterGenericType<AZStd::unordered_map<Data::StringType, EntitySpawnTicket>>();
                 serializeContext->RegisterGenericType<AZStd::unordered_map<Data::StringType, EntitySpawnTicket>>();
                 serializeContext->RegisterGenericType<AZStd::unordered_map<Data::NumberType, EntitySpawnTicket>>();
                 serializeContext->RegisterGenericType<AZStd::unordered_map<Data::NumberType, EntitySpawnTicket>>();
 
 
@@ -46,6 +43,8 @@ namespace ScriptCanvas
 
 
             if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection))
             if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection))
             {
             {
+                // reflecting EntitySpawnTicket to support Map<string, EntitySpawnTicket> and Map<Number, EntitySpawnTicket>
+                // as Script Canvas variable types
                 behaviorContext->Class<BehaviorClassReflection<EntitySpawnTicket>>("ReflectOnDemandTargets_EntitySpawnTicket")
                 behaviorContext->Class<BehaviorClassReflection<EntitySpawnTicket>>("ReflectOnDemandTargets_EntitySpawnTicket")
                     ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
                     ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
                     ->Attribute(AZ::Script::Attributes::Ignore, true)
                     ->Attribute(AZ::Script::Attributes::Ignore, true)
@@ -67,9 +66,35 @@ namespace ScriptCanvas
                         [](const AZStd::unordered_map<Data::NumberType, EntitySpawnTicket>&)
                         [](const AZStd::unordered_map<Data::NumberType, EntitySpawnTicket>&)
                         {
                         {
                         });
                         });
+
+                // reflecting SpawnableAssetRef to support Map<string, SpawnableAssetRef> and Map<Number, SpawnableAssetRef>
+                // as Script Canvas variable types
+                behaviorContext
+                    ->Class<BehaviorClassReflection<SpawnableAssetRef>>("ReflectOnDemandTargets_SpawnableAssetRef")
+                    ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
+                    ->Attribute(AZ::Script::Attributes::Ignore, true)
+                    // required to support Array<SpawnableAssetRef> variable type in Script Canvas
+                    ->Method(
+                        "ReflectVector",
+                        [](const AZStd::vector<SpawnableAssetRef>&)
+                        {
+                        })
+                    // required to support Map<String, SpawnableAssetRef> variable type in Script Canvas
+                    ->Method(
+                        "MapStringToSpawnableAssetRef",
+                        [](const AZStd::unordered_map<Data::StringType, SpawnableAssetRef>&)
+                        {
+                        })
+                    // required to support Map<Number, SpawnableAssetRef> variable type in Script Canvas
+                    ->Method(
+                        "MapNumberToSpawnableAssetRef",
+                        [](const AZStd::unordered_map<Data::NumberType, SpawnableAssetRef>&)
+                        {
+                        });
             }
             }
 
 
             HashContainerReflector<EntitySpawnTicket>::Reflect(reflection);
             HashContainerReflector<EntitySpawnTicket>::Reflect(reflection);
+            HashContainerReflector<SpawnableAssetRef>::Reflect(reflection);
         }
         }
 
 
         void Spawning::InitNodeRegistry(NodeRegistry& nodeRegistry)
         void Spawning::InitNodeRegistry(NodeRegistry& nodeRegistry)

+ 0 - 1
Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/Spawning.h

@@ -10,7 +10,6 @@
 
 
 // This header is only meant to include the nodes and should not contain
 // This header is only meant to include the nodes and should not contain
 // shared code
 // shared code
-#include <ScriptCanvas/Libraries/Spawning/SpawnableAsset.h>
 #include <ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h>
 #include <ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h>
 #include <ScriptCanvas/Libraries/Spawning/SpawnNodeable.h>
 #include <ScriptCanvas/Libraries/Spawning/SpawnNodeable.h>
 #include <ScriptCanvas/Libraries/Spawning/DespawnNodeable.h>
 #include <ScriptCanvas/Libraries/Spawning/DespawnNodeable.h>

+ 0 - 1
Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake

@@ -141,7 +141,6 @@ set(FILES
     Include/ScriptCanvas/Libraries/Time/HeartBeatNodeable.cpp
     Include/ScriptCanvas/Libraries/Time/HeartBeatNodeable.cpp
     Include/ScriptCanvas/Libraries/Time/TimerNodeable.cpp
     Include/ScriptCanvas/Libraries/Time/TimerNodeable.cpp
     Include/ScriptCanvas/Libraries/Spawning/Spawning.cpp
     Include/ScriptCanvas/Libraries/Spawning/Spawning.cpp
-    Include/ScriptCanvas/Libraries/Spawning/SpawnableAsset.cpp
     Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.cpp
     Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.cpp
     Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp
     Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp
     Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.cpp
     Include/ScriptCanvas/Libraries/Spawning/DespawnNodeable.cpp

+ 0 - 1
Gems/ScriptCanvas/Code/scriptcanvasgem_headers.cmake

@@ -253,7 +253,6 @@ set(FILES
     Include/ScriptCanvas/Libraries/Time/TimerNodeable.h
     Include/ScriptCanvas/Libraries/Time/TimerNodeable.h
     Include/ScriptCanvas/Libraries/Time/TimerNodeable.ScriptCanvasNodeable.xml
     Include/ScriptCanvas/Libraries/Time/TimerNodeable.ScriptCanvasNodeable.xml
     Include/ScriptCanvas/Libraries/Spawning/Spawning.h
     Include/ScriptCanvas/Libraries/Spawning/Spawning.h
-    Include/ScriptCanvas/Libraries/Spawning/SpawnableAsset.h
     Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h
     Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.h
     Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.ScriptCanvasNodeable.xml
     Include/ScriptCanvas/Libraries/Spawning/CreateSpawnTicketNodeable.ScriptCanvasNodeable.xml
     Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.h
     Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.h