Merge branch 'development' into o3de_sdk/installer_configs
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#import <AppKit/NSEvent.h>
|
||||
|
||||
#include "EditorDefs.h"
|
||||
#include "QtEditorApplication.h"
|
||||
#include "QtEditorApplication_mac.h"
|
||||
|
||||
// AzFramework
|
||||
#include <AzFramework/Input/Buses/Notifications/RawInputNotificationBus_Platform.h>
|
||||
|
||||
@@ -1788,6 +1788,11 @@ AZStd::string SandboxIntegrationManager::GetComponentEditorIcon(const AZ::Uuid&
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
AZStd::string SandboxIntegrationManager::GetComponentTypeEditorIcon(const AZ::Uuid& componentType)
|
||||
{
|
||||
return GetComponentEditorIcon(componentType, nullptr);
|
||||
}
|
||||
|
||||
AZStd::string SandboxIntegrationManager::GetComponentIconPath(const AZ::Uuid& componentType,
|
||||
AZ::Crc32 componentIconAttrib, AZ::Component* component)
|
||||
{
|
||||
|
||||
@@ -233,6 +233,7 @@ private:
|
||||
}
|
||||
|
||||
AZStd::string GetComponentEditorIcon(const AZ::Uuid& componentType, AZ::Component* component) override;
|
||||
AZStd::string GetComponentTypeEditorIcon(const AZ::Uuid& componentType) override;
|
||||
AZStd::string GetComponentIconPath(const AZ::Uuid& componentType, AZ::Crc32 componentIconAttrib, AZ::Component* component) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ ComponentDataModel::ComponentDataModel(QObject* parent)
|
||||
if (element.m_elementId == AZ::Edit::ClassElements::EditorData)
|
||||
{
|
||||
AZStd::string iconPath;
|
||||
EBUS_EVENT_RESULT(iconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, classData->m_typeId, nullptr);
|
||||
AzToolsFramework::EditorRequestBus::BroadcastResult(iconPath, &AzToolsFramework::EditorRequests::GetComponentTypeEditorIcon, classData->m_typeId);
|
||||
if (!iconPath.empty())
|
||||
{
|
||||
m_componentIcons[classData->m_typeId] = QIcon(iconPath.c_str());
|
||||
|
||||
@@ -408,7 +408,7 @@ CTrackViewNodesCtrl::CTrackViewNodesCtrl(QWidget* hParentWnd, CTrackViewDialog*
|
||||
serializeContext->EnumerateDerived<AZ::Component>([this](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid&) -> bool
|
||||
{
|
||||
AZStd::string iconPath;
|
||||
EBUS_EVENT_RESULT(iconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, classData->m_typeId, nullptr);
|
||||
AzToolsFramework::EditorRequestBus::BroadcastResult(iconPath, &AzToolsFramework::EditorRequests::GetComponentTypeEditorIcon, classData->m_typeId);
|
||||
if (!iconPath.empty())
|
||||
{
|
||||
m_componentTypeToIconMap[classData->m_typeId] = QIcon(iconPath.c_str());
|
||||
|
||||
@@ -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>
|
||||
@@ -216,11 +215,6 @@ namespace AZ
|
||||
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 +500,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 +524,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 +556,7 @@ namespace AZ
|
||||
{
|
||||
AZ::Interface<AZ::IConsole>::Unregister(m_console);
|
||||
delete m_console;
|
||||
ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ConsoleUnavailable", R"({})");
|
||||
}
|
||||
|
||||
m_moduleManager.reset();
|
||||
@@ -558,6 +564,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 +680,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 +701,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 +767,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,87 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
|
||||
using Type = AZ::SettingsRegistryInterface::Type;
|
||||
using NotifyEventHandler = AZ::SettingsRegistryInterface::NotifyEventHandler;
|
||||
|
||||
if (!ValidateEvent(settingsRegistry, eventName))
|
||||
{
|
||||
AZ_Warning("ComponentApplicationLifecycle", false, R"(Cannot register 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 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,54 @@
|
||||
/*
|
||||
* 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/Runtime/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
|
||||
//! @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);
|
||||
}
|
||||
@@ -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__))
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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/DOM/DomVisitor.h>
|
||||
|
||||
namespace AZ::DOM
|
||||
{
|
||||
const char* VisitorError::CodeToString(VisitorErrorCode code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case VisitorErrorCode::UnsupportedOperation:
|
||||
return "operation not supported";
|
||||
case VisitorErrorCode::InvalidData:
|
||||
return "invalid data specified";
|
||||
case VisitorErrorCode::InternalError:
|
||||
return "internal error";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
VisitorError::VisitorError(VisitorErrorCode code)
|
||||
: m_code(code)
|
||||
{
|
||||
}
|
||||
|
||||
VisitorError::VisitorError(VisitorErrorCode code, AZStd::string additionalInfo)
|
||||
: m_code(code)
|
||||
, m_additionalInfo(AZStd::move(additionalInfo))
|
||||
{
|
||||
}
|
||||
|
||||
VisitorErrorCode VisitorError::GetCode() const
|
||||
{
|
||||
return m_code;
|
||||
}
|
||||
|
||||
const AZStd::string& VisitorError::GetAdditionalInfo() const
|
||||
{
|
||||
return m_additionalInfo;
|
||||
}
|
||||
|
||||
AZStd::string VisitorError::FormatVisitorErrorMessage() const
|
||||
{
|
||||
if (m_additionalInfo.empty())
|
||||
{
|
||||
return AZStd::string::format("VisitorError: %s.", CodeToString(m_code));
|
||||
}
|
||||
return AZStd::string::format("VisitorError: %s. %s.", CodeToString(m_code), m_additionalInfo.c_str());
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::VisitorFailure(VisitorErrorCode code)
|
||||
{
|
||||
return AZ::Failure(VisitorError(code));
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo)
|
||||
{
|
||||
return AZ::Failure(VisitorError(code, AZStd::move(additionalInfo)));
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::VisitorFailure(VisitorError error)
|
||||
{
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::VisitorSuccess()
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::Null()
|
||||
{
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::Bool([[maybe_unused]] bool value)
|
||||
{
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::Int64([[maybe_unused]] AZ::s64 value)
|
||||
{
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::Uint64([[maybe_unused]] AZ::u64 value)
|
||||
{
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::Double([[maybe_unused]] double value)
|
||||
{
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::String([[maybe_unused]] AZStd::string_view value, [[maybe_unused]] Lifetime lifetime)
|
||||
{
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::OpaqueValue([[maybe_unused]] const OpaqueType& value, [[maybe_unused]] Lifetime lifetime)
|
||||
{
|
||||
if (!SupportsOpaqueValues())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Opaque values are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::RawValue([[maybe_unused]] AZStd::string_view value, [[maybe_unused]] Lifetime lifetime)
|
||||
{
|
||||
if (!SupportsRawValues())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Raw values are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::StartObject()
|
||||
{
|
||||
if (!SupportsObjects())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Objects are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::EndObject([[maybe_unused]] AZ::u64 attributeCount)
|
||||
{
|
||||
if (!SupportsObjects())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Objects are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::Key([[maybe_unused]] AZ::Name key)
|
||||
{
|
||||
if (!SupportsObjects() && !SupportsNodes())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Keys are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime)
|
||||
{
|
||||
if (!SupportsRawKeys())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Raw keys are not supported by this visitor");
|
||||
}
|
||||
return Key(AZ::Name(key));
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::StartArray()
|
||||
{
|
||||
if (!SupportsArrays())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Arrays are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::EndArray([[maybe_unused]] AZ::u64 elementCount)
|
||||
{
|
||||
if (!SupportsArrays())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Arrays are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::StartNode([[maybe_unused]] AZ::Name name)
|
||||
{
|
||||
if (!SupportsNodes())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Nodes are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::RawStartNode(AZStd::string_view name, [[maybe_unused]] Lifetime lifetime)
|
||||
{
|
||||
return StartNode(AZ::Name(name));
|
||||
}
|
||||
|
||||
Visitor::Result Visitor::EndNode([[maybe_unused]] AZ::u64 attributeCount, [[maybe_unused]] AZ::u64 elementCount)
|
||||
{
|
||||
if (!SupportsNodes())
|
||||
{
|
||||
return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Nodes are not supported by this visitor");
|
||||
}
|
||||
return VisitorSuccess();
|
||||
}
|
||||
|
||||
VisitorFlags Visitor::GetVisitorFlags() const
|
||||
{
|
||||
// By default support raw keys (promoting them to AZ::Name) and support Array / Object / Node
|
||||
// We leave Opaque type support and Raw Values to more specialized, implementation-specific cases
|
||||
return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes;
|
||||
}
|
||||
|
||||
bool Visitor::SupportsRawValues() const
|
||||
{
|
||||
return (GetVisitorFlags() & VisitorFlags::SupportsRawValues) != VisitorFlags::Null;
|
||||
}
|
||||
|
||||
bool Visitor::SupportsRawKeys() const
|
||||
{
|
||||
return (GetVisitorFlags() & VisitorFlags::SupportsRawKeys) != VisitorFlags::Null;
|
||||
}
|
||||
|
||||
bool Visitor::SupportsObjects() const
|
||||
{
|
||||
return (GetVisitorFlags() & VisitorFlags::SupportsObjects) != VisitorFlags::Null;
|
||||
}
|
||||
|
||||
bool Visitor::SupportsArrays() const
|
||||
{
|
||||
return (GetVisitorFlags() & VisitorFlags::SupportsArrays) != VisitorFlags::Null;
|
||||
}
|
||||
|
||||
bool Visitor::SupportsNodes() const
|
||||
{
|
||||
return (GetVisitorFlags() & VisitorFlags::SupportsNodes) != VisitorFlags::Null;
|
||||
}
|
||||
|
||||
bool Visitor::SupportsOpaqueValues() const
|
||||
{
|
||||
return (GetVisitorFlags() & VisitorFlags::SupportsOpaqueValues) != VisitorFlags::Null;
|
||||
}
|
||||
} // namespace AZ::DOM
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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/Name/Name.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/any.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ::DOM
|
||||
{
|
||||
//
|
||||
// Lifetime enum
|
||||
//
|
||||
//! Specifies the period in which a reference value will still be alive and safe to read.
|
||||
enum class Lifetime
|
||||
{
|
||||
//! Specifies that the value is safe to read and will remain so indefinitely.
|
||||
//! This implies that the value will not be mutated for the duration of this storage.
|
||||
Persistent,
|
||||
//! Specifies that the value may change or be deallocated, and must be copied to be safely stored.
|
||||
Temporary,
|
||||
};
|
||||
|
||||
//
|
||||
// VisitorErrorCode enum
|
||||
//
|
||||
//! Error code specifying the reason a Visitor operation failed.
|
||||
enum class VisitorErrorCode
|
||||
{
|
||||
//! Set when a Visitor doesn't have an implementation for a given attribute type.
|
||||
//! A pure-JSON serializer might reject a Node attribute, for example, and serialization visitors
|
||||
//! can forbid non-serializable Opaque types.
|
||||
UnsupportedOperation,
|
||||
//! Set when a Visitor has received malformed or invalid data.
|
||||
//! Potential sources include mismatching Begin/End call pairs or invalid attribute or element counts
|
||||
//! being sent to End methods.
|
||||
InvalidData,
|
||||
//! The Visitor failed for some other reason not caused by invalid input.
|
||||
//! If returning a custom error with this code, it's preferrable to also provide supplemental info
|
||||
//! in the form of an explanatory string.
|
||||
InternalError
|
||||
};
|
||||
|
||||
//
|
||||
// VisitorError class
|
||||
//
|
||||
//! Details of the reason for failure within a VisitorInterface operation.
|
||||
class VisitorError final
|
||||
{
|
||||
public:
|
||||
explicit VisitorError(VisitorErrorCode code);
|
||||
VisitorError(VisitorErrorCode code, AZStd::string additionalInfo);
|
||||
|
||||
//! Gets the error code associated with this error.
|
||||
VisitorErrorCode GetCode() const;
|
||||
//! Gets a supplemental error info string from the error.
|
||||
//! Returns an empty string if no additional information was provided to the error.
|
||||
const AZStd::string& GetAdditionalInfo() const;
|
||||
//! Provides a formatted, human-readable error description that can be used for logging purposes.
|
||||
AZStd::string FormatVisitorErrorMessage() const;
|
||||
|
||||
//! Helper method, translates a VisitorErrorCode to a human readable string.
|
||||
static const char* CodeToString(VisitorErrorCode code);
|
||||
|
||||
private:
|
||||
VisitorErrorCode m_code;
|
||||
AZStd::string m_additionalInfo;
|
||||
};
|
||||
|
||||
//! A type alias for opaque DOM types that aren't meant to be serializable.
|
||||
//! /see VisitorInterface::OpaqueValue
|
||||
using OpaqueType = AZStd::any;
|
||||
|
||||
//
|
||||
// VisitorFlags enum
|
||||
//
|
||||
//! Flags representning capabilities of a \ref Visitor.
|
||||
enum class VisitorFlags : AZ::u16
|
||||
{
|
||||
//! No flags are set. This can be used in conjunction with bitwise operators to check a flag.
|
||||
Null = 0,
|
||||
//! If set, this Visitor interface supports raw strings in place of specific value types.
|
||||
//! Visitors with this flag accept RawValue calls in lieu of more specific value calls such as Int64 or String.
|
||||
SupportsRawValues = (1 << 1),
|
||||
//! If set, this Visitor interface supports raw strings in place of Name types for keys and Node names.
|
||||
//! Visitors with this flag accept RawKey and RawStartNode in lieu of Key and StartNode calls.
|
||||
SupportsRawKeys = (1 << 2),
|
||||
//! If set, this Visitor interface supports Object types described via BeginObject and EndObject.
|
||||
SupportsObjects = (1 << 3),
|
||||
//! If set, this Visitor interface supports Array types described via BeginArray and EndArray.
|
||||
SupportsArrays = (1 << 4),
|
||||
//! If set, this Visitor interface supports Node types described BeginNode and EndNode.
|
||||
SupportsNodes = (1 << 4),
|
||||
//! If set, this Visitor interface supports opaque values described via OpaqueValue.
|
||||
SupportsOpaqueValues = (1 << 5),
|
||||
};
|
||||
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(VisitorFlags);
|
||||
|
||||
//
|
||||
// Visitor class
|
||||
//
|
||||
//! An interface for performing operations on elements of a generic DOM (Document Object Model).
|
||||
//! A Document Object Model is defined here as a tree structure comprised of one of the following values:
|
||||
//! - Primitives: plain data types, including
|
||||
//! - \ref Int64: 64 bit signed integer
|
||||
//! - \ref Uint64: 64 bit unsigned integer
|
||||
//! - \ref Bool: boolean value
|
||||
//! - \ref Double: 64 bit double precision float
|
||||
//! - \ref Null: sentinel "empty" type with no value representation
|
||||
//! - \ref String: UTF8 encoded string
|
||||
//! - \ref Object: an ordered container of key/value pairs where keys are AZ::Names and values may be any DOM type
|
||||
//! (including Object)
|
||||
//! - \ref Array: an ordered container of values, in which values are any DOM value type (including Array)
|
||||
//! - \ref Node: a container
|
||||
//! - \ref OpaqueValue: An arbitrary value stored in an AZStd::any. This is a non-serializable representation of an
|
||||
//! entry useful for in-memory options. This is intended to be used as an intermediate value over the course of DOM
|
||||
//! transformation and as a proxy to pass through types of which the DOM has no knowledge to other systems.
|
||||
//!
|
||||
//! Opaque values are rejected by the default VisitorInterface implementation.
|
||||
//!
|
||||
//! Care should be ensured that DOMs representing opaque types are only visited by consumers that understand them.
|
||||
class Visitor
|
||||
{
|
||||
public:
|
||||
virtual ~Visitor() = default;
|
||||
|
||||
//! The result of a Visitor operation.
|
||||
//! A failure indicates a non-recoverable issue and signals that no further visit calls may be made in the
|
||||
//! current state.
|
||||
using Result = AZ::Outcome<void, VisitorError>;
|
||||
|
||||
//! Returns a set of flags representing the operations this Visitor supports.
|
||||
//! The base implementation supports raw keys (\see VisitorFlags::SupportsRawKeys) and
|
||||
//! arrays (\see VisitorFlags::SupportsArrays), objects (\see VisitorFlags::SupportsObjects), and
|
||||
//! nodes (\see VisitorFlags::SupportsNodes).
|
||||
//! Raw (\see VisitorFlags::SupportsRawValues) and opaque values (\see VisitorFlags::SupportsOpaqueValues)
|
||||
//! are disallowed by default, as their handling is intended to be implementation-specific.
|
||||
virtual VisitorFlags GetVisitorFlags() const;
|
||||
//! /see VisitorFlags::SupportsRawValues
|
||||
bool SupportsRawValues() const;
|
||||
//! /see VisitorFlags::SupportsRawKeys
|
||||
bool SupportsRawKeys() const;
|
||||
//! /see VisitorFlags::SupportsObjects
|
||||
bool SupportsObjects() const;
|
||||
//! /see VisitorFlags::SupportsArrays
|
||||
bool SupportsArrays() const;
|
||||
//! /see VisitorFlags::SupportsNodes
|
||||
bool SupportsNodes() const;
|
||||
//! /see VisitorFlags::SupportsOpaqueValues
|
||||
bool SupportsOpaqueValues() const;
|
||||
|
||||
//! Operates on an empty null value.
|
||||
virtual Result Null();
|
||||
//! Operates on a bool value.
|
||||
virtual Result Bool(bool value);
|
||||
//! Operates on a signed, 64 bit integer value.
|
||||
virtual Result Int64(AZ::s64 value);
|
||||
//! Operates on an unsigned, 64 bit integer value.
|
||||
virtual Result Uint64(AZ::u64 value);
|
||||
//! Operates on a double precision, 64 bit floating point value.
|
||||
virtual Result Double(double value);
|
||||
//! Operates on a string value. As strings are a reference type.
|
||||
//! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
|
||||
virtual Result String(AZStd::string_view value, Lifetime lifetime);
|
||||
//! Operates on an opaque value. As opaque values are a reference type, storage semantics are provided to
|
||||
//! indicate where the value may be stored persistently or requires a copy.
|
||||
//! The base implementation of OpaqueValue rejects the operation, as opaque values are meant for special
|
||||
//! cases with specific implementations, not generic usage.
|
||||
//! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy.
|
||||
virtual Result OpaqueValue(const OpaqueType& value, Lifetime lifetime);
|
||||
//! Operates on a raw value encoded as a UTF-8 string that hasn't had its type deduced.
|
||||
//! Visitors that support raw values (\see VisitorFlags::SupportsRawValues) may parse the raw value and
|
||||
//! forward it to the corresponding value call or calls of their choice.
|
||||
//! The base implementation of RawValue rejects the operation, as raw values are meant to be handled on
|
||||
//! a per-implementation basis.
|
||||
virtual Result RawValue(AZStd::string_view value, Lifetime lifetime);
|
||||
|
||||
//! Operates on an Object.
|
||||
//! Callers may make any number of Key calls, followed by calls representing a value (including a nested
|
||||
//! StartObject call) and then must call EndObject.
|
||||
virtual Result StartObject();
|
||||
//! Finishes operating on an Object.
|
||||
//! Callers must provide the number of attributes that were provided to the object, i.e. the number of key
|
||||
//! and value calls made within the direct context of this object (but not any nested objects / nodes).
|
||||
virtual Result EndObject(AZ::u64 attributeCount);
|
||||
|
||||
//! Specifies a key for a key/value pair.
|
||||
//! Key must be called subsequent to a call to \ref StartObject or \ref StartNode and immediately followed by
|
||||
//! calls representing the key's associated value.
|
||||
virtual Result Key(AZ::Name key);
|
||||
//! Specifies a key for a key/value pair using a raw string instead of \ref AZ::Name.
|
||||
//! \see Key
|
||||
virtual Result RawKey(AZStd::string_view key, Lifetime lifetime);
|
||||
|
||||
//! Operates on an Array.
|
||||
//! Callers may make any number of subsequent value calls to represent the elements of the array, and then must
|
||||
//! call EndArray.
|
||||
virtual Result StartArray();
|
||||
//! Finishes operating on an Array.
|
||||
//! Callers must provide the number of elements that were provided to the array, i.e. the number of value calls
|
||||
//! made within the direct context of this array (but not any nested arrays / nodes).
|
||||
virtual Result EndArray(AZ::u64 elementCount);
|
||||
|
||||
//! Operates on a Node.
|
||||
//! Callers may make any number of Key calls followed by value calls or value calls not prefixed with a Key
|
||||
//! call, and then must call EndNode. See \ref StartObject and \ref StartArray as Node types combine the
|
||||
//! functionality of both structures into a named Node structure.
|
||||
virtual Result StartNode(AZ::Name name);
|
||||
//! Operates on a Node using a raw string instead of \ref AZ::Name.
|
||||
//! \see StartNode
|
||||
virtual Result RawStartNode(AZStd::string_view name, Lifetime lifetime);
|
||||
//! Finishes operating on a Node.
|
||||
//! Callers must provide both the number of attributes the were provided and the number of elements that were
|
||||
//! provided to the node, attributes being values prefaced by a call to Key.
|
||||
virtual Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount);
|
||||
|
||||
protected:
|
||||
Visitor() = default;
|
||||
|
||||
//! Helper method, constructs a failure \ref Result with the specified code.
|
||||
static Result VisitorFailure(VisitorErrorCode code);
|
||||
//! Helper method, constructs a failure \ref Result with the specified code and supplemental info.
|
||||
static Result VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo);
|
||||
//! Helper method, constructs a failure \ref Result with the specified error.
|
||||
static Result VisitorFailure(VisitorError error);
|
||||
//! Helper method, constructs a success \ref Result.
|
||||
static Result VisitorSuccess();
|
||||
};
|
||||
} // namespace AZ::DOM
|
||||
@@ -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
|
||||
|
||||
@@ -634,12 +634,18 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
}
|
||||
|
||||
// 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)
|
||||
constexpr auto projectNameKey =
|
||||
FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
|
||||
+ "/project_name";
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectName;
|
||||
if (!registry.Get(projectName, projectNameKey))
|
||||
// Read the project name from the project.json file if it exists
|
||||
if (AZ::IO::FixedMaxPath projectJsonPath = normalizedProjectPath / "project.json";
|
||||
AZ::IO::SystemFile::Exists(projectJsonPath.c_str()))
|
||||
{
|
||||
registry.MergeSettingsFile(projectJsonPath.Native(),
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey);
|
||||
}
|
||||
if (FixedValueString projectName; !registry.Get(projectName, projectNameKey))
|
||||
{
|
||||
projectName = path.Filename().Native();
|
||||
registry.Set(projectNameKey, projectName);
|
||||
|
||||
@@ -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
|
||||
@@ -121,6 +123,8 @@ set(FILES
|
||||
Debug/TraceMessagesDrillerBus.h
|
||||
Debug/TraceReflection.cpp
|
||||
Debug/TraceReflection.h
|
||||
DOM/DomVisitor.cpp
|
||||
DOM/DomVisitor.h
|
||||
Driller/DefaultStringPool.h
|
||||
Driller/Driller.cpp
|
||||
Driller/Driller.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,25 @@ 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 +236,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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -258,10 +258,17 @@ namespace AzFramework
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void XcbNativeWindow::SetWindowTitle(const AZStd::string& title)
|
||||
{
|
||||
// Set the title of both the window and the task bar by using
|
||||
// a buffer to hold the title twice, separated by a null-terminator
|
||||
auto doubleTitleSize = (title.size() + 1) * 2;
|
||||
AZStd::string doubleTitle(doubleTitleSize, '\0');
|
||||
azstrncpy(doubleTitle.data(), doubleTitleSize, title.c_str(), title.size());
|
||||
azstrncpy(&doubleTitle.data()[title.size() + 1], title.size(), title.c_str(), title.size());
|
||||
|
||||
xcb_void_cookie_t xcbCheckResult;
|
||||
xcbCheckResult = xcb_change_property(
|
||||
m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, static_cast<uint32_t>(title.size()),
|
||||
title.c_str());
|
||||
m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, static_cast<uint32_t>(doubleTitle.size()),
|
||||
doubleTitle.c_str());
|
||||
AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set window title.");
|
||||
}
|
||||
|
||||
|
||||
@@ -308,7 +308,9 @@ namespace UnitTest
|
||||
registry->Set(projectPathKey, "AutomatedTesting");
|
||||
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
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace AzGameFramework
|
||||
|
||||
// Used the lowercase the platform name since the bootstrap.game.<config>.<platform>.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))
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace AzQtComponents
|
||||
, m_closeOnClick(true)
|
||||
, m_ui(new Ui::ToastNotification())
|
||||
, m_fadeAnimation(nullptr)
|
||||
, m_configuration(toastConfiguration)
|
||||
{
|
||||
setProperty("HasNoWindowDecorations", true);
|
||||
|
||||
@@ -80,7 +81,13 @@ namespace AzQtComponents
|
||||
}
|
||||
|
||||
ToastNotification::~ToastNotification()
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
bool ToastNotification::IsDuplicate(const ToastConfiguration& toastConfiguration)
|
||||
{
|
||||
return toastConfiguration.m_title == m_configuration.m_title
|
||||
&& toastConfiguration.m_description == m_configuration.m_description;
|
||||
}
|
||||
|
||||
void ToastNotification::paintEvent(QPaintEvent* event)
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace AzQtComponents
|
||||
void ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint);
|
||||
|
||||
void UpdatePosition(const QPoint& screenPosition, const QPointF& anchorPoint);
|
||||
|
||||
bool IsDuplicate(const ToastConfiguration& toastConfiguration);
|
||||
|
||||
// QDialog
|
||||
void showEvent(QShowEvent* showEvent) override;
|
||||
@@ -64,7 +66,7 @@ namespace AzQtComponents
|
||||
|
||||
private:
|
||||
QPropertyAnimation* m_fadeAnimation;
|
||||
|
||||
ToastConfiguration m_configuration;
|
||||
bool m_closeOnClick;
|
||||
QTimer m_lifeSpan;
|
||||
uint32_t m_borderRadius = 0;
|
||||
|
||||
@@ -826,6 +826,10 @@ namespace AzToolsFramework
|
||||
/// Path will be empty if component should have no icon.
|
||||
virtual AZStd::string GetComponentEditorIcon(const AZ::Uuid& /*componentType*/, AZ::Component* /*component*/) { return AZStd::string(); }
|
||||
|
||||
//! Return path to icon for component type.
|
||||
//! Path will be empty if component type should have no icon.
|
||||
virtual AZStd::string GetComponentTypeEditorIcon(const AZ::Uuid& /*componentType*/) { return AZStd::string(); }
|
||||
|
||||
/**
|
||||
* Return the icon image path based on the component type and where it is used.
|
||||
* \param componentType component type
|
||||
|
||||
+2
@@ -43,6 +43,8 @@ namespace AzToolsFramework
|
||||
};
|
||||
|
||||
//! Provides a bus to notify when the different editor modes are entered/exit.
|
||||
//! @note The editor modes are not discrete states but rather each progression of mode retain the active the parent
|
||||
//! mode that the new mode progressed from.
|
||||
class ViewportEditorModeNotifications : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
|
||||
+27
-2
@@ -9,9 +9,27 @@
|
||||
#include <AzToolsFramework/Application/EditorEntityManager.h>
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
static bool AreEntitiesValidForDuplication(const EntityIdList& entityIds)
|
||||
{
|
||||
for (AZ::EntityId entityId : entityIds)
|
||||
{
|
||||
if (GetEntityById(entityId) == nullptr)
|
||||
{
|
||||
AZ_Error(
|
||||
"Entity", false,
|
||||
"Entity with id '%llu' is not found. This can happen when you try to duplicate the entity before it is created. Please "
|
||||
"ensure entities are created before trying to duplicate them.",
|
||||
static_cast<AZ::u64>(entityId));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorEntityManager::Start()
|
||||
{
|
||||
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
|
||||
@@ -62,7 +80,11 @@ namespace AzToolsFramework
|
||||
EntityIdList selectedEntities;
|
||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities);
|
||||
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
|
||||
if (AreEntitiesValidForDuplication(selectedEntities))
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EditorEntityManager::DuplicateEntityById(AZ::EntityId entityId)
|
||||
@@ -72,7 +94,10 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorEntityManager::DuplicateEntities(const EntityIdList& entities)
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
|
||||
if (AreEntitiesValidForDuplication(entities))
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,5 +34,4 @@ namespace AzToolsFramework
|
||||
private:
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace AzToolsFramework
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(ToolsApplicationNotificationBusHandler, "{7EB67956-FF86-461A-91E2-7B08279CFACF}", AZ::SystemAllocator,
|
||||
EntityRegistered, EntityDeregistered);
|
||||
EntityRegistered, EntityDeregistered, AfterEntitySelectionChanged);
|
||||
|
||||
void EntityRegistered(AZ::EntityId entityId) override
|
||||
{
|
||||
@@ -187,6 +187,11 @@ namespace AzToolsFramework
|
||||
{
|
||||
Call(FN_EntityDeregistered, entityId);
|
||||
}
|
||||
|
||||
void AfterEntitySelectionChanged(const EntityIdList& newlySelectedEntities, const EntityIdList& newlyDeselectedEntities) override
|
||||
{
|
||||
Call(FN_AfterEntitySelectionChanged, newlySelectedEntities, newlyDeselectedEntities);
|
||||
}
|
||||
};
|
||||
|
||||
struct ViewPaneCallbackBusHandler final
|
||||
@@ -410,6 +415,7 @@ namespace AzToolsFramework
|
||||
->Handler<Internal::ToolsApplicationNotificationBusHandler>()
|
||||
->Event("EntityRegistered", &ToolsApplicationEvents::EntityRegistered)
|
||||
->Event("EntityDeregistered", &ToolsApplicationEvents::EntityDeregistered)
|
||||
->Event("AfterEntitySelectionChanged", &ToolsApplicationEvents::AfterEntitySelectionChanged)
|
||||
;
|
||||
|
||||
behaviorContext->Class<ViewPaneOptions>()
|
||||
@@ -428,6 +434,7 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Script::Attributes::Module, "editor")
|
||||
->Event("RegisterCustomViewPane", &EditorRequests::RegisterCustomViewPane)
|
||||
->Event("UnregisterViewPane", &EditorRequests::UnregisterViewPane)
|
||||
->Event("GetComponentTypeEditorIcon", &EditorRequests::GetComponentTypeEditorIcon)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<EditorEventsBus>("EditorEventBus")
|
||||
|
||||
@@ -1110,7 +1110,8 @@ namespace AzToolsFramework
|
||||
// Select the duplicated entities/instances
|
||||
auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
|
||||
ToolsApplicationRequestBus::Broadcast(
|
||||
&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
|
||||
}
|
||||
|
||||
return AZ::Success(AZStd::move(duplicatedEntityAndInstanceIds));
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
AZStd::string componentIconPath;
|
||||
EBUS_EVENT_RESULT(componentIconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, componentClass->m_typeId, nullptr);
|
||||
AzToolsFramework::EditorRequestBus::BroadcastResult(componentIconPath, &AzToolsFramework::EditorRequests::GetComponentTypeEditorIcon, componentClass->m_typeId);
|
||||
componentIconTable[componentClass] = QString::fromUtf8(componentIconPath.c_str());
|
||||
}
|
||||
|
||||
|
||||
+34
@@ -63,6 +63,12 @@ namespace AzToolsFramework
|
||||
|
||||
ToastId ToastNotificationsView::ShowToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||
{
|
||||
// reject duplicate messages
|
||||
if (m_rejectDuplicates && DuplicateNotificationInQueue(toastConfiguration))
|
||||
{
|
||||
return ToastId();
|
||||
}
|
||||
|
||||
ToastId toastId = CreateToastNotification(toastConfiguration);
|
||||
m_queuedNotifications.emplace_back(toastId);
|
||||
|
||||
@@ -70,10 +76,28 @@ namespace AzToolsFramework
|
||||
{
|
||||
DisplayQueuedNotification();
|
||||
}
|
||||
else if (m_queuedNotifications.size() >= m_maxQueuedNotifications)
|
||||
{
|
||||
// hiding the active toast will cause the next toast to be displayed
|
||||
HideToastNotification(m_activeNotification);
|
||||
}
|
||||
|
||||
return toastId;
|
||||
}
|
||||
|
||||
bool ToastNotificationsView::DuplicateNotificationInQueue(const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||
{
|
||||
for (auto iter : m_notifications)
|
||||
{
|
||||
if (iter.second && iter.second->IsDuplicate(toastConfiguration))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ToastId ToastNotificationsView::ShowToastAtCursor(const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||
{
|
||||
ToastId toastId = CreateToastNotification(toastConfiguration);
|
||||
@@ -187,4 +211,14 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_anchorPoint = anchorPoint;
|
||||
}
|
||||
|
||||
void ToastNotificationsView::SetMaxQueuedNotifications(AZ::u32 maxQueuedNotifications)
|
||||
{
|
||||
m_maxQueuedNotifications = maxQueuedNotifications;
|
||||
}
|
||||
|
||||
void ToastNotificationsView::SetRejectDuplicates(bool rejectDuplicates)
|
||||
{
|
||||
m_rejectDuplicates = rejectDuplicates;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -52,10 +52,13 @@ namespace AzToolsFramework
|
||||
|
||||
void SetOffset(const QPoint& offset);
|
||||
void SetAnchorPoint(const QPointF& anchorPoint);
|
||||
void SetMaxQueuedNotifications(AZ::u32 maxQueuedNotifications);
|
||||
void SetRejectDuplicates(bool rejectDuplicates);
|
||||
|
||||
private:
|
||||
ToastId CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration);
|
||||
void DisplayQueuedNotification();
|
||||
bool DuplicateNotificationInQueue(const AzQtComponents::ToastConfiguration& toastConfiguration);
|
||||
QPoint GetGlobalPoint();
|
||||
|
||||
ToastId m_activeNotification;
|
||||
@@ -64,5 +67,7 @@ namespace AzToolsFramework
|
||||
|
||||
QPoint m_offset = QPoint(10, 10);
|
||||
QPointF m_anchorPoint = QPointF(1, 0);
|
||||
AZ::u32 m_maxQueuedNotifications = 5;
|
||||
bool m_rejectDuplicates = true;
|
||||
};
|
||||
} // AzToolsFramework
|
||||
|
||||
+33
-17
@@ -943,13 +943,15 @@ namespace AzToolsFramework
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const int count = rowCount(parent);
|
||||
AZ::EntityId newParentId = GetEntityFromIndex(parent);
|
||||
AZ::EntityId beforeEntityId = GetEntityFromIndex(index(row, 0, parent));
|
||||
AZ::EntityId beforeEntityId = (row >= 0 && row < count) ? GetEntityFromIndex(index(row, 0, parent)) : AZ::EntityId();
|
||||
EntityIdList topLevelEntityIds;
|
||||
topLevelEntityIds.reserve(entityIdListContainer.m_entityIds.size());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::FindTopLevelEntityIdsInactive, entityIdListContainer.m_entityIds, topLevelEntityIds);
|
||||
if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId))
|
||||
const auto appendActionForInvalid = newParentId.IsValid() && (row >= count) ? AppendEnd : AppendBeginning;
|
||||
if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId, appendActionForInvalid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1046,7 +1048,7 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId)
|
||||
bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId, ReparentForInvalid forInvalid)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
if (!CanReparentEntities(newParentId, selectedEntityIds))
|
||||
@@ -1056,10 +1058,18 @@ namespace AzToolsFramework
|
||||
|
||||
m_isFilterDirty = true;
|
||||
|
||||
ScopedUndoBatch undo("Reparent Entities");
|
||||
//capture child entity order before re-parent operation, which will automatically add order info if not present
|
||||
EntityOrderArray entityOrderArray = GetEntityChildOrder(newParentId);
|
||||
|
||||
//search for the insertion entity in the order array
|
||||
const auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId);
|
||||
const bool hasInvalidIndex = beforeEntityItr == entityOrderArray.end();
|
||||
if (hasInvalidIndex && forInvalid == None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedUndoBatch undo("Reparent Entities");
|
||||
// The new parent is dirty due to sort change(s)
|
||||
undo.MarkEntityDirty(GetEntityIdForSortInfo(newParentId));
|
||||
|
||||
@@ -1088,9 +1098,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
//search for the insertion entity in the order array
|
||||
auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId);
|
||||
|
||||
|
||||
//replace order info matching selection with bad values rather than remove to preserve layout
|
||||
for (auto& id : entityOrderArray)
|
||||
{
|
||||
@@ -1100,17 +1108,25 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
if (newParentId.IsValid())
|
||||
//if adding to a valid parent entity, insert at the found entity location or at the head/tail depending on placeAtTail flag
|
||||
if (hasInvalidIndex)
|
||||
{
|
||||
//if adding to a valid parent entity, insert at the found entity location or at the head of the container
|
||||
auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.begin();
|
||||
entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end());
|
||||
}
|
||||
else
|
||||
switch(forInvalid)
|
||||
{
|
||||
case AppendEnd:
|
||||
entityOrderArray.insert(entityOrderArray.end(), processedEntityIds.begin(), processedEntityIds.end());
|
||||
break;
|
||||
case AppendBeginning:
|
||||
entityOrderArray.insert(entityOrderArray.begin(), processedEntityIds.begin(), processedEntityIds.end());
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Unexpected type for ReparentForInvalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if adding to an invalid parent entity (the root), insert at the found entity location or at the tail of the container
|
||||
auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.end();
|
||||
entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end());
|
||||
entityOrderArray.insert(beforeEntityItr, processedEntityIds.begin(), processedEntityIds.end());
|
||||
}
|
||||
|
||||
//remove placeholder entity ids
|
||||
|
||||
+8
-1
@@ -72,6 +72,13 @@ namespace AzToolsFramework
|
||||
ColumnCount //!< Total number of columns
|
||||
};
|
||||
|
||||
enum ReparentForInvalid
|
||||
{
|
||||
None, //!< For an invalid location the entity does not change location
|
||||
AppendEnd, //!< Append Item to end of target parent list
|
||||
AppendBeginning, //!< Append Item to the beginning of target parent list
|
||||
};
|
||||
|
||||
// Note: the ColumnSortIndex column isn't shown, hence the -1 and the need for a separate counter.
|
||||
// A wrong column count number causes refresh issues and hover mismatch on model update.
|
||||
static const int VisibleColumnCount = ColumnCount - 1;
|
||||
@@ -162,7 +169,7 @@ namespace AzToolsFramework
|
||||
|
||||
// Buffer Processing Slots - These are called using single-shot events when the buffers begin to fill.
|
||||
bool CanReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds) const;
|
||||
bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId());
|
||||
bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId(), ReparentForInvalid forInvalid = None);
|
||||
|
||||
//! Use the current filter setting and re-evaluate the filter.
|
||||
void InvalidateFilter();
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ namespace AzToolsFramework
|
||||
|
||||
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
|
||||
{
|
||||
m_mousePosition = QPoint();
|
||||
m_mousePosition = QPoint(-1, -1);
|
||||
m_currentHoveredIndex = QModelIndex();
|
||||
update();
|
||||
}
|
||||
@@ -200,7 +200,7 @@ namespace AzToolsFramework
|
||||
const bool isEnabled = (this->model()->flags(index) & Qt::ItemIsEnabled);
|
||||
|
||||
const bool isSelected = selectionModel()->isSelected(index);
|
||||
const bool isHovered = (index == indexAt(m_mousePosition)) && isEnabled;
|
||||
const bool isHovered = (index == indexAt(m_mousePosition).siblingAtColumn(0)) && isEnabled;
|
||||
|
||||
// Paint the branch Selection/Hover Rect
|
||||
PaintBranchSelectionHoverRect(painter, rect, isSelected, isHovered);
|
||||
|
||||
+3
-6
@@ -153,6 +153,9 @@ namespace AzToolsFramework
|
||||
{
|
||||
initEntityOutlinerWidgetResources();
|
||||
|
||||
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
AZ_Assert(m_editorEntityUiInterface != nullptr, "EntityOutlinerWidget requires a EditorEntityUiInterface instance on Initialize.");
|
||||
|
||||
m_gui = new Ui::EntityOutlinerWidgetUI();
|
||||
m_gui->setupUi(this);
|
||||
|
||||
@@ -282,12 +285,6 @@ namespace AzToolsFramework
|
||||
|
||||
m_listModel->Initialize();
|
||||
|
||||
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
||||
|
||||
AZ_Assert(
|
||||
m_editorEntityUiInterface != nullptr,
|
||||
"EntityOutlinerWidget requires a EditorEntityUiInterface instance on Initialize.");
|
||||
|
||||
EditorPickModeNotificationBus::Handler::BusConnect(GetEntityContextId());
|
||||
EntityHighlightMessages::Bus::Handler::BusConnect();
|
||||
EntityOutlinerModelNotificationBus::Handler::BusConnect();
|
||||
|
||||
+1
-1
@@ -583,7 +583,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
AZStd::string iconPath;
|
||||
EBUS_EVENT_RESULT(iconPath, AzToolsFramework::EditorRequests::Bus, GetComponentEditorIcon, componentType, const_cast<AZ::Component*>(&componentInstance));
|
||||
AzToolsFramework::EditorRequestBus::BroadcastResult(iconPath, &AzToolsFramework::EditorRequests::GetComponentEditorIcon, componentType, const_cast<AZ::Component*>(&componentInstance));
|
||||
GetHeader()->SetIcon(QIcon(iconPath.c_str()));
|
||||
|
||||
bool isExpanded = true;
|
||||
|
||||
@@ -427,8 +427,8 @@ namespace AzToolsFramework::ViewportUi::Internal
|
||||
void ViewportUiDisplay::PositionUiOverlayOverRenderViewport()
|
||||
{
|
||||
QPoint offset = m_renderOverlay->mapToGlobal(QPoint());
|
||||
m_uiMainWindow.move(offset);
|
||||
m_uiOverlay.setFixedSize(m_renderOverlay->width(), m_renderOverlay->height());
|
||||
m_uiMainWindow.setGeometry(offset.x(), offset.y(), m_renderOverlay->width(), m_renderOverlay->height());
|
||||
m_uiOverlay.setGeometry(m_uiMainWindow.rect());
|
||||
UpdateUiOverlayGeometry();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h>
|
||||
@@ -187,10 +188,13 @@ namespace UnitTest
|
||||
ASSERT_NE(m_viewportEditorModeTracker, nullptr);
|
||||
m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({AzToolsFramework::GetEntityContextId()});
|
||||
ASSERT_NE(m_viewportEditorModes, nullptr);
|
||||
m_focusModeInterface = AZ::Interface<AzToolsFramework::FocusModeInterface>::Get();
|
||||
ASSERT_NE(m_focusModeInterface, nullptr);
|
||||
}
|
||||
|
||||
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr;
|
||||
const ViewportEditorModesInterface* m_viewportEditorModes = nullptr;
|
||||
AzToolsFramework::FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4)
|
||||
@@ -522,32 +526,48 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive)
|
||||
ViewportEditorModeTrackerIntegrationTestFixture,
|
||||
EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive)
|
||||
{
|
||||
// When component mode is entered
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode,
|
||||
AZStd::vector<AzToolsFramework::ComponentModeFramework::EntityAndComponentModeBuilders>{});
|
||||
|
||||
bool inComponentMode = false;
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult(
|
||||
inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode);
|
||||
|
||||
// Expect to be in component mode
|
||||
EXPECT_TRUE(inComponentMode);
|
||||
EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode());
|
||||
|
||||
// Expect the default and component viewport editor modes to be active
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default));
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component));
|
||||
|
||||
// Do not expect the pick and focus viewport editor modes to be active
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick));
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModeTrackerIntegrationTestFixture,
|
||||
EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive)
|
||||
ExitingComponentModeAfterEnteringFrominitialStateHasViewportEditorModesDefaultActive)
|
||||
{
|
||||
// When component mode is entered and exited
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode,
|
||||
AZStd::vector<AzToolsFramework::ComponentModeFramework::EntityAndComponentModeBuilders>{});
|
||||
|
||||
EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode());
|
||||
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode);
|
||||
|
||||
// Expect to not be in component mode
|
||||
EXPECT_FALSE(AzToolsFramework::ComponentModeFramework::InComponentMode());
|
||||
|
||||
// Expect only the default viewport editor mode to be active
|
||||
ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModeTrackerIntegrationTestFixture,
|
||||
EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickActive)
|
||||
{
|
||||
// When entering pick mode
|
||||
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
|
||||
@@ -563,6 +583,96 @@ namespace UnitTest
|
||||
ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick);
|
||||
}
|
||||
|
||||
// FocusMode integration tests will follow (LYN-6995)
|
||||
TEST_F(
|
||||
ViewportEditorModeTrackerIntegrationTestFixture,
|
||||
EnteringEditorDefaultEntitySelectionFromEditorPickEntitySelectionHasOnlyViewportEditorModeDefaultActive)
|
||||
{
|
||||
// When pick mode is entered and exited
|
||||
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
|
||||
EditorInteractionSystemViewportSelectionRequestBus::Event(
|
||||
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
|
||||
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
|
||||
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
|
||||
{
|
||||
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
|
||||
});
|
||||
|
||||
EditorInteractionSystemViewportSelectionRequestBus::Event(
|
||||
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
|
||||
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
|
||||
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
|
||||
{
|
||||
return AZStd::make_unique<AzToolsFramework::EditorDefaultSelection>(entityDataCache, viewportEditorModeTracker);
|
||||
});
|
||||
|
||||
// Expect only the default viewport editor mode to be active
|
||||
ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default);
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, EnteringFocusModeAfterInitialStateHasViewportEditorModeDefaultAndPickActive)
|
||||
{
|
||||
// When entering focus mode
|
||||
m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 });
|
||||
|
||||
// Expect the default and focus viewport editor modes to be active
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default));
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus));
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick));
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModeTrackerIntegrationTestFixture,
|
||||
ExitingFocusModeAfterEnteringFromInitialStateHasOnlyViewportEditorModeDefaultActive)
|
||||
{
|
||||
// When entering and leaving focus mode
|
||||
m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 });
|
||||
m_focusModeInterface->SetFocusRoot(AZ::EntityId());
|
||||
|
||||
// Expect only the default mode to be active
|
||||
ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default);
|
||||
}
|
||||
|
||||
TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeFromFocusModeStateHasViewportEditorModeDefaultAndFocusAndComponentActive)
|
||||
{
|
||||
// When entering component mode from focus mode
|
||||
m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 });
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode,
|
||||
AZStd::vector<AzToolsFramework::ComponentModeFramework::EntityAndComponentModeBuilders>{});
|
||||
|
||||
// Expect to be in component mode
|
||||
EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode());
|
||||
|
||||
// Expect the default, focus and component viewport editor modes to be active
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default));
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus));
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component));
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ViewportEditorModeTrackerIntegrationTestFixture,
|
||||
ExitingComponentModeAfterEnteringFromFocusModeHasViewportEditorModeDefaultAndFocusActive)
|
||||
{
|
||||
// When entering and leaving component mode from focus mode
|
||||
m_focusModeInterface->SetFocusRoot(AZ::EntityId{ 1 });
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode,
|
||||
AZStd::vector<AzToolsFramework::ComponentModeFramework::EntityAndComponentModeBuilders>{});
|
||||
|
||||
EXPECT_TRUE(AzToolsFramework::ComponentModeFramework::InComponentMode());
|
||||
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::EndComponentMode);
|
||||
|
||||
// Expect to not be in component mode
|
||||
EXPECT_FALSE(AzToolsFramework::ComponentModeFramework::InComponentMode());
|
||||
|
||||
// Expect the default and focus viewport editor modes to be active
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default));
|
||||
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus));
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component));
|
||||
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -242,7 +242,7 @@ void IDebugCallStack::WriteLineToLog(const char* format, ...)
|
||||
va_end(ArgList);
|
||||
|
||||
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Open("@Log@\\error.log", AZ::IO::GetOpenModeFromStringMode("a+t"), fileHandle);
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Open("@log@\\error.log", AZ::IO::GetOpenModeFromStringMode("a+t"), fileHandle);
|
||||
if (fileHandle != AZ::IO::InvalidHandle)
|
||||
{
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Write(fileHandle, szBuffer, strlen(szBuffer));
|
||||
@@ -254,7 +254,7 @@ void IDebugCallStack::WriteLineToLog(const char* format, ...)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void IDebugCallStack::StartMemLog()
|
||||
{
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Open("@Log@\\memallocfile.log", AZ::IO::OpenMode::ModeWrite, m_memAllocFileHandle);
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->Open("@log@\\memallocfile.log", AZ::IO::OpenMode::ModeWrite, m_memAllocFileHandle);
|
||||
|
||||
assert(m_memAllocFileHandle != AZ::IO::InvalidHandle);
|
||||
}
|
||||
|
||||
@@ -61,8 +61,12 @@ namespace AssetBundler
|
||||
{
|
||||
AZStd::string absolutePath = filePath.toUtf8().data();
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str()))
|
||||
{
|
||||
AZStd::string projectName = pathToProjectNameMap.at(absolutePath);
|
||||
{
|
||||
AZStd::string projectName;
|
||||
if (pathToProjectNameMap.contains(absolutePath))
|
||||
{
|
||||
projectName = pathToProjectNameMap.at(absolutePath);
|
||||
}
|
||||
|
||||
// If a project name is already specified, then the associated file is a default file
|
||||
LoadFile(absolutePath, projectName, !projectName.empty());
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/AZStdContainers.inl>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/containers/bitset.h>
|
||||
#include <AzFramework/Asset/AssetProcessorMessages.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
|
||||
@@ -3576,23 +3576,24 @@ namespace AssetProcessor
|
||||
// Absolute path, just check the 1 scan folder
|
||||
if (AZ::IO::PathView(encodedFileData.toUtf8().constData()).IsAbsolute())
|
||||
{
|
||||
QString scanFolderName;
|
||||
if (!m_platformConfig->ConvertToRelativePath(encodedFileData, resultDatabaseSourceName, scanFolderName))
|
||||
auto scanFolderInfo = m_platformConfig->GetScanFolderForFile(encodedFileData);
|
||||
|
||||
if (!m_platformConfig->ConvertToRelativePath(encodedFileData, scanFolderInfo, resultDatabaseSourceName))
|
||||
{
|
||||
AZ_Warning(
|
||||
AssetProcessor::ConsoleChannel, false,
|
||||
"'%s' does not appear to be in any input folder. Use relative paths instead.",
|
||||
sourceDependency.m_sourceFileDependencyPath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make an absolute path that is ScanFolderPath + Part of search path before the wildcard
|
||||
QDir rooted(scanFolderInfo->ScanPath());
|
||||
QString scanFolderAndKnownSubPath = rooted.absoluteFilePath(knownPathBeforeWildcard);
|
||||
|
||||
auto scanFolderInfo = m_platformConfig->GetScanFolderByPath(scanFolderName);
|
||||
|
||||
// Make an absolute path that is ScanFolderPath + Part of search path before the wildcard
|
||||
QDir rooted(scanFolderName);
|
||||
QString scanFolderAndKnownSubPath = rooted.absoluteFilePath(knownPathBeforeWildcard);
|
||||
|
||||
resolvedDependencyList.append(m_platformConfig->FindWildcardMatches(
|
||||
scanFolderAndKnownSubPath, relativeSearch, false, scanFolderInfo->RecurseSubFolders()));
|
||||
resolvedDependencyList.append(m_platformConfig->FindWildcardMatches(
|
||||
scanFolderAndKnownSubPath, relativeSearch, false, scanFolderInfo->RecurseSubFolders()));
|
||||
}
|
||||
}
|
||||
else // Relative path, check every scan folder
|
||||
{
|
||||
|
||||
@@ -259,6 +259,11 @@ namespace AssetProcessor
|
||||
scratchBuffer.reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
|
||||
AZStd::fixed_vector<AZStd::string_view, AzFramework::MaxPlatformCodeNames> platformCodes;
|
||||
AzFramework::PlatformHelper::AppendPlatformCodeNames(platformCodes, request.m_platformInfo.m_identifier);
|
||||
AZ_Assert(platformCodes.size() <= 1, "A one-to-one mapping of asset type platform identifier"
|
||||
" to platform codename is required in the SettingsRegistryBuilder."
|
||||
" The bootstrap.game is now only produced per build configuration and doesn't take into account"
|
||||
" different platforms names");
|
||||
|
||||
const AZStd::string& assetPlatformIdentifier = request.m_jobDescription.GetPlatformIdentifier();
|
||||
// Determines the suffix that will be used for the launcher based on processing server vs non-server assets
|
||||
const char* launcherType = assetPlatformIdentifier != AzFramework::PlatformHelper::GetPlatformName(AzFramework::PlatformId::SERVER)
|
||||
@@ -293,9 +298,10 @@ namespace AssetProcessor
|
||||
outputBuffer.Reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
|
||||
SettingsExporter exporter(outputBuffer, excludes);
|
||||
|
||||
for (AZStd::string_view platform : platformCodes)
|
||||
if (!platformCodes.empty())
|
||||
{
|
||||
AZ::u32 productSubID = static_cast<AZ::u32>(AZStd::hash<AZStd::string_view>{}(platform)); // Deliberately ignoring half the bits.
|
||||
AZStd::string_view platform = platformCodes.front();
|
||||
constexpr AZ::u32 productSubID = 0;
|
||||
for (size_t i = 0; i < AZStd::size(specializations); ++i)
|
||||
{
|
||||
const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i];
|
||||
@@ -337,7 +343,7 @@ namespace AssetProcessor
|
||||
// The purpose of this section is to copy the Gem's SourcePaths from the Global Settings Registry
|
||||
// the local SettingsRegistry. The reason this is needed is so that the call to
|
||||
// `MergeSettingsToRegistry_GemRegistries` below is able to locate each gem's "<gem-root>/Registry" folder
|
||||
// that will be merged into the bootstrap.game.<configuration>.<platform>.setreg file
|
||||
// that will be merged into the bootstrap.game.<configuration>.setreg file
|
||||
// This is used by the GameLauncher applications to read from a single merged .setreg file
|
||||
// containing the settings needed to run a game/simulation without have access to the source code base registry
|
||||
AZStd::vector<AzFramework::GemInfo> gemInfos;
|
||||
@@ -408,8 +414,6 @@ namespace AssetProcessor
|
||||
}
|
||||
|
||||
outputPath += specialization.GetSpecialization(0); // Append configuration
|
||||
outputPath += '.';
|
||||
outputPath += platform;
|
||||
outputPath += ".setreg";
|
||||
|
||||
AZ::IO::SystemFile file;
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace AssetProcessor
|
||||
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
config.AddExcludeRecognizer(excludeRecogniser);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
friend struct DuplicateProductsTest;
|
||||
friend struct DuplicateProcessTest;
|
||||
friend struct AbsolutePathProductDependencyTest;
|
||||
friend struct WildcardSourceDependencyTest;
|
||||
|
||||
explicit AssetProcessorManager_Test(PlatformConfiguration* config, QObject* parent = nullptr);
|
||||
~AssetProcessorManager_Test() override;
|
||||
@@ -4446,7 +4447,9 @@ AssetBuilderSDK::AssetBuilderDesc MockBuilderInfoHandler::CreateBuilderDesc(cons
|
||||
|
||||
void FingerprintTest::SetUp()
|
||||
{
|
||||
AZ_Printf("FingerprintTest", "SetUp start");
|
||||
AssetProcessorManagerTest::SetUp();
|
||||
AZ_Printf("FingerprintTest", "SetUp self");
|
||||
|
||||
// We don't want the mock application manager to provide builder descriptors, mockBuilderInfoHandler will provide our own
|
||||
m_mockApplicationManager->BusDisconnect();
|
||||
@@ -4465,18 +4468,23 @@ void FingerprintTest::SetUp()
|
||||
});
|
||||
|
||||
ASSERT_TRUE(UnitTestUtils::CreateDummyFile(m_absolutePath, ""));
|
||||
AZ_Printf("FingerprintTest", "SetUp end");
|
||||
}
|
||||
|
||||
void FingerprintTest::TearDown()
|
||||
{
|
||||
AZ_Printf("FingerprintTest", "TearDown start");
|
||||
m_jobResults = AZStd::vector<AssetProcessor::JobDetails>{};
|
||||
m_mockBuilderInfoHandler = {};
|
||||
|
||||
AZ_Printf("FingerprintTest", "TearDown parent");
|
||||
AssetProcessorManagerTest::TearDown();
|
||||
AZ_Printf("FingerprintTest", "TearDown end");
|
||||
}
|
||||
|
||||
void FingerprintTest::RunFingerprintTest(QString builderFingerprint, QString jobFingerprint, bool expectedResult)
|
||||
{
|
||||
AZ_Printf("FingerprintTest", "Fingerprint Test Start");
|
||||
m_mockBuilderInfoHandler.m_builderDesc.m_analysisFingerprint = builderFingerprint.toUtf8().data();
|
||||
m_mockBuilderInfoHandler.m_jobFingerprint = jobFingerprint;
|
||||
QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, m_absolutePath));
|
||||
@@ -4485,6 +4493,7 @@ void FingerprintTest::RunFingerprintTest(QString builderFingerprint, QString job
|
||||
ASSERT_EQ(m_mockBuilderInfoHandler.m_createJobsCount, 1);
|
||||
ASSERT_EQ(m_jobResults.size(), 1);
|
||||
ASSERT_EQ(m_jobResults[0].m_autoFail, expectedResult);
|
||||
AZ_Printf("FingerprintTest", "Fingerprint Test End");
|
||||
}
|
||||
|
||||
TEST_F(FingerprintTest, FingerprintChecking_JobFingerprint_NoBuilderFingerprint)
|
||||
@@ -5308,3 +5317,141 @@ TEST_F(MetadataFileTest, MetadataFile_SourceFileExtensionDifferentCase)
|
||||
ASSERT_TRUE(BlockUntilIdle(5000));
|
||||
ASSERT_EQ(jobDetails.m_jobEntry.m_pathRelativeToWatchFolder, relFileName);
|
||||
}
|
||||
|
||||
bool WildcardSourceDependencyTest::Test(
|
||||
const AZStd::string& dependencyPath, AZStd::vector<AZStd::string>& resolvedPaths)
|
||||
{
|
||||
[[maybe_unused]] QString resolvedName;
|
||||
QStringList stringlistPaths;
|
||||
AssetBuilderSDK::SourceFileDependency dependency(dependencyPath, AZ::Uuid::CreateNull(), AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards);
|
||||
bool result = m_assetProcessorManager->ResolveSourceFileDependencyPath(dependency, resolvedName, stringlistPaths);
|
||||
|
||||
// Convert to a vector of AZStd::strings because GTest handles this type better when displaying errors
|
||||
for (const QString& resolvedPath : stringlistPaths)
|
||||
{
|
||||
resolvedPaths.emplace_back(resolvedPath.toUtf8().constData());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void WildcardSourceDependencyTest::SetUp()
|
||||
{
|
||||
AssetProcessorManagerTest::SetUp();
|
||||
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
// Add a non-recursive scan folder. Only files directly inside of this folder should be picked up, subfolders are ignored
|
||||
m_config->AddScanFolder(ScanFolderInfo(tempPath.filePath("no_recurse"), "no_recurse",
|
||||
"no_recurse", false, false, m_config->GetEnabledPlatforms(), 1));
|
||||
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder1/1a.foo"));
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder1/1b.foo"));
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/a.foo"));
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/b.foo"));
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/folder/one/c.foo"));
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/folder/one/d.foo"));
|
||||
|
||||
// Add a file that is not in a scanfolder. Should always be ignored
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("not/a/scanfolder/e.foo"));
|
||||
|
||||
// Add a file in the non-recursive scanfolder. Since its not directly in the scan folder, it should always be ignored
|
||||
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("no_recurse/one/two/three/f.foo"));
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Relative_Broad)
|
||||
{
|
||||
// Expect all files except for the 2 invalid ones (e and f)
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
|
||||
ASSERT_TRUE(Test("*.foo", resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "b.foo", "folder/one/c.foo", "folder/one/d.foo", "1a.foo", "1b.foo"));
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Relative_WithFolder)
|
||||
{
|
||||
// Make sure we can filter to files under a folder
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
|
||||
ASSERT_TRUE(Test("folder/*.foo", resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("folder/one/c.foo", "folder/one/d.foo"));
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Relative_WildcardPath)
|
||||
{
|
||||
// Make sure the * wildcard works even if the full filename is given
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
|
||||
ASSERT_TRUE(Test("*a.foo", resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "1a.foo"));
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Absolute_WithFolder)
|
||||
{
|
||||
// Make sure we can use absolute paths to filter to files under a folder
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_TRUE(Test(tempPath.absoluteFilePath("subfolder2/redirected/*.foo").toUtf8().constData(), resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "b.foo", "folder/one/c.foo", "folder/one/d.foo"));
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Absolute_NotInScanfolder)
|
||||
{
|
||||
// Files outside a scanfolder should not be returned even with an absolute path
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_TRUE(Test(tempPath.absoluteFilePath("not/a/scanfolder/*.foo").toUtf8().constData(), resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Relative_NotInScanfolder)
|
||||
{
|
||||
// Files outside a scanfolder should not be returned
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_TRUE(Test("*/e.foo", resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Relative_InNonRecursiveScanfolder)
|
||||
{
|
||||
// Files deep inside non-recursive scanfolders should not be returned
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_TRUE(Test("*/f.foo", resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Absolute_InNonRecursiveScanfolder)
|
||||
{
|
||||
// Absolute paths to files deep inside non-recursive scanfolders should not be returned
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_TRUE(Test(tempPath.absoluteFilePath("one/two/three/*.foo").toUtf8().constData(), resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Relative_NoWildcard)
|
||||
{
|
||||
// No wildcard results in a failure
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_FALSE(Test("subfolder1/1a.foo", resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(WildcardSourceDependencyTest, Absolute_NoWildcard)
|
||||
{
|
||||
// No wildcard results in a failure
|
||||
AZStd::vector<AZStd::string> resolvedPaths;
|
||||
QDir tempPath(m_tempDir.path());
|
||||
|
||||
ASSERT_FALSE(Test(tempPath.absoluteFilePath("subfolder1/1a.foo").toUtf8().constData(), resolvedPaths));
|
||||
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
|
||||
}
|
||||
|
||||
@@ -131,6 +131,14 @@ struct MultiplatformPathDependencyTest
|
||||
void SetUp() override;
|
||||
};
|
||||
|
||||
struct WildcardSourceDependencyTest
|
||||
: AssetProcessorManagerTest
|
||||
{
|
||||
bool Test(const AZStd::string& dependencyPath, AZStd::vector<AZStd::string>& resolvedPaths);
|
||||
|
||||
void SetUp() override;
|
||||
};
|
||||
|
||||
struct MockBuilderInfoHandler
|
||||
: public AssetProcessor::AssetBuilderInfoBus::Handler
|
||||
{
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace AssetProcessor
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
// we are excluding all the files in the folder but not the folder itself
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser);
|
||||
m_assetScanner.get()->StartScan();
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace AssetProcessor
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
// we are excluding the complete folder here
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser);
|
||||
m_assetScanner.get()->StartScan();
|
||||
|
||||
|
||||
+2
@@ -405,6 +405,8 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes)
|
||||
auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular");
|
||||
ASSERT_TRUE(configRoot);
|
||||
UnitTestPlatformConfiguration config;
|
||||
|
||||
config.AddScanFolder(ScanFolderInfo("blahblah", "Blah ScanFolder", "sf2", true, true), true);
|
||||
m_absorber.Clear();
|
||||
ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false));
|
||||
ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0);
|
||||
|
||||
@@ -347,7 +347,7 @@ namespace AssetProcessor
|
||||
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
config.AddExcludeRecognizer(excludeRecogniser);
|
||||
|
||||
AssetProcessorManager_Test apm(&config); // note, this will 'push' the scan folders in to the db.
|
||||
@@ -1791,13 +1791,8 @@ namespace AssetProcessor
|
||||
UNIT_TEST_EXPECT_TRUE((newfingerprintForPCAfterVersionChange != fingerprintForPC) || (newfingerprintForPCAfterVersionChange != newfingerprintForPC));//Fingerprints should be different
|
||||
UNIT_TEST_EXPECT_TRUE((newfingerprintForANDROIDAfterVersionChange != fingerprintForANDROID) || (newfingerprintForANDROIDAfterVersionChange != newfingerprintForANDROID));//Fingerprints should be different
|
||||
|
||||
//------Test for Files which are excluded
|
||||
processResults.clear();
|
||||
absolutePath = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath("subfolder3/savebackup/test.txt"));
|
||||
QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absolutePath));
|
||||
UNIT_TEST_EXPECT_FALSE(BlockUntil(idling, 3000)); //Processing a file that will be excluded should not cause assetprocessor manager to emit the onBecameIdle signal because its state should not change
|
||||
UNIT_TEST_EXPECT_TRUE(processResults.size() == 0);
|
||||
|
||||
|
||||
// ------------- Test querying asset status -------------------
|
||||
{
|
||||
absolutePath = tempPath.absoluteFilePath("subfolder2/folder/ship.tiff");
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <AzCore/UnitTest/UnitTest.h>
|
||||
|
||||
//! These macros can be used for checking your unit tests,
|
||||
//! you can check AssetScannerUnitTest.cpp for usage
|
||||
@@ -155,6 +156,7 @@ namespace UnitTestUtils
|
||||
|
||||
bool OnPreWarning([[maybe_unused]] const char* window, [[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* message) override
|
||||
{
|
||||
UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message);
|
||||
++m_numWarningsAbsorbed;
|
||||
if (m_debugMessages)
|
||||
{
|
||||
@@ -165,6 +167,7 @@ namespace UnitTestUtils
|
||||
|
||||
bool OnPreAssert([[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* message) override
|
||||
{
|
||||
UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message);
|
||||
++m_numAssertsAbsorbed;
|
||||
if (m_debugMessages)
|
||||
{
|
||||
@@ -175,6 +178,7 @@ namespace UnitTestUtils
|
||||
|
||||
bool OnPreError([[maybe_unused]] const char* window, [[maybe_unused]] const char* fileName, [[maybe_unused]] int line, [[maybe_unused]] const char* func, [[maybe_unused]] const char* message) override
|
||||
{
|
||||
UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message);
|
||||
++m_numErrorsAbsorbed;
|
||||
if (m_debugMessages)
|
||||
{
|
||||
@@ -183,8 +187,9 @@ namespace UnitTestUtils
|
||||
return true; // I handled this, do not forward it
|
||||
}
|
||||
|
||||
bool OnPrintf(const char* /*window*/, const char* /*message*/) override
|
||||
bool OnPrintf(const char* /*window*/, const char* message) override
|
||||
{
|
||||
UnitTest::ColoredPrintf(UnitTest::COLOR_YELLOW, message);
|
||||
++m_numMessagesAbsorbed;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1633,13 +1633,18 @@ namespace AssetProcessor
|
||||
|
||||
bool AssetProcessor::PlatformConfiguration::IsFileExcluded(QString fileName) const
|
||||
{
|
||||
for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
|
||||
QString relPath, scanFolderName;
|
||||
if (ConvertToRelativePath(fileName, relPath, scanFolderName))
|
||||
{
|
||||
if (excludeRecognizer.m_patternMatcher.MatchesPath(fileName.toUtf8().constData()))
|
||||
for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
|
||||
{
|
||||
return true;
|
||||
if (excludeRecognizer.m_patternMatcher.MatchesPath(relPath.toUtf8().constData()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -50,10 +50,10 @@
|
||||
"order": 6000
|
||||
},
|
||||
"Exclude HoldFiles": {
|
||||
"pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*"
|
||||
"pattern": "(^|.+/)Levels/.*_hold(/.*)?$"
|
||||
},
|
||||
"Exclude TempFiles": {
|
||||
"pattern": ".*\\\\/\\\\$tmp[0-9]*_.*"
|
||||
"pattern": "(^|.+/)\\\\$tmp[0-9]*_.*"
|
||||
},
|
||||
"RC i_caf": {
|
||||
"glob": "*.i_caf",
|
||||
|
||||
+2
-2
@@ -74,10 +74,10 @@
|
||||
"include": "test"
|
||||
},
|
||||
"Exclude HoldFiles": {
|
||||
"pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*"
|
||||
"pattern": "(^|.+/)Levels/.*_hold(/.*)?$"
|
||||
},
|
||||
"Exclude TempFiles": {
|
||||
"pattern": ".*\\\\/\\\\$tmp[0-9]*_.*"
|
||||
"pattern": "(^|.+/)\\\\$tmp[0-9]*_.*"
|
||||
},
|
||||
"RC i_caf": {
|
||||
"glob": "*.i_caf",
|
||||
|
||||
@@ -34,6 +34,7 @@ ly_add_target(
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
Platform/${PAL_PLATFORM_NAME}
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::Qt::Core
|
||||
|
||||
@@ -11,4 +11,6 @@ set(FILES
|
||||
ProjectBuilderWorker_linux.cpp
|
||||
ProjectUtils_linux.cpp
|
||||
ProjectManagerDefs_linux.cpp
|
||||
ProjectManager_Traits_Platform.h
|
||||
ProjectManager_Traits_Linux.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 <ProjectManager_Traits_Linux.h>
|
||||
@@ -11,4 +11,6 @@ set(FILES
|
||||
ProjectBuilderWorker_mac.cpp
|
||||
ProjectUtils_mac.cpp
|
||||
ProjectManagerDefs_mac.cpp
|
||||
ProjectManager_Traits_Platform.h
|
||||
ProjectManager_Traits_Mac.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 <ProjectManager_Traits_Mac.h>
|
||||
@@ -11,4 +11,6 @@ set(FILES
|
||||
ProjectBuilderWorker_windows.cpp
|
||||
ProjectUtils_windows.cpp
|
||||
ProjectManagerDefs_windows.cpp
|
||||
ProjectManager_Traits_Platform.h
|
||||
ProjectManager_Traits_Windows.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 <ProjectManager_Traits_Windows.h>
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true
|
||||
@@ -9,7 +9,7 @@ QMainWindow {
|
||||
|
||||
#ScreensCtrl {
|
||||
min-width:1200px;
|
||||
min-height:800px;
|
||||
min-height:700px;
|
||||
}
|
||||
|
||||
QPushButton:focus {
|
||||
@@ -691,6 +691,12 @@ QProgressBar::chunk {
|
||||
|
||||
#gemRepoAddDialogInstructionTitleLabel {
|
||||
font-size:14px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#gemRepoAddDialogWarningLabel {
|
||||
font-size:12px;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
#addGemRepoDialog #formFrame {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <AzQtComponents/Utilities/HandleDpiAwareness.h>
|
||||
#include <AzQtComponents/Components/StyleManager.h>
|
||||
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
#include <ProjectManager_Traits_Platform.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
@@ -194,8 +195,12 @@ namespace O3DE::ProjectManager
|
||||
// set stylesheet after creating the main window or their styles won't get updated
|
||||
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:ProjectManager.qss"));
|
||||
|
||||
// the decoration wrapper is intended to remember window positioning and sizing
|
||||
// the decoration wrapper is intended to remember window positioning and sizing
|
||||
#if AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR
|
||||
auto wrapper = new AzQtComponents::WindowDecorationWrapper();
|
||||
#else
|
||||
auto wrapper = new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionDisabled);
|
||||
#endif
|
||||
wrapper->setGuest(m_mainWindow.data());
|
||||
|
||||
// show the main window here to apply the stylesheet before restoring geometry or we
|
||||
|
||||
@@ -42,7 +42,9 @@ namespace O3DE::ProjectManager
|
||||
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel, m_downloadController);
|
||||
vLayout->addWidget(m_headerWidget);
|
||||
|
||||
connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged);
|
||||
connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo);
|
||||
connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setMargin(0);
|
||||
@@ -73,6 +75,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_notificationsView = AZStd::make_unique<AzToolsFramework::ToastNotificationsView>(this, AZ_CRC("GemCatalogNotificationsView"));
|
||||
m_notificationsView->SetOffset(QPoint(10, 70));
|
||||
m_notificationsView->SetMaxQueuedNotifications(1);
|
||||
}
|
||||
|
||||
void GemCatalogScreen::ReinitForProject(const QString& projectPath)
|
||||
@@ -94,48 +97,6 @@ namespace O3DE::ProjectManager
|
||||
m_headerWidget->ReinitForProject();
|
||||
|
||||
connect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter);
|
||||
connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged);
|
||||
connect(
|
||||
m_headerWidget, &GemCatalogHeaderWidget::AddGem,
|
||||
[&]()
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
QString defaultPath;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
defaultPath = engineInfo.m_defaultGemsFolder;
|
||||
}
|
||||
|
||||
if (defaultPath.isEmpty())
|
||||
{
|
||||
defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
// register the gem to the o3de_manifest.json and to the project after the user confirms
|
||||
// project creation/update
|
||||
auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory);
|
||||
if(!registerResult)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gemsToRegisterWithProject.insert(directory);
|
||||
AZ::Outcome<GemInfo, void> gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory);
|
||||
if (gemInfoResult)
|
||||
{
|
||||
m_gemModel->AddGem(gemInfoResult.GetValue<GemInfo>());
|
||||
m_gemModel->UpdateGemDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
@@ -144,6 +105,46 @@ namespace O3DE::ProjectManager
|
||||
});
|
||||
}
|
||||
|
||||
void GemCatalogScreen::OnAddGemClicked()
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
QString defaultPath;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
defaultPath = engineInfo.m_defaultGemsFolder;
|
||||
}
|
||||
|
||||
if (defaultPath.isEmpty())
|
||||
{
|
||||
defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
// register the gem to the o3de_manifest.json and to the project after the user confirms
|
||||
// project creation/update
|
||||
auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory);
|
||||
if(!registerResult)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gemsToRegisterWithProject.insert(directory);
|
||||
AZ::Outcome<GemInfo, void> gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory);
|
||||
if (gemInfoResult)
|
||||
{
|
||||
m_gemModel->AddGem(gemInfoResult.GetValue<GemInfo>());
|
||||
m_gemModel->UpdateGemDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies)
|
||||
{
|
||||
if (m_notificationsEnabled)
|
||||
@@ -166,6 +167,10 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
notification += " " + tr("and") + " ";
|
||||
}
|
||||
if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded)
|
||||
{
|
||||
m_downloadController->AddGemDownload(GemModel::GetName(modelIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (numChangedDependencies == 1 )
|
||||
@@ -174,7 +179,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else if (numChangedDependencies > 1)
|
||||
{
|
||||
notification += QString("%d Gem ").arg(numChangedDependencies) + tr("dependencies");
|
||||
notification += QString("%1 Gem ").arg(numChangedDependencies) + tr("dependencies");
|
||||
}
|
||||
notification += " " + (added ? tr("activated") : tr("deactivated"));
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
public slots:
|
||||
void OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies);
|
||||
void OnAddGemClicked();
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent* event) override;
|
||||
|
||||
@@ -225,21 +225,22 @@ namespace O3DE::ProjectManager
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int totalGems = m_gemModel->rowCount();
|
||||
const int selectedGemTotal = m_gemModel->TotalAddedGems();
|
||||
const int selectedGemTotal = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true).size();
|
||||
const int unselectedGemTotal = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true).size();
|
||||
const int enabledGemTotal = m_gemModel->TotalAddedGems(/*includeDependencies=*/true);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Unselected));
|
||||
elementCounts.push_back(totalGems - selectedGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Selected));
|
||||
elementCounts.push_back(selectedGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive));
|
||||
elementCounts.push_back(totalGems - enabledGemTotal);
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemSelectedString(GemSortFilterProxyModel::GemSelected::Unselected));
|
||||
elementCounts.push_back(unselectedGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Active));
|
||||
elementCounts.push_back(enabledGemTotal);
|
||||
|
||||
elementNames.push_back(GemSortFilterProxyModel::GetGemActiveString(GemSortFilterProxyModel::GemActive::Inactive));
|
||||
elementCounts.push_back(totalGems - enabledGemTotal);
|
||||
|
||||
bool wasCollapsed = false;
|
||||
if (m_statusFilter)
|
||||
{
|
||||
@@ -262,44 +263,51 @@ namespace O3DE::ProjectManager
|
||||
|
||||
const QList<QAbstractButton*> buttons = m_statusFilter->GetButtonGroup()->buttons();
|
||||
|
||||
QAbstractButton* unselectedButton = buttons[0];
|
||||
QAbstractButton* selectedButton = buttons[1];
|
||||
unselectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
selectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Selected);
|
||||
QAbstractButton* selectedButton = buttons[0];
|
||||
QAbstractButton* unselectedButton = buttons[1];
|
||||
selectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Selected);
|
||||
unselectedButton->setChecked(m_filterProxyModel->GetGemSelected() == GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
|
||||
auto updateGemSelection = [=]([[maybe_unused]] bool checked)
|
||||
{
|
||||
if (unselectedButton->isChecked() && !selectedButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
}
|
||||
else if (!unselectedButton->isChecked() && selectedButton->isChecked())
|
||||
if (!unselectedButton->isChecked() && selectedButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Selected);
|
||||
}
|
||||
else if (unselectedButton->isChecked() && !selectedButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Unselected);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::NoFilter);
|
||||
if (unselectedButton->isChecked() && selectedButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::Both);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_filterProxyModel->SetGemSelected(GemSortFilterProxyModel::GemSelected::NoFilter);
|
||||
}
|
||||
}
|
||||
};
|
||||
connect(unselectedButton, &QAbstractButton::toggled, this, updateGemSelection);
|
||||
connect(selectedButton, &QAbstractButton::toggled, this, updateGemSelection);
|
||||
|
||||
QAbstractButton* inactiveButton = buttons[2];
|
||||
QAbstractButton* activeButton = buttons[3];
|
||||
inactiveButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Inactive);
|
||||
activeButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Active);
|
||||
QAbstractButton* activeButton = buttons[2];
|
||||
QAbstractButton* inactiveButton = buttons[3];
|
||||
activeButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Active);
|
||||
inactiveButton->setChecked(m_filterProxyModel->GetGemActive() == GemSortFilterProxyModel::GemActive::Inactive);
|
||||
|
||||
auto updateGemActive = [=]([[maybe_unused]] bool checked)
|
||||
{
|
||||
if (inactiveButton->isChecked() && !activeButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive);
|
||||
}
|
||||
else if (!inactiveButton->isChecked() && activeButton->isChecked())
|
||||
if (!inactiveButton->isChecked() && activeButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Active);
|
||||
}
|
||||
else if (inactiveButton->isChecked() && !activeButton->isChecked())
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::Inactive);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_filterProxyModel->SetGemActive(GemSortFilterProxyModel::GemActive::NoFilter);
|
||||
|
||||
@@ -50,11 +50,26 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
// Gem selected
|
||||
if (m_gemSelectedFilter != GemSelected::NoFilter)
|
||||
// Gem selected
|
||||
if (m_gemSelectedFilter == GemSelected::Selected)
|
||||
{
|
||||
const GemSelected sourceGemStatus = static_cast<GemSelected>(GemModel::IsAdded(sourceIndex));
|
||||
if (m_gemSelectedFilter != sourceGemStatus)
|
||||
if (!GemModel::NeedsToBeAdded(sourceIndex, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Gem unselected
|
||||
else if (m_gemSelectedFilter == GemSelected::Unselected)
|
||||
{
|
||||
if (!GemModel::NeedsToBeRemoved(sourceIndex, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Gem selected or unselected
|
||||
else if (m_gemSelectedFilter == GemSelected::Both)
|
||||
{
|
||||
if (!GemModel::NeedsToBeAdded(sourceIndex, true) && !GemModel::NeedsToBeRemoved(sourceIndex, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
NoFilter = -1,
|
||||
Unselected,
|
||||
Selected
|
||||
Selected,
|
||||
Both
|
||||
};
|
||||
enum class GemActive
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace O3DE::ProjectManager
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setContentsMargins(30, 30, 25, 10);
|
||||
vLayout->setSpacing(0);
|
||||
vLayout->setAlignment(Qt::AlignTop);
|
||||
setLayout(vLayout);
|
||||
|
||||
QLabel* instructionTitleLabel = new QLabel(tr("Enter a valid path to add a new user repository"));
|
||||
@@ -41,9 +42,18 @@ namespace O3DE::ProjectManager
|
||||
vLayout->addWidget(instructionContextLabel);
|
||||
|
||||
m_repoPath = new FormFolderBrowseEditWidget(tr("Repository Path"), "", this);
|
||||
m_repoPath->setFixedWidth(600);
|
||||
m_repoPath->setFixedSize(QSize(600, 100));
|
||||
vLayout->addWidget(m_repoPath);
|
||||
|
||||
vLayout->addSpacing(10);
|
||||
|
||||
QLabel* warningLabel = new QLabel(tr("Online repositories may contain files that could potentially harm your computer,"
|
||||
" please ensure you understand the risks before downloading Gems from third-party sources."));
|
||||
warningLabel->setObjectName("gemRepoAddDialogWarningLabel");
|
||||
warningLabel->setWordWrap(true);
|
||||
warningLabel->setAlignment(Qt::AlignLeft);
|
||||
vLayout->addWidget(warningLabel);
|
||||
|
||||
vLayout->addSpacing(40);
|
||||
|
||||
QDialogButtonBox* dialogButtons = new QDialogButtonBox();
|
||||
|
||||
@@ -133,6 +133,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are already on this screen still notify we are on this screen to refresh it
|
||||
newScreen->NotifyCurrentScreen();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace AZ
|
||||
|
||||
// Register utilities
|
||||
AZ::SceneAPI::SceneCore::PatternMatcher::Reflect(context);
|
||||
AZ::SceneAPI::Utilities::DebugSceneGraph::Reflect(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
|
||||
@@ -20,6 +21,36 @@
|
||||
|
||||
namespace AZ::SceneAPI::Utilities
|
||||
{
|
||||
void DebugNode::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<DebugNode>()
|
||||
->Field("Name", &DebugNode::m_name)
|
||||
->Field("Path", &DebugNode::m_path)
|
||||
->Field("Type", &DebugNode::m_type)
|
||||
->Field("Data", &DebugNode::m_data);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugSceneGraph::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
DebugNode::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<DebugSceneGraph>()
|
||||
->Field("Version", &DebugSceneGraph::m_version)
|
||||
->Field("ProductName", &DebugSceneGraph::m_productName)
|
||||
->Field("SceneName", &DebugSceneGraph::m_sceneName)
|
||||
->Field("Nodes", &DebugSceneGraph::m_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, const char* data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: %s\n", name, data);
|
||||
@@ -38,21 +69,29 @@ namespace AZ::SceneAPI::Utilities
|
||||
void DebugOutput::Write(const char* name, const AZStd::string& data)
|
||||
{
|
||||
Write(name, data.c_str());
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, double data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: %f\n", name, data);
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, uint64_t data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: %" PRIu64 "\n", name, data);
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, int64_t data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: %" PRId64 "\n", name, data);
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, const DataTypes::MatrixType& data)
|
||||
@@ -63,6 +102,7 @@ namespace AZ::SceneAPI::Utilities
|
||||
AZ::Vector3 translation{};
|
||||
data.GetBasisAndTranslation(&basisX, &basisY, &basisZ, &translation);
|
||||
|
||||
m_pauseNodeData = true;
|
||||
m_output += AZStd::string::format("\t%s:\n", name);
|
||||
|
||||
m_output += "\t";
|
||||
@@ -76,16 +116,23 @@ namespace AZ::SceneAPI::Utilities
|
||||
|
||||
m_output += "\t";
|
||||
Write("Transl", translation);
|
||||
m_pauseNodeData = false;
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, bool data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: %s\n", name, data ? "true" : "false");
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, Vector3 data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: <% f, % f, % f>\n", name, data.GetX(), data.GetY(), data.GetZ());
|
||||
|
||||
AddToNode(name, data);
|
||||
}
|
||||
|
||||
void DebugOutput::Write(const char* name, AZStd::optional<bool> data)
|
||||
@@ -128,6 +175,11 @@ namespace AZ::SceneAPI::Utilities
|
||||
return m_output;
|
||||
}
|
||||
|
||||
DebugNode DebugOutput::GetDebugNode() const
|
||||
{
|
||||
return m_currentNode;
|
||||
}
|
||||
|
||||
void WriteAndLog(AZ::IO::SystemFile& dbgFile, const char* strToWrite)
|
||||
{
|
||||
AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "%s", strToWrite);
|
||||
@@ -137,7 +189,6 @@ namespace AZ::SceneAPI::Utilities
|
||||
|
||||
void DebugOutput::BuildDebugSceneGraph(const char* outputFolder, AZ::SceneAPI::Events::ExportProductList& productList, const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene>& scene, AZStd::string productName)
|
||||
{
|
||||
const int debugSceneGraphVersion = 1;
|
||||
AZStd::string debugSceneFile;
|
||||
|
||||
AzFramework::StringFunc::Path::ConstructFull(outputFolder, productName.c_str(), debugSceneFile);
|
||||
@@ -147,7 +198,7 @@ namespace AZ::SceneAPI::Utilities
|
||||
if (dbgFile.Open(debugSceneFile.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY))
|
||||
{
|
||||
WriteAndLog(dbgFile, AZStd::string::format("ProductName: %s", productName.c_str()).c_str());
|
||||
WriteAndLog(dbgFile, AZStd::string::format("debugSceneGraphVersion: %d", debugSceneGraphVersion).c_str());
|
||||
WriteAndLog(dbgFile, AZStd::string::format("debugSceneGraphVersion: %d", SceneGraphVersion).c_str());
|
||||
WriteAndLog(dbgFile, scene->GetName().c_str());
|
||||
|
||||
const AZ::SceneAPI::Containers::SceneGraph& sceneGraph = scene->GetGraph();
|
||||
@@ -158,6 +209,11 @@ namespace AZ::SceneAPI::Utilities
|
||||
AZ::SceneAPI::Containers::Views::BreadthFirst>(
|
||||
sceneGraph, sceneGraph.GetRoot(), pairView.cbegin(), true);
|
||||
|
||||
DebugSceneGraph debugSceneGraph;
|
||||
debugSceneGraph.m_version = SceneGraphVersion;
|
||||
debugSceneGraph.m_productName = productName;
|
||||
debugSceneGraph.m_sceneName = scene->GetName().c_str();
|
||||
|
||||
for (auto&& viewIt : view)
|
||||
{
|
||||
if (viewIt.second == nullptr)
|
||||
@@ -170,20 +226,31 @@ namespace AZ::SceneAPI::Utilities
|
||||
WriteAndLog(dbgFile, AZStd::string::format("Node Name: %s", viewIt.first.GetName()).c_str());
|
||||
WriteAndLog(dbgFile, AZStd::string::format("Node Path: %s", viewIt.first.GetPath()).c_str());
|
||||
WriteAndLog(dbgFile, AZStd::string::format("Node Type: %s", graphObject->RTTI_GetTypeName()).c_str());
|
||||
|
||||
AZ::SceneAPI::Utilities::DebugOutput debugOutput;
|
||||
|
||||
AZ::SceneAPI::Utilities::DebugOutput debugOutput(
|
||||
DebugNode(viewIt.first.GetName(), viewIt.first.GetPath(), graphObject->RTTI_GetTypeName()));
|
||||
|
||||
viewIt.second->GetDebugOutput(debugOutput);
|
||||
|
||||
if (!debugOutput.GetOutput().empty())
|
||||
{
|
||||
WriteAndLog(dbgFile, debugOutput.GetOutput().c_str());
|
||||
}
|
||||
|
||||
debugSceneGraph.m_nodes.push_back(debugOutput.GetDebugNode());
|
||||
}
|
||||
dbgFile.Close();
|
||||
|
||||
Utils::SaveObjectToFile((debugSceneFile + ".xml").c_str(), DataStream::StreamType::ST_XML, &debugSceneGraph);
|
||||
|
||||
static const AZ::Data::AssetType dbgSceneGraphAssetType("{07F289D1-4DC7-4C40-94B4-0A53BBCB9F0B}");
|
||||
productList.AddProduct(productName, AZ::Uuid::CreateName(productName.c_str()), dbgSceneGraphAssetType,
|
||||
AZStd::nullopt, AZStd::nullopt);
|
||||
|
||||
static const AZ::Data::AssetType dbgSceneGraphXmlAssetType("{51F37614-0D77-4F36-9AC6-7ED70A0AC868}");
|
||||
productList.AddProduct(
|
||||
(productName + ".xml"), AZ::Uuid::CreateName((productName + ".xml").c_str()), dbgSceneGraphXmlAssetType,
|
||||
AZStd::nullopt, AZStd::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <cinttypes>
|
||||
#include <AzCore/std/any.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -34,15 +35,63 @@ namespace AZ
|
||||
|
||||
namespace AZ::SceneAPI::Utilities
|
||||
{
|
||||
constexpr int SceneGraphVersion = 1;
|
||||
|
||||
struct DebugNode
|
||||
{
|
||||
AZ_TYPE_INFO(DebugNode, "{490B9D4C-1847-46EB-BEBC-49812E104626}");
|
||||
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_path;
|
||||
AZStd::string m_type;
|
||||
|
||||
DebugNode() = default;
|
||||
|
||||
DebugNode(AZStd::string name, AZStd::string path, AZStd::string type)
|
||||
: m_name(AZStd::move(name)),
|
||||
m_path(AZStd::move(path)),
|
||||
m_type(AZStd::move(type))
|
||||
{
|
||||
}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
using DataItem = AZStd::pair<AZStd::string, AZStd::any>;
|
||||
AZStd::vector<DataItem> m_data;
|
||||
};
|
||||
|
||||
struct DebugSceneGraph
|
||||
{
|
||||
AZ_TYPE_INFO(DebugSceneGraph, "{375F6558-5709-409F-881E-8ED575D56C92}");
|
||||
|
||||
int m_version = SceneGraphVersion;
|
||||
AZStd::string m_productName;
|
||||
AZStd::string m_sceneName;
|
||||
AZStd::vector<DebugNode> m_nodes;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
};
|
||||
|
||||
class DebugOutput
|
||||
{
|
||||
public:
|
||||
DebugOutput(DebugNode node) : m_currentNode(AZStd::move(node)){}
|
||||
|
||||
template<typename T>
|
||||
void Write(const char* name, const AZStd::vector<T>& data);
|
||||
|
||||
template<typename T>
|
||||
void Write(const char* name, const AZStd::vector<AZStd::vector<T>>& data);
|
||||
|
||||
template<typename T>
|
||||
void AddToNode(const char* name, const T& data)
|
||||
{
|
||||
if (!m_pauseNodeData)
|
||||
{
|
||||
m_currentNode.m_data.emplace_back(name, AZStd::make_any<AZStd::decay_t<T>>(data));
|
||||
}
|
||||
}
|
||||
|
||||
SCENE_CORE_API void Write(const char* name, const char* data);
|
||||
SCENE_CORE_API void WriteArray(const char* name, const unsigned int* data, int size);
|
||||
SCENE_CORE_API void Write(const char* name, const AZStd::string& data);
|
||||
@@ -57,11 +106,15 @@ namespace AZ::SceneAPI::Utilities
|
||||
SCENE_CORE_API void Write(const char* name, AZStd::optional<AZ::Vector3> data);
|
||||
|
||||
SCENE_CORE_API const AZStd::string& GetOutput() const;
|
||||
SCENE_CORE_API DebugNode GetDebugNode() const;
|
||||
|
||||
SCENE_CORE_API static void BuildDebugSceneGraph(const char* outputFolder, AZ::SceneAPI::Events::ExportProductList& productList, const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene>& scene, AZStd::string productName);
|
||||
|
||||
protected:
|
||||
AZStd::string m_output;
|
||||
DebugSceneGraph m_graph;
|
||||
DebugNode m_currentNode;
|
||||
bool m_pauseNodeData = false; // If true, don't append any data to the DebugNode. Useful when a Write function calls other Write functions
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,11 @@ namespace AZ::SceneAPI::Utilities
|
||||
template <typename T>
|
||||
void DebugOutput::Write(const char* name, const AZStd::vector<T>& data)
|
||||
{
|
||||
m_output += AZStd::string::format("\t%s: Count %zu. Hash: %zu\n", name, data.size(), AZStd::hash_range(data.begin(), data.end()));
|
||||
size_t hash = AZStd::hash_range(data.begin(), data.end());
|
||||
m_output += AZStd::string::format("\t%s: Count %zu. Hash: %zu\n", name, data.size(), hash);
|
||||
|
||||
AddToNode(AZStd::string::format("%s - Count", name).c_str(), data.size());
|
||||
AddToNode(AZStd::string::format("%s - Hash", name).c_str(), hash);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -27,5 +31,9 @@ namespace AZ::SceneAPI::Utilities
|
||||
}
|
||||
|
||||
m_output += AZStd::string::format("\t%s: Count %zu. Hash: %zu\n", name, data.size(), hash);
|
||||
|
||||
AddToNode(AZStd::string::format("%s - Count", name).c_str(), data.size());
|
||||
AddToNode(AZStd::string::format("%s - Hash", name).c_str(), hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -81,8 +81,6 @@ namespace AZ
|
||||
|
||||
// Load the asset catalog so that we can find any nested assets successfully. We also need to tick the tick bus
|
||||
// so that the OnCatalogLoaded event gets processed now, instead of during application shutdown.
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml");
|
||||
application.Tick();
|
||||
|
||||
AZStd::string logggingScratchBuffer;
|
||||
|
||||
Reference in New Issue
Block a user