a05d5f5d6d
Entity aliases can now be updated as a reaction to the spawnable being loaded or at any other time afterwards through the Spawnable Entities Interface. Currently these changes are applied to the spawnable that owns the entity aliases, but once the Spawnable Entities Interface makes use of AzFramework::Scene a copy of the entity aliases should be stored in the scene and be updated instead of the spawnable. This change also adds support for a load barrier, which acts the same as a regular barrier but also accounts for the spawnable being loaded and won't trigger the callback until has completed. The return values in from the processing functions in the Spawnable Entities Manager now have a clearer return value to indicate whether a request has completed or is being re-queued. Signed-off-by: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com>
121 lines
4.6 KiB
C++
121 lines
4.6 KiB
C++
/*
|
|
* 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/std/smart_ptr/make_shared.h>
|
|
#include <AzFramework/Spawnable/SpawnableEntitiesContainer.h>
|
|
|
|
namespace AzFramework
|
|
{
|
|
SpawnableEntitiesContainer::SpawnableEntitiesContainer(AZ::Data::Asset<Spawnable> spawnable)
|
|
{
|
|
Connect(AZStd::move(spawnable));
|
|
}
|
|
|
|
SpawnableEntitiesContainer::~SpawnableEntitiesContainer()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
bool SpawnableEntitiesContainer::IsSet() const
|
|
{
|
|
return m_threadData != nullptr;
|
|
}
|
|
|
|
uint32_t SpawnableEntitiesContainer::GetCurrentGeneration() const
|
|
{
|
|
return m_currentGeneration;
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::SpawnAllEntities()
|
|
{
|
|
AZ_Assert(m_threadData, "Calling SpawnAllEntities on a Spawnable container that's not set.");
|
|
SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_threadData->m_spawnedEntitiesTicket);
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::SpawnEntities(AZStd::vector<uint32_t> entityIndices)
|
|
{
|
|
AZ_Assert(m_threadData, "Calling SpawnEntities on a Spawnable container that's not set.");
|
|
SpawnableEntitiesInterface::Get()->SpawnEntities(
|
|
m_threadData->m_spawnedEntitiesTicket, AZStd::move(entityIndices));
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::DespawnAllEntities()
|
|
{
|
|
AZ_Assert(m_threadData, "Calling DespawnEntities on a Spawnable container that's not set.");
|
|
SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_threadData->m_spawnedEntitiesTicket);
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::Reset(AZ::Data::Asset<Spawnable> spawnable)
|
|
{
|
|
Clear();
|
|
Connect(AZStd::move(spawnable));
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::Clear()
|
|
{
|
|
if (m_threadData != nullptr)
|
|
{
|
|
m_monitor.Disconnect();
|
|
m_monitor.m_threadData.reset();
|
|
|
|
SpawnableEntitiesInterface::Get()->Barrier(
|
|
m_threadData->m_spawnedEntitiesTicket,
|
|
[threadData = m_threadData](EntitySpawnTicket::Id) mutable
|
|
{
|
|
threadData.reset();
|
|
});
|
|
|
|
m_threadData.reset();
|
|
// The generation is incremented here instead of Connect in order to make sure that any callback that checks the
|
|
// provided generation with the current generation is aware that the container has moved on to the next iteration
|
|
// of the container even though it's empty and unassigned at this point.
|
|
m_currentGeneration++;
|
|
}
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::Alert(AlertCallback callback, CheckIfSpawnableIsLoaded spawnableCheck)
|
|
{
|
|
AZ_Assert(m_threadData, "Calling DespawnEntities on a Spawnable container that's not set.");
|
|
auto callbackWrapper = [generation = m_threadData->m_generation, callback = AZStd::move(callback)](EntitySpawnTicket::Id)
|
|
{
|
|
callback(generation);
|
|
};
|
|
if (spawnableCheck == CheckIfSpawnableIsLoaded::No)
|
|
{
|
|
SpawnableEntitiesInterface::Get()->Barrier(m_threadData->m_spawnedEntitiesTicket, AZStd::move(callbackWrapper));
|
|
}
|
|
else
|
|
{
|
|
SpawnableEntitiesInterface::Get()->LoadBarrier(m_threadData->m_spawnedEntitiesTicket, AZStd::move(callbackWrapper));
|
|
}
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::Connect(AZ::Data::Asset<Spawnable> spawnable)
|
|
{
|
|
AZ::Data::AssetId spawnableId = spawnable.GetId();
|
|
|
|
AZ_Assert(m_threadData == nullptr, "Connecting a spawnable entities container that's already connected.");
|
|
AZ_Assert(m_monitor.m_threadData == nullptr, "Connecting a spawnable entities monitor that's already connected.");
|
|
|
|
m_threadData = AZStd::make_shared<ThreadSafeData>();
|
|
m_threadData->m_spawnedEntitiesTicket = EntitySpawnTicket(AZStd::move(spawnable));
|
|
m_threadData->m_generation = m_currentGeneration;
|
|
|
|
m_monitor.m_threadData = m_threadData;
|
|
m_monitor.Connect(spawnableId);
|
|
}
|
|
|
|
void SpawnableEntitiesContainer::Monitor::OnSpawnableReloaded(AZ::Data::Asset<Spawnable>&& replacementAsset)
|
|
{
|
|
AZ_Assert(m_threadData, "SpawnableEntitiesContainer is monitoring a spawnable, but doesn't have the associated data.");
|
|
|
|
AZ_TracePrintf("Spawnables", "Reloading spawnable '%s'.\n", replacementAsset.GetHint().c_str());
|
|
SpawnableEntitiesInterface::Get()->ReloadSpawnable(m_threadData->m_spawnedEntitiesTicket, AZStd::move(replacementAsset));
|
|
}
|
|
} // namespace AzFramework
|