Updates in preparation for adding entity aliases to spawnables.

The following has been changed:
- AssetDataStream can now return the stored streaming deadline and priority.
- RootSpawnable now has an event that's called just before root spawnable spawns entities. This is an immediate event unlike the other events that are queued.

Signed-off-by: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com>
This commit is contained in:
AMZN-koppersr
2021-10-25 13:43:00 -07:00
parent e4df621f88
commit 48f2487d3c
5 changed files with 45 additions and 16 deletions
@@ -70,6 +70,9 @@ namespace AZ::Data
const char* GetFilename() const override { return m_filePath.c_str(); }
AZStd::chrono::milliseconds GetStreamingDeadline() const { return m_curDeadline; }
AZ::IO::IStreamerTypes::Priority GetStreamingPriority() const { return m_curPriority; }
// AssetDataStream specific APIs
//! Whether or not all data has been loaded.
@@ -30,12 +30,22 @@ namespace AzFramework
//! Called when the root spawnable has been assigned a new value. This may be called several times without a call to release
//! in between.
//! NOTE: The callback is not queued but immediately called from a random thread. This is done because this callback is typically
//! used before entities are spawned and if it's queued then the entities spawn before this callback is called.
//! @param rootSpawnable The new root spawnable that was assigned.
//! @param generation The generation of the root spawnable. This will increment every time a new spawnable is assigned.
virtual void OnRootSpawnableAssigned([[maybe_unused]] AZ::Data::Asset<Spawnable> rootSpawnable,
[[maybe_unused]] uint32_t generation) {}
//! Called when the root spawnable has completed spawning of entities. This may be called several times without a call to release
//! in between.
//! NOTE: This callback is queued and will be called with a delay and from the main thread.
//! @param rootSpawnable The new root spawnable that was used to spawn entities from.
//! @param generation The generation of the root spawnable. This will increment every time a new spawnable is assigned.
virtual void OnRootSpawnableReady(
[[maybe_unused]] AZ::Data::Asset<Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation) {}
//! Called when the root spawnable has Released. This will only be called if there's no root spawnable assigned to take the
//! place of the original root spawnable.
//! Note: This callback is queued and will be called with a delay and from the main thread.
//! @param generation The generation of the root spawnable that was released.
virtual void OnRootSpawnableReleased([[maybe_unused]] uint32_t generation) {}
};
@@ -72,7 +72,7 @@ namespace AzFramework
uint64_t SpawnableSystemComponent::AssignRootSpawnable(AZ::Data::Asset<Spawnable> rootSpawnable)
{
uint64_t generation = 0;
uint32_t generation = 0;
if (m_rootSpawnableId == rootSpawnable.GetId())
{
@@ -87,16 +87,25 @@ namespace AzFramework
// Suspend and resume processing in the container that completion calls aren't received until
// everything has been setup to accept callbacks from the call.
m_rootSpawnableContainer.Reset(rootSpawnable);
m_rootSpawnableContainer.SpawnAllEntities();
generation = m_rootSpawnableContainer.GetCurrentGeneration();
AZ_TracePrintf("Spawnables", "Root spawnable set to '%s' at generation %zu.\n", rootSpawnable.GetHint().c_str(),
generation);
// Don't send out the alert that the root spawnable has been assigned until the spawnable itself is ready. The common
// use case is for handlers to do something with the information in the spawnable before the entities get spawned.
m_rootSpawnableContainer.Alert(
[rootSpawnable](uint32_t generation)
{
RootSpawnableNotificationBus::Broadcast(
&RootSpawnableNotificationBus::Events::OnRootSpawnableAssigned, AZStd::move(rootSpawnable), generation);
}, SpawnableEntitiesContainer::CheckIfSpawnableIsLoaded::Yes);
m_rootSpawnableContainer.SpawnAllEntities();
m_rootSpawnableContainer.Alert(
[newSpawnable = AZStd::move(rootSpawnable)](uint32_t generation)
{
RootSpawnableNotificationBus::QueueBroadcast(
&RootSpawnableNotificationBus::Events::OnRootSpawnableAssigned, newSpawnable, generation);
&RootSpawnableNotificationBus::Events::OnRootSpawnableReady, AZStd::move(newSpawnable), generation);
});
AZ_TracePrintf("Spawnables", "Root spawnable set to '%s' at generation %zu.\n", rootSpawnable.GetHint().c_str(), generation);
}
else
{
@@ -132,6 +141,12 @@ namespace AzFramework
AZ_TracePrintf("Spawnables", "New root spawnable '%s' assigned (generation: %i).\n", rootSpawnable.GetHint().c_str(), generation);
}
void SpawnableSystemComponent::OnRootSpawnableReady(
[[maybe_unused]] AZ::Data::Asset<Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
{
AZ_TracePrintf("Spawnables", "Entities from new root spawnable '%s' are ready (generation: %i).\n", rootSpawnable.GetHint().c_str(), generation);
}
void SpawnableSystemComponent::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
{
AZ_TracePrintf("Spawnables", "Generation %i of the root spawnable has been released.\n", generation);
@@ -82,6 +82,7 @@ namespace AzFramework
//
void OnRootSpawnableAssigned(AZ::Data::Asset<Spawnable> rootSpawnable, uint32_t generation) override;
void OnRootSpawnableReady(AZ::Data::Asset<Spawnable> rootSpawnable, uint32_t generation) override;
void OnRootSpawnableReleased(uint32_t generation) override;
protected:
@@ -581,15 +581,15 @@ namespace AzToolsFramework
{
if (m_rootInstance && m_playInEditorData.m_isEnabled)
{
AZ_Assert(m_playInEditorData.m_entities.IsSet(),
AZ_Assert(
m_playInEditorData.m_entities.IsSet(),
"Invalid Game Mode Entities Container encountered after play-in-editor stopped. "
"Confirm that the container was initialized correctly");
m_playInEditorData.m_entities.DespawnAllEntities();
m_playInEditorData.m_entities.Alert(
[assets = AZStd::move(m_playInEditorData.m_assets),
deactivatedEntities = AZStd::move(m_playInEditorData.m_deactivatedEntities)]
([[maybe_unused]]uint32_t generation) mutable
deactivatedEntities = AZStd::move(m_playInEditorData.m_deactivatedEntities)]([[maybe_unused]] uint32_t generation) mutable
{
auto end = deactivatedEntities.rend();
for (auto it = deactivatedEntities.rbegin(); it != end; ++it)
@@ -614,15 +614,15 @@ namespace AzToolsFramework
AzFramework::GameEntityContextEventBus::Broadcast(&AzFramework::GameEntityContextEventBus::Events::OnGameEntitiesReset);
});
m_playInEditorData.m_entities.Clear();
}
// Game entity cleanup is queued onto the next tick via the DespawnEntities call.
// To avoid both game entities and Editor entities active at the same time
// we flush the tick queue to ensure the game entities are cleared first.
// The Alert callback that follows the DespawnEntities call will then reactivate the editor entities
// This should be considered temporary as a move to a less rigid event sequence that supports async entity clean up
// is the desired direction forward.
AZ::TickBus::ExecuteQueuedEvents();
// Game entity cleanup is queued onto the next tick via the DespawnEntities call.
// To avoid both game entities and Editor entities active at the same time
// we flush the tick queue to ensure the game entities are cleared first.
// The Alert callback that follows the DespawnEntities call will then reactivate the editor entities
// This should be considered temporary as a move to a less rigid event sequence that supports async entity clean up
// is the desired direction forward.
AZ::TickBus::ExecuteQueuedEvents();
}
m_playInEditorData.m_isEnabled = false;
}