Resolve MP Gem Ctrl+G changes with main
This commit is contained in:
@@ -1 +0,0 @@
|
||||
*.xml
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzCore/Preprocessor/Enum.h>
|
||||
#include <AzCore/std/containers/bitset.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
@@ -216,16 +217,14 @@ namespace AZ
|
||||
/**
|
||||
* Setting for each reference (Asset<T>) to control loading of referenced assets during serialization.
|
||||
*/
|
||||
enum class AssetLoadBehavior : u8
|
||||
{
|
||||
PreLoad = 0, ///< Serializer will "Pre load" dependencies, asset containers may load in parallel but will not signal AssetReady
|
||||
QueueLoad = 1, ///< Serializer will queue an asynchronous load of the referenced asset and return the object to the user. User code should use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
NoLoad = 2, ///< Serializer will load reference information, but asset loading will be left to the user. User code should call Asset<T>::QueueLoad and use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
///< AssetContainers will skip NoLoad dependencies
|
||||
|
||||
AZ_ENUM_WITH_UNDERLYING_TYPE(AssetLoadBehavior, u8,
|
||||
(PreLoad, 0), ///< Serializer will "Pre load" dependencies, asset containers may load in parallel but will not signal AssetReady
|
||||
(QueueLoad, 1), ///< Serializer will queue an asynchronous load of the referenced asset and return the object to the user. User code should use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
(NoLoad, 2), ///< Serializer will load reference information, but asset loading will be left to the user. User code should call Asset<T>::QueueLoad and use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
///< AssetContainers will skip NoLoad dependencies
|
||||
Count,
|
||||
Default = QueueLoad,
|
||||
};
|
||||
(Default, QueueLoad)
|
||||
);
|
||||
|
||||
struct AssetFilterInfo
|
||||
{
|
||||
@@ -1235,6 +1234,7 @@ namespace AZ
|
||||
} // namespace ProductDependencyInfo
|
||||
} // namespace Data
|
||||
|
||||
AZ_TYPE_INFO_SPECIALIZE(Data::AssetLoadBehavior, "{DAF9ECED-FEF3-4D7A-A220-8CFD6A5E6DA1}");
|
||||
AZ_TYPE_INFO_TEMPLATE_WITH_NAME(AZ::Data::Asset, "Asset", "{C891BF19-B60C-45E2-BFD0-027D15DDC939}", AZ_TYPE_INFO_CLASS);
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -269,13 +269,13 @@ namespace AZ
|
||||
{
|
||||
for (auto& [assetId, dependentAsset] : m_dependencies)
|
||||
{
|
||||
if (dependentAsset->IsReady())
|
||||
if (dependentAsset->IsReady() || dependentAsset->IsError())
|
||||
{
|
||||
HandleReadyAsset(dependentAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto asset = m_rootAsset.GetStrongReference(); asset.IsReady())
|
||||
if (auto asset = m_rootAsset.GetStrongReference(); asset.IsReady() || asset.IsError())
|
||||
{
|
||||
HandleReadyAsset(asset);
|
||||
}
|
||||
@@ -496,10 +496,10 @@ namespace AZ
|
||||
m_waitingCount -= 1;
|
||||
disconnectEbus = true;
|
||||
|
||||
if (m_waitingAssets.empty())
|
||||
{
|
||||
allReady = true;
|
||||
}
|
||||
}
|
||||
if (m_waitingAssets.empty())
|
||||
{
|
||||
allReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,8 +510,15 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
if (allReady && m_initComplete)
|
||||
// If there are no assets left to be loaded, trigger the final AssetContainer notification (ready or canceled).
|
||||
// We guard against prematurely sending it (m_initComplete) because it's possible for assets to get removed from our waiting
|
||||
// list *while* we're still building up the list, so the list would appear to be empty too soon.
|
||||
// We also guard against sending it multiple times (m_finalNotificationSent), because in some error conditions, it may be
|
||||
// possible to try to remove the same asset multiple times, which if it's the last asset, it could trigger multiple
|
||||
// notifications.
|
||||
if (allReady && m_initComplete && !m_finalNotificationSent)
|
||||
{
|
||||
m_finalNotificationSent = true;
|
||||
if (m_rootAsset)
|
||||
{
|
||||
AssetManagerBus::Broadcast(&AssetManagerBus::Events::OnAssetContainerReady, this);
|
||||
|
||||
@@ -137,6 +137,7 @@ namespace AZ
|
||||
AZStd::atomic_int m_invalidDependencies{ 0 };
|
||||
AZStd::unordered_set<AZ::Data::AssetId> m_unloadedDependencies;
|
||||
AZStd::atomic_bool m_initComplete{ false };
|
||||
AZStd::atomic_bool m_finalNotificationSent{false};
|
||||
|
||||
mutable AZStd::recursive_mutex m_preloadMutex;
|
||||
// AssetId -> List of assets it is still waiting on
|
||||
|
||||
@@ -70,6 +70,17 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const AZ::Data::AssetLoadBehavior autoLoadBehavior = instance->GetAutoLoadBehavior();
|
||||
const AZ::Data::AssetLoadBehavior defaultAutoLoadBehavior = defaultInstance ?
|
||||
defaultInstance->GetAutoLoadBehavior() : AZ::Data::AssetLoadBehavior::Default;
|
||||
|
||||
result.Combine(
|
||||
ContinueStoringToJsonObjectField(outputValue, "loadBehavior",
|
||||
&autoLoadBehavior, &defaultAutoLoadBehavior,
|
||||
azrtti_typeid<Data::AssetLoadBehavior>(), context));
|
||||
}
|
||||
|
||||
{
|
||||
ScopedContextPath subPathHint(context, "m_assetHint");
|
||||
const AZStd::string* hint = &instance->GetHint();
|
||||
@@ -100,14 +111,28 @@ namespace AZ
|
||||
AssetId id;
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
|
||||
SerializedAssetTracker* assetTracker =
|
||||
context.GetMetadata().Find<SerializedAssetTracker>();
|
||||
|
||||
{
|
||||
Data::AssetLoadBehavior loadBehavior = instance->GetAutoLoadBehavior();
|
||||
|
||||
result =
|
||||
ContinueLoadingFromJsonObjectField(&loadBehavior,
|
||||
azrtti_typeid<Data::AssetLoadBehavior>(),
|
||||
inputValue, "loadBehavior", context);
|
||||
|
||||
instance->SetAutoLoadBehavior(loadBehavior);
|
||||
}
|
||||
|
||||
auto it = inputValue.FindMember("assetId");
|
||||
if (it != inputValue.MemberEnd())
|
||||
{
|
||||
ScopedContextPath subPath(context, "assetId");
|
||||
result = ContinueLoading(&id, azrtti_typeid<AssetId>(), it->value, context);
|
||||
result.Combine(ContinueLoading(&id, azrtti_typeid<AssetId>(), it->value, context));
|
||||
if (!id.m_guid.IsNull())
|
||||
{
|
||||
*instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), AssetLoadBehavior::NoLoad);
|
||||
*instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), instance->GetAutoLoadBehavior());
|
||||
|
||||
|
||||
result.Combine(context.Report(result, "Successfully created Asset<T> with id."));
|
||||
@@ -142,6 +167,11 @@ namespace AZ
|
||||
"The asset hint is missing for Asset<T>, so it will be left empty."));
|
||||
}
|
||||
|
||||
if (assetTracker)
|
||||
{
|
||||
assetTracker->AddAsset(*instance);
|
||||
}
|
||||
|
||||
bool success = result.GetOutcome() <= JSR::Outcomes::PartialSkip;
|
||||
bool defaulted = result.GetOutcome() == JSR::Outcomes::DefaultsUsed || result.GetOutcome() == JSR::Outcomes::PartialDefaults;
|
||||
AZStd::string_view message =
|
||||
@@ -150,5 +180,20 @@ namespace AZ
|
||||
"Not enough information was available to create an instance of Asset<T> or data was corrupted.";
|
||||
return context.Report(result, message);
|
||||
}
|
||||
|
||||
void SerializedAssetTracker::AddAsset(Asset<AssetData>& asset)
|
||||
{
|
||||
m_serializedAssets.emplace_back(asset);
|
||||
}
|
||||
|
||||
const AZStd::vector<Asset<AssetData>>& SerializedAssetTracker::GetTrackedAssets() const
|
||||
{
|
||||
return m_serializedAssets;
|
||||
}
|
||||
|
||||
AZStd::vector<Asset<AssetData>>& SerializedAssetTracker::GetTrackedAssets()
|
||||
{
|
||||
return m_serializedAssets;
|
||||
}
|
||||
} // namespace Data
|
||||
} // namespace AZ
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -37,5 +38,18 @@ namespace AZ
|
||||
private:
|
||||
JsonSerializationResult::Result LoadAsset(void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context);
|
||||
};
|
||||
|
||||
class SerializedAssetTracker final
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(SerializedAssetTracker, "{1E067091-8C0A-44B1-A455-6E97663F6963}");
|
||||
|
||||
void AddAsset(Asset<AssetData>& asset);
|
||||
AZStd::vector<Asset<AssetData>>& GetTrackedAssets();
|
||||
const AZStd::vector<Asset<AssetData>>& GetTrackedAssets() const;
|
||||
|
||||
private:
|
||||
AZStd::vector<Asset<AssetData>> m_serializedAssets;
|
||||
};
|
||||
} // namespace Data
|
||||
} // namespace AZ
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <AzCore/Asset/AssetJsonSerializer.h>
|
||||
#include <AzCore/Asset/AssetManagerComponent.h>
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Preprocessor/EnumReflectUtils.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
@@ -24,6 +24,11 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Data
|
||||
{
|
||||
AZ_ENUM_DEFINE_REFLECT_UTILITIES(AssetLoadBehavior);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AssetDatabaseComponent
|
||||
// [6/25/2012]
|
||||
@@ -99,6 +104,8 @@ namespace AZ
|
||||
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
AZ::Data::AssetLoadBehaviorReflect(*serializeContext);
|
||||
|
||||
serializeContext->RegisterGenericType<Data::Asset<Data::AssetData>>();
|
||||
|
||||
serializeContext->Class<AssetManagerComponent, AZ::Component>()
|
||||
|
||||
@@ -916,27 +916,49 @@ namespace AZ
|
||||
SetSettingsRegistrySpecializations(specializations);
|
||||
|
||||
AZStd::vector<char> scratchBuffer;
|
||||
// Retrieves the list gem module build targets that the active project depends on
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry,
|
||||
AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
|
||||
// In development builds apply the o3de registry and the command line to allow early overrides. This will
|
||||
// allow developers to override things like default paths or Asset Processor connection settings. Any additional
|
||||
// values will be replaced by later loads, so this step will happen again at the end of loading.
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
|
||||
// Project User Registry is merged after the command line here to allow make sure the any command line override of the project path
|
||||
// is used for merging the project's user registry
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry);
|
||||
#endif
|
||||
//! Retrieves the list gem targets that the project has load dependencies on
|
||||
//! This populates the /Amazon/Gems/<GemName>/SourcePaths array entries which is required
|
||||
//! by the MergeSettingsToRegistry_GemRegistry() function below to locate the gem's root folder
|
||||
//! and merge in the gem's registry files.
|
||||
//! But when running from a pre-built app from the O3DE SDK(Editor/AssetProcessor), the projects binary
|
||||
//! directory is needed in order to located the load dependency registry files
|
||||
//! That project binary folder is generated with the <ProjectRoot>/user/Registry when CMake is configured
|
||||
//! for the project
|
||||
//! Therefore the order of merging must be as follows
|
||||
//! 1. MergeSettingsToRegistry_ProjectUserRegistry - Populates the /Amazon/Project/Settings/Build/project_build_path
|
||||
//! which contains the path to the project binary directory
|
||||
//! 2. MergeSettingsToRegistry_TargetBuildDependencyRegistry - Loads the cmake_dependencies.<project_name>.<application_name>.setreg
|
||||
//! file from the locations in order of
|
||||
//! 1. <executable_directory>/Registry
|
||||
//! 2. <cache_root>/Registry
|
||||
//! 3. <project_build_path>/bin/$<CONFIG>/Registry
|
||||
//! 3. MergeSettingsToRegistry_GemRegistries - Merges the settings registry files from each gem's <GemRoot>/Registry directory
|
||||
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry,
|
||||
AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true);
|
||||
#endif
|
||||
// Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry);
|
||||
}
|
||||
|
||||
void ComponentApplication::SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations)
|
||||
@@ -1304,7 +1326,7 @@ namespace AZ
|
||||
// Add all auto loadable non-asset gems to the list of gem modules to load
|
||||
if (!moduleLoadData.m_autoLoad)
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
for (AZ::OSString& dynamicLibraryPath : moduleLoadData.m_dynamicLibraryPaths)
|
||||
{
|
||||
|
||||
@@ -24,9 +24,7 @@ namespace AZ
|
||||
AZ_TYPE_INFO_SPECIALIZE(AZStd::chrono::system_clock::time_point, "{5C48FD59-7267-405D-9C06-1EA31379FE82}");
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper that reflects a AZStd::chrono::system_clock::time_point to script.
|
||||
*/
|
||||
//! Wrapper that reflects a AZStd::chrono::system_clock::time_point to script.
|
||||
class ScriptTimePoint
|
||||
{
|
||||
public:
|
||||
@@ -38,33 +36,45 @@ namespace AZ
|
||||
explicit ScriptTimePoint(AZStd::chrono::system_clock::time_point timePoint)
|
||||
: m_timePoint(timePoint) {}
|
||||
|
||||
AZStd::string ToString() const
|
||||
{
|
||||
return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count());
|
||||
}
|
||||
//! Formats the time point in a string formatted as: "Time <seconds since epoch>".
|
||||
AZStd::string ToString() const;
|
||||
|
||||
const AZStd::chrono::system_clock::time_point& Get() { return m_timePoint; }
|
||||
//! Returns the time point.
|
||||
const AZStd::chrono::system_clock::time_point& Get() const;
|
||||
|
||||
// Returns the time point in seconds
|
||||
double GetSeconds() const
|
||||
{
|
||||
typedef AZStd::chrono::duration<double> double_seconds;
|
||||
return AZStd::chrono::duration_cast<double_seconds>(m_timePoint.time_since_epoch()).count();
|
||||
}
|
||||
//! Returns the time point in seconds
|
||||
double GetSeconds() const;
|
||||
|
||||
// Returns the time point in milliseconds
|
||||
double GetMilliseconds() const
|
||||
{
|
||||
typedef AZStd::chrono::duration<double, AZStd::milli> double_ms;
|
||||
return AZStd::chrono::duration_cast<double_ms>(m_timePoint.time_since_epoch()).count();
|
||||
}
|
||||
//! Returns the time point in milliseconds
|
||||
double GetMilliseconds() const;
|
||||
|
||||
static void Reflect(ReflectContext* reflection);
|
||||
|
||||
protected:
|
||||
|
||||
AZStd::chrono::system_clock::time_point m_timePoint;
|
||||
};
|
||||
|
||||
inline AZStd::string ScriptTimePoint::ToString() const
|
||||
{
|
||||
return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count());
|
||||
}
|
||||
|
||||
inline const AZStd::chrono::system_clock::time_point& ScriptTimePoint::Get() const
|
||||
{
|
||||
return m_timePoint;
|
||||
}
|
||||
|
||||
inline double ScriptTimePoint::GetSeconds() const
|
||||
{
|
||||
typedef AZStd::chrono::duration<double> double_seconds;
|
||||
return AZStd::chrono::duration_cast<double_seconds>(m_timePoint.time_since_epoch()).count();
|
||||
}
|
||||
|
||||
inline double ScriptTimePoint::GetMilliseconds() const
|
||||
{
|
||||
typedef AZStd::chrono::duration<double, AZStd::milli> double_ms;
|
||||
return AZStd::chrono::duration_cast<double_ms>(m_timePoint.time_since_epoch()).count();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
|
||||
@@ -599,6 +599,34 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
? devWriteStorage.value()
|
||||
: projectUserPath.Native());
|
||||
|
||||
// Set the project in-memory build path if the ProjectBuildPath key has been supplied
|
||||
if (AZ::IO::FixedMaxPath projectBuildPath; registry.Get(projectBuildPath.Native(), ProjectBuildPath))
|
||||
{
|
||||
registry.Remove(FilePathKey_ProjectBuildPath);
|
||||
registry.Remove(FilePathKey_ProjectConfigurationBinPath);
|
||||
AZ::IO::FixedMaxPath buildConfigurationPath = normalizedProjectPath / projectBuildPath;
|
||||
if (IO::SystemFile::Exists(buildConfigurationPath.c_str()))
|
||||
{
|
||||
registry.Set(FilePathKey_ProjectBuildPath, buildConfigurationPath.LexicallyNormal().Native());
|
||||
}
|
||||
|
||||
// Add the specific build configuration paths to the Settings Registry
|
||||
// First try <project-build-path>/bin/$<CONFIG> and if that path doesn't exist
|
||||
// try <project-build-path>/bin/$<PLATFORM>/$<CONFIG>
|
||||
buildConfigurationPath /= "bin";
|
||||
if (IO::SystemFile::Exists((buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).c_str()))
|
||||
{
|
||||
registry.Set(FilePathKey_ProjectConfigurationBinPath,
|
||||
(buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native());
|
||||
}
|
||||
else if (IO::SystemFile::Exists((buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).c_str()))
|
||||
{
|
||||
registry.Set(FilePathKey_ProjectConfigurationBinPath,
|
||||
(buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name.
|
||||
auto projectNameKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
|
||||
@@ -689,6 +717,14 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
mergePath /= SettingsRegistryInterface::RegistryFolder;
|
||||
registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer);
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath projectBinPath;
|
||||
if (registry.Get(projectBinPath.Native(), FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
// Append the project build path path to the project root
|
||||
projectBinPath /= SettingsRegistryInterface::RegistryFolder;
|
||||
registry.MergeSettingsFolder(projectBinPath.Native(), specializations, platform, "", scratchBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void MergeSettingsToRegistry_EngineRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
@@ -934,7 +970,8 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
"project-path", AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)},
|
||||
OptionKeyToRegsetKey{
|
||||
"project-cache-path",
|
||||
AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}};
|
||||
AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)},
|
||||
OptionKeyToRegsetKey{"project-build-path", ProjectBuildPath} };
|
||||
|
||||
AZStd::fixed_vector<AZStd::string, commandOptions.size()> overrideArgs;
|
||||
|
||||
|
||||
@@ -52,6 +52,14 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
//! project settings can be stored
|
||||
inline static constexpr char FilePathKey_ProjectUserPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectUserPath";
|
||||
|
||||
//! User facing key which represents the root of a project cmake build tree. i.e the ${CMAKE_BINARY_DIR}
|
||||
//! A relative path is taking relative to the *project* root, NOT *engine* root.
|
||||
inline constexpr AZStd::string_view ProjectBuildPath = "/Amazon/Project/Settings/Build/project_build_path";
|
||||
//! In-Memory only key which stores an absolute path to the project build directory
|
||||
inline constexpr AZStd::string_view FilePathKey_ProjectBuildPath = "/Amazon/AzCore/Runtime/FilePaths/ProjectBuildPath";
|
||||
//! In-Memory only key which stores the configuration directory containing the built binaries
|
||||
inline constexpr AZStd::string_view FilePathKey_ProjectConfigurationBinPath = "/Amazon/AzCore/Runtime/FilePaths/ProjectConfigurationBinPath";
|
||||
|
||||
//! Development write storage path may be considered temporary or cache storage on some platforms
|
||||
inline static constexpr char FilePathKey_DevWriteStorage[] = "/Amazon/AzCore/Runtime/FilePaths/DevWriteStorage";
|
||||
|
||||
@@ -128,7 +136,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
//! Callback function that is after a has been filtered through the CommentPrefixFunc
|
||||
//! to determine if the text matches a section header
|
||||
//! returns a view of the section name if the line contains a section
|
||||
//! Otherwise an empty view is returend
|
||||
//! Otherwise an empty view is returned
|
||||
using SectionHeaderFunc = AZStd::function<AZStd::string_view(AZStd::string_view line)>;
|
||||
|
||||
//! Root JSON pointer path to place all key=values pairs of configuration data within
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -17,4 +17,15 @@
|
||||
namespace AZStd
|
||||
{
|
||||
using std::abs;
|
||||
}
|
||||
using std::acos;
|
||||
using std::asin;
|
||||
using std::atan;
|
||||
using std::atan2;
|
||||
using std::cos;
|
||||
using std::exp2;
|
||||
using std::fmod;
|
||||
using std::round;
|
||||
using std::sin;
|
||||
using std::sqrt;
|
||||
using std::tan;
|
||||
} // namespace AZStd
|
||||
|
||||
+4
-4
@@ -17,8 +17,9 @@ namespace AZ
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void GetModulePath(AZ::OSString& path)
|
||||
AZ::IO::FixedMaxPath GetModulePath()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void* OpenModule(const AZ::OSString& fileName, bool&)
|
||||
@@ -26,10 +27,9 @@ namespace AZ
|
||||
// Android 19 does not have RTLD_NOLOAD but it should be OK since only the Editor expects to reopen modules
|
||||
return dlopen(fileName.c_str(), RTLD_NOW);
|
||||
}
|
||||
|
||||
void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath)
|
||||
|
||||
void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&)
|
||||
{
|
||||
fullPath = path + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-12
@@ -10,7 +10,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
|
||||
#include <AzCore/std/string/osstring.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -19,15 +18,9 @@ namespace AZ
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void GetModulePath(AZ::OSString& path)
|
||||
AZ::IO::FixedMaxPath GetModulePath()
|
||||
{
|
||||
char exePath[AZ_MAX_PATH_LEN];
|
||||
if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) ==
|
||||
AZ::Utils::ExecutablePathResult::Success)
|
||||
{
|
||||
path = exePath;
|
||||
path.push_back('/');
|
||||
}
|
||||
return AZ::Utils::GetExecutableDirectory();
|
||||
}
|
||||
|
||||
void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen)
|
||||
@@ -40,10 +33,9 @@ namespace AZ
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath)
|
||||
|
||||
void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&)
|
||||
{
|
||||
fullPath = path + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+47
-30
@@ -11,9 +11,11 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <dlfcn.h>
|
||||
#include <libgen.h>
|
||||
|
||||
@@ -21,9 +23,9 @@ namespace AZ
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void GetModulePath(AZ::OSString& path);
|
||||
AZ::IO::FixedMaxPath GetModulePath();
|
||||
void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen);
|
||||
void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath);
|
||||
void ConstructModuleFullFileName(AZ::IO::FixedMaxPath& fullPath);
|
||||
}
|
||||
|
||||
class DynamicModuleHandleUnixLike
|
||||
@@ -36,40 +38,55 @@ namespace AZ
|
||||
: DynamicModuleHandle(fullFileName)
|
||||
, m_handle(nullptr)
|
||||
{
|
||||
AZ::OSString path;
|
||||
AZ::OSString fileName;
|
||||
AZ::OSString fullPath = "";
|
||||
AZ::OSString::size_type finalSlash = m_fileName.find_last_of("/");
|
||||
if (finalSlash != AZ::OSString::npos)
|
||||
AZ::IO::FixedMaxPath fullFilePath(AZStd::string_view{m_fileName});
|
||||
if (fullFilePath.HasFilename())
|
||||
{
|
||||
// Path up to and including final slash
|
||||
path = m_fileName.substr(0, finalSlash + 1);
|
||||
// Everything after the final slash
|
||||
// If m_fileName ends in /, the end result is path/lib.dylib, which just fails to load.
|
||||
fileName = m_fileName.substr(finalSlash + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no slash found, assume empty path, only file name
|
||||
path = "";
|
||||
Platform::GetModulePath(path);
|
||||
fileName = m_fileName;
|
||||
AZ::IO::FixedMaxPathString fileNamePath{fullFilePath.Filename().Native()};
|
||||
if (!fileNamePath.starts_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX))
|
||||
{
|
||||
fileNamePath = AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX + fileNamePath;
|
||||
}
|
||||
|
||||
if (!fileNamePath.ends_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION))
|
||||
{
|
||||
fileNamePath += AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION;
|
||||
}
|
||||
|
||||
fullFilePath.ReplaceFilename(AZStd::string_view(fileNamePath));
|
||||
}
|
||||
|
||||
if (fileName.substr(0, 3) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX)
|
||||
Platform::ConstructModuleFullFileName(fullFilePath);
|
||||
|
||||
// Check if the module exist at the given path within the current working directory
|
||||
// If it doesn't attempt to append the path to the executable path
|
||||
if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str()))
|
||||
{
|
||||
fileName = AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX + fileName;
|
||||
auto candidatePath = Platform::GetModulePath() / fullFilePath;
|
||||
if (AZ::IO::SystemFile::Exists(candidatePath.c_str()))
|
||||
{
|
||||
fullFilePath = candidatePath;
|
||||
}
|
||||
}
|
||||
|
||||
size_t extensionLen = strlen(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION);
|
||||
if (fileName.substr(fileName.length() - extensionLen, extensionLen) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION)
|
||||
// If the path still doesn't exist at this point, check the SettingsRegistryMergeUtils
|
||||
// FilePathKey_ProjectBuildPath key to see if a project-build-path argument has been supplied
|
||||
if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str()))
|
||||
{
|
||||
fileName = fileName + AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if(AZ::IO::FixedMaxPath projectModulePath;
|
||||
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
projectModulePath /= fullFilePath;
|
||||
if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
|
||||
{
|
||||
fullFilePath = projectModulePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Platform::ConstructModuleFullFileName(path, fileName, fullPath);
|
||||
|
||||
m_fileName = fullPath;
|
||||
m_fileName = AZStd::string_view{fullFilePath.Native()};
|
||||
}
|
||||
|
||||
~DynamicModuleHandleUnixLike() override
|
||||
@@ -81,9 +98,9 @@ namespace AZ
|
||||
{
|
||||
AZ::Debug::Trace::Printf("Module", "Attempting to load module:%s\n", m_fileName.c_str());
|
||||
bool alreadyOpen = false;
|
||||
|
||||
|
||||
m_handle = Platform::OpenModule(m_fileName, alreadyOpen);
|
||||
|
||||
|
||||
if(m_handle)
|
||||
{
|
||||
if (alreadyOpen)
|
||||
|
||||
+25
-3
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -31,13 +32,13 @@ namespace AZ
|
||||
{
|
||||
// Ensure filename ends in ".dll"
|
||||
// Otherwise filenames like "gem.1.0.0" fail to load (.0 is assumed to be the extension).
|
||||
if (m_fileName.substr(m_fileName.length() - 4) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION)
|
||||
if (!m_fileName.ends_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION))
|
||||
{
|
||||
m_fileName = m_fileName + AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION;
|
||||
m_fileName += AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION;
|
||||
}
|
||||
|
||||
AZ::IO::PathView modulePathView{ m_fileName };
|
||||
// If the module path doesn't have a directory within it, prepend it to the path
|
||||
// If the module path doesn't have a directory within it, prepend the executable directory to the path
|
||||
// and check if the new path exist
|
||||
if (modulePathView.HasFilename() && !modulePathView.HasParentPath())
|
||||
{
|
||||
@@ -54,6 +55,27 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the module file path does not exist, attempt to search for the module within
|
||||
// the project's build directory
|
||||
if (!AZ::IO::SystemFile::Exists(m_fileName.c_str()))
|
||||
{
|
||||
// The Settings Registry may not exist in early startup if modules are loaded
|
||||
// before the ComponentApplication is crated(such as in the Editor main.cpp)
|
||||
// Therefore an existence check is needed
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if(AZ::IO::FixedMaxPath projectModulePath;
|
||||
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
projectModulePath /= AZStd::string_view(m_fileName);
|
||||
if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
|
||||
{
|
||||
m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~DynamicModuleHandleWindows() override
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
|
||||
#include <AzCore/std/string/osstring.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -19,15 +18,9 @@ namespace AZ
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void GetModulePath(AZ::OSString& path)
|
||||
AZ::IO::FixedMaxPath GetModulePath()
|
||||
{
|
||||
char exePath[AZ_MAX_PATH_LEN];
|
||||
if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) ==
|
||||
AZ::Utils::ExecutablePathResult::Success)
|
||||
{
|
||||
path = exePath;
|
||||
path.push_back('/');
|
||||
}
|
||||
return AZ::Utils::GetExecutableDirectory();
|
||||
}
|
||||
|
||||
void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen)
|
||||
@@ -40,10 +33,9 @@ namespace AZ
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath)
|
||||
|
||||
void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&)
|
||||
{
|
||||
fullPath = path + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
|
||||
#include <AzCore/std/string/osstring.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -19,15 +18,9 @@ namespace AZ
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
void GetModulePath(AZ::OSString& path)
|
||||
AZ::IO::FixedMaxPath GetModulePath()
|
||||
{
|
||||
char exePath[AZ_MAX_PATH_LEN];
|
||||
if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) ==
|
||||
AZ::Utils::ExecutablePathResult::Success)
|
||||
{
|
||||
AZ::OSString frameworks = "/Frameworks/";
|
||||
path = exePath + frameworks;
|
||||
}
|
||||
return AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "Frameworks";
|
||||
}
|
||||
|
||||
void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen)
|
||||
@@ -40,10 +33,15 @@ namespace AZ
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath)
|
||||
|
||||
void ConstructModuleFullFileName(AZ::IO::FixedMaxPath& fullPath)
|
||||
{
|
||||
fullPath = path + fileName + ".framework/" + fileName;
|
||||
// Append .framework to the name of full path
|
||||
// Afterwards use the AZ::IO::Path Append function append the filename as a child
|
||||
// of the framework directory
|
||||
AZ::IO::FixedMaxPathString fileName = fullPath.Filename().Native();
|
||||
fullPath.ReplaceFilename(fileName + ".framework");
|
||||
fullPath /= fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,11 +1042,7 @@ namespace UnitTest
|
||||
|
||||
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerCoreTest_BasicDependencyManagement_Success)
|
||||
#else
|
||||
TEST_F(AssetJobsFloodTest, ContainerCoreTest_BasicDependencyManagement_Success)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
{
|
||||
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
|
||||
// Setup has already created/destroyed assets
|
||||
|
||||
@@ -351,6 +351,7 @@ namespace UnitTest
|
||||
public AZ::Data::AssetCatalog
|
||||
{
|
||||
static inline const AZ::Uuid TestAssetId{"{E970B177-5F45-44EB-A2C4-9F29D9A0B2A2}"};
|
||||
static inline const AZ::Uuid MissingAssetId{"{11111111-1111-1111-1111-111111111111}"};
|
||||
static inline constexpr AZStd::string_view TestAssetPath = "test";
|
||||
|
||||
void SetUp() override
|
||||
@@ -431,24 +432,40 @@ namespace UnitTest
|
||||
// AssetCatalogRequestBus implementation
|
||||
|
||||
// Minimalist mocks to provide our desired asset path or asset id
|
||||
AZStd::string GetAssetPathById([[maybe_unused]] const AZ::Data::AssetId& id) override
|
||||
AZStd::string GetAssetPathById(const AZ::Data::AssetId& id) override
|
||||
{
|
||||
return TestAssetPath;
|
||||
if (id == TestAssetId)
|
||||
{
|
||||
return TestAssetPath;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
AZ::Data::AssetId GetAssetIdByPath(
|
||||
[[maybe_unused]] const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister,
|
||||
const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister,
|
||||
[[maybe_unused]] bool autoRegisterIfNotFound) override
|
||||
{
|
||||
return TestAssetId;
|
||||
if (path == TestAssetPath)
|
||||
{
|
||||
return TestAssetId;
|
||||
}
|
||||
|
||||
return AZ::Data::AssetId();
|
||||
}
|
||||
|
||||
// Return the mocked-out information for our test asset
|
||||
AZ::Data::AssetInfo GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& id) override
|
||||
AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override
|
||||
{
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
assetInfo.m_assetId = TestAssetId;
|
||||
assetInfo.m_assetType = AZ::AzTypeInfo<EmptyAsset>::Uuid();
|
||||
assetInfo.m_relativePath = TestAssetPath;
|
||||
|
||||
if (id == TestAssetId)
|
||||
{
|
||||
assetInfo.m_assetId = TestAssetId;
|
||||
assetInfo.m_assetType = AZ::AzTypeInfo<EmptyAsset>::Uuid();
|
||||
assetInfo.m_relativePath = TestAssetPath;
|
||||
}
|
||||
|
||||
return assetInfo;
|
||||
}
|
||||
|
||||
@@ -456,15 +473,20 @@ namespace UnitTest
|
||||
|
||||
// Set the mocked-out asset load to have a 0-byte length so that the load skips I/O and immediately returns success
|
||||
AZ::Data::AssetStreamInfo GetStreamInfoForLoad(
|
||||
[[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override
|
||||
const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override
|
||||
{
|
||||
EXPECT_TRUE(type == AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
AZ::Data::AssetStreamInfo info;
|
||||
|
||||
info.m_dataOffset = 0;
|
||||
info.m_streamName = TestAssetPath;
|
||||
info.m_dataLen = 0;
|
||||
info.m_streamFlags = AZ::IO::OpenMode::ModeRead;
|
||||
|
||||
if (id == TestAssetId)
|
||||
{
|
||||
info.m_streamName = TestAssetPath;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -489,4 +511,27 @@ namespace UnitTest
|
||||
EXPECT_TRUE(testAsset.IsReady());
|
||||
}
|
||||
|
||||
// This test verifies that even if the asset loading returns immediately with an error, all of the loading code works
|
||||
// successfully. The test itself loads a missing asset twice - the first time is a non-immediate error, where the error
|
||||
// isn't reported until the DispatchEvents() call. The second time is an immediate error, because now the asset is already
|
||||
// registered in an Error state. If the test fails, it will likely get caught in the shutdown of the test class, if any
|
||||
// assets still exist at the point that the asset handler is unregistered. If they're present, then handling of the immediate
|
||||
// error didn't work, as it left around extra references to the asset that haven't been cleaned up.
|
||||
TEST_F(AssetManagerStreamerImmediateCompletionTests, ImmediateAssetError_WorksSuccessfully)
|
||||
{
|
||||
AZ::Data::AssetLoadParameters loadParams;
|
||||
|
||||
// Attempt to load a missing asset the first time. It will get an error, but not until the DispatchEvents() call happens.
|
||||
auto testAsset1 = AssetManager::Instance().GetAsset<EmptyAsset>(MissingAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams);
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
EXPECT_TRUE(testAsset1.IsError());
|
||||
|
||||
// While the reference to the missing asset still exists, try to get it again. This will cause a more immediate error in
|
||||
// the AssetContainer code, which should still get handled correctly. In the failure condition, it will instead leave the
|
||||
// AssetContainer in a state where it never sends the final OnAssetContainerReady/Canceled message.
|
||||
auto testAsset2 = AssetManager::Instance().GetAsset<EmptyAsset>(MissingAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams);
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
EXPECT_TRUE(testAsset2.IsError());
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -135,6 +135,7 @@ namespace JsonSerializationTests
|
||||
auto instance = AZStd::make_shared<Asset>();
|
||||
instance->Create(id, false);
|
||||
instance->SetHint("TestFile");
|
||||
instance->SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -158,6 +159,7 @@ namespace JsonSerializationTests
|
||||
"guid": "{BBEAC89F-8BAD-4A9D-BF6E-D0DF84A8DFD6}",
|
||||
"subId": 1
|
||||
},
|
||||
"loadBehavior": "PreLoad",
|
||||
"assetHint": "TestFile"
|
||||
})";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user