Merge remote-tracking branch 'upstream/stabilization/2110' into nvsickle/FixEntityOrdering
This commit is contained in:
@@ -65,8 +65,35 @@ namespace AZ
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides - Application is a singleton
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
typedef AZStd::recursive_mutex MutexType;
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
|
||||
static constexpr bool EnableEventQueue = true;
|
||||
using EventQueueMutexType = AZStd::mutex;
|
||||
struct PostThreadDispatchInvoker
|
||||
{
|
||||
~PostThreadDispatchInvoker();
|
||||
};
|
||||
|
||||
template <typename DispatchMutex>
|
||||
struct ThreadDispatchLockGuard
|
||||
{
|
||||
ThreadDispatchLockGuard(DispatchMutex& contextMutex)
|
||||
: m_lock{ contextMutex }
|
||||
{}
|
||||
ThreadDispatchLockGuard(DispatchMutex& contextMutex, AZStd::adopt_lock_t adopt_lock)
|
||||
: m_lock{ contextMutex, adopt_lock }
|
||||
{}
|
||||
ThreadDispatchLockGuard(const ThreadDispatchLockGuard&) = delete;
|
||||
ThreadDispatchLockGuard& operator=(const ThreadDispatchLockGuard&) = delete;
|
||||
private:
|
||||
PostThreadDispatchInvoker m_threadPolicyInvoker;
|
||||
using LockType = AZStd::conditional_t<LocklessDispatch, AZ::Internal::NullLockGuard<DispatchMutex>, AZStd::scoped_lock<DispatchMutex>>;
|
||||
LockType m_lock;
|
||||
};
|
||||
|
||||
template <typename DispatchMutex, bool>
|
||||
using DispatchLockGuard = ThreadDispatchLockGuard<DispatchMutex>;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~AssetCatalogRequests() = default;
|
||||
@@ -200,6 +227,17 @@ namespace AZ
|
||||
|
||||
using AssetCatalogRequestBus = AZ::EBus<AssetCatalogRequests>;
|
||||
|
||||
inline AssetCatalogRequests::PostThreadDispatchInvoker::~PostThreadDispatchInvoker()
|
||||
{
|
||||
if (!AssetCatalogRequestBus::IsInDispatchThisThread())
|
||||
{
|
||||
if (AssetCatalogRequestBus::QueuedEventCount())
|
||||
{
|
||||
AssetCatalogRequestBus::ExecuteQueuedEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Events that AssetManager listens for
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/ComponentApplicationLifecycle.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
#include <AzCore/Debug/LocalFileEventLogger.h>
|
||||
@@ -44,8 +45,6 @@
|
||||
#include <AzCore/Module/Module.h>
|
||||
#include <AzCore/Module/ModuleManager.h>
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/Path/Path_fwd.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
@@ -215,12 +214,6 @@ namespace AZ
|
||||
// Update old Project path before attempting to merge in new Settings Registry values in order to prevent recursive calls
|
||||
m_oldProjectPath = newProjectPath;
|
||||
|
||||
// Merge the project.json file into settings registry under ProjectSettingsRootKey path.
|
||||
AZ::IO::FixedMaxPath projectMetadataFile{ AZ::SettingsRegistryMergeUtils::FindEngineRoot(m_registry) / newProjectPath };
|
||||
projectMetadataFile /= "project.json";
|
||||
m_registry.MergeSettingsFile(projectMetadataFile.Native(),
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey);
|
||||
|
||||
// Update all the runtime file paths based on the new "project_path" value.
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry);
|
||||
}
|
||||
@@ -506,6 +499,16 @@ namespace AZ
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry);
|
||||
|
||||
// The /O3DE/Application/LifecycleEvents array contains a valid set of lifecycle events
|
||||
// Those lifecycle events are normally read from the <engine-root>/Registry
|
||||
// which isn't merged until ComponentApplication::Create invokes MergeSettingsToRegistry
|
||||
// So pre-populate the valid lifecycle even entries
|
||||
ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "SystemAllocatorCreated");
|
||||
ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "SettingsRegistryAvailable");
|
||||
ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "ConsoleAvailable");
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SystemAllocatorCreated", R"({})");
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SettingsRegistryAvailable", R"({})");
|
||||
|
||||
// Create the Module Manager
|
||||
m_moduleManager = AZStd::make_unique<ModuleManager>();
|
||||
|
||||
@@ -520,6 +523,7 @@ namespace AZ
|
||||
m_ownsConsole = true;
|
||||
m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
|
||||
m_settingsRegistryConsoleFunctors = AZ::SettingsRegistryConsoleUtils::RegisterAzConsoleCommands(*m_settingsRegistry, *m_console);
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ConsoleAvailable", R"({})");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +555,7 @@ namespace AZ
|
||||
{
|
||||
AZ::Interface<AZ::IConsole>::Unregister(m_console);
|
||||
delete m_console;
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ConsoleUnavailable", R"({})");
|
||||
}
|
||||
|
||||
m_moduleManager.reset();
|
||||
@@ -558,6 +563,8 @@ namespace AZ
|
||||
if (AZ::SettingsRegistry::Get() == m_settingsRegistry.get())
|
||||
{
|
||||
SettingsRegistry::Unregister(m_settingsRegistry.get());
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SettingsRegistryUnavailable", R"({})");
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SystemAllocatorPendingDestruction", R"({})");
|
||||
}
|
||||
m_settingsRegistry.reset();
|
||||
|
||||
@@ -672,6 +679,8 @@ namespace AZ
|
||||
ReflectionEnvironment::GetReflectionManager()->Reflect(azrtti_typeid(this), [this](ReflectContext* context) {Reflect(context); });
|
||||
|
||||
RegisterCoreComponents();
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ReflectionManagerAvailable", R"({})");
|
||||
|
||||
TickBus::AllowFunctionQueuing(true);
|
||||
SystemTickBus::AllowFunctionQueuing(true);
|
||||
|
||||
@@ -691,6 +700,7 @@ namespace AZ
|
||||
|
||||
// Load the actual modules
|
||||
LoadModules();
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsLoaded", R"({})");
|
||||
|
||||
// Execute user.cfg after modules have been loaded but before processing any command-line overrides
|
||||
AZ::IO::FixedMaxPath platformCachePath;
|
||||
@@ -756,12 +766,14 @@ namespace AZ
|
||||
m_entities.rehash(0); // force free all memory
|
||||
|
||||
DestroyReflectionManager();
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ReflectionManagerUnavailable", R"({})");
|
||||
|
||||
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearNotifiers();
|
||||
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearMergeEvents();
|
||||
|
||||
// Uninit and unload any dynamic modules.
|
||||
m_moduleManager->UnloadModules();
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsUnloaded", R"({})");
|
||||
|
||||
NameDictionary::Destroy();
|
||||
|
||||
|
||||
@@ -175,6 +175,8 @@ namespace AZ
|
||||
bool m_loadDynamicModules = true;
|
||||
//! Used by test fixtures to ensure reflection occurs to edit context.
|
||||
bool m_createEditContext = false;
|
||||
//! Indicates whether the AssetCatalog.xml should be loaded by default in Application::StartCommon
|
||||
bool m_loadAssetCatalog = true;
|
||||
};
|
||||
|
||||
ComponentApplication();
|
||||
@@ -356,7 +358,7 @@ namespace AZ
|
||||
/// Calculates the root directory of the engine.
|
||||
void CalculateEngineRoot();
|
||||
|
||||
/// Calculates the directory where the bootstrap.cfg file resides.
|
||||
/// Deprecated: The term "AppRoot" has no meaning
|
||||
void CalculateAppRoot();
|
||||
|
||||
template<typename Iterator>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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/Component/ComponentApplicationLifecycle.h>
|
||||
#include <AzCore/Settings/SettingsRegistryVisitorUtils.h>
|
||||
|
||||
namespace AZ::ComponentApplicationLifecycle
|
||||
{
|
||||
bool ValidateEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName)
|
||||
{
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
using Type = SettingsRegistryInterface::Type;
|
||||
FixedValueString eventRegistrationKey{ ApplicationLifecycleEventRegistrationKey };
|
||||
eventRegistrationKey += '/';
|
||||
eventRegistrationKey += eventName;
|
||||
return settingsRegistry.GetType(eventRegistrationKey) == Type::Object;
|
||||
}
|
||||
|
||||
bool SignalEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName, AZStd::string_view eventValue)
|
||||
{
|
||||
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
|
||||
using Format = AZ::SettingsRegistryInterface::Format;
|
||||
|
||||
if (!ValidateEvent(settingsRegistry, eventName))
|
||||
{
|
||||
AZ_Warning("ComponentApplicationLifecycle", false, R"(Cannot signal event %.*s. Name does is not a field of object "%.*s".)"
|
||||
R"( Please make sure the entry exists in the '<engine-root>/Registry/application_lifecycle_events.setreg")"
|
||||
" or in *.setreg within the project", AZ_STRING_ARG(eventName), AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey));
|
||||
return false;
|
||||
}
|
||||
auto eventRegistrationKey = FixedValueString::format("%.*s/%.*s", AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey),
|
||||
AZ_STRING_ARG(eventName));
|
||||
|
||||
return settingsRegistry.MergeSettings(eventValue, Format::JsonMergePatch, eventRegistrationKey);
|
||||
}
|
||||
|
||||
bool RegisterEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName)
|
||||
{
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
using Format = AZ::SettingsRegistryInterface::Format;
|
||||
|
||||
if (!ValidateEvent(settingsRegistry, eventName))
|
||||
{
|
||||
FixedValueString eventRegistrationKey{ ApplicationLifecycleEventRegistrationKey };
|
||||
eventRegistrationKey += '/';
|
||||
eventRegistrationKey += eventName;
|
||||
return settingsRegistry.MergeSettings(R"({})", Format::JsonMergePatch, eventRegistrationKey);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
|
||||
AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent)
|
||||
{
|
||||
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
|
||||
using Type = AZ::SettingsRegistryInterface::Type;
|
||||
using NotifyEventHandler = AZ::SettingsRegistryInterface::NotifyEventHandler;
|
||||
|
||||
// Some systems may attempt to register a handler before the settings registry has been loaded
|
||||
// If so, this flag lets them automatically register an event if it hasn't yet been registered.
|
||||
// RegisterEvent calls validate event.
|
||||
if ((!autoRegisterEvent && !ValidateEvent(settingsRegistry, eventName)) ||
|
||||
(autoRegisterEvent && !RegisterEvent(settingsRegistry, eventName)))
|
||||
{
|
||||
AZ_Warning(
|
||||
"ComponentApplicationLifecycle", false,
|
||||
R"(Cannot register event %.*s. Name is not a field of object "%.*s".)"
|
||||
R"( Please make sure the entry exists in the '<engine-root>/Registry/application_lifecycle_events.setreg")"
|
||||
" or in *.setreg within the project", AZ_STRING_ARG(eventName), AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey));
|
||||
return false;
|
||||
}
|
||||
auto eventNameRegistrationKey = FixedValueString::format("%.*s/%.*s", AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey),
|
||||
AZ_STRING_ARG(eventName));
|
||||
auto lifecycleCallback = [callback = AZStd::move(callback), eventNameRegistrationKey](AZStd::string_view path, Type type)
|
||||
{
|
||||
if (path == eventNameRegistrationKey)
|
||||
{
|
||||
callback(path, type);
|
||||
}
|
||||
};
|
||||
|
||||
handler = NotifyEventHandler(AZStd::move(lifecycleCallback));
|
||||
settingsRegistry.RegisterNotifier(handler);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
|
||||
namespace AZ::ComponentApplicationLifecycle
|
||||
{
|
||||
//! Root Key where lifecycle events should be registered under
|
||||
inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Application/LifecycleEvents";
|
||||
|
||||
|
||||
//! Validates that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey
|
||||
//! @param settingsRegistry registry where @eventName will be searched
|
||||
//! @param eventName name of key that validated that exists as an element in the ApplicationLifecycleEventRegistrationKey array
|
||||
//! @return true if the @eventName was found in the ApplicationLifecycleEventRegistrationKey array
|
||||
bool ValidateEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName);
|
||||
|
||||
//! Wrapper around setting a value underneath the ApplicationLifecycleEventRegistrationKey
|
||||
//! It validates if the @eventName is is part of the ApplicationLifecycleEventRegistrationKey array
|
||||
//! It then appends the @eventName to the ApplicationLifecycleEventRegistrationKey merges the @eventValue into
|
||||
//! the SettingsRegistry at that key
|
||||
//! NOTE: This function should only be invoked from ComponentApplication and its derived classes
|
||||
//! @param settingsRegistry registry where eventName should be set
|
||||
//! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to signal
|
||||
//! @param eventValue JSON Object that will be merged into the SettingsRegistry at <ApplicationLifecycleEventRootKey>/<eventName>
|
||||
//! @return true if the eventValue was successfully merged at the <ApplicationLifecycleEventRootKey>/<eventName>
|
||||
bool SignalEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName, AZStd::string_view eventValue);
|
||||
|
||||
//! Register that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey
|
||||
//! @param settingsRegistry registry where @eventName will be searched
|
||||
//! @param eventName name of key that will be stored in the ApplicationLifecycleEventRegistrationKey array
|
||||
//! @return true if the event passed validation or the eventName was stored in the ApplicationLifecycleEventRegistrationKey array
|
||||
bool RegisterEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName);
|
||||
|
||||
//! Wrapper around registering the NotifyEventHandler with the SettingsRegistry for the specified event
|
||||
//! It validates if the @eventName is is part of the ApplicationLifecycleEventRegistrationKey array and if
|
||||
//! so moves the @callback into @handler and then registers the handler with the SettingsRegistry NotifyEvent
|
||||
//! @param settingsRegistry registry where handler will be registered
|
||||
//! @param handler handler where callback will be moved into and then registered with the SettingsRegistry
|
||||
//! if the specified @eventName passes validation
|
||||
//! @param callback will be moved into the handler if the specified @eventName is valid
|
||||
//! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to register
|
||||
//! @param autoRegisterEvent automatically register this event if it hasn't been registered yet. This is useful
|
||||
//! when registering a handler before the settings registry has been loaded.
|
||||
//! @return true if the handler was registered with the SettingsRegistry NotifyEvent
|
||||
bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
|
||||
AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent = false);
|
||||
}
|
||||
@@ -262,6 +262,6 @@ static constexpr AZ::ThreadSafety ConsoleThreadSafety<_TYPE, std::enable_if_t<st
|
||||
//! @param _FLAGS a set of AzFramework::ConsoleFunctorFlags used to mutate behaviour
|
||||
//! @param _DESC a description of the cvar
|
||||
#define AZ_CONSOLEFREEFUNC_4(_NAME, _FUNCTION, _FLAGS, _DESC) \
|
||||
inline AZ::ConsoleFunctor<void, false> Functor##_FUNCTION(#_FUNCTION, _DESC, _FLAGS | AZ::ConsoleFunctorFlags::DontDuplicate, AZ::TypeId::CreateNull(), &_FUNCTION)
|
||||
inline AZ::ConsoleFunctor<void, false> Functor##_FUNCTION(_NAME, _DESC, _FLAGS | AZ::ConsoleFunctorFlags::DontDuplicate, AZ::TypeId::CreateNull(), &_FUNCTION)
|
||||
|
||||
#define AZ_CONSOLEFREEFUNC(...) AZ_MACRO_SPECIALIZE(AZ_CONSOLEFREEFUNC_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
|
||||
|
||||
@@ -10,16 +10,13 @@
|
||||
#include <AzCore/Module/Internal/ModuleManagerSearchPathTool.h>
|
||||
|
||||
#include <AzCore/Module/Module.h>
|
||||
#include <AzCore/RTTI/AttributeReader.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/ComponentApplicationLifecycle.h>
|
||||
#include <AzCore/NativeUI/NativeUIRequests.h>
|
||||
#include <AzCore/Script/ScriptSystemBus.h>
|
||||
#include <AzCore/Script/ScriptContext.h>
|
||||
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
@@ -221,11 +218,16 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string componentNamesArray = R"({ "SystemComponents":[)";
|
||||
const char* comma = "";
|
||||
// For all system components, deactivate
|
||||
for (auto componentIt = m_systemComponents.rbegin(); componentIt != m_systemComponents.rend(); ++componentIt)
|
||||
{
|
||||
ModuleEntity::DeactivateComponent(**componentIt);
|
||||
componentNamesArray += AZStd::string::format(R"(%s"%s")", comma, (*componentIt)->RTTI_GetTypeName());
|
||||
comma = ", ";
|
||||
}
|
||||
componentNamesArray += R"(]})";
|
||||
|
||||
// For all modules that we created an entity for, set them to "Init" (meaning not Activated)
|
||||
for (auto& moduleData : m_ownedModules)
|
||||
@@ -239,6 +241,13 @@ namespace AZ
|
||||
|
||||
// Since the system components have been deactivated clear out the vector.
|
||||
m_systemComponents.clear();
|
||||
|
||||
// Signal that the System Components have deactivated
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "SystemComponentsDeactivated", componentNamesArray);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -284,7 +293,11 @@ namespace AZ
|
||||
{
|
||||
// Split the tag list
|
||||
AZStd::vector<AZStd::string_view> tagList;
|
||||
AZStd::tokenize<AZStd::string_view>(tags, ",", tagList);
|
||||
auto TokenizeTags = [&tagList](AZStd::string_view token)
|
||||
{
|
||||
tagList.push_back(token);
|
||||
};
|
||||
AZ::StringFunc::TokenizeVisitor(tags, TokenizeTags, ',');
|
||||
|
||||
m_systemComponentTags.resize(tagList.size());
|
||||
AZStd::transform(tagList.begin(), tagList.end(), m_systemComponentTags.begin(), [](const AZStd::string_view& tag)
|
||||
@@ -737,11 +750,17 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string componentNamesArray = R"({ "SystemComponents":[)";
|
||||
const char* comma = "";
|
||||
// Activate the entities in the appropriate order
|
||||
for (Component* component : componentsToActivate)
|
||||
{
|
||||
ModuleEntity::ActivateComponent(*component);
|
||||
|
||||
componentNamesArray += AZStd::string::format(R"(%s"%s")", comma, component->RTTI_GetTypeName());
|
||||
comma = ", ";
|
||||
}
|
||||
componentNamesArray += R"(]})";
|
||||
|
||||
// Done activating; set state to active
|
||||
for (auto& moduleData : modulesToInit)
|
||||
@@ -755,5 +774,12 @@ namespace AZ
|
||||
|
||||
// Save the activated components for deactivation later
|
||||
m_systemComponents.insert(m_systemComponents.end(), componentsToActivate.begin(), componentsToActivate.end());
|
||||
|
||||
// Signal that the System Components are activated
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "SystemComponentsActivated",
|
||||
componentNamesArray);
|
||||
}
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
namespace AZ::Internal
|
||||
{
|
||||
static constexpr const char* ProductCacheDirectoryName = "Cache";
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString GetEngineMonikerForProject(
|
||||
SettingsRegistryInterface& settingsRegistry, const AZ::IO::FixedMaxPath& projectJsonPath)
|
||||
{
|
||||
@@ -228,19 +230,20 @@ namespace AZ::Internal
|
||||
|
||||
namespace AZ::SettingsRegistryMergeUtils
|
||||
{
|
||||
constexpr AZStd::string_view InternalScanUpEngineRootKey{ "/O3DE/Settings/Internal/engine_root_scan_up_path" };
|
||||
constexpr AZStd::string_view InternalScanUpProjectRootKey{ "/O3DE/Settings/Internal/project_root_scan_up_path" };
|
||||
|
||||
AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry)
|
||||
{
|
||||
static constexpr AZStd::string_view InternalScanUpEngineRootKey{ "/O3DE/Runtime/Internal/engine_root_scan_up_path" };
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
using Type = SettingsRegistryInterface::Type;
|
||||
|
||||
AZ::IO::FixedMaxPath engineRoot;
|
||||
// This is the 'external' engine root key, as in passed from command-line or .setreg files.
|
||||
auto engineRootKey = SettingsRegistryInterface::FixedValueString::format("%s/engine_path", BootstrapSettingsRootKey);
|
||||
constexpr auto engineRootKey = FixedValueString(BootstrapSettingsRootKey) + "/engine_path";
|
||||
|
||||
// Step 1 Run the scan upwards logic once to find the location of the engine.json if it exist
|
||||
// Once this step is run the {InternalScanUpEngineRootKey} is set in the Settings Registry
|
||||
// to have this scan logic only run once InternalScanUpEngineRootKey the supplied registry
|
||||
if (settingsRegistry.GetType(InternalScanUpEngineRootKey) == SettingsRegistryInterface::Type::NoType)
|
||||
if (settingsRegistry.GetType(InternalScanUpEngineRootKey) == Type::NoType)
|
||||
{
|
||||
// We can scan up from exe directory to find engine.json, use that for engine root if it exists.
|
||||
engineRoot = Internal::ScanUpRootLocator("engine.json");
|
||||
@@ -283,14 +286,18 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
|
||||
AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry)
|
||||
{
|
||||
AZ::IO::FixedMaxPath projectRoot;
|
||||
const auto projectRootKey = SettingsRegistryInterface::FixedValueString::format("%s/project_path", BootstrapSettingsRootKey);
|
||||
static constexpr AZStd::string_view InternalScanUpProjectRootKey{ "/O3DE/Runtime/Internal/project_root_scan_up_path" };
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
using Type = SettingsRegistryInterface::Type;
|
||||
|
||||
// Step 1 Run the scan upwards logic once to find the location of the project.json if it exist
|
||||
AZ::IO::FixedMaxPath projectRoot;
|
||||
constexpr auto projectRootKey = FixedValueString(BootstrapSettingsRootKey) + "/project_path";
|
||||
|
||||
// Step 1 Run the scan upwards logic once to find the location of the closest ancestor project.json
|
||||
// Once this step is run the {InternalScanUpProjectRootKey} is set in the Settings Registry
|
||||
// to have this scan logic only run once for the supplied registry
|
||||
// SettingsRegistryInterface::GetType is used to check if a key is set
|
||||
if (settingsRegistry.GetType(InternalScanUpProjectRootKey) == SettingsRegistryInterface::Type::NoType)
|
||||
if (settingsRegistry.GetType(InternalScanUpProjectRootKey) == Type::NoType)
|
||||
{
|
||||
projectRoot = Internal::ScanUpRootLocator("project.json");
|
||||
// Set the {InternalScanUpProjectRootKey} to make sure this code path isn't called again for this settings registry
|
||||
@@ -305,19 +312,129 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
}
|
||||
|
||||
// Step 2 Check the project-path key
|
||||
// This is the project path root key, as in passed from command-line or .setreg files.
|
||||
if (settingsRegistry.Get(projectRoot.Native(), projectRootKey))
|
||||
// This is the project path root key, as passed from command-line or *.setreg files.
|
||||
settingsRegistry.Get(projectRoot.Native(), projectRootKey);
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
//! The algorithm that is used to find the project cache is as follows
|
||||
//! 1. The "{BootstrapSettingsRootKey}/project_cache_path" is checked for the path
|
||||
//! 2. Otherwise append the ProductCacheDirectoryName constant to the <project-path>
|
||||
static AZ::IO::FixedMaxPath FindProjectCachePath(SettingsRegistryInterface& settingsRegistry, const AZ::IO::FixedMaxPath& projectPath)
|
||||
{
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
|
||||
constexpr auto projectCachePathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_cache_path";
|
||||
|
||||
// Step 1 Check the project-cache-path key
|
||||
if (AZ::IO::FixedMaxPath projectCachePath; settingsRegistry.Get(projectCachePath.Native(), projectCachePathKey))
|
||||
{
|
||||
return projectRoot;
|
||||
return projectCachePath;
|
||||
}
|
||||
|
||||
// Step 3 Check for a "Cache" directory by scanning upwards from the executable directory
|
||||
if (auto candidateRoot = Internal::ScanUpRootLocator("Cache");
|
||||
!candidateRoot.empty() && AZ::IO::SystemFile::IsDirectory(candidateRoot.c_str()))
|
||||
// Step 2 Append the "Cache" directory to the project-path
|
||||
return projectPath / Internal::ProductCacheDirectoryName;
|
||||
}
|
||||
|
||||
//! Set the user directory with the provided path or using <project-path>/user as default
|
||||
static AZ::IO::FixedMaxPath FindProjectUserPath(SettingsRegistryInterface& settingsRegistry,
|
||||
const AZ::IO::FixedMaxPath& projectPath)
|
||||
{
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
|
||||
// User: root - same as the @user@ alias, this is the starting path for transient data and log files.
|
||||
constexpr auto projectUserPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_user_path";
|
||||
|
||||
// Step 1 Check the project-user-path key
|
||||
if (AZ::IO::FixedMaxPath projectUserPath; settingsRegistry.Get(projectUserPath.Native(), projectUserPathKey))
|
||||
{
|
||||
projectRoot = AZStd::move(candidateRoot);
|
||||
return projectUserPath;
|
||||
}
|
||||
|
||||
// Step 2 Append the "User" directory to the project-path
|
||||
return projectPath / "user";
|
||||
}
|
||||
|
||||
//! Set the log directory using the settings registry path or using <project-user-path>/log as default
|
||||
static AZ::IO::FixedMaxPath FindProjectLogPath(SettingsRegistryInterface& settingsRegistry,
|
||||
const AZ::IO::FixedMaxPath& projectUserPath)
|
||||
{
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
|
||||
// User: root - same as the @log@ alias, this is the starting path for transient data and log files.
|
||||
constexpr auto projectLogPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_log_path";
|
||||
|
||||
// Step 1 Check the project-user-path key
|
||||
if (AZ::IO::FixedMaxPath projectLogPath; settingsRegistry.Get(projectLogPath.Native(), projectLogPathKey))
|
||||
{
|
||||
return projectLogPath;
|
||||
}
|
||||
|
||||
// Step 2 Append the "Log" directory to the project-user-path
|
||||
return projectUserPath / "log";
|
||||
}
|
||||
|
||||
// check for a default write storage path, fall back to the <project-user-path> if not
|
||||
static AZ::IO::FixedMaxPath FindDevWriteStoragePath(const AZ::IO::FixedMaxPath& projectUserPath)
|
||||
{
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> devWriteStorage = Utils::GetDevWriteStoragePath();
|
||||
return devWriteStorage.has_value() ? *devWriteStorage : projectUserPath;
|
||||
}
|
||||
|
||||
// check for the project build path, which is a relative path from the project root
|
||||
// that specifies where the build directory is located
|
||||
static void SetProjectBuildPath(SettingsRegistryInterface& settingsRegistry,
|
||||
const AZ::IO::FixedMaxPath& projectPath)
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath projectBuildPath; settingsRegistry.Get(projectBuildPath.Native(), ProjectBuildPath))
|
||||
{
|
||||
settingsRegistry.Remove(FilePathKey_ProjectBuildPath);
|
||||
settingsRegistry.Remove(FilePathKey_ProjectConfigurationBinPath);
|
||||
AZ::IO::FixedMaxPath buildConfigurationPath = (projectPath / projectBuildPath).LexicallyNormal();
|
||||
if (IO::SystemFile::Exists(buildConfigurationPath.c_str()))
|
||||
{
|
||||
settingsRegistry.Set(FilePathKey_ProjectBuildPath, buildConfigurationPath.Native());
|
||||
}
|
||||
|
||||
// Add the specific build configuration paths to the Settings Registry
|
||||
// First try <project-build-path>/bin/$<CONFIG> and if that path doesn't exist
|
||||
// try <project-build-path>/bin/$<PLATFORM>/$<CONFIG>
|
||||
buildConfigurationPath /= "bin";
|
||||
if (IO::SystemFile::Exists((buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).c_str()))
|
||||
{
|
||||
settingsRegistry.Set(FilePathKey_ProjectConfigurationBinPath,
|
||||
(buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).Native());
|
||||
}
|
||||
else if (IO::SystemFile::Exists((buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).c_str()))
|
||||
{
|
||||
settingsRegistry.Set(FilePathKey_ProjectConfigurationBinPath,
|
||||
(buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).Native());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the project name within the Settings Registry by looking up the "project_name"
|
||||
// within the project.json file
|
||||
static void SetProjectName(SettingsRegistryInterface& settingsRegistry,
|
||||
const AZ::IO::FixedMaxPath& projectPath)
|
||||
{
|
||||
using FixedValueString = SettingsRegistryInterface::FixedValueString;
|
||||
// Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name.
|
||||
constexpr auto projectNameKey = FixedValueString(ProjectSettingsRootKey) + "/project_name";
|
||||
|
||||
// Read the project name from the project.json file if it exists
|
||||
if (AZ::IO::FixedMaxPath projectJsonPath = projectPath / "project.json";
|
||||
AZ::IO::SystemFile::Exists(projectJsonPath.c_str()))
|
||||
{
|
||||
settingsRegistry.MergeSettingsFile(projectJsonPath.Native(),
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey);
|
||||
}
|
||||
// If a project name isn't set the default will be set to the final path segment of the project path
|
||||
if (FixedValueString projectName; !settingsRegistry.Get(projectName, projectNameKey))
|
||||
{
|
||||
projectName = projectPath.Filename().Native();
|
||||
settingsRegistry.Set(projectNameKey, projectName);
|
||||
}
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
AZStd::string_view ConfigParserSettings::DefaultCommentPrefixFilter(AZStd::string_view line)
|
||||
@@ -397,7 +514,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
bool MergeSettingsToRegistry_ConfigFile(SettingsRegistryInterface& registry, AZStd::string_view filePath,
|
||||
const ConfigParserSettings& configParserSettings)
|
||||
{
|
||||
auto configPath = FindEngineRoot(registry) / filePath;
|
||||
auto configPath = FindProjectRoot(registry) / filePath;
|
||||
IO::FileReader configFile;
|
||||
bool configFileOpened{};
|
||||
switch (configParserSettings.m_fileReaderClass)
|
||||
@@ -542,19 +659,77 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
void MergeSettingsToRegistry_AddRuntimeFilePaths(SettingsRegistryInterface& registry)
|
||||
{
|
||||
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
|
||||
// Binary folder
|
||||
AZ::IO::FixedMaxPath path = AZ::Utils::GetExecutableDirectory();
|
||||
registry.Set(FilePathKey_BinaryFolder, path.LexicallyNormal().Native());
|
||||
|
||||
// Engine root folder - corresponds to the @engroot@ and @engroot@ aliases
|
||||
AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry);
|
||||
registry.Set(FilePathKey_EngineRootFolder, engineRoot.LexicallyNormal().Native());
|
||||
// Binary folder - corresponds to the @exefolder@ alias
|
||||
AZ::IO::FixedMaxPath exePath = AZ::Utils::GetExecutableDirectory();
|
||||
registry.Set(FilePathKey_BinaryFolder, exePath.LexicallyNormal().Native());
|
||||
|
||||
auto projectPathKey = FixedValueString::format("%s/project_path", BootstrapSettingsRootKey);
|
||||
SettingsRegistryInterface::FixedValueString projectPathValue;
|
||||
if (registry.Get(projectPathValue, projectPathKey))
|
||||
// Project path - corresponds to the @projectroot@ alias
|
||||
// NOTE: We make the project-path in the BootstrapSettingsRootKey absolute first
|
||||
|
||||
AZ::IO::FixedMaxPath projectPath = FindProjectRoot(registry);
|
||||
if (constexpr auto projectPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_path";
|
||||
!projectPath.empty())
|
||||
{
|
||||
// Cache folder
|
||||
if (projectPath.IsRelative())
|
||||
{
|
||||
if (auto projectAbsPath = AZ::Utils::ConvertToAbsolutePath(projectPath.Native());
|
||||
projectAbsPath.has_value())
|
||||
{
|
||||
projectPath = AZStd::move(*projectAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
projectPath = projectPath.LexicallyNormal();
|
||||
AZ_Warning("SettingsRegistryMergeUtils", AZ::IO::SystemFile::Exists(projectPath.c_str()),
|
||||
R"(Project path "%s" does not exist. Is the "%.*s" registry setting set to a valid absolute path?)"
|
||||
, projectPath.c_str(), AZ_STRING_ARG(projectPathKey));
|
||||
|
||||
registry.Set(FilePathKey_ProjectPath, projectPath.Native());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_TracePrintf("SettingsRegistryMergeUtils",
|
||||
R"(Project path isn't set in the Settings Registry at "%.*s".)"
|
||||
" Project-related filepaths will be set relative to the executable directory\n",
|
||||
AZ_STRING_ARG(projectPathKey));
|
||||
registry.Set(FilePathKey_ProjectPath, exePath.Native());
|
||||
}
|
||||
|
||||
// Engine root folder - corresponds to the @engroot@ alias
|
||||
AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry);
|
||||
if (!engineRoot.empty())
|
||||
{
|
||||
if (engineRoot.IsRelative())
|
||||
{
|
||||
if (auto engineRootAbsPath = AZ::Utils::ConvertToAbsolutePath(engineRoot.Native());
|
||||
engineRootAbsPath.has_value())
|
||||
{
|
||||
engineRoot = AZStd::move(*engineRootAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
engineRoot = engineRoot.LexicallyNormal();
|
||||
registry.Set(FilePathKey_EngineRootFolder, engineRoot.Native());
|
||||
}
|
||||
|
||||
// Cache folder
|
||||
AZ::IO::FixedMaxPath projectCachePath = FindProjectCachePath(registry, projectPath).LexicallyNormal();
|
||||
if (!projectCachePath.empty())
|
||||
{
|
||||
if (projectCachePath.IsRelative())
|
||||
{
|
||||
if (auto projectCacheAbsPath = AZ::Utils::ConvertToAbsolutePath(projectCachePath.Native());
|
||||
projectCacheAbsPath.has_value())
|
||||
{
|
||||
projectCachePath = AZStd::move(*projectCacheAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
projectCachePath = projectCachePath.LexicallyNormal();
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, projectCachePath.Native());
|
||||
|
||||
// Cache/<asset-platform> folder
|
||||
// Get the name of the asset platform assigned by the bootstrap. First check for platform version such as "windows_assets"
|
||||
// and if that's missing just get "assets".
|
||||
FixedValueString assetPlatform;
|
||||
@@ -570,118 +745,67 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
assetPlatform = AZ::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME);
|
||||
}
|
||||
|
||||
// Project path - corresponds to the @projectroot@ alias
|
||||
// NOTE: Here we append to engineRoot, but if projectPathValue is absolute then engineRoot is discarded.
|
||||
path = engineRoot / projectPathValue;
|
||||
|
||||
AZ_Warning("SettingsRegistryMergeUtils", AZ::IO::SystemFile::Exists(path.c_str()),
|
||||
R"(Project path "%s" does not exist. Is the "%.*s" registry setting set to valid absolute path?)"
|
||||
, path.c_str(), aznumeric_cast<int>(projectPathKey.size()), projectPathKey.data());
|
||||
|
||||
AZ::IO::FixedMaxPath normalizedProjectPath = path.LexicallyNormal();
|
||||
registry.Set(FilePathKey_ProjectPath, normalizedProjectPath.Native());
|
||||
|
||||
// Set the user directory with the provided path or using project/user as default
|
||||
auto projectUserPathKey = FixedValueString::format("%s/project_user_path", BootstrapSettingsRootKey);
|
||||
AZ::IO::FixedMaxPath projectUserPath;
|
||||
if (!registry.Get(projectUserPath.Native(), projectUserPathKey))
|
||||
{
|
||||
projectUserPath = (normalizedProjectPath / "user").LexicallyNormal();
|
||||
}
|
||||
registry.Set(FilePathKey_ProjectUserPath, projectUserPath.Native());
|
||||
|
||||
// Set the log directory with the provided path or using project/user/log as default
|
||||
auto projectLogPathKey = FixedValueString::format("%s/project_log_path", BootstrapSettingsRootKey);
|
||||
AZ::IO::FixedMaxPath projectLogPath;
|
||||
if (!registry.Get(projectLogPath.Native(), projectLogPathKey))
|
||||
{
|
||||
projectLogPath = (projectUserPath / "log").LexicallyNormal();
|
||||
}
|
||||
registry.Set(FilePathKey_ProjectLogPath, projectLogPath.Native());
|
||||
|
||||
// check for a default write storage path, fall back to the project's user/ directory if not
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> devWriteStorage = Utils::GetDevWriteStoragePath();
|
||||
registry.Set(FilePathKey_DevWriteStorage, devWriteStorage.has_value()
|
||||
? devWriteStorage.value()
|
||||
: projectUserPath.Native());
|
||||
|
||||
// Set the project in-memory build path if the ProjectBuildPath key has been supplied
|
||||
if (AZ::IO::FixedMaxPath projectBuildPath; registry.Get(projectBuildPath.Native(), ProjectBuildPath))
|
||||
{
|
||||
registry.Remove(FilePathKey_ProjectBuildPath);
|
||||
registry.Remove(FilePathKey_ProjectConfigurationBinPath);
|
||||
AZ::IO::FixedMaxPath buildConfigurationPath = normalizedProjectPath / projectBuildPath;
|
||||
if (IO::SystemFile::Exists(buildConfigurationPath.c_str()))
|
||||
{
|
||||
registry.Set(FilePathKey_ProjectBuildPath, buildConfigurationPath.LexicallyNormal().Native());
|
||||
}
|
||||
|
||||
// Add the specific build configuration paths to the Settings Registry
|
||||
// First try <project-build-path>/bin/$<CONFIG> and if that path doesn't exist
|
||||
// try <project-build-path>/bin/$<PLATFORM>/$<CONFIG>
|
||||
buildConfigurationPath /= "bin";
|
||||
if (IO::SystemFile::Exists((buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).c_str()))
|
||||
{
|
||||
registry.Set(FilePathKey_ProjectConfigurationBinPath,
|
||||
(buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native());
|
||||
}
|
||||
else if (IO::SystemFile::Exists((buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).c_str()))
|
||||
{
|
||||
registry.Set(FilePathKey_ProjectConfigurationBinPath,
|
||||
(buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name.
|
||||
auto projectNameKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
|
||||
+ "/project_name";
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectName;
|
||||
if (!registry.Get(projectName, projectNameKey))
|
||||
{
|
||||
projectName = path.Filename().Native();
|
||||
registry.Set(projectNameKey, projectName);
|
||||
}
|
||||
|
||||
// Cache folders - sets up various paths in registry for the cache.
|
||||
// Make sure the asset platform is set before setting these cache paths.
|
||||
// Make sure the asset platform is set before setting cache path for the asset platform.
|
||||
if (!assetPlatform.empty())
|
||||
{
|
||||
// Cache: project root - no corresponding fileIO alias, but this is where the asset database lives.
|
||||
// A registry override is accepted using the "project_cache_path" key.
|
||||
auto projectCacheRootOverrideKey = FixedValueString::format("%s/project_cache_path", BootstrapSettingsRootKey);
|
||||
// Clear path to make sure that the `project_cache_path` value isn't concatenated to the project path
|
||||
path.clear();
|
||||
if (registry.Get(path.Native(), projectCacheRootOverrideKey))
|
||||
{
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native());
|
||||
path /= assetPlatform;
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cache: root - same as the @products@ alias, this is the starting path for cache files.
|
||||
path = normalizedProjectPath / "Cache";
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native());
|
||||
path /= assetPlatform;
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
}
|
||||
registry.Set(FilePathKey_CacheRootFolder, (projectCachePath / assetPlatform).Native());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// User folder
|
||||
AZ::IO::FixedMaxPath projectUserPath = FindProjectUserPath(registry, projectPath);
|
||||
if (!projectUserPath.empty())
|
||||
{
|
||||
// Set the default ProjectUserPath to the <engine-root>/user directory
|
||||
registry.Set(FilePathKey_ProjectUserPath, (engineRoot / "user").LexicallyNormal().Native());
|
||||
AZ_TracePrintf("SettingsRegistryMergeUtils",
|
||||
R"(Project path isn't set in the Settings Registry at "%.*s". Project-related filepaths will not be set)" "\n",
|
||||
aznumeric_cast<int>(projectPathKey.size()), projectPathKey.data());
|
||||
if (projectUserPath.IsRelative())
|
||||
{
|
||||
if (auto projectUserAbsPath = AZ::Utils::ConvertToAbsolutePath(projectUserPath.Native());
|
||||
projectUserAbsPath.has_value())
|
||||
{
|
||||
projectUserPath = AZStd::move(*projectUserAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
projectUserPath = projectUserPath.LexicallyNormal();
|
||||
registry.Set(FilePathKey_ProjectUserPath, projectUserPath.Native());
|
||||
}
|
||||
|
||||
// Log folder
|
||||
if (AZ::IO::FixedMaxPath projectLogPath = FindProjectLogPath(registry, projectUserPath); !projectLogPath.empty())
|
||||
{
|
||||
if (projectLogPath.IsRelative())
|
||||
{
|
||||
if (auto projectLogAbsPath = AZ::Utils::ConvertToAbsolutePath(projectLogPath.Native()))
|
||||
{
|
||||
projectLogPath = AZStd::move(*projectLogAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
projectLogPath = projectLogPath.LexicallyNormal();
|
||||
registry.Set(FilePathKey_ProjectLogPath, projectLogPath.Native());
|
||||
}
|
||||
|
||||
// Developer Write Storage folder
|
||||
if (AZ::IO::FixedMaxPath devWriteStoragePath = FindDevWriteStoragePath(projectUserPath); !devWriteStoragePath.empty())
|
||||
{
|
||||
if (devWriteStoragePath.IsRelative())
|
||||
{
|
||||
if (auto devWriteStorageAbsPath = AZ::Utils::ConvertToAbsolutePath(devWriteStoragePath.Native()))
|
||||
{
|
||||
devWriteStoragePath = AZStd::move(*devWriteStorageAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
devWriteStoragePath = devWriteStoragePath.LexicallyNormal();
|
||||
registry.Set(FilePathKey_DevWriteStorage, devWriteStoragePath.Native());
|
||||
}
|
||||
|
||||
// Set the project in-memory build path if the ProjectBuildPath key has been supplied
|
||||
SetProjectBuildPath(registry, projectPath);
|
||||
// Set the project name using the "project_name" key
|
||||
SetProjectName(registry, projectPath);
|
||||
|
||||
#if !AZ_TRAIT_OS_IS_HOST_OS_PLATFORM
|
||||
// Setup the cache, user, and log paths to platform specific locations when running on non-host platforms
|
||||
path = engineRoot;
|
||||
if (AZStd::optional<AZ::IO::FixedMaxPathString> nonHostCacheRoot = Utils::GetDefaultAppRootPath();
|
||||
nonHostCacheRoot)
|
||||
{
|
||||
@@ -690,25 +814,25 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
}
|
||||
else
|
||||
{
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, projectPath.Native());
|
||||
registry.Set(FilePathKey_CacheRootFolder, projectPath.Native());
|
||||
}
|
||||
if (AZStd::optional<AZ::IO::FixedMaxPathString> devWriteStorage = Utils::GetDevWriteStoragePath();
|
||||
devWriteStorage)
|
||||
{
|
||||
const AZ::IO::FixedMaxPath devWriteStoragePath(*devWriteStorage);
|
||||
registry.Set(FilePathKey_DevWriteStorage, devWriteStoragePath.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_ProjectUserPath, (devWriteStoragePath / "user").LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_ProjectLogPath, (devWriteStoragePath / "user/log").LexicallyNormal().Native());
|
||||
const auto devWriteStoragePath = AZ::IO::PathView(*devWriteStorage).LexicallyNormal();
|
||||
registry.Set(FilePathKey_DevWriteStorage, devWriteStoragePath.Native());
|
||||
registry.Set(FilePathKey_ProjectUserPath, (devWriteStoragePath / "user").Native());
|
||||
registry.Set(FilePathKey_ProjectLogPath, (devWriteStoragePath / "user" / "log").Native());
|
||||
}
|
||||
else
|
||||
{
|
||||
registry.Set(FilePathKey_DevWriteStorage, path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_ProjectUserPath, (path / "user").LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_ProjectLogPath, (path / "user/log").LexicallyNormal().Native());
|
||||
}
|
||||
#endif // AZ_TRAIT_OS_IS_HOST_OS_PLATFORM
|
||||
registry.Set(FilePathKey_DevWriteStorage, projectPath.Native());
|
||||
registry.Set(FilePathKey_ProjectUserPath, (projectPath / "user").Native());
|
||||
registry.Set(FilePathKey_ProjectLogPath, (projectPath / "user" / "log").Native());
|
||||
}
|
||||
#endif // AZ_TRAIT_OS_IS_HOST_OS_PLATFORM
|
||||
}
|
||||
|
||||
void MergeSettingsToRegistry_TargetBuildDependencyRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
const SettingsRegistryInterface::Specializations& specializations, AZStd::vector<char>* scratchBuffer)
|
||||
|
||||
@@ -87,9 +87,9 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry);
|
||||
|
||||
//! The algorithm that is used to find the project root is as follows
|
||||
//! 1. The first time this function is it performs a upward scan for a project.json file from
|
||||
//! the executable directory and if found stores that path to an internal key.
|
||||
//! In the same step it injects the path into the front of list of command line parameters
|
||||
//! 1. The first time this function runs it performs an upward scan for a "project.json" file from
|
||||
//! the executable directory and stores that path into an internal key.
|
||||
//! In the same step it injects the path into the back of the command line parameters
|
||||
//! using the --regset="{BootstrapSettingsRootKey}/project_path=<path>" value
|
||||
//! 2. Next the "{BootstrapSettingsRootKey}/project_path" is checked to see if it has a project path set
|
||||
//!
|
||||
|
||||
@@ -15,20 +15,20 @@
|
||||
|
||||
namespace AZ::SettingsRegistryScriptUtils::Internal
|
||||
{
|
||||
static void RegisterScriptProxyForNotify(SettingsRegistryScriptProxy& settingsRegistryProxy)
|
||||
static void RegisterScriptProxyForNotify(SettingsRegistryInterface* settingsRegistry,
|
||||
SettingsRegistryScriptProxy::NotifyEventProxy* notifyEventProxy)
|
||||
{
|
||||
if (settingsRegistryProxy.IsValid())
|
||||
if (settingsRegistry != nullptr)
|
||||
{
|
||||
auto ForwardSettingsUpdateToProxyEvent = [&settingsRegistryProxy](AZStd::string_view path, AZ::SettingsRegistryInterface::Type)
|
||||
auto ForwardSettingsUpdateToProxyEvent = [notifyEventProxy](AZStd::string_view path, AZ::SettingsRegistryInterface::Type)
|
||||
{
|
||||
if (settingsRegistryProxy.m_notifyEventProxy)
|
||||
if (notifyEventProxy)
|
||||
{
|
||||
settingsRegistryProxy.m_notifyEventProxy->m_scriptNotifyEvent.Signal(path);
|
||||
notifyEventProxy->m_scriptNotifyEvent.Signal(path);
|
||||
}
|
||||
};
|
||||
// Register the forwarding function with the BehaviorContext
|
||||
settingsRegistryProxy.m_notifyEventProxy->m_settingsUpdatedHandler =
|
||||
settingsRegistryProxy.m_settingsRegistry->RegisterNotifier(ForwardSettingsUpdateToProxyEvent);
|
||||
notifyEventProxy->m_settingsUpdatedHandler = settingsRegistry->RegisterNotifier(ForwardSettingsUpdateToProxyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace AZ::SettingsRegistryScriptUtils::Internal
|
||||
: m_settingsRegistry(AZStd::move(settingsRegistry))
|
||||
, m_notifyEventProxy(AZStd::make_shared<NotifyEventProxy>())
|
||||
{
|
||||
RegisterScriptProxyForNotify(*this);
|
||||
RegisterScriptProxyForNotify(m_settingsRegistry.get(), m_notifyEventProxy.get());
|
||||
}
|
||||
|
||||
// Raw AZ::SettingsRegistryInterface pointer is not owned by the proxy, so it's deleter is a no-op
|
||||
@@ -45,7 +45,7 @@ namespace AZ::SettingsRegistryScriptUtils::Internal
|
||||
: m_settingsRegistry(settingsRegistry, [](AZ::SettingsRegistryInterface*) {})
|
||||
, m_notifyEventProxy(AZStd::make_shared<NotifyEventProxy>())
|
||||
{
|
||||
RegisterScriptProxyForNotify(*this);
|
||||
RegisterScriptProxyForNotify(m_settingsRegistry.get(), m_notifyEventProxy.get());
|
||||
}
|
||||
|
||||
// SettingsRegistryScriptProxy function that determines if the SettingsRegistry object is valid
|
||||
|
||||
@@ -41,6 +41,8 @@ set(FILES
|
||||
Component/ComponentApplication.cpp
|
||||
Component/ComponentApplication.h
|
||||
Component/ComponentApplicationBus.h
|
||||
Component/ComponentApplicationLifecycle.cpp
|
||||
Component/ComponentApplicationLifecycle.h
|
||||
Component/ComponentBus.cpp
|
||||
Component/ComponentBus.h
|
||||
Component/ComponentExport.h
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/ComponentApplicationLifecycle.h>
|
||||
#include <AzCore/Component/NonUniformScaleBus.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
@@ -120,6 +121,11 @@ namespace AzFramework
|
||||
m_archiveFileIO = AZStd::make_unique<AZ::IO::ArchiveFileIO>(m_archive.get());
|
||||
AZ::IO::FileIOBase::SetInstance(m_archiveFileIO.get());
|
||||
SetFileIOAliases();
|
||||
// The FileIOAvailable event needs to be registered here as this event is sent out
|
||||
// before the settings registry has merged the .setreg files from the <engine-root>
|
||||
// (That happens in MergeSettingsToRegistry
|
||||
AZ::ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "FileIOAvailable");
|
||||
AZ::ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "FileIOAvailable", R"({})");
|
||||
}
|
||||
|
||||
if (auto nativeUI = AZ::Interface<AZ::NativeUI::NativeUIRequests>::Get(); nativeUI == nullptr)
|
||||
@@ -172,6 +178,8 @@ namespace AzFramework
|
||||
// Archive classes relies on the FileIOBase DirectInstance to close
|
||||
// files properly
|
||||
m_directFileIO.reset();
|
||||
|
||||
AZ::ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "FileIOUnavailable", R"({})");
|
||||
}
|
||||
|
||||
void Application::Start(const Descriptor& descriptor, const StartupParameters& startupParameters)
|
||||
@@ -196,7 +204,24 @@ namespace AzFramework
|
||||
systemEntity->Activate();
|
||||
AZ_Assert(systemEntity->GetState() == AZ::Entity::State::Active, "System Entity failed to activate.");
|
||||
|
||||
m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active);
|
||||
if (m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); m_isStarted)
|
||||
{
|
||||
if (m_startupParameters.m_loadAssetCatalog)
|
||||
{
|
||||
// Start Monitoring Asset changes over the network and load the AssetCatalog
|
||||
auto StartMonitoringAssetsAndLoadCatalog = [this](AZ::Data::AssetCatalogRequests* assetCatalogRequests)
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath assetCatalogPath;
|
||||
m_settingsRegistry->Get(assetCatalogPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
|
||||
{
|
||||
assetCatalogPath /= "assetcatalog.xml";
|
||||
assetCatalogRequests->LoadCatalog(assetCatalogPath.c_str());
|
||||
}
|
||||
};
|
||||
using AssetCatalogBus = AZ::Data::AssetCatalogRequestBus;
|
||||
AssetCatalogBus::Broadcast(AZStd::move(StartMonitoringAssetsAndLoadCatalog));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::PreModuleLoad()
|
||||
@@ -210,6 +235,17 @@ namespace AzFramework
|
||||
{
|
||||
if (m_isStarted)
|
||||
{
|
||||
if (m_startupParameters.m_loadAssetCatalog)
|
||||
{
|
||||
// Stop Monitoring Assets changes
|
||||
auto StopMonitoringAssets = [](AZ::Data::AssetCatalogRequests* assetCatalogRequests)
|
||||
{
|
||||
assetCatalogRequests->StopMonitoringAssets();
|
||||
};
|
||||
using AssetCatalogBus = AZ::Data::AssetCatalogRequestBus;
|
||||
AssetCatalogBus::Broadcast(AZStd::move(StopMonitoringAssets));
|
||||
}
|
||||
|
||||
ApplicationLifecycleEvents::Bus::Broadcast(&ApplicationLifecycleEvents::OnApplicationAboutToStop);
|
||||
|
||||
m_pimpl.reset();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/ComponentApplicationLifecycle.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
@@ -363,6 +364,23 @@ namespace AZ::IO
|
||||
, m_mainThreadId{ AZStd::this_thread::get_id() }
|
||||
{
|
||||
CompressionBus::Handler::BusConnect();
|
||||
|
||||
// If the settings registry is not available at this point,
|
||||
// then something catastrophic has happened in the application startup.
|
||||
// That should have been caught and messaged out earlier in startup.
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
// Automatically register the event if it's not registered, because
|
||||
// this system is initialized before the settings registry has loaded the event list.
|
||||
AZ::ComponentApplicationLifecycle::RegisterHandler(
|
||||
*settingsRegistry, m_componentApplicationLifecycleHandler,
|
||||
[this](AZStd::string_view /*path*/, AZ::SettingsRegistryInterface::Type /*type*/)
|
||||
{
|
||||
OnSystemEntityActivated();
|
||||
},
|
||||
"SystemComponentsActivated",
|
||||
/*autoRegisterEvent*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -1175,13 +1193,20 @@ namespace AZ::IO
|
||||
}
|
||||
}
|
||||
|
||||
auto bundleManifest = GetBundleManifest(desc.pZip);
|
||||
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog;
|
||||
auto bundleManifest = GetBundleManifest(desc.pZip);
|
||||
if (bundleManifest)
|
||||
{
|
||||
bundleCatalog = GetBundleCatalog(desc.pZip, bundleManifest->GetCatalogName());
|
||||
}
|
||||
|
||||
// If this archive is loaded before the serialize context is available, then the manifest and catalog will need to be loaded later.
|
||||
if (!bundleManifest || !bundleCatalog)
|
||||
{
|
||||
m_archivesWithCatalogsToLoad.push_back(
|
||||
ArchivesWithCatalogsToLoad(szFullPath, szBindRoot, flags, nextBundle, desc.m_strFileName));
|
||||
}
|
||||
|
||||
bool usePrefabSystemForLevels = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
|
||||
@@ -1219,12 +1244,17 @@ namespace AZ::IO
|
||||
m_levelOpenEvent.Signal(levelDirs);
|
||||
}
|
||||
|
||||
AZ::IO::ArchiveNotificationBus::Broadcast([](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
|
||||
AZStd::shared_ptr<AzFramework::AssetBundleManifest> bundleManifest, const AZ::IO::FixedMaxPath& nextBundle, AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog)
|
||||
if (bundleManifest && bundleCatalog)
|
||||
{
|
||||
archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
|
||||
}, desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
|
||||
|
||||
AZ::IO::ArchiveNotificationBus::Broadcast(
|
||||
[](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
|
||||
AZStd::shared_ptr<AzFramework::AssetBundleManifest> bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
|
||||
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog)
|
||||
{
|
||||
archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
|
||||
},
|
||||
desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2138,7 +2168,7 @@ namespace AZ::IO
|
||||
}
|
||||
|
||||
currentDirPattern = currentDir + AZ_FILESYSTEM_SEPARATOR_WILDCARD;
|
||||
currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "levels.pak";
|
||||
currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "level.pak";
|
||||
|
||||
ZipDir::FileEntry* fileEntry = findFile.FindExact(currentFilePattern.c_str());
|
||||
if (fileEntry)
|
||||
@@ -2175,4 +2205,36 @@ namespace AZ::IO
|
||||
|
||||
return catalogInfo;
|
||||
}
|
||||
|
||||
void Archive::OnSystemEntityActivated()
|
||||
{
|
||||
for (const auto& archiveInfo : m_archivesWithCatalogsToLoad)
|
||||
{
|
||||
AZStd::intrusive_ptr<INestedArchive> archive =
|
||||
OpenArchive(archiveInfo.m_fullPath, archiveInfo.m_bindRoot, archiveInfo.m_flags, nullptr);
|
||||
if (!archive)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ZipDir::CachePtr pZip = static_cast<NestedArchive*>(archive.get())->GetCache();
|
||||
|
||||
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog;
|
||||
auto bundleManifest = GetBundleManifest(pZip);
|
||||
if (bundleManifest)
|
||||
{
|
||||
bundleCatalog = GetBundleCatalog(pZip, bundleManifest->GetCatalogName());
|
||||
}
|
||||
|
||||
AZ::IO::ArchiveNotificationBus::Broadcast(
|
||||
[](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
|
||||
AZStd::shared_ptr<AzFramework::AssetBundleManifest> bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
|
||||
AZStd::shared_ptr<AzFramework::AssetRegistry> bundleCatalog)
|
||||
{
|
||||
archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
|
||||
},
|
||||
archiveInfo.m_strFileName.c_str(), bundleManifest, archiveInfo.m_nextBundle, bundleCatalog);
|
||||
}
|
||||
m_archivesWithCatalogsToLoad.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <AzCore/IO/CompressionBus.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
@@ -271,6 +272,11 @@ namespace AZ::IO
|
||||
ZipDir::CachePtr* pZip = {}) const;
|
||||
private:
|
||||
|
||||
// Archives can't be fully mounted until the system entity has been activated,
|
||||
// because mounting them requires the BundlingSystemComponent and the serialization system
|
||||
// to both be available.
|
||||
void OnSystemEntityActivated();
|
||||
|
||||
bool OpenPackCommon(AZStd::string_view szBindRoot, AZStd::string_view pName, AZStd::intrusive_ptr<AZ::IO::MemoryBlock> pData = nullptr, bool addLevels = true);
|
||||
bool OpenPacksCommon(AZStd::string_view szDir, AZStd::string_view pWildcardIn, AZStd::vector<AZ::IO::FixedMaxPathString>* pFullPaths = nullptr, bool addLevels = true);
|
||||
|
||||
@@ -313,6 +319,8 @@ namespace AZ::IO
|
||||
mutable AZStd::shared_mutex m_csZips;
|
||||
ZipArray m_arrZips;
|
||||
|
||||
AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Opened files collector.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -339,5 +347,34 @@ namespace AZ::IO
|
||||
// [LYN-2376] Remove once legacy slice support is removed
|
||||
LevelPackOpenEvent m_levelOpenEvent;
|
||||
LevelPackCloseEvent m_levelCloseEvent;
|
||||
|
||||
// If pak files are loaded before the serialization and bundling system
|
||||
// are ready to go, their asset catalogs can't be loaded.
|
||||
// In this case, cache information about those archives,
|
||||
// and attempt to load the catalogs later, when the required systems are enabled.
|
||||
struct ArchivesWithCatalogsToLoad
|
||||
{
|
||||
ArchivesWithCatalogsToLoad(
|
||||
AZStd::string_view fullPath,
|
||||
AZStd::string_view bindRoot,
|
||||
int flags,
|
||||
AZ::IO::PathView nextBundle,
|
||||
AZ::IO::Path strFileName)
|
||||
: m_fullPath(fullPath)
|
||||
, m_bindRoot(bindRoot)
|
||||
, m_flags(flags)
|
||||
, m_nextBundle(nextBundle)
|
||||
, m_strFileName(strFileName)
|
||||
{
|
||||
}
|
||||
|
||||
AZ::IO::Path m_strFileName;
|
||||
AZStd::string m_fullPath;
|
||||
AZStd::string m_bindRoot;
|
||||
AZ::IO::PathView m_nextBundle;
|
||||
int m_flags;
|
||||
};
|
||||
|
||||
AZStd::vector<ArchivesWithCatalogsToLoad> m_archivesWithCatalogsToLoad;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ namespace AzFramework
|
||||
|
||||
if (!bytes.empty())
|
||||
{
|
||||
AZStd::shared_ptr < AzFramework::AssetRegistry> prevRegistry;
|
||||
AZStd::shared_ptr<AzFramework::AssetRegistry> prevRegistry;
|
||||
if (!m_initialized)
|
||||
{
|
||||
// First time initialization may have updates already processed which we want to apply
|
||||
@@ -589,7 +589,6 @@ namespace AzFramework
|
||||
AZ_TracePrintf("AssetCatalog", "Loaded registry containing %u assets.\n", m_registry->m_assetIdToInfo.size());
|
||||
|
||||
// It's currently possible in tools for us to have received updates from AP which were applied before the catalog was ready to load
|
||||
// due to CryPak and CrySystem coming online later than our components
|
||||
if (!m_initialized)
|
||||
{
|
||||
ApplyDeltaCatalog(prevRegistry);
|
||||
@@ -611,12 +610,13 @@ namespace AzFramework
|
||||
// the mutex. If the listener tries to perform a blocking asset load via GetAsset() / BlockUntilLoadComplete(), the spawned asset
|
||||
// thread will make a call to the AssetCatalogRequestBus and block on the held mutex. This would cause a deadlock, since the listener
|
||||
// won't free the mutex until the load is complete.
|
||||
// So instead, queue the notification until the next tick, so that it doesn't occur within the AssetCatalogRequestBus mutex, and also
|
||||
// So instead, queue the notification until after the AssetCatalogRequestBus mutex is unlocked for the current thread, and also
|
||||
// so that the entire AssetCatalog initialization is complete.
|
||||
AZ::TickBus::QueueFunction([catalogRegistryString = AZStd::string(catalogRegistryFile)]()
|
||||
{
|
||||
AssetCatalogEventBus::Broadcast(&AssetCatalogEventBus::Events::OnCatalogLoaded, catalogRegistryString.c_str());
|
||||
});
|
||||
auto OnCatalogLoaded = [catalogRegistryString = AZStd::string(catalogRegistryFile)]()
|
||||
{
|
||||
AssetCatalogEventBus::Broadcast(&AssetCatalogEventBus::Events::OnCatalogLoaded, catalogRegistryString.c_str());
|
||||
};
|
||||
AZ::Data::AssetCatalogRequestBus::QueueFunction(AZStd::move(OnCatalogLoaded));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,6 +978,7 @@ namespace AzFramework
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_registryMutex);
|
||||
|
||||
m_registry->Clear();
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace AzFramework
|
||||
//=========================================================================
|
||||
void AssetRegistry::Clear()
|
||||
{
|
||||
m_assetDependencies = {};
|
||||
m_assetIdToInfo = AssetIdToInfoMap();
|
||||
m_assetPathToId = AssetPathToIdMap();
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Asset/FileTagAsset.h>
|
||||
@@ -89,19 +89,19 @@ namespace AzFramework
|
||||
bool FileTagManager::Save(FileTagType fileTagType, const AZStd::string& destinationFilePath = AZStd::string())
|
||||
{
|
||||
AzFramework::FileTag::FileTagAsset* fileTagAsset = GetFileTagAsset(fileTagType);
|
||||
AZStd::string filePathToSave = destinationFilePath;
|
||||
AZ::IO::Path filePathToSave = destinationFilePath;
|
||||
if (filePathToSave.empty())
|
||||
{
|
||||
filePathToSave = FileTagQueryManager::GetDefaultFileTagFilePath(fileTagType);
|
||||
}
|
||||
|
||||
if (!AzFramework::StringFunc::EndsWith(filePathToSave, AzFramework::FileTag::FileTagAsset::Extension()))
|
||||
if (!filePathToSave.Extension().Native().ends_with(AzFramework::FileTag::FileTagAsset::Extension()))
|
||||
{
|
||||
AZ_Error("FileTag", false, "Unable to save tag file (%s). Invalid file extension, file tag can only have (%s) extension.\n", filePathToSave.c_str(), AzFramework::FileTag::FileTagAsset::Extension());
|
||||
return false;
|
||||
}
|
||||
|
||||
return AZ::Utils::SaveObjectToFile(filePathToSave, AZ::DataStream::StreamType::ST_XML, fileTagAsset);
|
||||
return AZ::Utils::SaveObjectToFile(filePathToSave.Native(), AZ::DataStream::StreamType::ST_XML, fileTagAsset);
|
||||
}
|
||||
|
||||
AZ::Outcome<AZStd::string, AZStd::string> FileTagManager::AddTagsInternal(AZStd::string filePath, FileTagType fileTagType, AZStd::vector<AZStd::string> fileTags, AzFramework::FileTag::FilePatternType filePatternType)
|
||||
@@ -239,17 +239,22 @@ namespace AzFramework
|
||||
QueryFileTagsEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZStd::string FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType fileTagType)
|
||||
AZ::IO::Path FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType fileTagType)
|
||||
{
|
||||
auto destinationFilePath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / EngineAssetSourceRelPath;
|
||||
AZ::IO::Path destinationFilePath;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
settingsRegistry->Get(destinationFilePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
}
|
||||
destinationFilePath /= EngineAssetSourceRelPath;
|
||||
destinationFilePath /= fileTagType == FileTagType::Exclude ? ExcludeFileName : IncludeFileName;
|
||||
destinationFilePath.ReplaceExtension(AzFramework::FileTag::FileTagAsset::Extension());
|
||||
return destinationFilePath.String();
|
||||
return destinationFilePath;
|
||||
}
|
||||
|
||||
bool FileTagQueryManager::Load(const AZStd::string& filePath)
|
||||
{
|
||||
AZStd::string fileToLoad = filePath;
|
||||
AZ::IO::Path fileToLoad = filePath;
|
||||
if (fileToLoad.empty())
|
||||
{
|
||||
fileToLoad = GetDefaultFileTagFilePath(m_fileTagType);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/IO/Path/Path_fwd.h>
|
||||
#include <AzFramework/FileTag/FileTagBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
@@ -88,7 +89,7 @@ namespace AzFramework
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AZStd::string GetDefaultFileTagFilePath(FileTagType fileTagType);
|
||||
static AZ::IO::Path GetDefaultFileTagFilePath(FileTagType fileTagType);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
|
||||
namespace AzFramework
|
||||
@@ -66,7 +67,8 @@ namespace AzFramework
|
||||
m_excludeFileQueryManager.reset(aznew FileTagQueryManager(FileTagType::Exclude));
|
||||
if (!m_excludeFileQueryManager.get()->Load())
|
||||
{
|
||||
AZ_Error("FileTagQueryComponent", false, "Not able to load default exclude file (%s). Please make sure that it exists on disk.\n", FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType::Exclude).c_str());
|
||||
AZ_Error("FileTagQueryComponent", false, "Not able to load default exclude file (%s). Please make sure that it exists on disk.\n",
|
||||
FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType::Exclude).c_str());
|
||||
}
|
||||
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -20,18 +21,15 @@ namespace AZ
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class ViewportRequests
|
||||
: public AZ::EBusTraits
|
||||
class ViewportRequests : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = ViewportId;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
virtual ~ViewportRequests() {}
|
||||
|
||||
//! Gets the current camera's world to view matrix.
|
||||
virtual const AZ::Matrix4x4& GetCameraViewMatrix() const = 0;
|
||||
//! Sets the current camera's world to view matrix.
|
||||
@@ -44,8 +42,36 @@ namespace AzFramework
|
||||
virtual AZ::Transform GetCameraTransform() const = 0;
|
||||
//! Convenience method, sets the camera's world to view matrix from this AZ::Transform.
|
||||
virtual void SetCameraTransform(const AZ::Transform& transform) = 0;
|
||||
|
||||
protected:
|
||||
~ViewportRequests() = default;
|
||||
};
|
||||
|
||||
using ViewportRequestBus = AZ::EBus<ViewportRequests>;
|
||||
|
||||
} //namespace AzFramework
|
||||
//! The additional padding around the viewport when a viewport border is active.
|
||||
struct ViewportBorderPadding
|
||||
{
|
||||
float m_top;
|
||||
float m_bottom;
|
||||
float m_left;
|
||||
float m_right;
|
||||
};
|
||||
|
||||
//! For performing queries about the state of the viewport border.
|
||||
class ViewportBorderRequests : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = ViewportId;
|
||||
|
||||
//! Returns if a viewport border is in effect and what the current dimensions (padding) of the border are.
|
||||
virtual AZStd::optional<ViewportBorderPadding> GetViewportBorderPadding() const = 0;
|
||||
|
||||
protected:
|
||||
~ViewportBorderRequests() = default;
|
||||
};
|
||||
|
||||
using ViewportBorderRequestBus = AZ::EBus<ViewportBorderRequests>;
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -41,7 +41,9 @@ namespace UnitTest
|
||||
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_application->Start({});
|
||||
|
||||
@@ -45,7 +45,9 @@ namespace UnitTest
|
||||
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_application->Start({});
|
||||
|
||||
@@ -305,10 +305,14 @@ namespace UnitTest
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_app->Start(desc);
|
||||
AZ::ComponentApplication::StartupParameters startupParameters;
|
||||
startupParameters.m_loadAssetCatalog = false;
|
||||
m_app->Start(desc, startupParameters);
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
|
||||
@@ -45,6 +45,13 @@ namespace AzGameFramework
|
||||
enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak";
|
||||
m_archive->OpenPack("@products@", enginePakPath.Native());
|
||||
}
|
||||
|
||||
// By default, load all archives in the products folder.
|
||||
// If you want to adjust this for your project, make sure that the archive containing
|
||||
// the bootstrap for the settings registry is still loaded here, and any archives containing
|
||||
// assets used early in startup, like default shaders, are loaded here.
|
||||
constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed)
|
||||
m_archive->OpenPacks(paksFolder);
|
||||
}
|
||||
|
||||
GameApplication::~GameApplication()
|
||||
@@ -80,9 +87,9 @@ namespace AzGameFramework
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
#endif
|
||||
|
||||
// Used the lowercase the platform name since the bootstrap.game.<config>.<platform>.setreg is being loaded
|
||||
// Used the lowercase the platform name since the bootstrap.game.<config>.setreg is being loaded
|
||||
// from the asset cache root where all the files are in lowercased from regardless of the filesystem case-sensitivity
|
||||
static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE "." AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER ".setreg";
|
||||
static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE ".setreg";
|
||||
|
||||
AZ::IO::FixedMaxPath cacheRootPath;
|
||||
if (registry.Get(cacheRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
|
||||
|
||||
+4
@@ -58,6 +58,10 @@ namespace AzToolsFramework
|
||||
//! @return The highest closed entity container id if any, or entityId otherwise.
|
||||
virtual AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const = 0;
|
||||
|
||||
//! Triggers the OnContainerEntityStatusChanged notifications for all registered containers,
|
||||
//! allowing listeners to update correctly.
|
||||
virtual void RefreshAllContainerEntities(AzFramework::EntityContextId entityContextId) const = 0;
|
||||
|
||||
//! Clears all open state information for Container Entities for the EntityContextId provided.
|
||||
//! Used when context is switched, for example in the case of a new root prefab being loaded
|
||||
//! in place of an old one.
|
||||
|
||||
+9
@@ -142,6 +142,15 @@ namespace AzToolsFramework
|
||||
Clear(editorEntityContextId);
|
||||
}
|
||||
|
||||
void ContainerEntitySystemComponent::RefreshAllContainerEntities([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
|
||||
{
|
||||
for (AZ::EntityId containerEntityId : m_containers)
|
||||
{
|
||||
ContainerEntityNotificationBus::Broadcast(
|
||||
&ContainerEntityNotificationBus::Events::OnContainerEntityStatusChanged, containerEntityId, m_openContainers.contains(containerEntityId));
|
||||
}
|
||||
}
|
||||
|
||||
ContainerEntityOperationResult ContainerEntitySystemComponent::Clear(AzFramework::EntityContextId entityContextId)
|
||||
{
|
||||
// We don't yet support multiple entity contexts, so only clear the default.
|
||||
|
||||
+1
@@ -47,6 +47,7 @@ namespace AzToolsFramework
|
||||
ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) override;
|
||||
bool IsContainerOpen(AZ::EntityId entityId) const override;
|
||||
AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override;
|
||||
void RefreshAllContainerEntities(AzFramework::EntityContextId entityContextId) const override;
|
||||
ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) override;
|
||||
bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const override;
|
||||
|
||||
|
||||
@@ -86,6 +86,45 @@ namespace AzToolsFramework::Prefab
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnParentOfFocusedPrefab(
|
||||
[[maybe_unused]] AzFramework::EntityContextId entityContextId)
|
||||
{
|
||||
// If only one instance is in the hierarchy, this operation is invalid
|
||||
size_t hierarchySize = m_instanceFocusHierarchy.size();
|
||||
if (hierarchySize <= 1)
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string("Prefab Focus Handler: Could not complete FocusOnParentOfFocusedPrefab operation while focusing on the root."));
|
||||
}
|
||||
|
||||
// Retrieve parent of currently focused prefab.
|
||||
InstanceOptionalReference parentInstance = m_instanceFocusHierarchy[hierarchySize - 2];
|
||||
|
||||
// Use container entity of parent Instance for focus operations.
|
||||
AZ::EntityId entityId = parentInstance->get().GetContainerEntityId();
|
||||
|
||||
// Initialize Undo Batch object
|
||||
ScopedUndoBatch undoBatch("Edit Prefab");
|
||||
|
||||
// Clear selection
|
||||
{
|
||||
const EntityIdList selectedEntities = EntityIdList{};
|
||||
auto selectionUndo = aznew SelectionCommand(selectedEntities, "Clear Selection");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities);
|
||||
}
|
||||
|
||||
// Edit Prefab
|
||||
{
|
||||
auto editUndo = aznew PrefabFocusUndo("Edit Prefab");
|
||||
editUndo->Capture(entityId);
|
||||
editUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
FocusOnPrefabInstanceOwningEntityId(entityId);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index)
|
||||
{
|
||||
if (index < 0 || index >= m_instanceFocusHierarchy.size())
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace AzToolsFramework::Prefab
|
||||
|
||||
// PrefabFocusPublicInterface overrides ...
|
||||
PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override;
|
||||
PrefabFocusOperationResult FocusOnParentOfFocusedPrefab(AzFramework::EntityContextId entityContextId) override;
|
||||
PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override;
|
||||
AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const override;
|
||||
bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override;
|
||||
|
||||
@@ -30,6 +30,9 @@ namespace AzToolsFramework::Prefab
|
||||
//! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0;
|
||||
|
||||
//! Set the focused prefab instance to the parent of the currently focused prefab instance. Supports undo/redo.
|
||||
virtual PrefabFocusOperationResult FocusOnParentOfFocusedPrefab(AzFramework::EntityContextId entityContextId) = 0;
|
||||
|
||||
//! Set the focused prefab instance to the instance at position index of the current path. Supports undo/redo.
|
||||
//! @param index The index of the instance in the current path that we want the prefab system to focus on.
|
||||
virtual PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) = 0;
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
#include <AzCore/Utils/TypeHash.h>
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
@@ -565,6 +566,7 @@ namespace AzToolsFramework
|
||||
parentId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
|
||||
}
|
||||
|
||||
// If the parent entity isn't owned by a prefab instance, bail.
|
||||
InstanceOptionalReference owningInstanceOfParentEntity = GetOwnerInstanceByEntityId(parentId);
|
||||
if (!owningInstanceOfParentEntity)
|
||||
{
|
||||
@@ -572,6 +574,14 @@ namespace AzToolsFramework
|
||||
"Cannot add entity because the owning instance of parent entity with id '%llu' could not be found.",
|
||||
static_cast<AZ::u64>(parentId)));
|
||||
}
|
||||
|
||||
// If the parent entity is a closed container, bail.
|
||||
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get(); !containerEntityInterface->IsContainerOpen(parentId))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Cannot add entity because the parent entity (id '%llu') is a closed container entity.",
|
||||
static_cast<AZ::u64>(parentId)));
|
||||
}
|
||||
|
||||
EntityAlias entityAlias = Instance::GenerateEntityAlias();
|
||||
|
||||
|
||||
+30
-16
@@ -43,6 +43,7 @@
|
||||
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserSourceDropBus.h>
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
@@ -764,10 +765,21 @@ namespace AzToolsFramework
|
||||
return canHandleData;
|
||||
}
|
||||
|
||||
bool EntityOutlinerListModel::CanDropMimeDataAssets(const QMimeData* data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex& /*parent*/) const
|
||||
bool EntityOutlinerListModel::CanDropMimeDataAssets(
|
||||
const QMimeData* data,
|
||||
[[maybe_unused]] Qt::DropAction action,
|
||||
[[maybe_unused]] int row,
|
||||
[[maybe_unused]] int column,
|
||||
const QModelIndex& parent) const
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
// Disable dropping assets on closed container entities.
|
||||
AZ::EntityId parentId = GetEntityFromIndex(parent);
|
||||
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
!containerEntityInterface->IsContainerOpen(parentId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType()))
|
||||
{
|
||||
return DecodeAssetMimeData(data);
|
||||
@@ -788,8 +800,15 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the parent entity is a closed container, bail.
|
||||
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
!containerEntityInterface->IsContainerOpen(assignParentId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Source Files
|
||||
if (sourceFiles.size() > 0)
|
||||
if (!sourceFiles.empty())
|
||||
{
|
||||
// Get position (center of viewport). If no viewport is available, (0,0,0) will be used.
|
||||
AZ::Vector3 viewportCenterPosition = AZ::Vector3::CreateZero();
|
||||
@@ -973,6 +992,12 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the new parent is a closed container, bail.
|
||||
if (auto containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get(); !containerEntityInterface->IsContainerOpen(newParentId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore entities not owned by the editor context. It is assumed that all entities belong
|
||||
// to the same context since multiple selection doesn't span across views.
|
||||
for (const AZ::EntityId& entityId : selectedEntityIds)
|
||||
@@ -2155,20 +2180,9 @@ namespace AzToolsFramework
|
||||
|
||||
void EntityOutlinerItemDelegate::PaintAncestorForegrounds(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
// Go through ancestors and add them to the stack
|
||||
AZStd::stack<QModelIndex> handlerStack;
|
||||
|
||||
// Ancestor foregrounds are painted on top of the childrens'.
|
||||
for (QModelIndex ancestorIndex = index.parent(); ancestorIndex.isValid(); ancestorIndex = ancestorIndex.parent())
|
||||
{
|
||||
handlerStack.push(ancestorIndex);
|
||||
}
|
||||
|
||||
// Apply the ancestor overrides from top to bottom
|
||||
while (!handlerStack.empty())
|
||||
{
|
||||
QModelIndex ancestorIndex = handlerStack.top();
|
||||
handlerStack.pop();
|
||||
|
||||
AZ::EntityId ancestorEntityId(ancestorIndex.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
|
||||
auto ancestorUiHandler = m_editorEntityFrameworkInterface->GetHandler(ancestorEntityId);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx>
|
||||
|
||||
@@ -92,4 +93,16 @@ namespace AzToolsFramework
|
||||
painter->drawLine(rect.bottomLeft(), rect.bottomRight());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
bool LevelRootUiHandler::OnEntityDoubleClick(AZ::EntityId entityId) const
|
||||
{
|
||||
if (auto prefabFocusPublicInterface = AZ::Interface<Prefab::PrefabFocusPublicInterface>::Get();
|
||||
!prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
|
||||
}
|
||||
|
||||
// Don't propagate event.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace AzToolsFramework
|
||||
bool CanToggleLockVisibility(AZ::EntityId entityId) const override;
|
||||
bool CanRename(AZ::EntityId entityId) const override;
|
||||
void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
bool OnEntityDoubleClick(AZ::EntityId entityId) const override;
|
||||
|
||||
private:
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
|
||||
+127
-15
@@ -35,6 +35,7 @@
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
||||
#include <AzToolsFramework/Viewport/ActionBus.h>
|
||||
|
||||
#include <AzQtComponents/Components/Widgets/CheckBox.h>
|
||||
#include <AzQtComponents/Components/FlowLayout.h>
|
||||
@@ -54,6 +55,7 @@
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollArea>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -61,6 +63,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
AzFramework::EntityContextId PrefabIntegrationManager::s_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
|
||||
ContainerEntityInterface* PrefabIntegrationManager::s_containerEntityInterface = nullptr;
|
||||
EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr;
|
||||
PrefabFocusPublicInterface* PrefabIntegrationManager::s_prefabFocusPublicInterface = nullptr;
|
||||
@@ -136,6 +140,9 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
// Get EditorEntityContextId
|
||||
EditorEntityContextRequestBus::BroadcastResult(s_editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
// Initialize Editor functionality for the Prefab Focus Handler
|
||||
auto prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::Get();
|
||||
prefabFocusInterface->InitializeEditorInterfaces();
|
||||
@@ -145,10 +152,16 @@ namespace AzToolsFramework
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Register(this);
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
|
||||
EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
|
||||
InitializeShortcuts();
|
||||
}
|
||||
|
||||
PrefabIntegrationManager::~PrefabIntegrationManager()
|
||||
{
|
||||
UninitializeShortcuts();
|
||||
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Unregister(this);
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusDisconnect();
|
||||
@@ -161,6 +174,74 @@ namespace AzToolsFramework
|
||||
PrefabUserSettings::Reflect(context);
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::InitializeShortcuts()
|
||||
{
|
||||
// Open/Edit Prefab (+)
|
||||
// We also support = to enable easier editing on compact US keyboards.
|
||||
{
|
||||
m_actions.emplace_back(AZStd::make_unique<QAction>(nullptr));
|
||||
|
||||
m_actions.back()->setShortcuts({ QKeySequence(Qt::Key_Plus), QKeySequence(Qt::Key_Equal) });
|
||||
m_actions.back()->setText("Open/Edit Prefab");
|
||||
m_actions.back()->setStatusTip("Edit the prefab in focus mode.");
|
||||
|
||||
QObject::connect(
|
||||
m_actions.back().get(), &QAction::triggered, m_actions.back().get(),
|
||||
[]
|
||||
{
|
||||
AzToolsFramework::EntityIdList selectedEntities;
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
selectedEntities, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
|
||||
|
||||
if (selectedEntities.size() != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::EntityId selectedEntity = selectedEntities[0];
|
||||
|
||||
if (!s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity))
|
||||
{
|
||||
ContextMenu_EditPrefab(selectedEntity);
|
||||
}
|
||||
});
|
||||
|
||||
EditorActionRequestBus::Broadcast(
|
||||
&EditorActionRequests::AddActionViaBusCrc, AZ_CRC_CE("com.o3de.action.editortransform.prefabopen"),
|
||||
m_actions.back().get());
|
||||
}
|
||||
|
||||
// Close Prefab (-)
|
||||
{
|
||||
m_actions.emplace_back(AZStd::make_unique<QAction>(nullptr));
|
||||
|
||||
m_actions.back()->setShortcuts({ QKeySequence(Qt::Key_Minus) });
|
||||
m_actions.back()->setText("Close Prefab");
|
||||
m_actions.back()->setStatusTip("Close focus mode for this prefab and move one level up.");
|
||||
|
||||
QObject::connect(
|
||||
m_actions.back().get(), &QAction::triggered, m_actions.back().get(),
|
||||
[]
|
||||
{
|
||||
ContextMenu_ClosePrefab();
|
||||
});
|
||||
|
||||
EditorActionRequestBus::Broadcast(
|
||||
&EditorActionRequests::AddActionViaBusCrc, AZ_CRC_CE("com.o3de.action.editortransform.prefabclose"),
|
||||
m_actions.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::UninitializeShortcuts()
|
||||
{
|
||||
m_actions.clear();
|
||||
}
|
||||
|
||||
int PrefabIntegrationManager::GetMenuPosition() const
|
||||
{
|
||||
return aznumeric_cast<int>(EditorContextMenuOrdering::MIDDLE);
|
||||
@@ -181,16 +262,13 @@ namespace AzToolsFramework
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
||||
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
||||
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
// Create Prefab
|
||||
{
|
||||
if (!selectedEntities.empty())
|
||||
{
|
||||
// Hide if the only selected entity is the Focused Instance Container
|
||||
if (selectedEntities.size() > 1 ||
|
||||
selectedEntities[0] != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId))
|
||||
selectedEntities[0] != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(s_editorEntityContextId))
|
||||
{
|
||||
bool layerInSelection = false;
|
||||
|
||||
@@ -254,17 +332,30 @@ namespace AzToolsFramework
|
||||
|
||||
if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity))
|
||||
{
|
||||
// Edit Prefab
|
||||
if (!s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity))
|
||||
{
|
||||
QAction* editAction = menu->addAction(QObject::tr("Edit Prefab"));
|
||||
// Edit Prefab
|
||||
QAction* editAction = menu->addAction(QObject::tr("Open/Edit Prefab"));
|
||||
editAction->setShortcut(QKeySequence(Qt::Key_Plus));
|
||||
editAction->setToolTip(QObject::tr("Edit the prefab in focus mode."));
|
||||
|
||||
QObject::connect(editAction, &QAction::triggered, editAction, [selectedEntity] {
|
||||
ContextMenu_EditPrefab(selectedEntity);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close Prefab
|
||||
QAction* closeAction = menu->addAction(QObject::tr("Close Prefab"));
|
||||
closeAction->setShortcut(QKeySequence(Qt::Key_Minus));
|
||||
closeAction->setToolTip(QObject::tr("Close focus mode for this prefab and move one level up."));
|
||||
|
||||
itemWasShown = true;
|
||||
QObject::connect(
|
||||
closeAction, &QAction::triggered, closeAction,
|
||||
[]
|
||||
{
|
||||
ContextMenu_ClosePrefab();
|
||||
});
|
||||
}
|
||||
|
||||
// Save Prefab
|
||||
@@ -279,9 +370,9 @@ namespace AzToolsFramework
|
||||
QObject::connect(saveAction, &QAction::triggered, saveAction, [selectedEntity] {
|
||||
ContextMenu_SavePrefab(selectedEntity);
|
||||
});
|
||||
|
||||
itemWasShown = true;
|
||||
}
|
||||
|
||||
itemWasShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,7 +386,8 @@ namespace AzToolsFramework
|
||||
QObject::connect(deleteAction, &QAction::triggered, deleteAction, [] { ContextMenu_DeleteSelected(); });
|
||||
|
||||
if (selectedEntities.empty() ||
|
||||
(selectedEntities.size() == 1 && selectedEntities[0] == s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId)))
|
||||
(selectedEntities.size() == 1 &&
|
||||
selectedEntities[0] == s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(s_editorEntityContextId)))
|
||||
{
|
||||
deleteAction->setDisabled(true);
|
||||
}
|
||||
@@ -306,7 +398,7 @@ namespace AzToolsFramework
|
||||
AZ::EntityId selectedEntityId = selectedEntities[0];
|
||||
|
||||
if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntityId) &&
|
||||
selectedEntityId != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId))
|
||||
selectedEntityId != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(s_editorEntityContextId))
|
||||
{
|
||||
QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab..."));
|
||||
QObject::connect(
|
||||
@@ -334,6 +426,24 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::OnStartPlayInEditorBegin()
|
||||
{
|
||||
// Focus on the root prefab (AZ::EntityId() will default to it)
|
||||
s_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId());
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::OnStopPlayInEditor()
|
||||
{
|
||||
// Refresh all containers when leaving Game Mode to ensure everything is synced.
|
||||
QTimer::singleShot(
|
||||
0,
|
||||
[&]()
|
||||
{
|
||||
s_containerEntityInterface->RefreshAllContainerEntities(s_editorEntityContextId);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_CreatePrefab(AzToolsFramework::EntityIdList selectedEntities)
|
||||
{
|
||||
// Save a reference to our currently active window since it will be
|
||||
@@ -343,12 +453,9 @@ namespace AzToolsFramework
|
||||
const AZStd::string prefabFilesPath = "@projectroot@/Prefabs";
|
||||
|
||||
// Remove focused instance container entity if it's part of the list
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
auto focusedContainerIter = AZStd::find(
|
||||
selectedEntities.begin(), selectedEntities.end(),
|
||||
s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId));
|
||||
s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(s_editorEntityContextId));
|
||||
if (focusedContainerIter != selectedEntities.end())
|
||||
{
|
||||
selectedEntities.erase(focusedContainerIter);
|
||||
@@ -500,6 +607,11 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_ClosePrefab()
|
||||
{
|
||||
s_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(s_editorEntityContextId);
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity)
|
||||
{
|
||||
s_prefabFocusPublicInterface->FocusOnOwningPrefab(containerEntity);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserSourceDropBus.h>
|
||||
#include <AzToolsFramework/Editor/EditorContextMenuBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/LevelRootUiHandler.h>
|
||||
@@ -56,6 +57,7 @@ namespace AzToolsFramework
|
||||
, public PrefabInstanceContainerNotificationBus::Handler
|
||||
, public PrefabIntegrationInterface
|
||||
, public QObject
|
||||
, private EditorEntityContextNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabIntegrationManager, AZ::SystemAllocator, 0);
|
||||
@@ -76,6 +78,10 @@ namespace AzToolsFramework
|
||||
// EntityOutlinerSourceDropHandlingBus overrides ...
|
||||
void HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const override;
|
||||
|
||||
// EditorEntityContextNotificationBus overrides ...
|
||||
void OnStartPlayInEditorBegin() override;
|
||||
void OnStopPlayInEditor() override;
|
||||
|
||||
// PrefabInstanceContainerNotificationBus overrides ...
|
||||
void OnPrefabComponentActivate(AZ::EntityId entityId) override;
|
||||
void OnPrefabComponentDeactivate(AZ::EntityId entityId) override;
|
||||
@@ -96,11 +102,16 @@ namespace AzToolsFramework
|
||||
static void ContextMenu_CreatePrefab(AzToolsFramework::EntityIdList selectedEntities);
|
||||
static void ContextMenu_InstantiatePrefab();
|
||||
static void ContextMenu_InstantiateProceduralPrefab();
|
||||
static void ContextMenu_ClosePrefab();
|
||||
static void ContextMenu_EditPrefab(AZ::EntityId containerEntity);
|
||||
static void ContextMenu_SavePrefab(AZ::EntityId containerEntity);
|
||||
static void ContextMenu_DeleteSelected();
|
||||
static void ContextMenu_DetachPrefab(AZ::EntityId containerEntity);
|
||||
|
||||
// Shortcut setup handlers
|
||||
void InitializeShortcuts();
|
||||
void UninitializeShortcuts();
|
||||
|
||||
// Prompt and resolve dialogs
|
||||
static bool QueryUserForPrefabSaveLocation(
|
||||
const AZStd::string& suggestedName, const char* initialTargetDirectory, AZ::u32 prefabUserSettingsId, QWidget* activeWindow,
|
||||
@@ -140,7 +151,10 @@ namespace AzToolsFramework
|
||||
AZStd::unique_ptr<QDialog> ConstructSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference);
|
||||
void SavePrefabsInDialog(QDialog* unsavedPrefabsDialog);
|
||||
|
||||
AZStd::vector<AZStd::unique_ptr<QAction>> m_actions;
|
||||
|
||||
static const AZStd::string s_prefabFileExtension;
|
||||
static AzFramework::EntityContextId s_editorEntityContextId;
|
||||
|
||||
static ContainerEntityInterface* s_containerEntityInterface;
|
||||
static EditorEntityUiInterface* s_editorEntityUiInterface;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
AzFramework::EntityContextId PrefabUiHandler::s_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
|
||||
const QColor PrefabUiHandler::m_backgroundColor = QColor("#444444");
|
||||
const QColor PrefabUiHandler::m_backgroundHoverColor = QColor("#5A5A5A");
|
||||
const QColor PrefabUiHandler::m_backgroundSelectedColor = QColor("#656565");
|
||||
@@ -47,6 +49,9 @@ namespace AzToolsFramework
|
||||
AZ_Assert(false, "PrefabUiHandler - could not get PrefabFocusPublicInterface on PrefabUiHandler construction.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get EditorEntityContextId
|
||||
EditorEntityContextRequestBus::BroadcastResult(s_editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
}
|
||||
|
||||
QString PrefabUiHandler::GenerateItemInfoString(AZ::EntityId entityId) const
|
||||
@@ -180,7 +185,7 @@ namespace AzToolsFramework
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void PrefabUiHandler::PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
void PrefabUiHandler::PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const
|
||||
{
|
||||
if (!painter)
|
||||
@@ -425,19 +430,23 @@ namespace AzToolsFramework
|
||||
|
||||
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
||||
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
|
||||
|
||||
// Go one level up.
|
||||
int length = m_prefabFocusPublicInterface->GetPrefabFocusPathLength(editorEntityContextId);
|
||||
m_prefabFocusPublicInterface->FocusOnPathIndex(editorEntityContextId, length - 2);
|
||||
// Close this prefab and focus on the parent
|
||||
m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(s_editorEntityContextId);
|
||||
}
|
||||
}
|
||||
|
||||
bool PrefabUiHandler::OnEntityDoubleClick(AZ::EntityId entityId) const
|
||||
{
|
||||
// Focus on this prefab
|
||||
m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
|
||||
if (!m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
|
||||
{
|
||||
// Focus on this prefab
|
||||
m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close this prefab and focus on the parent
|
||||
m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(s_editorEntityContextId);
|
||||
}
|
||||
|
||||
// Don't propagate event.
|
||||
return true;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h>
|
||||
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
|
||||
@@ -34,9 +36,12 @@ namespace AzToolsFramework
|
||||
QString GenerateItemTooltip(AZ::EntityId entityId) const override;
|
||||
QIcon GenerateItemIcon(AZ::EntityId entityId) const override;
|
||||
void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const override;
|
||||
void PaintItemForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void PaintDescendantForeground(
|
||||
QPainter* painter,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index,
|
||||
const QModelIndex& descendantIndex) const override;
|
||||
bool OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void OnOutlinerItemCollapse(const QModelIndex& index) const override;
|
||||
bool OnEntityDoubleClick(AZ::EntityId entityId) const override;
|
||||
@@ -49,6 +54,8 @@ namespace AzToolsFramework
|
||||
static QModelIndex GetLastVisibleChild(const QModelIndex& parent);
|
||||
static QModelIndex Internal_GetLastVisibleChild(const QAbstractItemModel* model, const QModelIndex& index);
|
||||
|
||||
static AzFramework::EntityContextId s_editorEntityContextId;
|
||||
|
||||
static constexpr int m_prefabCapsuleRadius = 6;
|
||||
static constexpr int m_prefabBorderThickness = 2;
|
||||
static const QColor m_backgroundColor;
|
||||
|
||||
+3
-4
@@ -59,12 +59,11 @@ namespace AzToolsFramework::Prefab
|
||||
connect(m_backButton, &QToolButton::clicked, this,
|
||||
[&]()
|
||||
{
|
||||
if (int length = m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId); length > 1)
|
||||
{
|
||||
m_prefabFocusPublicInterface->FocusOnPathIndex(m_editorEntityContextId, length - 2);
|
||||
}
|
||||
m_prefabFocusPublicInterface->FocusOnParentOfFocusedPrefab(m_editorEntityContextId);
|
||||
}
|
||||
);
|
||||
|
||||
m_backButton->setToolTip("Up one level (-)");
|
||||
}
|
||||
|
||||
void PrefabViewportFocusPathHandler::OnPrefabFocusChanged()
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiCluster.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiDisplay.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiDisplayLayout.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiSwitcher.h>
|
||||
#include <AzToolsFramework/ViewportUi/ViewportUiTextField.h>
|
||||
#include <QWidget>
|
||||
@@ -19,7 +20,6 @@
|
||||
namespace AzToolsFramework::ViewportUi::Internal
|
||||
{
|
||||
const static int HighlightBorderSize = 5;
|
||||
const static int TopHighlightBorderSize = 25;
|
||||
const static char* HighlightBorderColor = "#4A90E2";
|
||||
|
||||
static void UnparentWidgets(ViewportUiElementIdInfoLookup& viewportUiElementIdInfoLookup)
|
||||
@@ -61,7 +61,7 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
, m_uiOverlay(parent)
|
||||
, m_fullScreenLayout(&m_uiOverlay)
|
||||
, m_uiOverlayLayout()
|
||||
, m_componentModeBorderText(&m_uiOverlay)
|
||||
, m_viewportBorderText(&m_uiOverlay)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -221,11 +221,11 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
|
||||
AZStd::shared_ptr<QWidget> ViewportUiDisplay::GetViewportUiElement(ViewportUiElementId elementId)
|
||||
{
|
||||
auto element = m_viewportUiElements.find(elementId);
|
||||
if (element != m_viewportUiElements.end())
|
||||
if (auto element = m_viewportUiElements.find(elementId); element != m_viewportUiElements.end())
|
||||
{
|
||||
return element->second.m_widget;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -287,27 +287,30 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
{
|
||||
return element.IsValid() && element.m_widget->isVisible();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::CreateViewportBorder(const AZStd::string& borderTitle)
|
||||
{
|
||||
const AZStd::string styleSheet = AZStd::string::format(
|
||||
"border: %dpx solid %s; border-top: %dpx solid %s;", HighlightBorderSize, HighlightBorderColor, TopHighlightBorderSize,
|
||||
"border: %dpx solid %s; border-top: %dpx solid %s;", HighlightBorderSize, HighlightBorderColor, ViewportUiTopBorderSize,
|
||||
HighlightBorderColor);
|
||||
m_uiOverlay.setStyleSheet(styleSheet.c_str());
|
||||
m_uiOverlayLayout.setContentsMargins(
|
||||
HighlightBorderSize + ViewportUiOverlayMargin, TopHighlightBorderSize + ViewportUiOverlayMargin,
|
||||
HighlightBorderSize + ViewportUiOverlayMargin, ViewportUiTopBorderSize + ViewportUiOverlayMargin,
|
||||
HighlightBorderSize + ViewportUiOverlayMargin, HighlightBorderSize + ViewportUiOverlayMargin);
|
||||
m_componentModeBorderText.setVisible(true);
|
||||
m_componentModeBorderText.setText(borderTitle.c_str());
|
||||
m_viewportBorderText.setVisible(true);
|
||||
m_viewportBorderText.setText(borderTitle.c_str());
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::RemoveViewportBorder()
|
||||
{
|
||||
m_componentModeBorderText.setVisible(false);
|
||||
m_viewportBorderText.setVisible(false);
|
||||
m_uiOverlay.setStyleSheet("border: none;");
|
||||
m_uiOverlayLayout.setMargin(ViewportUiOverlayMargin);
|
||||
m_uiOverlayLayout.setContentsMargins(
|
||||
ViewportUiOverlayMargin, ViewportUiOverlayMargin + ViewportUiOverlayTopMarginPadding, ViewportUiOverlayMargin,
|
||||
ViewportUiOverlayMargin);
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::PositionViewportUiElementFromWorldSpace(ViewportUiElementId elementId, const AZ::Vector3& pos)
|
||||
@@ -359,10 +362,10 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
|
||||
// format the label which will appear on top of the highlight border
|
||||
AZStd::string styleSheet = AZStd::string::format("background-color: %s; border: none;", HighlightBorderColor);
|
||||
m_componentModeBorderText.setStyleSheet(styleSheet.c_str());
|
||||
m_componentModeBorderText.setFixedHeight(TopHighlightBorderSize);
|
||||
m_componentModeBorderText.setVisible(false);
|
||||
m_fullScreenLayout.addWidget(&m_componentModeBorderText, 0, 0, Qt::AlignTop | Qt::AlignHCenter);
|
||||
m_viewportBorderText.setStyleSheet(styleSheet.c_str());
|
||||
m_viewportBorderText.setFixedHeight(ViewportUiTopBorderSize);
|
||||
m_viewportBorderText.setVisible(false);
|
||||
m_fullScreenLayout.addWidget(&m_viewportBorderText, 0, 0, Qt::AlignTop | Qt::AlignHCenter);
|
||||
}
|
||||
|
||||
void ViewportUiDisplay::PrepareWidgetForViewportUi(QPointer<QWidget> widget)
|
||||
@@ -395,14 +398,14 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
|
||||
void ViewportUiDisplay::UpdateUiOverlayGeometry()
|
||||
{
|
||||
// add the component mode border region if visible
|
||||
// add the viewport border region if visible
|
||||
QRegion region;
|
||||
if (m_componentModeBorderText.isVisible())
|
||||
if (m_viewportBorderText.isVisible())
|
||||
{
|
||||
// get the border region by taking the entire region and subtracting the non-border area
|
||||
region += m_uiOverlay.rect();
|
||||
region -= QRect(
|
||||
QPoint(m_uiOverlay.rect().left() + HighlightBorderSize, m_uiOverlay.rect().top() + TopHighlightBorderSize),
|
||||
QPoint(m_uiOverlay.rect().left() + HighlightBorderSize, m_uiOverlay.rect().top() + ViewportUiTopBorderSize),
|
||||
QPoint(m_uiOverlay.rect().right() - HighlightBorderSize, m_uiOverlay.rect().bottom() - HighlightBorderSize));
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
QWidget m_uiOverlay; //!< The UI Overlay which displays Viewport UI Elements.
|
||||
QGridLayout m_fullScreenLayout; //!< The layout which extends across the full screen.
|
||||
ViewportUiDisplayLayout m_uiOverlayLayout; //!< The layout used for optionally anchoring Viewport UI Elements.
|
||||
QLabel m_componentModeBorderText; //!< The text used for the Component Mode border.
|
||||
QLabel m_viewportBorderText; //!< The text used for the viewport border.
|
||||
|
||||
QWidget* m_renderOverlay;
|
||||
QPointer<QWidget> m_fullScreenWidget; //!< Reference to the widget attached to m_fullScreenLayout if any.
|
||||
|
||||
+12
-5
@@ -14,13 +14,20 @@
|
||||
#include <QGridLayout>
|
||||
#include <QPointer>
|
||||
|
||||
namespace AzToolsFramework::ViewportUi
|
||||
{
|
||||
//! Margin for the Viewport UI Overlay (in pixels)
|
||||
constexpr int ViewportUiOverlayMargin = 5;
|
||||
//! Padding to make space for ImGui (in pixels)
|
||||
constexpr int ViewportUiOverlayTopMarginPadding = 20;
|
||||
//! Size of the top viewport border (in pixels)
|
||||
constexpr int ViewportUiTopBorderSize = 25;
|
||||
//! Size of the left, right and bottom viewport border (in pixels)
|
||||
constexpr int ViewportUiLeftRightBottomBorderSize = 5;
|
||||
} // namespace AzToolsFramework::ViewportUi
|
||||
|
||||
namespace AzToolsFramework::ViewportUi::Internal
|
||||
{
|
||||
// margin for the Viewport UI Overlay in pixels
|
||||
constexpr int ViewportUiOverlayMargin = 5;
|
||||
// padding to make space for ImGui
|
||||
constexpr int ViewportUiOverlayTopMarginPadding = 20;
|
||||
|
||||
//! QGridLayout implementation that uses a grid of QVBox/QHBoxLayouts internally to stack widgets.
|
||||
class ViewportUiDisplayLayout : public QGridLayout
|
||||
{
|
||||
|
||||
@@ -57,9 +57,7 @@ namespace UnitTest
|
||||
ArgumentContainer argContainer{ {} };
|
||||
|
||||
// Append Command Line override for the Project Cache Path
|
||||
auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", m_tempDir.GetDirectory());
|
||||
auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" };
|
||||
argContainer.push_back(projectCachePathOverride.data());
|
||||
auto projectPathOverride = FixedValueString::format(R"(--project-path="%s")", m_tempDir.GetDirectory());
|
||||
argContainer.push_back(projectPathOverride.data());
|
||||
m_application = new ToolsTestApplication("AssetFileInfoListComparisonTest", aznumeric_caster(argContainer.size()), argContainer.data());
|
||||
AzToolsFramework::AssetSeedManager assetSeedManager;
|
||||
@@ -100,7 +98,7 @@ namespace UnitTest
|
||||
m_application->Start(AzFramework::Application::Descriptor());
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
@@ -223,7 +221,7 @@ namespace UnitTest
|
||||
|
||||
// AssetFileInfo should contain {2*, 4*, 5}
|
||||
AzToolsFramework::AssetFileInfoList assetFileInfoList;
|
||||
|
||||
|
||||
ASSERT_TRUE(AZ::Utils::LoadObjectFromFileInPlace(TempFiles[FileIndex::ResultAssetFileInfoList], assetFileInfoList)) << "Unable to read the asset file info list.\n";
|
||||
|
||||
EXPECT_EQ(assetFileInfoList.m_fileInfoList.size(), 3);
|
||||
@@ -256,7 +254,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[2], m_assets[4], m_assets[5] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -298,7 +296,7 @@ namespace UnitTest
|
||||
{
|
||||
firstAssetIdToAssetFileInfoMap[assetFileInfo.m_assetId] = AZStd::move(assetFileInfo);
|
||||
}
|
||||
|
||||
|
||||
AzToolsFramework::AssetFileInfoList secondAssetFileInfoList;
|
||||
ASSERT_TRUE(AZ::Utils::LoadObjectFromFileInPlace(TempFiles[FileIndex::SecondAssetFileInfoList], secondAssetFileInfoList)) << "Unable to read the asset file info list.\n";
|
||||
|
||||
@@ -315,7 +313,7 @@ namespace UnitTest
|
||||
auto foundSecond = secondAssetIdToAssetFileInfoMap.find(assetFileInfo.m_assetId);
|
||||
if (foundSecond != secondAssetIdToAssetFileInfoMap.end())
|
||||
{
|
||||
// Even if the asset Id is present in both the AssetFileInfo List, it should match the file hash from the second AssetFileInfo list
|
||||
// Even if the asset Id is present in both the AssetFileInfo List, it should match the file hash from the second AssetFileInfo list
|
||||
for (int idx = 0; idx < AzToolsFramework::AssetFileInfo::s_arraySize; idx++)
|
||||
{
|
||||
if (foundSecond->second.m_hash[idx] != assetFileInfo.m_hash[idx])
|
||||
@@ -343,7 +341,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[0], m_assets[1], m_assets[2], m_assets[3], m_assets[4], m_assets[5] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -403,7 +401,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[1], m_assets[2], m_assets[3], m_assets[4] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -462,7 +460,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[5] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -493,7 +491,7 @@ namespace UnitTest
|
||||
|
||||
EXPECT_EQ(assetFileInfoList.m_fileInfoList.size(), 5);
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[0], m_assets[1], m_assets[2], m_assets[3], m_assets[4] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -601,7 +599,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[2] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -625,12 +623,12 @@ namespace UnitTest
|
||||
AssetFileInfoListComparison::ComparisonData filePatternComparisonData(AssetFileInfoListComparison::ComparisonType::FilePattern,"$1", "Asset[0-3].txt", AssetFileInfoListComparison::FilePatternType::Regex);
|
||||
filePatternComparisonData.m_firstInput = TempFiles[FileIndex::FirstAssetFileInfoList];
|
||||
assetFileInfoListComparison.AddComparisonStep(filePatternComparisonData);
|
||||
|
||||
|
||||
AzToolsFramework::AssetFileInfoListComparison::ComparisonData deltaComparisonData(AzToolsFramework::AssetFileInfoListComparison::ComparisonType::Delta, TempFiles[FileIndex::ResultAssetFileInfoList]);
|
||||
deltaComparisonData.m_firstInput = "$1";
|
||||
deltaComparisonData.m_secondInput = TempFiles[FileIndex::SecondAssetFileInfoList];
|
||||
assetFileInfoListComparison.AddComparisonStep(deltaComparisonData);
|
||||
|
||||
|
||||
ASSERT_TRUE(assetFileInfoListComparison.CompareAndSaveResults().IsSuccess()) << "Multiple Comparison Operation( FilePattern + Delta ) failed.\n";
|
||||
// Output of the FilePattern Operation should be {0,1,2,3}
|
||||
// Output of the Delta Operation should be {2*,4*,5}
|
||||
@@ -666,7 +664,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[2], m_assets[4], m_assets[5] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
@@ -738,7 +736,7 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
// Verifying that correct assetId are present in the assetFileInfo list
|
||||
AZStd::unordered_set<AZ::Data::AssetId> expectedAssetIds{ m_assets[4], m_assets[5] };
|
||||
|
||||
for (const AzToolsFramework::AssetFileInfo& assetFileInfo : assetFileInfoList.m_fileInfoList)
|
||||
|
||||
@@ -63,10 +63,8 @@ namespace UnitTest
|
||||
ArgumentContainer argContainer{ {} };
|
||||
|
||||
// Append Command Line override for the Project Cache Path
|
||||
AZ::IO::Path cacheProjectRootFolder{ m_tempDir.GetDirectory() };
|
||||
auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", cacheProjectRootFolder.c_str());
|
||||
auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" };
|
||||
argContainer.push_back(projectCachePathOverride.data());
|
||||
auto cacheProjectRootFolder = AZ::IO::Path{ m_tempDir.GetDirectory() } / "Cache";
|
||||
auto projectPathOverride = FixedValueString::format(R"(--project-path="%s")", m_tempDir.GetDirectory());
|
||||
argContainer.push_back(projectPathOverride.data());
|
||||
m_application = new ToolsTestApplication("AssetSeedManagerTest", aznumeric_caster(argContainer.size()), argContainer.data());
|
||||
m_assetSeedManager = new AzToolsFramework::AssetSeedManager();
|
||||
|
||||
@@ -572,7 +572,9 @@ namespace UnitTest
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
AzFramework::Application::Descriptor descriptor;
|
||||
|
||||
@@ -59,7 +59,9 @@ protected:
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_app.Start(AZ::ComponentApplication::Descriptor());
|
||||
@@ -184,7 +186,9 @@ public:
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_app.Start(AzFramework::Application::Descriptor());
|
||||
|
||||
@@ -44,10 +44,8 @@ namespace UnitTest
|
||||
ArgumentContainer argContainer{ {} };
|
||||
|
||||
// Append Command Line override for the Project Cache Path
|
||||
AZ::IO::Path cacheProjectRootFolder{ m_tempDir.GetDirectory() };
|
||||
auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", cacheProjectRootFolder.c_str());
|
||||
auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" };
|
||||
argContainer.push_back(projectCachePathOverride.data());
|
||||
auto cacheProjectRootFolder = AZ::IO::Path{ m_tempDir.GetDirectory() } / "Cache";
|
||||
auto projectPathOverride = FixedValueString::format(R"(--project-path="%s")", m_tempDir.GetDirectory());
|
||||
argContainer.push_back(projectPathOverride.data());
|
||||
m_application = new ToolsTestApplication("AddressedAssetCatalogManager", aznumeric_caster(argContainer.size()), argContainer.data());
|
||||
|
||||
@@ -195,10 +193,7 @@ namespace UnitTest
|
||||
ArgumentContainer argContainer{ {} };
|
||||
|
||||
// Append Command Line override for the Project Cache Path
|
||||
AZ::IO::Path cacheProjectRootFolder{ m_tempDir.GetDirectory() };
|
||||
auto projectCachePathOverride = FixedValueString::format(R"(--project-cache-path="%s")", cacheProjectRootFolder.c_str());
|
||||
auto projectPathOverride = FixedValueString{ R"(--project-path=AutomatedTesting)" };
|
||||
argContainer.push_back(projectCachePathOverride.data());
|
||||
auto projectPathOverride = FixedValueString::format(R"(--project-path="%s")", m_tempDir.GetDirectory());
|
||||
argContainer.push_back(projectPathOverride.data());
|
||||
m_application = new ToolsTestApplication("MessageTest", aznumeric_caster(argContainer.size()), argContainer.data());
|
||||
|
||||
|
||||
@@ -1059,7 +1059,9 @@ namespace UnitTest
|
||||
AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
AZ::IO::FixedMaxPath enginePath;
|
||||
registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
|
||||
m_app.Start(AzFramework::Application::Descriptor());
|
||||
|
||||
Reference in New Issue
Block a user