From 895974db57cc6472baf94d7254f7acca23384fc4 Mon Sep 17 00:00:00 2001 From: pereslav Date: Tue, 21 Sep 2021 14:50:06 +0100 Subject: [PATCH] Removed spawn/despawn events from the spawnable system. Used NetworkSpawnableHolderComponent instead Signed-off-by: pereslav --- .../Spawnable/SpawnableEntitiesInterface.h | 9 --- .../Spawnable/SpawnableEntitiesManager.cpp | 20 ----- .../Spawnable/SpawnableEntitiesManager.h | 6 -- .../Mocks/MockSpawnableEntitiesInterface.h | 2 - .../NetworkEntity/INetworkEntityManager.h | 10 +++ .../NetworkEntity/NetworkEntityManager.cpp | 78 +------------------ .../NetworkEntity/NetworkEntityManager.h | 18 +---- .../NetworkSpawnableHolderComponent.cpp | 24 ++++++ .../NetworkSpawnableHolderComponent.h | 2 + 9 files changed, 43 insertions(+), 126 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h index 254df8f1b0..4b09dcbc75 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h @@ -320,15 +320,6 @@ namespace AzFramework //! @param optionalArgs Optional additional arguments, see BarrierOptionalArgs. virtual void Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) = 0; - //! Register a handler for OnSpawned events. - //! @param handler The handler to receive the event. - virtual void AddOnSpawnedHandler(AZ::Event, - const AZStd::vector&, const void*>::Handler& handler) = 0; - - //! Register a handler for OnDespawned events. - //! @param handler The handler to receive the event. - virtual void AddOnDespawnedHandler(AZ::Event, const void*>::Handler& handler) = 0; - protected: [[nodiscard]] virtual AZStd::pair CreateTicket(AZ::Data::Asset&& spawnable) = 0; virtual void DestroyTicket(void* ticket) = 0; diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp index f052f83224..5fa072a451 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp @@ -146,16 +146,6 @@ namespace AzFramework QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } - void SpawnableEntitiesManager::AddOnSpawnedHandler(AZ::Event, const AZStd::vector&, const void*>::Handler& handler) - { - handler.Connect(m_onSpawnedEvent); - } - - void SpawnableEntitiesManager::AddOnDespawnedHandler(AZ::Event, const void*>::Handler& handler) - { - handler.Connect(m_onDespawnedEvent); - } - auto SpawnableEntitiesManager::ProcessQueue(CommandQueuePriority priority) -> CommandQueueStatus { CommandQueueStatus result = CommandQueueStatus::NoCommandsLeft; @@ -359,8 +349,6 @@ namespace AzFramework ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end())); } - m_onSpawnedEvent.Signal(ticket.m_spawnable, ticket.m_spawnedEntities, &ticket); - ticket.m_currentRequestId++; return true; } @@ -441,8 +429,6 @@ namespace AzFramework ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end())); } - m_onSpawnedEvent.Signal(ticket.m_spawnable, ticket.m_spawnedEntities, &ticket); - ticket.m_currentRequestId++; return true; } @@ -474,8 +460,6 @@ namespace AzFramework request.m_completionCallback(request.m_ticketId); } - m_onDespawnedEvent.Signal(ticket.m_spawnable, &ticket); - ticket.m_currentRequestId++; return true; } @@ -503,8 +487,6 @@ namespace AzFramework } } - m_onDespawnedEvent.Signal(ticket.m_spawnable, &ticket); - // Rebuild the list of entities. ticket.m_spawnedEntities.clear(); const Spawnable::EntityList& entities = request.m_spawnable->GetEntities(); @@ -562,8 +544,6 @@ namespace AzFramework ticket.m_spawnedEntities.begin(), ticket.m_spawnedEntities.end())); } - m_onSpawnedEvent.Signal(ticket.m_spawnable, ticket.m_spawnedEntities, &ticket); - ticket.m_currentRequestId++; return true; diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h index c78b1778a4..69985f8aa9 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h @@ -69,9 +69,6 @@ namespace AzFramework void Barrier(EntitySpawnTicket& spawnInfo, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) override; - void AddOnSpawnedHandler(AZ::Event, const AZStd::vector&, const void*>::Handler& handler) override; - void AddOnDespawnedHandler(AZ::Event, const void*>::Handler& handler) override; - // // The following function is thread safe but intended to be run from the main thread. // @@ -227,9 +224,6 @@ namespace AzFramework //! SpawnablePriority_Default which gives users a bit of room to fine tune the priorities as this value can be configured //! through the Settings Registry under the key "/O3DE/AzFramework/Spawnables/HighPriorityThreshold". SpawnablePriority m_highPriorityThreshold { 64 }; - - AZ::Event, const AZStd::vector&, const void*> m_onSpawnedEvent; - AZ::Event, const void*> m_onDespawnedEvent; }; AZ_DEFINE_ENUM_BITWISE_OPERATORS(AzFramework::SpawnableEntitiesManager::CommandQueuePriority); diff --git a/Code/Framework/AzFramework/Tests/Mocks/MockSpawnableEntitiesInterface.h b/Code/Framework/AzFramework/Tests/Mocks/MockSpawnableEntitiesInterface.h index 89e79ecf9b..a5df7af4c3 100644 --- a/Code/Framework/AzFramework/Tests/Mocks/MockSpawnableEntitiesInterface.h +++ b/Code/Framework/AzFramework/Tests/Mocks/MockSpawnableEntitiesInterface.h @@ -59,8 +59,6 @@ namespace AzFramework MOCK_METHOD1(CreateTicket, AZStd::pair(AZ::Data::Asset&& spawnable)); MOCK_METHOD1(DestroyTicket, void(void* ticket)); - MOCK_METHOD1(AddOnSpawnedHandler, void(AZ::Event, const AZStd::vector&, const void*>::Handler& handler)); - MOCK_METHOD1(AddOnDespawnedHandler, void(AZ::Event, const void*>::Handler& handler)); /** Installs some default result values for the above functions. * Note that you can always override these in scope of your test by adding additional ON_CALL / EXPECT_CALL diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h index 8a5fec869c..5bcf038eff 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace Multiplayer { @@ -75,6 +76,15 @@ namespace Multiplayer const AZ::Transform& transform ) = 0; + //! Requests a network spawnable to instantiate at a given transform + //! This is an async function. The instantiated entities are not available immediately but will be constructed by the spawnable system + //! The spawnable ticket has to be kept for the whole lifetime of the entities + //! @param netSpawnable the network spawnable to spawn + //! @param transform the transform where the spawnable should be spawned + //! @return the ticket for managing the spawned entities + [[nodiscard]] virtual AZStd::unique_ptr RequestNetSpawnableInstantiation( + const AZ::Data::Asset& netSpawnable, const AZ::Transform& transform) = 0; + //! Configures new networked entity //! @param netEntity the entity to setup //! @param prefabEntryId the name of the spawnable the entity originated from diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index 61fd741dc6..f4f744494b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -30,14 +30,9 @@ namespace Multiplayer : m_networkEntityAuthorityTracker(*this) , m_removeEntitiesEvent([this] { RemoveEntities(); }, AZ::Name("NetworkEntityManager remove entities event")) , m_updateEntityDomainEvent([this] { UpdateEntityDomain(); }, AZ::Name("NetworkEntityManager update entity domain event")) - , m_onSpawnedHandler([this](AZ::Data::Asset spawnable, const AZStd::vector& entities, const void* spawnTicket) { this->OnSpawned(spawnable, entities, spawnTicket); }) - , m_onDespawnedHandler([this](AZ::Data::Asset spawnable, const void* spawnTicket) { this->OnDespawned(spawnable, spawnTicket); }) { AZ::Interface::Register(this); AzFramework::RootSpawnableNotificationBus::Handler::BusConnect(); - - AzFramework::SpawnableEntitiesInterface::Get()->AddOnSpawnedHandler(m_onSpawnedHandler); - AzFramework::SpawnableEntitiesInterface::Get()->AddOnDespawnedHandler(m_onDespawnedHandler); } NetworkEntityManager::~NetworkEntityManager() @@ -473,52 +468,17 @@ namespace Multiplayer } AZStd::unique_ptr NetworkEntityManager::RequestNetSpawnableInstantiation( - const AZ::Data::Asset& rootSpawnable, const AZStd::vector& entities) + const AZ::Data::Asset& netSpawnable, const AZ::Transform& transform) { - if (entities.empty()) - { - AZ_Error("NetworkEntityManager", false, - "RequestNetSpawnableInstantiation: No entities in the spawnable %s", rootSpawnable.GetHint().c_str()); - return nullptr; - } - - // The first entity in every spawnable is the root one - const AZ::Entity* rootEntity = *entities.begin(); - if (!rootEntity) - { - AZ_Error("NetworkEntityManager", false, - "RequestNetSpawnableInstantiation: Root entity is null in the spawnable %s", rootSpawnable.GetHint().c_str()); - return nullptr; - } - - const auto* holderComponent = rootEntity->FindComponent(); - if (!holderComponent) - { - // This spawnable doesn't have a corresponding network spawnable. - return nullptr; - } - - AzFramework::TransformComponent* rootEntityTransform = - rootEntity->FindComponent(); - if (!rootEntityTransform) - { - AZ_Error("NetworkEntityManager", false, - "RequestNetSpawnableInstantiation: Root entity has no transform in the spawnable %s", rootSpawnable.GetHint().c_str()); - return nullptr; - } - - // Retrieve the corresponding network spawnable asset - AZ::Data::Asset netSpawnableAsset = holderComponent->GetNetworkSpawnableAsset(); - // Prepare the parameters for the spawning process AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; optionalArgs.m_priority = AzFramework::SpawnablePriority_High; const AZ::Name netSpawnableName = - AZ::Interface::Get()->GetSpawnableNameFromAssetId(netSpawnableAsset.GetId()); + AZ::Interface::Get()->GetSpawnableNameFromAssetId(netSpawnable.GetId()); // Pre-insertion callback allows us to do network-specific setup for the entities before they are added to the scene - optionalArgs.m_preInsertionCallback = [netSpawnableName, rootTransform = rootEntityTransform->GetWorldTM()] + optionalArgs.m_preInsertionCallback = [netSpawnableName, rootTransform = transform] (AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView entities) { bool shouldUpdateTransform = (rootTransform.IsClose(AZ::Transform::Identity()) == false); @@ -546,7 +506,7 @@ namespace Multiplayer }; // Spawn with the newly created ticket. This allows the calling code to manage the lifetime of the constructed entities - auto ticket = AZStd::make_unique(netSpawnableAsset); + auto ticket = AZStd::make_unique(netSpawnable); AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*ticket, AZStd::move(optionalArgs)); return ticket; } @@ -572,28 +532,6 @@ namespace Multiplayer { multiplayer->SendReadyForEntityUpdates(false); } - - m_netSpawnableTickets.clear(); - } - - void NetworkEntityManager::OnSpawned(AZ::Data::Asset spawnable, - const AZStd::vector& entities, const void* spawnTicket) - { - if (ShouldSpawnNetEntities()) - { - AZStd::unique_ptr ticket = RequestNetSpawnableInstantiation(spawnable, entities); - if (ticket) - { - AZ::Data::AssetId spawnableAssetId = spawnable.GetId(); - m_netSpawnableTickets[spawnTicket] = AZStd::move(ticket); - } - } - } - - void NetworkEntityManager::OnDespawned([[maybe_unused]] AZ::Data::Asset spawnable, - const void* spawnTicket) - { - m_netSpawnableTickets.erase(spawnTicket); } void NetworkEntityManager::SetupNetEntity(AZ::Entity* netEntity, PrefabEntityId prefabEntityId, NetEntityRole netEntityRole) @@ -611,12 +549,4 @@ namespace Multiplayer netEntity->GetName().c_str()); } } - - bool NetworkEntityManager::ShouldSpawnNetEntities() const - { - const auto agentType = GetMultiplayer()->GetAgentType(); - const bool shouldSpawnNetEntities = - (agentType == MultiplayerAgentType::ClientServer || agentType == MultiplayerAgentType::DedicatedServer); - return shouldSpawnNetEntities; - } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index 14efa4feeb..50e6beedad 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -61,6 +60,9 @@ namespace Multiplayer const AZ::Transform& transform ) override; + AZStd::unique_ptr RequestNetSpawnableInstantiation( + const AZ::Data::Asset& netSpawnable, const AZ::Transform& transform) override; + void SetupNetEntity(AZ::Entity* netEntity, PrefabEntityId prefabEntityId, NetEntityRole netEntityRole) override; uint32_t GetEntityCount() const override; @@ -93,15 +95,6 @@ namespace Multiplayer private: void RemoveEntities(); NetEntityId NextId(); - bool ShouldSpawnNetEntities() const; - void OnSpawned(AZ::Data::Asset spawnable, - const AZStd::vector& entities, const void* spawnTicket); - void OnDespawned(AZ::Data::Asset spawnable, const void* spawnTicket); - - // Note: This is an async function. - // The instantiated entities are not available immediately but will be constructed by the spawnable system - AZStd::unique_ptr RequestNetSpawnableInstantiation( - const AZ::Data::Asset& rootSpawnable, const AZStd::vector& entities); NetworkEntityTracker m_networkEntityTracker; NetworkEntityAuthorityTracker m_networkEntityAuthorityTracker; @@ -130,10 +123,5 @@ namespace Multiplayer DeferredRpcMessages m_localDeferredRpcMessages; NetworkSpawnableLibrary m_networkPrefabLibrary; - - AZStd::unordered_map> m_netSpawnableTickets; - - AZ::Event, const AZStd::vector&, const void*>::Handler m_onSpawnedHandler; - AZ::Event, const void*>::Handler m_onDespawnedHandler; }; } diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp index e83f6fea84..d33c3274c2 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include namespace Multiplayer { @@ -28,10 +30,32 @@ namespace Multiplayer void NetworkSpawnableHolderComponent::Activate() { + const auto agentType = GetMultiplayer()->GetAgentType(); + const bool shouldSpawnNetEntities = + (agentType == MultiplayerAgentType::ClientServer || agentType == MultiplayerAgentType::DedicatedServer); + + if(shouldSpawnNetEntities) + { + AZ::Transform rootEntityTransform = AZ::Transform::CreateIdentity(); + + AzFramework::TransformComponent* rootEntityTransformComponent = + GetEntity()->FindComponent(); + if (rootEntityTransformComponent) + { + rootEntityTransform = rootEntityTransformComponent->GetWorldTM(); + } + + INetworkEntityManager* networkEntityManager = GetNetworkEntityManager(); + AZ_Assert(networkEntityManager != nullptr, + "Network Entity Manager must be initialized before NetworkSpawnableHolderComponent is activated"); + + m_netSpawnableTicket = networkEntityManager->RequestNetSpawnableInstantiation(m_networkSpawnableAsset, rootEntityTransform); + } } void NetworkSpawnableHolderComponent::Deactivate() { + m_netSpawnableTicket.reset(); } void NetworkSpawnableHolderComponent::SetNetworkSpawnableAsset(AZ::Data::Asset networkSpawnableAsset) diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h index f32e8d31ab..3836212c48 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkSpawnableHolderComponent.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace Multiplayer { @@ -37,5 +38,6 @@ namespace Multiplayer private: AZ::Data::Asset m_networkSpawnableAsset{ AZ::Data::AssetLoadBehavior::PreLoad }; + AZStd::unique_ptr m_netSpawnableTicket; }; } // namespace Multiplayer