diff --git a/Assets/Editor/Prefabs/Default_Level.prefab b/Assets/Editor/Prefabs/Default_Level.prefab
index d02d669f53..0267131fa0 100644
--- a/Assets/Editor/Prefabs/Default_Level.prefab
+++ b/Assets/Editor/Prefabs/Default_Level.prefab
@@ -185,7 +185,7 @@
{
"id": {
"materialAssetId": {
- "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
+ "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
"subId": 803645540
}
}
@@ -197,7 +197,7 @@
"id": {
"lodIndex": 0,
"materialAssetId": {
- "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
+ "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
"subId": 803645540
}
}
diff --git a/Assets/Engine/Engine_Dependencies.xml b/Assets/Engine/Engine_Dependencies.xml
index 0d6541e18e..b969b3bc97 100644
--- a/Assets/Engine/Engine_Dependencies.xml
+++ b/Assets/Engine/Engine_Dependencies.xml
@@ -1,16 +1,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed
index aafbffbe8f..18ccd19dc3 100644
--- a/Assets/Engine/SeedAssetList.seed
+++ b/Assets/Engine/SeedAssetList.seed
@@ -1,621 +1,260 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py
index ee8e177bbb..303a012cda 100755
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py
@@ -47,82 +47,6 @@ class TestsAssetProcessorBatch_DependenycyTests(object):
"""
AssetProcessorBatch Dependency tests
"""
-
- @pytest.mark.test_case_id("C16877166")
- @pytest.mark.BAT
- @pytest.mark.assetpipeline
- # fmt:off
- def test_WindowsMacPlatforms_RunAPBatch_NotMissingDependency(self, ap_setup_fixture, asset_processor,
- workspace):
- # fmt:on
- """
- Engine Schema
- This test case has a conditional scenario depending on the existence of surfacetypes.xml in a project.
- Some projects have this file and others do not. Run the conditional scenario depending on the existence
- of the file in the project
- libs/materialeffects/surfacetypes.xml is listed as an entry engine_dependencies.xml
- libs/materialeffects/surfacetypes.xml is not listed as a missing dependency
- in the 'assetprocessorbatch' console output
-
- Test Steps:
- 1. Assets are pre-processed
- 2. Verify that engine_dependencies.xml exists
- 3. Verify engine_dependencies.xml has surfacetypes.xml present
- 4. Run Missing Dependency scanner against the engine_dependenciese.xml
- 5. Verify that Surfacetypes.xml is NOT in the missing depdencies output
- 6. Add the schema file which allows our xml parser to understand dependencies for our engine_dependencies file
- 7. Process assets
- 8. Run Missing Dependency scanner against the engine_dependenciese.xml
- 9. Verify that surfacetypes.xml is in the missing dependencies out
- """
-
- env = ap_setup_fixture
- BATCH_LOG_PATH = env["ap_batch_log_file"]
- asset_processor.create_temp_asset_root()
- asset_processor.add_relative_source_asset(os.path.join("Assets", "Engine", "engine_dependencies.xml"))
- asset_processor.add_scan_folder(os.path.join("Assets", "Engine"))
- asset_processor.add_relative_source_asset(os.path.join("Assets", "Engine", "Libs", "MaterialEffects", "surfacetypes.xml"))
-
- # Precondition: Assets are all processed
- asset_processor.batch_process()
-
- DEPENDENCIES_PATH = os.path.join(asset_processor.temp_project_cache(), "engine_dependencies.xml")
- assert os.path.exists(DEPENDENCIES_PATH), "The engine_dependencies.xml does not exist."
- surfacetypes_in_dependencies = False
- surfacetypes_missing_logline = False
-
- # Read engine_dependencies.xml to see if surfacetypes.xml is present
- with open(DEPENDENCIES_PATH, "r") as dependencies_file:
- for line in dependencies_file.readlines():
- if "surfacetypes.xml" in line:
- surfacetypes_in_dependencies = True
- logger.info("Surfacetypes.xml was listed in the engine_dependencies.xml file.")
- break
-
- if not surfacetypes_in_dependencies:
- logger.info("Surfacetypes.xml was not listed in the engine_dependencies.xml file.")
-
- _, output = asset_processor.batch_process(capture_output=True,
- extra_params="--dsp=%engine_dependencies.xml")
- log = APOutputParser(output)
- for _ in log.get_lines(run=-1, contains=["surfacetypes.xml", "Missing"]):
- surfacetypes_missing_logline = True
-
- assert surfacetypes_missing_logline, "Surfacetypes.xml not seen in the batch log as missing."
-
- # Add the schema file which allows our xml parser to understand dependencies for our engine_dependencies file
- asset_processor.add_relative_source_asset(os.path.join("Assets", "Engine", "Schema", "enginedependency.xmlschema"))
- asset_processor.batch_process()
-
- _, output = asset_processor.batch_process(capture_output=True,
- extra_params="--dsp=%engine_dependencies.xml")
- log = APOutputParser(output)
- surfacetypes_missing_logline = False
- for _ in log.get_lines(run=-1, contains=["surfacetypes.xml", "Missing"]):
- surfacetypes_missing_logline = True
-
- assert not surfacetypes_missing_logline, "Surfacetypes.xml not seen in the batch log as missing."
-
schemas = [
("C16877167", ".ent"),
("C16877168", "Environment.xml"),
diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp
index e4138da932..5cffedd774 100644
--- a/Code/Editor/CryEdit.cpp
+++ b/Code/Editor/CryEdit.cpp
@@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING
// AzCore
#include
+#include
#include
#include
#include
@@ -1686,6 +1687,11 @@ bool CCryEditApp::InitInstance()
return false;
}
+ if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get())
+ {
+ AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "LegacySystemInterfaceCreated", R"({})");
+ }
+
// Process some queued events come from system init
// Such as asset catalog loaded notification.
// There are some systems need to load configurations from assets for post initialization but before loading level
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h b/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h
index f8e263d6b0..f76ea19589 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h
@@ -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
+ 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, AZStd::scoped_lock>;
+ LockType m_lock;
+ };
+
+ template
+ using DispatchLockGuard = ThreadDispatchLockGuard;
//////////////////////////////////////////////////////////////////////////
virtual ~AssetCatalogRequests() = default;
@@ -200,6 +227,17 @@ namespace AZ
using AssetCatalogRequestBus = AZ::EBus;
+ inline AssetCatalogRequests::PostThreadDispatchInvoker::~PostThreadDispatchInvoker()
+ {
+ if (!AssetCatalogRequestBus::IsInDispatchThisThread())
+ {
+ if (AssetCatalogRequestBus::QueuedEventCount())
+ {
+ AssetCatalogRequestBus::ExecuteQueuedEvents();
+ }
+ }
+ }
+
/*
* Events that AssetManager listens for
*/
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
index ba66d56379..df8db79db0 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
@@ -14,6 +14,7 @@
#include
#include
+#include
#include
#include
@@ -44,8 +45,6 @@
#include
#include
-#include
-#include
#include
#include
@@ -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 /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();
@@ -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::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(m_settingsRegistry.get())->ClearNotifiers();
static_cast(m_settingsRegistry.get())->ClearMergeEvents();
// Uninit and unload any dynamic modules.
m_moduleManager->UnloadModules();
+ ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsUnloaded", R"({})");
NameDictionary::Destroy();
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
index f2b1bb8905..6df93aff4e 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
@@ -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
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp
new file mode 100644
index 0000000000..8e15871bc0
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+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 '/Registry/application_lifecycle_events.setreg")"
+ " or in *.setreg within the project", AZ_STRING_ARG(eventName), AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey));
+ return false;
+ }
+ auto eventRegistrationKey = FixedValueString::format("%.*s/%.*s", AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey),
+ AZ_STRING_ARG(eventName));
+
+ return settingsRegistry.MergeSettings(eventValue, Format::JsonMergePatch, eventRegistrationKey);
+ }
+
+ bool RegisterEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName)
+ {
+ using FixedValueString = SettingsRegistryInterface::FixedValueString;
+ using Format = AZ::SettingsRegistryInterface::Format;
+
+ if (!ValidateEvent(settingsRegistry, eventName))
+ {
+ FixedValueString eventRegistrationKey{ ApplicationLifecycleEventRegistrationKey };
+ eventRegistrationKey += '/';
+ eventRegistrationKey += eventName;
+ return settingsRegistry.MergeSettings(R"({})", Format::JsonMergePatch, eventRegistrationKey);
+ }
+
+ return true;
+ }
+
+ bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
+ AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent)
+ {
+ using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
+ using Type = AZ::SettingsRegistryInterface::Type;
+ using NotifyEventHandler = AZ::SettingsRegistryInterface::NotifyEventHandler;
+
+ // Some systems may attempt to register a handler before the settings registry has been loaded
+ // If so, this flag lets them automatically register an event if it hasn't yet been registered.
+ // RegisterEvent calls validate event.
+ if ((!autoRegisterEvent && !ValidateEvent(settingsRegistry, eventName)) ||
+ (autoRegisterEvent && !RegisterEvent(settingsRegistry, eventName)))
+ {
+ AZ_Warning(
+ "ComponentApplicationLifecycle", false,
+ R"(Cannot register event %.*s. Name is not a field of object "%.*s".)"
+ R"( Please make sure the entry exists in the '/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;
+ }
+}
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h
new file mode 100644
index 0000000000..6f07c0da3f
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include
+#include
+
+namespace AZ::ComponentApplicationLifecycle
+{
+ //! Root Key where lifecycle events should be registered under
+ inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Application/LifecycleEvents";
+
+
+ //! Validates that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey
+ //! @param settingsRegistry registry where @eventName will be searched
+ //! @param eventName name of key that validated that exists as an element in the ApplicationLifecycleEventRegistrationKey array
+ //! @return true if the @eventName was found in the ApplicationLifecycleEventRegistrationKey array
+ bool ValidateEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName);
+
+ //! Wrapper around setting a value underneath the ApplicationLifecycleEventRegistrationKey
+ //! It validates if the @eventName is is part of the ApplicationLifecycleEventRegistrationKey array
+ //! It then appends the @eventName to the ApplicationLifecycleEventRegistrationKey merges the @eventValue into
+ //! the SettingsRegistry at that key
+ //! NOTE: This function should only be invoked from ComponentApplication and its derived classes
+ //! @param settingsRegistry registry where eventName should be set
+ //! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to signal
+ //! @param eventValue JSON Object that will be merged into the SettingsRegistry at /
+ //! @return true if the eventValue was successfully merged at the /
+ bool SignalEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName, AZStd::string_view eventValue);
+
+ //! Register that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey
+ //! @param settingsRegistry registry where @eventName will be searched
+ //! @param eventName name of key that will be stored in the ApplicationLifecycleEventRegistrationKey array
+ //! @return true if the event passed validation or the eventName was stored in the ApplicationLifecycleEventRegistrationKey array
+ bool RegisterEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName);
+
+ //! Wrapper around registering the NotifyEventHandler with the SettingsRegistry for the specified event
+ //! It validates if the @eventName is is part of the ApplicationLifecycleEventRegistrationKey array and if
+ //! so moves the @callback into @handler and then registers the handler with the SettingsRegistry NotifyEvent
+ //! @param settingsRegistry registry where handler will be registered
+ //! @param handler handler where callback will be moved into and then registered with the SettingsRegistry
+ //! if the specified @eventName passes validation
+ //! @param callback will be moved into the handler if the specified @eventName is valid
+ //! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to register
+ //! @param autoRegisterEvent automatically register this event if it hasn't been registered yet. This is useful
+ //! when registering a handler before the settings registry has been loaded.
+ //! @return true if the handler was registered with the SettingsRegistry NotifyEvent
+ bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
+ AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent = false);
+}
diff --git a/Code/Framework/AzCore/AzCore/Console/IConsole.h b/Code/Framework/AzCore/AzCore/Console/IConsole.h
index 73d17ac65a..aef163d22b 100644
--- a/Code/Framework/AzCore/AzCore/Console/IConsole.h
+++ b/Code/Framework/AzCore/AzCore/Console/IConsole.h
@@ -262,6 +262,6 @@ static constexpr AZ::ThreadSafety ConsoleThreadSafety<_TYPE, std::enable_if_t Functor##_FUNCTION(#_FUNCTION, _DESC, _FLAGS | AZ::ConsoleFunctorFlags::DontDuplicate, AZ::TypeId::CreateNull(), &_FUNCTION)
+ inline AZ::ConsoleFunctor 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__))
diff --git a/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp b/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp
index 1fdeafa309..cbf3ce5243 100644
--- a/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp
+++ b/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp
@@ -10,16 +10,13 @@
#include
#include
-#include
-#include
#include
#include
#include
-#include
#include
+#include
+#include
#include
-#include
-#include
#include
#include
@@ -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 tagList;
- AZStd::tokenize(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
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
index 36f66312d8..5458a3fadf 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
@@ -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);
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp
index c32591874b..5cd36785dc 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp
@@ -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())
{
- 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())
{
- RegisterScriptProxyForNotify(*this);
+ RegisterScriptProxyForNotify(m_settingsRegistry.get(), m_notifyEventProxy.get());
}
// SettingsRegistryScriptProxy function that determines if the SettingsRegistry object is valid
diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake
index 41229429f2..0c5a360844 100644
--- a/Code/Framework/AzCore/AzCore/azcore_files.cmake
+++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake
@@ -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
diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
index f8d0ea8bb1..323e834413 100644
--- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -120,6 +121,11 @@ namespace AzFramework
m_archiveFileIO = AZStd::make_unique(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
+ // (That happens in MergeSettingsToRegistry
+ AZ::ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "FileIOAvailable");
+ AZ::ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "FileIOAvailable", R"({})");
}
if (auto nativeUI = AZ::Interface::Get(); nativeUI == nullptr)
@@ -172,6 +178,8 @@ namespace AzFramework
// Archive classes relies on the FileIOBase DirectInstance to close
// files properly
m_directFileIO.reset();
+
+ AZ::ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "FileIOUnavailable", R"({})");
}
void Application::Start(const Descriptor& descriptor, const StartupParameters& startupParameters)
@@ -196,7 +204,24 @@ namespace AzFramework
systemEntity->Activate();
AZ_Assert(systemEntity->GetState() == AZ::Entity::State::Active, "System Entity failed to activate.");
- m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active);
+ if (m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); m_isStarted)
+ {
+ if (m_startupParameters.m_loadAssetCatalog)
+ {
+ // Start Monitoring Asset changes over the network and load the AssetCatalog
+ auto StartMonitoringAssetsAndLoadCatalog = [this](AZ::Data::AssetCatalogRequests* assetCatalogRequests)
+ {
+ if (AZ::IO::FixedMaxPath assetCatalogPath;
+ m_settingsRegistry->Get(assetCatalogPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
+ {
+ assetCatalogPath /= "assetcatalog.xml";
+ assetCatalogRequests->LoadCatalog(assetCatalogPath.c_str());
+ }
+ };
+ using AssetCatalogBus = AZ::Data::AssetCatalogRequestBus;
+ AssetCatalogBus::Broadcast(AZStd::move(StartMonitoringAssetsAndLoadCatalog));
+ }
+ }
}
void Application::PreModuleLoad()
@@ -210,6 +235,17 @@ namespace AzFramework
{
if (m_isStarted)
{
+ if (m_startupParameters.m_loadAssetCatalog)
+ {
+ // Stop Monitoring Assets changes
+ auto StopMonitoringAssets = [](AZ::Data::AssetCatalogRequests* assetCatalogRequests)
+ {
+ assetCatalogRequests->StopMonitoringAssets();
+ };
+ using AssetCatalogBus = AZ::Data::AssetCatalogRequestBus;
+ AssetCatalogBus::Broadcast(AZStd::move(StopMonitoringAssets));
+ }
+
ApplicationLifecycleEvents::Bus::Broadcast(&ApplicationLifecycleEvents::OnApplicationAboutToStop);
m_pimpl.reset();
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
index cd30b753b5..c1c5775958 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
@@ -12,6 +12,7 @@
#include
#include
+#include
#include
#include
#include
@@ -363,6 +364,23 @@ namespace AZ::IO
, m_mainThreadId{ AZStd::this_thread::get_id() }
{
CompressionBus::Handler::BusConnect();
+
+ // If the settings registry is not available at this point,
+ // then something catastrophic has happened in the application startup.
+ // That should have been caught and messaged out earlier in startup.
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ // Automatically register the event if it's not registered, because
+ // this system is initialized before the settings registry has loaded the event list.
+ AZ::ComponentApplicationLifecycle::RegisterHandler(
+ *settingsRegistry, m_componentApplicationLifecycleHandler,
+ [this](AZStd::string_view /*path*/, AZ::SettingsRegistryInterface::Type /*type*/)
+ {
+ OnSystemEntityActivated();
+ },
+ "SystemComponentsActivated",
+ /*autoRegisterEvent*/ true);
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -1175,13 +1193,20 @@ namespace AZ::IO
}
}
- auto bundleManifest = GetBundleManifest(desc.pZip);
AZStd::shared_ptr bundleCatalog;
+ auto bundleManifest = GetBundleManifest(desc.pZip);
if (bundleManifest)
{
bundleCatalog = GetBundleCatalog(desc.pZip, bundleManifest->GetCatalogName());
}
+ // If this archive is loaded before the serialize context is available, then the manifest and catalog will need to be loaded later.
+ if (!bundleManifest || !bundleCatalog)
+ {
+ m_archivesWithCatalogsToLoad.push_back(
+ ArchivesWithCatalogsToLoad(szFullPath, szBindRoot, flags, nextBundle, desc.m_strFileName));
+ }
+
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
@@ -1219,12 +1244,17 @@ namespace AZ::IO
m_levelOpenEvent.Signal(levelDirs);
}
- AZ::IO::ArchiveNotificationBus::Broadcast([](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
- AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle, AZStd::shared_ptr bundleCatalog)
+ if (bundleManifest && bundleCatalog)
{
- archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
- }, desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
-
+ AZ::IO::ArchiveNotificationBus::Broadcast(
+ [](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
+ AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
+ AZStd::shared_ptr bundleCatalog)
+ {
+ archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
+ },
+ desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
+ }
return true;
}
@@ -2138,7 +2168,7 @@ namespace AZ::IO
}
currentDirPattern = currentDir + AZ_FILESYSTEM_SEPARATOR_WILDCARD;
- currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "levels.pak";
+ currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "level.pak";
ZipDir::FileEntry* fileEntry = findFile.FindExact(currentFilePattern.c_str());
if (fileEntry)
@@ -2175,4 +2205,36 @@ namespace AZ::IO
return catalogInfo;
}
+
+ void Archive::OnSystemEntityActivated()
+ {
+ for (const auto& archiveInfo : m_archivesWithCatalogsToLoad)
+ {
+ AZStd::intrusive_ptr archive =
+ OpenArchive(archiveInfo.m_fullPath, archiveInfo.m_bindRoot, archiveInfo.m_flags, nullptr);
+ if (!archive)
+ {
+ continue;
+ }
+
+ ZipDir::CachePtr pZip = static_cast(archive.get())->GetCache();
+
+ AZStd::shared_ptr bundleCatalog;
+ auto bundleManifest = GetBundleManifest(pZip);
+ if (bundleManifest)
+ {
+ bundleCatalog = GetBundleCatalog(pZip, bundleManifest->GetCatalogName());
+ }
+
+ AZ::IO::ArchiveNotificationBus::Broadcast(
+ [](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
+ AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
+ AZStd::shared_ptr bundleCatalog)
+ {
+ archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
+ },
+ archiveInfo.m_strFileName.c_str(), bundleManifest, archiveInfo.m_nextBundle, bundleCatalog);
+ }
+ m_archivesWithCatalogsToLoad.clear();
+ }
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
index f08d90a66e..279702b433 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -271,6 +272,11 @@ namespace AZ::IO
ZipDir::CachePtr* pZip = {}) const;
private:
+ // Archives can't be fully mounted until the system entity has been activated,
+ // because mounting them requires the BundlingSystemComponent and the serialization system
+ // to both be available.
+ void OnSystemEntityActivated();
+
bool OpenPackCommon(AZStd::string_view szBindRoot, AZStd::string_view pName, AZStd::intrusive_ptr pData = nullptr, bool addLevels = true);
bool OpenPacksCommon(AZStd::string_view szDir, AZStd::string_view pWildcardIn, AZStd::vector* pFullPaths = nullptr, bool addLevels = true);
@@ -313,6 +319,8 @@ namespace AZ::IO
mutable AZStd::shared_mutex m_csZips;
ZipArray m_arrZips;
+ AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
+
//////////////////////////////////////////////////////////////////////////
// Opened files collector.
//////////////////////////////////////////////////////////////////////////
@@ -339,5 +347,34 @@ namespace AZ::IO
// [LYN-2376] Remove once legacy slice support is removed
LevelPackOpenEvent m_levelOpenEvent;
LevelPackCloseEvent m_levelCloseEvent;
+
+ // If pak files are loaded before the serialization and bundling system
+ // are ready to go, their asset catalogs can't be loaded.
+ // In this case, cache information about those archives,
+ // and attempt to load the catalogs later, when the required systems are enabled.
+ struct ArchivesWithCatalogsToLoad
+ {
+ ArchivesWithCatalogsToLoad(
+ AZStd::string_view fullPath,
+ AZStd::string_view bindRoot,
+ int flags,
+ AZ::IO::PathView nextBundle,
+ AZ::IO::Path strFileName)
+ : m_fullPath(fullPath)
+ , m_bindRoot(bindRoot)
+ , m_flags(flags)
+ , m_nextBundle(nextBundle)
+ , m_strFileName(strFileName)
+ {
+ }
+
+ AZ::IO::Path m_strFileName;
+ AZStd::string m_fullPath;
+ AZStd::string m_bindRoot;
+ AZ::IO::PathView m_nextBundle;
+ int m_flags;
+ };
+
+ AZStd::vector m_archivesWithCatalogsToLoad;
};
}
diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp
index e6b8211c28..3d76bcefc4 100644
--- a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp
@@ -565,7 +565,7 @@ namespace AzFramework
if (!bytes.empty())
{
- AZStd::shared_ptr < AzFramework::AssetRegistry> prevRegistry;
+ AZStd::shared_ptr 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 lock(m_registryMutex);
m_registry->Clear();
+ m_initialized = false;
}
diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp
index f9eefa7639..26a22f4625 100644
--- a/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp
@@ -61,6 +61,7 @@ namespace AzFramework
//=========================================================================
void AssetRegistry::Clear()
{
+ m_assetDependencies = {};
m_assetIdToInfo = AssetIdToInfoMap();
m_assetPathToId = AssetPathToIdMap();
}
diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp
index f820ee56ed..abbb9ec2f1 100644
--- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp
+++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp
@@ -10,11 +10,11 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -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 FileTagManager::AddTagsInternal(AZStd::string filePath, FileTagType fileTagType, AZStd::vector 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);
diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h
index be3d6e6d08..d2dee3f629 100644
--- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h
+++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
namespace AzFramework
@@ -88,7 +89,7 @@ namespace AzFramework
/////////////////////////////////////////////////////////////////////////
- static AZStd::string GetDefaultFileTagFilePath(FileTagType fileTagType);
+ static AZ::IO::Path GetDefaultFileTagFilePath(FileTagType fileTagType);
protected:
diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp b/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp
index 1e03a6df0d..1d09500415 100644
--- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp
+++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp
@@ -16,6 +16,7 @@
#include
#include
+#include
#include
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();
diff --git a/Code/Framework/AzFramework/Tests/AssetCatalog.cpp b/Code/Framework/AzFramework/Tests/AssetCatalog.cpp
index 8cdc54f34f..9e5c72f74c 100644
--- a/Code/Framework/AzFramework/Tests/AssetCatalog.cpp
+++ b/Code/Framework/AzFramework/Tests/AssetCatalog.cpp
@@ -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
diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
index 0cce93d751..f0417d206e 100644
--- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
+++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
@@ -45,6 +45,13 @@ namespace AzGameFramework
enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak";
m_archive->OpenPack("@products@", enginePakPath.Native());
}
+
+ // By default, load all archives in the products folder.
+ // If you want to adjust this for your project, make sure that the archive containing
+ // the bootstrap for the settings registry is still loaded here, and any archives containing
+ // assets used early in startup, like default shaders, are loaded here.
+ constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed)
+ m_archive->OpenPacks(paksFolder);
}
GameApplication::~GameApplication()
@@ -82,7 +89,7 @@ namespace AzGameFramework
// Used the lowercase the platform name since the bootstrap.game...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))
diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp
index 0ef9cdfc3b..0f832ff1a5 100644
--- a/Code/LauncherUnified/Launcher.cpp
+++ b/Code/LauncherUnified/Launcher.cpp
@@ -9,6 +9,7 @@
#include
#include
+#include
#include
#include
#include
@@ -664,6 +665,8 @@ namespace O3DELauncher
systemInitParams.pSystem = CreateSystemInterface(systemInitParams);
#endif // !defined(AZ_MONOLITHIC_BUILD)
+ AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "LegacySystemInterfaceCreated", R"({})");
+
ReturnCode status = ReturnCode::Success;
if (systemInitParams.pSystem)
diff --git a/Code/Legacy/CrySystem/IDebugCallStack.cpp b/Code/Legacy/CrySystem/IDebugCallStack.cpp
index deb9c11581..a02658d34a 100644
--- a/Code/Legacy/CrySystem/IDebugCallStack.cpp
+++ b/Code/Legacy/CrySystem/IDebugCallStack.cpp
@@ -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);
}
diff --git a/Code/Legacy/CrySystem/System.h b/Code/Legacy/CrySystem/System.h
index 015b09a69b..a3a0f12278 100644
--- a/Code/Legacy/CrySystem/System.h
+++ b/Code/Legacy/CrySystem/System.h
@@ -590,7 +590,7 @@ public:
bool InitVTuneProfiler();
- void OpenBasicPaks();
+ void OpenPlatformPaks();
void OpenLanguagePak(const char* sLanguage);
void OpenLanguageAudioPak(const char* sLanguage);
void GetLocalizedPath(const char* sLanguage, AZStd::string& sLocalizedPath);
diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp
index ee1c498a9a..ac0683cf1b 100644
--- a/Code/Legacy/CrySystem/SystemInit.cpp
+++ b/Code/Legacy/CrySystem/SystemInit.cpp
@@ -649,7 +649,7 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
auto projectName = AZ::Utils::GetProjectName();
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str());
- OpenBasicPaks();
+ OpenPlatformPaks();
// Load game-specific folder.
LoadConfiguration("game.cfg");
@@ -786,29 +786,19 @@ void CSystem::InitLocalization()
OpenLanguageAudioPak(language.c_str());
}
-void CSystem::OpenBasicPaks()
+void CSystem::OpenPlatformPaks()
{
- static bool bBasicPaksLoaded = false;
- if (bBasicPaksLoaded)
+ static bool bPlatformPaksLoaded = false;
+ if (bPlatformPaksLoaded)
{
return;
}
- bBasicPaksLoaded = true;
-
- // open pak files
- constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed)
- m_env.pCryPak->OpenPacks(paksFolder);
-
- InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( paksFolder.c_str() )");
+ bPlatformPaksLoaded = true;
//////////////////////////////////////////////////////////////////////////
// Open engine packs
//////////////////////////////////////////////////////////////////////////
- const char* const assetsDir = "@products@";
-
- // After game paks to have same search order as with files on disk
- m_env.pCryPak->OpenPack(assetsDir, "engine.pak");
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15
@@ -816,6 +806,7 @@ void CSystem::OpenBasicPaks()
#endif
#ifdef AZ_PLATFORM_ANDROID
+ const char* const assetsDir = "@products@";
// Load Android Obb files if available
const char* obbStorage = AZ::Android::Utils::GetObbStoragePath();
AZStd::string mainObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(true)));
@@ -824,7 +815,7 @@ void CSystem::OpenBasicPaks()
m_env.pCryPak->OpenPack(assetsDir, patchObbPath.c_str());
#endif //AZ_PLATFORM_ANDROID
- InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( Engine... )");
+ InlineInitializationProcessing("CSystem::OpenPlatformPaks OpenPacks( Engine... )");
}
//////////////////////////////////////////////////////////////////////////
@@ -1328,7 +1319,7 @@ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////
// Open basic pak files after intro movie playback started
//////////////////////////////////////////////////////////////////////////
- OpenBasicPaks();
+ OpenPlatformPaks();
//////////////////////////////////////////////////////////////////////////
// AUDIO
diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
index c65ab24aed..7823a0582f 100644
--- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
+++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
@@ -159,6 +159,7 @@ namespace AssetProcessor
builderDesc.m_busId = m_builderId;
builderDesc.m_createJobFunction = AZStd::bind(&SettingsRegistryBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDesc.m_processJobFunction = AZStd::bind(&SettingsRegistryBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
+ builderDesc.m_version = 1;
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDesc);
@@ -259,6 +260,11 @@ namespace AssetProcessor
scratchBuffer.reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
AZStd::fixed_vector 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 +299,9 @@ 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(AZStd::hash{}(platform)); // Deliberately ignoring half the bits.
+ AZStd::string_view platform = platformCodes.front();
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 "/Registry" folder
- // that will be merged into the bootstrap.game...setreg file
+ // that will be merged into the bootstrap.game..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 gemInfos;
@@ -407,9 +413,8 @@ namespace AssetProcessor
return;
}
- outputPath += specialization.GetSpecialization(0); // Append configuration
- outputPath += '.';
- outputPath += platform;
+ AZStd::string_view specializationString(specialization.GetSpecialization(0));
+ outputPath += specializationString; // Append configuration
outputPath += ".setreg";
AZ::IO::SystemFile file;
@@ -426,7 +431,10 @@ namespace AssetProcessor
}
file.Close();
- response.m_outputProducts.emplace_back(outputPath, m_assetType, productSubID + aznumeric_cast(i));
+ AZ::u32 hashedSpecialization = static_cast(AZStd::hash{}(specializationString));
+ AZ_Assert(hashedSpecialization != 0, "Product ID generation failed for specialization %.*s. This can result in a product ID collision with other builders for this asset.",
+ AZ_STRING_ARG(specializationString));
+ response.m_outputProducts.emplace_back(outputPath, m_assetType, hashedSpecialization);
response.m_outputProducts.back().m_dependenciesHandled = true;
outputPath.erase(extensionOffset);
diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp
index 6cfe072f80..d0528a9cad 100644
--- a/Code/Tools/SerializeContextTools/SliceConverter.cpp
+++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp
@@ -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;
diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
index 3f5761270a..c232d4bba7 100644
--- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
+++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
@@ -10,6 +10,7 @@
#include
#include
+#include
#include
#include
#include
@@ -132,7 +133,6 @@ namespace AZ
m_createDefaultScene = false;
}
- AzFramework::AssetCatalogEventBus::Handler::BusConnect();
TickBus::Handler::BusConnect();
// Listen for window system requests (e.g. requests for default window handle)
@@ -143,6 +143,20 @@ namespace AZ
Render::Bootstrap::DefaultWindowBus::Handler::BusConnect();
Render::Bootstrap::RequestBus::Handler::BusConnect();
+
+ // If the settings registry isn't available, something earlier in startup will report that failure.
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ // Automatically register the event if it's not registered, because
+ // this system is initialized before the settings registry has loaded the event list.
+ AZ::ComponentApplicationLifecycle::RegisterHandler(
+ *settingsRegistry, m_componentApplicationLifecycleHandler,
+ [this](AZStd::string_view /*path*/, AZ::SettingsRegistryInterface::Type /*type*/)
+ {
+ Initialize();
+ },
+ "LegacySystemInterfaceCreated");
+ }
}
void BootstrapSystemComponent::Deactivate()
@@ -153,7 +167,6 @@ namespace AZ
AzFramework::WindowSystemRequestBus::Handler::BusDisconnect();
AzFramework::WindowSystemNotificationBus::Handler::BusDisconnect();
TickBus::Handler::BusDisconnect();
- AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
m_brdfTexture = nullptr;
RemoveRenderPipeline();
@@ -164,14 +177,14 @@ namespace AZ
m_windowHandle = nullptr;
}
- void BootstrapSystemComponent::OnCatalogLoaded(const char* /*catalogFile*/)
+ void BootstrapSystemComponent::Initialize()
{
- if (m_isAssetCatalogLoaded)
+ if (m_isInitialized)
{
return;
}
- m_isAssetCatalogLoaded = true;
+ m_isInitialized = true;
if (!RPI::RPISystemInterface::Get()->IsInitialized())
{
@@ -216,7 +229,7 @@ namespace AZ
{
m_windowHandle = windowHandle;
- if (m_isAssetCatalogLoaded)
+ if (m_isInitialized)
{
CreateWindowContext();
if (m_createDefaultScene)
diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
index 566d19b1a4..74679f5753 100644
--- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
+++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
@@ -8,10 +8,10 @@
#pragma once
#include
-#include
#include
+#include
+#include
-#include
#include
#include
#include
@@ -29,7 +29,6 @@
#include
#include
-
namespace AZ
{
namespace Render
@@ -40,7 +39,6 @@ namespace AZ
: public Component
, public TickBus::Handler
, public AzFramework::WindowNotificationBus::Handler
- , public AzFramework::AssetCatalogEventBus::Handler
, public AzFramework::WindowSystemNotificationBus::Handler
, public AzFramework::WindowSystemRequestBus::Handler
, public Render::Bootstrap::DefaultWindowBus::Handler
@@ -82,13 +80,12 @@ namespace AZ
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
int GetTickOrder() override;
- // AzFramework::AssetCatalogEventBus::Handler overrides ...
- void OnCatalogLoaded(const char* catalogFile) override;
-
// AzFramework::WindowSystemNotificationBus::Handler overrides ...
void OnWindowCreated(AzFramework::NativeWindowHandle windowHandle) override;
private:
+ void Initialize();
+
void CreateDefaultRenderPipeline();
void CreateDefaultScene();
void DestroyDefaultScene();
@@ -105,7 +102,7 @@ namespace AZ
RPI::ScenePtr m_defaultScene = nullptr;
AZStd::shared_ptr m_defaultFrameworkScene = nullptr;
- bool m_isAssetCatalogLoaded = false;
+ bool m_isInitialized = false;
// The id of the render pipeline created by this component
RPI::RenderPipelineId m_renderPipelineId;
@@ -119,6 +116,8 @@ namespace AZ
// Maps AZ scenes to RPI scene weak pointers to allow looking up a ScenePtr instead of a raw Scene*
AZStd::unordered_map> m_azSceneToAtomSceneMap;
+
+ AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
};
} // namespace Bootstrap
} // namespace Render
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp
index e8ec77e7bd..ba3bfe4718 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp
@@ -175,8 +175,6 @@ namespace AtomToolsFramework
AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast(
&AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized);
- AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml");
-
if (!AZ::RPI::RPISystemInterface::Get()->IsInitialized())
{
AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets();
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp
index fc5b31297a..d46e7b27be 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp
@@ -47,30 +47,27 @@ namespace AtomToolsFramework
void PreviewRendererSystemComponent::Activate()
{
- AzFramework::AssetCatalogEventBus::Handler::BusConnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
PreviewRendererSystemRequestBus::Handler::BusConnect();
+
+ AZ::TickBus::QueueFunction(
+ [this]()
+ {
+ if (!m_previewRenderer)
+ {
+ m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer(
+ "PreviewRendererSystemComponent Preview Scene", "PreviewRendererSystemComponent Preview Pipeline"));
+ }
+ });
}
void PreviewRendererSystemComponent::Deactivate()
{
PreviewRendererSystemRequestBus::Handler::BusDisconnect();
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
- AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
m_previewRenderer.reset();
}
- void PreviewRendererSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
- {
- AZ::TickBus::QueueFunction([this](){
- if (!m_previewRenderer)
- {
- m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer(
- "PreviewRendererSystemComponent Preview Scene", "PreviewRendererSystemComponent Preview Pipeline"));
- }
- });
- }
-
void PreviewRendererSystemComponent::OnApplicationAboutToStop()
{
m_previewRenderer.reset();
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h
index 8110d84794..0b145bbdf1 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h
@@ -9,7 +9,6 @@
#pragma once
#include
-#include
#include
#include
#include
@@ -19,7 +18,6 @@ namespace AtomToolsFramework
//! System component that manages a global PreviewRenderer.
class PreviewRendererSystemComponent final
: public AZ::Component
- , public AzFramework::AssetCatalogEventBus::Handler
, public AzFramework::ApplicationLifecycleEvents::Bus::Handler
, public PreviewRendererSystemRequestBus::Handler
{
@@ -38,9 +36,6 @@ namespace AtomToolsFramework
void Deactivate() override;
private:
- // AzFramework::AssetCatalogEventBus::Handler overrides ...
- void OnCatalogLoaded(const char* catalogFile) override;
-
// AzFramework::ApplicationLifecycleEvents overrides...
void OnApplicationAboutToStop() override;
diff --git a/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab b/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab
index b5aed9d14b..92874574e4 100644
--- a/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab
+++ b/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab
@@ -581,7 +581,7 @@
{
"id": {
"materialAssetId": {
- "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
+ "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
"subId": 803645540
}
}
@@ -593,7 +593,7 @@
"id": {
"lodIndex": 0,
"materialAssetId": {
- "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
+ "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
"subId": 803645540
}
}
@@ -608,10 +608,10 @@
"Configuration": {
"ModelAsset": {
"assetId": {
- "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
- "subId": 277333723
+ "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
+ "subId": 277889906
},
- "assetHint": "objects/groudplane/groundplane_521x521m.azmodel"
+ "assetHint": "objects/groudplane/groundplane_512x512m.azmodel"
}
}
}
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice b/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice
index b4c9eac10f..e0c7c9e456 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice
+++ b/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice
@@ -836,7 +836,7 @@
-
+
diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp
index b7ee805b3c..00629eb65d 100644
--- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp
+++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp
@@ -143,6 +143,7 @@ namespace Blast
void BlastSystemComponent::Deactivate()
{
AZ_PROFILE_FUNCTION(Physics);
+ AZ::Data::AssetBus::MultiHandler::BusDisconnect();
CrySystemEventBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
BlastSystemRequestBus::Handler::BusDisconnect();
diff --git a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp
index c9fc656488..168a3640a8 100644
--- a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp
+++ b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp
@@ -9,43 +9,40 @@
#include "BundlingSystemComponent.h"
#include
+#include
+#include
#include
#include
+#include
#include
-#include
-
-#include
-#include
-
#include
+
namespace LmbrCentral
{
const char bundleRoot[] = "@products@";
+ // Calls the LoadBundles method
+ static void ConsoleCommandLoadBundles(const AZ::ConsoleCommandContainer& commandArgs);
+ // Calls the UnloadBundles method
+ static void ConsoleCommandUnloadBundles(const AZ::ConsoleCommandContainer& commandArgs);
+
+ AZ_CONSOLEFREEFUNC("loadbundles", ConsoleCommandLoadBundles, AZ::ConsoleFunctorFlags::Null, "Load Asset Bundles");
+ AZ_CONSOLEFREEFUNC("unloadbundles", ConsoleCommandUnloadBundles, AZ::ConsoleFunctorFlags::Null, "Unload Asset Bundles");
+
void BundlingSystemComponent::Activate()
{
BundlingSystemRequestBus::Handler::BusConnect();
- CrySystemEventBus::Handler::BusConnect();
AZ::IO::ArchiveNotificationBus::Handler::BusConnect();
}
void BundlingSystemComponent::Deactivate()
{
AZ::IO::ArchiveNotificationBus::Handler::BusDisconnect();
- CrySystemEventBus::Handler::BusDisconnect();
BundlingSystemRequestBus::Handler::BusDisconnect();
}
- void BundlingSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams)
- {
- AZ_UNUSED(systemInitParams);
-
- system.GetIConsole()->AddCommand("loadbundles", ConsoleCommandLoadBundles);
- system.GetIConsole()->AddCommand("unloadbundles", ConsoleCommandUnloadBundles);
- }
-
void BundlingSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast(context))
@@ -58,7 +55,7 @@ namespace LmbrCentral
AZStd::vector BundlingSystemComponent::GetBundleList(const char* bundlePath, const char* bundleExtension) const
{
- AZStd::string fileFilter{ AZStd::string::format("*%s",bundleExtension) };
+ AZStd::string fileFilter{ AZStd::string::format("*%s", bundleExtension) };
AZStd::vector bundleList;
AZ::IO::FileIOBase::GetInstance()->FindFiles(bundlePath, fileFilter.c_str(), [&bundleList](const char* foundPath) -> bool
@@ -73,29 +70,28 @@ namespace LmbrCentral
return bundleList;
}
- void BundlingSystemComponent::ConsoleCommandLoadBundles(IConsoleCmdArgs* pCmdArgs)
+ void ConsoleCommandLoadBundles(const AZ::ConsoleCommandContainer& commandArgs)
{
const char defaultBundleFolder[] = "bundles";
const char defaultBundleExtension[] = ".pak";
- const char* bundleFolder = pCmdArgs->GetArgCount() > 1 ? pCmdArgs->GetArg(1) : defaultBundleFolder;
- const char* bundleExtension = pCmdArgs->GetArgCount() > 2 ? pCmdArgs->GetArg(2) : defaultBundleExtension;
+ AZ::CVarFixedString bundleFolder = commandArgs.size() > 0 ? AZ::CVarFixedString(commandArgs[0]) : defaultBundleFolder;
+ AZ::CVarFixedString bundleExtension = commandArgs.size() > 1 ? AZ::CVarFixedString(commandArgs[1]) : defaultBundleExtension;
- BundlingSystemRequestBus::Broadcast(&BundlingSystemRequestBus::Events::LoadBundles, bundleFolder, bundleExtension);
+ BundlingSystemRequestBus::Broadcast(&BundlingSystemRequestBus::Events::LoadBundles, bundleFolder.c_str(), bundleExtension.c_str());
}
- void BundlingSystemComponent::ConsoleCommandUnloadBundles(IConsoleCmdArgs* pCmdArgs)
+ void ConsoleCommandUnloadBundles([[maybe_unused]] const AZ::ConsoleCommandContainer& commandArgs)
{
- AZ_UNUSED(pCmdArgs);
BundlingSystemRequestBus::Broadcast(&BundlingSystemRequestBus::Events::UnloadBundles);
}
void BundlingSystemComponent::UnloadBundles()
{
- ISystem* crySystem{ GetISystem() };
- if (!crySystem)
+ auto archive = AZ::Interface::Get();
+ if (!archive)
{
- AZ_Error("BundlingSystem", false, "Couldn't Get ISystem to unload bundles!");
+ AZ_Error("BundlingSystem", false, "Couldn't Get IArchive to load bundles!");
return;
}
if (!m_bundleModeBundles.size())
@@ -106,7 +102,7 @@ namespace LmbrCentral
AZStd::lock_guard openBundleLock(m_bundleModeMutex);
for (const auto& thisBundle : m_bundleModeBundles)
{
- if (crySystem->GetIPak()->ClosePack(thisBundle.c_str()))
+ if (archive->ClosePack(thisBundle.c_str()))
{
AZ_TracePrintf("BundlingSystem", "Unloaded %s\n",thisBundle.c_str());
}
@@ -128,15 +124,8 @@ namespace LmbrCentral
return;
}
- ISystem* crySystem{ GetISystem() };
- if (!crySystem)
- {
- AZ_Error("BundlingSystem", false, "Couldn't Get ISystem to load bundles!");
- return;
- }
-
- auto cryPak = crySystem->GetIPak();
- if (!cryPak)
+ auto archive = AZ::Interface::Get();
+ if (!archive)
{
AZ_Error("BundlingSystem", false, "Couldn't Get IArchive to load bundles!");
return;
@@ -152,8 +141,8 @@ namespace LmbrCentral
}
}
AZStd::string bundlePath;
- AzFramework::StringFunc::Path::Join(bundleRoot, thisBundle.c_str(), bundlePath);
- if (cryPak->OpenPack(bundleRoot, thisBundle.c_str()))
+ AZ::StringFunc::Path::Join(bundleRoot, thisBundle.c_str(), bundlePath);
+ if (archive->OpenPack(bundleRoot, thisBundle.c_str()))
{
AZ_TracePrintf("BundlingSystem", "Loaded bundle %s\n",bundlePath.c_str());
m_bundleModeBundles.emplace_back(AZStd::move(bundlePath));
@@ -230,28 +219,21 @@ namespace LmbrCentral
void BundlingSystemComponent::OpenDependentBundles(const char* bundleName, AZStd::shared_ptr bundleManifest)
{
- ISystem* crySystem{ GetISystem() };
- if (!crySystem)
- {
- AZ_Error("BundlingSystem", false, "Couldn't Get ISystem to load dependent bundles for %s", bundleName);
- return;
- }
-
- auto cryPak{ crySystem->GetIPak() };
- if (!cryPak)
+ auto archive = AZ::Interface::Get();
+ if (!archive)
{
AZ_Error("BundlingSystem", false, "Couldn't Get IArchive to load dependent bundles for %s", bundleName);
return;
}
AZStd::string folderPath;
- AzFramework::StringFunc::Path::GetFolderPath(bundleName, folderPath);
+ AZ::StringFunc::Path::GetFolderPath(bundleName, folderPath);
for (const auto& thisBundle : bundleManifest->GetDependentBundleNames())
{
AZStd::string bundlePath;
- AzFramework::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath);
+ AZ::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath);
- if (!cryPak->OpenPack(bundleRoot, bundlePath.c_str()))
+ if (!archive->OpenPack(bundleRoot, bundlePath.c_str()))
{
// We're not bailing here intentionally - try to open the remaining bundles
AZ_Warning("BundlingSystem", false, "Failed to open dependent bundle %s of bundle %s", bundlePath.c_str(), bundleName);
@@ -300,28 +282,21 @@ namespace LmbrCentral
void BundlingSystemComponent::CloseDependentBundles(const char* bundleName, AZStd::shared_ptr bundleManifest)
{
- ISystem* crySystem{ GetISystem() };
- if (!crySystem)
- {
- AZ_Error("BundlingSystem", false, "Couldn't get ISystem to close dependent bundles for %s", bundleName);
- return;
- }
-
- auto cryPak{ crySystem->GetIPak() };
- if (!cryPak)
+ auto archive = AZ::Interface::Get();
+ if (!archive)
{
AZ_Error("BundlingSystem", false, "Couldn't get IArchive to close dependent bundles for %s", bundleName);
return;
}
AZStd::string folderPath;
- AzFramework::StringFunc::Path::GetFolderPath(bundleName, folderPath);
+ AZ::StringFunc::Path::GetFolderPath(bundleName, folderPath);
for (const auto& thisBundle : bundleManifest->GetDependentBundleNames())
{
AZStd::string bundlePath;
- AzFramework::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath);
+ AZ::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath);
- if (!cryPak->ClosePack(bundlePath.c_str()))
+ if (!archive->ClosePack(bundlePath.c_str()))
{
// We're not bailing here intentionally - try to close the remaining bundles
AZ_Warning("BundlingSystem", false, "Failed to close dependent bundle %s of bundle %s", bundlePath.c_str(), bundleName);
diff --git a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h
index 15fdf1103c..e7c8775530 100644
--- a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h
+++ b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h
@@ -19,11 +19,8 @@
#include
-#include
#include
-struct IConsoleCmdArgs;
-
namespace AzFramework
{
class AssetBundleManifest;
@@ -42,10 +39,9 @@ namespace LmbrCentral
* System component for managing bundles
*/
class BundlingSystemComponent
- : public AZ::Component,
- public BundlingSystemRequestBus::Handler,
- public CrySystemEventBus::Handler,
- public AZ::IO::ArchiveNotificationBus::Handler
+ : public AZ::Component
+ , public BundlingSystemRequestBus::Handler
+ , public AZ::IO::ArchiveNotificationBus::Handler
{
public:
AZ_COMPONENT(BundlingSystemComponent, "{0FB7153D-EE80-4B1C-9584-134270401AAF}");
@@ -70,13 +66,6 @@ namespace LmbrCentral
void BundleOpened(const char* bundleName, AZStd::shared_ptr bundleManifest, const char* nextBundle, AZStd::shared_ptr bundleCatalog) override;
void BundleClosed(const char* bundleName) override;
- // CrySystemEventBus
- void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override;
-
- // Calls the LoadBundles method
- static void ConsoleCommandLoadBundles(IConsoleCmdArgs* pCmdArgs);
- // Calls the UnloadBundles method
- static void ConsoleCommandUnloadBundles(IConsoleCmdArgs* pCmdArgs);
AZStd::vector GetBundleList(const char* bundlePath, const char* bundleExtension) const;
diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp
index e509890efa..027d19fdef 100644
--- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp
+++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp
@@ -83,8 +83,6 @@
namespace LmbrCentral
{
- static const char* s_assetCatalogFilename = "assetcatalog.xml";
-
using LmbrCentralAllocatorScope = AZ::AllocatorScope;
// This component boots the required allocators for LmbrCentral everywhere but AssetBuilders
@@ -353,8 +351,7 @@ namespace LmbrCentral
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
// Add asset types and extensions to AssetCatalog. Uses "AssetCatalogService".
- auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler();
- if (assetCatalog)
+ if (auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); assetCatalog)
{
assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid());
assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid());
@@ -373,7 +370,6 @@ namespace LmbrCentral
assetCatalog->AddExtension("cax");
}
- CrySystemEventBus::Handler::BusConnect();
AZ::Data::AssetManagerNotificationBus::Handler::BusConnect();
@@ -445,7 +441,6 @@ namespace LmbrCentral
m_unhandledAssetInfo.clear();
AZ::Data::AssetManagerNotificationBus::Handler::BusDisconnect();
- CrySystemEventBus::Handler::BusDisconnect();
// AssetHandler's destructor calls Unregister()
m_assetHandlers.clear();
@@ -456,42 +451,6 @@ namespace LmbrCentral
}
m_allocatorShutdowns.clear();
}
-
- void LmbrCentralSystemComponent::OnCrySystemPreInitialize([[maybe_unused]] ISystem& system, [[maybe_unused]] const SSystemInitParams& systemInitParams)
- {
- EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, StartMonitoringAssets);
- }
-
- void LmbrCentralSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams)
- {
-#if !defined(AZ_MONOLITHIC_BUILD)
- // When module is linked dynamically, we must set our gEnv pointer.
- // When module is linked statically, we'll share the application's gEnv pointer.
- gEnv = system.GetGlobalEnvironment();
-#endif
-
- // Enable catalog now that application's asset root is set.
- if (system.GetGlobalEnvironment()->IsEditor())
- {
- // In the editor, we build the catalog by scanning the disk.
- if (systemInitParams.pUserCallback)
- {
- systemInitParams.pUserCallback->OnInitProgress("Refreshing asset catalog...");
- }
- }
-
- // load the catalog from disk (supported over VFS).
- EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, LoadCatalog, AZStd::string::format("@products@/%s", s_assetCatalogFilename).c_str());
- }
-
- void LmbrCentralSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system)
- {
- EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, StopMonitoringAssets);
-
-#if !defined(AZ_MONOLITHIC_BUILD)
- gEnv = nullptr;
-#endif
- }
} // namespace LmbrCentral
#if !defined(LMBR_CENTRAL_EDITOR)
diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.h b/Gems/LmbrCentral/Code/Source/LmbrCentral.h
index 9a0c327ea7..650061dce6 100644
--- a/Gems/LmbrCentral/Code/Source/LmbrCentral.h
+++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.h
@@ -15,8 +15,6 @@
#include
#include
-#include
-
/*!
* \namespace LmbrCentral
* LmbrCentral ties together systems from CryEngine and systems from the AZ framework.
@@ -49,7 +47,6 @@ namespace LmbrCentral
*/
class LmbrCentralSystemComponent
: public AZ::Component
- , private CrySystemEventBus::Handler
, private AZ::Data::AssetManagerNotificationBus::Handler
{
public:
@@ -71,13 +68,6 @@ namespace LmbrCentral
void Deactivate() override;
////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- // CrySystemEvents
- void OnCrySystemPreInitialize(ISystem& system, const SSystemInitParams& systemInitParams) override;
- void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override;
- void OnCrySystemShutdown(ISystem& system) override;
- ////////////////////////////////////////////////////////////////////////////
-
AZStd::vector > m_assetHandlers;
AZStd::vector > m_unhandledAssetInfo;
AZStd::vector> m_allocatorShutdowns;
diff --git a/Registry/application_lifecycle_events.setreg b/Registry/application_lifecycle_events.setreg
new file mode 100644
index 0000000000..0d9cd0f170
--- /dev/null
+++ b/Registry/application_lifecycle_events.setreg
@@ -0,0 +1,30 @@
+// The Lifecycle events contains the name of the event as a string
+// ComponentApplication derived classes
+// will set these these keys to a JSON Object indicate an event has occured
+// A callback can be registered with the SettingsRegistry
+// to be notified when that key is set
+// The JSON object that is set will contain any payload data
+// related to the event
+{
+ "O3DE" : {
+ "Application": {
+ "LifecycleEvents": {
+ "SystemComponentsActivated": {},
+ "SystemComponentsDeactivated": {},
+ "ReflectionManagerAvailable": {},
+ "ReflectionManagerUnavailable": {},
+ "SystemAllocatorCreated": {},
+ "SystemAllocatorPendingDestruction": {},
+ "SettingsRegistryAvailable": {},
+ "SettingsRegistryUnavailable": {},
+ "ConsoleAvailable": {},
+ "ConsoleUnavailable": {},
+ "GemsLoaded": {},
+ "GemsUnloaded": {},
+ "FileIOAvailable": {},
+ "FileIOUnavailable": {},
+ "LegacySystemInterfaceCreated": {}
+ }
+ }
+ }
+}
diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake
index c09fe0fc6f..34ef3efd9b 100644
--- a/cmake/Projects.cmake
+++ b/cmake/Projects.cmake
@@ -150,22 +150,43 @@ foreach(project ${LY_PROJECTS})
# Get project name
o3de_read_json_key(project_name ${full_directory_path}/project.json "project_name")
+ # The cmake tar command has a bit of a flaw
+ # Any paths within the archive files it creates are relative to the current working directory.
+ # That means with the setup of:
+ # cwd = "/Cache/pc"
+ # project product assets = "/Cache/pc/*"
+ # cmake dependency registry files = "/build/bin/Release/Registry/*"
+ # Running the tar command would result in the assets being placed in the to layout
+ # correctly, but the registry files
+ # engine.pak/
+ # ../...build/bin/Release/Registry/cmake_dependencies.*.setreg -> Not correct
+ # project.json -> Correct
+
# Generate pak for project in release installs
cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE install_base_runtime_output_directory)
set(install_engine_pak_template [=[
if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$")
set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@install_base_runtime_output_directory@/@PAL_PLATFORM_NAME@/${CMAKE_INSTALL_CONFIG_NAME}/@LY_BUILD_PERMUTATION@")
set(install_pak_output_folder "${install_output_folder}/Cache/@LY_ASSET_DEPLOY_ASSET_TYPE@")
+ set(runtime_output_directory_RELEASE @CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE@)
if(NOT DEFINED LY_ASSET_DEPLOY_ASSET_TYPE)
set(LY_ASSET_DEPLOY_ASSET_TYPE @LY_ASSET_DEPLOY_ASSET_TYPE@)
endif()
message(STATUS "Generating ${install_pak_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}")
file(MAKE_DIRECTORY "${install_pak_output_folder}")
cmake_path(SET cache_product_path "@full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}")
+ # Copy the generated cmake_dependencies.*.setreg files for loading gems in non-monolithic to the cache
+ file(GLOB gem_source_paths_setreg "${runtime_output_directory_RELEASE}/Registry/*.setreg")
+ # The MergeSettingsToRegistry_TargetBuildDependencyRegistry function looks for lowercase "registry"
+ # So make sure the to copy it to a lowercase path, so that it works on non-case sensitive filesystems
+ file(MAKE_DIRECTORY "${cache_product_path}/registry")
+ file(COPY ${gem_source_paths_setreg} DESTINATION "${cache_product_path}/registry")
+
file(GLOB product_assets "${cache_product_path}/*")
- if(product_assets)
+ list(APPEND pak_artifacts ${product_assets})
+ if(pak_artifacts)
execute_process(
- COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_pak_output_folder}/engine.pak" --format=zip -- ${product_assets}
+ COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_pak_output_folder}/engine.pak" --format=zip -- ${pak_artifacts}
WORKING_DIRECTORY "${cache_product_path}"
RESULT_VARIABLE archive_creation_result
)