Removed spawn/despawn events from the spawnable system. Used NetworkSpawnableHolderComponent instead
Signed-off-by: pereslav <pereslav@amazon.com>
This commit is contained in:
@@ -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<AZ::Data::Asset<Spawnable>,
|
||||
const AZStd::vector<AZ::Entity*>&, const void*>::Handler& handler) = 0;
|
||||
|
||||
//! Register a handler for OnDespawned events.
|
||||
//! @param handler The handler to receive the event.
|
||||
virtual void AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>, const void*>::Handler& handler) = 0;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] virtual AZStd::pair<EntitySpawnTicket::Id, void*> CreateTicket(AZ::Data::Asset<Spawnable>&& spawnable) = 0;
|
||||
virtual void DestroyTicket(void* ticket) = 0;
|
||||
|
||||
@@ -146,16 +146,6 @@ namespace AzFramework
|
||||
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>, const AZStd::vector<AZ::Entity*>&, const void*>::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_onSpawnedEvent);
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>, 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;
|
||||
|
||||
@@ -69,9 +69,6 @@ namespace AzFramework
|
||||
|
||||
void Barrier(EntitySpawnTicket& spawnInfo, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) override;
|
||||
|
||||
void AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>, const AZStd::vector<AZ::Entity*>&, const void*>::Handler& handler) override;
|
||||
void AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>, 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<AZ::Data::Asset<Spawnable>, const AZStd::vector<AZ::Entity*>&, const void*> m_onSpawnedEvent;
|
||||
AZ::Event<AZ::Data::Asset<Spawnable>, const void*> m_onDespawnedEvent;
|
||||
};
|
||||
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(AzFramework::SpawnableEntitiesManager::CommandQueuePriority);
|
||||
|
||||
@@ -59,8 +59,6 @@ namespace AzFramework
|
||||
|
||||
MOCK_METHOD1(CreateTicket, AZStd::pair<EntitySpawnTicket::Id, void*>(AZ::Data::Asset<Spawnable>&& spawnable));
|
||||
MOCK_METHOD1(DestroyTicket, void(void* ticket));
|
||||
MOCK_METHOD1(AddOnSpawnedHandler, void(AZ::Event<AZ::Data::Asset<Spawnable>, const AZStd::vector<AZ::Entity*>&, const void*>::Handler& handler));
|
||||
MOCK_METHOD1(AddOnDespawnedHandler, void(AZ::Event<AZ::Data::Asset<Spawnable>, 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
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
|
||||
|
||||
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<AzFramework::EntitySpawnTicket> RequestNetSpawnableInstantiation(
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& 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
|
||||
|
||||
@@ -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<AzFramework::Spawnable> spawnable, const AZStd::vector<AZ::Entity*>& entities, const void* spawnTicket) { this->OnSpawned(spawnable, entities, spawnTicket); })
|
||||
, m_onDespawnedHandler([this](AZ::Data::Asset<AzFramework::Spawnable> spawnable, const void* spawnTicket) { this->OnDespawned(spawnable, spawnTicket); })
|
||||
{
|
||||
AZ::Interface<INetworkEntityManager>::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<AzFramework::EntitySpawnTicket> NetworkEntityManager::RequestNetSpawnableInstantiation(
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& rootSpawnable, const AZStd::vector<AZ::Entity*>& entities)
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& 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<NetworkSpawnableHolderComponent>();
|
||||
if (!holderComponent)
|
||||
{
|
||||
// This spawnable doesn't have a corresponding network spawnable.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AzFramework::TransformComponent* rootEntityTransform =
|
||||
rootEntity->FindComponent<AzFramework::TransformComponent>();
|
||||
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<AzFramework::Spawnable> 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<INetworkSpawnableLibrary>::Get()->GetSpawnableNameFromAssetId(netSpawnableAsset.GetId());
|
||||
AZ::Interface<INetworkSpawnableLibrary>::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<AzFramework::EntitySpawnTicket>(netSpawnableAsset);
|
||||
auto ticket = AZStd::make_unique<AzFramework::EntitySpawnTicket>(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<AzFramework::Spawnable> spawnable,
|
||||
const AZStd::vector<AZ::Entity*>& entities, const void* spawnTicket)
|
||||
{
|
||||
if (ShouldSpawnNetEntities())
|
||||
{
|
||||
AZStd::unique_ptr<AzFramework::EntitySpawnTicket> 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<AzFramework::Spawnable> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <AzCore/EBus/ScheduledEvent.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkSpawnableLibrary.h>
|
||||
@@ -61,6 +60,9 @@ namespace Multiplayer
|
||||
const AZ::Transform& transform
|
||||
) override;
|
||||
|
||||
AZStd::unique_ptr<AzFramework::EntitySpawnTicket> RequestNetSpawnableInstantiation(
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& 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<AzFramework::Spawnable> spawnable,
|
||||
const AZStd::vector<AZ::Entity*>& entities, const void* spawnTicket);
|
||||
void OnDespawned(AZ::Data::Asset<AzFramework::Spawnable> 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<AzFramework::EntitySpawnTicket> RequestNetSpawnableInstantiation(
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& rootSpawnable, const AZStd::vector<AZ::Entity*>& entities);
|
||||
|
||||
NetworkEntityTracker m_networkEntityTracker;
|
||||
NetworkEntityAuthorityTracker m_networkEntityAuthorityTracker;
|
||||
@@ -130,10 +123,5 @@ namespace Multiplayer
|
||||
DeferredRpcMessages m_localDeferredRpcMessages;
|
||||
|
||||
NetworkSpawnableLibrary m_networkPrefabLibrary;
|
||||
|
||||
AZStd::unordered_map<const void*, AZStd::unique_ptr<AzFramework::EntitySpawnTicket>> m_netSpawnableTickets;
|
||||
|
||||
AZ::Event<AZ::Data::Asset<AzFramework::Spawnable>, const AZStd::vector<AZ::Entity*>&, const void*>::Handler m_onSpawnedHandler;
|
||||
AZ::Event<AZ::Data::Asset<AzFramework::Spawnable>, const void*>::Handler m_onDespawnedHandler;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <Source/Pipeline/NetworkSpawnableHolderComponent.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
|
||||
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<AzFramework::TransformComponent>();
|
||||
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<AzFramework::Spawnable> networkSpawnableAsset)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -37,5 +38,6 @@ namespace Multiplayer
|
||||
|
||||
private:
|
||||
AZ::Data::Asset<AzFramework::Spawnable> m_networkSpawnableAsset{ AZ::Data::AssetLoadBehavior::PreLoad };
|
||||
AZStd::unique_ptr<AzFramework::EntitySpawnTicket> m_netSpawnableTicket;
|
||||
};
|
||||
} // namespace Multiplayer
|
||||
|
||||
Reference in New Issue
Block a user