Merge pull request #917 from aws-lumberyard-dev/SpawnableIndexQuery
Additional list function added to Spawnables.
This commit is contained in:
@@ -19,10 +19,13 @@
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzFramework/Spawnable/SpawnableMetaData.h>
|
||||
|
||||
namespace AzFramework
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
}
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class Spawnable final
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
//
|
||||
// SpawnableEntityContainerView
|
||||
//
|
||||
|
||||
SpawnableEntityContainerView::SpawnableEntityContainerView(AZ::Entity** begin, size_t length)
|
||||
: m_begin(begin)
|
||||
, m_end(begin + length)
|
||||
@@ -52,6 +56,9 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SpawnableConstEntityContainerView
|
||||
//
|
||||
|
||||
SpawnableConstEntityContainerView::SpawnableConstEntityContainerView(AZ::Entity** begin, size_t length)
|
||||
: m_begin(begin)
|
||||
@@ -91,6 +98,136 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SpawnableIndexEntityPair
|
||||
//
|
||||
|
||||
SpawnableIndexEntityPair::SpawnableIndexEntityPair(AZ::Entity** entityIterator, size_t* indexIterator)
|
||||
: m_entity(entityIterator)
|
||||
, m_index(indexIterator)
|
||||
{
|
||||
}
|
||||
|
||||
AZ::Entity* SpawnableIndexEntityPair::GetEntity()
|
||||
{
|
||||
return *m_entity;
|
||||
}
|
||||
|
||||
const AZ::Entity* SpawnableIndexEntityPair::GetEntity() const
|
||||
{
|
||||
return *m_entity;
|
||||
}
|
||||
|
||||
size_t SpawnableIndexEntityPair::GetIndex() const
|
||||
{
|
||||
return *m_index;
|
||||
}
|
||||
|
||||
//
|
||||
// SpawnableIndexEntityIterator
|
||||
//
|
||||
|
||||
SpawnableIndexEntityIterator::SpawnableIndexEntityIterator(AZ::Entity** entityIterator, size_t* indexIterator)
|
||||
: m_value(entityIterator, indexIterator)
|
||||
{
|
||||
}
|
||||
|
||||
SpawnableIndexEntityIterator& SpawnableIndexEntityIterator::operator++()
|
||||
{
|
||||
++m_value.m_entity;
|
||||
++m_value.m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SpawnableIndexEntityIterator SpawnableIndexEntityIterator::operator++(int)
|
||||
{
|
||||
SpawnableIndexEntityIterator result = *this;
|
||||
++m_value.m_entity;
|
||||
++m_value.m_index;
|
||||
return result;
|
||||
}
|
||||
|
||||
SpawnableIndexEntityIterator& SpawnableIndexEntityIterator::operator--()
|
||||
{
|
||||
--m_value.m_entity;
|
||||
--m_value.m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SpawnableIndexEntityIterator SpawnableIndexEntityIterator::operator--(int)
|
||||
{
|
||||
SpawnableIndexEntityIterator result = *this;
|
||||
--m_value.m_entity;
|
||||
--m_value.m_index;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SpawnableIndexEntityIterator::operator==(const SpawnableIndexEntityIterator& rhs)
|
||||
{
|
||||
return m_value.m_entity == rhs.m_value.m_entity && m_value.m_index == rhs.m_value.m_index;
|
||||
}
|
||||
|
||||
bool SpawnableIndexEntityIterator::operator!=(const SpawnableIndexEntityIterator& rhs)
|
||||
{
|
||||
return m_value.m_entity != rhs.m_value.m_entity || m_value.m_index != rhs.m_value.m_index;
|
||||
}
|
||||
|
||||
SpawnableIndexEntityPair& SpawnableIndexEntityIterator::operator*()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const SpawnableIndexEntityPair& SpawnableIndexEntityIterator::operator*() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
SpawnableIndexEntityPair* SpawnableIndexEntityIterator::operator->()
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
const SpawnableIndexEntityPair* SpawnableIndexEntityIterator::operator->() const
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SpawnableConstIndexEntityContainerView
|
||||
//
|
||||
|
||||
SpawnableConstIndexEntityContainerView::SpawnableConstIndexEntityContainerView(
|
||||
AZ::Entity** beginEntity, size_t* beginIndices, size_t length)
|
||||
: m_begin(beginEntity, beginIndices)
|
||||
, m_end(beginEntity + length, beginIndices + length)
|
||||
{
|
||||
}
|
||||
|
||||
const SpawnableIndexEntityIterator& SpawnableConstIndexEntityContainerView::begin()
|
||||
{
|
||||
return m_begin;
|
||||
}
|
||||
|
||||
const SpawnableIndexEntityIterator& SpawnableConstIndexEntityContainerView::end()
|
||||
{
|
||||
return m_end;
|
||||
}
|
||||
|
||||
const SpawnableIndexEntityIterator& SpawnableConstIndexEntityContainerView::cbegin()
|
||||
{
|
||||
return m_begin;
|
||||
}
|
||||
|
||||
const SpawnableIndexEntityIterator& SpawnableConstIndexEntityContainerView::cend()
|
||||
{
|
||||
return m_end;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// EntitySpawnTicket
|
||||
//
|
||||
|
||||
EntitySpawnTicket::EntitySpawnTicket(EntitySpawnTicket&& rhs)
|
||||
: m_payload(rhs.m_payload)
|
||||
|
||||
@@ -58,6 +58,72 @@ namespace AzFramework
|
||||
AZ::Entity** m_end;
|
||||
};
|
||||
|
||||
class SpawnableIndexEntityPair
|
||||
{
|
||||
public:
|
||||
friend class SpawnableIndexEntityIterator;
|
||||
|
||||
AZ::Entity* GetEntity();
|
||||
const AZ::Entity* GetEntity() const;
|
||||
size_t GetIndex() const;
|
||||
|
||||
private:
|
||||
SpawnableIndexEntityPair() = default;
|
||||
SpawnableIndexEntityPair(const SpawnableIndexEntityPair&) = default;
|
||||
SpawnableIndexEntityPair(SpawnableIndexEntityPair&&) = default;
|
||||
SpawnableIndexEntityPair(AZ::Entity** entityIterator, size_t* indexIterator);
|
||||
|
||||
SpawnableIndexEntityPair& operator=(const SpawnableIndexEntityPair&) = default;
|
||||
SpawnableIndexEntityPair& operator=(SpawnableIndexEntityPair&&) = default;
|
||||
|
||||
AZ::Entity** m_entity { nullptr };
|
||||
size_t* m_index { nullptr };
|
||||
};
|
||||
|
||||
class SpawnableIndexEntityIterator
|
||||
{
|
||||
public:
|
||||
// Limited to bidirectional iterator as there's no use case for extending it further, but can be extended if a use case is found.
|
||||
using iterator_category = AZStd::bidirectional_iterator_tag;
|
||||
using value_type = SpawnableIndexEntityPair;
|
||||
using difference_type = size_t;
|
||||
using pointer = SpawnableIndexEntityPair*;
|
||||
using reference = SpawnableIndexEntityPair&;
|
||||
|
||||
SpawnableIndexEntityIterator(AZ::Entity** entityIterator, size_t* indexIterator);
|
||||
|
||||
SpawnableIndexEntityIterator& operator++();
|
||||
SpawnableIndexEntityIterator operator++(int);
|
||||
SpawnableIndexEntityIterator& operator--();
|
||||
SpawnableIndexEntityIterator operator--(int);
|
||||
|
||||
bool operator==(const SpawnableIndexEntityIterator& rhs);
|
||||
bool operator!=(const SpawnableIndexEntityIterator& rhs);
|
||||
|
||||
SpawnableIndexEntityPair& operator*();
|
||||
const SpawnableIndexEntityPair& operator*() const;
|
||||
SpawnableIndexEntityPair* operator->();
|
||||
const SpawnableIndexEntityPair* operator->() const;
|
||||
|
||||
private:
|
||||
SpawnableIndexEntityPair m_value;
|
||||
};
|
||||
|
||||
class SpawnableConstIndexEntityContainerView
|
||||
{
|
||||
public:
|
||||
SpawnableConstIndexEntityContainerView(AZ::Entity** beginEntity, size_t* beginIndices, size_t length);
|
||||
|
||||
const SpawnableIndexEntityIterator& begin();
|
||||
const SpawnableIndexEntityIterator& end();
|
||||
const SpawnableIndexEntityIterator& cbegin();
|
||||
const SpawnableIndexEntityIterator& cend();
|
||||
|
||||
private:
|
||||
SpawnableIndexEntityIterator m_begin;
|
||||
SpawnableIndexEntityIterator m_end;
|
||||
};
|
||||
|
||||
//! Requests to the SpawnableEntitiesInterface require a ticket with a valid spawnable that be used as a template. A ticket can
|
||||
//! be reused for multiple calls on the same spawnable and is safe to use by multiple threads at the same time. Entities created
|
||||
//! from the spawnable may be tracked by the ticket and so using the same ticket is needed to despawn the exact entities created
|
||||
@@ -88,6 +154,7 @@ namespace AzFramework
|
||||
using EntityDespawnCallback = AZStd::function<void(EntitySpawnTicket&)>;
|
||||
using ReloadSpawnableCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableConstEntityContainerView)>;
|
||||
using ListEntitiesCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableConstEntityContainerView)>;
|
||||
using ListIndicesEntitiesCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableConstIndexEntityContainerView)>;
|
||||
using ClaimEntitiesCallback = AZStd::function<void(EntitySpawnTicket&, SpawnableEntityContainerView)>;
|
||||
using BarrierCallback = AZStd::function<void(EntitySpawnTicket&)>;
|
||||
|
||||
@@ -140,6 +207,15 @@ namespace AzFramework
|
||||
//! @param ticket Only the entities associated with this ticket will be listed.
|
||||
//! @param listCallback Required callback that will be called to list the entities on.
|
||||
virtual void ListEntities(EntitySpawnTicket& ticket, ListEntitiesCallback listCallback) = 0;
|
||||
//! List all entities that are spawned using this ticket with their spawnable index.
|
||||
//! Spawnables contain a flat list of entities, which are used as templates to spawn entities from. For every spawned entity
|
||||
//! the index of the entity in the spawnable that was used as a template is stored. This version of ListEntities will return
|
||||
//! both the entities and this index. The index can be used with SpawnEntities to create the same entities again. Note that
|
||||
//! the same index may appear multiple times as there are no restriction on how many instance of a specific entity can be
|
||||
//! created.
|
||||
//! @param ticket Only the entities associated with this ticket will be listed.
|
||||
//! @param listCallback Required callback that will be called to list the entities and indices on.
|
||||
virtual void ListIndicesAndEntities(EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback) = 0;
|
||||
//! Claim all entities that are spawned using this ticket. Ownership of the entities is transferred from the ticket to the
|
||||
//! caller through the callback. After this call the ticket will have no entities associated with it. The caller of
|
||||
//! this function will need to manage the entities after this call.
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace AzFramework
|
||||
void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, EntityPreInsertionCallback preInsertionCallback,
|
||||
EntitySpawnCallback completionCallback)
|
||||
{
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnAllEntities hasn't been initialized.");
|
||||
|
||||
SpawnAllEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_completionCallback = AZStd::move(completionCallback);
|
||||
@@ -40,6 +42,8 @@ namespace AzFramework
|
||||
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices,
|
||||
EntityPreInsertionCallback preInsertionCallback, EntitySpawnCallback completionCallback)
|
||||
{
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnEntities hasn't been initialized.");
|
||||
|
||||
SpawnEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_entityIndices = AZStd::move(entityIndices);
|
||||
@@ -54,6 +58,8 @@ namespace AzFramework
|
||||
|
||||
void SpawnableEntitiesManager::DespawnAllEntities(EntitySpawnTicket& ticket, EntityDespawnCallback completionCallback)
|
||||
{
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to DespawnAllEntities hasn't been initialized.");
|
||||
|
||||
DespawnAllEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_completionCallback = AZStd::move(completionCallback);
|
||||
@@ -67,6 +73,8 @@ namespace AzFramework
|
||||
void SpawnableEntitiesManager::ReloadSpawnable(EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable,
|
||||
ReloadSpawnableCallback completionCallback)
|
||||
{
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to ReloadSpawnable hasn't been initialized.");
|
||||
|
||||
ReloadSpawnableCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_spawnable = AZStd::move(spawnable);
|
||||
@@ -81,6 +89,7 @@ namespace AzFramework
|
||||
void SpawnableEntitiesManager::ListEntities(EntitySpawnTicket& ticket, ListEntitiesCallback listCallback)
|
||||
{
|
||||
AZ_Assert(listCallback, "ListEntities called on spawnable entities without a valid callback to use.");
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to ListEntities hasn't been initialized.");
|
||||
|
||||
ListEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
@@ -92,9 +101,25 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::ListIndicesAndEntities(EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback)
|
||||
{
|
||||
AZ_Assert(listCallback, "ListEntities called on spawnable entities without a valid callback to use.");
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to ListEntities hasn't been initialized.");
|
||||
|
||||
ListIndicesEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
queueEntry.m_listCallback = AZStd::move(listCallback);
|
||||
{
|
||||
AZStd::scoped_lock queueLock(m_pendingRequestQueueMutex);
|
||||
queueEntry.m_ticketId = GetTicketPayload<Ticket>(ticket).m_nextTicketId++;
|
||||
m_pendingRequestQueue.push(AZStd::move(queueEntry));
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::ClaimEntities(EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback)
|
||||
{
|
||||
AZ_Assert(listCallback, "ClaimEntities called on spawnable entities without a valid callback to use.");
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to ClaimEntities hasn't been initialized.");
|
||||
|
||||
ClaimEntitiesCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
@@ -109,6 +134,7 @@ namespace AzFramework
|
||||
void SpawnableEntitiesManager::Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback)
|
||||
{
|
||||
AZ_Assert(completionCallback, "Barrier on spawnable entities called without a valid callback to use.");
|
||||
AZ_Assert(ticket.IsValid(), "Ticket provided to Barrier hasn't been initialized.");
|
||||
|
||||
BarrierCommand queueEntry;
|
||||
queueEntry.m_ticket = &ticket;
|
||||
@@ -499,6 +525,27 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
bool SpawnableEntitiesManager::ProcessRequest(ListIndicesEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
Ticket& ticket = GetTicketPayload<Ticket>(*request.m_ticket);
|
||||
if (request.m_ticketId == ticket.m_currentTicketId)
|
||||
{
|
||||
AZ_Assert(
|
||||
ticket.m_spawnedEntities.size() == ticket.m_spawnedEntityIndices.size(),
|
||||
"Entities and indices on spawnable ticket have gone out of sync.");
|
||||
request.m_listCallback(
|
||||
*request.m_ticket,
|
||||
SpawnableConstIndexEntityContainerView(
|
||||
ticket.m_spawnedEntities.begin(), ticket.m_spawnedEntityIndices.begin(), ticket.m_spawnedEntities.size()));
|
||||
ticket.m_currentTicketId++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpawnableEntitiesManager::ProcessRequest(ClaimEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
Ticket& ticket = GetTicketPayload<Ticket>(*request.m_ticket);
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace AzFramework
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AzFramework::SpawnableEntitiesManager, "{6E14333F-128C-464C-94CA-A63B05A5E51C}");
|
||||
AZ_CLASS_ALLOCATOR(SpawnableEntitiesManager, AZ::SystemAllocator, 0);
|
||||
|
||||
enum class CommandQueueStatus : bool
|
||||
{
|
||||
@@ -58,6 +59,7 @@ namespace AzFramework
|
||||
ReloadSpawnableCallback completionCallback = {}) override;
|
||||
|
||||
void ListEntities(EntitySpawnTicket& ticket, ListEntitiesCallback listCallback) override;
|
||||
void ListIndicesAndEntities(EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback) override;
|
||||
void ClaimEntities(EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback) override;
|
||||
|
||||
void Barrier(EntitySpawnTicket& spawnInfo, BarrierCallback completionCallback) override;
|
||||
@@ -123,6 +125,12 @@ namespace AzFramework
|
||||
EntitySpawnTicket* m_ticket;
|
||||
uint32_t m_ticketId;
|
||||
};
|
||||
struct ListIndicesEntitiesCommand
|
||||
{
|
||||
ListIndicesEntitiesCallback m_listCallback;
|
||||
EntitySpawnTicket* m_ticket;
|
||||
uint32_t m_ticketId;
|
||||
};
|
||||
struct ClaimEntitiesCommand
|
||||
{
|
||||
ClaimEntitiesCallback m_listCallback;
|
||||
@@ -141,8 +149,9 @@ namespace AzFramework
|
||||
uint32_t m_ticketId;
|
||||
};
|
||||
|
||||
using Requests = AZStd::variant<SpawnAllEntitiesCommand, SpawnEntitiesCommand, DespawnAllEntitiesCommand, ReloadSpawnableCommand,
|
||||
ListEntitiesCommand, ClaimEntitiesCommand, BarrierCommand, DestroyTicketCommand>;
|
||||
using Requests = AZStd::variant<
|
||||
SpawnAllEntitiesCommand, SpawnEntitiesCommand, DespawnAllEntitiesCommand, ReloadSpawnableCommand, ListEntitiesCommand,
|
||||
ListIndicesEntitiesCommand, ClaimEntitiesCommand, BarrierCommand, DestroyTicketCommand>;
|
||||
|
||||
AZ::Entity* SpawnSingleEntity(const AZ::Entity& entityTemplate,
|
||||
AZ::SerializeContext& serializeContext);
|
||||
@@ -155,6 +164,7 @@ namespace AzFramework
|
||||
bool ProcessRequest(DespawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(ReloadSpawnableCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(ListEntitiesCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(ListIndicesEntitiesCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(ClaimEntitiesCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(BarrierCommand& request, AZ::SerializeContext& serializeContext);
|
||||
bool ProcessRequest(DestroyTicketCommand& request, AZ::SerializeContext& serializeContext);
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesManager.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class TestApplication : public AzFramework::Application
|
||||
{
|
||||
public:
|
||||
// ComponentApplication
|
||||
void SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations) override
|
||||
{
|
||||
Application::SetSettingsRegistrySpecializations(specializations);
|
||||
specializations.Append("test");
|
||||
specializations.Append("spawnable");
|
||||
}
|
||||
};
|
||||
|
||||
class SpawnableEntitiesManagerTest : public AllocatorsFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_application = new TestApplication();
|
||||
AZ::ComponentApplication::Descriptor descriptor;
|
||||
m_application->Start(descriptor);
|
||||
|
||||
m_spawnable = aznew AzFramework::Spawnable(
|
||||
AZ::Data::AssetId::CreateString("{EB2E8A2B-F253-4A90-BBF4-55F2EED786B8}:0"), AZ::Data::AssetData::AssetStatus::Ready);
|
||||
m_spawnableAsset = new AZ::Data::Asset<AzFramework::Spawnable>(m_spawnable, AZ::Data::AssetLoadBehavior::Default);
|
||||
m_ticket = new AzFramework::EntitySpawnTicket(*m_spawnableAsset);
|
||||
|
||||
auto managerInterface = AzFramework::SpawnableEntitiesInterface::Get();
|
||||
m_manager = azrtti_cast<AzFramework::SpawnableEntitiesManager*>(managerInterface);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
delete m_ticket;
|
||||
m_ticket = nullptr;
|
||||
// One more tick on the spawnable entities manager in order to delete the ticket fully.
|
||||
m_manager->ProcessQueue();
|
||||
|
||||
delete m_spawnableAsset;
|
||||
m_spawnableAsset = nullptr;
|
||||
// This will also delete m_spawnable.
|
||||
|
||||
delete m_application;
|
||||
m_application = nullptr;
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
void FillSpawnable(size_t numElements)
|
||||
{
|
||||
AzFramework::Spawnable::EntityList& entities = m_spawnable->GetEntities();
|
||||
entities.reserve(numElements);
|
||||
for (size_t i=0; i<numElements; ++i)
|
||||
{
|
||||
entities.push_back(AZStd::make_unique<AZ::Entity>());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
AZ::Data::Asset<AzFramework::Spawnable>* m_spawnableAsset { nullptr };
|
||||
AzFramework::SpawnableEntitiesManager* m_manager { nullptr };
|
||||
AzFramework::EntitySpawnTicket* m_ticket { nullptr };
|
||||
AzFramework::Spawnable* m_spawnable { nullptr };
|
||||
TestApplication* m_application { nullptr };
|
||||
};
|
||||
|
||||
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_Call_AllEntitiesSpawned)
|
||||
{
|
||||
static constexpr size_t NumEntities = 4;
|
||||
FillSpawnable(NumEntities);
|
||||
|
||||
size_t spawnedEntitiesCount = 0;
|
||||
auto callback =
|
||||
[&spawnedEntitiesCount](AzFramework::EntitySpawnTicket&, AzFramework::SpawnableConstEntityContainerView entities)
|
||||
{
|
||||
spawnedEntitiesCount += entities.size();
|
||||
};
|
||||
m_manager->SpawnAllEntities(*m_ticket, {}, AZStd::move(callback));
|
||||
m_manager->ProcessQueue();
|
||||
|
||||
EXPECT_EQ(NumEntities, spawnedEntitiesCount);
|
||||
}
|
||||
|
||||
TEST_F(SpawnableEntitiesManagerTest, ListEntities_Call_AllEntitiesAreReported)
|
||||
{
|
||||
static constexpr size_t NumEntities = 4;
|
||||
FillSpawnable(NumEntities);
|
||||
|
||||
bool allValidEntityIds = true;
|
||||
size_t spawnedEntitiesCount = 0;
|
||||
auto callback = [&allValidEntityIds, &spawnedEntitiesCount]
|
||||
(AzFramework::EntitySpawnTicket&, AzFramework::SpawnableConstEntityContainerView entities)
|
||||
{
|
||||
for (auto&& entity : entities)
|
||||
{
|
||||
allValidEntityIds = entity->GetId().IsValid() && allValidEntityIds;
|
||||
}
|
||||
spawnedEntitiesCount += entities.size();
|
||||
};
|
||||
|
||||
m_manager->SpawnAllEntities(*m_ticket);
|
||||
m_manager->ListEntities(*m_ticket, AZStd::move(callback));
|
||||
m_manager->ProcessQueue();
|
||||
|
||||
EXPECT_TRUE(allValidEntityIds);
|
||||
EXPECT_EQ(NumEntities, spawnedEntitiesCount);
|
||||
}
|
||||
|
||||
TEST_F(SpawnableEntitiesManagerTest, ListIndicesAndEntities_Call_AllEntitiesAreReportedAndIncrementByOne)
|
||||
{
|
||||
static constexpr size_t NumEntities = 4;
|
||||
FillSpawnable(NumEntities);
|
||||
|
||||
bool allValidEntityIds = true;
|
||||
size_t spawnedEntitiesCount = 0;
|
||||
auto callback = [&allValidEntityIds, &spawnedEntitiesCount]
|
||||
(AzFramework::EntitySpawnTicket&, AzFramework::SpawnableConstIndexEntityContainerView entities)
|
||||
{
|
||||
for (auto&& indexEntityPair : entities)
|
||||
{
|
||||
// Since all entities are spawned a single time, the indices should be 0..NumEntities.
|
||||
if (indexEntityPair.GetIndex() == spawnedEntitiesCount)
|
||||
{
|
||||
spawnedEntitiesCount++;
|
||||
}
|
||||
allValidEntityIds = indexEntityPair.GetEntity()->GetId().IsValid() && allValidEntityIds;
|
||||
}
|
||||
};
|
||||
|
||||
m_manager->SpawnAllEntities(*m_ticket);
|
||||
m_manager->ListIndicesAndEntities(*m_ticket, AZStd::move(callback));
|
||||
m_manager->ProcessQueue();
|
||||
|
||||
EXPECT_TRUE(allValidEntityIds);
|
||||
EXPECT_EQ(NumEntities, spawnedEntitiesCount);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
set(FILES
|
||||
../AzCore/Tests/Main.cpp
|
||||
Spawnable/SpawnableEntitiesManagerTests.cpp
|
||||
ArchiveCompressionTests.cpp
|
||||
ArchiveTests.cpp
|
||||
BehaviorEntityTests.cpp
|
||||
|
||||
Reference in New Issue
Block a user