You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Framework/AzFramework/AzFramework/Scene/SceneSystemComponent.cpp

158 lines
5.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 <AzFramework/Scene/SceneSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
namespace AzFramework
{
void SceneSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SceneSystemComponent, AZ::Component>();
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<SceneSystemComponent>(
"Scene System Component", "System component responsible for owning scenes")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Editor")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
;
}
}
}
SceneSystemComponent::SceneSystemComponent() = default;
SceneSystemComponent::~SceneSystemComponent() = default;
void SceneSystemComponent::Activate()
{
}
void SceneSystemComponent::Deactivate()
{
}
void SceneSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("SceneSystemComponentService", 0xd8975435));
}
void SceneSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("SceneSystemComponentService", 0xd8975435));
}
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> SceneSystemComponent::CreateScene(AZStd::string_view name)
{
return CreateSceneWithParent(name, nullptr);
}
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> SceneSystemComponent::CreateSceneWithParent(
AZStd::string_view name, AZStd::shared_ptr<Scene> parent)
{
const AZStd::shared_ptr<Scene>& existingScene = GetScene(name);
if (existingScene)
{
return AZ::Failure<AZStd::string>("A scene already exists with this name.");
}
auto newScene = AZStd::make_shared<Scene>(name, AZStd::move(parent));
m_activeScenes.push_back(newScene);
{
AZStd::lock_guard lock(m_eventMutex);
m_events.Signal(EventType::SceneCreated, newScene);
}
return AZ::Success(AZStd::move(newScene));
}
AZStd::shared_ptr<Scene> SceneSystemComponent::GetScene(AZStd::string_view name)
{
auto sceneIterator = AZStd::find_if(m_activeScenes.begin(), m_activeScenes.end(),
[name](auto& scene) -> bool
{
return scene->GetName() == name;
}
);
return sceneIterator == m_activeScenes.end() ? nullptr : *sceneIterator;
}
void SceneSystemComponent::IterateActiveScenes(const ActiveIterationCallback& callback)
{
bool keepGoing = true;
auto end = m_activeScenes.end();
for (auto it = m_activeScenes.begin(); it != end && keepGoing; ++it)
{
keepGoing = callback(*it);
}
}
void SceneSystemComponent::IterateZombieScenes(const ZombieIterationCallback& callback)
{
bool keepGoing = true;
auto end = m_zombieScenes.end();
for (auto it = m_zombieScenes.begin(); it != end && keepGoing;)
{
if (!it->expired())
{
keepGoing = callback(*(it->lock()));
++it;
}
else
{
*it = m_zombieScenes.back();
m_zombieScenes.pop_back();
end = m_zombieScenes.end();
}
}
}
bool SceneSystemComponent::RemoveScene(AZStd::string_view name)
{
for (AZStd::shared_ptr<Scene>& scene : m_activeScenes)
{
if (scene->GetName() == name)
{
MarkSceneForDestruction(*scene);
{
AZStd::lock_guard lock(m_eventMutex);
m_events.Signal(EventType::ScenePendingRemoval, scene);
}
// Zombies are weak pointers that are kept around for situations where there's a delay in deleting the scene. This can happen
// if there are outstanding calls like in-progress async calls or resources locked by hardware. A weak_ptr of the original
// scene is kept so the zombie scene can still be found through iteration as it may require additional calls such as Tick calls.
m_zombieScenes.push_back(scene);
scene = AZStd::move(m_activeScenes.back());
m_activeScenes.pop_back();
// The scene may not be held onto anymore, so check here to see if the previously added zombie can be released.
if (m_zombieScenes.back().expired())
{
m_zombieScenes.pop_back();
}
return true;
}
}
AZ_Warning("SceneSystemComponent", false, R"(Attempting to remove scene name "%.*s", but that scene was not found.)", AZ_STRING_ARG(name));
return false;
}
void SceneSystemComponent::ConnectToEvents(SceneEvent::Handler& handler)
{
AZStd::lock_guard lock(m_eventMutex);
handler.Connect(m_events);
}
} // namespace AzFramework