Merge pull request #4154 from aws-lumberyard-dev/Prefab/DestroyGameEntitySupport
Enable destroying entities spawned using a spawnable
This commit is contained in:
@@ -649,6 +649,16 @@ namespace AZ
|
||||
m_stateEvent.Signal(oldState, m_state);
|
||||
}
|
||||
|
||||
void Entity::SetSpawnTicketId(u32 spawnTicketId)
|
||||
{
|
||||
m_spawnTicketId = spawnTicketId;
|
||||
}
|
||||
|
||||
u32 Entity::GetSpawnTicketId() const
|
||||
{
|
||||
return m_spawnTicketId;
|
||||
}
|
||||
|
||||
void Entity::OnNameChanged() const
|
||||
{
|
||||
EBUS_EVENT_ID(GetId(), EntityBus, OnEntityNameChanged, m_name);
|
||||
|
||||
@@ -133,6 +133,14 @@ namespace AZ
|
||||
//! @return The state of the entity. For example, the entity has been initialized, the entity is active, and so on.
|
||||
State GetState() const { return m_state; }
|
||||
|
||||
//! Gets the ticket id used to spawn the entity.
|
||||
//! @return the ticket id used to spawn the entity. If entity is not spawned, the id will be 0.
|
||||
u32 GetSpawnTicketId() const;
|
||||
|
||||
//! Sets the ticket id used to spawn the entity. The ticket id in the entity will remain 0 unless it's set using this function.
|
||||
//! @param spawnTicketId the ticket id used to spawn the entity.
|
||||
void SetSpawnTicketId(u32 spawnTicketId);
|
||||
|
||||
//! Connects an entity state event handler to the entity.
|
||||
//! All state changes will be signaled through this event.
|
||||
//! @param handler reference to the EntityStateEvent handler to attach to the entities state event.
|
||||
@@ -410,6 +418,8 @@ namespace AZ
|
||||
//! A user-friendly name for the entity. This makes error messages easier to read.
|
||||
AZStd::string m_name;
|
||||
|
||||
u32 m_spawnTicketId = 0;
|
||||
|
||||
//! The state of the entity.
|
||||
State m_state;
|
||||
|
||||
|
||||
@@ -91,15 +91,6 @@ namespace AzFramework
|
||||
*/
|
||||
virtual void DestroyGameEntity(const AZ::EntityId& /*id*/) = 0;
|
||||
|
||||
/**
|
||||
* Destroys an entity only in slice mode (when prefabs are disabled). This request is only added as a stop-gap solution
|
||||
* to prevent the editor from crashing when prefabs are enabled and must only be called through the BehaviorContext binding
|
||||
* for 'DestroyGameEntity'. No code should be written to directly call this method. This will be removed soon.
|
||||
*
|
||||
* @param id The ID of the entity to destroy.
|
||||
*/
|
||||
virtual void DestroyGameEntityOnlyInSliceMode(const AZ::EntityId& /*id*/) = 0;
|
||||
|
||||
/**
|
||||
* Destroys an entity and all of its descendants.
|
||||
* The entity and its descendants are immediately deactivated and will be
|
||||
@@ -108,15 +99,6 @@ namespace AzFramework
|
||||
*/
|
||||
virtual void DestroyGameEntityAndDescendants(const AZ::EntityId& /*id*/) = 0;
|
||||
|
||||
/**
|
||||
* Destroys an entity and its descendants only in slice mode (when prefabs are disabled). This request is only added as a stop-gap
|
||||
* solution to prevent the editor from crashing when prefabs are enabled and must only be called through the BehaviorContext
|
||||
* binding for 'DestroyGameEntityAndDescendants'.No code should be written to directly call this method. This will be removed soon.
|
||||
*
|
||||
* @param id The ID of the entity to destroy.
|
||||
*/
|
||||
virtual void DestroyGameEntityAndDescendantsOnlyInSliceMode(const AZ::EntityId& /*id*/) = 0;
|
||||
|
||||
/**
|
||||
* Activates the game entity.
|
||||
* @param id The ID of the entity to activate.
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Entity/EntityContext.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
|
||||
|
||||
#include "GameEntityContextComponent.h"
|
||||
|
||||
@@ -47,9 +48,9 @@ namespace AzFramework
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Event("CreateGameEntity", &GameEntityContextRequestBus::Events::CreateGameEntityForBehaviorContext)
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Event("DestroyGameEntity", &GameEntityContextRequestBus::Events::DestroyGameEntityOnlyInSliceMode)
|
||||
->Event("DestroyGameEntity", &GameEntityContextRequestBus::Events::DestroyGameEntity)
|
||||
->Event(
|
||||
"DestroyGameEntityAndDescendants", &GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendantsOnlyInSliceMode)
|
||||
"DestroyGameEntityAndDescendants", &GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendants)
|
||||
->Event("ActivateGameEntity", &GameEntityContextRequestBus::Events::ActivateGameEntity)
|
||||
->Event("DeactivateGameEntity", &GameEntityContextRequestBus::Events::DeactivateGameEntity)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::DeactivatesInputEntity, true)
|
||||
@@ -249,23 +250,6 @@ namespace AzFramework
|
||||
DestroyGameEntityInternal(id, false);
|
||||
}
|
||||
|
||||
void GameEntityContextComponent::DestroyGameEntityOnlyInSliceMode(const AZ::EntityId& id)
|
||||
{
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
if (!isPrefabSystemEnabled)
|
||||
{
|
||||
DestroyGameEntityInternal(id, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(
|
||||
"GameEntityContextComponent", false,
|
||||
"Destroying a game entity is temporarily disabled until the Spawnable system can support this.");
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GameEntityContextComponent::DestroyGameEntityAndDescendantsById
|
||||
//=========================================================================
|
||||
@@ -274,24 +258,6 @@ namespace AzFramework
|
||||
DestroyGameEntityInternal(id, true);
|
||||
}
|
||||
|
||||
|
||||
void GameEntityContextComponent::DestroyGameEntityAndDescendantsOnlyInSliceMode(const AZ::EntityId& id)
|
||||
{
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
if (!isPrefabSystemEnabled)
|
||||
{
|
||||
DestroyGameEntityInternal(id, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(
|
||||
"GameEntityContextComponent", false,
|
||||
"Destroying a game entity and its descendants is temporarily disabled until the Spawnable system can support this.");
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GameEntityContextComponent::DestroyGameEntityInternal
|
||||
//=========================================================================
|
||||
@@ -319,6 +285,28 @@ namespace AzFramework
|
||||
EBUS_EVENT_RESULT(currentEntity, AZ::ComponentApplicationBus, FindEntity, *entityIdIter);
|
||||
if (currentEntity)
|
||||
{
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
if (isPrefabSystemEnabled)
|
||||
{
|
||||
if (currentEntity->GetSpawnTicketId() > 0)
|
||||
{
|
||||
SpawnableEntitiesDefinition* spawnableEntitiesInterface = SpawnableEntitiesInterface::Get();
|
||||
AZ_Assert(spawnableEntitiesInterface != nullptr, "SpawnableEntitiesInterface is not found.");
|
||||
spawnableEntitiesInterface->RetrieveEntitySpawnTicket(
|
||||
currentEntity->GetSpawnTicketId(),
|
||||
[spawnableEntitiesInterface, currentEntity](EntitySpawnTicket* entitySpawnTicket)
|
||||
{
|
||||
if (entitySpawnTicket != nullptr)
|
||||
{
|
||||
spawnableEntitiesInterface->DespawnEntity(currentEntity->GetId(), *entitySpawnTicket);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentEntity->GetState() == AZ::Entity::State::Active)
|
||||
{
|
||||
// Deactivate the entity, we'll destroy it as soon as it is safe.
|
||||
|
||||
@@ -90,11 +90,6 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GameEntityContextRequestBus
|
||||
void DestroyGameEntityOnlyInSliceMode(const AZ::EntityId&) override;
|
||||
void DestroyGameEntityAndDescendantsOnlyInSliceMode(const AZ::EntityId&) override;
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
|
||||
};
|
||||
|
||||
@@ -283,8 +283,12 @@ namespace AzFramework
|
||||
: m_payload(rhs.m_payload)
|
||||
, m_id(rhs.m_id)
|
||||
{
|
||||
auto manager = SpawnableEntitiesInterface::Get();
|
||||
AZ_Assert(manager, "SpawnableEntitiesInterface has no implementation.");
|
||||
rhs.m_payload = nullptr;
|
||||
rhs.m_id = 0;
|
||||
AZStd::scoped_lock lock(manager->m_entitySpawnTicketMapMutex);
|
||||
manager->m_entitySpawnTicketMap.insert_or_assign(rhs.m_id, this);
|
||||
}
|
||||
|
||||
EntitySpawnTicket::EntitySpawnTicket(AZ::Data::Asset<Spawnable> spawnable)
|
||||
@@ -294,6 +298,8 @@ namespace AzFramework
|
||||
AZStd::pair<EntitySpawnTicket::Id, void*> result = manager->CreateTicket(AZStd::move(spawnable));
|
||||
m_id = result.first;
|
||||
m_payload = result.second;
|
||||
AZStd::scoped_lock lock(manager->m_entitySpawnTicketMapMutex);
|
||||
manager->m_entitySpawnTicketMap.insert_or_assign(m_id, this);
|
||||
}
|
||||
|
||||
EntitySpawnTicket::~EntitySpawnTicket()
|
||||
@@ -304,6 +310,8 @@ namespace AzFramework
|
||||
AZ_Assert(manager, "Attempting to destroy an entity spawn ticket while the SpawnableEntitiesInterface has no implementation.");
|
||||
manager->DestroyTicket(m_payload);
|
||||
m_payload = nullptr;
|
||||
AZStd::scoped_lock lock(manager->m_entitySpawnTicketMapMutex);
|
||||
manager->m_entitySpawnTicketMap.erase(m_id);
|
||||
m_id = 0;
|
||||
}
|
||||
}
|
||||
@@ -312,17 +320,23 @@ namespace AzFramework
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
auto manager = SpawnableEntitiesInterface::Get();
|
||||
AZ_Assert(manager, "Attempting to destroy an entity spawn ticket while the SpawnableEntitiesInterface has no implementation.");
|
||||
if (m_payload)
|
||||
{
|
||||
auto manager = SpawnableEntitiesInterface::Get();
|
||||
AZ_Assert(manager, "Attempting to destroy an entity spawn ticket while the SpawnableEntitiesInterface has no implementation.");
|
||||
manager->DestroyTicket(m_payload);
|
||||
}
|
||||
|
||||
Id previousId = m_id;
|
||||
m_id = rhs.m_id;
|
||||
rhs.m_id = 0;
|
||||
|
||||
m_payload = rhs.m_payload;
|
||||
rhs.m_payload = nullptr;
|
||||
|
||||
AZStd::scoped_lock lock(manager->m_entitySpawnTicketMapMutex);
|
||||
manager->m_entitySpawnTicketMap.erase(previousId);
|
||||
manager->m_entitySpawnTicketMap.insert_or_assign(m_id, this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace AzFramework
|
||||
public:
|
||||
friend class SpawnableEntitiesDefinition;
|
||||
|
||||
using Id = uint64_t;
|
||||
using Id = uint32_t;
|
||||
|
||||
EntitySpawnTicket() = default;
|
||||
EntitySpawnTicket(const EntitySpawnTicket&) = delete;
|
||||
@@ -176,6 +176,7 @@ namespace AzFramework
|
||||
using EntitySpawnCallback = AZStd::function<void(EntitySpawnTicket::Id, SpawnableConstEntityContainerView)>;
|
||||
using EntityPreInsertionCallback = AZStd::function<void(EntitySpawnTicket::Id, SpawnableEntityContainerView)>;
|
||||
using EntityDespawnCallback = AZStd::function<void(EntitySpawnTicket::Id)>;
|
||||
using RetrieveEntitySpawnTicketCallback = AZStd::function<void(EntitySpawnTicket*)>;
|
||||
using ReloadSpawnableCallback = AZStd::function<void(EntitySpawnTicket::Id, SpawnableConstEntityContainerView)>;
|
||||
using ListEntitiesCallback = AZStd::function<void(EntitySpawnTicket::Id, SpawnableConstEntityContainerView)>;
|
||||
using ListIndicesEntitiesCallback = AZStd::function<void(EntitySpawnTicket::Id, SpawnableConstIndexEntityContainerView)>;
|
||||
@@ -220,12 +221,21 @@ namespace AzFramework
|
||||
struct DespawnAllEntitiesOptionalArgs final
|
||||
{
|
||||
//! Callback that's called when despawning entities has completed. This can be triggered from a different thread than the one that
|
||||
//! made the function call to despawn. The returned list of entities contains all the newly created entities.
|
||||
//! made the function call to despawn.
|
||||
EntityDespawnCallback m_completionCallback;
|
||||
//! The priority at which this call will be executed.
|
||||
SpawnablePriority m_priority { SpawnablePriority_Default };
|
||||
};
|
||||
|
||||
struct DespawnEntityOptionalArgs final
|
||||
{
|
||||
//! Callback that's called when despawning entity has completed. This can be triggered from a different thread than the one that
|
||||
//! made the function call to despawn.
|
||||
EntityDespawnCallback m_completionCallback;
|
||||
//! The priority at which this call will be executed.
|
||||
SpawnablePriority m_priority{ SpawnablePriority_Default };
|
||||
};
|
||||
|
||||
struct ReloadSpawnableOptionalArgs final
|
||||
{
|
||||
//! Callback that's called when respawning entities has completed. This can be triggered from a different thread than the one that
|
||||
@@ -291,9 +301,17 @@ namespace AzFramework
|
||||
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0;
|
||||
//! Removes all entities in the provided list from the environment.
|
||||
//! @param ticket The ticket previously used to spawn entities with.
|
||||
//! @param priority The priority at which this call will be executed.
|
||||
//! @param optionalArgs Optional additional arguments, see DespawnAllEntitiesOptionalArgs.
|
||||
virtual void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) = 0;
|
||||
//! Removes the entity with the provided id from the spawned list of entities.
|
||||
//! @param entityId the id of entity to despawn.
|
||||
//! @param ticket The ticket previously used to spawn entities with.
|
||||
//! @param optionalArgs Optional additional arguments, see DespawnEntityOptionalArgs.
|
||||
virtual void DespawnEntity(AZ::EntityId entityId, EntitySpawnTicket& ticket, DespawnEntityOptionalArgs optionalArgs = {}) = 0;
|
||||
//! Gets the EntitySpawnTicket associated with the entitySpawnTicketId.
|
||||
//! @param entitySpawnTicketId the id of EntitySpawnTicket to get.
|
||||
//! @param callback The callback to execute upon retrieving the ticket.
|
||||
virtual void RetrieveEntitySpawnTicket(EntitySpawnTicket::Id entitySpawnTicketId, RetrieveEntitySpawnTicketCallback callback) = 0;
|
||||
//! Removes all entities in the provided list from the environment and reconstructs the entities from the provided spawnable.
|
||||
//! @param ticket Holds the information on the entities to reload.
|
||||
//! @param priority The priority at which this call will be executed.
|
||||
@@ -361,6 +379,9 @@ namespace AzFramework
|
||||
{
|
||||
return reinterpret_cast<const T*>(ticket->m_payload);
|
||||
}
|
||||
|
||||
AZStd::unordered_map<EntitySpawnTicket::Id, EntitySpawnTicket*> m_entitySpawnTicketMap;
|
||||
AZStd::recursive_mutex m_entitySpawnTicketMapMutex;
|
||||
};
|
||||
|
||||
using SpawnableEntitiesInterface = AZ::Interface<SpawnableEntitiesDefinition>;
|
||||
|
||||
@@ -85,6 +85,35 @@ namespace AzFramework
|
||||
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::DespawnEntity(AZ::EntityId entityId, EntitySpawnTicket& ticket, DespawnEntityOptionalArgs optionalArgs)
|
||||
{
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to DespawnEntity hasn't been initialized.");
|
||||
|
||||
DespawnEntityCommand queueEntry;
|
||||
queueEntry.m_ticketId = ticket.GetId();
|
||||
queueEntry.m_entityId = entityId;
|
||||
queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback);
|
||||
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::RetrieveEntitySpawnTicket(EntitySpawnTicket::Id entitySpawnTicketId, RetrieveEntitySpawnTicketCallback callback)
|
||||
{
|
||||
if (entitySpawnTicketId == 0)
|
||||
{
|
||||
AZ_Assert(false, "Ticket id provided to RetrieveEntitySpawnTicket is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::scoped_lock lock(m_entitySpawnTicketMapMutex);
|
||||
auto entitySpawnTicketIterator = m_entitySpawnTicketMap.find(entitySpawnTicketId);
|
||||
if (entitySpawnTicketIterator == m_entitySpawnTicketMap.end())
|
||||
{
|
||||
AZ_Assert(false, "The EntitySpawnTicket corresponding to id '%lu' cannot be found", entitySpawnTicketId);
|
||||
return;
|
||||
}
|
||||
callback(entitySpawnTicketIterator->second);
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::ReloadSpawnable(
|
||||
EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs)
|
||||
{
|
||||
@@ -223,12 +252,13 @@ namespace AzFramework
|
||||
return queue.m_delayed.empty() ? CommandQueueStatus::NoCommandsLeft : CommandQueueStatus::HasCommandsLeft;
|
||||
}
|
||||
|
||||
AZStd::pair<uint64_t, void*> SpawnableEntitiesManager::CreateTicket(AZ::Data::Asset<Spawnable>&& spawnable)
|
||||
AZStd::pair<EntitySpawnTicket::Id, void*> SpawnableEntitiesManager::CreateTicket(AZ::Data::Asset<Spawnable>&& spawnable)
|
||||
{
|
||||
static AZStd::atomic_uint64_t idCounter { 1 };
|
||||
static AZStd::atomic_uint32_t idCounter { 1 };
|
||||
|
||||
auto result = aznew Ticket();
|
||||
result->m_spawnable = AZStd::move(spawnable);
|
||||
|
||||
return AZStd::make_pair<EntitySpawnTicket::Id, void*>(idCounter++, result);
|
||||
}
|
||||
|
||||
@@ -339,6 +369,7 @@ namespace AzFramework
|
||||
// Add to the game context, now the entities are active
|
||||
for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it)
|
||||
{
|
||||
(*it)->SetSpawnTicketId(request.m_ticketId);
|
||||
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
|
||||
}
|
||||
|
||||
@@ -420,6 +451,7 @@ namespace AzFramework
|
||||
// Add to the game context, now the entities are active
|
||||
for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it)
|
||||
{
|
||||
(*it)->SetSpawnTicketId(request.m_ticketId);
|
||||
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
|
||||
}
|
||||
|
||||
@@ -447,8 +479,10 @@ namespace AzFramework
|
||||
{
|
||||
if (entity != nullptr)
|
||||
{
|
||||
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
|
||||
entity->SetSpawnTicketId(0);
|
||||
GameEntityContextRequestBus::Broadcast(
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendants, entity->GetId());
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,6 +503,40 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
bool SpawnableEntitiesManager::ProcessRequest(DespawnEntityCommand& request)
|
||||
{
|
||||
Ticket& ticket = *request.m_ticket;
|
||||
if (request.m_requestId == ticket.m_currentRequestId)
|
||||
{
|
||||
AZStd::vector<AZ::Entity*>& spawnedEntities = request.m_ticket->m_spawnedEntities;
|
||||
for (auto entityIterator = spawnedEntities.begin(); entityIterator != spawnedEntities.end(); ++entityIterator)
|
||||
{
|
||||
if (*entityIterator != nullptr && (*entityIterator)->GetId() == request.m_entityId)
|
||||
{
|
||||
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
|
||||
(*entityIterator)->SetSpawnTicketId(0);
|
||||
GameEntityContextRequestBus::Broadcast(
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntity, (*entityIterator)->GetId());
|
||||
AZStd::iter_swap(entityIterator, spawnedEntities.rbegin());
|
||||
spawnedEntities.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (request.m_completionCallback)
|
||||
{
|
||||
request.m_completionCallback(request.m_ticketId);
|
||||
}
|
||||
|
||||
ticket.m_currentRequestId++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpawnableEntitiesManager::ProcessRequest(ReloadSpawnableCommand& request)
|
||||
{
|
||||
Ticket& ticket = *request.m_ticket;
|
||||
@@ -482,8 +550,10 @@ namespace AzFramework
|
||||
{
|
||||
if (entity != nullptr)
|
||||
{
|
||||
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
|
||||
entity->SetSpawnTicketId(0);
|
||||
GameEntityContextRequestBus::Broadcast(
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendants, entity->GetId());
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,8 +706,10 @@ namespace AzFramework
|
||||
{
|
||||
if (entity != nullptr)
|
||||
{
|
||||
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
|
||||
entity->SetSpawnTicketId(0);
|
||||
GameEntityContextRequestBus::Broadcast(
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendants, entity->GetId());
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
|
||||
}
|
||||
}
|
||||
delete request.m_ticket;
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace AzFramework
|
||||
void SpawnEntities(
|
||||
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) override;
|
||||
void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) override;
|
||||
void DespawnEntity(AZ::EntityId entityId, EntitySpawnTicket& ticket, DespawnEntityOptionalArgs optionalArgs = {}) override;
|
||||
void RetrieveEntitySpawnTicket(EntitySpawnTicket::Id entitySpawnTicketId, RetrieveEntitySpawnTicketCallback callback) override;
|
||||
void ReloadSpawnable(
|
||||
EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs = {}) override;
|
||||
|
||||
@@ -132,6 +134,14 @@ namespace AzFramework
|
||||
EntitySpawnTicket::Id m_ticketId;
|
||||
uint32_t m_requestId;
|
||||
};
|
||||
struct DespawnEntityCommand
|
||||
{
|
||||
EntityDespawnCallback m_completionCallback;
|
||||
Ticket* m_ticket;
|
||||
AZ::EntityId m_entityId;
|
||||
EntitySpawnTicket::Id m_ticketId;
|
||||
uint32_t m_requestId;
|
||||
};
|
||||
struct ReloadSpawnableCommand
|
||||
{
|
||||
AZ::Data::Asset<Spawnable> m_spawnable;
|
||||
@@ -176,8 +186,16 @@ namespace AzFramework
|
||||
};
|
||||
|
||||
using Requests = AZStd::variant<
|
||||
SpawnAllEntitiesCommand, SpawnEntitiesCommand, DespawnAllEntitiesCommand, ReloadSpawnableCommand, ListEntitiesCommand,
|
||||
ListIndicesEntitiesCommand, ClaimEntitiesCommand, BarrierCommand, DestroyTicketCommand>;
|
||||
SpawnAllEntitiesCommand,
|
||||
SpawnEntitiesCommand,
|
||||
DespawnAllEntitiesCommand,
|
||||
DespawnEntityCommand,
|
||||
ReloadSpawnableCommand,
|
||||
ListEntitiesCommand,
|
||||
ListIndicesEntitiesCommand,
|
||||
ClaimEntitiesCommand,
|
||||
BarrierCommand,
|
||||
DestroyTicketCommand>;
|
||||
|
||||
struct Queue
|
||||
{
|
||||
@@ -199,6 +217,7 @@ namespace AzFramework
|
||||
bool ProcessRequest(SpawnAllEntitiesCommand& request);
|
||||
bool ProcessRequest(SpawnEntitiesCommand& request);
|
||||
bool ProcessRequest(DespawnAllEntitiesCommand& request);
|
||||
bool ProcessRequest(DespawnEntityCommand& request);
|
||||
bool ProcessRequest(ReloadSpawnableCommand& request);
|
||||
bool ProcessRequest(ListEntitiesCommand& request);
|
||||
bool ProcessRequest(ListIndicesEntitiesCommand& request);
|
||||
|
||||
@@ -40,6 +40,11 @@ namespace AzFramework
|
||||
|
||||
MOCK_METHOD2(DespawnAllEntities, void(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs));
|
||||
|
||||
MOCK_METHOD3(DespawnEntity, void(AZ::EntityId entityId, EntitySpawnTicket& ticket, DespawnEntityOptionalArgs optionalArgs));
|
||||
|
||||
MOCK_METHOD2(
|
||||
RetrieveEntitySpawnTicket, void(EntitySpawnTicket::Id entitySpawnTicketId, RetrieveEntitySpawnTicketCallback callback));
|
||||
|
||||
MOCK_METHOD3(
|
||||
ReloadSpawnable,
|
||||
void(EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs));
|
||||
|
||||
Reference in New Issue
Block a user