From 36c4e827bd1ef2cadc25b3f0fc18b68782c97be9 Mon Sep 17 00:00:00 2001 From: alexpete Date: Fri, 26 Mar 2021 14:31:50 -0700 Subject: [PATCH 1/2] Integrating latest from github/staging Integrating up through commit 5e1bdae --- .p4ignore | 30 - AssetProcessorPlatformConfig.ini | 590 ------- ...reg => AssetProcessorPlatformConfig.setreg | 239 ++- AutomatedReview/Jenkinsfile | 111 +- AutomatedTesting/CMakeLists.txt | 8 + AutomatedTesting/Config/Editor.xml | 197 --- AutomatedTesting/Config/Game.xml | 179 -- AutomatedTesting/Config/Server.xml | 136 -- .../Gem/AssetProcessorGemConfig.ini | 16 - .../Gem/AssetProcessorGemConfig.setreg | 23 + .../Gem/PythonTests/CMakeLists.txt | 40 +- .../ap_all_platforms_setup_fixture.py | 12 +- .../ap_external_project_setup_fixture.py | 2 +- .../asset_processor_batch_tests_2.py | 5 +- .../asset_processor_gui_tests_2.py | 34 +- .../missing_dependency_tests.py | 2 +- .../assetpipeline/fbx_tests/fbx_tests.py | 4 +- .../automatedtesting_shared/base.py | 5 +- .../PythonTests/scripting/TestSuite_Active.py | 10 +- .../scripting/TestSuite_Sandbox.py | 30 + .../Registry/assets_scan_folders.setreg | 42 +- .../TestAssets/test_chunks_builder.py | 5 +- .../UI/TextureAtlas/sample.texatlas | 2 +- AutomatedTesting/gems.json | 298 ---- BuildReleaseAuxiliaryContent.py | 4 +- CMakeLists.txt | 27 +- Code/CryEngine/Cry3DEngine/3DEngineRender.cpp | 2 +- Code/CryEngine/Cry3DEngine/3dEngine.cpp | 2 +- Code/CryEngine/Cry3DEngine/3dEngineLoad.cpp | 14 +- Code/CryEngine/Cry3DEngine/LightEntity.cpp | 3 +- Code/CryEngine/Cry3DEngine/Material.cpp | 15 +- Code/CryEngine/Cry3DEngine/Material.h | 15 +- Code/CryEngine/Cry3DEngine/StatObj.h | 10 +- Code/CryEngine/Cry3DEngine/StatObjConstr.cpp | 4 - Code/CryEngine/CryCommon/IAudioSystem.h | 2 +- Code/CryEngine/CryCommon/IMaterial.h | 7 +- Code/CryEngine/CryCommon/ISystem.h | 196 +-- Code/CryEngine/CryCommon/MaterialUtils.h | 15 +- Code/CryEngine/CryCommon/Mocks/ISystemMock.h | 18 - Code/CryEngine/CryCommon/ParseEngineConfig.h | 160 -- Code/CryEngine/CryCommon/ProjectDefines.h | 2 +- .../CryEngine/CryCommon/crycommon_files.cmake | 1 - Code/CryEngine/CrySystem/BootProfiler.cpp | 630 ------- Code/CryEngine/CrySystem/BootProfiler.h | 67 - Code/CryEngine/CrySystem/DebugCallStack.cpp | 13 +- Code/CryEngine/CrySystem/IDebugCallStack.cpp | 18 +- Code/CryEngine/CrySystem/LoadingProfiler.cpp | 647 -------- Code/CryEngine/CrySystem/LoadingProfiler.h | 69 - .../CrySystem/NotificationNetwork.cpp | 10 +- .../CrySystem/StreamEngine/StreamEngine.cpp | 2 +- Code/CryEngine/CrySystem/System.cpp | 40 +- Code/CryEngine/CrySystem/System.h | 36 +- Code/CryEngine/CrySystem/SystemCFG.cpp | 12 +- Code/CryEngine/CrySystem/SystemInit.cpp | 341 +--- Code/CryEngine/CrySystem/SystemWin32.cpp | 15 - .../CrySystem/Tests/Test_BootProfiler.cpp | 115 -- .../CrySystem/Tests/test_MaterialUtils.cpp | 15 +- .../CrySystem/UnitTests/CryPakUnitTests.cpp | 4 +- Code/CryEngine/CrySystem/VisRegTest.cpp | 4 +- .../CryEngine/CrySystem/crysystem_files.cmake | 4 - Code/CryEngine/RenderDll/Common/Renderer.cpp | 4 +- .../Common/Shaders/RemoteCompiler.cpp | 22 +- .../Shaders/RemoteShaderCompilerUnitTests.cpp | 131 +- .../RenderDll/Common/Shaders/ShaderCache.cpp | 7 +- .../RenderDll/Common/Shaders/ShaderCore.cpp | 2 +- .../Common/Shaders/ShaderSerialize.cpp | 2 +- .../XRenderD3D9/D3DHWShaderCompiling.cpp | 4 +- .../RenderDll/XRenderD3D9/D3DSystem.cpp | 5 +- .../AzCore/Component/ComponentApplication.cpp | 326 ++-- .../AzCore/Component/ComponentApplication.h | 66 +- .../Component/ComponentApplicationBus.h | 5 + .../AzCore/AzCore/Console/Console.cpp | 6 +- Code/Framework/AzCore/AzCore/IO/FileIO.h | 39 +- Code/Framework/AzCore/AzCore/IO/Path/Path.h | 8 +- Code/Framework/AzCore/AzCore/IO/Path/Path.inl | 6 +- .../AzCore/AzCore/Math/MathReflection.cpp | 1 + .../AzCore/Math/MathVectorSerializer.cpp | 53 + .../AzCore/AzCore/Math/MathVectorSerializer.h | 12 + .../AzCore/AzCore/Settings/CommandLine.cpp | 308 ++-- .../AzCore/AzCore/Settings/CommandLine.h | 51 +- .../AzCore/Settings/SettingsRegistryImpl.cpp | 10 +- .../Settings/SettingsRegistryMergeUtils.cpp | 629 ++++--- .../Settings/SettingsRegistryMergeUtils.h | 83 +- .../AzCore/AzCore/StringFunc/StringFunc.cpp | 80 +- .../AzCore/AzCore/StringFunc/StringFunc.h | 51 +- .../UnitTest/MockComponentApplication.h | 1 + .../AzCore/UnitTest/Mocks/MockFileIOBase.h | 1 + Code/Framework/AzCore/AzCore/Utils/Utils.cpp | 43 + Code/Framework/AzCore/AzCore/Utils/Utils.h | 21 +- .../AzCore/AzCore/std/string/fixed_string.h | 5 + .../AzCore/AzCore/std/string/fixed_string.inl | 17 + .../AzCore/AzCore/std/string/string.h | 16 + .../AzCore/AzCore/std/string/string_view.h | 16 + .../Android/AzCore/Utils/Utils_Android.cpp | 10 +- .../Android/platform_android_files.cmake | 1 + .../AzCore/Utils/Utils_Unimplemented.cpp | 22 + .../UnixLike/AzCore/Utils/Utils_UnixLike.cpp | 23 +- .../WinAPI/AzCore/Utils/Utils_WinAPI.cpp | 8 +- .../Linux/AzCore/Utils/Utils_Linux.cpp | 2 +- .../Platform/Mac/AzCore/Utils/Utils_Mac.cpp | 2 +- .../StreamerConfiguration_Windows.cpp | 2 +- .../Windows/AzCore/Utils/Utils_Windows.cpp | 26 +- .../Platform/iOS/AzCore/Utils/Utils_iOS.mm | 4 +- .../Platform/iOS/platform_ios_files.cmake | 1 + Code/Framework/AzCore/Tests/AZStd/String.cpp | 21 + .../AzCore/Tests/BehaviorContextFixture.h | 3 +- .../AzCore/Tests/FileIOBaseTestTypes.h | 5 + .../Android/Tests/UtilsTests_Android.cpp | 10 +- .../UnixLike/Tests/UtilsTests_UnixLike.cpp | 6 +- .../Common/WinAPI/Tests/UtilsTests_WinAPI.cpp | 10 +- Code/Framework/AzCore/Tests/Serialization.cpp | 3 +- .../Json/MathVectorSerializerTests.cpp | 8 + .../Tests/Settings/CommandLineTests.cpp | 18 +- .../Tests/SettingsRegistryMergeUtilsTests.cpp | 199 +-- .../AzCore/Tests/SettingsRegistryTests.cpp | 64 +- Code/Framework/AzCore/Tests/StringFunc.cpp | 29 + .../AzFramework/API/ApplicationAPI.h | 10 +- .../AzFramework/Application/Application.cpp | 207 ++- .../AzFramework/Application/Application.h | 8 +- .../AzFramework/Archive/Archive.cpp | 3 +- .../AzFramework/Archive/ArchiveFileIO.cpp | 10 + .../AzFramework/Archive/ArchiveFileIO.h | 1 + .../AzFramework/Asset/AssetCatalog.cpp | 6 +- .../AzFramework/Asset/AssetSystemBus.h | 2 +- .../AzFramework/Asset/AssetSystemComponent.h | 1 - .../Asset/AssetSystemComponentHelper.cpp | 39 +- .../AzFramework/FileTag/FileTag.cpp | 6 +- .../AzFramework/AzFramework/Gem/GemInfo.cpp | 95 ++ .../AzFramework/AzFramework/Gem/GemInfo.h | 41 + .../AzFramework/IO/LocalFileIO.cpp | 53 +- .../AzFramework/AzFramework/IO/LocalFileIO.h | 1 + .../AzFramework/IO/RemoteFileIO.cpp | 14 + .../AzFramework/AzFramework/IO/RemoteFileIO.h | 2 + .../AzFramework/Logging/LogFile.cpp | 5 +- .../AzFramework}/Process/ProcessCommon_fwd.h | 4 +- .../Process/ProcessCommunicator.cpp | 7 +- .../Process/ProcessCommunicator.h | 31 +- .../AzFramework}/Process/ProcessWatcher.cpp | 12 +- .../AzFramework}/Process/ProcessWatcher.h | 10 +- .../ProjectManager/ProjectManager.cpp | 250 +-- .../ProjectManager/ProjectManager.h | 2 +- .../Spawnable/SpawnableSystemComponent.cpp | 3 +- .../AzFramework/azframework_files.cmake | 7 + .../AzFramework/AzFramework_Traits_Android.h | 3 + .../AzFramework/Process/ProcessCommon.h | 51 + .../Process/ProcessCommunicator_Android.cpp | 50 + .../Process/ProcessWatcher_Android.cpp | 90 + .../ProjectManager/ProjectManager_Android.cpp | 27 - .../Android/platform_android_files.cmake | 4 +- .../Process/ProcessCommon_Default.h | 53 + .../Process/ProcessCommunicator_Default.cpp | 51 + .../Process/ProcessWatcher_Default.cpp | 90 + .../ProjectManager/ProjectManager_Default.cpp | 28 - .../AssetSystemComponentHelper_Linux.cpp | 29 +- .../AzFramework/AzFramework_Traits_Linux.h | 3 + .../AzFramework/Process/ProcessCommon.h} | 4 +- .../Process}/ProcessCommunicator_Linux.cpp | 7 +- .../Process}/ProcessWatcher_Linux.cpp | 9 +- .../ProjectManager/ProjectManager_Linux.cpp | 27 - .../Platform/Linux/platform_linux_files.cmake | 4 +- .../Asset/AssetSystemComponentHelper_Mac.cpp | 20 +- .../Mac/AzFramework/AzFramework_Traits_Mac.h | 3 + .../Mac/AzFramework/Process/ProcessCommon.h} | 6 +- .../Process/ProcessCommunicator_Mac.cpp} | 8 +- .../Process/ProcessWatcher_Mac.cpp} | 9 +- .../ProjectManager/ProjectManager_Mac.cpp | 27 - .../Platform/Mac/platform_mac_files.cmake | 4 +- .../AssetSystemComponentHelper_Windows.cpp | 21 +- .../AzFramework/AzFramework_Traits_Windows.h | 3 + .../AzFramework/Process/ProcessCommon.h} | 2 +- .../Process}/ProcessCommunicator_Win.cpp | 5 +- .../Process}/ProcessWatcher_Win.cpp | 16 +- .../ProjectManager/ProjectManager_Windows.cpp | 77 - .../Windows/platform_windows_files.cmake | 4 +- .../iOS/AzFramework/AzFramework_Traits_iOS.h | 3 + .../iOS/AzFramework/Process/ProcessCommon.h | 51 + .../Process/ProcessCommunicator_iOS.cpp | 50 + .../Process/ProcessWatcher_iOS.cpp | 90 + .../ProjectManager/ProjectManager_iOS.cpp | 28 - .../Platform/iOS/platform_ios_files.cmake | 4 +- .../Application/GameApplication.cpp | 4 +- .../Components/StyleManager.cpp | 16 +- .../AzQtComponents/Components/StyleManager.h | 13 +- .../Components/StyleSheetCache.cpp | 7 +- .../Components/StyleSheetCache.h | 5 +- .../AzQtComponents/Gallery/StyleSheetPage.cpp | 10 +- .../AzQtComponents/Gallery/main.cpp | 9 +- .../PropertyEditorStandalone/main.cpp | 13 +- .../AzQtComponents/StyleGallery/main.cpp | 15 +- .../Utilities/QtPluginPaths.cpp | 25 - .../AzQtComponents/Utilities/QtPluginPaths.h | 4 - Code/Framework/AzTest/AzTest/Utils.cpp | 22 +- .../Application/ToolsApplication.cpp | 12 +- .../Archive/ArchiveComponent.cpp | 12 +- .../AzToolsFramework/Asset/AssetUtils.cpp | 583 +++---- .../AzToolsFramework/Asset/AssetUtils.h | 94 +- .../PlatformAddressedAssetCatalog.cpp | 41 +- .../SourceControl/PerforceComponent.cpp | 6 +- .../SourceControl/PerforceConnection.cpp | 24 +- .../SourceControl/PerforceConnection.h | 13 +- .../Core/EditorFrameworkApplication.cpp | 12 - .../UI/Outliner/EntityOutlinerWidget.cpp | 12 +- .../aztoolsframework_files.cmake | 5 - .../aztoolsframework_linux_files.cmake | 3 - .../aztoolsframework_mac_files.cmake | 3 - .../aztoolsframework_win_files.cmake | 3 - .../aztoolsframework_windows_files.cmake | 3 - .../Archive/ArchiveComponent_Windows.cpp | 2 +- .../Tests/AssetSeedManager.cpp | 3 +- .../Framework/AzToolsFramework/Tests/Main.cpp | 11 +- Code/Framework/Tests/Application.cpp | 29 +- .../Tests/ArchiveCompressionTests.cpp | 8 +- Code/Framework/Tests/ArchiveTests.cpp | 36 +- Code/Framework/Tests/AssetCatalog.cpp | 1 - Code/Framework/Tests/ComponentAddRemove.cpp | 3 +- Code/Framework/Tests/EntityTestbed.h | 1 - Code/Framework/Tests/NetBindingMocks.h | 1 + Code/Framework/Tests/ProcessLaunchMain.cpp | 11 +- .../Tests/ProcessLaunchParseTests.cpp | 40 +- Code/Framework/Tests/ProjectManagerTests.cpp | 314 ---- .../Tests/frameworktests_files.cmake | 1 - Code/LauncherUnified/CMakeLists.txt | 52 +- Code/LauncherUnified/Launcher.cpp | 252 +-- Code/LauncherUnified/Launcher.h | 8 +- Code/LauncherUnified/LauncherProject.cpp | 21 +- .../Android/Launcher_Traits_Android.h | 2 - .../Platform/Linux/Launcher_Traits_Linux.h | 2 - .../Platform/Mac/Launcher_Traits_Mac.h | 2 - .../Platform/Mac/launcher_project_mac.cmake | 34 +- .../Windows/Launcher_Traits_Windows.h | 2 - .../Windows/launcher_project_windows.cmake | 9 +- .../Platform/iOS/Launcher_Traits_iOS.h | 2 - .../Platform/iOS/launcher_project_ios.cmake | 37 +- Code/LauncherUnified/Tests/Test.cpp | 9 +- .../AssetDatabaseLocationListener.cpp | 22 +- .../Editor/Core/QtEditorApplication.cpp | 12 +- Code/Sandbox/Editor/CryEdit.cpp | 40 +- .../Editor/Dialogs/PythonScriptsDialog.cpp | 66 +- .../Sandbox/Editor/EditorToolsApplication.cpp | 12 - Code/Sandbox/Editor/GameEngine.cpp | 54 +- .../Sandbox/Editor/GraphicsSettingsDialog.cpp | 12 +- Code/Sandbox/Editor/IEditor.h | 2 - Code/Sandbox/Editor/IEditorImpl.cpp | 11 - Code/Sandbox/Editor/IEditorImpl.h | 1 - Code/Sandbox/Editor/Lib/Tests/IEditorMock.h | 1 - Code/Sandbox/Editor/MainStatusBar.cpp | 17 +- Code/Sandbox/Editor/Settings.cpp | 41 +- .../TrackView/AtomOutputFrameCapture.cpp | 124 ++ .../Editor/TrackView/AtomOutputFrameCapture.h | 74 + .../TrackView/SequenceBatchRenderDialog.cpp | 64 +- .../TrackView/SequenceBatchRenderDialog.h | 9 +- Code/Sandbox/Editor/Util/FileUtil.cpp | 10 +- .../WelcomeScreen/WelcomeScreenDialog.cpp | 10 +- Code/Sandbox/Editor/editor_lib_files.cmake | 2 + .../UI/AssetCatalogModel.cpp | 6 +- .../UI/Outliner/OutlinerWidget.cpp | 11 +- .../PlatformSettings_Base.cpp | 7 +- .../PlatformSettings_Base.h | 4 +- .../Plugins/ProjectSettingsTool/Utils.cpp | 9 +- .../ProjectBuilder/root.build.gradle.in | 2 +- .../source/utils/applicationManager.cpp | 82 +- .../source/utils/applicationManager.h | 4 +- .../Tools/AssetBundler/source/utils/utils.cpp | 399 ++--- Code/Tools/AssetBundler/source/utils/utils.h | 76 +- .../AssetBundler/tests/DummyProject/gems.json | 25 - Code/Tools/AssetBundler/tests/UtilsTests.cpp | 2 +- .../tests/applicationManagerTests.cpp | 4 +- Code/Tools/AssetBundler/tests/tests_main.cpp | 157 +- .../AssetBuilder/AssetBuilderApplication.cpp | 137 +- .../AssetBuilder/AssetBuilderApplication.h | 2 - .../AssetBuilder/AssetBuilderComponent.cpp | 228 +-- .../AssetBuilder/AssetBuilderComponent.h | 1 + .../Tests/AssetBuilderApplicationTests.cpp | 56 - .../AssetProcessor/AssetBuilder/main.cpp | 6 - .../AssetBuilderSDK/AssetBuilderSDK.cpp | 4 +- .../AssetBuilderSDK/AssetBuilderSDK.h | 8 +- Code/Tools/AssetProcessor/CMakeLists.txt | 65 + .../assetprocessor_test_files.cmake | 1 - .../native/AssetManager/AssetCatalog.cpp | 72 +- .../AssetManager/PathDependencyManager.cpp | 59 +- .../AssetManager/PathDependencyManager.h | 3 - .../AssetManager/assetProcessorManager.cpp | 76 +- .../native/FileServer/fileServer.cpp | 52 +- .../SettingsRegistryBuilder.cpp | 44 +- .../native/connection/connectionManager.cpp | 4 +- .../native/connection/connectionworker.cpp | 8 +- .../native/resourcecompiler/RCBuilder.cpp | 20 +- .../AssetCatalog/AssetCatalogUnitTests.cpp | 93 +- .../tests/AssetProcessorMessagesTests.cpp | 4 +- .../native/tests/SourceFileRelocatorTests.cpp | 15 +- .../AssetProcessorManagerTest.cpp | 154 +- .../platformconfigurationtests.cpp | 162 +- .../native/tests/utilities/assetUtilsTest.cpp | 11 +- .../AssetProcessor/native/ui/MainWindow.cpp | 2 +- .../unittests/AssetCatalogUnitTests.cpp | 655 -------- .../AssetProcessorManagerUnitTests.cpp | 133 +- .../AssetProcessorServerUnitTests.cpp | 5 +- .../native/unittests/UnitTestRunner.h | 2 +- .../native/unittests/UtilitiesUnitTests.cpp | 2 +- .../native/utilities/ApplicationManager.cpp | 193 +-- .../native/utilities/ApplicationManager.h | 7 +- .../utilities/ApplicationManagerBase.cpp | 11 +- .../native/utilities/ApplicationManagerBase.h | 2 +- .../native/utilities/BuilderManager.cpp | 40 +- .../native/utilities/BuilderManager.h | 6 +- .../utilities/CommunicatorTracePrinter.cpp | 2 +- .../utilities/CommunicatorTracePrinter.h | 6 +- .../utilities/GUIApplicationManager.cpp | 149 +- .../utilities/MissingDependencyScanner.cpp | 35 +- .../utilities/MissingDependencyScanner.h | 2 +- .../utilities/PlatformConfiguration.cpp | 1452 +++++++++++------ .../native/utilities/PlatformConfiguration.h | 108 +- .../native/utilities/assetUtils.cpp | 578 +++---- .../native/utilities/assetUtils.h | 41 +- .../AssetProcessorPlatformConfig.ini | 2 +- .../AssetProcessorPlatformConfig.ini | 2 +- .../AssetProcessorPlatformConfig.ini | 2 +- .../AssetProcessorPlatformConfig.ini | 8 +- .../AssetProcessorPlatformConfig.ini | 2 +- .../AssetProcessor/testdata/unittests.qrc | 12 - Code/Tools/CMakeLists.txt | 1 - .../Tools/Uploader/ToolsCrashUploader.cpp | 11 +- Code/Tools/GemRegistry/CMakeLists.txt | 62 - .../gemregistry_shared_files.cmake | 15 - .../include/GemRegistry/Dependency.h | 28 - .../include/GemRegistry/IGemRegistry.h | 399 ----- .../GemRegistry/include/GemRegistry/Version.h | 52 - .../GemRegistry/source/GemDescription.cpp | 621 ------- .../Tools/GemRegistry/source/GemDescription.h | 100 -- Code/Tools/GemRegistry/source/GemRegistry.cpp | 425 ----- Code/Tools/GemRegistry/source/GemRegistry.h | 105 -- .../GemRegistry/source/ProjectSettings.cpp | 596 ------- .../GemRegistry/source/ProjectSettings.h | 69 - .../GemRegistry/tests/DependencyTest.cpp | 408 ----- .../GemRegistry/tests/DescriptionTest.cpp | 378 ----- .../GemRegistry/tests/ProjectSettingsTest.cpp | 247 --- Code/Tools/GemRegistry/tests/RegistryTest.cpp | 36 - Code/Tools/GemRegistry/tests/VersionTest.cpp | 465 ------ Code/Tools/GemRegistry/tests/main.cpp | 38 - .../Tools/News/NewsBuilder/Qt/NewsBuilder.cpp | 11 +- Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h | 4 +- Code/Tools/News/NewsBuilder/main.cpp | 13 +- Code/Tools/ProfVis/ProfVis.sln | 20 - Code/Tools/ProfVis/ProfVis/App.config | 6 - Code/Tools/ProfVis/ProfVis/Form1.Designer.cs | 162 -- Code/Tools/ProfVis/ProfVis/Form1.cs | 891 ---------- Code/Tools/ProfVis/ProfVis/Form1.resx | 123 -- Code/Tools/ProfVis/ProfVis/ProfVis.csproj | 129 -- Code/Tools/ProfVis/ProfVis/Program.cs | 35 - .../ProfVis/Properties/AssemblyInfo.cs | 49 - .../Properties/DataSources/Form1.datasource | 10 - .../ProfVis.Properties.Resources.datasource | 10 - .../ProfVis.Properties.Settings.datasource | 10 - .../Properties/DataSources/Program.datasource | 10 - .../ProfVis/Properties/Resources.Designer.cs | 72 - .../ProfVis/ProfVis/Properties/Resources.resx | 117 -- .../ProfVis/Properties/Settings.Designer.cs | 31 - .../ProfVis/Properties/Settings.settings | 7 - .../source/ApplicationParameters.cpp | 27 +- .../RC/ResourceCompiler/ResourceCompiler.cpp | 1 - Code/Tools/RC/ResourceCompiler/main.cpp | 24 +- .../RC/ResourceCompilerPC/StatCGFCompiler.cpp | 19 +- .../RC/ResourceCompilerPC/Tests/test_Main.cpp | 3 +- .../ResourceCompilerScene/SceneCompiler.cpp | 33 +- .../Importers/AssImpSkinWeightsImporter.cpp | 76 +- .../Importers/AssImpSkinWeightsImporter.h | 3 +- .../SDKWrapper/AssImpMaterialWrapper.cpp | 76 +- .../SDKWrapper/AssImpMaterialWrapper.h | 18 +- .../SDKWrapper/AssImpSceneWrapper.cpp | 2 + .../DataTypes/GraphData/IMaterialData.h | 18 +- .../Tests/Containers/SceneBehaviorTests.cpp | 3 +- .../SceneCore/Utilities/DebugOutput.cpp | 35 + .../SceneCore/Utilities/DebugOutput.h | 3 + .../Behaviors/ScriptProcessorRuleBehavior.cpp | 2 +- Code/Tools/SceneAPI/SceneData/CMakeLists.txt | 2 + .../SceneData/GraphData/MaterialData.cpp | 36 +- .../SceneData/GraphData/MaterialData.h | 56 +- .../SceneData/GraphData/SkinWeightData.cpp | 13 + .../SceneData/GraphData/SkinWeightData.h | 1 + .../SceneData/SceneData_testing_files.cmake | 1 + .../SceneManifest/SceneManifestRuleTests.cpp | 178 ++ .../SerializeContextTools/Application.cpp | 64 +- .../Tools/SerializeContextTools/Application.h | 6 +- .../SerializeContextTools/CMakeLists.txt | 2 - .../Tools/SerializeContextTools/Converter.cpp | 35 +- Code/Tools/SerializeContextTools/Converter.h | 2 +- Code/Tools/SerializeContextTools/Dumper.cpp | 3 +- .../Tools/SerializeContextTools/Utilities.cpp | 10 +- Code/Tools/SerializeContextTools/main.cpp | 28 +- .../ShaderCacheGen/ShaderCacheGen.cpp | 7 - .../Source/LUA/LUAEditorMainWindow.cpp | 7 +- Engine/Registry/bootstrap.setreg | 39 + .../AWSClientAuthResourceMappingConstants.h | 16 + .../AWSCognitoAuthenticationProvider.h | 6 +- .../AuthenticationProviderTypes.h | 31 - .../Private/Authentication/OAuthConstants.h | 38 +- ...entAuthPersistentCognitoIdentityProvider.h | 1 - .../AWSCognitoAuthorizationController.h | 8 +- .../AWSCognitoAuthorizationTypes.h | 59 - .../AWSCognitoUserManagementController.h | 12 +- .../AWSCognitoUserManagementTypes.h | 50 - .../AWSCognitoAuthorizationBus.h | 2 +- .../AWSCognitoUserManagementBus.h | 2 +- .../Source/AWSClientAuthSystemComponent.cpp | 12 +- .../AWSCognitoAuthenticationProvider.cpp | 49 +- .../GoogleAuthenticationProvider.cpp | 54 +- .../LWAAuthenticationProvider.cpp | 50 +- .../AWSCognitoAuthorizationController.cpp | 48 +- .../AWSCognitoUserManagementController.cpp | 40 +- .../Code/Tests/AWSClientAuthGemMock.h | 38 +- .../AWSClientAuthSystemComponentTest.cpp | 30 +- .../AWSCognitoAuthenticationProviderTest.cpp | 34 +- .../AuthenticationProviderManagerTest.cpp | 5 - .../AWSCognitoAuthorizationControllerTest.cpp | 47 +- ...AWSCognitoUserManagementControllerTest.cpp | 42 +- .../Code/awsclientauth_files.cmake | 3 +- Gems/AWSClientAuth/cdk/requirements.txt | 6 +- Gems/AWSCore/Code/CMakeLists.txt | 2 - .../Code/Include/Private/MetricsManager.h | 5 + .../Code/Source/AWSMetricsSystemComponent.cpp | 10 +- .../AWSMetrics/Code/Source/MetricsManager.cpp | 35 +- .../Code/Tests/MetricsManagerTest.cpp | 20 +- Gems/AWSMetrics/cdk/README.md | 28 +- Gems/AWSMetrics/cdk/aws_metrics/auth.py | 2 +- .../cdk/aws_metrics/aws_metrics_constants.py | 2 +- Gems/Achievements/Code/CMakeLists.txt | 1 - Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt | 3 +- Gems/AssetValidation/Code/CMakeLists.txt | 2 - .../Code/Source/AssetSeedUtil.cpp | 196 +-- .../Code/Source/AssetSeedUtil.h | 27 +- .../Source/AssetValidationSystemComponent.cpp | 6 +- .../Code/Tests/AssetValidationTest.cpp | 20 +- .../Code/Tests/AssetValidationTestShared.h | 11 +- .../AssetProcessorGemConfig.ini | 15 - .../AssetProcessorGemConfig.setreg | 7 + .../ImageProcessingAtom/Code/CMakeLists.txt | 4 +- .../Code/Source/ImageBuilderComponent.cpp | 21 + .../Code/Source/ImageBuilderComponent.h | 8 + .../Source/ImageProcessingSystemComponent.h | 1 - .../Code/Tests/ImageProcessing_Test.cpp | 15 +- Gems/Atom/Asset/Shader/Code/CMakeLists.txt | 8 +- .../Shader/Code/Source/Editor/AzslBuilder.cpp | 14 +- .../Code/Source/Editor/AzslCompiler.cpp | 4 +- .../AzslShaderBuilderSystemComponent.cpp | 10 +- .../Editor/CommonFiles/GlobalBuildOptions.cpp | 6 - .../Editor/CommonFiles/Preprocessor.cpp | 14 +- .../Code/Source/Editor/ShaderAssetBuilder.cpp | 14 +- .../Source/Editor/ShaderBuilderUtility.cpp | 4 +- .../Code/Source/Editor/ShaderBuilderUtility.h | 1 + .../Editor/ShaderVariantAssetBuilder.cpp | 85 +- .../Source/Editor/ShaderVariantAssetBuilder.h | 1 + .../Code/Source/Editor/SrgLayoutBuilder.cpp | 6 +- Gems/Atom/Bootstrap/Code/CMakeLists.txt | 1 - .../Component/DebugCamera/Code/CMakeLists.txt | 1 - .../Types/EnhancedPBR_ForwardPass.shader | 7 + .../Types/EnhancedPBR_ForwardPass_EDS.shader | 7 + .../Types/EnhancedPBR_Shadowmap_WithPS.azsl | 2 +- .../StandardMultilayerPBR_ForwardPass.shader | 7 + ...andardMultilayerPBR_ForwardPass_EDS.shader | 7 + .../Types/StandardPBR_ForwardPass.shader | 7 + .../Types/StandardPBR_ForwardPass_EDS.shader | 7 + .../Types/StandardPBR_Shadowmap_WithPS.azsl | 2 +- Gems/Atom/Feature/Common/Code/CMakeLists.txt | 9 +- .../Atom/Feature/Utils/FrameCaptureBus.h | 12 + .../Atom/Feature/Utils/LightingPreset.h | 8 +- .../Include/Atom/Feature/Utils/ModelPreset.h | 2 + .../Source/FrameCaptureSystemComponent.cpp | 27 +- .../Material/ConvertEmissiveUnitFunctor.h | 8 +- .../MaterialConverterSystemComponent.cpp | 60 +- .../Source/Utils/EditorLightingPreset.cpp | 3 +- .../Code/Source/Utils/EditorModelPreset.cpp | 1 + .../Code/Source/Utils/LightingPreset.cpp | 14 +- .../Common/Code/Source/Utils/ModelPreset.cpp | 4 +- Gems/Atom/RHI/Code/CMakeLists.txt | 1 - .../Atom/RHI.Edit/ShaderPlatformInterface.h | 29 +- .../RHI/Code/Include/Atom/RHI.Edit/Utils.h | 2 +- .../Code/Include/Atom/RHI.Reflect/Format.h | 1 + Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp | 23 +- Gems/Atom/RHI/DX12/Code/CMakeLists.txt | 10 +- ...NsightAftermathGpuCrashTracker_Windows.cpp | 11 +- .../RHI.Builders/ShaderPlatformInterface.cpp | 35 +- .../RHI.Builders/ShaderPlatformInterface.h | 13 +- Gems/Atom/RHI/Metal/Code/CMakeLists.txt | 10 +- .../RHI.Builders/ShaderPlatformInterface.cpp | 27 +- .../RHI.Builders/ShaderPlatformInterface.h | 13 +- Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt | 10 +- .../RHI.Builders/ShaderPlatformInterface.cpp | 32 +- .../RHI.Builders/ShaderPlatformInterface.h | 13 +- .../RHI/Vulkan/Code/Source/RHI/Formats.inl | 1 + Gems/Atom/RPI/Code/CMakeLists.txt | 13 +- .../RPI.Builders/Material/MaterialBuilder.cpp | 2 +- .../Model/MaterialAssetBuilderComponent.cpp | 2 +- .../Model/ModelAssetBuilderComponent.cpp | 2 +- .../Pass/Specific/RenderToTexturePass.cpp | 2 +- .../Pass/Specific/SwapChainPass.cpp | 2 +- .../Code/Tests.Builders/BuilderTestFixture.h | 3 +- .../Tests/Common/AssetManagerTestFixture.h | 3 +- .../RPI/Code/Tests/Common/RPITestFixture.cpp | 3 +- .../AtomToolsFramework/Code/CMakeLists.txt | 4 +- .../Inspector/InspectorRequestBus.h | 4 +- .../Inspector/InspectorWidget.h | 2 +- .../Code/Source/Inspector/InspectorWidget.cpp | 2 +- .../Tools/MaterialEditor/Code/CMakeLists.txt | 7 + .../MaterialViewportNotificationBus.h | 6 + .../Viewport/MaterialViewportRequestBus.h | 45 +- .../Code/Source/MaterialEditorApplication.cpp | 4 +- .../Viewport/MaterialViewportComponent.cpp | 174 +- .../Viewport/MaterialViewportComponent.h | 25 +- .../Viewport/MaterialViewportRenderer.cpp | 22 +- .../Viewport/MaterialViewportRenderer.h | 2 + .../Source/Window/MaterialEditorWindow.cpp | 45 - .../Window/MaterialEditorWindowComponent.cpp | 3 + .../LightingPresetBrowserDialog.cpp | 73 + .../LightingPresetBrowserDialog.h | 40 + .../ModelPresetBrowserDialog.cpp | 73 + .../ModelPresetBrowserDialog.h | 40 + .../PresetBrowserDialog.cpp | 115 ++ .../PresetBrowserDialog.h | 50 + .../PresetBrowserDialog.ui | 44 + .../Source/Window/ToolBar/FovSliderWidget.cpp | 45 - .../Source/Window/ToolBar/FovSliderWidget.h | 39 - .../Window/ToolBar/MaterialEditorToolBar.cpp | 19 +- .../ViewportSettingsInspector.cpp | 314 +++- .../ViewportSettingsInspector.h | 33 + .../Tools/MaterialEditor/Code/Source/main.cpp | 9 +- .../Code/materialeditorwindow_files.cmake | 9 +- .../Code/CMakeLists.txt | 6 + .../ShaderManagementConsoleApplication.cpp | 4 +- .../Code/Source/main.cpp | 9 +- .../AtomBridge/Code/CMakeLists.txt | 2 - .../Code/Source/FlyCameraInputComponent.h | 2 +- .../AtomImGuiTools/Code/CMakeLists.txt | 1 - .../AssetProcessorGemConfig.ini | 4 - .../AssetProcessorGemConfig.setreg | 13 + .../CommonFeatures/Code/CMakeLists.txt | 5 +- .../Material/MaterialComponentController.cpp | 4 + .../EMotionFXAtom/Code/CMakeLists.txt | 5 +- .../ImguiAtom/Code/CMakeLists.txt | 1 - .../DccScriptingInterface/Code/CMakeLists.txt | 1 - .../DccScriptingInterface/azpy/__init__.py | 4 +- .../azpy/config_utils.py | 22 +- .../AssetProcessorGemConfig.ini | 12 - .../AssetProcessorGemConfig.setreg | 20 + Gems/AudioEngineWwise/Code/CMakeLists.txt | 9 +- .../AudioEngineWwiseGemSystemComponent.cpp | 14 +- .../AudioEngineWwiseGemSystemComponent.h | 2 +- .../Tests/AudioEngineWwiseBuilderTest.cpp | 3 +- Gems/AudioSystem/Code/CMakeLists.txt | 9 +- .../Source/AudioSystemGemSystemComponent.cpp | 2 +- .../Code/CMakeLists.txt | 2 + Gems/Blast/AssetProcessorGemConfig.ini | 13 - Gems/Blast/AssetProcessorGemConfig.setreg | 22 + Gems/Blast/Code/CMakeLists.txt | 10 +- Gems/Blast/Code/blast_unsupported.cmake | 3 +- Gems/Camera/Code/CMakeLists.txt | 5 +- Gems/CameraFramework/Code/CMakeLists.txt | 1 - Gems/CertificateManager/Code/CMakeLists.txt | 1 - Gems/CrashReporting/Code/CMakeLists.txt | 1 - Gems/CustomAssetExample/Code/CMakeLists.txt | 5 +- Gems/DebugDraw/Code/CMakeLists.txt | 5 +- Gems/EMotionFX/Code/CMakeLists.txt | 11 +- .../CommandSystem/Source/MotionCommands.cpp | 2 +- Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp | 460 +++--- .../EMStudioSDK/Source/FileManager.cpp | 53 +- .../EMStudioSDK/Source/Workspace.cpp | 33 +- .../Code/Tests/SystemComponentFixture.h | 8 +- .../Code/Tests/UI/CanUseFileMenu.cpp | 5 +- Gems/EMotionFX/Code/Tests/UI/UIFixture.cpp | 9 +- Gems/EditorPythonBindings/Code/CMakeLists.txt | 4 +- .../Code/Source/PythonSystemComponent.cpp | 127 +- .../Code/Tests/EditorPythonBindingsTest.cpp | 6 +- .../Code/Tests/PythonTestingUtility.h | 20 +- Gems/ExpressionEvaluation/Code/CMakeLists.txt | 1 - Gems/FastNoise/Code/CMakeLists.txt | 11 +- Gems/GameEffectSystem/Code/CMakeLists.txt | 1 - Gems/GameLift/Code/CMakeLists.txt | 5 +- Gems/GameState/Code/CMakeLists.txt | 1 - Gems/GameStateSamples/Code/CMakeLists.txt | 1 - Gems/Gestures/Code/CMakeLists.txt | 1 - Gems/GradientSignal/Code/CMakeLists.txt | 11 +- Gems/GraphCanvas/Code/CMakeLists.txt | 5 +- Gems/GraphModel/Code/CMakeLists.txt | 6 +- Gems/HttpRequestor/Code/CMakeLists.txt | 1 - Gems/ImGui/Code/CMakeLists.txt | 9 +- .../AssetProcessorGemConfig.ini | 15 - .../AssetProcessorGemConfig.setreg | 7 + Gems/ImageProcessing/Code/CMakeLists.txt | 5 +- .../AtlasBuilder/AtlasBuilderWorker.cpp | 235 +-- .../Source/AtlasBuilder/AtlasBuilderWorker.h | 9 - .../Code/Source/ImageBuilderComponent.cpp | 21 + .../Code/Source/ImageBuilderComponent.h | 8 + .../Code/Tests/ImageProcessing_Test.cpp | 3 +- Gems/InAppPurchases/Code/CMakeLists.txt | 1 - Gems/LandscapeCanvas/Code/CMakeLists.txt | 11 +- Gems/LmbrCentral/Code/CMakeLists.txt | 11 +- .../XmlBuilderWorker/XmlBuilderWorker.cpp | 4 +- .../TranslationBuilderComponent.cpp | 14 +- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 20 - .../Builders/CopyDependencyBuilderTest.cpp | 8 +- .../Code/Tests/Builders/LevelBuilderTest.cpp | 7 +- .../Code/Tests/Builders/LuaBuilderTests.cpp | 3 +- .../Tests/Builders/MaterialBuilderTests.cpp | 3 +- .../Code/Tests/Builders/SliceBuilderTests.cpp | 3 +- Gems/LocalUser/Code/CMakeLists.txt | 1 - Gems/LyShine/Code/CMakeLists.txt | 11 +- Gems/LyShine/Code/Editor/FileHelpers.cpp | 43 +- Gems/LyShine/Code/Tests/LyShineEditorTest.cpp | 5 +- Gems/LyShineExamples/Code/CMakeLists.txt | 1 - Gems/Maestro/Code/CMakeLists.txt | 9 +- Gems/MessagePopup/Code/CMakeLists.txt | 1 - Gems/Metastream/Code/CMakeLists.txt | 1 - Gems/Microphone/Code/CMakeLists.txt | 3 +- Gems/Multiplayer/Code/CMakeLists.txt | 3 +- .../Code/CMakeLists.txt | 1 - Gems/NvCloth/Code/CMakeLists.txt | 9 +- .../Tests/NvClothEditorTestEnvironment.cpp | 4 +- .../Code/Tests/NvClothTestEnvironment.cpp | 4 +- Gems/NvCloth/Code/nvcloth_stub.cmake | 3 +- Gems/PhysX/AssetProcessorGemConfig.ini | 9 - Gems/PhysX/AssetProcessorGemConfig.setreg | 17 + Gems/PhysX/Code/CMakeLists.txt | 9 +- Gems/PhysX/Code/Tests/PhysXEditorTest.cpp | 2 +- .../PhysX/Code/Tests/PhysXTestEnvironment.cpp | 2 +- Gems/PhysXDebug/Code/CMakeLists.txt | 11 +- Gems/Prefab/PrefabBuilder/CMakeLists.txt | 5 +- .../prefabbuilder_dependencies.cmake | 12 - .../PrefabBuilder/prefabbuilder_files.cmake | 1 - Gems/Presence/Code/CMakeLists.txt | 1 - Gems/PythonAssetBuilder/Code/CMakeLists.txt | 6 +- .../PythonAssetBuilderSystemComponent.cpp | 19 +- Gems/QtForPython/Code/CMakeLists.txt | 3 +- Gems/RADTelemetry/Code/CMakeLists.txt | 1 - Gems/RenderToTexture/Code/CMakeLists.txt | 9 +- .../Source/EditorRenderToTextureComponent.cpp | 2 +- .../Code/Source/RenderToTextureComponent.cpp | 2 +- Gems/SVOGI/Code/CMakeLists.txt | 3 +- Gems/SaveData/Code/CMakeLists.txt | 1 - Gems/SceneLoggingExample/Code/CMakeLists.txt | 1 - Gems/SceneProcessing/Code/CMakeLists.txt | 5 +- .../Builder/ScriptCanvasBuilderWorker.cpp | 25 +- .../ScriptCanvasFunctionBuilderWorker.cpp | 23 +- Gems/ScriptCanvas/Code/CMakeLists.txt | 12 +- .../Editor/Assets/ScriptCanvasMemoryAsset.cpp | 2 +- .../Translation/TranslationUtilities.cpp | 15 +- .../Code/Tests/ScriptCanvasBuilderTests.cpp | 3 +- .../ScriptCanvasDeveloper/Code/CMakeLists.txt | 8 +- .../Code/CMakeLists.txt | 1 - Gems/ScriptCanvasPhysics/Code/CMakeLists.txt | 1 - Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 5 +- .../Framework/ScriptCanvasTestFixture.h | 4 +- Gems/ScriptEvents/Code/CMakeLists.txt | 5 +- .../ScriptedEntityTweener/Code/CMakeLists.txt | 1 - Gems/SliceFavorites/Code/CMakeLists.txt | 4 +- .../Code/Source/FavoriteDataModel.cpp | 16 +- Gems/StartingPointCamera/Code/CMakeLists.txt | 3 +- Gems/StartingPointInput/Code/CMakeLists.txt | 5 +- .../StartingPointMovement/Code/CMakeLists.txt | 1 - Gems/SurfaceData/Code/CMakeLists.txt | 9 +- Gems/TestAssetBuilder/Code/CMakeLists.txt | 3 +- .../Builder/TestAssetBuilderComponent.cpp | 12 +- Gems/TextureAtlas/Code/CMakeLists.txt | 1 - Gems/TickBusOrderViewer/Code/CMakeLists.txt | 1 - Gems/Twitch/Code/CMakeLists.txt | 4 +- Gems/Vegetation/Code/CMakeLists.txt | 13 +- .../Code/CMakeLists.txt | 1 - Gems/VirtualGamepad/Code/CMakeLists.txt | 1 - Gems/Visibility/Code/CMakeLists.txt | 5 +- Gems/WhiteBox/AssetProcessorGemConfig.ini | 5 - Gems/WhiteBox/AssetProcessorGemConfig.setreg | 13 + Gems/WhiteBox/Code/CMakeLists.txt | 10 +- .../Code/Tests/WhiteBoxPhysicsTest.cpp | 2 +- .../DefaultProject/Template/CMakeLists.txt | 23 + .../Template/EngineFinder.cmake | 13 +- .../managers/abstract_resource_locator.py | 19 +- .../_internal/managers/platforms/mac.py | 4 +- .../_internal/managers/platforms/windows.py | 4 +- .../ly_test_tools/builtin/helpers.py | 6 +- .../launchers/platforms/android/launcher.py | 27 +- .../ly_test_tools/launchers/platforms/base.py | 2 - .../launchers/platforms/win/launcher.py | 13 +- .../lumberyard/asset_processor.py | 133 +- .../lumberyard/asset_processor_config_util.py | 230 ++- .../ly_test_tools/lumberyard/settings.py | 4 - Tools/LyTestTools/tests/CMakeLists.txt | 16 +- .../LyTestTools/tests/integ/test_settings.py | 52 - .../unit/test_abstract_resource_locator.py | 4 +- .../tests/unit/test_asset_processor.py | 45 +- .../tests/unit/test_launcher_android.py | 2 - .../tests/unit/test_manager_platforms_mac.py | 4 +- .../unit/test_manager_platforms_windows.py | 4 +- .../ly_remote_console/tests/CMakeLists.txt | 3 +- .../build/Platform/Android/build_config.json | 18 +- .../build/Platform/Android/gradle_windows.cmd | 4 +- .../build/Platform/Linux/asset_linux.sh | 4 +- .../build/Platform/Linux/build_config.json | 23 +- .../build/Platform/Mac/asset_mac.sh | 4 +- .../build/Platform/Mac/build_config.json | 11 +- .../build/Platform/Windows/asset_windows.cmd | 4 +- .../build/Platform/Windows/build_config.json | 50 +- .../build/Platform/iOS/build_config.json | 19 +- .../JenkinsScripts/build/cmake_package.py | 2 +- bootstrap.cfg | 1 - cmake/3rdParty.cmake | 10 - cmake/3rdParty/FindAWSNativeSDK.cmake | 118 -- cmake/3rdParty/FindQt.cmake | 173 -- .../Android/AWSNativeSDK_android.cmake | 69 - .../Android/BuiltInPackages_android.cmake | 1 + .../Android/cmake_android_files.cmake | 1 - .../Platform/Linux/AWSNativeSDK_linux.cmake | 73 - .../Linux/BuiltInPackages_linux.cmake | 4 +- cmake/3rdParty/Platform/Linux/Qt_linux.cmake | 80 - .../Platform/Linux/Qt_qmake_linux.cmake.in | 38 - .../Platform/Linux/cmake_linux_files.cmake | 2 - .../Platform/Mac/AWSNativeSDK_mac.cmake | 95 -- .../Platform/Mac/BuiltInPackages_mac.cmake | 4 +- cmake/3rdParty/Platform/Mac/Qt_mac.cmake | 78 - .../Platform/Mac/cmake_mac_files.cmake | 2 - .../Windows/AWSNativeSDK_windows.cmake | 74 - .../Windows/BuiltInPackages_windows.cmake | 4 +- .../Platform/Windows/Qt_windows.cmake | 55 - .../Windows/cmake_windows_files.cmake | 2 - .../Platform/iOS/AWSNativeSDK_ios.cmake | 37 - .../Platform/iOS/BuiltInPackages_ios.cmake | 1 + .../Platform/iOS/cmake_ios_files.cmake | 1 - cmake/3rdParty/cmake_files.cmake | 2 - cmake/3rdPartyPackages.cmake | 6 + cmake/EngineFinder.cmake | 13 +- cmake/FileUtil.cmake | 3 +- cmake/Initialize.cmake | 3 + cmake/LYWrappers.cmake | 92 +- cmake/Monolithic.cmake | 2 +- cmake/PAL.cmake | 10 +- cmake/Platform/iOS/SDK_ios.cmake | 10 +- cmake/Projects.cmake | 31 +- cmake/SettingsRegistry.cmake | 63 +- .../Platform/Android/android_deployment.py | 2 +- .../Tools/Platform/Android/android_support.py | 160 +- .../Android/generate_android_project.py | 34 +- .../Android/unit_test_android_deployment.py | 31 +- .../unit_test_generate_android_project.py | 2 +- cmake/Tools/add_remove_gem.py | 4 +- cmake/Tools/common.py | 161 +- cmake/Tools/current_project.py | 18 +- cmake/Tools/engine_template.py | 32 +- cmake/Tools/generate_game_paks.py | 4 +- cmake/Tools/layout_tool.py | 370 ++--- cmake/Tools/unit_test_common.py | 70 +- cmake/Tools/unit_test_current_project.py | 10 +- cmake/Tools/unit_test_layout_tool.py | 96 +- cmake/UnitTest.cmake | 2 +- cmake/gemcmake.py | 5 +- cmake/projectcmake.py | 5 +- cmake/run_epbtest.cmake | 2 +- ctest_scripts/CMakeLists.txt | 16 +- python/requirements.txt | 23 + .../build_node/Platform/Mac/init-setup.sh | 84 + .../build_node/Platform/Mac/install-jdk.sh | 25 +- .../build_node/Platform/Mac/install-python.sh | 19 +- .../build_node/Platform/Mac/install-xcode.sh | 46 + .../Platform/Mac/jenkins-self-register-mac.sh | 79 + scripts/build/package/package.py | 2 +- .../build/package/package_filelists/all.json | 3 +- .../commit_validation/commit_validation.py | 2 +- scripts/project_manager/projects.py | 52 +- 764 files changed, 11367 insertions(+), 20165 deletions(-) delete mode 100644 .p4ignore delete mode 100644 AssetProcessorPlatformConfig.ini rename Engine/Registry/AssetProcessorPlatformConfig.setreg => AssetProcessorPlatformConfig.setreg (50%) delete mode 100644 AutomatedTesting/Config/Editor.xml delete mode 100644 AutomatedTesting/Config/Game.xml delete mode 100644 AutomatedTesting/Config/Server.xml delete mode 100644 AutomatedTesting/Gem/AssetProcessorGemConfig.ini create mode 100644 AutomatedTesting/Gem/AssetProcessorGemConfig.setreg create mode 100644 AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Sandbox.py delete mode 100644 AutomatedTesting/gems.json delete mode 100644 Code/CryEngine/CryCommon/ParseEngineConfig.h delete mode 100644 Code/CryEngine/CrySystem/BootProfiler.cpp delete mode 100644 Code/CryEngine/CrySystem/BootProfiler.h delete mode 100644 Code/CryEngine/CrySystem/LoadingProfiler.cpp delete mode 100644 Code/CryEngine/CrySystem/LoadingProfiler.h delete mode 100644 Code/CryEngine/CrySystem/Tests/Test_BootProfiler.cpp create mode 100644 Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp create mode 100644 Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp create mode 100644 Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h rename Code/Framework/{AzToolsFramework/AzToolsFramework => AzFramework/AzFramework}/Process/ProcessCommon_fwd.h (95%) rename Code/Framework/{AzToolsFramework/AzToolsFramework => AzFramework/AzFramework}/Process/ProcessCommunicator.cpp (97%) rename Code/Framework/{AzToolsFramework/AzToolsFramework => AzFramework/AzFramework}/Process/ProcessCommunicator.h (90%) rename Code/Framework/{AzToolsFramework/AzToolsFramework => AzFramework/AzFramework}/Process/ProcessWatcher.cpp (90%) rename Code/Framework/{AzToolsFramework/AzToolsFramework => AzFramework/AzFramework}/Process/ProcessWatcher.h (95%) create mode 100644 Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommon.h create mode 100644 Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommunicator_Android.cpp create mode 100644 Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessWatcher_Android.cpp delete mode 100644 Code/Framework/AzFramework/Platform/Android/AzFramework/ProjectManager/ProjectManager_Android.cpp create mode 100644 Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommon_Default.h create mode 100644 Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommunicator_Default.cpp create mode 100644 Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessWatcher_Default.cpp delete mode 100644 Code/Framework/AzFramework/Platform/Common/Default/AzFramework/ProjectManager/ProjectManager_Default.cpp rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Linux.h => AzFramework/Platform/Linux/AzFramework/Process/ProcessCommon.h} (95%) rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal => AzFramework/Platform/Linux/AzFramework/Process}/ProcessCommunicator_Linux.cpp (98%) rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal => AzFramework/Platform/Linux/AzFramework/Process}/ProcessWatcher_Linux.cpp (98%) delete mode 100644 Code/Framework/AzFramework/Platform/Linux/AzFramework/ProjectManager/ProjectManager_Linux.cpp rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_OSX.h => AzFramework/Platform/Mac/AzFramework/Process/ProcessCommon.h} (91%) rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_OSX.cpp => AzFramework/Platform/Mac/AzFramework/Process/ProcessCommunicator_Mac.cpp} (98%) rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_OSX.cpp => AzFramework/Platform/Mac/AzFramework/Process/ProcessWatcher_Mac.cpp} (98%) delete mode 100644 Code/Framework/AzFramework/Platform/Mac/AzFramework/ProjectManager/ProjectManager_Mac.cpp rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Win.h => AzFramework/Platform/Windows/AzFramework/Process/ProcessCommon.h} (98%) rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal => AzFramework/Platform/Windows/AzFramework/Process}/ProcessCommunicator_Win.cpp (98%) rename Code/Framework/{AzToolsFramework/AzToolsFramework/Process/internal => AzFramework/Platform/Windows/AzFramework/Process}/ProcessWatcher_Win.cpp (96%) delete mode 100644 Code/Framework/AzFramework/Platform/Windows/AzFramework/ProjectManager/ProjectManager_Windows.cpp create mode 100644 Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommon.h create mode 100644 Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommunicator_iOS.cpp create mode 100644 Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessWatcher_iOS.cpp delete mode 100644 Code/Framework/AzFramework/Platform/iOS/AzFramework/ProjectManager/ProjectManager_iOS.cpp delete mode 100644 Code/Framework/Tests/ProjectManagerTests.cpp create mode 100644 Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.cpp create mode 100644 Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.h delete mode 100644 Code/Tools/AssetBundler/tests/DummyProject/gems.json delete mode 100644 Code/Tools/AssetProcessor/native/unittests/AssetCatalogUnitTests.cpp delete mode 100644 Code/Tools/AssetProcessor/testdata/unittests.qrc delete mode 100644 Code/Tools/GemRegistry/CMakeLists.txt delete mode 100644 Code/Tools/GemRegistry/gemregistry_shared_files.cmake delete mode 100644 Code/Tools/GemRegistry/include/GemRegistry/Dependency.h delete mode 100644 Code/Tools/GemRegistry/include/GemRegistry/IGemRegistry.h delete mode 100644 Code/Tools/GemRegistry/include/GemRegistry/Version.h delete mode 100644 Code/Tools/GemRegistry/source/GemDescription.cpp delete mode 100644 Code/Tools/GemRegistry/source/GemDescription.h delete mode 100644 Code/Tools/GemRegistry/source/GemRegistry.cpp delete mode 100644 Code/Tools/GemRegistry/source/GemRegistry.h delete mode 100644 Code/Tools/GemRegistry/source/ProjectSettings.cpp delete mode 100644 Code/Tools/GemRegistry/source/ProjectSettings.h delete mode 100644 Code/Tools/GemRegistry/tests/DependencyTest.cpp delete mode 100644 Code/Tools/GemRegistry/tests/DescriptionTest.cpp delete mode 100644 Code/Tools/GemRegistry/tests/ProjectSettingsTest.cpp delete mode 100644 Code/Tools/GemRegistry/tests/RegistryTest.cpp delete mode 100644 Code/Tools/GemRegistry/tests/VersionTest.cpp delete mode 100644 Code/Tools/GemRegistry/tests/main.cpp delete mode 100644 Code/Tools/ProfVis/ProfVis.sln delete mode 100644 Code/Tools/ProfVis/ProfVis/App.config delete mode 100644 Code/Tools/ProfVis/ProfVis/Form1.Designer.cs delete mode 100644 Code/Tools/ProfVis/ProfVis/Form1.cs delete mode 100644 Code/Tools/ProfVis/ProfVis/Form1.resx delete mode 100644 Code/Tools/ProfVis/ProfVis/ProfVis.csproj delete mode 100644 Code/Tools/ProfVis/ProfVis/Program.cs delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/AssemblyInfo.cs delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/DataSources/Form1.datasource delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Resources.datasource delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Settings.datasource delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/DataSources/Program.datasource delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/Resources.Designer.cs delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/Resources.resx delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/Settings.Designer.cs delete mode 100644 Code/Tools/ProfVis/ProfVis/Properties/Settings.settings create mode 100644 Code/Tools/SceneAPI/SceneData/Tests/SceneManifest/SceneManifestRuleTests.cpp create mode 100644 Engine/Registry/bootstrap.setreg create mode 100644 Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthResourceMappingConstants.h delete mode 100644 Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationTypes.h delete mode 100644 Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementTypes.h delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.ini create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.setreg create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.ini create mode 100644 Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.setreg delete mode 100644 Gems/AudioEngineWwise/AssetProcessorGemConfig.ini create mode 100644 Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg delete mode 100644 Gems/Blast/AssetProcessorGemConfig.ini create mode 100644 Gems/Blast/AssetProcessorGemConfig.setreg delete mode 100644 Gems/ImageProcessing/AssetProcessorGemConfig.ini create mode 100644 Gems/ImageProcessing/AssetProcessorGemConfig.setreg delete mode 100644 Gems/PhysX/AssetProcessorGemConfig.ini create mode 100644 Gems/PhysX/AssetProcessorGemConfig.setreg delete mode 100644 Gems/Prefab/PrefabBuilder/prefabbuilder_dependencies.cmake delete mode 100644 Gems/WhiteBox/AssetProcessorGemConfig.ini create mode 100644 Gems/WhiteBox/AssetProcessorGemConfig.setreg delete mode 100644 Tools/LyTestTools/tests/integ/test_settings.py delete mode 100644 cmake/3rdParty/FindAWSNativeSDK.cmake delete mode 100644 cmake/3rdParty/FindQt.cmake delete mode 100644 cmake/3rdParty/Platform/Android/AWSNativeSDK_android.cmake delete mode 100644 cmake/3rdParty/Platform/Linux/AWSNativeSDK_linux.cmake delete mode 100644 cmake/3rdParty/Platform/Linux/Qt_linux.cmake delete mode 100644 cmake/3rdParty/Platform/Linux/Qt_qmake_linux.cmake.in delete mode 100644 cmake/3rdParty/Platform/Mac/AWSNativeSDK_mac.cmake delete mode 100644 cmake/3rdParty/Platform/Mac/Qt_mac.cmake delete mode 100644 cmake/3rdParty/Platform/Windows/AWSNativeSDK_windows.cmake delete mode 100644 cmake/3rdParty/Platform/Windows/Qt_windows.cmake delete mode 100644 cmake/3rdParty/Platform/iOS/AWSNativeSDK_ios.cmake create mode 100644 scripts/build/build_node/Platform/Mac/init-setup.sh rename Code/Tools/GemRegistry/gemregistry_test_files.cmake => scripts/build/build_node/Platform/Mac/install-jdk.sh (51%) rename Code/Tools/GemRegistry/gemregistry_files.cmake => scripts/build/build_node/Platform/Mac/install-python.sh (66%) create mode 100644 scripts/build/build_node/Platform/Mac/install-xcode.sh create mode 100644 scripts/build/build_node/Platform/Mac/jenkins-self-register-mac.sh diff --git a/.p4ignore b/.p4ignore deleted file mode 100644 index a342dd77dd..0000000000 --- a/.p4ignore +++ /dev/null @@ -1,30 +0,0 @@ -*.ilk -*.suo -*.user -*.o -*.temp -*.bootstrap.digests -*.log -*.exp -*.vssettings -*.exportlog -*.mayaSwatches -*.ma.swatches -*.bak -*.bak2 -*.akd -Solutions -BinTemp -*.options -*.pyc -*.db -Cache -AssetProcessor_tmp.exe -Builders_Temp -Bin64vc* -$tmp* -.pytest_cache -__pycache__ -# Python Module egg file -*.egg -*.egg-link \ No newline at end of file diff --git a/AssetProcessorPlatformConfig.ini b/AssetProcessorPlatformConfig.ini deleted file mode 100644 index 82cc6d0d1e..0000000000 --- a/AssetProcessorPlatformConfig.ini +++ /dev/null @@ -1,590 +0,0 @@ -; ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default. - -; PLATFORM DEFINITIONS -; [Platform (unique identifier)] -; tags=(comma-seperated-tags) -; -; note: the 'identifier' of a platform is the word(s) following the "Platform" keyword (so [Platform pc] means identifier -; is 'pc' for example. This is used to name its assets folder in the cache and should be used in your bootstrap.cfg -; or your main.cpp to choose what assets to load for that particular platform. -; Its primary use is to enable additional non-host platforms (Ios, android...) that are not the current platform. -; note: 'tags' is a comma-seperated list of tags to tag the platform with that builders can inspect to decide what to do. - -; while builders can accept any tags you add in order to make decisions, common tags are -; tools - this platform can host the tools and editor and such -; renderer - this platform runs the client engine and renders on a GPU. If missing we could be on a server-only platform -; mobile - a mobile platform such as a set top box or phone with limited resources -; console - a console platform -; server - a server platform of some kind, usually headless, no renderer. - -[Platform pc] -tags=tools,renderer,dx12,vulkan - -[Platform es3] -tags=android,mobile,renderer,vulkan - -[Platform ios] -tags=mobile,renderer,metal - -[Platform osx_gl] -tags=tools,renderer,metal - -; this is an example of a headless platform that has no renderer. -; To use this you would still need to make sure 'assetplatform' in your startup params in your main() chooses this 'server' platform as your server 'assets' flavor -[Platform server] -tags=server,dx12,vulkan - -; this section allows you to turn on various platforms in addition to the host platform you're running on -; 'enabled' is AUTOMATICALLY TRUE for the current platform that you are running on, so it is not necessary to force it to true for that platform -; To enable any additional platform, just uncomment the appropriate line below. - -[Platforms] -;pc=enabled -;es3=enabled -;ios=enabled -;osx_gl=enabled -;jasper=enabled -;provo=enabled -;salem=enabled -;server=enabled - -; ---- The number of worker jobs, 0 means use the number of Logical Cores -[Jobs] -minJobs=1 -maxJobs=0 - -; cacheServerAddress is the location of the asset server cache. -; Currently for a network share server this would be the absolute file path to the network share folder. -[Server] -;cacheServerAddress= - -; ---- add any metadata file type here that needs to be monitored by the AssetProcessor. -; Modifying these meta file will cause the source asset to re-compile again. -; They are specified in the following format -; metadata extension=original extension to replace -; if the metadata extension does not replace the original, then the original can be blank -; so for example if your normal file is blah.tif and your metafile for that file is blah.tif.exportsettings -; then your declaration would be exportsettings= ; ie, it would be blank -; however if your metafile REPLACES the extension (for example, if you have the file blah.i_caf and its metafile is blah.exportsettings) -; then you specify the original extension here to narrow the scope. -; If a relative path to a specific file is provided instead of an extension, a change to the file will change all files -; with the associated extension (e.g. Animations/SkeletonList.xml=i_caf will cause all i_caf files to recompile when -; Animations/SkeletonList.xml within the current game project changes) - -[MetaDataTypes] -exportsettings= -animsettings=i_caf -Animations/SkeletonList.xml=i_caf -cbc=abc -fbx.assetinfo=fbx - -; ---- add any folders to scan here. The priority order is the order they appear here -; available macros are -; @ROOT@ - the location of engineroot.txt -; @GAMENAME@ - the name of the current game project, for example 'RPGSample' -; note that they are sorted by their 'order' value, and the lower the order the more important an asset is -; lower order numbers override higher ones. -; If specified, output will be prepended to every path found in that recognizer's watch folder. -; Note that you can also make the scan folder platform specific by using the keywords include and exclude. -; Both include and exclude can contain either platform tags, platform identifiers or both. -; if no include is specified, all currently enabled platforms are included by default. -; If includes ARE specified, it will be filtered down by the list of currently enabled platforms. -; [ScanFolder (unique identifier)] -; include = (comma seperated platform tags or identifiers) -; exclude = (comma seperated platform tags or identifiers) -; For example if you want to include a scan folder only for platforms that have the platform tags tools and renderer -; but omit it for platform osx_gl, you will have a scanfolder rule like -; [ScanFolder (unique identifier)] -; watch=@ROOT@/foo -; include = tools, renderer -; exclude = osx_gl - -[ScanFolder Game] -watch=@ROOT@/@GAMENAME@ -display=@GAMENAME@ -recursive=1 -order=0 - -; gems will be auto-added from 100 onwards - -[ScanFolder Root] -watch=@ROOT@ -recursive=0 -order=10000 - -[ScanFolder Engine] -watch=@ENGINEROOT@/Engine -recursive=1 -order=20000 - -[ScanFolder Editor] -watch=@ENGINEROOT@/Editor -output=editor -recursive=1 -order=30000 -include=tools,renderer - - -;Excludes files that match the pattern or glob -; if you use a pattern, remember to escape your backslashes (\\) -[Exclude _LevelBackups] -pattern=.*\\/Levels\\/.*\\/_savebackup\\/.* - -[Exclude _LevelAutoBackups] -pattern=.*\\/Levels\\/.*\\/_autobackup\\/.* - -[Exclude HoldFiles] -pattern=.*\\/Levels\\/.*_hold\\/.* - -[Exclude TempFiles] -; note that $ has meaning to regex, so we escape it. -pattern=.*\\/\\$tmp[0-9]*_.* - -[Exclude AlembicCompressionTemplates] -pattern=.*\\/Presets\\/GeomCache\\/.* - -[Exclude TmpAnimationCompression] -pattern=.*\\/Editor\\/Tmp\\/AnimationCompression\\/.* - -[Exclude EventLog] -pattern=.*\\/Editor\\/.*eventlog\\.xml - -[Exclude GameGemsCode] -pattern=.*\\/Gem\\/Code\\/.* - -[Exclude GameGemsResources] -pattern=.*\\/Gem\\/Resources\\/.* - -[Exclude Private Certs] -pattern=.*\DynamicContent\\/Certificates\\/Private\\/.* - -[Exclude CMakeLists] -pattern=.*\\/CMakeLists.txt - -[Exclude CMakeFiles] -pattern=.*\\/.*\\.cmake - -;------------------------------------------------------------------------------ -; Large Worlds Test -;------------------------------------------------------------------------------ - -[Exclude Work In Progress Folders] -pattern=.*\\/WIP\\/.* - -[Exclude Content Source Folders] -pattern=.*\\/CONTENT_SOURCE\\/.* - -[Exclude Art Source Folders] -pattern=.*\\/ArtSource\\/.* - -;------------------------------------------------------------------------------ -; RC params mapping examples -;------------------------------------------------------------------------------ - -; note that productAssetType is a means of setting the output asset Type (as in AZ::Data::AssetType) of a simple job -; and is the recommended way to specify that a certain kind of file (such as '*.myextension') becomes registered as the -; actual UUID of that type in the engine itself. - -; Use a regex for matching files, same params for all platforms -;[RC TGAs] -;pattern=.+\\.tga$ -;params=/tga /texture - -; Use a glob, have special params for es3 platform -;[RC TIFFs] -;glob=*.tif -;params=/texture -;es3=/pvrt - -; You can also modify a version to compile all matching files again -; By default the version is empty -;[RC tif] -;glob=*.tif -;params = \\someparams -;version =1.0 -; This will make the AssetProcessor compile all the .tif files again - -; you can also optionally supply a priority. -; this is used to sort jobs when no other external circumstance sorts them -; for example, copy jobs will be higher in priority than other jobs that are not copy jobs -; however if they're both copy jobs or both not, and no other circumstances apply, then priority will be used. -; default priority is zero if not specified - -; you can specify an option to skip processing for a file type based on the platform. -; for example, if you dont want to process tif files for ios, you can make tif files -; process on any platform except for ios: -;[RC tif] -;glob=*.tif -;params = \\someparams -;ios=skip - -; you can specify an option to output product dependencies for a copy job. -; please note that you only need to set this option when cry code is required to parse the asset. -; otherwise product dependencies will be output automatically by the CopyDependencyBuilder. -; for example, if you want to output the product dependencies for font assets: -;[RC font] -;glob=*.font -;params=copy -;outputProductDependencies=true - -; you can also specify an option to make all jobs critical that matches some pattern/glob. -; for example, if you want to make all png files critical than set critical to true. -; Note that by default all copy jobs are critical. -; Critical jobs are processed before non critical jobs and also prevent the runtime or editor from starting until they are all complete. -;[RC png] -;glob=*.png -;params = \\someparams -;critical=true - -; you can also specify an option to make all the job store in the asset server cache location if you are running AP in server mode. -; For example, if you want to store all png jobs in the asset server cache location including their logs, you can set checkServer = true. -; The client(i.e if you are running AP in non-server mode) will also check for this flag to know which jobs to fetch from the asset server cache location. -; if unsucessful, it will process the job locally as usual. -;[RC png] -;glob=*.png -;params = \\someparams -;critical=true -;checkServer=true - -; note that the FULL PATH to the file will be used as the match, not the relative path -; so ensure start your patterns with .* or as appropriate. -; Also, any rules which match will apply - so if you have two rules which both apply to PNG files for example -; but you only want one, you might want to use exclusion patterns: - -;Example: process everything EXCEPT the ones in the libs/ui folder with these params -;[RC png-normal] -;pattern=(?!.*libs\\/ui\\/).*\\.png -;params=/imagecompressor=CTSquish /streaming=0 -;lockSource=true - -;Example: Process everything in the libs/ui folder with linear color space -;[RC png-ui] -;pattern=(.*libs\\/ui\\/).*\\.png -;params=/imagecompressor=CTSquish /streaming=0 /colorspace=linear,linear -;lockSource=true - -; More example Regexes: -; pattern=(?!(.*libs\\/ui\\/)|(.*editor\\/).*\\.png -; This pattern will not match anything with editor/ or libs/ui/ in it -; pattern=((.*libs\\/ui\\/)|(.*editor\\/).*\\.png -; This pattern will only match anything with editor/ or libs/ui/ in it - -;Give every [Section Name] its own unique Name or else they will overwrite each other! - -[RC i_caf] -glob=*.i_caf -params=/cafAlignTracks=1 /animConfigFolder=Animations /skipdba=1 /refresh=1 -; force server to send the 'pc' platform to RC.EXE so it compiles the same as PC. -server=/cafAlignTracks=1 /animConfigFolder=Animations /skipdba=1 /refresh=1 /p=pc -priority=5 -productAssetType={6023CFF8-FCBA-4528-A8BF-6E0E10B9AB9C} - -[RC caf] -glob=*.caf -params=copy -productAssetType={6023CFF8-FCBA-4528-A8BF-6E0E10B9AB9C} -; same as above - -[RC mp4] -glob=*.mp4 -params=copy -productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF} - -[RC mkv] -glob=*.mkv -params=copy -productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF} -; same as above - -[RC webm] -glob=*.webm -params=copy -productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF} -; same as above - -[RC mov] -glob=*.mov -params=copy -productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF} -; same as above - -[RC bk2] -glob=*.bk2 -params=copy -productAssetType={BF4879B9-B893-41D2-80E9-24A7BDCD2B50} - -[RC img] -glob=*.img -params=copy - -[RC dba] -glob=*.dba -params=copy -productAssetType={511562BE-65A5-4538-A5F1-AC685366243E} -version=2 - -[RC cgf] -glob=*.cgf -params=/VertexPositionFormat=exporter /VertexIndexFormat=u32 -; on server, feed rc.exe the param /p=pc to force it to compile assets for server platform in pc format. -server=/VertexPositionFormat=exporter /VertexIndexFormat=u32 /p=pc -lockSource=true -priority=10 -; allow CGF files to compile first, so untextured models appear before their textures for faster startup -; other available params: /SplitLODs=1 - -[RC surfaceTagNameList] -glob=*.surfaceTagNameList -params=copy -productAssetType={A471B2A9-85FC-4993-842D-1881CBC03A2B} - -[RC gradImageSettings] -glob=*.gradimagesettings -params=copy -productAssetType={B36FEB5C-41B6-4B58-A212-21EF5AEF523C} - -[RC fbx] -glob=*.fbx -; Priority set to 9 so its "before" things like materials but after things like actors and motions (which build using a proper AssetBuilderSDK builder and thus are not in this file) -priority=9 -version=5 - -[RC chr] -glob=*.chr -params=copy -productAssetType={60161B46-21F0-4396-A4F0-F2CCF0664CDE} -version=2 - -[RC skin] -glob=*.skin -params=copy - -[RC cfi] -glob=*.cfi -params=copy - -[RC cfx] -glob=*.cfx -params=copy - -[RC cfr] -glob=*.cfr -params=copy - -; Warning: If you change the VertexIndexFormat, make sure you update the vtx_idx typedef in Code\CryEngine\CryCommon\ProjectDefines.h -[RC abc] -glob=*.abc -params=/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u32 -console=/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u32 -mobile=/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u16 -version=3 -server=skip - -[RC png-entityicon] -pattern=(.*EntityIcons\\/).*\\.png -productAssetType={3436C30E-E2C5-4C3B-A7B9-66C94A28701B} -params=skip ; only tools-supporting platforms should copy this file. Everyone else can skip. -tools=copy - -[RC usm] -glob=*.usm -params=copy -server=skip - -[RC animevents] -glob=*.animevents -params=copy -productAssetType={C1D209C1-F81A-4586-A34E-1615995F9F3F} -version=2 - -[RC adb] -glob=*.adb -params=copy -productAssetType={50908273-CA36-4668-9828-15DD5092F973} - -[RC bspace] -glob=*.bspace -params=copy - -[RC cdf] -glob=*.cdf -params=copy -productAssetType={DF036C63-9AE6-4AC3-A6AC-8A1D76126C01} -; note - this used to be skinnedMeshAsset but its now Character Definition File specific. -; .skin has its own type. - -[RC chrparams] -glob=*.chrparams -params=copy -productAssetType={4BBB785A-6824-4803-A607-F9323E7BEEF1} -version=2 - -[RC comb] -glob=*.comb -params=copy - -[RC dlg] -glob=*.dlg -params=copy - -[RC csv] -glob=*.csv -params=copy - -[RC json] -glob=*.json -params=copy - -[RC lmg] -glob=*.lmg -params=copy - -[RC smtl] -glob=*.smtl -params=copy - -[RC sub] -glob=*.sub -params=copy -productAssetType={71F9D30E-13F7-40D6-A3C9-E5358004B31F} -version=2 - -[RC sbsar] -glob=*.sbsar -params=copy - -[RC loc.agsxml] -glob=*.loc.agsxml -params=copy -version=1 - -[RC node] -glob=*.node -params=copy - -[RC veg] -glob=*.veg -params=copy - -[RC dat] -glob=*.dat -params=copy - -[RC lut] -glob=*.lut -params=copy - -[RC txt] -pattern=^(?!.*PreloadLibs.txt).*\\.txt -params=copy - -[RC cal] -glob=*.cal -params=copy - -[RC grp] -glob=*.grp -params=copy -productAssetType={7629EDD3-A361-49A2-B271-252127097D81} -version=2 - -[RC xls] -glob=*.xls -params=copy - -[RC ini] -glob=*.ini -params=copy - -[RC ttf] -glob=*.ttf -params=copy - -[RC otf] -glob=*.otf -params=copy - -[RC ext] -glob=*.ext -params=copy - -[RC pak] -; Copy all pak files except level.pak, level.pak has its own builder. -pattern=^((?!\\/level\\.pak).)*\\.pak$ -params=copy - -[RC ctc] -glob=*.ctc -params=copy - -[RC uiprefab] -glob=*.uiprefab -params=copy -server=skip - -[RC sprite] -glob=*.sprite -params=copy -server=skip - -[RC bin] -glob=*.bin -params=copy - -[RC inputbindings] -glob=*.inputbindings -params=copy -productAssetType={25971C7A-26E2-4D08-A146-2EFCC1C36B0C} - -[RC physmaterial] -glob=*.physmaterial -params=copy -productAssetType={9E366D8C-33BB-4825-9A1F-FA3ADBE11D0F} - -[RC ocm] -glob=*.ocm -params=copy - -; Feature tests use the raw .tif files for the golden image comparison -[RC goldenimages] -pattern=.*GoldenImages\\/.*\\.tif -params=copy -server=skip - -; Copy over certificates for use with FileDataSource -[RC CertificatePEM] -glob=*.pem -params=copy - -; Copy over certificates for use with Dynamic Content -[RC CertificateDER] -glob=*.der -params=copy - -[RC PhysXMeshAsset] -glob=*.pxmesh -params=copy -productAssetType={7A2871B9-5EAB-4DE0-A901-B0D2C6920DDB} - -; Copy over cooked PhysX heightfield -[RC PhysX HeightField] -glob=*.pxheightfield -params=copy -productAssetType={B61189FE-B2D7-4AF1-8951-CB5C0F7834FC} - -[RC filetag] -glob=*.filetag -params=copy -productAssetType={F3BE5CAB-85B7-44B7-9495-863863F6B267} - -; Precompiled shader srg -[RC azsrg] -glob=*.azsrg -params=copy -productAssetType={F8C9F4AE-3F6A-45AD-B4FB-0CA415FCC2E1} - -; Precompiled shader variant -[RC azshadervariant] -glob=*.azshadervariant -params=copy -productAssetType={9F4D654B-4439-4C61-8DCD-F1C7C5560768} diff --git a/Engine/Registry/AssetProcessorPlatformConfig.setreg b/AssetProcessorPlatformConfig.setreg similarity index 50% rename from Engine/Registry/AssetProcessorPlatformConfig.setreg rename to AssetProcessorPlatformConfig.setreg index 27fd752210..c075342b98 100644 --- a/Engine/Registry/AssetProcessorPlatformConfig.setreg +++ b/AssetProcessorPlatformConfig.setreg @@ -1,4 +1,23 @@ { + // ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default. + + // PLATFORM DEFINITIONS + // [Platform (unique identifier)] + // tags=(comma-seperated-tags) + // + // note: the 'identifier' of a platform is the word(s) following the "Platform" keyword (so [Platform pc] means identifier + // is 'pc' for example. This is used to name its assets folder in the cache and should be used in your bootstrap.cfg + // or your main.cpp to choose what assets to load for that particular platform. + // Its primary use is to enable additional non-host platforms (Ios, android...) that are not the current platform. + // note: 'tags' is a comma-seperated list of tags to tag the platform with that builders can inspect to decide what to do. + + // while builders can accept any tags you add in order to make decisions, common tags are + // tools - this platform can host the tools and editor and such + // renderer - this platform runs the client engine and renders on a GPU. If missing we could be on a server-only platform + // mobile - a mobile platform such as a set top box or phone with limited resources + // console - a console platform + // server - a server platform of some kind, usually headless, no renderer. + "Amazon": { "AssetProcessor": { "Settings": { @@ -14,27 +33,82 @@ "Platform osx_gl": { "tags": "tools,renderer,metal" }, + // this is an example of a headless platform that has no renderer. + // To use this you would still need to make sure 'assetplatform' in your startup params in your main() chooses this 'server' platform as your server 'assets' flavor "Platform server": { "tags": "server,dx12,vulkan" }, + // this section allows you to turn on various platforms in addition to the host platform you're running on + // 'enabled' is AUTOMATICALLY TRUE for the current platform that you are running on, so it is not necessary to force it to true for that platform + // To enable any additional platform, just uncomment the appropriate line below. + "Platforms": { + //"pc": "enabled", + //"es3": "enabled", + //"ios": "enabled", + //"osx_gl": "enabled", + //"server": "enabled" + }, + // ---- The number of worker jobs, 0 means use the number of Logical Cores "Jobs": { "minJobs": 1, "maxJobs": 0 }, + // cacheServerAddress is the location of the asset server cache. + // Currently for a network share server this would be the absolute file path to the network share folder. + "Server": { + //"cacheServerAddress": "" + }, + + // ---- add any metadata file type here that needs to be monitored by the AssetProcessor. + // Modifying these meta file will cause the source asset to re-compile again. + // They are specified in the following format + // metadata extension=original extension to replace + // if the metadata extension does not replace the original, then the original can be blank + // so for example if your normal file is blah.tif and your metafile for that file is blah.tif.exportsettings + // then your declaration would be exportsettings= ; ie, it would be blank + // however if your metafile REPLACES the extension (for example, if you have the file blah.i_caf and its metafile is blah.exportsettings) + // then you specify the original extension here to narrow the scope. + // If a relative path to a specific file is provided instead of an extension, a change to the file will change all files + // with the associated extension (e.g. Animations/SkeletonList.xml=i_caf will cause all i_caf files to recompile when + // Animations/SkeletonList.xml within the current game project changes) + "MetaDataTypes": { "animsettings": "i_caf", - "Animations": { - "SkeletonList.xml": "i_caf" - }, + "Animations/SkeletonList.xml": "i_caf", "cbc": "abc", "fbx.assetinfo": "fbx" }, + + // ---- add any folders to scan here. The priority order is the order they appear here + // available macros are + // @ROOT@ - the location of asset root + // @PROJECTROOT@ - the location of the project root, for example 'Q:\MyProjects\RPGSample' + // note that they are sorted by their 'order' value, and the lower the order the more important an asset is + // lower order numbers override higher ones. + // If specified, output will be prepended to every path found in that recognizer's watch folder. + // Note that you can also make the scan folder platform specific by using the keywords include and exclude. + // Both include and exclude can contain either platform tags, platform identifiers or both. + // if no include is specified, all currently enabled platforms are included by default. + // If includes ARE specified, it will be filtered down by the list of currently enabled platforms. + // "ScanFolder (unique identifier)": { + // "include": "(comma seperated platform tags or identifiers)", + // "exclude": "(comma seperated platform tags or identifiers)" + // } + // For example if you want to include a scan folder only for platforms that have the platform tags tools and renderer + // but omit it for platform osx_gl, you will have a scanfolder rule like + // "ScanFolder (unique identifier)": { + // "watch": "@ROOT@/foo", + // "include": "tools, renderer", + // "exclude": "osx_gl" + // } + "ScanFolder Game": { - "watch": "@ROOT@/@GAMENAME@", - "display": "@GAMENAME@", + "watch": "@PROJECTROOT@", + "display": "@PROJECTROOT@", "recursive": 1, "order": 0 }, + // gems will be auto-added from 100 onwards "ScanFolder Root": { "watch": "@ROOT@", "recursive": 0, @@ -52,6 +126,9 @@ "order": 30000, "include": "tools,renderer" }, + + // Excludes files that match the pattern or glob + // if you use a pattern, remember to escape your backslashes (\\) "Exclude _LevelBackups": { "pattern": ".*\\\\/Levels\\\\/.*\\\\/_savebackup\\\\/.*" }, @@ -61,6 +138,7 @@ "Exclude HoldFiles": { "pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*" }, + // note that $ has meaning to regex, so we escape it. "Exclude TempFiles": { "pattern": ".*\\\\/\\\\$tmp[0-9]*_.*" }, @@ -88,6 +166,16 @@ "Exclude CMakeFiles": { "pattern": ".*\\\\/.*\\\\.cmake" }, + "Exclude User": { + "pattern": ".*/[Uu]ser/.*" + }, + "Exclude Build": { + "pattern": ".*/[Bb]uild/.*" + }, + + // ------------------------------------------------------------------------------ + // Large Worlds Test + // ------------------------------------------------------------------------------ "Exclude Work In Progress Folders": { "pattern": ".*\\\\/WIP\\\\/.*" }, @@ -97,9 +185,112 @@ "Exclude Art Source Folders": { "pattern": ".*\\\\/ArtSource\\\\/.*" }, + //------------------------------------------------------------------------------ + // RC params mapping examples + //------------------------------------------------------------------------------ + + // note that productAssetType is a means of setting the output asset Type (as in AZ::Data::AssetType) of a simple job + // and is the recommended way to specify that a certain kind of file (such as '*.myextension') becomes registered as the + // actual UUID of that type in the engine itself. + + // Use a regex for matching files, same params for all platforms + // "RC TGAs": { + // "pattern": ".+\\\\.tga$", + // "params": "/tga /texture" + //} + + // Use a glob, have special params for es3 platform + // "RC TIFFs": { + // "glob": "*.tif", + // "params": "/texture", + // "es3": "/pvrt" + //} + + // You can also modify a version to compile all matching files again + // By default the version is empty + // "RC tif": { + // "glob": "*.tif", + // "params": "\\someparams", + // "version": 1.0 + //} + // This will make the AssetProcessor compile all the .tif files again + + // you can also optionally supply a priority. + // this is used to sort jobs when no other external circumstance sorts them + // for example, copy jobs will be higher in priority than other jobs that are not copy jobs + // however if they're both copy jobs or both not, and no other circumstances apply, then priority will be used. + // default priority is zero if not specified + + // you can specify an option to skip processing for a file type based on the platform. + // for example, if you dont want to process tif files for ios, you can make tif files + // process on any platform except for ios: + // "RC tif": { + // "glob": "*.tif", + // "params": "\\someparams", + // "ios": "skip" + //} + + // you can specify an option to output product dependencies for a copy job. + // please note that you only need to set this option when cry code is required to parse the asset. + // otherwise product dependencies will be output automatically by the CopyDependencyBuilder. + // for example, if you want to output the product dependencies for font assets: + // "RC font": { + // "glob": "*.font", + // "params": "copy", + // "outputProductDependencies": true + //} + + // you can also specify an option to make all jobs critical that matches some pattern/glob. + // for example, if you want to make all png files critical than set critical to true. + // Note that by default all copy jobs are critical. + // Critical jobs are processed before non critical jobs and also prevent the runtime or editor from starting until they are all complete. + // "RC png": { + // "glob": "*.png", + // "params": "\\someparams", + // "critical": true + //} + + // you can also specify an option to make all the job store in the asset server cache location if you are running AP in server mode. + // For example, if you want to store all png jobs in the asset server cache location including their logs, you can set checkServer = true. + // The client(i.e if you are running AP in non-server mode) will also check for this flag to know which jobs to fetch from the asset server cache location. + // if unsucessful, it will process the job locally as usual. + // "RC png": { + // "glob": "*.png", + // "params": "\\someparams", + // "critical": true, + // "checkServer": true + //} + + // note that the FULL PATH to the file will be used as the match, not the relative path + // so ensure start your patterns with .* or as appropriate. + // Also, any rules which match will apply - so if you have two rules which both apply to PNG files for example + // but you only want one, you might want to use exclusion patterns: + + //Example: process everything EXCEPT the ones in the libs/ui folder with these params + // "RC png-normal": { + // "pattern": "(?!.*libs\\\\/ui\\\\/).*\\.png", + // "params": "/imagecompressor=CTSquish /streaming=0", + // "lockSource": true + //} + + //Example: Process everything in the libs/ui folder with linear color space + // "RC png-ui": { + // "pattern": "(.*libs\\\\/ui\\\\/).*\\.png", + // "params": "/imagecompressor=CTSquish /streaming=0 /colorspace=linear,linear", + // "lockSource": true + //} + + // More example Regexes: + // "pattern": "(?!(.*libs\\\\/ui\\\\/)|(.*editor\\\\/).*\\\\.png" + // This pattern will not match anything with editor/ or libs/ui/ in it + // "pattern": "((.*libs\\\\/ui\\\\/)|(.*editor\\\\/).*\\\\.png" + // This pattern will only match anything with editor/ or libs/ui/ in it + + // Give every [Section Name] its own unique Name or else they will overwrite each other! "RC i_caf": { "glob": "*.i_caf", "params": "/cafAlignTracks=1 /animConfigFolder=Animations /skipdba=1 /refresh=1", + // force server to send the 'pc' platform to RC.EXE so it compiles the same as PC. "server": "/cafAlignTracks=1 /animConfigFolder=Animations /skipdba=1 /refresh=1 /p=pc", "priority": 5, "productAssetType": "{6023CFF8-FCBA-4528-A8BF-6E0E10B9AB9C}" @@ -147,9 +338,12 @@ "RC cgf": { "glob": "*.cgf", "params": "/VertexPositionFormat=exporter /VertexIndexFormat=u32", + // on server, feed rc.exe the param /p=pc to force it to compile assets for server platform in pc format. "server": "/VertexPositionFormat=exporter /VertexIndexFormat=u32 /p=pc", "lockSource": true, "priority": 10 + // allow CGF files to compile first, so untextured models appear before their textures for faster startup + // other available params: /SplitLODs=1 }, "RC surfaceTagNameList": { "glob": "*.surfaceTagNameList", @@ -163,8 +357,9 @@ }, "RC fbx": { "glob": "*.fbx", + // Priority set to 9 so its "before" things like materials but after things like actors and motions (which build using a proper AssetBuilderSDK builder and thus are not in this file) "priority": 9, - "version": 4 + "version": 5 }, "RC chr": { "glob": "*.chr", @@ -188,6 +383,7 @@ "glob": "*.cfr", "params": "copy" }, + // Warning: If you change the VertexIndexFormat, make sure you update the vtx_idx typedef in Code\CryEngine\CryCommon\ProjectDefines.h "RC abc": { "glob": "*.abc", "params": "/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u32", @@ -199,7 +395,7 @@ "RC png-entityicon": { "pattern": "(.*EntityIcons\\\\/).*\\\\.png", "productAssetType": "{3436C30E-E2C5-4C3B-A7B9-66C94A28701B}", - "params": "skip ; only tools-supporting platforms should copy this file. Everyone else can skip.", + "params": "skip", "tools": "copy" }, "RC usm": { @@ -227,6 +423,9 @@ "params": "copy", "productAssetType": "{DF036C63-9AE6-4AC3-A6AC-8A1D76126C01}" }, + // note - this used to be skinnedMeshAsset but its now Character Definition File specific. + // .skin has its own type. + "RC chrparams": { "glob": "*.chrparams", "params": "copy", @@ -272,13 +471,6 @@ "params": "copy", "version": 1 }, - "RC Editor Slice Copy": { - "glob": "*.slice", - "params": "copy", - "critical": true, - "productAssetType": "{C62C7A87-9C09-4148-A985-12F2C99C0A45}", - "priority": 2 - }, "RC node": { "glob": "*.node", "params": "copy" @@ -329,6 +521,7 @@ "glob": "*.ext", "params": "copy" }, + // Copy all pak files except level.pak, level.pak has its own builder. "RC pak": { "pattern": "^((?!\\\\/level\\\\.pak).)*\\\\.pak$", "params": "copy" @@ -365,15 +558,18 @@ "glob": "*.ocm", "params": "copy" }, + // Feature tests use the raw .tif files for the golden image comparison "RC goldenimages": { "pattern": ".*GoldenImages\\\\/.*\\\\.tif", "params": "copy", "server": "skip" }, + // Copy over certificates for use with FileDataSource "RC CertificatePEM": { "glob": "*.pem", "params": "copy" }, + // Copy over certificates for use with Dynamic Content "RC CertificateDER": { "glob": "*.der", "params": "copy" @@ -383,6 +579,7 @@ "params": "copy", "productAssetType": "{7A2871B9-5EAB-4DE0-A901-B0D2C6920DDB}" }, + // Copy over cooked PhysX heightfield "RC PhysX HeightField": { "glob": "*.pxheightfield", "params": "copy", @@ -392,8 +589,20 @@ "glob": "*.filetag", "params": "copy", "productAssetType": "{F3BE5CAB-85B7-44B7-9495-863863F6B267}" + }, + // Precompiled shader srg + "RC azsrg": { + "glob": "*.azsrg", + "params": "copy", + "productAssetType": "{F8C9F4AE-3F6A-45AD-B4FB-0CA415FCC2E1}" + }, + // Precompiled shader variant + "RC azshadervariant": { + "glob": "*.azshadervariant", + "params": "copy", + "productAssetType": "{9F4D654B-4439-4C61-8DCD-F1C7C5560768}" } } } } -} \ No newline at end of file +} diff --git a/AutomatedReview/Jenkinsfile b/AutomatedReview/Jenkinsfile index 0a3d4ad7e9..ac2c871736 100644 --- a/AutomatedReview/Jenkinsfile +++ b/AutomatedReview/Jenkinsfile @@ -119,6 +119,7 @@ def LoadPipelineConfig(String pipelineName, String branchName) { PullFilesFromGit(PIPELINE_CONFIG_FILE, branchName) def pipelineConfig = {} pipelineConfig = readJSON file: PIPELINE_CONFIG_FILE + palRm(PIPELINE_CONFIG_FILE) pipelineConfig.platforms = EMPTY_JSON // Load the pipeline configs per platform @@ -137,6 +138,7 @@ def LoadPipelineConfig(String pipelineName, String branchName) { pipelineConfig.platforms[platform] = EMPTY_JSON pipelineConfig.platforms[platform].PIPELINE_ENV = readJSON file: pipeline_config_path.toString() } + palRm(pipeline_config_path.toString()) } } @@ -155,6 +157,7 @@ def LoadPipelineConfig(String pipelineName, String branchName) { if(platform) { pipelineConfig.platforms[platform].build_types = readJSON file: build_config_path.toString() } + palRm(build_config_path.toString()) } } return pipelineConfig @@ -202,39 +205,45 @@ def PullFilesFromGit(String filenamePath, String branchName, boolean failIfNotFo folderPathParts.remove(folderPathParts.size()-1) // remove the filename def folderPath = folderPathParts.join('/') if (folderPath.contains('*')) { - - def currentPath = '' - for (int i = 0; i < folderPathParts.size(); i++) { - if (folderPathParts[i] == '*') { - palMkdir(currentPath) - retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${currentPath} > ${currentPath}/.codecommit", "GetFolder ${currentPath}") } - def folderInfo = readJSON file: "${currentPath}/.codecommit" - folderInfo.subFolders.each { folder -> - def newSubPath = currentPath + '/' + folder.relativePath - for (int j = i+1; j < folderPathParts.size(); j++) { - newSubPath = newSubPath + '/' + folderPathParts[j] + + try { + def currentPath = '' + for (int i = 0; i < folderPathParts.size(); i++) { + if (folderPathParts[i] == '*') { + palMkdir(currentPath) + retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${currentPath} > ${currentPath}/.codecommit", "GetFolder ${currentPath}") } + def folderInfo = readJSON file: "${currentPath}/.codecommit" + folderInfo.subFolders.each { folder -> + def newSubPath = currentPath + '/' + folder.relativePath + for (int j = i+1; j < folderPathParts.size(); j++) { + newSubPath = newSubPath + '/' + folderPathParts[j] + } + newSubPath = newSubPath + '/' + filename + PullFilesFromGit(newSubPath, branchName, false, repositoryName) } - newSubPath = newSubPath + '/' + filename - PullFilesFromGit(newSubPath, branchName, false, repositoryName) + palRm("${currentPath}/.codecommit") + } + if (i == 0) { + currentPath = folderPathParts[i] + } else { + currentPath = currentPath + '/' + folderPathParts[i] } - palRm("${currentPath}/.codecommit") - } - if (i == 0) { - currentPath = folderPathParts[i] - } else { - currentPath = currentPath + '/' + folderPathParts[i] } + } catch(Exception e) { } } else if (filename.contains('*')) { - palMkdir(folderPath) - retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${folderPath} > ${folderPath}/.codecommit", "GetFolder ${folderPath}") } - def folderInfo = readJSON file: "${folderPath}/.codecommit" - folderInfo.files.each { file -> - PullFilesFromGit("${folderPath}/${filename}", branchName, false, repositoryName) + try { + palMkdir(folderPath) + retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${folderPath} > ${folderPath}/.codecommit", "GetFolder ${folderPath}") } + def folderInfo = readJSON file: "${folderPath}/.codecommit" + folderInfo.files.each { file -> + PullFilesFromGit("${folderPath}/${filename}", branchName, false, repositoryName) + } + palRm("${folderPath}/.codecommit") + } catch(Exception e) { } - palRm("${folderPath}/.codecommit") } else { @@ -271,18 +280,7 @@ def PullFilesFromGit(String filenamePath, String branchName, boolean failIfNotFo } } -def SetLfsCredentials(cmd, lbl = '') { - if (env.IS_UNIX) { - sh label: lbl, - script: cmd - } else { - bat label: lbl, - script: cmd - } -} - def CheckoutRepo(boolean disableSubmodules = false) { - palSh('git lfs uninstall', 'Git LFS Uninstall') // Prevent git from pulling lfs objects during checkout if(fileExists('.git')) { // If the repository after checkout is locked, likely we took a snapshot while git was running, @@ -292,7 +290,7 @@ def CheckoutRepo(boolean disableSubmodules = false) { palSh('git gc', 'Git GarbageCollect') } if(fileExists(indexLockFile)) { // if it is still there, remove it - palRm(indexLockFile, 'Remove index.lock') + palRm(indexLockFile) } palSh('git remote prune origin', 'Git reset') } @@ -329,14 +327,6 @@ def CheckoutRepo(boolean disableSubmodules = false) { } } - // Run lfs in a separate step. Jenkins is unable to load the credentials for the custom LFS endpoint - withCredentials([usernamePassword(credentialsId: "${env.GITHUB_USER}", passwordVariable: 'accesstoken', usernameVariable: 'username')]) { - SetLfsCredentials("git config -f .lfsconfig lfs.url https://${username}:${accesstoken}@${env.LFS_URL}", 'Set credentials') - } - palSh('git lfs install', 'Git LFS Install') - palSh('git lfs pull', 'Git LFS Pull') -} - // CHANGE_ID is used by some scripts to identify uniquely the current change (usually metric jobs) palSh('git rev-parse HEAD > commitid', 'Getting commit id') env.CHANGE_ID = readFile file: 'commitid' @@ -406,6 +396,26 @@ def Build(Map options, String platform, String type, String workspace) { } } +def TestMetrics(Map options, Map buildType, String workspace, String branchName, String repoName) { + catchError(buildResult: null, stageResult: null) { + def cmakeBuildDir = [workspace, buildType.value.PARAMETERS.OUTPUT_DIRECTORY].join('/') + def command = "${options.PYTHON_DIR}/python.cmd -u mars/scripts/python/ctest_test_metric_scraper.py -e jenkins.creds.user ${username} -e jenkins.creds.pass ${apitoken} ${cmakeBuildDir} ${branchName} %BUILD_NUMBER% AR ${buildType.value.PARAMETERS.CONFIGURATION} ${repoName} " + if (params.DESTINATION_BRANCH) + command += '--destination-branch "$DESTINATION_BRANCH" ' + dir(workspace) { + checkout scm: [ + $class: 'GitSCM', + extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'mars']], + userRemoteConfigs: [[url: "${env.MARS_REPO}", name: 'mars']] + ] + withCredentials([usernamePassword(credentialsId: "${env.SERVICE_USER}", passwordVariable: 'apitoken', usernameVariable: 'username')]) { + bat label: "Publishing ${buildType.key} Test Metrics", + script: command + } + } + } +} + def PostBuildCommonSteps(String workspace, boolean mount = true) { echo 'Starting post-build common steps...' @@ -448,6 +458,14 @@ def CreateBuildStage(Map pipelineConfig, String platformName, String jobName, Ma } } +def CreateTestMetricsStage(Map pipelineConfig, Map buildJob, String branchName, Map environmentVars) { + return { + stage("${buildJob.key}") { + TestMetrics(pipelineConfig, buildJob, environmentVars['WORKSPACE'], branchName, env.DEFAULT_REPOSITORY_NAME) + } + } +} + def CreateTeardownStage(Map environmentVars) { return { stage("Teardown") { @@ -538,6 +556,9 @@ try { } else { CreateBuildStage(pipelineConfig, platform.key, build_job.key, envVars).call() } + if (env.MARS_REPO && platform.key == 'Windows' && build_job.key.startsWith('test')) { + CreateTestMetricsStage(pipelineConfig, build_job, branchName, envVars).call() + } } catch(Exception e) { // https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/model/Result.java diff --git a/AutomatedTesting/CMakeLists.txt b/AutomatedTesting/CMakeLists.txt index b0e448ed83..b2d9a18c6a 100644 --- a/AutomatedTesting/CMakeLists.txt +++ b/AutomatedTesting/CMakeLists.txt @@ -9,4 +9,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +file(READ "${CMAKE_CURRENT_LIST_DIR}/project.json" project_json) + +string(JSON project_target_name ERROR_VARIABLE json_error GET ${project_json} "project_name") +if(${json_error}) + message(FATAL_ERROR "Unable to read key 'project_name' from 'project.json'") +endif() + +set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) add_subdirectory(Gem) diff --git a/AutomatedTesting/Config/Editor.xml b/AutomatedTesting/Config/Editor.xml deleted file mode 100644 index 03e69401d3..0000000000 --- a/AutomatedTesting/Config/Editor.xml +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Config/Game.xml b/AutomatedTesting/Config/Game.xml deleted file mode 100644 index f00e94a04d..0000000000 --- a/AutomatedTesting/Config/Game.xml +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Config/Server.xml b/AutomatedTesting/Config/Server.xml deleted file mode 100644 index af195f8516..0000000000 --- a/AutomatedTesting/Config/Server.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Gem/AssetProcessorGemConfig.ini b/AutomatedTesting/Gem/AssetProcessorGemConfig.ini deleted file mode 100644 index cc69bfdaa3..0000000000 --- a/AutomatedTesting/Gem/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,16 +0,0 @@ -; The PythonTest folder contains benchmarksettings test assets that should only get processed when -; the test is run, and the assets are temporarily copied to a separate folder. -[Exclude PythonTest Benchmark Settings Assets] -pattern=.*\\/PythonTests\\/.*benchmarksettings - -[Exclude fbx_tests] -pattern=.*\\/fbx_tests\\/assets\\/.* - -[Exclude wwise_bank_dependency_tests] -pattern=.*\\/wwise_bank_dependency_tests\\/assets\\/.* - -[Exclude AssetProcessorTestAssets] -pattern=.*\\/asset_processor_tests\\/assets\\/.* - -[Exclude Restricted AssetProcessorTestAssets] -pattern=.*\\/asset_processor_tests\\/restricted\\/.* diff --git a/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg b/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..043774c9cc --- /dev/null +++ b/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg @@ -0,0 +1,23 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "Exclude PythonTest Benchmark Settings Assets": { + "pattern": ".*\\\\/PythonTests\\\\/.*benchmarksettings" + }, + "Exclude fbx_tests": { + "pattern": ".*\\\\/fbx_tests\\\\/assets\\\\/.*" + }, + "Exclude wwise_bank_dependency_tests": { + "pattern": ".*\\\\/wwise_bank_dependency_tests\\\\/assets\\\\/.*" + }, + "Exclude AssetProcessorTestAssets": { + "pattern": ".*\\\\/asset_processor_tests\\\\/assets\\\\/.*" + }, + "Exclude Restricted AssetProcessorTestAssets": { + "pattern": ".*\\\\/asset_processor_tests\\\\/restricted\\\\/.*" + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index cb71f7f96a..a787fb84fa 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -30,6 +30,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryRenderNULL AZ::AssetProcessor AutomatedTesting.Assets + COMPONENT + Physics ) ly_add_pytest( NAME AutomatedTesting::PhysicsTests_Sandbox @@ -42,6 +44,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryRenderNULL AZ::AssetProcessor AutomatedTesting.Assets + COMPONENT + Physics ) endif() @@ -49,7 +53,7 @@ endif() if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_pytest( NAME AutomatedTesting::ScriptCanvasTests - TEST_SUITE main + TEST_SUITE periodic TEST_SERIAL PATH ${CMAKE_CURRENT_LIST_DIR}/scripting/TestSuite_Active.py TIMEOUT 3600 @@ -58,6 +62,20 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryRenderNULL AZ::AssetProcessor AutomatedTesting.Assets + COMPONENT + ScriptCanvas + ) + ly_add_pytest( + NAME AutomatedTesting::ScriptCanvasTests_Sandbox + TEST_SUITE sandbox + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/scripting/TestSuite_Sandbox.py + TIMEOUT 3600 + RUNTIME_DEPENDENCIES + Legacy::Editor + Legacy::CryRenderNULL + AZ::AssetProcessor + AutomatedTesting.Assets ) endif() @@ -74,6 +92,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryRenderNULL AZ::AssetProcessor AutomatedTesting.Assets + COMPONENT + WhiteBox ) endif() @@ -108,7 +128,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AssetProcessor AutomatedTesting.Assets Gem::EditorPythonBindings.Editor - COMPONENT TestTools + COMPONENT TestTools ) endif() @@ -136,7 +156,6 @@ include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED) ## DynVeg ## - ly_add_pytest( NAME DynamicVegetationTests_Main_NoGPU TEST_SERIAL @@ -150,6 +169,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ AutomatedTesting.GameLauncher AutomatedTesting.Assets Legacy::CryRenderNULL + COMPONENT + LargeWorlds ) ly_add_pytest( @@ -165,6 +186,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ AutomatedTesting.GameLauncher AutomatedTesting.Assets Legacy::CryRenderNULL + COMPONENT + LargeWorlds ) ly_add_pytest( @@ -179,10 +202,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ Legacy::Editor AutomatedTesting.Assets Legacy::CryRenderNULL + COMPONENT + LargeWorlds ) ## LandscapeCanvas ## - ly_add_pytest( NAME LandscapeCanvasTests_Main TEST_SERIAL @@ -194,6 +218,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ Legacy::Editor AutomatedTesting.Assets Legacy::CryRenderNULL + COMPONENT + LargeWorlds ) ## GradientSignal ## @@ -209,6 +235,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ Legacy::Editor AutomatedTesting.Assets Legacy::CryRenderNULL + COMPONENT + LargeWorlds ) ly_add_pytest( @@ -222,6 +250,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ Legacy::Editor AutomatedTesting.Assets Legacy::CryRenderNULL + COMPONENT + LargeWorlds ) endif() @@ -239,6 +269,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ Legacy::CryRenderNULL AZ::AssetProcessor AutomatedTesting.Assets + COMPONENT + Editor ) endif() diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_all_platforms_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_all_platforms_setup_fixture.py index 5a85d2de90..e4999a28f8 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_all_platforms_setup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_all_platforms_setup_fixture.py @@ -24,7 +24,7 @@ from . import ap_setup_fixture as ap_setup_fixture def ap_all_platforms_setup_fixture(request, workspace, ap_setup_fixture) -> Dict[str, str]: dev_dir = os.path.join(workspace.paths.dev()) - cache_dir = os.path.join(dev_dir, "Cache") + cache_dir = workspace.paths.cache() # add some useful locations resources = ap_setup_fixture @@ -33,11 +33,11 @@ def ap_all_platforms_setup_fixture(request, workspace, ap_setup_fixture) -> Dict resources["platform_cache"] = os.path.join(workspace.paths.platform_cache(), workspace.project.lower()) # Specific platform cache locations - resources["pc_cache_location"] = os.path.join(cache_dir, workspace.project, "pc") - resources["es3_cache_location"] = os.path.join(cache_dir, workspace.project, "es3") - resources["ios_cache_location"] = os.path.join(cache_dir, workspace.project, "ios") - resources["osx_gl_cache_location"] = os.path.join(cache_dir, workspace.project, "osx_gl") - resources["provo_cache_location"] = os.path.join(cache_dir, workspace.project, "provo") + resources["pc_cache_location"] = os.path.join(cache_dir, "pc") + resources["es3_cache_location"] = os.path.join(cache_dir, "es3") + resources["ios_cache_location"] = os.path.join(cache_dir, "ios") + resources["osx_gl_cache_location"] = os.path.join(cache_dir, "osx_gl") + resources["provo_cache_location"] = os.path.join(cache_dir, "provo") resources["all_platforms"] = ["pc", "es3", "ios", "osx_gl", "provo"] return resources diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_external_project_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_external_project_setup_fixture.py index 0b3b22aaca..553427dd17 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_external_project_setup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_external_project_setup_fixture.py @@ -52,7 +52,7 @@ def ap_external_project_setup_fixture(request, workspace) -> Dict: paths = mock() paths.asset_processor = lambda: resources["ap_path"] paths.asset_processor_batch = lambda: resources["ap_batch_path"] - paths.asset_processor_config_file = lambda: os.path.join(resources["project_dir"], "AssetProcessorConfig.ini") + paths.asset_processor_config_file = lambda: os.path.join(resources["project_dir"], "AssetProcessorConfig.setreg") mock_workspace.paths = paths resources["external_workspace"] = mock_workspace diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests_2.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests_2.py index db6c675bdb..00b04f1847 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests_2.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests_2.py @@ -163,7 +163,7 @@ class TestsAssetProcessorBatch_AllPlatforms(object): assert errors == 0, f"There were {errors} asset processing errors" # Check that project cache was created (DNE until AP makes it) - project_cache = os.path.join(external_resources["project_dir"], "Cache", external_resources["project_name"]) + project_cache = os.path.join(external_resources["project_dir"], "Cache") assert os.path.exists(project_cache), f"{project_cache} was not created by AP" # Clean up external project @@ -273,7 +273,8 @@ class TestsAssetProcessorBatch_Windows(object): "AssetProcessor: Error: Platform in config file or command line 'notaplatform'" should be present in the logs """ asset_processor.create_temp_asset_root() - error_search_terms = "AssetProcessor: Error: Platform in config file or command line 'notaplatform'" + error_search_terms = 'AssetProcessor: Error: The list of enabled platforms in the settings registry does not contain platform ' \ + '"notaplatform"' # Run APBatch expecting it to fail asset_processor.run_and_check_output(True, error_search_terms, platforms='notaplatform') diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_gui_tests_2.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_gui_tests_2.py index 9a7ad478aa..47dfaa6e8a 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_gui_tests_2.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_gui_tests_2.py @@ -25,7 +25,7 @@ import ly_test_tools.environment.waiter as waiter import ly_test_tools.environment.file_system as fs import ly_test_tools.environment.process_utils as process_utils import ly_test_tools.launchers.launcher_helper as launcher_helper -from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP +from ly_test_tools.lumberyard.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP, ASSET_PROCESSOR_SETTINGS_ROOT_KEY # Import fixtures from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor @@ -136,7 +136,7 @@ class TestsAssetProcessorGUI_WindowsAndMac(object): # Validate that no fatal errors (crashes) are reported within a certain time frame (10 seconds timeout) # This applies to AP and GameLauncher.exe time.sleep(CHECK_ALIVE_SECONDS) - launcher_name = f"{workspace.project.title()}Launcher" + launcher_name = f"{workspace.project.title()}.GameLauncher" # fmt:off assert process_utils.process_exists(launcher_name, ignore_extensions=True), \ f"{launcher_name} was not live during the check." @@ -221,23 +221,20 @@ class TestsAssetProcessorGUI_AllPlatforms(object): assert not test_assets_added_to_cache(), "Test assets are present in cache before adding scan folder" - # Add test assets folder in dev to AP config file (AssetProcessorPlatformConfig.ini) to be scanned - ap_config_file = os.path.join(asset_processor.temp_asset_root(), 'AssetProcessorPlatformConfig.ini') - config = configparser.ConfigParser() - config.read(ap_config_file) - config["ScanFolder C4874115"] = { - "watch": "@ROOT@/C4874115", - "output": "C4874115", - "recursive": "1", - "order": "5000", - } - with open(ap_config_file, "w") as configfile: - config.write(configfile) + # Supply an additional scan folder for the test via the settings registry regset parameters + test_scan_folder_params = [] + + test_scan_folder_root_key = f"{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/ScanFolder C4874115" + test_scan_folder_params.append(f'--regset="{test_scan_folder_root_key}/watch=@ROOT@/C4874115"') + test_scan_folder_params.append(f'--regset="{test_scan_folder_root_key}/output=C4874115"') + test_scan_folder_params.append(f'--regset="{test_scan_folder_root_key}/recursive=1"') + test_scan_folder_params.append(f'--regset="{test_scan_folder_root_key}/order=5000"') # Run AP GUI and read the config file we just modified to pick up our scan folder # Pass in a pattern so we don't spend time processing unrelated folders result, _ = asset_processor.gui_process(quitonidle=True, add_config_scan_folders=True, - scan_folder_pattern="*C4874115*") + scan_folder_pattern="*C4874115*", + extra_params=test_scan_folder_params) assert result, "AP GUI failed" # Verify test assets processed into cache after adding scan folder @@ -255,10 +252,9 @@ class TestsAssetProcessorGUI_AllPlatforms(object): test_ip_address = "1.1.1.1" # an IP address without Asset Processor asset_processor.create_temp_asset_root() - # Edit remote_ip setting in bootstrap.cfg to an IP address without Asset Processor - workspace.settings.modify_bootstrap_setting("remote_ip", test_ip_address, - bootstrap_path=os.path.join(asset_processor.temp_asset_root(), - 'bootstrap.cfg')) + # Set the remote_ip setting through the settings registry to an IP address without Asset Processor + extra_params = [] + extra_params.append(f'--regset="/Amazon/AzCore/Bootstrap/remote_ip={test_ip_address}"') # Run AP Gui to verify that assets process regardless of the new address result, _ = asset_processor.gui_process(quitonidle=True) diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/missing_dependency_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/missing_dependency_tests.py index 11b760f310..30d73e0e17 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/missing_dependency_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/missing_dependency_tests.py @@ -64,7 +64,7 @@ class TestsMissingDependencies_WindowsAndMac(object): self._missing_dep_helper = missing_dep_helper self._asset_processor.create_temp_asset_root() self._asset_processor.add_source_folder_assets(f"AutomatedTesting\\TestAssets") - missing_dep_helper.asset_db = os.path.join(asset_processor.temp_asset_root(), "Cache", workspace.project, + missing_dep_helper.asset_db = os.path.join(asset_processor.temp_asset_root(), "Cache", "assetdb.sqlite") self._asset_processor.add_source_folder_assets(f"{self._workspace.project}\\Slices") self._asset_processor.add_source_folder_assets(f"{self._workspace.project}\\Materials") diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py index b40808b2c9..594827ee76 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py @@ -597,9 +597,9 @@ class TestsFBX_AllPlatforms(object): # Load the asset database. db_path = os.path.join(asset_processor.temp_asset_root(), "Cache", - workspace.project, "assetdb.sqlite") + "assetdb.sqlite") cache_root = os.path.dirname(os.path.join(asset_processor.temp_asset_root(), "Cache", - workspace.project, ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform])) + ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform])) if blackbox_params.scene_debug_file: debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(), blackbox_params.scene_debug_file) diff --git a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py index 8c38fbe7ac..e3ef1a3ab4 100644 --- a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py +++ b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py @@ -131,8 +131,9 @@ class TestAutomationBase: crash_info = f.read() except Exception as ex: crash_info += f"\n{str(ex)}" - - error_str = f"Editor.exe crashed, return code: 0x{return_code:0X}\n\nCrash log:\n{crash_info}" + + return_code_str = f"0x{return_code:0X}" if isinstance(return_code, int) else "None" + error_str = f"Editor.exe crashed, return code: {return_code_str}\n\nCrash log:\n{crash_info}" errors.append(TestRunError("CRASH", error_str)) self.test_times[testcase_name] = time.time() - test_starttime diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py index ae9222ab42..8c34f29ebf 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py @@ -19,16 +19,11 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesti from base import TestAutomationBase - -@pytest.mark.SUITE_main +@pytest.mark.SUITE_periodic @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) class TestAutomation(TestAutomationBase): - - def test_Opening_Closing_Pane(self, request, workspace, editor, launcher_platform): - from . import Opening_Closing_Pane as test_module - self._run_test(request, workspace, editor, test_module) - + def test_Docking_Pane(self, request, workspace, editor, launcher_platform): from . import Docking_Pane as test_module self._run_test(request, workspace, editor, test_module) @@ -36,4 +31,3 @@ class TestAutomation(TestAutomationBase): def test_Resizing_Pane(self, request, workspace, editor, launcher_platform): from . import Resizing_Pane as test_module self._run_test(request, workspace, editor, test_module) - diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Sandbox.py new file mode 100644 index 0000000000..1ab6a59972 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Sandbox.py @@ -0,0 +1,30 @@ +""" +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. +""" + +import pytest +import os +import sys + +from ly_test_tools import LAUNCHERS + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared') + +from base import TestAutomationBase + + +@pytest.mark.SUITE_sandbox +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_Opening_Closing_Pane(self, request, workspace, editor, launcher_platform): + from . import Opening_Closing_Pane as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Registry/assets_scan_folders.setreg b/AutomatedTesting/Registry/assets_scan_folders.setreg index 02169bd4d5..5394d381a3 100644 --- a/AutomatedTesting/Registry/assets_scan_folders.setreg +++ b/AutomatedTesting/Registry/assets_scan_folders.setreg @@ -3,15 +3,45 @@ { "Gems": { - "AutomatedTesting.Assets": + "DevTextures": + { + "SourcePaths": + [ + "Gems/DevTextures" + ] + }, + "PBSreferenceMaterials": + { + "SourcePaths": + [ + "Gems/PBSreferenceMaterials" + ] + }, + "PhysicsEntities": + { + "SourcePaths": + [ + "Gems/PhysicsEntities" + ] + }, + "PhysXSamples": + { + "SourcePaths": + [ + "Gems/PhysXSamples" + ] + }, + "PrimitiveAssets": + { + "SourcePaths": + [ + "Gems/PrimitiveAssets" + ] + }, + "UiBasics": { "SourcePaths": [ - "Gems/DevTextures", - "Gems/PBSreferenceMaterials", - "Gems/PhysicsEntities", - "Gems/PhysXSamples", - "Gems/PrimitiveAssets", "Gems/UiBasics" ] } diff --git a/AutomatedTesting/TestAssets/test_chunks_builder.py b/AutomatedTesting/TestAssets/test_chunks_builder.py index 06a3e41e8c..04629cb53c 100644 --- a/AutomatedTesting/TestAssets/test_chunks_builder.py +++ b/AutomatedTesting/TestAssets/test_chunks_builder.py @@ -10,6 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ import azlmbr.scene as sceneApi from scene_api import scene_data as sceneData +import uuid def update_manifest(scene): graph = sceneData.SceneGraph(scene.graph) @@ -27,7 +28,9 @@ def update_manifest(scene): sceneManifest = sceneData.SceneManifest() for activeMeshIndex in range(len(chunkNameList)): - meshGroup = sceneManifest.add_mesh_group(chunkNameList[activeMeshIndex]) + chunkName = chunkNameList[activeMeshIndex] + meshGroup = sceneManifest.add_mesh_group(chunkName) + meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, scene.sourceFilename + chunkName)) + '}' sceneManifest.mesh_group_add_comment(meshGroup, 'auto generated by test_chunks_builder') sceneManifest.mesh_group_set_origin(meshGroup, None, 0, 0, 0, 1.0) for meshIndex in range(len(chunkNameList)): diff --git a/AutomatedTesting/UI/TextureAtlas/sample.texatlas b/AutomatedTesting/UI/TextureAtlas/sample.texatlas index 0fefadc808..779300a96f 100644 --- a/AutomatedTesting/UI/TextureAtlas/sample.texatlas +++ b/AutomatedTesting/UI/TextureAtlas/sample.texatlas @@ -1,2 +1,2 @@ -../Gems/LyShineExamples/Assets/UI/Textures/LyShineExamples/*map.tif +@engroot@/Gems/LyShineExamples/Assets/UI/Textures/LyShineExamples/*map.tif diff --git a/AutomatedTesting/gems.json b/AutomatedTesting/gems.json deleted file mode 100644 index a7ae802fda..0000000000 --- a/AutomatedTesting/gems.json +++ /dev/null @@ -1,298 +0,0 @@ -{ - "GemListFormatVersion": 2, - "Gems": [ - { - "Path": "Gems/EMotionFX", - "Uuid": "044a63ea67d04479aa5daf62ded9d9ca", - "Version": "0.1.0", - "_comment": "EMotionFX" - }, - { - "Path": "Gems/PBSreferenceMaterials", - "Uuid": "07375b61b1a2424bb03088bbdf28b2c8", - "Version": "0.1.0", - "_comment": "PBSreferenceMaterials" - }, - { - "Path": "Gems/GraphModel", - "Uuid": "0844f64a3acf4f5abf3a535dc9b63bc9", - "Version": "0.1.0", - "_comment": "GraphModel" - }, - { - "Path": "Gems/StartingPointInput", - "Uuid": "09f4bedeee614358bc36788e77f97e51", - "Version": "0.1.0", - "_comment": "StartingPointInput" - }, - { - "Path": "Gems/LyShine", - "Uuid": "0fefab3f13364722b2eab3b96ce2bf20", - "Version": "0.1.0", - "_comment": "LyShine" - }, - { - "Path": "Gems/LandscapeCanvas", - "Uuid": "19c2b2d5018940108baf252934b8e6bf", - "Version": "0.1.0", - "_comment": "LandscapeCanvas" - }, - { - "Path": "Gems/ScriptCanvasPhysics", - "Uuid": "1c27519a4dda4ffaaeebf91514e5b1e8", - "Version": "0.1.0", - "_comment": "ScriptCanvasPhysics" - }, - { - "Path": "Gems/HttpRequestor", - "Uuid": "28479e255bde466e91fc34eec808d9c7", - "Version": "1.0.0", - "_comment": "HttpRequestor" - }, - { - "Path": "Gems/DevTextures", - "Uuid": "2c227161447b4d77a5b07c093e214fe3", - "Version": "0.1.0", - "_comment": "DevTextures" - }, - { - "Path": "Gems/ScriptEvents", - "Uuid": "32d8ba21703e4bbbb08487366e48dd69", - "Version": "0.1.0", - "_comment": "ScriptEvents" - }, - { - "Path": "Gems/Maestro", - "Uuid": "3b9a978ed6f742a1acb99f74379a342c", - "Version": "0.1.0", - "_comment": "Maestro" - }, - { - "Path": "Gems/ExpressionEvaluation", - "Uuid": "4c6f9df57ca2468f93c8d860ee6a1167", - "Version": "0.1.0", - "_comment": "ExpressionEvaluation" - }, - { - "Path": "Gems/PhysX", - "Uuid": "4e08125824434932a0fe3717259caa47", - "Version": "0.1.0", - "_comment": "PhysX" - }, - { - "Path": "Gems/PhysXDebug", - "Uuid": "516145e2d9904b13813f1b54605e26a6", - "Version": "0.1.0", - "_comment": "PhysXDebug" - }, - { - "Path": "Gems/CameraFramework", - "Uuid": "54f2763fe191432fa681ce4a354eedf5", - "Version": "0.1.0", - "_comment": "CameraFramework" - }, - { - "Path": "Gems/TextureAtlas", - "Uuid": "5a149b6b3c964064bd4970f0e92f72e2", - "Version": "0.1.0", - "_comment": "TextureAtlas" - }, - { - "Path": "Gems/SurfaceData", - "Uuid": "5de82d29d6094bfe97c1a4d35fcd5fbe", - "Version": "0.1.0", - "_comment": "SurfaceData" - }, - { - "Path": "Gems/AssetValidation", - "Uuid": "5a5c3c10b91d4b4ea8baef474c5b5d49", - "Version": "0.1.0", - "_comment": "AssetValidation" - }, - { - "Path": "Gems/Gestures", - "Uuid": "6056556b6088413984309c4a413593ad", - "Version": "1.0.0", - "_comment": "Gestures" - }, - { - "Path": "Gems/CertificateManager", - "Uuid": "659cffff33b14a10835bafc6ea623f98", - "Version": "0.0.1", - "_comment": "CertificateManager" - }, - { - "Path": "Gems/DebugDraw", - "Uuid": "66239f50bf754354b514c850c8b841fb", - "Version": "0.1.0", - "_comment": "DebugDraw" - }, - { - "Path": "Gems/UiBasics", - "Uuid": "6bb61c9e547043f0afc5019d6d460b78", - "Version": "0.1.0", - "_comment": "UiBasics" - }, - { - "Path": "Gems/AudioSystem", - "Uuid": "6f63f2b6d07f4b89b4b7c86ebee7feb8", - "Version": "0.1.0", - "_comment": "AudioSystem" - }, - { - "Path": "Gems/StartingPointMovement", - "Uuid": "73d8779dc28a4123b7c9ed76217464af", - "Version": "0.1.0", - "_comment": "StartingPointMovement" - }, - { - "Path": "Gems/GameLift", - "Uuid": "76de765796504906b73be7365a9bff06", - "Version": "2.0.0", - "_comment": "GameLift" - }, - { - "Path": "Gems/SceneProcessing", - "Uuid": "7c2578f634df4345aca98d671e39b8ab", - "Version": "0.1.0", - "_comment": "SceneProcessing" - }, - { - "Path": "Gems/StartingPointCamera", - "Uuid": "834070b9537d44df83559e2045c3859f", - "Version": "0.1.0", - "_comment": "StartingPointCamera" - }, - { - "Path": "Gems/ScriptCanvas", - "Uuid": "869a0d0ec11a45c299917d45c81555e6", - "Version": "0.1.0", - "_comment": "ScriptCanvasGem" - }, - { - "Path": "Gems/GraphCanvas", - "Uuid": "875b6fcbdeea44deaae7984ad9bb6cdc", - "Version": "0.1.0", - "_comment": "GraphCanvas" - }, - { - "Path": "Gems/GradientSignal", - "Uuid": "8825563d9d964ec3be3bab681f3bd9f2", - "Version": "0.1.0", - "_comment": "GradientSignal" - }, - { - "Path": "Gems/InAppPurchases", - "Uuid": "92fe57eae7d3402a90761973678c079a", - "Version": "0.1.0", - "_comment": "InAppPurchases" - }, - { - "Path": "Gems/PhysicsEntities", - "Uuid": "99ea531451fc4f64a5a9fe8f385e8a76", - "Version": "0.1.0", - "_comment": "PhysicsEntities" - }, - { - "Path": "AutomatedTesting/Gem", - "Uuid": "afc25e1593194d6283d9ff744ab6d5a1", - "Version": "0.1.0" - }, - { - "Path": "Gems/EditorPythonBindings", - "Uuid": "b658359393884c4381c2fe2952b1472a", - "Version": "0.1.0", - "_comment": "EditorPythonBindings" - }, - { - "Path": "Gems/ImGui", - "Uuid": "bab8807a1bc646b3909f3cc200ffeedf", - "Version": "0.1.0", - "_comment": "ImGui" - }, - { - "Path": "Gems/ChatPlay", - "Uuid": "bfbc60c63ffd4b00927003735b26ce99", - "Version": "0.1.0", - "_comment": "ChatPlay" - }, - { - "Path": "Gems/Metastream", - "Uuid": "c02d7efe05134983b5699d9ee7594c3a", - "Version": "1.0.0", - "_comment": "Metastream" - }, - { - "Path": "Gems/PhysXSamples", - "Uuid": "c4a4aadba44241ae9f0141e145def7f7", - "Version": "0.1.0", - "_comment": "PhysXSamples" - }, - { - "Path": "Gems/Water", - "Uuid": "c5083fcf89b24ab68fb0611c01a07b1d", - "Version": "0.1.0", - "_comment": "Water" - }, - { - "Path": "Gems/WhiteBox", - "Uuid": "c5833dbda2e045d3a5f16b7414280c27", - "Version": "0.1.0", - "_comment": "WhiteBox" - }, - { - "Path": "Gems/TouchBending", - "Uuid": "c58d2057f3724b22ae0df0be68a4e316", - "Version": "0.1.0", - "_comment": "TouchBending" - }, - { - "Path": "Gems/FastNoise", - "Uuid": "c5f23032407f49ca8d8de1733423565c", - "Version": "0.1.0", - "_comment": "FastNoise" - }, - { - "Path": "Gems/LyShineExamples", - "Uuid": "c7935ecf5e8047fe8ca947b34b11cadb", - "Version": "0.1.0", - "_comment": "LyShineExamples" - }, - { - "Path": "Gems/PrimitiveAssets", - "Uuid": "ed07631f95fb4be1bd10cd37298ec697", - "Version": "1.0.0", - "_comment": "PrimitiveAssets" - }, - { - "Path": "Gems/ImageProcessing", - "Uuid": "eeffbd9211cf4ce0b5cc73696b427cbe", - "Version": "0.1.0", - "_comment": "ImageProcessing" - }, - { - "Path": "Gems/Vegetation", - "Uuid": "f394e7cf54424bba89615381bba9511b", - "Version": "0.1.0", - "_comment": "Vegetation" - }, - { - "Path": "Gems/TestAssetBuilder", - "Uuid": "f5c92f1560714010ba30467d93feecef", - "Version": "0.1.0", - "_comment": "TestAssetBuilder" - }, - { - "Path": "Gems/Camera", - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Version": "0.1.0", - "_comment": "Camera" - }, - { - "Path": "Gems/LmbrCentral", - "Uuid": "ff06785f7145416b9d46fde39098cb0c", - "Version": "0.1.0", - "_comment": "LmbrCentral" - } - ] -} \ No newline at end of file diff --git a/BuildReleaseAuxiliaryContent.py b/BuildReleaseAuxiliaryContent.py index 3d11750f8f..e30a4b50e1 100644 --- a/BuildReleaseAuxiliaryContent.py +++ b/BuildReleaseAuxiliaryContent.py @@ -24,12 +24,12 @@ def printMessage(message): def getCurrentProject(): bootstrap = open("bootstrap.cfg", "r") - gameProjectRegex = re.compile("^sys_game_folder\s*=\s*(.*)") + gameProjectRegex = re.compile(r"^project_path\s*=\s*(.*)") for line in bootstrap: gameFolderMatch = gameProjectRegex.match(line) if gameFolderMatch: - return gameFolderMatch.group(1) + return os.path.basename(gameFolderMatch.group(1)) return None diff --git a/CMakeLists.txt b/CMakeLists.txt index a43314a83c..801aa0447c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ endif() include(cmake/Version.cmake) if(NOT PROJECT_NAME) - project(Lumberyard + project(O3DE LANGUAGES C CXX VERSION ${LY_VERSION_STRING} ) @@ -83,13 +83,30 @@ endif() # Post-processing ################################################################################ +# Loop over the additional external subdirectories and invoke add_subdirectory on them +foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) + # Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory + # This is to deal with potential situations where multiple external directories has the same last directory name + # For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory + file(REAL_PATH ${external_directory} full_directory_path) + string(SHA256 full_directory_hash ${full_directory_path}) + # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit + # when the external subdirectory contains relative paths of significant length + string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) + # Use the last directory as the suffix path to use for the Binary Directory + get_filename_component(directory_name ${external_directory} NAME) + add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/${directory_name}-${full_directory_hash}) +endforeach() + # The following steps have to be done after all targets were registered: -# 1. link targets where the dependency was yet not declared, we need to have the declaration so we do different -# linking logic depending on the type of target -ly_delayed_target_link_libraries() -# 2. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls +# 1. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls # to provide applications with the filenames of gem modules to load +# This must be done before ly_delayed_target_link_libraries() as that inserts BUILD_DEPENDENCIE as MANUALLY_ADDED_DEPENDENCIES +# if the build dependency is a MODULE_LIBRARY. That would cause a false load dependency to be generated ly_delayed_generate_settings_registry() +# 2. link targets where the dependency was yet not declared, we need to have the declaration so we do different +# linking logic depending on the type of target +ly_delayed_target_link_libraries() # 3. generate a registry file for unit testing for platforms that support unit testing if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_delayed_generate_unit_test_module_registry() diff --git a/Code/CryEngine/Cry3DEngine/3DEngineRender.cpp b/Code/CryEngine/Cry3DEngine/3DEngineRender.cpp index 94dcd98240..7082bfbd38 100644 --- a/Code/CryEngine/Cry3DEngine/3DEngineRender.cpp +++ b/Code/CryEngine/Cry3DEngine/3DEngineRender.cpp @@ -1080,7 +1080,7 @@ void C3DEngine::WorldStreamUpdate() if (GetCVars()->e_StreamSaveStartupResultsIntoXML) { - const char* testResultsFile = "@cache@/TestResults/Streaming_Level_Start_Throughput.xml"; + const char* testResultsFile = "@usercache@/TestResults/Streaming_Level_Start_Throughput.xml"; AZ::IO::HandleType resultsFile = gEnv->pCryPak->FOpen(testResultsFile, "wb"); if (resultsFile != AZ::IO::InvalidHandle) diff --git a/Code/CryEngine/Cry3DEngine/3dEngine.cpp b/Code/CryEngine/Cry3DEngine/3dEngine.cpp index ecb028ba4f..42306c865f 100644 --- a/Code/CryEngine/Cry3DEngine/3dEngine.cpp +++ b/Code/CryEngine/Cry3DEngine/3dEngine.cpp @@ -952,7 +952,7 @@ void C3DEngine::ProcessStreamingLatencyTest(const CCamera& camIn, CCamera& camOu if (GetCVars()->e_SQTestCount == 0) { - const char* testResultsFile = "@cache@/TestResults/Streaming_Latency_Test.xml"; + const char* testResultsFile = "@usercache@/TestResults/Streaming_Latency_Test.xml"; AZ::IO::HandleType resultsFile = gEnv->pCryPak->FOpen(testResultsFile, "wb"); if (resultsFile != AZ::IO::InvalidHandle) diff --git a/Code/CryEngine/Cry3DEngine/3dEngineLoad.cpp b/Code/CryEngine/Cry3DEngine/3dEngineLoad.cpp index b467d11c77..a3cb04dea0 100644 --- a/Code/CryEngine/Cry3DEngine/3dEngineLoad.cpp +++ b/Code/CryEngine/Cry3DEngine/3dEngineLoad.cpp @@ -461,7 +461,7 @@ void C3DEngine::UnloadLevel() m_ptexIconLowMemoryUsage = nullptr; m_ptexIconHighMemoryUsage = nullptr; m_ptexIconEditorConnectedToConsole = nullptr; - + if (m_pOpticsManager && !gEnv->IsEditor()) { m_pOpticsManager->Reset(); @@ -656,7 +656,7 @@ bool C3DEngine::LoadLevel(const char* szFolderName, const char* szMissionName) // set default render parameters. // for some reason this is not done later??? m_pSkyLightManager->UpdateRenderParams(); - } + } // Load LevelData.xml File. XmlNodeRef xmlLevelData = GetSystem()->LoadXmlFromFile(GetLevelFilePath(LEVEL_DATA_FILE)); @@ -687,17 +687,7 @@ bool C3DEngine::LoadLevel(const char* szFolderName, const char* szMissionName) // preload level cgfs if (GetCVars()->e_StatObjPreload && !gEnv->IsEditor()) { - if (GetCVars()->e_StatObjPreload == 2) - { - GetSystem()->OutputLoadingTimeStats(); - } - m_pObjManager->PreloadLevelObjects(); - - if (GetCVars()->e_StatObjPreload == 2) - { - GetSystem()->OutputLoadingTimeStats(); - } } std::vector* pStatObjTable = NULL; diff --git a/Code/CryEngine/Cry3DEngine/LightEntity.cpp b/Code/CryEngine/Cry3DEngine/LightEntity.cpp index 63bd40ef58..df7f7f901a 100644 --- a/Code/CryEngine/Cry3DEngine/LightEntity.cpp +++ b/Code/CryEngine/Cry3DEngine/LightEntity.cpp @@ -317,7 +317,8 @@ int CLightEntity::UpdateGSMLightSourceDynamicShadowFrustum(int nDynamicLodCount, if (bDoGSM) { - Vec3 vSunDir = Get3DEngine()->GetSunDir().GetNormalized(); // todo: remove GetNormalized() once GetSunDir() returns the normalized value + //Vec3 vSunDir = Get3DEngine()->GetSunDir().GetNormalized(); // todo: remove GetNormalized() once GetSunDir() returns the normalized value + Vec3 vSunDir = Vec3(1.0f, 0.0f, 0.0f); Vec3 vCameraDirWithoutDepth = vCameraDir - vCameraDir.Dot(vSunDir) * vSunDir; Vec3 vFocusPos = passInfo.GetCamera().GetPosition() + vCameraDirWithoutDepth * fGSMBoxSize; diff --git a/Code/CryEngine/Cry3DEngine/Material.cpp b/Code/CryEngine/Cry3DEngine/Material.cpp index ed71df38ca..b0853db518 100644 --- a/Code/CryEngine/Cry3DEngine/Material.cpp +++ b/Code/CryEngine/Cry3DEngine/Material.cpp @@ -117,10 +117,6 @@ CMatInfo::CMatInfo() ZeroStruct(m_streamZoneInfo); -#ifdef TRACE_MATERIAL_LEAKS - m_sLoadingCallstack = GetSystem()->GetLoadingProfilerCallstack(); -#endif - // Used to know when a .dccmtl file has been changed, // requiring the source material to be updated m_dccMaterialHash = 0; @@ -341,7 +337,7 @@ ISurfaceType* CMatInfo::GetSurfaceType() ////////////////////////////////////////////////////////////////////////// void CMatInfo::SetSubMtlCount(int numSubMtl) { - AUTO_LOCK(GetSubMaterialResizeLock()); + AUTO_LOCK(GetSubMaterialResizeLock()); if (numSubMtl > 0) { m_Flags |= MTL_FLAG_MULTI_SUBMTL; @@ -1112,15 +1108,6 @@ void CMatInfo::SetTexelDensityDebug([[maybe_unused]] int mode) #endif } -const char* CMatInfo::GetLoadingCallstack() -{ -#ifdef TRACE_MATERIAL_LEAKS - return m_sLoadingCallstack.c_str(); -#else - return ""; -#endif -} - void CMatInfo::PrecacheMaterial(const float _fEntDistance, IRenderMesh* pRenderMesh, bool bFullUpdate, bool bDrawNear) { // FUNCTION_PROFILER_3DENGINE; diff --git a/Code/CryEngine/Cry3DEngine/Material.h b/Code/CryEngine/Cry3DEngine/Material.h index f11a15e250..bc0546a4e1 100644 --- a/Code/CryEngine/Cry3DEngine/Material.h +++ b/Code/CryEngine/Cry3DEngine/Material.h @@ -18,7 +18,6 @@ #include #if !defined(CONSOLE) -# define TRACE_MATERIAL_LEAKS # define SUPPORT_MATERIAL_EDITING #endif @@ -203,7 +202,7 @@ public: bool SetGetMaterialParamFloat(const char* sParamName, float& v, bool bGet, bool allowShaderParam = false, int materialIndex = 0) override; bool SetGetMaterialParamVec3(const char* sParamName, Vec3& v, bool bGet, bool allowShaderParam = false, int materialIndex = 0) override; bool SetGetMaterialParamVec4(const char* sParamName, Vec4& v, bool bGet, bool allowShaderParam = false, int materialIndex = 0) override; - + void SetDirty(bool dirty = true) override; bool IsDirty() const override; @@ -264,11 +263,6 @@ public: bool IsForwardRenderingRequired(); bool IsNearestCubemapRequired(); - ////////////////////////////////////////////////////////////////////////// - // Debug routines - ////////////////////////////////////////////////////////////////////////// - virtual const char* GetLoadingCallstack(); // trace leaking materials by callstack - void DisableTextureStreaming() override; virtual void RequestTexturesLoading(const float fMipFactor); @@ -286,13 +280,6 @@ public: void SetDccMaterialHash(uint32 hash) override { m_dccMaterialHash = hash; } virtual CryCriticalSection& GetSubMaterialResizeLock(); -public: - ////////////////////////////////////////////////////////////////////////// - // for debug purposes - ////////////////////////////////////////////////////////////////////////// -#ifdef TRACE_MATERIAL_LEAKS - string m_sLoadingCallstack; -#endif private: friend class CMatMan; diff --git a/Code/CryEngine/Cry3DEngine/StatObj.h b/Code/CryEngine/Cry3DEngine/StatObj.h index 4b9f60aeeb..771d7354a5 100644 --- a/Code/CryEngine/Cry3DEngine/StatObj.h +++ b/Code/CryEngine/Cry3DEngine/StatObj.h @@ -16,7 +16,6 @@ #pragma once #if !defined(CONSOLE) -# define TRACE_CGF_LEAKS # define SUPPORT_TERRAIN_AO_PRE_COMPUTATIONS #endif @@ -337,13 +336,6 @@ public: std::vector m_chunkBoneIds; ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - // for debug purposes - ////////////////////////////////////////////////////////////////////////// -#ifdef TRACE_CGF_LEAKS - string m_sLoadingCallstack; -#endif - private: ////////////////////////////////////////////////////////////////////////// // Sub objects. @@ -419,7 +411,7 @@ public: virtual unsigned int GetBreakableByGame() { return m_bBreakableByGame; }; //Note: This function checks both the children and root data - //It should really be 'has any deformable objects' + //It should really be 'has any deformable objects' //Should eventually be refactored as part of an eventual statobj refactor. virtual bool IsDeformable() override; diff --git a/Code/CryEngine/Cry3DEngine/StatObjConstr.cpp b/Code/CryEngine/Cry3DEngine/StatObjConstr.cpp index a4803f7c5d..c6afbd5707 100644 --- a/Code/CryEngine/Cry3DEngine/StatObjConstr.cpp +++ b/Code/CryEngine/Cry3DEngine/StatObjConstr.cpp @@ -56,10 +56,6 @@ CStatObj::CStatObj() m_fLodDistance = 0.0f; Init(); - -#ifdef TRACE_CGF_LEAKS - m_sLoadingCallstack = GetSystem()->GetLoadingProfilerCallstack(); -#endif } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CryCommon/IAudioSystem.h b/Code/CryEngine/CryCommon/IAudioSystem.h index c2edb36d90..0e68ae88d4 100644 --- a/Code/CryEngine/CryCommon/IAudioSystem.h +++ b/Code/CryEngine/CryCommon/IAudioSystem.h @@ -1064,7 +1064,7 @@ namespace Audio /////////////////////////////////////////////////////////////////////////////////////////// // Interface methods - virtual bool Initialize(const SSystemInitParams* initParams) = 0; + virtual bool Initialize() = 0; virtual void Release() = 0; }; diff --git a/Code/CryEngine/CryCommon/IMaterial.h b/Code/CryEngine/CryCommon/IMaterial.h index f611b2179c..81d612397f 100644 --- a/Code/CryEngine/CryCommon/IMaterial.h +++ b/Code/CryEngine/CryCommon/IMaterial.h @@ -392,7 +392,7 @@ struct IMaterial virtual void SetDirty(bool dirty = true) = 0; virtual bool IsDirty() const = 0; - //! Returns true if the material is the parent of a group of materials + //! Returns true if the material is the parent of a group of materials virtual bool IsMaterialGroup() const = 0; //! Returns true if the material is a single material belongs to a material group @@ -411,11 +411,6 @@ struct IMaterial // - 2, fast sketch mode. virtual void SetSketchMode(int mode) = 0; - ////////////////////////////////////////////////////////////////////////// - // Debug routines - ////////////////////////////////////////////////////////////////////////// - virtual const char* GetLoadingCallstack() = 0; // trace leaking materials by callstack - // Sets FT_DONT_STREAM flag for all textures used by the material // If a stream is already in process, this will stop the stream and flush the device texture virtual void DisableTextureStreaming() = 0; diff --git a/Code/CryEngine/CryCommon/ISystem.h b/Code/CryEngine/CryCommon/ISystem.h index 04eb36b008..679dc66327 100644 --- a/Code/CryEngine/CryCommon/ISystem.h +++ b/Code/CryEngine/CryCommon/ISystem.h @@ -119,8 +119,6 @@ namespace AZ class IResourceCompilerHelper; -class CBootProfilerRecord; - namespace Serialization { struct IArchiveHost; } @@ -629,15 +627,7 @@ struct SSystemInitParams void* hWnd; // void* hWndForInputSystem; // the HWND for the input devices, distinct from the hWnd, which the rendering system overrides anyways - char remoteIP[256]; - int remotePort; - bool remoteFileIO; bool remoteResourceCompiler; - bool connectToRemote; - bool waitForConnection; // if true, wait for the remote connection to be established before proceeding to system init. - char assetsPlatform[64]; // what flavor of assets to load. Corresponds to those in rc.ini and asset processor ini - char gameFolderName[256]; // just the name. Not the full path. - char branchToken[12]; // information written by the assetprocessor which help determine whether the game/editor are running from the same branch or not ILog* pLog; // You can specify your own ILog to be used by System. ILogCallback* pLogCallback; // You can specify your own ILogCallback to be added on log creation (used by Editor). @@ -648,45 +638,6 @@ struct SSystemInitParams IOutputPrintSink* pPrintSync; // Print Sync which can be used to catch all output from engine char szSystemCmdLine[2048]; // Command line. - - // set some paths before you create the system. - - // rootPath - (REQUIRED) folder containing root. Must contain system.cfg or bootstrap.cfg basically. - // the remainder are optional and if specified should contain prefixes that can be prepended to any file to get to that location: - // READ ONLY! - char rootPath[256]; - char rootPathCache[256]; - - // assetsPath - (REQUIRED) - where you assets live. The engine config parser will default this to @root@/gamename - // READ ONLY! - char assetsPath[256]; - char assetsPathCache[256]; - - // userPath - (OPTIONAL) User path contains a folder for preferences persistent storage. May be persisted to the cloud (by things like IOS) - // If not specified, this is assumed @root@/User/ - // WRITABLE - char userPath[256]; - - // cachePath - (OPTIONAL) a temporary store that can be erased at any time and does not need to be persisted - // on the cloud or anything like that. if not specified, this will be @user@/Cache - // WRITABLE - char cachePath[256]; - - // logPath - (OPTIONAL) a log path folder. - // If not specified, it will be @cache@/Logs - // WRITABLE - char logPath[256]; - - // the game should never use these values instead, the game should be using crypak or fileio with aliases: - // @root@ To get to the folder where system.cfg lives - // @assets@ to get to the folder containing game assets (textures and such) - by default, this is @root@/Gamename/ - // @devroot@ to get to source files that are checked into source control (PC EDITOR ONLY!) - // @engroot@ to get to path to the engine root folder - // @user@ to access user store - // @cache@ to access temporary cache - // @log@ to access log file and other forensic storage - char szBinariesDir[256]; - bool bEditor; // When running in Editor mode. bool bPreview; // When running in Preview mode (Minimal initialization). bool bTestMode; // When running in Automated testing mode. @@ -730,26 +681,7 @@ struct SSystemInitParams hWnd = NULL; hWndForInputSystem = NULL; - memset(rootPath, 0, sizeof(rootPath)); - memset(rootPathCache, 0, sizeof(rootPathCache)); - memset(userPath, 0, sizeof(userPath)); - memset(assetsPath, 0, sizeof(assetsPath)); - memset(assetsPathCache, 0, sizeof(assetsPathCache)); - memset(cachePath, 0, sizeof(cachePath)); - memset(logPath, 0, sizeof(logPath)); - memset(gameFolderName, 0, sizeof(gameFolderName)); - memset(branchToken, 0, sizeof(branchToken)); - - memset(remoteIP, 0, sizeof(remoteIP)); - azstrcpy(remoteIP, sizeof(remoteIP), "127.0.0.1"); - memset(assetsPlatform, 0, sizeof(assetsPlatform)); - azstrcpy(assetsPlatform, sizeof(assetsPlatform), "pc"); - - remotePort = 45643; - remoteFileIO = false; remoteResourceCompiler = false; - connectToRemote = false; - waitForConnection = false; pLog = NULL; pLogCallback = NULL; @@ -762,7 +694,6 @@ struct SSystemInitParams pValidator = NULL; pPrintSync = NULL; memset(szSystemCmdLine, 0, sizeof(szSystemCmdLine)); - memset(szBinariesDir, 0, sizeof(szBinariesDir)); bEditor = false; bPreview = false; @@ -798,17 +729,6 @@ struct SSystemInitParams pSharedEnvironment = nullptr; } - - bool UseAssetCache() const - { -#if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_MAC) || defined(AZ_PLATFORM_LINUX) - char checkPath[AZ_MAX_PATH_LEN] = { 0 }; - azsnprintf(checkPath, AZ_MAX_PATH_LEN, "%s/engine.json", rootPathCache); - return AZ::IO::SystemFile::Exists(checkPath); -#else - return false; -#endif // defined(AZ_PLATFORM_WINDOWS) || AZ_TRAIT_OS_PLATFORM_APPLE - } }; // Notes: @@ -1228,11 +1148,6 @@ struct ISystem // Gets number of CPUs virtual int GetLogicalCPUCount() = 0; - //! Get the 'kind' of assets you need to load - this describes the flavor of assets you are going to load - //! based on the platform you're on - so for example, android on ES3 will be 'es3' but android on opengl might load PC assets or others... - //! This is defined in bootstrap.cfg and is read-only during runtime. - virtual const char* GetAssetsPlatform() const = 0; - // Summary: // Return the rendering driver name. GL or Metal virtual const char* GetRenderingDriverName() const = 0; @@ -1406,43 +1321,6 @@ struct ISystem // True if system running in Test mode. virtual bool IsTestMode() const = 0; - ////////////////////////////////////////////////////////////////////////// - // Loading time/memory profiling - ////////////////////////////////////////////////////////////////////////// - - // Summary: - // Starts function loading stats profiling. - virtual struct SLoadingTimeContainer* StartLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler, const char* szFuncName) = 0; - - // Summary: - // Ends function loading stats profiling. - virtual void EndLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler) = 0; - - // Summary: - // Starts function profiling with bootprofiler (session must be started). - virtual CBootProfilerRecord* StartBootSectionProfiler(const char* name, const char* args) = 0; - - // Summary: - // Ends function profiling with bootprofiler. - virtual void StopBootSectionProfiler(CBootProfilerRecord* record) = 0; - - - // Summary: - // Starts frame session - virtual void StartBootProfilerSessionFrames(const char* pName) = 0; - - // Summary: - // Stops frame session - virtual void StopBootProfilerSessionFrames() = 0; - - // Summary: - // Prints loading stats into log. - virtual void OutputLoadingTimeStats() = 0; - - // Summary: - // Starts function loading stats profiling. - virtual const char* GetLoadingProfilerCallstack() = 0; - ////////////////////////////////////////////////////////////////////////// // File version. ////////////////////////////////////////////////////////////////////////// @@ -1581,10 +1459,10 @@ struct ISystem ////////////////////////////////////////////////////////////////////////// // Summary: - // Enable/Disable drawing the console + // Enable/Disable drawing the console virtual void SetConsoleDrawEnabled(bool enabled) = 0; - // Enable/Disable drawing the UI + // Enable/Disable drawing the UI virtual void SetUIDrawEnabled(bool enabled) = 0; // Summary: @@ -1772,79 +1650,19 @@ struct DiskOperationInfo #endif -#if defined(ENABLE_LOADING_PROFILER) - -struct CLoadingTimeProfiler -{ - CLoadingTimeProfiler(ISystem* pSystem, const char* szFuncName) - : m_pSystem(pSystem) - { - m_pSystem = pSystem; - m_pTimeContainer = m_pSystem->StartLoadingSectionProfiling(this, szFuncName); - } - - ~CLoadingTimeProfiler() - { - m_pSystem->EndLoadingSectionProfiling(this); - } - - struct SLoadingTimeContainer* m_pTimeContainer; - double m_fConstructorTime; - double m_fConstructorMemUsage; - - DiskOperationInfo m_constructorInfo; - - ISystem* m_pSystem; -}; - -class CSYSBootProfileBlock -{ - ISystem* m_pSystem; - CBootProfilerRecord* m_pRecord; -public: - CSYSBootProfileBlock(ISystem* pSystem, const char* name, const char* args = NULL) - : m_pSystem(pSystem) - { - if (m_pSystem) - { - m_pRecord = m_pSystem->StartBootSectionProfiler(name, args); - } - } - - ~CSYSBootProfileBlock() - { - if (m_pSystem) - { - m_pSystem->StopBootSectionProfiler(m_pRecord); - } - } -}; - -#ifdef AZ_PROFILE_TELEMETRY +#if defined(ENABLE_LOADING_PROFILER) && AZ_PROFILE_TELEMETRY #define LOADING_TIME_PROFILE_SECTION AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore) #define LOADING_TIME_PROFILE_SECTION_ARGS(...) AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, __VA_ARGS__) #define LOADING_TIME_PROFILE_SECTION_NAMED(sectionName) AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzCore, sectionName) -#define LOADING_TIME_PROFILE_SECTION_NAMED_ARGS(sectionName, args) AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, sectionName, args) - -#else - -#define LOADING_TIME_PROFILE_SECTION CSYSBootProfileBlock AZ_JOIN(_profileBlockLine, __LINE__)(gEnv && gEnv->pSystem ? gEnv->pSystem : nullptr, __FUNCTION__); -#define LOADING_TIME_PROFILE_SECTION_ARGS(args) CSYSBootProfileBlock AZ_JOIN(_profileBlockLine, __LINE__)(gEnv->pSystem, __FUNCTION__, args); -#define LOADING_TIME_PROFILE_SECTION_NAMED(sectionName) CSYSBootProfileBlock AZ_JOIN(_profileBlockLine, __LINE__)(gEnv->pSystem, sectionName); -#define LOADING_TIME_PROFILE_SECTION_NAMED_ARGS(sectionName, args) CSYSBootProfileBlock AZ_JOIN(_profileBlockLine, __LINE__)(gEnv->pSystem, sectionName, args); - -#endif // AZ_PROFILE_TELEMETRY +#define LOADING_TIME_PROFILE_SECTION_NAMED_ARGS(sectionName, ...) AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, sectionName, __VA_ARGS__) #else #define LOADING_TIME_PROFILE_SECTION -#define LOADING_TIME_PROFILE_SECTION_ARGS(args) +#define LOADING_TIME_PROFILE_SECTION_ARGS(...) #define LOADING_TIME_PROFILE_SECTION_NAMED(sectionName) -#define LOADING_TIME_PROFILE_SECTION_NAMED_ARGS(sectionName, args) -#define LOADING_TIME_PROFILE_SESSION_SECTION(sessionName) -#define LOADING_TIME_PROFILE_SESSION_START(sessionName) -#define LOADING_TIME_PROFILE_SESSION_STOP(sessionName) +#define LOADING_TIME_PROFILE_SECTION_NAMED_ARGS(sectionName, ...) #endif @@ -1865,7 +1683,7 @@ extern SC_API SSystemGlobalEnvironment* gEnv; inline ISystem* GetISystem() { // Some unit tests temporarily install and then uninstall ISystem* mocks. - // It is generally okay for runtime and tool systems which call this function to cache the returned pointer, + // It is generally okay for runtime and tool systems which call this function to cache the returned pointer, // because their lifetime is usually shorter than the lifetime of the ISystem* implementation. // It is NOT safe for this function to cache it as a static itself, though, as the static it would cache // it inside may outlive the the actual instance implementing ISystem* when unit tests are torn down and then restarted. diff --git a/Code/CryEngine/CryCommon/MaterialUtils.h b/Code/CryEngine/CryCommon/MaterialUtils.h index 87d2098e3e..901a517094 100644 --- a/Code/CryEngine/CryCommon/MaterialUtils.h +++ b/Code/CryEngine/CryCommon/MaterialUtils.h @@ -15,10 +15,12 @@ #include #include // for max path len -#include #include +#include #include +#include + namespace MaterialUtils { //! UnifyMaterialName - given a non-unified material name, remove the extension, unify the slashes @@ -75,14 +77,11 @@ namespace MaterialUtils static char cachedGameName[AZ_MAX_PATH_LEN] = { 0 }; if (!removals[removalSize - 1]) { - if ((gEnv) && (gEnv->pConsole)) + auto projectName = AZ::Utils::GetProjectName(); + if (!projectName.empty()) { - ICVar* pGameNameCVar = gEnv->pConsole->GetCVar("sys_game_folder"); - if (pGameNameCVar) - { - azstrcpy(cachedGameName, AZ_MAX_PATH_LEN, pGameNameCVar->GetString()); - azstrcat(cachedGameName, AZ_MAX_PATH_LEN, "/"); - } + azstrcpy(cachedGameName, AZ_MAX_PATH_LEN, projectName.c_str()); + azstrcat(cachedGameName, AZ_MAX_PATH_LEN, "/"); } if (cachedGameName[0] == 0) diff --git a/Code/CryEngine/CryCommon/Mocks/ISystemMock.h b/Code/CryEngine/CryCommon/Mocks/ISystemMock.h index ca4b838a63..5edd84fd75 100644 --- a/Code/CryEngine/CryCommon/Mocks/ISystemMock.h +++ b/Code/CryEngine/CryCommon/Mocks/ISystemMock.h @@ -55,8 +55,6 @@ public: int()); MOCK_METHOD0(GetLogicalCPUCount, int()); - MOCK_CONST_METHOD0(GetAssetsPlatform, - const char*()); MOCK_CONST_METHOD0(GetRenderingDriverName, const char*()); MOCK_METHOD1(DumpMemoryUsageStatistics, @@ -206,22 +204,6 @@ public: bool()); MOCK_METHOD3(SetFrameProfiler, void(bool on, bool display, char* prefix)); - MOCK_METHOD2(StartLoadingSectionProfiling, - struct SLoadingTimeContainer*(CLoadingTimeProfiler * pProfiler, const char* szFuncName)); - MOCK_METHOD1(EndLoadingSectionProfiling, - void(CLoadingTimeProfiler * pProfiler)); - MOCK_METHOD2(StartBootSectionProfiler, - CBootProfilerRecord * (const char* name, const char* args)); - MOCK_METHOD1(StopBootSectionProfiler, - void(CBootProfilerRecord * record)); - MOCK_METHOD1(StartBootProfilerSessionFrames, - void(const char* pName)); - MOCK_METHOD0(StopBootProfilerSessionFrames, - void()); - MOCK_METHOD0(OutputLoadingTimeStats, - void()); - MOCK_METHOD0(GetLoadingProfilerCallstack, - const char*()); MOCK_METHOD0(GetFileVersion, const SFileVersion&()); MOCK_METHOD0(GetProductVersion, diff --git a/Code/CryEngine/CryCommon/ParseEngineConfig.h b/Code/CryEngine/CryCommon/ParseEngineConfig.h deleted file mode 100644 index 0eef1d7769..0000000000 --- a/Code/CryEngine/CryCommon/ParseEngineConfig.h +++ /dev/null @@ -1,160 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -#include "ISystem.h" -#include -#include -#include -#include -#include - -// any of the following tags can be present in the bootstrap.cfg -// you can also prefix it with a platform. -// so for example, you can specify remote_ip alone to specify it for all platforms -// or you could specify android_remote_ip to change it for android only. -// the instructions are executed in the order that they appear, so you can set the default -// by using the non-platform-specific version, and then later on in the file you -// can override specific platforms. - -#define CONFIG_KEY_FOR_REMOTEIP "remote_ip" -#define CONFIG_KEY_FOR_REMOTEPORT "remote_port" -#define CONFIG_KEY_FOR_GAMEFOLDER "sys_game_folder" -#define CONFIG_KEY_FOR_REMOTEFILEIO "remote_filesystem" -#define CONFIG_KEY_FOR_CONNECTTOREMOTE "connect_to_remote" -#define CONFIG_KEY_WAIT_FOR_CONNECT "wait_for_connect" -#define DEFAULT_GAMEDLL "EmptyTemplate" -#define DEFAULT_GAMEFOLDER "EmptyTemplate" -#define DEFAULT_REMOTEIP "127.0.0.1" -#define DEFAULT_REMOTEPORT 45643 -#define CONFIG_KEY_FOR_ASSETS "assets" -#define CONFIG_KEY_FOR_BRANCHTOKEN "assetProcessor_branch_token" - -////////////////////////////////////////////////////////////////////////// -class CEngineConfig -{ -public: - string m_gameFolder; // folder only ("MyGame") - string m_assetPlatform; // what platform folder assets are from if more than one is available or using VFS ("pc" / "es3") - bool m_connectToRemote; - bool m_remoteFileIO; - bool m_waitForConnect; - string m_remoteIP; - int m_remotePort; - - string m_rootFolder; // The engine root folder - string m_branchToken; - - CEngineConfig([[maybe_unused]] const char** sourcePaths = nullptr, [[maybe_unused]] size_t numSearchPaths = 0, [[maybe_unused]] size_t numLevelsUp = 3) - : m_gameFolder(DEFAULT_GAMEFOLDER) - , m_connectToRemote(false) - , m_remoteFileIO(false) - , m_remotePort(DEFAULT_REMOTEPORT) - , m_waitForConnect(false) - , m_remoteIP(DEFAULT_REMOTEIP) - { - m_assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); - - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - AZ::SettingsRegistryInterface::FixedValueString gameFolder; - auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, CONFIG_KEY_FOR_GAMEFOLDER); - if (settingsRegistry->Get(gameFolder, gameFolderKey)) - { - m_gameFolder.assign(gameFolder.c_str(), gameFolder.size()); - } - - AZ::SettingsRegistryInterface::FixedValueString engineRoot; - if (settingsRegistry->Get(engineRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) - { - m_rootFolder.assign(engineRoot.c_str(), engineRoot.size()); - } - } - - OnLoadSettings(); - } - - void CopyToStartupParams(SSystemInitParams& startupParams) const - { - startupParams.remoteFileIO = m_remoteFileIO; - startupParams.remotePort = m_remotePort; - startupParams.connectToRemote = m_connectToRemote; - startupParams.waitForConnection = m_waitForConnect; - - azstrncpy(startupParams.remoteIP, sizeof(startupParams.remoteIP), m_remoteIP.c_str(), m_remoteIP.length() + 1); // +1 for the null terminator - azstrncpy(startupParams.assetsPlatform, sizeof(startupParams.assetsPlatform), m_assetPlatform.c_str(), m_assetPlatform.length() + 1); // +1 for the null terminator - azstrncpy(startupParams.rootPath, sizeof(startupParams.rootPath), m_rootFolder.c_str(), m_rootFolder.length() + 1); // +1 for the null terminator - azstrncpy(startupParams.gameFolderName, sizeof(startupParams.gameFolderName), m_gameFolder.c_str(), m_gameFolder.length() + 1); // +1 for the null terminator - azstrncpy(startupParams.branchToken, sizeof(startupParams.branchToken), m_branchToken.c_str(), m_branchToken.length() + 1); // +1 for the null terminator - - // compute assets path based on game folder name - string gameFolderLower(m_gameFolder); - gameFolderLower.MakeLower(); - azsnprintf(startupParams.assetsPath, sizeof(startupParams.assetsPath), "%s/%s", startupParams.rootPath, gameFolderLower.c_str()); - - // compute where the cache should be located - azsnprintf(startupParams.rootPathCache, sizeof(startupParams.rootPathCache), "%s/Cache/%s/%s", m_rootFolder.c_str(), m_gameFolder.c_str(), m_assetPlatform.c_str()); - azsnprintf(startupParams.assetsPathCache, sizeof(startupParams.assetsPathCache), "%s/%s", startupParams.rootPathCache, gameFolderLower.c_str()); - } - -protected: - - void OnLoadSettings() - { - auto settingsRegistry = AZ::SettingsRegistry::Get(); - if (settingsRegistry == nullptr) - { - AZ_Warning("ParseEngineConfig", false, "Attempting to load configuration data while SettingsRegistry does not exist"); - return; - - } - AZ::SettingsRegistryInterface::FixedValueString settingsKeyPrefix = AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey; - AZ::SettingsRegistryInterface::FixedValueString settingsValueString; - AZ::s64 settingsValueInt{}; - - if (AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, settingsValueInt, settingsKeyPrefix, CONFIG_KEY_FOR_REMOTEFILEIO)) - { - m_remoteFileIO = settingsValueInt != 0; - } - if (AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, settingsValueInt, settingsKeyPrefix, CONFIG_KEY_WAIT_FOR_CONNECT)) - { - m_waitForConnect = settingsValueInt != 0; - } - if (AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, settingsValueInt, settingsKeyPrefix, CONFIG_KEY_FOR_CONNECTTOREMOTE)) - { - m_connectToRemote = settingsValueInt != 0; - } - if (AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, settingsValueInt, settingsKeyPrefix, CONFIG_KEY_FOR_REMOTEPORT)) - { - m_remotePort = aznumeric_cast(settingsValueInt); - } - if (settingsValueString = {}; - AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, settingsValueString, settingsKeyPrefix, CONFIG_KEY_FOR_REMOTEIP)) - { - m_remoteIP.assign(settingsValueString.c_str(), settingsValueString.size()); - } - if (settingsValueString = {}; - AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, settingsValueString, settingsKeyPrefix, CONFIG_KEY_FOR_ASSETS)) - { - m_assetPlatform.assign(settingsValueString.c_str(), settingsValueString.size()); - } - if (settingsValueString = {}; - settingsRegistry->Get(settingsValueString, settingsKeyPrefix + "/" + CONFIG_KEY_FOR_BRANCHTOKEN)) - { - m_branchToken.assign(settingsValueString.c_str(), settingsValueString.size()); - } - - } -}; diff --git a/Code/CryEngine/CryCommon/ProjectDefines.h b/Code/CryEngine/CryCommon/ProjectDefines.h index 211e3fcd94..9308412c15 100644 --- a/Code/CryEngine/CryCommon/ProjectDefines.h +++ b/Code/CryEngine/CryCommon/ProjectDefines.h @@ -293,7 +293,7 @@ typedef uint32 vtx_idx; #if defined(ENABLE_PROFILING_CODE) # define USE_DISK_PROFILER -//# define ENABLE_LOADING_PROFILER // Not guaranteed to have enough slots for all the threads in the system +# define ENABLE_LOADING_PROFILER // requires AZ_PROFILE_TELEMETRY to also be defined #endif #if defined(SOFTCODE_ENABLED) diff --git a/Code/CryEngine/CryCommon/crycommon_files.cmake b/Code/CryEngine/CryCommon/crycommon_files.cmake index 1d1ce19db7..8508180994 100644 --- a/Code/CryEngine/CryCommon/crycommon_files.cmake +++ b/Code/CryEngine/CryCommon/crycommon_files.cmake @@ -110,7 +110,6 @@ set(FILES AzDXGIFormat.h SFunctor.h FunctorBaseFunction.h - ParseEngineConfig.h CustomMemoryHeap.h FunctorBaseMember.h stridedptr.h diff --git a/Code/CryEngine/CrySystem/BootProfiler.cpp b/Code/CryEngine/CrySystem/BootProfiler.cpp deleted file mode 100644 index edfe87d0cd..0000000000 --- a/Code/CryEngine/CrySystem/BootProfiler.cpp +++ /dev/null @@ -1,630 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#if defined(ENABLE_LOADING_PROFILER) - -#include "BootProfiler.h" -#include "ThreadInfo.h" -#include -#include - - -namespace -{ - StaticInstance> gProfilerInstance; - enum - { - eMAX_THREADS_TO_PROFILE = 128, - eNUM_RECORDS_PER_POOL = 2048, // so, eNUM_RECORDS_PER_POOL * sizeof(CBootProfilerRecord) == mem consumed by pool item - // sizeof(CProfileBlockTimes)==152, - // poolmem = 304Kb for 1 pool per thread - }; -} - -int CBootProfiler::CV_sys_bp_frames = 0; -float CBootProfiler::CV_sys_bp_time_threshold = 0; - -class CProfileBlockTimes -{ -protected: - LARGE_INTEGER m_startTimeStamp; - LARGE_INTEGER m_stopTimeStamp; - LARGE_INTEGER m_freq; - CProfileBlockTimes() - { - memset(&m_startTimeStamp, 0, sizeof(m_startTimeStamp)); - memset(&m_stopTimeStamp, 0, sizeof(m_stopTimeStamp)); - memset(&m_freq, 0, sizeof(m_freq)); - } -}; - -class CBootProfilerRecord -{ -public: - const char* m_label; - LARGE_INTEGER m_startTimeStamp; - LARGE_INTEGER m_stopTimeStamp; - LARGE_INTEGER m_freq; - - CBootProfilerRecord* m_pParent; - typedef AZStd::vector ChildVector; - ChildVector m_Childs; - - CryFixedStringT<256> m_args; - - ILINE CBootProfilerRecord(const char* label, LARGE_INTEGER timestamp, LARGE_INTEGER freq, const char* args) - : m_label(label) - , m_startTimeStamp(timestamp) - , m_freq(freq) - , m_pParent(NULL) - { - memset(&m_stopTimeStamp, 0, sizeof(m_stopTimeStamp)); - if (args) - { - m_args = args; - } - } - - ILINE ~CBootProfilerRecord() - { - // childs are allocated via pool as well, the destructors of each child - // is called explicitly, for the purpose of freeing memory occupied by - // m_Child vector. Otherwise there will be a memory leak. - ChildVector::iterator it = m_Childs.begin(); - while (it != m_Childs.end()) - { - (*it)->~CBootProfilerRecord(); - ++it; - } - } - - void Print(AZ::IO::HandleType fileHandle, char* buf, size_t buf_size, size_t depth, LARGE_INTEGER stopTime, const char* threadName, const float timeThreshold) - { - if (m_stopTimeStamp.QuadPart == 0) - { - m_stopTimeStamp = stopTime; - } - - const float time = (float)(m_stopTimeStamp.QuadPart - m_startTimeStamp.QuadPart) * 1000.f / (float)m_freq.QuadPart; - - if (timeThreshold > 0.0f && time < timeThreshold) - { - return; - } - - string tabs; //tabs(depth++, '\t') - tabs.insert(0, depth++, '\t'); - - { - string label = m_label; - label.replace("&", "&"); - label.replace("<", "<"); - label.replace(">", ">"); - label.replace("\"", """); - label.replace("'", "'"); - - if (m_args.size() > 0) - { - m_args.replace("&", "&"); - m_args.replace("<", "<"); - m_args.replace(">", ">"); - m_args.replace("\"", """); - m_args.replace("'", "'"); - m_args.replace("%", "%"); - } - - sprintf_s(buf, buf_size, "%s \n", - tabs.c_str(), label.c_str(), time, m_startTimeStamp.QuadPart, m_stopTimeStamp.QuadPart, m_args.c_str()); - AZ::IO::Print(fileHandle, buf); - } - - const size_t childsSize = m_Childs.size(); - for (size_t i = 0; i < childsSize; ++i) - { - CBootProfilerRecord* record = m_Childs[i]; - assert(record); - record->Print(fileHandle, buf, buf_size, depth, stopTime, threadName, timeThreshold); - } - - sprintf_s(buf, buf_size, "%s\n", tabs.c_str()); - AZ::IO::Print(fileHandle, buf); - } -}; - -////////////////////////////////////////////////////////////////////////// - -class CProfileInfo -{ - friend class CBootProfilerSession; -private: - CBootProfilerRecord* m_pRoot; - CBootProfilerRecord* m_pCurrent; -public: - CProfileInfo() - : m_pRoot(NULL) - , m_pCurrent(NULL) {} -}; - - -class CBootProfilerThreadsInterface -{ -protected: - CBootProfilerThreadsInterface() - { - memset(m_threadInfo, 0, sizeof(m_threadInfo)); - m_threadCounter = 0; - } - - unsigned int GetThreadIndexByID(unsigned int threadID); - const char* GetThreadNameByIndex(unsigned int threadIndex); - - int m_threadCounter; -private: - unsigned int m_threadInfo[eMAX_THREADS_TO_PROFILE]; //threadIDs -}; - -////////////////////////////////////////////////////////////////////////// -ILINE unsigned int CBootProfilerThreadsInterface::GetThreadIndexByID(unsigned int threadID) -{ - for (int i = 0; i < eMAX_THREADS_TO_PROFILE; ++i) - { - if (m_threadInfo[i] == 0) - { - break; - } - if (m_threadInfo[i] == threadID) - { - return i; - } - } - - unsigned int counter = CryInterlockedIncrement(&m_threadCounter) - 1; //count to index - m_threadInfo[counter] = threadID; - - return counter; -} - -ILINE const char* CBootProfilerThreadsInterface::GetThreadNameByIndex(unsigned int threadIndex) -{ - assert(threadIndex < m_threadCounter); - - const char* threadName = CryThreadGetName(m_threadInfo[threadIndex]); - return threadName; -} - -class CRecordPool -{ -public: - CRecordPool() - : m_baseAddr(NULL) - , m_allocCounter(0) - , m_next(NULL) - { - m_baseAddr = (CBootProfilerRecord*)CryModuleMemalign(eNUM_RECORDS_PER_POOL * sizeof(CBootProfilerRecord), 16); - } - ~CRecordPool() - { - CryModuleMemalignFree(m_baseAddr); - delete m_next; - } - - ILINE CBootProfilerRecord* allocateRecord() - { - if (m_allocCounter < eNUM_RECORDS_PER_POOL) - { - CBootProfilerRecord* newRecord = m_baseAddr + m_allocCounter; - ++m_allocCounter; - return newRecord; - } - else - { - return NULL; - } - } - - ILINE void setNextPool(CRecordPool* pool) { m_next = pool; } - -private: - CBootProfilerRecord* m_baseAddr; - uint32 m_allocCounter; - - CRecordPool* m_next; -}; - -class CBootProfilerSession - : public CBootProfilerThreadsInterface - , protected CProfileBlockTimes -{ -public: - CBootProfilerSession(); - ~CBootProfilerSession(); - - void Start(); - void Stop(); - - CBootProfilerRecord* StartBlock(const char* name, const char* args); - void StopBlock(CBootProfilerRecord* record); - - void CollectResults(const char* filename, const float timeThreshold); - -private: - string m_name; - - CProfileInfo m_threadsProfileInfo[eMAX_THREADS_TO_PROFILE]; - CRecordPool* m_threadsRecordsPool[eMAX_THREADS_TO_PROFILE]; //head - CRecordPool* m_threadsCurrentPools[eMAX_THREADS_TO_PROFILE]; //current -}; - - -////////////////////////////////////////////////////////////////////////// - -CBootProfilerSession::CBootProfilerSession() -{ - memset(m_threadsProfileInfo, 0, sizeof(m_threadsProfileInfo)); - - memset(m_threadsRecordsPool, 0, sizeof(m_threadsRecordsPool)); - memset(m_threadsCurrentPools, 0, sizeof(m_threadsCurrentPools)); -} - -CBootProfilerSession::~CBootProfilerSession() -{ - for (unsigned int i = 0; i < m_threadCounter; ++i) - { - CProfileInfo& profile = m_threadsProfileInfo[i]; - - // Since m_pRoot is allocated using memory pool (line 296), - // its destructor is called explicitly to free the memory of - // m_Childs and each of its child. - - if (profile.m_pRoot) - { - profile.m_pRoot->~CBootProfilerRecord(); - } - delete m_threadsRecordsPool[i]; - } -} - -void CBootProfilerSession::Start() -{ - LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - m_startTimeStamp = time; - m_freq = freq; -} - -void CBootProfilerSession::Stop() -{ - LARGE_INTEGER time; - QueryPerformanceCounter(&time); - m_stopTimeStamp = time; -} - -CBootProfilerRecord* CBootProfilerSession::StartBlock(const char* name, const char* args) -{ - const unsigned int curThread = CryGetCurrentThreadId(); - const unsigned int threadIndex = GetThreadIndexByID(curThread); - - assert(threadIndex < eMAX_THREADS_TO_PROFILE); - - CProfileInfo& profile = m_threadsProfileInfo[threadIndex]; - - CRecordPool* pool = m_threadsCurrentPools[threadIndex]; - - if (!profile.m_pRoot) - { - if (!pool) - { - pool = new CRecordPool; - m_threadsRecordsPool[threadIndex] = pool; - m_threadsCurrentPools[threadIndex] = pool; - } - - CBootProfilerRecord* rec = pool->allocateRecord(); - profile.m_pRoot = profile.m_pCurrent = new(rec)CBootProfilerRecord("root", m_startTimeStamp, m_freq, args); - } - - assert(pool); - - LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - - CBootProfilerRecord* pParent = profile.m_pCurrent; - assert(pParent); - assert(profile.m_pRoot); - - CBootProfilerRecord* rec = pool->allocateRecord(); - if (!rec) - { - //pool is full, create a new one - pool = new CRecordPool; - m_threadsCurrentPools[threadIndex]->setNextPool(pool); - m_threadsCurrentPools[threadIndex] = pool; - - rec = pool->allocateRecord(); - } - - profile.m_pCurrent = new(rec)CBootProfilerRecord(name, time, freq, args); - profile.m_pCurrent->m_pParent = pParent; - pParent->m_Childs.push_back(profile.m_pCurrent); - - return profile.m_pCurrent; -} - -void CBootProfilerSession::StopBlock(CBootProfilerRecord* record) -{ - if (record) - { - LARGE_INTEGER time; - QueryPerformanceCounter(&time); - record->m_stopTimeStamp = time; - - unsigned int curThread = CryGetCurrentThreadId(); - unsigned int threadIndex = GetThreadIndexByID(curThread); - assert(threadIndex < eMAX_THREADS_TO_PROFILE); - - CProfileInfo& profile = m_threadsProfileInfo[threadIndex]; - profile.m_pCurrent = record->m_pParent; - } -} - -void CBootProfilerSession::CollectResults(const char* filename, const float timeThreshold) -{ - if (!gEnv || !gEnv->pCryPak) - { - AZ_Warning("BootProfiler", false, "CryPak not set - skipping CollectResults"); - return; - } - static const char* szTestResults = "@cache@\\TestResults"; - string filePath = string(szTestResults) + "\\" + "bp_" + filename + ".xml"; - char path[AZ::IO::IArchive::MaxPath] = ""; - gEnv->pCryPak->AdjustFileName(filePath.c_str(), path, AZ_ARRAY_SIZE(path), AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FLAGS_FOR_WRITING); - gEnv->pCryPak->MakeDir(szTestResults); - - AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; - gEnv->pFileIO->Open(path, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, fileHandle); - if (fileHandle == AZ::IO::InvalidHandle) - { - return; - } - - char buf[512]; - const unsigned int buf_size = sizeof(buf); - - sprintf_s(buf, buf_size, "\n"); - AZ::IO::Print(fileHandle, buf); - - const size_t numThreads = m_threadCounter; - for (size_t i = 0; i < numThreads; ++i) - { - CBootProfilerRecord* pRoot = m_threadsProfileInfo[i].m_pRoot; - if (pRoot) - { - pRoot->m_stopTimeStamp = m_stopTimeStamp; - - const char* threadName = GetThreadNameByIndex(i); - if (!threadName) - { - threadName = "UNKNOWN"; - } - - - const float time = (float)(pRoot->m_stopTimeStamp.QuadPart - pRoot->m_startTimeStamp.QuadPart) * 1000.f / (float)pRoot->m_freq.QuadPart; - - sprintf_s(buf, buf_size, "\t \n", threadName, time, - pRoot->m_startTimeStamp.QuadPart, pRoot->m_stopTimeStamp.QuadPart); - AZ::IO::Print(fileHandle, buf); - - for (size_t recordIdx = 0; recordIdx < pRoot->m_Childs.size(); ++recordIdx) - { - CBootProfilerRecord* record = pRoot->m_Childs[recordIdx]; - assert(record); - record->Print(fileHandle, buf, buf_size, 2, m_stopTimeStamp, threadName, timeThreshold); - } - - sprintf_s(buf, buf_size, "\t\n"); - AZ::IO::Print(fileHandle, buf); - } - } - - sprintf_s(buf, buf_size, "\n"); - AZ::IO::Print(fileHandle, buf); - gEnv->pFileIO->Close(fileHandle); -} - - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -CBootProfiler& CBootProfiler::GetInstance() -{ - return gProfilerInstance; -} - -CBootProfiler::CBootProfiler() - : m_pCurrentSession(NULL) - , m_pFrameRecord(NULL) - , m_levelLoadAdditionalFrames(0) -{ -} - -CBootProfiler::~CBootProfiler() -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - for (TSessionMap::iterator it = m_sessions.begin(); it != m_sessions.end(); ++it) - { - CBootProfilerSession* session = it->second; - delete session; - } -} - -// start session -void CBootProfiler::StartSession(const char* sessionName) -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - - TSessionMap::const_iterator it = m_sessions.find(sessionName); - if (it == m_sessions.end()) - { - m_pCurrentSession = new CBootProfilerSession(); - m_sessions[sessionName] = m_pCurrentSession; - m_pCurrentSession->Start(); - } -} - -// stop session -void CBootProfiler::StopSession(const char* sessionName) -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - if (m_pCurrentSession) - { - TSessionMap::iterator it = m_sessions.find(sessionName); - if (it != m_sessions.end()) - { - if (m_pCurrentSession == it->second) - { - CBootProfilerSession* session = m_pCurrentSession; - m_pCurrentSession = NULL; - - session->Stop(); - session->CollectResults(sessionName, CV_sys_bp_time_threshold); - - delete session; - } - m_sessions.erase(it); - } - } -} - -CBootProfilerRecord* CBootProfiler::StartBlock(const char* name, const char* args) -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - if (m_pCurrentSession) - { - return m_pCurrentSession->StartBlock(name, args); - } - return NULL; -} - -void CBootProfiler::StopBlock(CBootProfilerRecord* record) -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - if (m_pCurrentSession) - { - m_pCurrentSession->StopBlock(record); - } -} - -void CBootProfiler::StartFrame(const char* name) -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - if (CV_sys_bp_frames) - { - StartSession("frames"); - m_pFrameRecord = StartBlock(name, NULL); - } -} - -void CBootProfiler::StopFrame() -{ - AZStd::lock_guard recordGuard{ m_recordMutex }; - if (m_pCurrentSession && CV_sys_bp_frames) - { - StopBlock(m_pFrameRecord); - m_pFrameRecord = NULL; - - --CV_sys_bp_frames; - if (0 == CV_sys_bp_frames) - { - StopSession("frames"); - } - } - - if (m_pCurrentSession && m_levelLoadAdditionalFrames) - { - --m_levelLoadAdditionalFrames; - if (0 == m_levelLoadAdditionalFrames) - { - StopSession("level"); - } - } -} - -void CBootProfiler::Init(ISystem* pSystem) -{ - //REGISTER_CVAR(sys_BootProfiler, 1, VF_DEV_ONLY, - // "Collect and output session statistics into TestResults/bp_(session_name).xml \n" - // "0 = Disabled\n" - // "1 = Enabled\n"); - - pSystem->GetISystemEventDispatcher()->RegisterListener(this); - StartSession("boot"); -} - -void CBootProfiler::RegisterCVars() -{ - REGISTER_CVAR2("sys_bp_frames", &CV_sys_bp_frames, 0, VF_DEV_ONLY, "Starts frame profiling for specified number of frames using BootProfiler"); - REGISTER_CVAR2("sys_bp_time_threshold", &CV_sys_bp_time_threshold, 0.1f, VF_DEV_ONLY, "If greater than 0 don't write blocks that took less time (default 0.1 ms)"); -} - -void CBootProfiler::OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) -{ - switch (event) - { - case ESYSTEM_EVENT_GAME_POST_INIT_DONE: - { - StopSession("boot"); - break; - } - case ESYSTEM_EVENT_GAME_MODE_SWITCH_START: - { - break; - } - - case ESYSTEM_EVENT_GAME_MODE_SWITCH_END: - { - break; - } - - case ESYSTEM_EVENT_LEVEL_LOAD_START: - { - break; - } - case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE: - { - StartSession("level"); - break; - } - case ESYSTEM_EVENT_LEVEL_LOAD_END: - { - StopSession("level"); - break; - } - case ESYSTEM_EVENT_LEVEL_PRECACHE_END: - { - //level loading can be stopped here, or m_levelLoadAdditionalFrames can be used to prolong dump for this amount of frames - //StopSession("level"); - m_levelLoadAdditionalFrames = 20; - break; - } - } -} - -void CBootProfiler::SetFrameCount(int frameCount) -{ - CV_sys_bp_frames = frameCount; -} -#endif diff --git a/Code/CryEngine/CrySystem/BootProfiler.h b/Code/CryEngine/CrySystem/BootProfiler.h deleted file mode 100644 index ad097257a6..0000000000 --- a/Code/CryEngine/CrySystem/BootProfiler.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_BOOTPROFILER_H -#define CRYINCLUDE_CRYSYSTEM_BOOTPROFILER_H -#pragma once - -#if defined(ENABLE_LOADING_PROFILER) - -#include -#include -#include - -class CBootProfilerRecord; -class CBootProfilerSession; - -class CBootProfiler - : public ISystemEventListener -{ - friend class CBootProfileBLock; -public: - CBootProfiler(); - ~CBootProfiler(); - - static CBootProfiler& GetInstance(); - - void Init(ISystem* pSystem); - void RegisterCVars(); - - void StartSession(const char* sessionName); - void StopSession(const char* sessionName); - - CBootProfilerRecord* StartBlock(const char* name, const char* args); - void StopBlock(CBootProfilerRecord* record); - - void StartFrame(const char* name); - void StopFrame(); -protected: - // === ISystemEventListener - virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam); - void SetFrameCount(int frameCount); - -private: - CBootProfilerSession* m_pCurrentSession; - typedef AZStd::unordered_map TSessionMap; - TSessionMap m_sessions; - - static int CV_sys_bp_frames; - static float CV_sys_bp_time_threshold; - CBootProfilerRecord* m_pFrameRecord; - AZStd::recursive_mutex m_recordMutex; - int m_levelLoadAdditionalFrames; -}; - -#endif - -#endif // CRYINCLUDE_CRYSYSTEM_BOOTPROFILER_H diff --git a/Code/CryEngine/CrySystem/DebugCallStack.cpp b/Code/CryEngine/CrySystem/DebugCallStack.cpp index fee3e2bf53..789bf64844 100644 --- a/Code/CryEngine/CrySystem/DebugCallStack.cpp +++ b/Code/CryEngine/CrySystem/DebugCallStack.cpp @@ -277,17 +277,6 @@ int DebugCallStack::handleException(EXCEPTION_POINTERS* exception_pointer) sprintf_s(excCode, "0x%08X", exception_pointer->ExceptionRecord->ExceptionCode); WriteLineToLog("Exception: %s, at Address: %s", excCode, excAddr); - if (CSystem* pSystem = (CSystem*)GetSystem()) - { - if (const char* pLoadingProfilerCallstack = pSystem->GetLoadingProfilerCallstack()) - { - if (pLoadingProfilerCallstack[0]) - { - WriteLineToLog(" LoadingProfilerCallstack: %s", pLoadingProfilerCallstack); - } - } - } - { IMemoryManager::SProcessMemInfo memInfo; if (gEnv->pSystem->GetIMemoryManager()->GetProcessMemInfo(memInfo)) @@ -593,7 +582,7 @@ void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex) AZ::Debug::SymbolStorage::DecodeFrames(frames, numFrames, lines); for (unsigned int i2 = 0; i2 < numFrames; ++i2) { - fprintf(f, "%2d) %s\n", numFrames - i2, lines[i2]); + fprintf(f, "%2d) %s\n", numFrames - i2, lines[i2]); } } } diff --git a/Code/CryEngine/CrySystem/IDebugCallStack.cpp b/Code/CryEngine/CrySystem/IDebugCallStack.cpp index 178bbf0544..8394da6463 100644 --- a/Code/CryEngine/CrySystem/IDebugCallStack.cpp +++ b/Code/CryEngine/CrySystem/IDebugCallStack.cpp @@ -20,8 +20,8 @@ #include "System.h" #include #include - -#include +#include +#include //#if !defined(LINUX) #include @@ -186,21 +186,17 @@ AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option") } } - if (gEnv->pConsole) - { - if (ICVar* pCVarGameDir = gEnv->pConsole->GetCVar("sys_game_folder")) - { - sprintf(s, "GameDir: %s\n", pCVarGameDir->GetString()); - azstrcat(str, length, s); - } - } + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + azstrcat(str, length, "ProjectDir: "); + azstrcat(str, length, projectPath.c_str()); + azstrcat(str, length, "\n"); #if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_APPEND_MODULENAME GetModuleFileNameA(NULL, s, sizeof(s)); // Log EXE filename only if possible (not full EXE path which could contain sensitive info) AZStd::string exeName; - if (AzFramework::StringFunc::Path::GetFullFileName(s, exeName)) + if (AZ::StringFunc::Path::GetFullFileName(s, exeName)) { azstrcat(str, length, "Executable: "); azstrcat(str, length, exeName.c_str()); diff --git a/Code/CryEngine/CrySystem/LoadingProfiler.cpp b/Code/CryEngine/CrySystem/LoadingProfiler.cpp deleted file mode 100644 index c736dce8cd..0000000000 --- a/Code/CryEngine/CrySystem/LoadingProfiler.cpp +++ /dev/null @@ -1,647 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#if defined(ENABLE_LOADING_PROFILER) - -#include "System.h" -#include "LoadingProfiler.h" - -#define LOADING_TIME_CONTAINER_MAX_TEXT_SIZE 1024 -#define MAX_LOADING_TIME_PROFILER_STACK_DEPTH 16 - -//#define SAVE_SAVELEVELSTATS_IN_ROOT - -struct SLoadingTimeContainer - : public _i_reference_target_t -{ - SLoadingTimeContainer() {} - - SLoadingTimeContainer(SLoadingTimeContainer* pParent, const char* pPureFuncName, const int nRootIndex) - { - m_dSelfMemUsage = m_dTotalMemUsage = m_dSelfTime = m_dTotalTime = 0; - m_nCounter = 1; - m_pFuncName = pPureFuncName; - m_pParent = pParent; - m_nRootIndex = nRootIndex; - } - - static int Cmp_SLoadingTimeContainer_Time(const void* v1, const void* v2) - { - SLoadingTimeContainer* pChunk1 = (SLoadingTimeContainer*)v1; - SLoadingTimeContainer* pChunk2 = (SLoadingTimeContainer*)v2; - - if (pChunk1->m_dSelfTime > pChunk2->m_dSelfTime) - { - return -1; - } - else if (pChunk1->m_dSelfTime < pChunk2->m_dSelfTime) - { - return 1; - } - - return 0; - } - - static int Cmp_SLoadingTimeContainer_MemUsage(const void* v1, const void* v2) - { - SLoadingTimeContainer* pChunk1 = (SLoadingTimeContainer*)v1; - SLoadingTimeContainer* pChunk2 = (SLoadingTimeContainer*)v2; - - if (pChunk1->m_dSelfMemUsage > pChunk2->m_dSelfMemUsage) - { - return -1; - } - else if (pChunk1->m_dSelfMemUsage < pChunk2->m_dSelfMemUsage) - { - return 1; - } - - return 0; - } - - static double GetUsedMemory(ISystem* pSysytem) - { - static IMemoryManager::SProcessMemInfo processMemInfo; - pSysytem->GetIMemoryManager()->GetProcessMemInfo(processMemInfo); - return double(processMemInfo.PagefileUsage) / double(1024 * 1024); - } - - - void Clear() - { - for (size_t i = 0, end = m_pChilds.size(); i < end; ++i) - { - delete m_pChilds[i]; - } - } - - ~SLoadingTimeContainer() - { - Clear(); - } - - - double m_dSelfTime, m_dTotalTime; - double m_dSelfMemUsage, m_dTotalMemUsage; - uint32 m_nCounter; - - const char* m_pFuncName; - SLoadingTimeContainer* m_pParent; - int m_nRootIndex; - std::vector m_pChilds; - - DiskOperationInfo m_selfInfo; - DiskOperationInfo m_totalInfo; - bool m_bUsed; -}; - -bool operator== (const SLoadingTimeContainer& a, const SLoadingTimeContainer& b) -{ - return b.m_pFuncName == a.m_pFuncName; -} - -bool operator== (const SLoadingTimeContainer& a, const char* b) -{ - return b == a.m_pFuncName; -} - - -SLoadingTimeContainer* CLoadingProfilerSystem::m_pCurrentLoadingTimeContainer = 0; -SLoadingTimeContainer* CLoadingProfilerSystem::m_pRoot[2] = {0, 0}; -int CLoadingProfilerSystem::m_iActiveRoot = 0; -ICVar* CLoadingProfilerSystem::m_pEnableProfile = 0; -int CLoadingProfilerSystem::nLoadingProfileMode = 1; -int CLoadingProfilerSystem::nLoadingProfilerNotTrackedAllocations = -1; -CryCriticalSection CLoadingProfilerSystem::csLock; - -////////////////////////////////////////////////////////////////////////// -void CLoadingProfilerSystem::OutputLoadingTimeStats(ILog* pLog, int nMode) -{ - nLoadingProfileMode = nMode; - - PodArray arrNoStack; - CreateNoStackList(arrNoStack); - - - if (nLoadingProfileMode > 0) - { // loading mem stats per func - pLog->Log("------ Level loading memory allocations (MB) by function ------------"); - pLog->Log(" ||Self | Total | Calls | Function (%d MB lost)||", nLoadingProfilerNotTrackedAllocations); - pLog->Log("---------------------------------------------------------------------"); - - qsort(arrNoStack.GetElements(), arrNoStack.Count(), sizeof(arrNoStack[0]), SLoadingTimeContainer::Cmp_SLoadingTimeContainer_MemUsage); - - for (int i = 0; i < arrNoStack.Count(); i++) - { - const SLoadingTimeContainer* pTimeContainer = &arrNoStack[i]; - pLog->Log("|%6.1f | %6.1f | %6d | %s|", - pTimeContainer->m_dSelfMemUsage, pTimeContainer->m_dTotalMemUsage, (int)pTimeContainer->m_nCounter, pTimeContainer->m_pFuncName); - } - - pLog->Log("---------------------------------------------------------------------"); - } - - if (nLoadingProfileMode > 0) - { // loading time stats per func - pLog->Log("----------- Level loading time (sec) by function --------------------"); - pLog->Log(" ||Self | Total | Calls | Function||"); - pLog->Log("---------------------------------------------------------------------"); - - qsort(arrNoStack.GetElements(), arrNoStack.Count(), sizeof(arrNoStack[0]), SLoadingTimeContainer::Cmp_SLoadingTimeContainer_Time); - - for (int i = 0; i < arrNoStack.Count(); i++) - { - const SLoadingTimeContainer* pTimeContainer = &arrNoStack[i]; - pLog->Log("|%6.1f | %6.1f | %6d | %s|", - pTimeContainer->m_dSelfTime, pTimeContainer->m_dTotalTime, (int)pTimeContainer->m_nCounter, pTimeContainer->m_pFuncName); - } - - if (nLoadingProfileMode == 1) - { - pLog->Log("----- ( Use sys_ProfileLevelLoading 2 for more detailed stats ) -----"); - } - else - { - pLog->Log("---------------------------------------------------------------------"); - } - } - - if (nLoadingProfileMode > 0) - { // file info - pLog->Log("----------------------------- Level file information by function --------------------------------"); - pLog->Log("|| Self | Total |Bandwith| Calls | Function||"); - pLog->Log("|| Seeks |FileOpen|FileRead| Seeks |FileOpen|FileRead| Kb/s | | ||"); - - qsort(arrNoStack.GetElements(), arrNoStack.Count(), sizeof(arrNoStack[0]), SLoadingTimeContainer::Cmp_SLoadingTimeContainer_Time); - - for (int i = 0; i < arrNoStack.Count(); i++) - { - const SLoadingTimeContainer* pTimeContainer = &arrNoStack[i]; - double bandwidth = pTimeContainer->m_dSelfTime > 0 ? (pTimeContainer->m_selfInfo.m_dOperationSize / pTimeContainer->m_dSelfTime / 1024.0) : 0.; - pLog->Log("|%6d | %6d | %6d |%6d | %6d | %6d | %6.1f | %6d | %s|", - pTimeContainer->m_selfInfo.m_nSeeksCount, pTimeContainer->m_selfInfo.m_nFileOpenCount, pTimeContainer->m_selfInfo.m_nFileReadCount, - pTimeContainer->m_totalInfo.m_nSeeksCount, pTimeContainer->m_totalInfo.m_nFileOpenCount, pTimeContainer->m_totalInfo.m_nFileReadCount, - bandwidth, (int)pTimeContainer->m_nCounter, pTimeContainer->m_pFuncName); - } - - if (nLoadingProfileMode == 1) - { - pLog->Log("----- ( Use sys_ProfileLevelLoading 2 for more detailed stats ) -----"); - } - else - { - pLog->Log("---------------------------------------------------------------------"); - } - } -} - -struct CSystemEventListner_LoadingProfiler - : public ISystemEventListener -{ -private: - CLoadingTimeProfiler* m_pPrecacheProfiler; - ESystemEvent lastEvent; -public: - CSystemEventListner_LoadingProfiler() - : m_pPrecacheProfiler(NULL) {} - - virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) - { - switch (event) - { - case ESYSTEM_EVENT_GAME_MODE_SWITCH_START: - { - CLoadingProfilerSystem::Clean(); - if (m_pPrecacheProfiler == NULL) - { - m_pPrecacheProfiler = new CLoadingTimeProfiler(gEnv->pSystem, "ModeSwitch"); - } - break; - } - - case ESYSTEM_EVENT_GAME_MODE_SWITCH_END: - { - SAFE_DELETE(m_pPrecacheProfiler); - CLoadingProfilerSystem::SaveTimeContainersToFile(gEnv->bMultiplayer == true ? "mode_switch_mp.lmbrlp" : "mode_switch_sp.lmbrlp", 0.0, true); - } - - case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE: - { - CLoadingProfilerSystem::Clean(); - if (m_pPrecacheProfiler == NULL) - { - m_pPrecacheProfiler = new CLoadingTimeProfiler(gEnv->pSystem, "LevelLoading"); - } - break; - } - - case ESYSTEM_EVENT_LEVEL_LOAD_END: - { - delete m_pPrecacheProfiler; - m_pPrecacheProfiler = new CLoadingTimeProfiler(gEnv->pSystem, "Precache"); - break; - } - case ESYSTEM_EVENT_LEVEL_PRECACHE_END: - { - if (lastEvent == ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME) - { - SAFE_DELETE(m_pPrecacheProfiler); - string levelName = "no_level"; - ICVar* sv_map = gEnv->pConsole->GetCVar("sv_map"); - if (sv_map) - { - levelName = sv_map->GetString(); - } - - string levelNameFullProfile = levelName + "_LP.lmbrlp"; - string levelNameThreshold = levelName + "_LP_OneSec.lmbrlp"; - CLoadingProfilerSystem::SaveTimeContainersToFile(levelNameFullProfile.c_str(), 0.0, false); - CLoadingProfilerSystem::SaveTimeContainersToFile(levelNameThreshold.c_str(), 1.0, true); - } - break; - } - case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: - { - // Ensure that the precache profiler is dead - SAFE_DELETE(m_pPrecacheProfiler); - break; - } - } - - if (event != ESYSTEM_EVENT_RANDOM_SEED) - { - lastEvent = event; - } - } -}; - -static CSystemEventListner_LoadingProfiler g_system_event_listener_loadingProfiler; - -void CLoadingProfilerSystem::Init() -{ - gEnv->pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_loadingProfiler); -} - - -////////////////////////////////////////////////////////////////////////// -void CLoadingProfilerSystem::ShutDown() -{ - if (gEnv && gEnv->pSystem && gEnv->pSystem->GetISystemEventDispatcher()) - { - gEnv->pSystem->GetISystemEventDispatcher()->RemoveListener(&g_system_event_listener_loadingProfiler); - } -} - -////////////////////////////////////////////////////////////////////////// -SLoadingTimeContainer* CLoadingProfilerSystem::StartLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler, const char* szFuncName) -{ - if (!nLoadingProfileMode || !gEnv->pConsole) - { - return NULL; - } - - DWORD threadID = GetCurrentThreadId(); - - static DWORD dwMainThreadId = GetCurrentThreadId(); - if (threadID != dwMainThreadId) - { - return NULL; - } - - if (!m_pEnableProfile) - { - if (gEnv->pConsole) - { - m_pEnableProfile = gEnv->pConsole->GetCVar("sys_ProfileLevelLoading"); - if (!m_pEnableProfile) - { - return 0; - } - } - else - { - return 0; - } - } - - if (m_pEnableProfile->GetIVal() <= 0) - { - return 0; - } - - //if (m_pCurrentLoadingTimeContainer == m_pRoot && strstr(szFuncName,"Open")) - //{ - // pProfiler->m_constructorInfo.m_nFileOpenCount +=1; - //} - - CryAutoCriticalSection lock(csLock); - - if (true /*pProfiler && pProfiler->m_pSystem*/) - { - ITimer* pTimer = pProfiler->m_pSystem->GetITimer(); - pProfiler->m_fConstructorTime = pTimer->GetAsyncTime().GetSeconds(); - pProfiler->m_fConstructorMemUsage = SLoadingTimeContainer::GetUsedMemory(pProfiler->m_pSystem); - - DiskOperationInfo info; - pProfiler->m_constructorInfo = info; - - if (nLoadingProfilerNotTrackedAllocations < 0) - { - nLoadingProfilerNotTrackedAllocations = (int)pProfiler->m_fConstructorMemUsage; - } - } - - SLoadingTimeContainer* pParent = m_pCurrentLoadingTimeContainer; - if (!pParent) - { - pParent = m_pCurrentLoadingTimeContainer = m_pRoot[m_iActiveRoot] = new SLoadingTimeContainer(0, "Root", m_iActiveRoot); - } - - for (size_t i = 0, end = m_pCurrentLoadingTimeContainer->m_pChilds.size(); i < end; ++i) - { - if (m_pCurrentLoadingTimeContainer->m_pChilds[i]->m_pFuncName == szFuncName) - { - assert(m_pCurrentLoadingTimeContainer->m_pChilds[i]->m_pParent == m_pCurrentLoadingTimeContainer); - assert(!m_pCurrentLoadingTimeContainer->m_pChilds[i]->m_bUsed); - m_pCurrentLoadingTimeContainer->m_pChilds[i]->m_bUsed = true; - m_pCurrentLoadingTimeContainer->m_pChilds[i]->m_nCounter++; - m_pCurrentLoadingTimeContainer = m_pCurrentLoadingTimeContainer->m_pChilds[i]; - return m_pCurrentLoadingTimeContainer; - } - } - - m_pCurrentLoadingTimeContainer = new SLoadingTimeContainer(pParent, szFuncName, pParent->m_nRootIndex); - m_pCurrentLoadingTimeContainer->m_bUsed = true; - { - // Need to iterate from the end than - pParent->m_pChilds.push_back(m_pCurrentLoadingTimeContainer); - } - - return m_pCurrentLoadingTimeContainer; -} - -void CLoadingProfilerSystem::EndLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler) -{ - if (!nLoadingProfileMode) - { - return; - } - - static DWORD dwMainThreadId = GetCurrentThreadId(); - - if (GetCurrentThreadId() != dwMainThreadId) - { - return; - } - - if (!pProfiler->m_pTimeContainer) - { - return; - } - - CryAutoCriticalSection lock(csLock); - - if (true /*pProfiler && pProfiler->m_pSystem*/) - { - ITimer* pTimer = pProfiler->m_pSystem->GetITimer(); - double fSelfTime = pTimer->GetAsyncTime().GetSeconds() - pProfiler->m_fConstructorTime; - double fMemUsage = SLoadingTimeContainer::GetUsedMemory(pProfiler->m_pSystem); - double fSelfMemUsage = fMemUsage - pProfiler->m_fConstructorMemUsage; - - - if (fSelfTime < 0.0) - { - assert(0); - } - pProfiler->m_pTimeContainer->m_dSelfTime += fSelfTime; - pProfiler->m_pTimeContainer->m_dTotalTime += fSelfTime; - pProfiler->m_pTimeContainer->m_dSelfMemUsage += fSelfMemUsage; - pProfiler->m_pTimeContainer->m_dTotalMemUsage += fSelfMemUsage; - - DiskOperationInfo info; - info -= pProfiler->m_constructorInfo; - pProfiler->m_pTimeContainer->m_totalInfo += info; - pProfiler->m_pTimeContainer->m_selfInfo += info; - pProfiler->m_pTimeContainer->m_bUsed = false; - - SLoadingTimeContainer* pParent = pProfiler->m_pTimeContainer->m_pParent; - pParent->m_selfInfo -= info; - pParent->m_dSelfTime -= fSelfTime; - pParent->m_dSelfMemUsage -= fSelfMemUsage; - if (pProfiler->m_pTimeContainer->m_pParent && pProfiler->m_pTimeContainer->m_pParent->m_nRootIndex == m_iActiveRoot) - { - m_pCurrentLoadingTimeContainer = pProfiler->m_pTimeContainer->m_pParent; - } - } -} - -const char* CLoadingProfilerSystem::GetLoadingProfilerCallstack() -{ - CryAutoCriticalSection lock(csLock); - - static char szStack[1024]; - - szStack[0] = 0; - - SLoadingTimeContainer* pC = m_pCurrentLoadingTimeContainer; - - PodArray arrItems; - - while (pC) - { - arrItems.Add(pC); - pC = pC->m_pParent; - } - - for (int i = arrItems.Count() - 1; i >= 0; i--) - { - cry_strcat(szStack, " > "); - cry_strcat(szStack, arrItems[i]->m_pFuncName); - } - - return &szStack[0]; -} - -void CLoadingProfilerSystem::FillProfilersList(AZStd::vector& profilers) -{ - UpdateSelfStatistics(m_pRoot[m_iActiveRoot]); - - PodArray arrNoStack; - CreateNoStackList(arrNoStack); - //qsort(arrNoStack.GetElements(), arrNoStack.Count(), sizeof(arrNoStack[0]), SLoadingTimeContainer::Cmp_SLoadingTimeContainer_Time); - - uint32 count = arrNoStack.Size(); - profilers.resize(count); - - for (uint32 i = 0; i < count; ++i) - { - profilers[i].name = arrNoStack[i].m_pFuncName; - profilers[i].selfTime = arrNoStack[i].m_dSelfTime; - profilers[i].callsTotal = arrNoStack[i].m_nCounter; - profilers[i].totalTime = arrNoStack[i].m_dTotalTime; - profilers[i].memorySize = arrNoStack[i].m_dTotalMemUsage; - profilers[i].selfInfo = arrNoStack[i].m_selfInfo; - profilers[i].totalInfo = arrNoStack[i].m_totalInfo; - } -} - - -void CLoadingProfilerSystem::AddTimeContainerFunction(PodArray& arrNoStack, SLoadingTimeContainer* node) -{ - if (!node) - { - return; - } - - SLoadingTimeContainer* it = std::find(arrNoStack.begin(), arrNoStack.end(), node->m_pFuncName); - - if (it == arrNoStack.end()) - { - arrNoStack.push_back(*node); - } - else - { - it->m_dSelfMemUsage += node->m_dSelfMemUsage; - it->m_dSelfTime += node->m_dSelfTime; - it->m_dTotalMemUsage += node->m_dTotalMemUsage; - it->m_dTotalTime += node->m_dTotalTime; - it->m_nCounter += node->m_nCounter; - it->m_selfInfo += node->m_selfInfo; - it->m_totalInfo += node->m_totalInfo; - } - - for (size_t i = 0, end = node->m_pChilds.size(); i < end; ++i) - { - AddTimeContainerFunction(arrNoStack, node->m_pChilds[i]); - } -} - -void CLoadingProfilerSystem::CreateNoStackList(PodArray& arrNoStack) -{ - AddTimeContainerFunction(arrNoStack, m_pRoot[m_iActiveRoot]); -} - -#define g_szTestResults "@cache@\\TestResults" - -void CLoadingProfilerSystem::SaveTimeContainersToFile(const char* name, double fMinTotalTime, bool bClean) -{ - if (m_pRoot[m_iActiveRoot]) - { - const char* levelName = name; - //Ignore any folders in the input name - const char* folder = strrchr(name, '/'); - if (folder != NULL) - { - levelName = folder + 1; - } - char path[AZ::IO::IArchive::MaxPath]; - path[sizeof(path) - 1] = 0; - - gEnv->pCryPak->AdjustFileName(string(string(g_szTestResults) + "\\" + levelName).c_str(), path, AZ_ARRAY_SIZE(path), AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FLAGS_FOR_WRITING); - gEnv->pCryPak->MakeDir(g_szTestResults); - - AZ::IO::HandleType handle = AZ::IO::InvalidHandle; - - AZ::IO::Result f = AZ::IO::FileIOBase::GetInstance()->Open(path,AZ::IO::OpenMode::ModeWrite, handle); - - if (handle != AZ::IO::InvalidHandle) - { - UpdateSelfStatistics(m_pRoot[m_iActiveRoot]); - WriteTimeContainerToFile(m_pRoot[m_iActiveRoot], handle, 0, fMinTotalTime); - AZ::IO::FileIOBase::GetInstance()->Close(handle); - } - - if (bClean) - { - Clean(); - } - } -} - -void CLoadingProfilerSystem::WriteTimeContainerToFile(SLoadingTimeContainer* p, AZ::IO::HandleType &handle, unsigned int depth, double fMinTotalTime) -{ - if (p == NULL) - { - return; - } - - if (p->m_dTotalTime < fMinTotalTime) - { - return; - } - - CryFixedStringT sDepth; - for (unsigned int i = 0; i < depth; i++) - { - sDepth += "\t"; - } - - CryFixedStringT<128> str(p->m_pFuncName); - str.replace(':', '_'); - - char data[4096]; - AZ::u64 bytesWritten; - - azsnprintf(data, sizeof(data), "%s<%s selfTime='%f' selfMemory='%f' totalTime='%f' totalMemory='%f' count='%i' totalSeeks='%i' totalReads='%i' totalOpens='%i' totalDiskSize='%f' selfSeeks='%i' selfReads='%i' selfOpens='%i' selfDiskSize='%f'>\n", - sDepth.c_str(), str.c_str(), p->m_dSelfTime, p->m_dSelfMemUsage, p->m_dTotalTime, p->m_dTotalMemUsage, p->m_nCounter, - p->m_totalInfo.m_nSeeksCount, p->m_totalInfo.m_nFileReadCount, p->m_totalInfo.m_nFileOpenCount, p->m_totalInfo.m_dOperationSize, - p->m_selfInfo.m_nSeeksCount, p->m_selfInfo.m_nFileReadCount, p->m_selfInfo.m_nFileOpenCount, p->m_selfInfo.m_dOperationSize); - - AZ::IO::FileIOBase::GetInstance()->Write(handle, data, strlen(data), &bytesWritten); - - for (size_t i = 0, end = p->m_pChilds.size(); i < end; ++i) - { - WriteTimeContainerToFile(p->m_pChilds[i], handle, depth + 1, fMinTotalTime); - } - - azsnprintf(data, sizeof(data), "%s\n", sDepth.c_str(), str.c_str()); - AZ::IO::FileIOBase::GetInstance()->Write(handle, data, strlen(data), &bytesWritten); - -} - -void CLoadingProfilerSystem::UpdateSelfStatistics(SLoadingTimeContainer* p) -{ - if (p == NULL) - { - return; - } - - p->m_dSelfMemUsage = 0; - p->m_dSelfTime = 0; - p->m_nCounter = 1; - p->m_selfInfo.m_dOperationSize = 0; - p->m_selfInfo.m_nFileOpenCount = 0; - p->m_selfInfo.m_nFileReadCount = 0; - p->m_selfInfo.m_nSeeksCount = 0; - - for (size_t i = 0, end = p->m_pChilds.size(); i < end; ++i) - { - p->m_dTotalMemUsage += p->m_pChilds[i]->m_dTotalMemUsage; - p->m_dTotalTime += p->m_pChilds[i]->m_dTotalTime; - p->m_totalInfo += p->m_pChilds[i]->m_totalInfo; - } -} - -void CLoadingProfilerSystem::Clean() -{ - m_iActiveRoot = (m_iActiveRoot + 1) % 2; - if (m_pRoot[m_iActiveRoot]) - { - delete m_pRoot[m_iActiveRoot]; - } - m_pCurrentLoadingTimeContainer = m_pRoot[m_iActiveRoot] = 0; -} - -#endif diff --git a/Code/CryEngine/CrySystem/LoadingProfiler.h b/Code/CryEngine/CrySystem/LoadingProfiler.h deleted file mode 100644 index b90139364e..0000000000 --- a/Code/CryEngine/CrySystem/LoadingProfiler.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_LOADINGPROFILER_H -#define CRYINCLUDE_CRYSYSTEM_LOADINGPROFILER_H -#pragma once - - -#if defined(ENABLE_LOADING_PROFILER) - -struct SLoadingTimeContainer; - - -struct SLoadingProfilerInfo -{ - string name; - double selfTime; - double totalTime; - uint32 callsTotal; - double memorySize; - - DiskOperationInfo selfInfo; - DiskOperationInfo totalInfo; -}; - - -class CLoadingProfilerSystem -{ -public: - static void Init(); - static void ShutDown(); - static void CreateNoStackList(PodArray&); - static void OutputLoadingTimeStats(ILog* pLog, int nMode); - static SLoadingTimeContainer* StartLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler, const char* szFuncName); - static void EndLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler); - static const char* GetLoadingProfilerCallstack(); - static void FillProfilersList(AZStd::vector& profilers); - static void FlushTimeContainers(); - static void SaveTimeContainersToFile(const char*, double fMinTotalTime, bool bClean); - static void WriteTimeContainerToFile(SLoadingTimeContainer* p, AZ::IO::HandleType &handle, unsigned int depth, double fMinTotalTime); - - static void UpdateSelfStatistics(SLoadingTimeContainer* p); - static void Clean(); -protected: - static void AddTimeContainerFunction(PodArray&, SLoadingTimeContainer*); -protected: - static int nLoadingProfileMode; - static int nLoadingProfilerNotTrackedAllocations; - static CryCriticalSection csLock; - static int m_iMaxArraySize; - static SLoadingTimeContainer* m_pCurrentLoadingTimeContainer; - static SLoadingTimeContainer* m_pRoot[2]; - static int m_iActiveRoot; - static ICVar* m_pEnableProfile; -}; - -#endif - -#endif // CRYINCLUDE_CRYSYSTEM_LOADINGPROFILER_H diff --git a/Code/CryEngine/CrySystem/NotificationNetwork.cpp b/Code/CryEngine/CrySystem/NotificationNetwork.cpp index e50c7284c9..f06f0634c0 100644 --- a/Code/CryEngine/CrySystem/NotificationNetwork.cpp +++ b/Code/CryEngine/CrySystem/NotificationNetwork.cpp @@ -16,6 +16,7 @@ #include #include +#include #undef LockDebug //#define LockDebug(str1,str2) {string strMessage;strMessage.Format(str1,str2);if (m_clients.size()) OutputDebugString(strMessage.c_str());} @@ -46,16 +47,13 @@ public: const char* path = nullptr; // Don't call GetGameFolder here, it returns a full absolute path and we just really want the game name - if (ICVar* pVar = gEnv->pConsole->GetCVar("sys_game_folder")) - { - path = pVar->GetString(); - } - if (!path) + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + if (projectPath.empty()) { return; } - pNotificationNetwork->Send("SystemInfo", path, ::strlen(path) + 1); + pNotificationNetwork->Send("SystemInfo", projectPath.c_str(), projectPath.size()); } } g_queryNotification; diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp index 057549e071..3163847b13 100644 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp +++ b/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp @@ -1243,7 +1243,7 @@ namespace { char path[AZ::IO::IArchive::MaxPath]; path[sizeof(path) - 1] = 0; - gEnv->pCryPak->AdjustFileName("@cache@\\TestResults\\StreamingLog.txt", path, AZ_ARRAY_SIZE(path), AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FLAGS_FOR_WRITING); + gEnv->pCryPak->AdjustFileName("@usercache@\\TestResults\\StreamingLog.txt", path, AZ_ARRAY_SIZE(path), AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FLAGS_FOR_WRITING); sFileName = path; } AZ::IO::HandleType fileHandle = fxopen(sFileName, (bFirstTime) ? "wt" : "at"); diff --git a/Code/CryEngine/CrySystem/System.cpp b/Code/CryEngine/CrySystem/System.cpp index 3739c1be11..285f5c2573 100644 --- a/Code/CryEngine/CrySystem/System.cpp +++ b/Code/CryEngine/CrySystem/System.cpp @@ -157,7 +157,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include "ServerThrottle.h" #include "ILocalMemoryUsage.h" #include "ResourceManager.h" -#include "LoadingProfiler.h" #include "HMDBus.h" #include "OverloadSceneManager/OverloadSceneManager.h" #include @@ -168,7 +167,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include "IZStdDecompressor.h" #include "zlib.h" #include "RemoteConsole/RemoteConsole.h" -#include "BootProfiler.h" #include #include @@ -320,10 +318,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_bIsAsserting = false; m_pSystemEventDispatcher = new CSystemEventDispatcher(); // Must be first. -#if defined(ENABLE_LOADING_PROFILER) - CBootProfiler::GetInstance().Init(this); -#endif - if (m_pSystemEventDispatcher) { m_pSystemEventDispatcher->RegisterListener(this); @@ -422,7 +416,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) // m_sys_filecache = NULL; m_gpu_particle_physics = NULL; m_pCpu = NULL; - m_sys_game_folder = NULL; m_bInitializedSuccessfully = false; m_bShaderCacheGenMode = false; @@ -634,10 +627,6 @@ void CSystem::ShutDown() EBUS_EVENT(CrySystemEventBus, OnCrySystemShutdown, *this); } -#if defined(ENABLE_LOADING_PROFILER) - CLoadingProfilerSystem::ShutDown(); -#endif - if (m_pUserCallback) { m_pUserCallback->OnShutdown(); @@ -657,7 +646,7 @@ void CSystem::ShutDown() SAFE_DELETE(m_pTextModeConsole); KillPhysicsThread(); - + if (m_sys_firstlaunch) { m_sys_firstlaunch->Set("0"); @@ -828,7 +817,7 @@ void CSystem::ShutDown() void CSystem::Quit() { CryLogAlways("CSystem::Quit invoked from thread %" PRI_THREADID " (main is %" PRI_THREADID ")", GetCurrentThreadId(), gEnv->mMainThreadId); - + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop); // If this was set from anywhere but the main thread, bail and let the main thread handle shutdown @@ -857,13 +846,13 @@ void CSystem::Quit() /* * TODO: This call to _exit, _Exit, TerminateProcess etc. needs to - * eventually be removed. This causes an extremely early exit before we - * actually perform cleanup. When this gets called most managers are + * eventually be removed. This causes an extremely early exit before we + * actually perform cleanup. When this gets called most managers are * simply never deleted and we leave it to the OS to clean up our mess * which is just really bad practice. However there are LOTS of issues - * with shutdown at the moment. Removing this will simply cause - * a crash when either the Editor or Launcher initiate shutdown. Both - * applications crash differently too. Bugs will be logged about those + * with shutdown at the moment. Removing this will simply cause + * a crash when either the Editor or Launcher initiate shutdown. Both + * applications crash differently too. Bugs will be logged about those * issues. */ #if defined(AZ_RESTRICTED_PLATFORM) @@ -1117,7 +1106,7 @@ void CSystem::CreatePhysicsThread() #include AZ_RESTRICTED_FILE(System_cpp) #endif - { + { m_PhysThread = new CPhysicsThreadTask; GetIThreadTaskManager()->RegisterTask(m_PhysThread, threadParams); } @@ -1412,7 +1401,7 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) ti.xscale = ti.yscale = 1.2f; const int viewportHeight = GetViewCamera().GetViewSurfaceZ(); - + #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_8 #include AZ_RESTRICTED_FILE(System_cpp) @@ -1428,7 +1417,7 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) switch (stat.GetType()) { case AZ::IO::Statistic::Type::FloatingPoint: - gEnv->pRenderer->DrawTextQueued(Vec3(10, y, 1.0f), ti, + gEnv->pRenderer->DrawTextQueued(Vec3(10, y, 1.0f), ti, AZStd::string::format("%s/%s: %.3f", stat.GetOwner().data(), stat.GetName().data(), stat.GetFloatValue()).c_str()); break; case AZ::IO::Statistic::Type::Integer: @@ -2744,10 +2733,10 @@ bool CSystem::HandleMessage([[maybe_unused]] HWND hWnd, UINT uMsg, WPARAM wParam { // System event translation case WM_CLOSE: - /* + /* Trigger CSystem to call Quit() the next time it calls Update(). HandleMessages can get messages - pumped to it from SyncMainWithRender which would + pumped to it from SyncMainWithRender which would be called recurively by Quit(). Doing so would cause the render thread to deadlock and the main thread to spin in SRenderThread::WaitFlushFinishedCond. @@ -2897,11 +2886,6 @@ std::shared_ptr CSystem::CreateLocalFileIO() return std::make_shared(); } -const char* CSystem::GetAssetsPlatform() const -{ - return m_assetPlatform.c_str(); -} - IViewSystem* CSystem::GetIViewSystem() { return m_pViewSystem; diff --git a/Code/CryEngine/CrySystem/System.h b/Code/CryEngine/CrySystem/System.h index 47ea7133d5..1244283f7d 100644 --- a/Code/CryEngine/CrySystem/System.h +++ b/Code/CryEngine/CrySystem/System.h @@ -45,7 +45,6 @@ struct IConsoleCmdArgs; class CServerThrottle; struct ICryFactoryRegistryImpl; struct IZLibCompressor; -class CLoadingProfilerSystem; class CWatchdogThread; class CThreadManager; @@ -437,11 +436,6 @@ public: uint32 GetUsedMemory(); - //! For asset processor, we need to know what kind of assets we're loading. This comes all the way from bootstrap.cfg - //! It will be a string like "pc" or "es3" or such and controls what kind of assets we have access to (its used when for example - //! attempting to open a file when multiple different assets for different platforms are available.) - const char* GetAssetsPlatform() const; - virtual void DumpMemoryUsageStatistics(bool bUseKB); virtual void DumpMemoryCoverage(); void CollectMemInfo(SCryEngineStatsGlobalMemInfo&); @@ -685,7 +679,7 @@ private: bool InitRenderer(WIN_HINSTANCE hinst, WIN_HWND hwnd, const SSystemInitParams& initParams); bool InitFont(const SSystemInitParams& initParams); - bool InitFileSystem(const SSystemInitParams& initParams); + bool InitFileSystem(); bool InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams); bool InitStreamEngine(); bool Init3DEngine(const SSystemInitParams& initParams); @@ -792,7 +786,7 @@ public: const CTimeValue& GetLastTickTime(void) const { return m_lastTickTime; } const ICVar* GetDedicatedMaxRate(void) const { return m_svDedicatedMaxRate; } - + const char* GetRenderingDriverName(void) const { if(m_rDriver) @@ -802,7 +796,7 @@ public: return nullptr; } - + std::shared_ptr CreateLocalFileIO(); // Gets the dimensions (in pixels) of the primary physical display. @@ -914,7 +908,6 @@ private: // ------------------------------------------------------ // DLL names ICVar* m_sys_dll_response_system; - ICVar* m_sys_game_folder; #if !defined(_RELEASE) ICVar* m_sys_resource_cache_folder; #endif @@ -950,7 +943,6 @@ private: // ------------------------------------------------------ ICVar* m_rFullscreenWindow; ICVar* m_rFullscreenNativeRes; ICVar* m_rDriver; - ICVar* m_cvGameName; ICVar* m_rDisplayInfo; ICVar* m_rOverscanBordersDrawDebugView; ICVar* m_sysNoUpdate; @@ -1040,8 +1032,6 @@ private: // ------------------------------------------------------ uint64 m_nUpdateCounter; - int sys_ProfileLevelLoading, sys_ProfileLevelLoadingDump; - bool m_executedCommandLine = false; AZStd::unique_ptr m_missingAssetLogger; @@ -1072,18 +1062,6 @@ public: void CloseLanguageAudioPak(const char* sLanguage); void UpdateMovieSystem(const int updateFlags, const float fFrameTime, const bool bPreUpdate); - // level loading profiling - virtual void OutputLoadingTimeStats(); - virtual struct SLoadingTimeContainer* StartLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler, const char* szFuncName); - virtual void EndLoadingSectionProfiling(CLoadingTimeProfiler* pProfiler); - virtual const char* GetLoadingProfilerCallstack(); - - ////////////////////////////////////////////////////////////////////////// - virtual CBootProfilerRecord* StartBootSectionProfiler(const char* name, const char* args); - virtual void StopBootSectionProfiler(CBootProfilerRecord* record); - virtual void StartBootProfilerSessionFrames(const char* pName); - virtual void StopBootProfilerSessionFrames(); - ////////////////////////////////////////////////////////////////////////// // CryAssert and error related. virtual bool RegisterErrorObserver(IErrorObserver* errorObserver); @@ -1139,17 +1117,9 @@ protected: // ------------------------------------------------------------- ITextModeConsole* m_pTextModeConsole; INotificationNetwork* m_pNotificationNetwork; - string m_binariesDir; string m_currentLanguageAudio; - string m_assetPlatform; // ("es3" / "pc" / etc) describes the KIND of assets we load and controls where they're loaded from string m_systemConfigName; // computed from system_(hardwareplatform)_(assetsPlatform) - eg, system_android_es3.cfg or system_android_opengl.cfg or system_windows_pc.cfg - // the following variables capture what was set up in the systeminitparams after/during InitFileSystem - // They are not actually to be used except to establish aliases like @user@ - string m_userRootDir; - string m_cacheDir; - string m_logsDir; - std::vector< std::pair > m_updateTimes; CMemoryFragmentationProfiler m_MemoryFragmentationProfiler; diff --git a/Code/CryEngine/CrySystem/SystemCFG.cpp b/Code/CryEngine/CrySystem/SystemCFG.cpp index 16880a2f39..573056370f 100644 --- a/Code/CryEngine/CrySystem/SystemCFG.cpp +++ b/Code/CryEngine/CrySystem/SystemCFG.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include "SystemCFG.h" @@ -252,15 +253,8 @@ void CSystem::LogVersion() ////////////////////////////////////////////////////////////////////////// void CSystem::LogBuildInfo() { - ICVar* pGameName = m_env.pConsole->GetCVar("sys_game_name"); - if (pGameName) - { - CryLogAlways("GameName: %s", pGameName->GetString()); - } - else - { - CryLogAlways("Couldn't find game name in cvar sys_game_name"); - } + auto projectName = AZ::Utils::GetProjectName(); + CryLogAlways("GameName: %s", projectName.c_str()); CryLogAlways("BuildTime: " __DATE__ " " __TIME__); } diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 3dad415d99..5fcf63a2ef 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -115,8 +116,6 @@ #include "SystemCFG.h" #include "AutoDetectSpec.h" #include "ResourceManager.h" -#include "LoadingProfiler.h" -#include "BootProfiler.h" #include "VisRegTest.h" #include "MTSafeAllocator.h" #include "NotificationNetwork.h" @@ -498,7 +497,7 @@ struct SysSpecOverrideSinkConsole else { // If the cvar doesn't exist, calling this function only saves the value in case it's registered later where - // at that point it will be set from the stored value. This is required because otherwise registering the + // at that point it will be set from the stored value. This is required because otherwise registering the // cvar bypasses any callbacks and uses values directly from the cvar group files. gEnv->pConsole->LoadConfigVar(szKey, szValue); } @@ -618,13 +617,13 @@ static void LoadDetectedSpec(ICVar* pVar) if (gEnv->IsEditor()) { ESystemConfigPlatform configPlatform = GetISystem()->GetConfigPlatform(); - // Check if the config platform is set first. + // Check if the config platform is set first. if (configPlatform != CONFIG_INVALID_PLATFORM) { platform = configPlatform; } } - + AZStd::string configFile; GetSpecConfigFileToLoad(pVar, configFile, platform); if (configFile.length()) @@ -779,7 +778,7 @@ static void LoadDetectedSpec(ICVar* pVar) MobileSysInspect::GetSpecForGPUAndAPI(adapterDesc, apiver, gpuConfigFile); GetISystem()->LoadConfiguration(gpuConfigFile.c_str(), pSysSpecOverrideSinkConsole); } -#endif +#endif } if (bMultiGPUEnabled) { @@ -832,23 +831,7 @@ AZStd::unique_ptr CSystem::LoadDynamiclibrary(const cha { AZStd::unique_ptr handle = AZ::DynamicModuleHandle::Create(dllName); - bool libraryLoaded = false; -#ifdef WIN32 - if (m_binariesDir.empty()) - { - libraryLoaded = handle->Load(false); - } - else - { - char currentDirectory[1024]; - AZ::Utils::GetExecutableDirectory(currentDirectory, AZ_ARRAY_SIZE(currentDirectory)); - SetCurrentDirectory(m_binariesDir.c_str()); - libraryLoaded = handle->Load(false); - SetCurrentDirectory(currentDirectory); - } -#else - libraryLoaded = handle->Load(false); -#endif + bool libraryLoaded = handle->Load(false); // We need to inject the environment first thing so that allocators are available immediately InjectEnvironmentFunction injectEnv = handle->GetFunction(INJECT_ENVIRONMENT_FUNCTION); if (injectEnv) @@ -974,7 +957,7 @@ bool CSystem::InitializeEngineModule(const char* dllName, const char* moduleClas #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else +#else dllfile.append(dllName); @@ -1007,7 +990,7 @@ bool CSystem::InitializeEngineModule(const char* dllName, const char* moduleClas if (CryCreateClassInstance(moduleClassName, pModule)) { bResult = pModule->Initialize(m_env, initParams); - + // After initializing the module, give it a chance to register any AZ console vars // declared within the module. pModule->RegisterConsoleVars(); @@ -1453,7 +1436,7 @@ bool CSystem::InitRenderer(WIN_HINSTANCE hinst, WIN_HWND hwnd, const SSystemInit displayWidth *= scaleFactor; displayHeight *= scaleFactor; - + const int maxWidth = m_rMaxWidth->GetIVal(); if (maxWidth > 0 && maxWidth < displayWidth) { @@ -1524,7 +1507,7 @@ bool CSystem::InitRenderer(WIN_HINSTANCE hinst, WIN_HWND hwnd, const SSystemInit ///////////////////////////////////////////////////////////////////////////////// -bool CSystem::InitFileSystem(const SSystemInitParams& initParams) +bool CSystem::InitFileSystem() { LOADING_TIME_PROFILE_SECTION; using namespace AzFramework::AssetSystem; @@ -1549,136 +1532,6 @@ bool CSystem::InitFileSystem(const SSystemInitParams& initParams) } #endif // !defined(_RELEASE) - bool usingAssetCache = initParams.UseAssetCache(); - const char* rootPath = usingAssetCache ? initParams.rootPathCache : initParams.rootPath; - const char* assetsPath = usingAssetCache ? initParams.assetsPathCache : initParams.assetsPath; - - if (rootPath == 0) - { - AZ_Assert(false, "No root path specified in SystemInitParams"); - return false; - } - - if (assetsPath == 0) - { - AZ_Assert(false, "No assets path specified in SystemInitParams"); - return false; - } - - // establish the root folder and assets folder immediately. - // Other folders that can be computed from the root can be specified later. - m_env.pFileIO->SetAlias("@root@", rootPath); - m_env.pFileIO->SetAlias("@assets@", assetsPath); - - if (initParams.userPath[0] == 0) - { - string outPath = PathUtil::Make(m_env.pFileIO->GetAlias("@root@"), "user"); - - m_env.pFileIO->SetAlias("@user@", outPath.c_str()); - } - else - { - m_env.pFileIO->SetAlias("@user@", initParams.userPath); - } - - if (initParams.logPath[0] == 0) - { - char resolveBuffer[AZ_MAX_PATH_LEN] = { 0 }; - - m_env.pFileIO->ResolvePath("@user@", resolveBuffer, AZ_MAX_PATH_LEN); - string outPath = PathUtil::Make(resolveBuffer, "log"); - m_env.pFileIO->SetAlias("@log@", outPath.c_str()); - } - else - { - m_env.pFileIO->SetAlias("@log@", initParams.logPath); - } - - m_env.pFileIO->CreatePath("@root@"); - m_env.pFileIO->CreatePath("@user@"); - m_env.pFileIO->CreatePath("@log@"); - - if ((!m_env.IsInToolMode()) || (m_bShaderCacheGenMode)) // in tool mode, the promise is that you won't access @cache@! - { - string finalCachePath; - if (initParams.cachePath[0] == 0) - { - char resolveBuffer[AZ_MAX_PATH_LEN] = { 0 }; - - m_env.pFileIO->ResolvePath("@user@", resolveBuffer, AZ_MAX_PATH_LEN); - finalCachePath = PathUtil::Make(resolveBuffer, "cache"); - } - else - { - finalCachePath = initParams.cachePath; - } - -#if defined(AZ_PLATFORM_WINDOWS) - // Search for a non-locked cache directory because shaders require separate caches for each running instance. - // We only need to do this check for Windows, because consoles can't have multiple instances running simultaneously. - // Ex: running editor and game, running multiple games, or multiple non-interactive editor instances - // for parallel level exports. - - string originalPath = finalCachePath; -#if defined(REMOTE_ASSET_PROCESSOR) - bool allowEngineConnection = !initParams.bToolMode && !initParams.bTestMode; - bool allowRemoteIO = allowEngineConnection && initParams.remoteFileIO && !initParams.bEditor; - - if (!allowRemoteIO) // not running on VFS -#endif - { - int attemptNumber = 0; - - // The number of max attempts ultimately dictates the number of Lumberyard instances that can run - // simultaneously. This should be a reasonably high number so that it doesn't artificially limit - // the number of instances (ex: parallel level exports via multiple Editor runs). It also shouldn't - // be set *infinitely* high - each cache folder is GBs in size, and finding a free directory is a - // linear search, so the more instances we allow, the longer the search will take. - // 128 seems like a reasonable compromise. - constexpr int maxAttempts = 128; - - char workBuffer[AZ_MAX_PATH_LEN] = { 0 }; - while (attemptNumber < maxAttempts) - { - finalCachePath = originalPath; - if (attemptNumber != 0) - { - azsnprintf(workBuffer, AZ_MAX_PATH_LEN, "%s%i", originalPath.c_str(), attemptNumber); - finalCachePath = workBuffer; - } - else - { - finalCachePath = originalPath; - } - - ++attemptNumber; // do this here so we don't forget - - m_env.pFileIO->CreatePath(finalCachePath.c_str()); - // if the directory already exists, check for locked file - string outLockPath = PathUtil::Make(finalCachePath.c_str(), "lockfile.txt"); - - // note, the zero here after GENERIC_READ|GENERIC_WRITE indicates no share access at all - g_cacheLock = CreateFileA(outLockPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); - if (g_cacheLock != INVALID_HANDLE_VALUE) - { - break; - } - } - - if (attemptNumber >= maxAttempts) - { - AZ_Assert(false, "Couldn't find a valid asset cache folder for the Asset Processor after %i attempts.", attemptNumber); - AZ_Printf("FileSystem", "Couldn't find a valid asset cache folder for the Asset Processor after %i attempts.", attemptNumber); - return false; - } - } - -#endif // defined(AZ_PLATFORM_WINDOWS) - AZ_Printf("FileSystem", "Using %s folder for asset cache.\n", finalCachePath.c_str()); - m_env.pFileIO->SetAlias("@cache@", finalCachePath.c_str()); - m_env.pFileIO->CreatePath("@cache@"); - } - m_env.pCryPak = AZ::Interface::Get(); m_env.pFileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(m_env.pCryPak, "CryPak has not been initialized on AZ::Interface"); @@ -1755,7 +1608,6 @@ void CSystem::ShutdownFileSystem() bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION; - // Load value of sys_game_folder from system.cfg into the sys_game_folder console variable { ILoadConfigurationEntrySink* pCVarsWhiteListConfigSink = GetCVarsWhiteListConfigSink(); LoadConfiguration(m_systemConfigName.c_str(), pCVarsWhiteListConfigSink); @@ -1767,17 +1619,19 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams& initPara #endif GetISystem()->SetConfigPlatform(GetDevicePlatform()); - + #if defined(CRY_ENABLE_RC_HELPER) if (!m_env.pResourceCompilerHelper) { m_env.pResourceCompilerHelper = new CResourceCompilerHelper(); } #endif - // you may not set these in game.cfg or in system.cfg - m_sys_game_folder->ForceSet(initParams.gameFolderName); - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "GameDir: %s\n", m_sys_game_folder->GetString()); + auto projectPath = AZ::Utils::GetProjectPath(); + AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Path: %s\n", projectPath.empty() ? "None specified" : projectPath.c_str()); + + auto projectName = AZ::Utils::GetProjectName(); + AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str()); // simply open all paks if fast load pak can't be found if (!m_pResourceManager->LoadFastLoadPaks(true)) @@ -1857,7 +1711,7 @@ bool CSystem::InitFont(const SSystemInitParams& initParams) bool CSystem::Init3DEngine(const SSystemInitParams& initParams) { LOADING_TIME_PROFILE_SECTION(GetISystem()); - + if (!InitializeEngineModule(DLL_3DENGINE, "EngineModule_Cry3DEngine", initParams)) { return false; @@ -1930,7 +1784,7 @@ bool CSystem::InitVTuneProfiler() LOADING_TIME_PROFILE_SECTION(GetISystem()); #ifdef PROFILE_WITH_VTUNE - + WIN_HMODULE hModule = LoadDLL("VTuneApi.dll"); if (!hModule) { @@ -2033,7 +1887,7 @@ void CSystem::OpenBasicPaks() bBasicPaksLoaded = true; LOADING_TIME_PROFILE_SECTION; - + // open pak files constexpr AZStd::string_view paksFolder = "@assets@/*.pak"; // (@assets@ assumed) m_env.pCryPak->OpenPacks(paksFolder); @@ -2188,12 +2042,6 @@ string GetUniqueLogFileName(string logFileName) } - -void OnLevelLoadingDump([[maybe_unused]] ICVar* pArgs) -{ - gEnv->pSystem->OutputLoadingTimeStats(); -} - #if defined(WIN32) || defined(WIN64) static wstring GetErrorStringUnsupportedCPU() { @@ -2415,8 +2263,8 @@ bool CSystem::Init(const SSystemInitParams& startupParams) signal(SIGILL, CryEngineSignalHandler); #endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - // Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the - // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is + // Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the + // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is // initialized to this instance's SSystemGlobalEnvironment (m_env), we will force set it again here // to m_env if (!gEnv) @@ -2451,7 +2299,7 @@ bool CSystem::Init(const SSystemInitParams& startupParams) // Linux is all console for now and so no room for dialog boxes! m_env.bNoAssertDialog = true; #endif - + m_pCmdLine = new CCmdLine(startupParams.szSystemCmdLine); AZCoreLogSink::Connect(); @@ -2461,25 +2309,25 @@ bool CSystem::Init(const SSystemInitParams& startupParams) { azConsole->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead()); } - - m_assetPlatform = startupParams.assetsPlatform; - - // compute system config name - if (m_assetPlatform.empty()) + + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry) { - AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n" - R"(This can be set via the via the --regset "%s/assets=" command line option)" - R"(, by setting value at the "%s/assets path" within a *.setreg file that is loaded by the application)" - R"( or by setting the "assets" field in the bootstrap.cfg.)", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - return false; - } + AZ::SettingsRegistryInterface::FixedValueString assetPlatform; + if (!AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, assetPlatform, + AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "assets")) + { + assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); + AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n" + R"(This typically done by setting he "assets" field in the bootstrap.cfg for within a .setreg file)""\n" + R"(A fallback of %s will be used.)", + AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, + assetPlatform.c_str()); + } - m_systemConfigName = "system_" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_"; - m_systemConfigName += m_assetPlatform; - m_systemConfigName += ".cfg"; + m_systemConfigName = "system_" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_"; + m_systemConfigName += assetPlatform.c_str(); + m_systemConfigName += ".cfg"; + } AZ_Assert(CryMemory::IsHeapValid(), "Memory heap must be valid before continuing SystemInit."); @@ -2518,11 +2366,6 @@ AZ_POP_DISABLE_WARNING m_hInst = (WIN_HINSTANCE)startupParams.hInstance; m_hWnd = (WIN_HWND)startupParams.hWnd; - m_userRootDir = startupParams.userPath; - m_logsDir = startupParams.logPath; - m_cacheDir = startupParams.cachePath; - - m_binariesDir = startupParams.szBinariesDir; m_bEditor = startupParams.bEditor; m_bPreviewMode = startupParams.bPreview; m_bTestMode = startupParams.bTestMode; @@ -2666,17 +2509,13 @@ AZ_POP_DISABLE_WARNING ////////////////////////////////////////////////////////////////////////// // File system, must be very early ////////////////////////////////////////////////////////////////////////// - if (!InitFileSystem(startupParams)) + if (!InitFileSystem()) { return false; } ////////////////////////////////////////////////////////////////////////// InlineInitializationProcessing("CSystem::Init InitFileSystem"); -#if defined(ENABLE_LOADING_PROFILER) - CLoadingProfilerSystem::Init(); -#endif - m_missingAssetLogger = AZStd::make_unique(); ////////////////////////////////////////////////////////////////////////// @@ -2786,10 +2625,6 @@ AZ_POP_DISABLE_WARNING GetIRemoteConsole()->RegisterConsoleVariables(); -#ifdef ENABLE_LOADING_PROFILER - CBootProfiler::GetInstance().RegisterCVars(); -#endif - if (!startupParams.bSkipConsole) { // Register system console variables. @@ -2827,7 +2662,7 @@ AZ_POP_DISABLE_WARNING m_env.pCryPak->OpenPack("@assets@", "Engine.pak"); #if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) MobileSysInspect::LoadDeviceSpecMapping(); -#endif +#endif InitFileSystem_LoadEngineFolders(startupParams); @@ -3472,10 +3307,6 @@ AZ_POP_DISABLE_WARNING MarkThisThreadForDebugging("Main"); } -#if defined(ENABLE_LOADING_PROFILER) - CLoadingProfilerSystem::SaveTimeContainersToFile("EngineStart.crylp", 0.0, true); -#endif - InlineInitializationProcessing("CSystem::Init End"); #if defined(IS_PROSDK) @@ -4188,7 +4019,7 @@ static void ScreenshotCmd(IConsoleCmdArgs* pParams) } } -// Helper to maintain backwards compatibility with our CVar but not force our new code to +// Helper to maintain backwards compatibility with our CVar but not force our new code to // pull in CryCommon by routing through an environment variable void CmdSetAwsLogLevel(IConsoleCmdArgs* pArgs) { @@ -4424,7 +4255,6 @@ void CSystem::CreateSystemVars() // Register DLL names as cvars before we load them // EVarFlags dllFlags = (EVarFlags)0; - m_sys_game_folder = REGISTER_STRING("sys_game_folder", "EmptyTemplate", VF_READONLY, "Specifies the game folder to read all data from. Can be fully pathed for external folders or relative path for folders inside the root."); m_sys_dll_response_system = REGISTER_STRING("sys_dll_response_system", 0, dllFlags, "Specifies the DLL to load for the dynamic response system"); m_sys_initpreloadpacks = REGISTER_STRING("sys_initpreloadpacks", "", 0, "Specifies the paks for an engine initialization"); @@ -4447,8 +4277,6 @@ void CSystem::CreateSystemVars() m_level_load_screen_minimum_time = REGISTER_FLOAT("level_load_screen_minimum_time", 0.0f, 0, "Minimum amount of time to show the level load screen. Important to prevent short loads from flashing the load screen. 0 means there is no limit."); #endif // if AZ_LOADSCREENCOMPONENT_ENABLED - m_cvGameName = REGISTER_STRING("sys_game_name", "Lumberyard", VF_DUMPTODISK, "Specifies the name to be displayed in the Launcher window title bar"); - REGISTER_INT("cvDoVerboseWindowTitle", 0, VF_NULL, ""); m_pCVarQuit = REGISTER_INT("ExitOnQuit", 1, VF_NULL, ""); @@ -4495,7 +4323,7 @@ void CSystem::CreateSystemVars() } #endif - + attachVariable("sys_PakReadSlice", &g_cvars.archiveVars.nReadSlice, "If non-0, means number of kilobytes to use to read files in portions. Should only be used on Win9x kernels"); attachVariable("sys_PakInMemorySizeLimit", &g_cvars.archiveVars.nInMemoryPerPakSizeLimit, "Individual pak size limit for being loaded into memory (MB)"); @@ -4818,15 +4646,6 @@ void CSystem::CreateSystemVars() "e.g. LoadConfig lowspec.cfg\n" "Usage: LoadConfig "); - REGISTER_CVAR(sys_ProfileLevelLoading, 0, VF_CHEAT, - "Output level loading stats into log\n" - "0 = Off\n" - "1 = Output basic info about loading time per function\n" - "2 = Output full statistics including loading time and memory allocations with call stack info"); - - REGISTER_CVAR_CB(sys_ProfileLevelLoadingDump, 0, VF_CHEAT, "Output level loading dump stats into log\n", OnLevelLoadingDump); - - assert(m_env.pConsole); m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F12", "Screenshot"); m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F11", "RecordClip"); @@ -4871,7 +4690,7 @@ void CSystem::CreateSystemVars() // adding CVAR to toggle assert verbosity level const int defaultAssertValue = 1; - REGISTER_CVAR2_CB("sys_asserts", &g_cvars.sys_asserts, defaultAssertValue, VF_CHEAT, + REGISTER_CVAR2_CB("sys_asserts", &g_cvars.sys_asserts, defaultAssertValue, VF_CHEAT, "0 = Suppress Asserts\n" "1 = Log Asserts\n" "2 = Show Assert Dialog\n" @@ -4957,78 +4776,6 @@ void CSystem::AddCVarGroupDirectory(const string& sPath) gEnv->pCryPak->FindClose(handle); } -void CSystem::OutputLoadingTimeStats() -{ -#if defined(ENABLE_LOADING_PROFILER) - if (GetIConsole()) - { - if (ICVar* pVar = GetIConsole()->GetCVar("sys_ProfileLevelLoading")) - { - CLoadingProfilerSystem::OutputLoadingTimeStats(GetILog(), pVar->GetIVal()); - } - } -#endif -} - -SLoadingTimeContainer* CSystem::StartLoadingSectionProfiling([[maybe_unused]] CLoadingTimeProfiler* pProfiler, [[maybe_unused]] const char* szFuncName) -{ -#if defined(ENABLE_LOADING_PROFILER) - return CLoadingProfilerSystem::StartLoadingSectionProfiling(pProfiler, szFuncName); -#else - return 0; -#endif -} - -void CSystem::EndLoadingSectionProfiling([[maybe_unused]] CLoadingTimeProfiler* pProfiler) -{ -#if defined(ENABLE_LOADING_PROFILER) - CLoadingProfilerSystem::EndLoadingSectionProfiling(pProfiler); -#endif -} - -const char* CSystem::GetLoadingProfilerCallstack() -{ -#if defined(ENABLE_LOADING_PROFILER) - return CLoadingProfilerSystem::GetLoadingProfilerCallstack(); -#else - return nullptr; -#endif -} - -CBootProfilerRecord* CSystem::StartBootSectionProfiler([[maybe_unused]] const char* name, [[maybe_unused]] const char* args) -{ -#if defined(ENABLE_LOADING_PROFILER) - CBootProfiler& profiler = CBootProfiler::GetInstance(); - return profiler.StartBlock(name, args); -#else - return nullptr; -#endif -} - -void CSystem::StopBootSectionProfiler([[maybe_unused]] CBootProfilerRecord* record) -{ -#if defined(ENABLE_LOADING_PROFILER) - CBootProfiler& profiler = CBootProfiler::GetInstance(); - profiler.StopBlock(record); -#endif -} - -void CSystem::StartBootProfilerSessionFrames([[maybe_unused]] const char* pName) -{ -#if defined(ENABLE_LOADING_PROFILER) - CBootProfiler& profiler = CBootProfiler::GetInstance(); - profiler.StartFrame(pName); -#endif -} - -void CSystem::StopBootProfilerSessionFrames() -{ -#if defined(ENABLE_LOADING_PROFILER) - CBootProfiler& profiler = CBootProfiler::GetInstance(); - profiler.StopFrame(); -#endif -} - bool CSystem::RegisterErrorObserver(IErrorObserver* errorObserver) { return stl::push_back_unique(m_errorObservers, errorObserver); diff --git a/Code/CryEngine/CrySystem/SystemWin32.cpp b/Code/CryEngine/CrySystem/SystemWin32.cpp index c6b252124c..8198949359 100644 --- a/Code/CryEngine/CrySystem/SystemWin32.cpp +++ b/Code/CryEngine/CrySystem/SystemWin32.cpp @@ -92,13 +92,6 @@ static AZStd::vector GetModuleNames() moduleNames.push_back("CryFont" MODULE_EXTENSION); moduleNames.push_back("CrySystem" MODULE_EXTENSION); - if (gEnv && gEnv->pConsole) - { - string gameModuleNameRaw = gEnv->pConsole->GetCVar("sys_dll_game")->GetString(); - gameModuleNameRaw.append(MODULE_EXTENSION); - moduleNames.push_back(gameModuleNameRaw.c_str()); - } - #undef MODULE_EXTENSION # if defined(LINUX) @@ -1076,14 +1069,6 @@ void CSystem::FatalError(const char* format, ...) CryLogAlways(" Last System Error: %s", szSysErrorMessage); } - if (const char* pLoadingProfilerCallstack = GetLoadingProfilerCallstack()) - { - if (pLoadingProfilerCallstack[0]) - { - CryLogAlways(" LoadingProfilerCallstack: %s", pLoadingProfilerCallstack); - } - } - if (GetUserCallback()) { GetUserCallback()->OnError(szBuffer); diff --git a/Code/CryEngine/CrySystem/Tests/Test_BootProfiler.cpp b/Code/CryEngine/CrySystem/Tests/Test_BootProfiler.cpp deleted file mode 100644 index e7e25d51e9..0000000000 --- a/Code/CryEngine/CrySystem/Tests/Test_BootProfiler.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -* 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. -* -*/ -#include "CrySystem_precompiled.h" - -#include -#include -#include -#include -#include -#include - -#if defined(ENABLE_LOADING_PROFILER) - -namespace UnitTests -{ - using BootProfilerTestAllocatorScope = AZ::AllocatorScope; - class BootProfilerTest : - public ::testing::Test, - BootProfilerTestAllocatorScope, - UnitTest::TraceBusRedirector - { - public: - BootProfilerTest() - { - BootProfilerTestAllocatorScope::ActivateAllocators(); - UnitTest::TraceBusRedirector::BusConnect(); - } - - ~BootProfilerTest() - { - UnitTest::TraceBusRedirector::BusDisconnect(); - BootProfilerTestAllocatorScope::DeactivateAllocators(); - } - - void SetUp() override - { - - } - - void TearDown() override - { - - } - - }; - - TEST_F(BootProfilerTest, BootProfilerTest_StartStopBlocksInThreads_Success) - { - CBootProfiler testProfiler; - const char scopeName[] = "TestScope"; - const char blockArg[] = "TestArg"; - const int numAttempts = 1000; - const int numThreads = 10; - - auto switchSessionFunc = [&]() { - for (int sessionNum = 0; sessionNum < numAttempts; ++sessionNum) - { - auto sessionName = AZStd::string::format("TestSession%d", sessionNum); - testProfiler.StartSession(sessionName.c_str()); - testProfiler.StopSession(sessionName.c_str()); - } - }; - auto testProfileFunc = [&]() { - for (int blockNum = 0; blockNum < numAttempts; ++blockNum) - { - auto someBlock = testProfiler.StartBlock(scopeName, blockArg); - testProfiler.StopBlock(someBlock); - } - }; - AZStd::thread threadArray[numThreads]; - - AZStd::thread sessionThread = AZStd::thread(switchSessionFunc); - for (int i = 0; i < numThreads; ++i) - { - threadArray[i] = AZStd::thread(testProfileFunc); - } - for (int i = 0; i < numThreads; ++i) - { - threadArray[i].join(); - } - sessionThread.join(); - } - - class FrameTestBootProfiler : public CBootProfiler - { - public: - FrameTestBootProfiler(int frameCount) : CBootProfiler() - { - SetFrameCount(frameCount); - } - }; - TEST_F(BootProfilerTest, BootProfilerTest_FrameStartStop_Success) - { - const int numTestFrames = 10; - FrameTestBootProfiler testProfiler(numTestFrames); - - for (int i = 0; i < numTestFrames; ++i) - { - testProfiler.StartFrame("TestFrame"); - - testProfiler.StopFrame(); - } - } -} // namespace UnitTests - -#endif diff --git a/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp b/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp index 782587b7b0..99077e41e8 100644 --- a/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp +++ b/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp @@ -75,15 +75,10 @@ TEST(CrySystemMaterialUtilsTests, MaterialUtilsTestPrefixes) TEST(CrySystemMaterialUtilsTests, MaterialUtilsTestGameName) { char tempBuffer[AZ_MAX_PATH_LEN]; - - ICVar* pGameNameCVar = nullptr; - if ((gEnv)&&(gEnv->pConsole)) - { - pGameNameCVar = gEnv->pConsole->GetCVar("sys_game_folder"); - } - - azsnprintf(tempBuffer, AZ_MAX_PATH_LEN, ".\\%s\\materials\\blahblah.mat.mat.abc.test", pGameNameCVar ? pGameNameCVar->GetString() : "SamplesProject"); - + + auto projectName = AZ::Utils::GetProjectName(); + azsnprintf(tempBuffer, AZ_MAX_PATH_LEN, ".\\%s\\materials\\blahblah.mat.mat.abc.test", projectName.c_str()); + MaterialUtils::UnifyMaterialName(tempBuffer); EXPECT_TRUE(strcmp(tempBuffer, "materials/blahblah.mat.mat.abc") == 0); -} \ No newline at end of file +} diff --git a/Code/CryEngine/CrySystem/UnitTests/CryPakUnitTests.cpp b/Code/CryEngine/CrySystem/UnitTests/CryPakUnitTests.cpp index fd198371fe..7931acae76 100644 --- a/Code/CryEngine/CrySystem/UnitTests/CryPakUnitTests.cpp +++ b/Code/CryEngine/CrySystem/UnitTests/CryPakUnitTests.cpp @@ -60,7 +60,7 @@ namespace CryPakUnitTests AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); ASSERT_NE(nullptr, fileIo); - constexpr const char* testPakPath = "@cache@/archivecontainerlevel.pak"; + constexpr const char* testPakPath = "@usercache@/archivecontainerlevel.pak"; char resolvedArchivePath[AZ_MAX_PATH_LEN] = { 0 }; EXPECT_TRUE(fileIo->ResolvePath(testPakPath, resolvedArchivePath, AZ_MAX_PATH_LEN)); @@ -116,7 +116,7 @@ namespace CryPakUnitTests AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds{ 100 }); // helper paths and strings - AZStd::string gameFolder = fileIo->GetAlias("@cache@"); + AZStd::string gameFolder = fileIo->GetAlias("@usercache@"); AZStd::string testFile = "unittest.bin"; AZStd::string testFilePath = gameFolder + "\\" + testFile; diff --git a/Code/CryEngine/CrySystem/VisRegTest.cpp b/Code/CryEngine/CrySystem/VisRegTest.cpp index 27745c62e5..81ef205b47 100644 --- a/Code/CryEngine/CrySystem/VisRegTest.cpp +++ b/Code/CryEngine/CrySystem/VisRegTest.cpp @@ -297,7 +297,7 @@ void CVisRegTest::CaptureSample(const SCmd& cmd) if (m_cmdFreq == 1) // Final sample { // Screenshot - stack_string filename("@cache@/TestResults/VisReg/"); // the default unaliased assets folder is read-only! + stack_string filename("@usercache@/TestResults/VisReg/"); // the default unaliased assets folder is read-only! filename += m_testName + "/" + cmd.args.c_str(); gEnv->pRenderer->ScreenShot(filename); @@ -335,7 +335,7 @@ void CVisRegTest::Finish() bool CVisRegTest::WriteResults() { - stack_string filename("@cache@/TestResults/VisReg/"); + stack_string filename("@usercache@/TestResults/VisReg/"); filename += m_testName + "/visreg_results.xml"; AZ::IO::HandleType fileHandle = fxopen(filename.c_str(), "wb"); diff --git a/Code/CryEngine/CrySystem/crysystem_files.cmake b/Code/CryEngine/CrySystem/crysystem_files.cmake index 422fc221b5..c096a710f6 100644 --- a/Code/CryEngine/CrySystem/crysystem_files.cmake +++ b/Code/CryEngine/CrySystem/crysystem_files.cmake @@ -26,7 +26,6 @@ set(FILES IDebugCallStack.cpp AsyncPakManager.cpp Log.cpp - BootProfiler.cpp SystemRender.cpp NotificationNetwork.cpp PhysRenderer.cpp @@ -91,7 +90,6 @@ set(FILES WindowsConsole.h XConsole.h XConsoleVariable.h - BootProfiler.h crash_face.bmp ImageHandler.h ImageHandler.cpp @@ -121,11 +119,9 @@ set(FILES XML/WriteXMLSource.cpp ZipFile.h ZipFileFormat_info.h - LoadingProfiler.cpp PerfHUD.cpp ProfileLogSystem.cpp Sampler.cpp - LoadingProfiler.h PerfHUD.h ProfileLogSystem.h Sampler.h diff --git a/Code/CryEngine/RenderDll/Common/Renderer.cpp b/Code/CryEngine/RenderDll/Common/Renderer.cpp index e8591ebb01..41721ec110 100644 --- a/Code/CryEngine/RenderDll/Common/Renderer.cpp +++ b/Code/CryEngine/RenderDll/Common/Renderer.cpp @@ -902,7 +902,7 @@ void ShadersOptimizeHelper(CallableT setupParserBin, const char* logString) { setupParserBin(); CryLogAlways("\nStarting shaders optimizing for %s...", logString); - AZStd::string str = "@cache@/" + gRenDev->m_cEF.m_ShadersCache; + AZStd::string str = "@usercache@/" + gRenDev->m_cEF.m_ShadersCache; iLog->Log("Optimize shader cache folder: '%s'", gRenDev->m_cEF.m_ShadersCache.c_str()); gRenDev->m_cEF.mfOptimiseShaders(str.c_str(), false); } @@ -2396,7 +2396,7 @@ void CRenderer::InitRenderer() CV_r_ShaderCompilerFolderSuffix = REGISTER_STRING("r_ShaderCompilerFolderSuffix", "", VF_NULL, "Usage: r_ShaderCompilerFolderSuffix suffix \n" - "Default is empty. Set to some other value to append this suffix to the sys_game_folder when compiling shaders"); + "Default is empty. Set to some other value to append this suffix to the project name when compiling shaders"); { const SFileVersion& ver = gEnv->pSystem->GetFileVersion(); diff --git a/Code/CryEngine/RenderDll/Common/Shaders/RemoteCompiler.cpp b/Code/CryEngine/RenderDll/Common/Shaders/RemoteCompiler.cpp index cf189ff136..8bded3aee3 100644 --- a/Code/CryEngine/RenderDll/Common/Shaders/RemoteCompiler.cpp +++ b/Code/CryEngine/RenderDll/Common/Shaders/RemoteCompiler.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -306,23 +307,20 @@ namespace NRemoteCompiler m_RequestLineRootFolder = ""; - ICVar* pGameFolder = gEnv->pConsole->GetCVar("sys_game_folder"); + auto projectName = AZ::Utils::GetProjectName(); ICVar* pCompilerFolderSuffix = CRenderer::CV_r_ShaderCompilerFolderSuffix; - if (pGameFolder) + if (!projectName.empty()) { - string folder = pGameFolder->GetString(); - folder.Trim(); - if (!folder.empty()) + if (pCompilerFolderSuffix) { - if (pCompilerFolderSuffix) - { - string suffix = pCompilerFolderSuffix->GetString(); - suffix.Trim(); - folder.append(suffix); - } - m_RequestLineRootFolder = folder + string("/"); + string suffix = pCompilerFolderSuffix->GetString(); + suffix.Trim(); + projectName.append(suffix); } + + projectName.append("/"); + m_RequestLineRootFolder.assign(projectName.c_str(), projectName.size()); } if (m_RequestLineRootFolder.empty()) diff --git a/Code/CryEngine/RenderDll/Common/Shaders/RemoteShaderCompilerUnitTests.cpp b/Code/CryEngine/RenderDll/Common/Shaders/RemoteShaderCompilerUnitTests.cpp index 8d32c19998..b0bcf1e702 100644 --- a/Code/CryEngine/RenderDll/Common/Shaders/RemoteShaderCompilerUnitTests.cpp +++ b/Code/CryEngine/RenderDll/Common/Shaders/RemoteShaderCompilerUnitTests.cpp @@ -13,16 +13,61 @@ #include #include #include +#include #include #include "Mocks/IConsoleMock.h" #include "Mocks/ICVarMock.h" #include "Mocks/ISystemMock.h" #include "RemoteCompiler.h" + +namespace AZ +{ + class SettingsRegistrySimpleMock; + using NiceSettingsRegistrySimpleMock = ::testing::NiceMock; + + class SettingsRegistrySimpleMock : public AZ::SettingsRegistryInterface + { + public: + MOCK_CONST_METHOD1(GetType, Type(AZStd::string_view)); + MOCK_CONST_METHOD2(Visit, bool(Visitor&, AZStd::string_view)); + MOCK_CONST_METHOD2(Visit, bool(const VisitorCallback&, AZStd::string_view)); + MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(const NotifyCallback&)); + MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(NotifyCallback&&)); + + MOCK_CONST_METHOD2(Get, bool(bool&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool(s64&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool(u64&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool(double&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool(AZStd::string&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool(FixedValueString&, AZStd::string_view)); + MOCK_CONST_METHOD3(GetObject, bool(void*, Uuid, AZStd::string_view)); + + MOCK_METHOD2(Set, bool(AZStd::string_view, bool)); + MOCK_METHOD2(Set, bool(AZStd::string_view, s64)); + MOCK_METHOD2(Set, bool(AZStd::string_view, u64)); + MOCK_METHOD2(Set, bool(AZStd::string_view, double)); + MOCK_METHOD2(Set, bool(AZStd::string_view, AZStd::string_view)); + MOCK_METHOD2(Set, bool(AZStd::string_view, const char*)); + MOCK_METHOD3(SetObject, bool(AZStd::string_view, const void*, Uuid)); + + MOCK_METHOD1(Remove, bool(AZStd::string_view)); + + MOCK_METHOD3(MergeCommandLineArgument, bool(AZStd::string_view, AZStd::string_view, const CommandLineArgumentSettings&)); + MOCK_METHOD2(MergeSettings, bool(AZStd::string_view, Format)); + MOCK_METHOD4(MergeSettingsFile, bool(AZStd::string_view, Format, AZStd::string_view, AZStd::vector*)); + MOCK_METHOD5( + MergeSettingsFolder, + bool(AZStd::string_view, const Specializations&, AZStd::string_view, AZStd::string_view, AZStd::vector*)); + }; +} // namespace AZ + + namespace NRemoteCompiler { using ::testing::NiceMock; using ::testing::Return; + using ::testing::DoAll; using SystemAllocatorScope = AZ::AllocatorScope; @@ -65,9 +110,12 @@ namespace NRemoteCompiler SystemAllocatorScope::ActivateAllocators(); m_priorEnv = gEnv; + m_priorSettingsRegistry = AZ::SettingsRegistry::Get(); m_data.reset(new DataMembers); + AZ::SettingsRegistry::Register(&m_data->m_settings); + ON_CALL(m_data->m_console, GetCVar(_)) .WillByDefault(Return(&m_data->m_cvarMock)); @@ -89,6 +137,11 @@ namespace NRemoteCompiler void TearDown() override { gEnv = m_priorEnv; + AZ::SettingsRegistry::Unregister(&m_data->m_settings); + if (m_priorSettingsRegistry) + { + AZ::SettingsRegistry::Register(m_priorSettingsRegistry); + } m_data.reset(); SystemAllocatorScope::DeactivateAllocators(); AllocatorsTestFixture::TearDown(); @@ -99,12 +152,14 @@ namespace NRemoteCompiler NiceMock m_system; NiceMock m_console; NiceMock m_cvarMock; + AZ::NiceSettingsRegistrySimpleMock m_settings; SSystemGlobalEnvironment m_stubEnv; }; AZStd::unique_ptr m_data; SSystemGlobalEnvironment* m_priorEnv = nullptr; + AZ::SettingsRegistryInterface* m_priorSettingsRegistry = nullptr; }; // allow punch through to PRIVATE functions so that they do not need to be made PUBLIC. @@ -130,7 +185,9 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_Constructor_WithNoGameName_Fails) { - EXPECT_CALL(m_data->m_cvarMock, GetString()); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString regResult; + EXPECT_CALL(m_data->m_settings, Get(regResult, _)); AZ_TEST_START_TRACE_SUPPRESSION; ShaderSrvUnitTestAccessor srv; @@ -140,8 +197,10 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_Constructor_WithValidGameName_Succeeds) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; } @@ -149,11 +208,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_EncapsulateRequestInEngineConnectionProtocol_EmptyData_Fails) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - std::vector testVector; @@ -165,11 +225,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_EncapsulateRequestInEngineConnectionProtocol_ValidData_EmptyServerList_Fails) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - EXPECT_CALL(m_data->m_cvarMock, GetString()) .WillRepeatedly(Return("")); // empty server list @@ -186,11 +247,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_EncapsulateRequestInEngineConnectionProtocol_ValidInputs_Succeeds) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - // After this, it will repeatedly call get cvar to get the server address: const char* testList = "10.20.30.40"; @@ -207,11 +269,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_SendRequestViaEngineConnection_EmptyData_Fails) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - // After this, it will repeatedly call get cvar to get the server address: const char* testList = "10.20.30.40"; @@ -221,7 +284,7 @@ namespace NRemoteCompiler std::vector testVector; std::string testString("empty"); - // test for empty data - recvfailed expected (error emitted) + // test for empty data - RecvFailed expected (error emitted) AZ_TEST_START_TRACE_SUPPRESSION; testString = "empty"; testVector.assign(testString.begin(), testString.end()); @@ -232,11 +295,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_SendRequestViaEngineConnection_IncompleteData_Fails) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - // After this, it will repeatedly call get cvar to get the server address: const char* testList = "10.20.30.40"; @@ -247,7 +311,7 @@ namespace NRemoteCompiler std::string testString("incomplete"); testVector.assign(testString.begin(), testString.end()); - // test for incomplete data - recvfailed expected + // test for incomplete data - RecvFailed expected AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_EQ(srv.SendRequestViaEngineConnection(testVector), EServerError::ESRecvFailed); AZ_TEST_STOP_TRACE_SUPPRESSION(1); @@ -256,11 +320,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_SendRequestViaEngineConnection_CorruptData_Fails) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - // After this, it will repeatedly call get cvar to get the server address: const char* testList = "10.20.30.40"; @@ -271,7 +336,7 @@ namespace NRemoteCompiler std::string testString("corrupt"); testVector.assign(testString.begin(), testString.end()); - // test for incomplete data - recvfailed expected + // test for incomplete data - RecvFailed expected AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_EQ(srv.SendRequestViaEngineConnection(testVector), EServerError::ESRecvFailed); AZ_TEST_STOP_TRACE_SUPPRESSION(1); @@ -280,11 +345,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_SendRequestViaEngineConnection_CompileError_Fails_ReturnsText) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - // After this, it will repeatedly call get cvar to get the server address: const char* testList = "10.20.30.40"; @@ -294,11 +360,11 @@ namespace NRemoteCompiler std::vector testVector; std::string testString("corrupt"); testVector.assign(testString.begin(), testString.end()); - // test for an actual compile error - decompressed compile erro rexpected to be attached. + // test for an actual compile error - decompressed compile error expected to be attached. testString = "compile_failure"; testVector.assign(testString.begin(), testString.end()); EXPECT_EQ(srv.SendRequestViaEngineConnection(testVector), EServerError::ESCompileError); - // validate hte compile erorr decompressed successfully + // validate the compile error decompressed successfully const char* expected_decode = "decompressed_plaintext"; EXPECT_EQ(testVector.size(), strlen(expected_decode)); EXPECT_EQ(memcmp(testVector.data(), expected_decode, strlen(expected_decode)), 0); @@ -307,11 +373,12 @@ namespace NRemoteCompiler TEST_F(RemoteCompilerTest, CShaderSrv_SendRequestViaEngineConnection_ValidInput_Succeeds_ReturnsText) { // when we construct the server it calls get on the game name - EXPECT_CALL(m_data->m_cvarMock, GetString()) - .WillOnce(Return("StarterGame")); + using namespace ::testing; + AZ::SettingsRegistryInterface::FixedValueString projectName; + EXPECT_CALL(m_data->m_settings, Get(projectName, _)) + .WillOnce(DoAll(testing::SetArgReferee<0>("StarterGame"), Return(true))); ShaderSrvUnitTestAccessor srv; - // After this, it will repeatedly call get cvar to get the server address: const char* testList = "10.20.30.40"; diff --git a/Code/CryEngine/RenderDll/Common/Shaders/ShaderCache.cpp b/Code/CryEngine/RenderDll/Common/Shaders/ShaderCache.cpp index 8dec38548b..06c1715355 100644 --- a/Code/CryEngine/RenderDll/Common/Shaders/ShaderCache.cpp +++ b/Code/CryEngine/RenderDll/Common/Shaders/ShaderCache.cpp @@ -375,7 +375,7 @@ void CShaderMan::mfInitShadersCacheMissLog() // create valid path gEnv->pCryPak->MakeDir(g_szTestResults); - m_ShaderCacheMissPath = string("@cache@\\Shaders\\ShaderCacheMisses.txt"); // do we want this here, or maybe in @log@ ? + m_ShaderCacheMissPath = string("@usercache@\\Shaders\\ShaderCacheMisses.txt"); // do we want this here, or maybe in @log@ ? // load data which is already stored AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; @@ -2175,9 +2175,10 @@ void CShaderMan::mfOptimiseShaders(const char* szFolder, bool bForce) for (i = 0; i < Names.size(); i++) { const char* szName = Names[i].c_str(); - if (!strncmp(szName, "@cache@/", 7)) + constexpr AZStd::string_view userCache = "@usercache@/"; + if (szName == userCache) { - szName += 7; + szName += userCache.size(); } pCache = CHWShader::mfInitCache(szName, NULL, false, 0, false); if (!pCache || !pCache->m_pRes[CACHE_USER]) diff --git a/Code/CryEngine/RenderDll/Common/Shaders/ShaderCore.cpp b/Code/CryEngine/RenderDll/Common/Shaders/ShaderCore.cpp index 6fedb3110c..c0d44fcf40 100644 --- a/Code/CryEngine/RenderDll/Common/Shaders/ShaderCore.cpp +++ b/Code/CryEngine/RenderDll/Common/Shaders/ShaderCore.cpp @@ -1589,7 +1589,7 @@ void CShaderMan::mfInit (void) #else m_ShadersCache = CONCAT_PATHS(g_shaderCache, "D3D11"); #endif - m_szCachePath = "@cache@/"; + m_szCachePath = "@usercache@/"; if (CRenderer::CV_r_shadersImport == 3) { diff --git a/Code/CryEngine/RenderDll/Common/Shaders/ShaderSerialize.cpp b/Code/CryEngine/RenderDll/Common/Shaders/ShaderSerialize.cpp index 92185363be..aa457703cd 100644 --- a/Code/CryEngine/RenderDll/Common/Shaders/ShaderSerialize.cpp +++ b/Code/CryEngine/RenderDll/Common/Shaders/ShaderSerialize.cpp @@ -162,7 +162,7 @@ bool CShaderSerialize::OpenSResource(const char* szName, SSShaderRes* pSR, CSha stack_string szReadOnly = szName; // ShaderCacheGen behavior: - // CACHE_READONLY is not really used when exporting the .fxb, so we append the @cache@ alias to the relative shader path + // CACHE_READONLY is not really used when exporting the .fxb, so we append the @usercache@ alias to the relative shader path // here as well. We cannot just leave this as the relative Shaders/Cache/Foo.fxb value because then it creates a new // file in the asset cache as @assets@/Shaders/Cache/Foo.fxb, which is illegal (since only AP has the authority to write here) // Game runtime behavior: diff --git a/Code/CryEngine/RenderDll/XRenderD3D9/D3DHWShaderCompiling.cpp b/Code/CryEngine/RenderDll/XRenderD3D9/D3DHWShaderCompiling.cpp index 1f7c484705..b200f3e2bc 100644 --- a/Code/CryEngine/RenderDll/XRenderD3D9/D3DHWShaderCompiling.cpp +++ b/Code/CryEngine/RenderDll/XRenderD3D9/D3DHWShaderCompiling.cpp @@ -3490,7 +3490,7 @@ void CHWShader_D3D::mfSaveCGFile(const char* scr, const char* path) } else { - sprintf_s(name, "@cache@/shaders/fxerror/%s(GL%llx)/(LT%x)(RT%llx)/(MD%x)(MDV%x)(PSS%llx)(ST%llx).cg", GetName(), m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask, m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_pipelineState.opaque, m_pCurInst->m_Ident.m_STMask); + sprintf_s(name, "@usercache@/shaders/fxerror/%s(GL%llx)/(LT%x)(RT%llx)/(MD%x)(MDV%x)(PSS%llx)(ST%llx).cg", GetName(), m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask, m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_pipelineState.opaque, m_pCurInst->m_Ident.m_STMask); } AZ::IO::HandleType fileHandle; @@ -4672,7 +4672,7 @@ bool CAsyncShaderTask::CompileAsyncShader(SShaderAsyncInfo* pAsync) CryFixedStringT<1024> hlslPath; // Create a directory for this shader type, strip the .fxcb extension from the folder name - shaderSourceOutputFolder.Format("@cache@/%s",pAsync->m_pShader->m_pDevCache->m_Name.c_str()); + shaderSourceOutputFolder.Format("@usercache@/%s",pAsync->m_pShader->m_pDevCache->m_Name.c_str()); PathUtil::RemoveExtension(shaderSourceOutputFolder); gEnv->pFileIO->CreatePath(shaderSourceOutputFolder); diff --git a/Code/CryEngine/RenderDll/XRenderD3D9/D3DSystem.cpp b/Code/CryEngine/RenderDll/XRenderD3D9/D3DSystem.cpp index 7f9274da86..7fa44a8983 100644 --- a/Code/CryEngine/RenderDll/XRenderD3D9/D3DSystem.cpp +++ b/Code/CryEngine/RenderDll/XRenderD3D9/D3DSystem.cpp @@ -70,6 +70,7 @@ #endif #include "../Common/RenderCapabilities.h" +#include #ifdef WIN32 // Count monitors helper @@ -1634,8 +1635,8 @@ WIN_HWND CD3D9Renderer::Init([[maybe_unused]] int x, [[maybe_unused]] int y, int iLog->Log ("Direct3D driver is creating..."); iLog->Log ("Crytek Direct3D driver version %4.2f (%s <%s>)", VERSION_D3D, __DATE__, __TIME__); - const char* sGameName = iConsole->GetCVar("sys_game_name")->GetString(); - cry_strcpy(m_WinTitle, sGameName); + auto projectName = AZ::Utils::GetProjectName(); + cry_strcpy(m_WinTitle, projectName.c_str()); iLog->Log ("Creating window called '%s' (%dx%d)", m_WinTitle, width, height); diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index 2ff07d9147..0b783239c7 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -99,6 +101,18 @@ namespace AZ return environment ? environment->Get() : nullptr; } + ComponentApplication::EventLoggerDeleter::EventLoggerDeleter() noexcept= default; + ComponentApplication::EventLoggerDeleter::EventLoggerDeleter(bool skipDelete) noexcept + : m_skipDelete{skipDelete} + {} + void ComponentApplication::EventLoggerDeleter::operator()(AZ::Debug::LocalFileEventLogger* ptr) + { + if (!m_skipDelete) + { + delete ptr; + } + } + //========================================================================= // ComponentApplication::Descriptor // [5/30/2012] @@ -159,6 +173,80 @@ namespace AZ return true; }; + //! SettingsRegistry notifier handler which updates relevant registry settings based + //! on an update to '/Amazon/AzCore/Bootstrap/project_path' key. + struct UpdateProjectSettingsEventHandler + { + UpdateProjectSettingsEventHandler(AZ::SettingsRegistryInterface& registry) + : m_registry{ registry } + { + } + + void operator()(AZStd::string_view path, AZ::SettingsRegistryInterface::Type) + { + UpdateProjectSpecializationInRegistry(path); + } + + //! Add the project name as a specialization underneath the /Amazon/AzCore/Settings/Specializations path + //! and remove the current project name specialization if one exists. + void UpdateProjectSpecializationInRegistry(AZStd::string_view path) + { + auto projectPathKey = + AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + + "/project_path"; + if (path == projectPathKey) + { + AZ::SettingsRegistryInterface::FixedValueString newProjectPath; + if (m_registry.Get(newProjectPath, path) && !newProjectPath.empty()) + { + // Make the path absolute by appending to app root, in case project path is relative. + // If the project path is already absolute it will remain the same. + // If we turn it from a relative path to an absolute path, write-back the absolute path to the registry. + AZ::IO::FixedMaxPath projectPath = AZ::SettingsRegistryMergeUtils::FindEngineRoot(m_registry) / newProjectPath; + if (projectPath.Compare(newProjectPath.c_str())) + { + m_registry.Set(path, projectPath.Native()); + } + + // Merge the project.json file into settings registry under ProjectSettingsRootKey path. + AZ::IO::FixedMaxPath projectMetadataFile{ projectPath }; + projectMetadataFile /= "project.json"; + m_registry.MergeSettingsFile(projectMetadataFile.Native(), + AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey); + + // Get the 'project_name' value from what was in the 'project.json' file... + auto projectNameKey = + AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) + + "/project_name"; + + AZ::SettingsRegistryInterface::FixedValueString projectSpecialization; + if (m_registry.Get(projectSpecialization, projectNameKey)) + { + auto specializationKey = AZ::SettingsRegistryInterface::FixedValueString::format( + "%s/%s", AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, projectSpecialization.c_str()); + if (m_currentSpecialization != specializationKey) + { + m_registry.Set(specializationKey, true); + if (!m_currentSpecialization.empty()) + { + // Remove the previous Project Name from the specialization path if it was set. + m_registry.Remove(m_currentSpecialization); + } + m_currentSpecialization = specializationKey; + + // Update all the runtime file paths based on the new "project_path" value. + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); + } + } + } + } + } + + private: + AZ::SettingsRegistryInterface::FixedValueString m_currentSpecialization; + AZ::SettingsRegistryInterface& m_registry; + }; + void ComponentApplication::Descriptor::AllocatorRemapping::Reflect(ReflectContext* context, ComponentApplication* app) { (void)app; @@ -276,6 +364,7 @@ namespace AZ } ComponentApplication::ComponentApplication(int argC, char** argV) + : m_eventLogger{} { if (argV) { @@ -284,11 +373,23 @@ namespace AZ } else { - azstrcpy(m_commandLineBuffer, AZ_ARRAY_SIZE(m_commandLineBuffer), "no_argv_supplied"); + azstrcpy(m_commandLineBuffer, AZ_ARRAY_SIZE(m_commandLineBuffer), "no_argv_supplied"); // use a "valid" value here. This is because Qt and potentially other third party libraries require // that ArgC be 'at least 1' and that (*argV)[0] be a valid pointer to a real null terminated string. - m_argC = 1; - m_argV = &m_commandLineBufferAddress; + m_argC = 1; + m_argV = &m_commandLineBufferAddress; + } + + // Create the Event logger if it doesn't exist, otherwise reuse the one registered + // with the AZ::Interface + if (AZ::Interface::Get() == nullptr) + { + m_eventLogger.reset(new AZ::Debug::LocalFileEventLogger); + } + else + { + m_eventLogger = EventLoggerPtr(static_cast(AZ::Interface::Get()), + EventLoggerDeleter{ true }); } // Initializes the OSAllocator and SystemAllocator as soon as possible @@ -297,6 +398,7 @@ namespace AZ // Now that the Allocators are initialized, the Command Line parameters can be parsed m_commandLine.Parse(m_argC, m_argV); + ParseCommandLine(m_commandLine); // Create the settings registry and register it with the AZ interface system // This is done after the AppRoot has been calculated so that the Bootstrap.cfg @@ -304,62 +406,34 @@ namespace AZ m_settingsRegistry = AZStd::make_unique(); // Register the Settings Registry with the AZ Interface if there isn't one registered already - if (AZ::SettingsRegistry::Get() == nullptr) + if (SettingsRegistry::Get() == nullptr) { SettingsRegistry::Register(m_settingsRegistry.get()); } // Add the Command Line arguments into the SettingsRegistry - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_StoreCommandLine(*m_settingsRegistry, m_commandLine); + SettingsRegistryMergeUtils::StoreCommandLineToRegistry(*m_settingsRegistry, m_commandLine); + + // Merge Command Line arguments + constexpr bool executeRegDumpCommands = false; + SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); // Query for the Executable Path using OS specific functions CalculateExecutablePath(); - // If the current platform returns an engaged optional from Utils::GetDefaultAppRootPath(), that is used - // for the application root other the application root is found by scanning upwards from the Executable Directory - // for a bootstrap.cfg file - CalculateAppRoot(nullptr); - - // Add a notifier to update the /Amazon/AzCore/Settings/Specializations - // when the sys_game_folder property changes within the SettingsRegistry - // currentGameName is bound by value in order to allow the lambda to have a member variable that - // can track the current game specialization before it changes - AZ::SettingsRegistryInterface::FixedValueString currentGameSpecialization; - auto GameProjectChanged = [currentGameSpecialization](AZStd::string_view path, AZ::SettingsRegistryInterface::Type type) mutable - { - constexpr auto projectKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) - + "/sys_game_folder"; - if (projectKey == path && type == AZ::SettingsRegistryInterface::Type::String) - { - auto registry = AZ::SettingsRegistry::Get(); - AZ::SettingsRegistryInterface::FixedValueString newGameName; - if (registry && registry->Get(newGameName, path) && !newGameName.empty()) - { - auto specializationKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, newGameName.c_str()); + // Determine the path to the engine + CalculateEngineRoot(); - if (currentGameSpecialization != specializationKey) - { - registry->Set(specializationKey, true); - if (!currentGameSpecialization.empty()) - { - // Remove the previous Game Name from the specialization path if it was set - registry->Remove(currentGameSpecialization); - } - // Update the currentGameSpecialization - currentGameSpecialization = specializationKey; + // If the current platform returns an engaged optional from Utils::GetDefaultAppRootPath(), that is used + // for the application root. + CalculateAppRoot(); - // Update all the runtime filepaths based on the new "sys_game_folder" value - SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); - } - } - } - }; - m_gameProjectChangedHandler = m_settingsRegistry->RegisterNotifier(AZStd::move(GameProjectChanged)); + // Add a notifier to update the /Amazon/AzCore/Settings/Specializations + // when the 'project_path' property changes within the SettingsRegistry + m_projectChangedHandler = m_settingsRegistry->RegisterNotifier(UpdateProjectSettingsEventHandler{ *m_settingsRegistry }); // Merge the bootstrap.cfg file into the Settings Registry as soon as the OSAllocator has been created. SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(*m_settingsRegistry); - constexpr bool executeRegDumpCommands = false; SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry); @@ -391,11 +465,11 @@ namespace AZ Destroy(); } - // The m_gameProjectChangedHandler stores an AZStd::function internally + // The m_projectChangedHandler stores an AZStd::function internally // which allocates using the AZ SystemAllocator - // m_gameProjectChangedHandler is being default value initialized + // m_projectChangedHandler is being default value initialized // to clear out the AZStd::function - m_gameProjectChangedHandler = {}; + m_projectChangedHandler = {}; // Delete the AZ::IConsole if it was created by this application instance if (m_ownsConsole) @@ -412,6 +486,10 @@ namespace AZ } m_settingsRegistry.reset(); + // Set AZ::CommandLine to an empty object to clear out allocated memory before the allocators + // are destroyed + m_commandLine = {}; + DestroyAllocator(); } @@ -421,17 +499,6 @@ namespace AZ AZ_Assert(!m_isStarted, "Component application already started!"); m_startupParameters = startupParameters; - // Invokes CalculateAppRoot() again this time with the appRootOverride startup parameter - // supplied in order to allow overriding the AppRoot calculated in the constructor - if (m_startupParameters.m_appRootOverride) - { - CalculateAppRoot(m_startupParameters.m_appRootOverride); - // Re-check for the bootstrap.cfg file again using the appRoot override and update the file paths - SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(*m_settingsRegistry); - constexpr bool executeRegDumpCommands = false; - SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); - SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry); - } m_descriptor = descriptor; @@ -461,20 +528,14 @@ namespace AZ void ComponentApplication::CreateCommon() { { - AZ::SettingsRegistryInterface::FixedValueString registryValue; - m_settingsRegistry->Get(registryValue, AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage); - AZ::IO::FixedMaxPath outputPath{ registryValue }; + AZ::IO::FixedMaxPath outputPath; + m_settingsRegistry->Get(outputPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage); outputPath /= "eventlogger"; - registryValue.clear(); - AZ::IO::FixedMaxPathString baseFileName{ "EventLog" }; // default name - if (m_settingsRegistry->Get(registryValue, AZ::SettingsRegistryMergeUtils::BuildTargetNameKey)) - { - baseFileName = registryValue; - } + m_settingsRegistry->Get(baseFileName, AZ::SettingsRegistryMergeUtils::BuildTargetNameKey); - m_eventLogger.Start(outputPath.c_str(), baseFileName.c_str()); + m_eventLogger->Start(outputPath.Native(), baseFileName); } CreateDrillers(); @@ -515,7 +576,9 @@ namespace AZ LoadModules(); // Execute user.cfg after modules have been loaded but before processing any command-line overrides - m_console->ExecuteConfigFile("@root@/user.cfg"); + AZ::IO::FixedMaxPath platformCachePath; + m_settingsRegistry->Get(platformCachePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + m_console->ExecuteConfigFile((platformCachePath / "user.cfg").Native()); // Parse the command line parameters for console commands after modules have loaded m_console->ExecuteCommandLine(m_commandLine); @@ -601,7 +664,7 @@ namespace AZ m_drillerManager = nullptr; } - m_eventLogger.Stop(); + m_eventLogger->Stop(); // Clear the descriptor to deallocate all strings (owned by ModuleDescriptor) m_descriptor = Descriptor(); @@ -775,6 +838,46 @@ namespace AZ } } + void ComponentApplication::ParseCommandLine(const AZ::CommandLine& commandLine) + { + struct OptionKeyToRegsetKey + { + AZStd::string_view m_optionKey; + AZStd::string m_regsetKey; + }; + + // Provide overrides for the engine root, the project root and the project cache root + AZStd::array commandOptions = { + OptionKeyToRegsetKey{ "engine-path", AZStd::string::format("%s/engine_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) }, + OptionKeyToRegsetKey{ "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::fixed_vector overrideArgs; + + for (auto&& [optionKey, regsetKey] : commandOptions) + { + if (size_t optionCount = commandLine.GetNumSwitchValues(optionKey); optionCount > 0) + { + // Use the last supplied command option value to override previous values + auto overrideArg = AZStd::string::format(R"(--regset="%s=%s")", regsetKey.c_str(), + commandLine.GetSwitchValue(optionKey, optionCount - 1).c_str()); + overrideArgs.emplace_back(AZStd::move(overrideArg)); + } + } + + if (!overrideArgs.empty()) + { + // Dump the input command line, add the additional option overrides + // and Parse the new command line into the Component Application command line + AZ::CommandLine::ParamContainer commandLineArgs; + commandLine.Dump(commandLineArgs); + commandLineArgs.insert(commandLineArgs.end(), AZStd::make_move_iterator(overrideArgs.begin()), + AZStd::make_move_iterator(overrideArgs.end())); + m_commandLine.Parse(commandLineArgs); + } + } + void ComponentApplication::MergeSettingsToRegistry(SettingsRegistryInterface& registry) { SettingsRegistryInterface::Specializations specializations; @@ -788,14 +891,14 @@ namespace AZ // In development builds apply the developer 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_DevRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); #endif 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_DevRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif } @@ -1013,7 +1116,7 @@ namespace AZ struct GemModuleLoadData { AZ::OSString m_gemName; - AZ::OSString m_dynamicLibraryPath; + AZStd::vector m_dynamicLibraryPaths; bool m_autoLoad{ true }; }; @@ -1069,19 +1172,18 @@ namespace AZ } } - void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override + void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override { - if (valueName == "Module" && !value.empty()) + // Remove last path segment and check if the key corresponds to the Modules array + AZStd::optional moduleIndex = AZ::StringFunc::TokenizeLast(path, "/"); + if (path.ends_with("/Modules")) { - // Strip off the Module entry from the path - auto moduleKey = AZ::StringFunc::TokenizeLast(path, "/"); - if (!moduleKey) - { - return; - } + // Remove the "Modules" path segment to be at the GemName key + AZ::StringFunc::TokenizeLast(path, "/"); if (auto moduleLoadData = FindGemModuleEntry(path); moduleLoadData != nullptr) { - moduleLoadData->m_dynamicLibraryPath = value; + // Just use Json Serialization to load all the array elements + moduleLoadData->m_dynamicLibraryPaths.emplace_back(value); } } } @@ -1111,30 +1213,41 @@ namespace AZ } }; - constexpr size_t RegistryKeySize = 64; - auto gemModuleKey = AZStd::fixed_string::format("%s/Gems", AZ::SettingsRegistryMergeUtils::OrganizationRootKey); + auto gemModuleKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/Gems", AZ::SettingsRegistryMergeUtils::OrganizationRootKey); ModuleDescriptorList gemModules; { GemModuleVisitor moduleVisitor; - m_settingsRegistry->Visit(moduleVisitor, gemModuleKey); + m_settingsRegistry->Visit(moduleVisitor, gemModuleKey); for (GemModuleLoadData& moduleLoadData : moduleVisitor.m_modulesLoadData) { // Add all auto loadable non-asset gems to the list of gem modules to load - if (moduleLoadData.m_autoLoad && !moduleLoadData.m_dynamicLibraryPath.empty()) + if (!moduleLoadData.m_autoLoad) { - gemModules.emplace_back(DynamicModuleDescriptor{ AZStd::move(moduleLoadData.m_dynamicLibraryPath) }); + break; + } + for (AZ::OSString& dynamicLibraryPath : moduleLoadData.m_dynamicLibraryPaths) + { + auto CompareDynamicModuleDescriptor = [&dynamicLibraryPath](const DynamicModuleDescriptor& entry) + { + return entry.m_dynamicLibraryPath.contains(dynamicLibraryPath); + }; + if (auto moduleIter = AZStd::find_if(gemModules.begin(), gemModules.end(), CompareDynamicModuleDescriptor); + moduleIter == gemModules.end()) + { + gemModules.emplace_back(DynamicModuleDescriptor{ AZStd::move(dynamicLibraryPath) }); + } } } } - // The settings registry in the settings registry are prioritized to load before the modules in the ComponetnApplication descriptor + // The modules in the settings registry are prioritized to load before the modules in the ComponentApplication descriptor // in the order in which they were found for (auto&& moduleDescriptor : m_descriptor.m_modules) { // Append new dynamic library modules to the descriptor array auto CompareDynamicModuleDescriptor = [&moduleDescriptor](const DynamicModuleDescriptor& entry) { - return entry.m_dynamicLibraryPath.find(moduleDescriptor.m_dynamicLibraryPath) != AZStd::string_view::npos; + return entry.m_dynamicLibraryPath.contains(moduleDescriptor.m_dynamicLibraryPath); }; if (auto foundModuleIter = AZStd::find_if(gemModules.begin(), gemModules.end(), CompareDynamicModuleDescriptor); foundModuleIter == gemModules.end()) @@ -1260,17 +1373,8 @@ namespace AZ m_exeDirectory.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR); } - void ComponentApplication::CalculateAppRoot(const char* appRootOverride) + void ComponentApplication::CalculateAppRoot() { - if (appRootOverride) - { - m_appRoot = appRootOverride; - if (!m_appRoot.empty() && !m_appRoot.ends_with(AZ_CORRECT_FILESYSTEM_SEPARATOR)) - { - m_appRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR); - } - return; - } if (AZStd::optional appRootPath = Utils::GetDefaultAppRootPath(); appRootPath) { m_appRoot = AZStd::move(*appRootPath); @@ -1279,26 +1383,14 @@ namespace AZ m_appRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR); } } - else - { - m_appRoot = AZ::SettingsRegistryMergeUtils::GetAppRoot(m_settingsRegistry.get()).Native(); - m_appRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR); - } } - //========================================================================= - // CheckEngineMarkerFile - //========================================================================= - bool ComponentApplication::CheckPathForEngineMarker(const char* fullPath) const + void ComponentApplication::CalculateEngineRoot() { - static const char* engineMarkerFileName = "engine.json"; - char engineMarkerFullPathToCheck[AZ_MAX_PATH_LEN] = ""; - - azstrcpy(engineMarkerFullPathToCheck, AZ_ARRAY_SIZE(engineMarkerFullPathToCheck), fullPath); - azstrcat(engineMarkerFullPathToCheck, AZ_ARRAY_SIZE(engineMarkerFullPathToCheck), "/"); - azstrcat(engineMarkerFullPathToCheck, AZ_ARRAY_SIZE(engineMarkerFullPathToCheck), engineMarkerFileName); - - return AZ::IO::SystemFile::Exists(engineMarkerFullPathToCheck); + if (m_engineRoot = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*m_settingsRegistry).Native(); !m_engineRoot.empty()) + { + m_engineRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR); + } } void ComponentApplication::ResolveModulePath([[maybe_unused]] AZ::OSString& modulePath) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index e43f1f9938..4d1e26d242 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -9,15 +9,13 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -#ifndef AZCORE_COMPONENT_APPLICATION_H -#define AZCORE_COMPONENT_APPLICATION_H +#pragma once #include #include #include #include #include -#include #include #include #include @@ -40,12 +38,15 @@ namespace AZ class IConsole; class Module; class ModuleManager; +} +namespace AZ::Debug +{ + class DrillerManager; + class LocalFileEventLogger; +} - namespace Debug - { - class DrillerManager; - } - +namespace AZ +{ class ReflectionEnvironment { public: @@ -167,15 +168,6 @@ namespace AZ //! \note Dynamic AZ::Modules are specified in the ComponentApplication::Descriptor. CreateStaticModulesCallback m_createStaticModulesCallback = nullptr; - //! If set, this is used as the app root folder instead of it being calculated. - const char* m_appRootOverride = nullptr; - - //! The path to root of the asset cache folder. For instance: ./cache//pc - const char* m_cacheRootPath = nullptr; - - //! The path to the project in the asset cache folder. For instance: ./cache//pc/ - const char* m_cacheProjectPath = nullptr; - //! Specifies which system components to create & activate. If no tags specified, all system components are used. Specify as comma separated list. const char* m_systemComponentTags = nullptr; @@ -226,6 +218,8 @@ namespace AZ /// Returns the working root folder that has been registered with the app, if there is one. /// It's expected that derived applications will implement an application root. const char* GetAppRoot() const override { return m_appRoot.c_str(); } + /// Returns the path to the engine. + const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } /// Returns the path to the folder the executable is in. const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); } @@ -331,6 +325,9 @@ namespace AZ /// Create the drillers void CreateDrillers(); + /// Parse ComponentApplication specific command line arguments + void ParseCommandLine(const AZ::CommandLine& commandLine); + virtual void MergeSettingsToRegistry(SettingsRegistryInterface& registry); //! Sets the specializations that will be used when loading the Settings Registry. Extend this in derived @@ -363,17 +360,11 @@ namespace AZ /// Calculates the directory the application executable comes from. void CalculateExecutablePath(); - /// Calculates the directory where the bootstrap.cfg file resides. - void CalculateAppRoot(const char* appRootOverride = {}); + /// Calculates the root directory of the engine. + void CalculateEngineRoot(); - /** - * Check/verify a given path for the engine marker (file) so that we can identify that - * a given path is the engine root. This is only valid for target platforms that are built - * for the host platform and not deployable (ie windows, mac). - * @param fullPath The full path to look for the engine marker - * @return true if the input path contains the engine marker file, false if not - */ - virtual bool CheckPathForEngineMarker(const char* fullPath) const; + /// Calculates the directory where the bootstrap.cfg file resides. + void CalculateAppRoot(); template static void NormalizePath(Iterator begin, Iterator end, bool doLowercase = true) @@ -398,10 +389,11 @@ namespace AZ void* m_fixedMemoryBlock{ nullptr }; //!< Pointer to the memory block allocator, so we can free it OnDestroy. IAllocatorAllocate* m_osAllocator{ nullptr }; EntitySetType m_entities; - AZ::StringFunc::Path::FixedString m_exeDirectory; - AZ::StringFunc::Path::FixedString m_appRoot; + AZ::IO::FixedMaxPathString m_exeDirectory; + AZ::IO::FixedMaxPathString m_engineRoot; + AZ::IO::FixedMaxPathString m_appRoot; - AZ::SettingsRegistryInterface::NotifyEventHandler m_gameProjectChangedHandler; + AZ::SettingsRegistryInterface::NotifyEventHandler m_projectChangedHandler; // ConsoleFunctorHandle is responsible for unregistering the Settings Registry Console // from the m_console member when it goes out of scope @@ -427,9 +419,15 @@ namespace AZ // Created early to allow events to be logged before anything else. These will be kept in memory until // a file is associated with the logger. The internal buffer is limited to 64kb and once full unexpected // behavior may happen. The LocalFileEventLogger will register itself automatically with AZ::Interface. - AZ::Debug::LocalFileEventLogger m_eventLogger; + + struct EventLoggerDeleter + { + EventLoggerDeleter() noexcept; + EventLoggerDeleter(bool skipDelete) noexcept; + void operator()(AZ::Debug::LocalFileEventLogger* ptr); + bool m_skipDelete{}; + }; + using EventLoggerPtr = AZStd::unique_ptr; + EventLoggerPtr m_eventLogger; }; } - -#endif // AZCORE_COMPONENT_APPLICATION_H -#pragma once diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h index 993646358d..96aa56bfea 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h @@ -183,6 +183,11 @@ namespace AZ * @return A pointer to the name of the app's root folder, if a root folder was registered. */ virtual const char* GetAppRoot() const = 0; + /** + * Gets the path of the working engine folder that the app is a part of. + * @return A pointer to the engine path. + */ + virtual const char* GetEngineRoot() const = 0; /** * Gets the path to the directory that contains the application's executable. * @return A pointer to the name of the path that contains the application's executable. diff --git a/Code/Framework/AzCore/AzCore/Console/Console.cpp b/Code/Framework/AzCore/AzCore/Console/Console.cpp index 7623eb3f5f..3701f35f8d 100644 --- a/Code/Framework/AzCore/AzCore/Console/Console.cpp +++ b/Code/Framework/AzCore/AzCore/Console/Console.cpp @@ -161,9 +161,11 @@ namespace AZ void Console::ExecuteCommandLine(const AZ::CommandLine& commandLine) { - for (const auto& [switchKey, switchValues] : commandLine.GetSwitchList()) + for (auto&& commandArgument : commandLine) { - ConsoleCommandContainer commandArgs(switchValues.begin(), switchValues.end()); + const auto& switchKey = commandArgument.m_option; + const auto& switchValue = commandArgument.m_value; + ConsoleCommandContainer commandArgs{ switchValue }; PerformCommand(switchKey, commandArgs, ConsoleSilentMode::NotSilent, ConsoleInvokedFrom::AzConsole, ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null); } } diff --git a/Code/Framework/AzCore/AzCore/IO/FileIO.h b/Code/Framework/AzCore/AzCore/IO/FileIO.h index c69d8304e9..d253d6dae5 100644 --- a/Code/Framework/AzCore/AzCore/IO/FileIO.h +++ b/Code/Framework/AzCore/AzCore/IO/FileIO.h @@ -67,25 +67,7 @@ namespace AZ return a != OpenMode::Invalid; } - inline OpenMode operator | (OpenMode a, OpenMode b) - { - return static_cast(static_cast(a) | static_cast(b)); - } - - inline OpenMode operator & (OpenMode a, OpenMode b) - { - return static_cast(static_cast(a) & static_cast(b)); - } - - inline OpenMode& operator |= (OpenMode& a, OpenMode b) - { - return a = a | b; - } - - inline OpenMode& operator &= (OpenMode& a, OpenMode b) - { - return a = a & b; - } + AZ_DEFINE_ENUM_BITWISE_OPERATORS(OpenMode) OpenMode GetOpenModeFromStringMode(const char* mode); @@ -250,12 +232,14 @@ namespace AZ virtual bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const = 0; AZStd::optional ConvertToAlias(const AZ::IO::PathView& path) const; - /// ResolvePath - Replaces any aliases in path with their values and stores the result in resolvedPath, - /// also ensures that the path is absolute - /// returns true if path was resolved, false otherwise - /// note that all of the above file-finding and opening functions automatically resolve the path before operating - /// so you should not need to call this except in very exceptional circumstances where you absolutely need to - /// hit a physical file and don't want to use SystemFile + //! ResolvePath - Replaces any aliases in path with their values and stores the result in resolvedPath, + //! also ensures that the path is absolute + //! NOTE: If the path does not start with an alias then the resolved value of the @assets@ is used + //! which has the effect of making the path relative to the @assets@/ folder + //! returns true if path was resolved, false otherwise + //! note that all of the above file-finding and opening functions automatically resolve the path before operating + //! so you should not need to call this except in very exceptional circumstances where you absolutely need to + //! hit a physical file and don't want to use SystemFile virtual bool ResolvePath(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const = 0; //! ResolvePath - Replaces any @ aliases in the supplied path with their the resolved alias values @@ -265,6 +249,11 @@ namespace AZ virtual bool ResolvePath(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path) const = 0; AZStd::optional ResolvePath(const AZ::IO::PathView& path) const; + //! ReplaceAliases - If the path starts with an @...@ alias it is substituted with the alias value + //! otherwise the path is copied as is to the resolvedAlias path value + //! returns true if the resulting path can fit within AZ::IO::FixedMaxPath buffer + virtual bool ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const = 0; + /// Divulge the filename used to originally open that handle. virtual bool GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const = 0; diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.h b/Code/Framework/AzCore/AzCore/IO/Path/Path.h index b25b1b6fe1..97f528d1dc 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.h +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.h @@ -170,7 +170,7 @@ namespace AZ::IO //! Check whether the path is not absolute [[nodiscard]] constexpr bool IsRelative() const; //! Check whether the path is relative to the base path - [[nodiscard]] constexpr bool IsRelativeTo(const PathView & base) const; + [[nodiscard]] constexpr bool IsRelativeTo(const PathView& base) const; //! Normalizes a path in a purely lexical manner. //! # Path separators are converted to their preferred path separator @@ -517,7 +517,7 @@ namespace AZ::IO //! Checks if the path has a root directory [[nodiscard]] constexpr bool HasRootDirectory() const; //! Checks whether the entire root path portion of the path is empty - //! The root portion ofthe path is made up of root_name() / root_directory() + //! The root portion of the path is made up of root_name() / root_directory() [[nodiscard]] constexpr bool HasRootPath() const; //! checks whether the relative part of path is empty //! (C:\\ lumberyard\dev\) @@ -539,8 +539,8 @@ namespace AZ::IO [[nodiscard]] constexpr bool IsAbsolute() const; //! Check whether the path is not absolute [[nodiscard]] constexpr bool IsRelative() const; - //! Check whether the path is relative to the input path - [[nodiscard]] constexpr bool IsRelativeTo() const; + //! Check whether the path is relative to the base path + [[nodiscard]] constexpr bool IsRelativeTo(const PathView& base) const; // decomposition //! Given a windows path of "C:\lumberyard\foo\bar\name.txt" and a posix path of diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl index 7f90a61116..576ff215c9 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl @@ -1035,7 +1035,7 @@ namespace AZ::IO // move the parser from the end to a valid filename by decrementing for(--pathParserEnd, --patternParserEnd; pathParserEnd && patternParserEnd; --pathParserEnd, --patternParserEnd) { - if (!AZStd::wildcard_match(*patternParserEnd, *pathParserEnd)) + if (!AZStd::wildcard_match_case(*patternParserEnd, *pathParserEnd)) { return false; } @@ -1830,9 +1830,9 @@ namespace AZ::IO } template - [[nodiscard]] constexpr bool BasicPath::IsRelativeTo() const + [[nodiscard]] constexpr bool BasicPath::IsRelativeTo(const PathView& base) const { - return static_cast(*this).IsRelative(); + return static_cast(*this).IsRelativeTo(base); } template diff --git a/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp b/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp index c90677d6f3..06bc5de92a 100644 --- a/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp +++ b/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp @@ -369,6 +369,7 @@ namespace AZ context.Serializer()->HandlesType(); context.Serializer()->HandlesType(); context.Serializer()->HandlesType(); + context.Serializer()->HandlesType(); } void MathReflect(ReflectContext* context) diff --git a/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp b/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp index ac3d663164..aa9686f709 100644 --- a/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -238,4 +239,56 @@ namespace AZ { return JsonMathVectorSerializerInternal::Store(outputValue, inputValue, defaultValue, valueTypeId, context); } + + // Quaternion + + AZ_CLASS_ALLOCATOR_IMPL(JsonQuaternionSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result JsonQuaternionSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds. + + // check for "yaw, pitch, roll" object + if (inputValue.IsObject()) + { + if (inputValue.GetObject().ObjectEmpty()) + { + Quaternion* outQuaternion = reinterpret_cast(outputValue); + *outQuaternion = Quaternion::CreateIdentity(); + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Using identity quaternion for empty object."); + } + + AZ::BaseJsonSerializer* floatSerializer = context.GetRegistrationContext()->GetSerializerForType(azrtti_typeid()); + if (!floatSerializer) + { + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "Failed to find the json float serializer."); + } + + constexpr const char* names[3] = {"yaw", "pitch", "roll"}; + float values[3]; + int i = 0; + for (auto itr = inputValue.MemberBegin(); itr != inputValue.MemberEnd(); ++i, ++itr) + { + ScopedContextPath subPath(context, names[i]); + JSR::Result intermediate = floatSerializer->Load(values + i, azrtti_typeid(), itr->value, context); + if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed) + { + return intermediate; + } + } + + auto eulerAnglesDegrees = Vector3::CreateFromFloat3(values); + reinterpret_cast(outputValue)->SetFromEulerDegrees(eulerAnglesDegrees); + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read quaternion."); + } + + return JsonMathVectorSerializerInternal::Load(outputValue, outputValueTypeId, inputValue, context); + } + + JsonSerializationResult::Result JsonQuaternionSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, + const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) + { + return JsonMathVectorSerializerInternal::Store(outputValue, inputValue, defaultValue, valueTypeId, context); + } } diff --git a/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h b/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h index 9c401d2aff..9c2606b932 100644 --- a/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h +++ b/Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h @@ -51,4 +51,16 @@ namespace AZ JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) override; }; + + class JsonQuaternionSerializer + : public BaseJsonSerializer + { + public: + AZ_RTTI(JsonQuaternionSerializer, "{18604375-3606-49AC-B366-0F6DF9149FF3}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) override; + JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, + const Uuid& valueTypeId, JsonSerializerContext& context) override; + }; } diff --git a/Code/Framework/AzCore/AzCore/Settings/CommandLine.cpp b/Code/Framework/AzCore/AzCore/Settings/CommandLine.cpp index c7a5476340..6549992dc0 100644 --- a/Code/Framework/AzCore/AzCore/Settings/CommandLine.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/CommandLine.cpp @@ -10,11 +10,11 @@ * */ -#include +#include +#include #include +#include #include -#include -#include namespace AZ { @@ -29,6 +29,21 @@ namespace AZ return lowerStr; } + + AZStd::string_view UnquoteArgument(AZStd::string_view arg) + { + if (arg.size() < 2) + { + return arg; + } + + return arg.front() == '"' && arg.back() == '"' ? AZStd::string_view{ arg.begin() + 1, arg.end() - 1 } : arg; + } + + AZStd::string QuoteArgument(AZStd::string_view arg) + { + return !arg.empty() ? AZStd::string::format(R"("%.*s")", aznumeric_cast(arg.size()), arg.data()) : AZStd::string{ arg }; + } } CommandLine::CommandLine() @@ -41,15 +56,62 @@ namespace AZ { } - void CommandLine::AddArgument(AZStd::string currentArg, AZStd::string& currentSwitch) + void CommandLine::ParseOptionArgument(AZStd::string_view newOption, AZStd::string_view newValue, + CommandArgument* inProgressArgument) + { + // Allow argument values wrapped in quotes at both ends to become the value within the quotes + AZStd::string_view unquotedValue = UnquoteArgument(newValue); + if (unquotedValue != newValue) + { + // Update the inProgressArgument before adding new arguments + if(inProgressArgument) + { + inProgressArgument->m_value = unquotedValue; + // Set the inProgressArgument to nullptr to indicate that the inProgressArgument has been fulfilled + inProgressArgument = nullptr; + } + else + { + m_allValues.push_back({ newOption, unquotedValue }); + } + } + else + { + AZStd::vector tokens; + auto splitArgument = [&tokens](AZStd::string_view token) + { + tokens.emplace_back(AZ::StringFunc::StripEnds(token)); + }; + AZ::StringFunc::TokenizeVisitor(newValue, splitArgument, ",;"); + + // we do it this way because you are allowed to do odd things like + // -root=abc -root=hij,klm -root whee -root fun;days + // and roots value should be { abc, hij, klm, whee, fun, days } + for (AZStd::string_view optionValue : tokens) + { + if (inProgressArgument) + { + inProgressArgument->m_value = optionValue; + // Set the inProgressArgument to nullptr to indicate that the inProgressArgument has been fulfilled + inProgressArgument = nullptr; + } + else + { + m_allValues.push_back({ newOption, optionValue }); + } + } + } + } + + void CommandLine::AddArgument(AZStd::string_view currentArg, AZStd::string& currentSwitch) { - StringFunc::Strip(currentArg, " ", false, true, true); + currentArg = AZ::StringFunc::StripEnds(currentArg); if (!currentArg.empty()) { - if (AZStd::string_view(currentArg.begin(), currentArg.begin() + 1).find_first_of(m_commandLineOptionPrefix) != AZStd::string_view::npos) + if (m_commandLineOptionPrefix.contains(currentArg.front())) { - // its possible that its a key-value-pair like /blah=whatever - // we support this too, for compatibilty. + // its possible that its a key-value-pair like -blah=whatever + // we support this too, for compatibility. currentArg = currentArg.substr(1); if (currentArg[0] == '-') // for -- extra @@ -57,93 +119,41 @@ namespace AZ currentArg = currentArg.substr(1); } - AZStd::size_t foundPos = StringFunc::Find(currentArg.c_str(), '='); + AZStd::size_t foundPos = AZ::StringFunc::Find(currentArg, "="); if (foundPos != AZStd::string::npos) { - // Allow argument values wrapped in quotes at both ends to become the value within the quotes - if (currentArg.length() > (foundPos + 2) && currentArg[foundPos + 1] == '"' && currentArg[currentArg.length() - 1] == '"') - { - AZStd::string argName = currentArg.substr(0, foundPos); - argName = ToLower(argName); - StringFunc::Strip(argName, " ", false, true, true); - m_switches[argName].emplace_back(currentArg.substr(foundPos + 2, currentArg.length() - (foundPos + 2) - 1)); - currentSwitch.clear(); - return; - } - - // its in '=' format - AZStd::vector tokens; - StringFunc::Tokenize(currentArg.substr(foundPos + 1).c_str(), tokens, ",;"); - currentArg.resize(foundPos); - currentArg = ToLower(currentArg); - StringFunc::Strip(currentArg, " ", false, true, true); - m_switches.insert_key(currentArg); // returns pair - // we do it this way because you are allowed to do odd things like - // /root=abc /root=hij,klm /root whee /root fun;days - // and roots value should be { abc, hij, klm, whee, fun, days } - for (AZStd::string& switchValue : tokens) - { - StringFunc::Strip(switchValue, " ", false, true, true); - m_switches[currentArg].push_back(switchValue); - } + AZStd::string_view argumentView{ currentArg }; + AZStd::string_view option = AZ::StringFunc::StripEnds(argumentView.substr(0, foundPos)); + AZStd::string_view value = AZ::StringFunc::StripEnds(argumentView.substr(foundPos + 1)); + ParseOptionArgument(ToLower(option), value, nullptr); currentSwitch.clear(); } else { - // its in this format /switchName switchvalue + // its in this format -switchName switchvalue // (no equals) - currentSwitch = currentArg; - currentSwitch = ToLower(currentSwitch); - m_switches.insert_key(currentSwitch); + currentSwitch = ToLower(currentArg); + m_allValues.push_back({ currentSwitch, "" }); } } else { if (currentSwitch.empty()) { - m_miscValues.push_back(currentArg); + m_allValues.push_back({ "", UnquoteArgument(currentArg) }); } else { - // Allow argument values wrapped in quotes at both ends to become the value within the quotes - if (currentArg[0] == '"' && currentArg.length() >= 2 && currentArg[currentArg.length() - 1] == '"') - { - m_switches[currentSwitch].emplace_back(currentArg.substr(1, currentArg.length() - 2)); - currentSwitch.clear(); - return; - } - - AZStd::vector tokens; - StringFunc::Tokenize(currentArg.c_str(), tokens, ",;"); - for (AZStd::string& switchValue : tokens) - { - StringFunc::Strip(switchValue, " ", false, true, true); - m_switches[currentSwitch].push_back(switchValue); - } - + ParseOptionArgument(currentSwitch, currentArg, &m_allValues.back()); + currentSwitch.clear(); } - - currentSwitch.clear(); } } } - void CommandLine::Parse(const ParamContainer& commandLine) - { - m_switches.clear(); - m_miscValues.clear(); - - AZStd::string currentSwitch; - for (int i = 1; i < commandLine.size(); ++i) - { - AddArgument(commandLine[i], currentSwitch); - } - } - void CommandLine::Parse(int argc, char** argv) { - m_switches.clear(); - m_miscValues.clear(); + m_allValues.clear(); AZStd::string currentSwitch; // Start on 1 because 0 is the executable name @@ -157,91 +167,145 @@ namespace AZ } } - void CommandLine::Dump(ParamContainer& commandLineDumpOutput) + void CommandLine::Parse(const ParamContainer& commandLine) { - // Push back an empty argument as the Parse function always skips parsing the first argument - commandLineDumpOutput.emplace_back(AZStd::string()); - for (const AZStd::string& miscValue : m_miscValues) + m_allValues.clear(); + + // This version of Parse does not skip over 0th index + AZStd::string currentSwitch; + for (int i = 0; i < commandLine.size(); ++i) { - commandLineDumpOutput.push_back(miscValue); + AddArgument(commandLine[i], currentSwitch); } + } + + void CommandLine::Dump(ParamContainer& commandLineDumpOutput) const + { + AZ_Error("CommandLine", !m_commandLineOptionPrefix.empty(), + "Cannot dump command line switches from a command line with an empty option prefix"); - if (!m_commandLineOptionPrefix.empty()) + for (const CommandArgument& argument : m_allValues) { - for (const auto& [switchKey, switchValues] : m_switches) + if (!argument.m_option.empty()) { - AZStd::string prefixSwitchKey = m_commandLineOptionPrefix.front() + switchKey; - if (switchValues.empty()) - { - // There are no value for the switch so just push it back of the command line dump output - commandLineDumpOutput.emplace_back(prefixSwitchKey); - } - else - { - for (const auto& switchValue : switchValues) - { - commandLineDumpOutput.emplace_back(prefixSwitchKey); - commandLineDumpOutput.emplace_back(switchValue); - } - } + commandLineDumpOutput.emplace_back(m_commandLineOptionPrefix.front() + argument.m_option); + } + if (!argument.m_value.empty()) + { + commandLineDumpOutput.emplace_back(QuoteArgument(argument.m_value)); } - } - else - { - AZ_Error("CommandLine", false, "Cannot dump command line switches from a command line with an empty option prefix"); } } bool CommandLine::HasSwitch(AZStd::string_view switchName) const { - return m_switches.find(ToLower(switchName)) != m_switches.end(); + auto commandArgumentIter = AZStd::find_if(m_allValues.begin(), m_allValues.end(), + [optionName = ToLower(switchName)](const CommandArgument& argument) { return argument.m_option == optionName; }); + return commandArgumentIter != m_allValues.end(); } AZStd::size_t CommandLine::GetNumSwitchValues(AZStd::string_view switchName) const { - ParamMap::const_iterator switchFound = m_switches.find(ToLower(switchName)); - if (switchFound == m_switches.end()) - { - return 0; - } - - return switchFound->second.size(); + return AZStd::count_if(m_allValues.begin(), m_allValues.end(), + [optionName = ToLower(switchName)](const CommandArgument& argument) { return argument.m_option == optionName; }); } const AZStd::string& CommandLine::GetSwitchValue(AZStd::string_view switchName, AZStd::size_t index) const { - ParamMap::const_iterator switchFound = m_switches.find(ToLower(switchName)); - if (switchFound == m_switches.end()) + AZStd::string optionName = ToLower(switchName); + size_t currentPosIndex{}; + auto findArgumentAt = [&optionName, index, ¤tPosIndex](const CommandArgument& argument) { - return m_emptyValue; - } + if (argument.m_option == optionName) + { + return currentPosIndex++ == index; + } - AZ_Assert(index < switchFound->second.size(), "Invalid Command line switch lookup"); - if (index >= switchFound->second.size()) + return false; + }; + auto commandArgumentIter = AZStd::find_if(m_allValues.begin(), m_allValues.end(), findArgumentAt); + if (!optionName.empty()) + { + AZ_Assert(index < currentPosIndex, R"(Invalid Command line optional argument lookup of "%s" at index %zu)", + optionName.c_str(), index); + } + else + { + AZ_Assert(index < currentPosIndex, R"(Invalid Command line positional argument lookup at index %zu)", index); + } + if (commandArgumentIter == m_allValues.end()) { return m_emptyValue; } - - return switchFound->second.at(index); + return commandArgumentIter->m_value; } AZStd::size_t CommandLine::GetNumMiscValues() const { - return m_miscValues.size(); + return GetNumSwitchValues(""); } const AZStd::string& CommandLine::GetMiscValue(AZStd::size_t index) const { - AZ_Assert(index < m_miscValues.size(), "Invalid Command line lookup"); - if (index >= m_miscValues.size()) - { - return m_emptyValue; - } - return m_miscValues[index]; + // Positional arguments option value is an empty string + return GetSwitchValue("", index); } - const CommandLine::ParamMap& CommandLine::GetSwitchList() const + [[nodiscard]] bool CommandLine::empty() const + { + return m_allValues.empty(); + } + + auto CommandLine::size() const -> ArgumentVector::size_type + { + return m_allValues.size(); + } + auto CommandLine::begin() -> ArgumentVector::iterator + { + return m_allValues.begin(); + } + auto CommandLine::begin() const -> ArgumentVector::const_iterator + { + return m_allValues.begin(); + } + auto CommandLine::cbegin() const -> ArgumentVector::const_iterator + { + return m_allValues.cbegin(); + } + auto CommandLine::end() -> ArgumentVector::iterator + { + return m_allValues.end(); + } + auto CommandLine::end() const -> ArgumentVector::const_iterator + { + return m_allValues.end(); + } + auto CommandLine::cend() const -> ArgumentVector::const_iterator + { + return m_allValues.cend(); + } + auto CommandLine::rbegin() -> ArgumentVector::reverse_iterator + { + return m_allValues.rbegin(); + } + auto CommandLine::rbegin() const -> ArgumentVector::const_reverse_iterator + { + return m_allValues.rbegin(); + } + auto CommandLine::crbegin() const -> ArgumentVector::const_reverse_iterator + { + return m_allValues.crbegin(); + } + auto CommandLine::rend() -> ArgumentVector::reverse_iterator + { + return m_allValues.rend(); + } + auto CommandLine::rend() const -> ArgumentVector::const_reverse_iterator + { + return m_allValues.rend(); + } + auto CommandLine::crend() const -> ArgumentVector::const_reverse_iterator { - return m_switches; + return m_allValues.crend(); } } diff --git a/Code/Framework/AzCore/AzCore/Settings/CommandLine.h b/Code/Framework/AzCore/AzCore/Settings/CommandLine.h index 860e05f2b2..24e4571cd2 100644 --- a/Code/Framework/AzCore/AzCore/Settings/CommandLine.h +++ b/Code/Framework/AzCore/AzCore/Settings/CommandLine.h @@ -36,36 +36,47 @@ namespace AZ public: AZ_CLASS_ALLOCATOR(CommandLine, AZ::SystemAllocator, 0); + using ParamContainer = AZStd::vector; + + struct CommandArgument + { + AZStd::string m_option; + AZStd::string m_value; + }; + using ArgumentVector = AZStd::vector; + CommandLine(); /** * Initializes a CommandLine instance which uses the provided commandLineOptionPreix for parsing switches */ CommandLine(AZStd::string_view commandLineOptionPrefix); - - using ParamContainer = AZStd::vector; - using ParamMap = AZStd::unordered_map; /** * Construct a command line parser. * It will load parameters from the given ARGC/ARGV parameters instead of process command line. + * Skips over the first parameter as it assumes it is the executable name */ void Parse(int argc, char** argv); + /** + * Parses each element of the command line as parameter. + * Unlike the ARGC/ARGV version above, this function doesn't skip over the first parameter + * It allows for round trip conversion with the Dump() method + */ void Parse(const ParamContainer& commandLine); /** * Will dump command line parameters from the CommandLine in a format such that switches * are prefixed with the option prefix followed by their value(s) which are comma separated - * The result of this function can be supplied to Parse() to re-create an eqiuvlanet command line obect + * The result of this function can be supplied to Parse() to re-create an equivalent command line object * Ex, If the command line has the current list of parsed miscellaneous values and switches of * MiscValue = ["Foo", "Bat"] * Switches = ["GameFolder" : [], "RemoteIp" : ["10.0.0.1"], "ScanFolders" : ["\a\b\c", "\d\e\f"] * CommandLineOptionPrefix = "-/" * * Then the resulting dumped value would be - * Dump = ["", "Foo", "Bat", "-GameFolder", "-RemoteIp", "10.0.0.1", "-ScanFolders", "\a\b\c", "-ScanFolders", "\d\e\f"] - * NOTE: The first parameter is always empty string as the Parse function skips over it + * Dump = ["Foo", "Bat", "-GameFolder", "-RemoteIp", "10.0.0.1", "-ScanFolders", "\a\b\c", "-ScanFolders", "\d\e\f"] */ - void Dump(ParamContainer& commandLineDumpOutput); + void Dump(ParamContainer& commandLineDumpOutput) const; /** * Determines whether a switch is present in the command line @@ -97,16 +108,28 @@ namespace AZ */ const AZStd::string& GetMiscValue(AZStd::size_t index) const; - /* - * Return the list of parsed switches - */ - const ParamMap& GetSwitchList() const; + + // Range accessors + [[nodiscard]] bool empty() const; + auto size() const -> ArgumentVector::size_type; + auto begin() -> ArgumentVector::iterator; + auto begin() const -> ArgumentVector::const_iterator; + auto cbegin() const -> ArgumentVector::const_iterator; + auto end() -> ArgumentVector::iterator; + auto end() const -> ArgumentVector::const_iterator; + auto cend() const -> ArgumentVector::const_iterator; + auto rbegin() -> ArgumentVector::reverse_iterator; + auto rbegin() const -> ArgumentVector::const_reverse_iterator; + auto crbegin() const -> ArgumentVector::const_reverse_iterator; + auto rend() -> ArgumentVector::reverse_iterator; + auto rend() const -> ArgumentVector::const_reverse_iterator; + auto crend() const -> ArgumentVector::const_reverse_iterator; private: - void AddArgument(AZStd::string currentArg, AZStd::string& currentSwitch); + void AddArgument(AZStd::string_view currentArg, AZStd::string& currentSwitch); + void ParseOptionArgument(AZStd::string_view newOption, AZStd::string_view newValue, CommandArgument* inProgressArgument); - ParamMap m_switches; - ParamContainer m_miscValues; + ArgumentVector m_allValues; AZStd::string m_emptyValue; inline static constexpr size_t MaxCommandOptionPrefixes = 8; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp index d69392889f..9ea76817af 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp @@ -173,7 +173,15 @@ namespace AZ path.remove_prefix(1); // Remove the leading slash as the StackedString will add this back in. jsonPath.Push(path); } - Visit(visitor, jsonPath, "", *value); + // Extract the last token of the JSON pointer to use as the valueName + AZStd::string_view valueName; + size_t pointerTokenCount = pointer.GetTokenCount(); + if (pointerTokenCount > 0) + { + const rapidjson::Pointer::Token& lastToken = pointer.GetTokens()[pointerTokenCount - 1]; + valueName = AZStd::string_view(lastToken.name, lastToken.length); + } + Visit(visitor, jsonPath, valueName, *value); return true; } } diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 440d404526..f9fd606714 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -41,68 +41,197 @@ namespace AZ::Internal return value; } -} -namespace AZ::SettingsRegistryMergeUtils -{ - AZ::IO::FixedMaxPath GetAppRoot(SettingsRegistryInterface* settingsRegistry) + AZ::SettingsRegistryInterface::FixedValueString GetEngineMonikerForProject( + SettingsRegistryInterface& settingsRegistry, const AZ::IO::FixedMaxPath& projectPath) { - constexpr size_t MaxAppRootPathsToScan = 16; - AZStd::fixed_vector appRootScanPaths; - - // Check the commandLine for --app-root parameter - // If it exist use that instead - auto appRootOverrideKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/app-root", AZ::SettingsRegistryMergeUtils::CommandLineSwitchRootKey); - if (settingsRegistry) + // projectPath needs to be an absolute path here. + using namespace AZ::SettingsRegistryMergeUtils; + bool projectJsonMerged = false; + auto projectJsonPath = projectPath / "project.json"; + if (AZ::IO::SystemFile::Exists(projectJsonPath.c_str())) { - AZ::IO::FixedMaxPath appRootOverridePath; - if (settingsRegistry->Get(appRootOverridePath.Native(), appRootOverrideKey)) - { - return appRootOverridePath; - } + projectJsonMerged = settingsRegistry.MergeSettingsFile( + projectJsonPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ProjectSettingsRootKey); } - AZStd::optional> appRootPath = Utils::GetDefaultAppRootPath(); - if (appRootPath.has_value()) + AZ::SettingsRegistryInterface::FixedValueString engineMoniker; + if (projectJsonMerged) { - appRootScanPaths.push_back(*appRootPath); + // In project.json look for the "engine" key. + auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine", ProjectSettingsRootKey); + settingsRegistry.Get(engineMoniker, engineMonikerKey); } - AZStd::fixed_string executableDir; - AZ::Utils::ExecutablePathResult pathResult = Utils::GetExecutableDirectory(executableDir.data(), executableDir.capacity()); - if (pathResult == Utils::ExecutablePathResult::Success) + + return engineMoniker; + } + + AZ::IO::FixedMaxPath ReconcileEngineRootFromProjectPath(SettingsRegistryInterface& settingsRegistry, const AZ::IO::FixedMaxPath& projectPath) + { + // Find the engine root via the engine manifest file and project.json + // Locate the engine manifest file and merge it to settings registry. + // Visit over the engine paths list and merge the engine.json files to settings registry. + // Merge project.json to settings registry. That will give us an "engine" key. + // When we find a match for "engine_name" value against the "engine" value from before, we can stop and use that engine root. + // Finally set the BootstrapSettingsRootKey/engine_path setting so that subsequent calls to GetEngineRoot will use that + // and avoid all this logic. + + using namespace AZ::SettingsRegistryMergeUtils; + + AZ::IO::FixedMaxPath engineRoot; + if (auto engineManifestPath = AZ::Utils::GetEngineManifestPath(); !engineManifestPath.empty()) { - // Update the size value of the executable directory fixed string to correctly be the length of the null-terminated string stored within it - executableDir.resize_no_construct(AZStd::char_traits::length(executableDir.data())); - if (auto foundIt = AZStd::find(appRootScanPaths.begin(), appRootScanPaths.end(), executableDir); - foundIt == appRootScanPaths.end()) + bool manifestLoaded{false}; + + if (AZ::IO::SystemFile::Exists(engineManifestPath.c_str())) { - appRootScanPaths.push_back(executableDir); + manifestLoaded = settingsRegistry.MergeSettingsFile( + engineManifestPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineManifestRootKey); } - } - for (AZStd::string_view appRootScanPath : appRootScanPaths) - { - AZ::IO::FixedMaxPath appRootCandidate{ appRootScanPath }; - // Search for the application root - bool rootPathVisited = false; - do + struct EngineInfo + { + AZ::IO::FixedMaxPath m_path; + AZ::SettingsRegistryInterface::FixedValueString m_moniker; + }; + + struct EnginePathsVisitor : public AZ::SettingsRegistryInterface::Visitor { - if (AZ::IO::SystemFile::Exists((appRootCandidate / "bootstrap.cfg").c_str())) + void Visit( + [[maybe_unused]] AZStd::string_view path, [[maybe_unused]] AZStd::string_view valueName, + [[maybe_unused]] AZ::SettingsRegistryInterface::Type type, AZStd::string_view value) override { - return appRootCandidate; + m_enginePaths.emplace_back(EngineInfo{AZ::IO::FixedMaxPath{value}.LexicallyNormal(), {}}); } - // Validate that the parent directory isn't itself, that would imply - // that it is the root path - AZ::IO::PathView parentPath = appRootCandidate.ParentPath(); - rootPathVisited = appRootCandidate == parentPath; - // Recurse upwards one directory - appRootCandidate = AZStd::move(parentPath); + AZStd::vector m_enginePaths{}; + }; + + EnginePathsVisitor pathVisitor; + if (manifestLoaded) + { + auto enginePathsKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engines", EngineManifestRootKey); + settingsRegistry.Visit(pathVisitor, enginePathsKey); + } + + const auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine_name", EngineSettingsRootKey); + + for (EngineInfo& engineInfo : pathVisitor.m_enginePaths) + { + AZ::IO::FixedMaxPath engineSettingsPath{engineInfo.m_path}; + engineSettingsPath /= "engine.json"; + + if (AZ::IO::SystemFile::Exists(engineSettingsPath.c_str())) + { + if (settingsRegistry.MergeSettingsFile( + engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineSettingsRootKey)) + { + settingsRegistry.Get(engineInfo.m_moniker, engineMonikerKey); + } + } + + auto engineMoniker = Internal::GetEngineMonikerForProject(settingsRegistry, engineInfo.m_path / projectPath); + if (!engineMoniker.empty() && engineMoniker == engineInfo.m_moniker) + { + engineRoot = engineInfo.m_path; + break; + } + } + } + + return engineRoot; + } + + AZ::IO::FixedMaxPath ScanUpRootLocator(AZStd::string_view rootFileToLocate) + { + + AZStd::fixed_string executableDir; + if (Utils::GetExecutableDirectory(executableDir.data(), executableDir.capacity()) == Utils::ExecutablePathResult::Success) + { + // Update the size value of the executable directory fixed string to correctly be the length of the null-terminated string + // stored within it + executableDir.resize_no_construct(AZStd::char_traits::length(executableDir.data())); + } + + AZ::IO::FixedMaxPath engineRootCandidate{ executableDir }; + + bool rootPathVisited = false; + do + { + if (AZ::IO::SystemFile::Exists((engineRootCandidate / rootFileToLocate).c_str())) + { + return engineRootCandidate; + } - } while (!rootPathVisited); // Note for posix filesystems the parent directory of '/' is '/' and for windows // the parent directory of 'C:\\' is 'C:\\' + + // Validate that the parent directory isn't itself, that would imply + // that it is the filesystem root path + AZ::IO::PathView parentPath = engineRootCandidate.ParentPath(); + rootPathVisited = (engineRootCandidate == parentPath); + // Recurse upwards one directory + engineRootCandidate = AZStd::move(parentPath); + + } while (!rootPathVisited); + + return {}; + } + +} // namespace AZ::Internal + +namespace AZ::SettingsRegistryMergeUtils +{ + AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry) + { + AZ::IO::FixedMaxPath engineRoot; + + // This is the 'external' engine root key, as in passed from command-line or .setreg files. + auto engineRootKey = SettingsRegistryInterface::FixedValueString::format("%s/engine_path", BootstrapSettingsRootKey); + if (settingsRegistry.Get(engineRoot.Native(), engineRootKey); !engineRoot.empty()) + { + return engineRoot; } + + // We can scan up from exe directory to find engine.json, use that for engine root if it exists. + if (engineRoot = Internal::ScanUpRootLocator("engine.json"); !engineRoot.empty()) + { + settingsRegistry.Set(engineRootKey, engineRoot.c_str()); + return engineRoot; + } + + AZ::IO::FixedMaxPath projectRoot = FindProjectRoot(settingsRegistry); + if (projectRoot.empty()) + { + return {}; + } + + // Use the project.json and engine manifest to locate the engine root. + if (engineRoot = Internal::ReconcileEngineRootFromProjectPath(settingsRegistry, projectRoot); !engineRoot.empty()) + { + settingsRegistry.Set(engineRootKey, engineRoot.c_str()); + return engineRoot; + } + + return {}; + } + + AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry) + { + AZ::IO::FixedMaxPath projectRoot; + // This is the 'external' project root key, as in passed from command-line or .setreg files. + auto projectRootKey = SettingsRegistryInterface::FixedValueString::format("%s/project_path", BootstrapSettingsRootKey); + if (settingsRegistry.Get(projectRoot.Native(), projectRootKey)) + { + return projectRoot; + } + + if (projectRoot = Internal::ScanUpRootLocator("project.json"); !projectRoot.empty()) + { + settingsRegistry.Set(projectRootKey, projectRoot.c_str()); + return projectRoot; + } + return {}; } @@ -111,9 +240,9 @@ namespace AZ::SettingsRegistryMergeUtils constexpr AZStd::string_view commentPrefixes = ";#"; for (char commentPrefix : commentPrefixes) { - if (line.starts_with(commentPrefix)) + if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos) { - return {}; + return line.substr(0, commentOffset); } } @@ -123,7 +252,7 @@ namespace AZ::SettingsRegistryMergeUtils AZStd::string_view ConfigParserSettings::DefaultSectionHeaderFilter(AZStd::string_view line) { AZStd::string_view sectionName; - constexpr char sectionHeaderStart= '['; + constexpr char sectionHeaderStart = '['; constexpr char sectionHeaderEnd = ']'; if (line.starts_with(sectionHeaderStart) && line.ends_with(sectionHeaderEnd)) { @@ -184,7 +313,7 @@ namespace AZ::SettingsRegistryMergeUtils void QuerySpecializationsFromRegistry(SettingsRegistryInterface& registry, SettingsRegistryInterface::Specializations& specializations) { - // Append any specializations stored in the registry + // Append any specializations stored in the registry struct SpecializationsVisitor : AZ::SettingsRegistryInterface::Visitor { @@ -222,7 +351,7 @@ namespace AZ::SettingsRegistryMergeUtils bool MergeSettingsToRegistry_ConfigFile(SettingsRegistryInterface& registry, AZStd::string_view filePath, const ConfigParserSettings& configParserSettings) { - auto configPath = GetAppRoot(®istry) / filePath; + auto configPath = FindEngineRoot(registry) / filePath; IO::SystemFile configFile; if (!configFile.Open(configPath.c_str(), IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY)) { @@ -348,9 +477,13 @@ namespace AZ::SettingsRegistryMergeUtils ConfigParserSettings parserSettings; parserSettings.m_commentPrefixFunc = [](AZStd::string_view line) -> AZStd::string_view { - if (line.starts_with("--") || line.starts_with(';') || line.starts_with('#')) + constexpr AZStd::string_view commentPrefixes[]{ "--", ";","#" }; + for (AZStd::string_view commentPrefix : commentPrefixes) { - return {}; + if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos) + { + return line.substr(0, commentOffset); + } } return line; }; @@ -365,71 +498,104 @@ namespace AZ::SettingsRegistryMergeUtils registry.Set(FilePathKey_BinaryFolder, path.LexicallyNormal().Native()); // Engine root folder - corresponds to the @engroot@ and @devroot@ aliases - AZ::IO::FixedMaxPath appRoot = GetAppRoot(®istry); - registry.Set(FilePathKey_EngineRootFolder, appRoot.LexicallyNormal().Native()); + AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry); + registry.Set(FilePathKey_EngineRootFolder, engineRoot.LexicallyNormal().Native()); constexpr size_t bufferSize = 64; - auto buffer = AZStd::fixed_string::format("%s/sys_game_folder", BootstrapSettingsRootKey); + auto buffer = AZStd::fixed_string::format("%s/project_path", BootstrapSettingsRootKey); - AZStd::string_view projectPath(buffer); + AZ::SettingsRegistryInterface::FixedValueString projectPathKey(buffer); SettingsRegistryInterface::FixedValueString projectPathValue; - if (registry.Get(projectPathValue, projectPath)) + if (registry.Get(projectPathValue, projectPathKey)) { // Cache folder // Get the name of the asset platform assigned by the bootstrap. First check for platform version such as "windows_assets" - // and if that's missing just get "asset". + // and if that's missing just get "assets". constexpr char platformName[] = AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER; SettingsRegistryInterface::FixedValueString assetPlatform; buffer = AZStd::fixed_string::format("%s/%s_assets", BootstrapSettingsRootKey, platformName); - AZStd::string_view assetPlatformatPath(buffer); - if (!registry.Get(assetPlatform, assetPlatformatPath)) + AZStd::string_view assetPlatformKey(buffer); + if (!registry.Get(assetPlatform, assetPlatformKey)) { buffer = AZStd::fixed_string::format("%s/assets", BootstrapSettingsRootKey); - assetPlatformatPath = AZStd::string_view(buffer); - if (!registry.Get(assetPlatform, assetPlatformatPath)) - { - return; - } + assetPlatformKey = AZStd::string_view(buffer); + registry.Get(assetPlatform, assetPlatformKey); } - // Source game folder - corresponds to the @devassets@ alias - path = appRoot / projectPathValue; + // Project path - corresponds to the @devassets@ alias + // NOTE: Here we append to engineRoot, but if projectPathValue is absolute then engineRoot is discarded. + path = engineRoot / projectPathValue; + AZ_Warning("SettingsRegistryMergeUtils", AZ::IO::SystemFile::Exists(path.c_str()), - R"(Project Path "%s" does not exist. Is the "sys_game_folder" entry set to valid project folder?)" - , path.c_str()); - registry.Set(FilePathKey_SourceGameFolder, path.LexicallyNormal().Native()); - - // Source game name - The filename of the project directory and the name of the project - registry.Set(FilePathKey_SourceGameName, path.Filename().Native()); - - // Cache root folder - corresponds to the @root@ alias -#if AZ_TRAIT_USE_ASSET_CACHE_FOLDER - path = appRoot / "Cache" / projectPathValue / assetPlatform; -#else - // Use the Engine Root/App Root as the Asset root directory in this case - path = appRoot; -#endif - registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native()); - - // check for a default write storage path, fall back to the cache root if not + R"(Project path "%s" does not exist. Is the "%.*s" registry setting set to valid absolute path?)" + , path.c_str(), aznumeric_cast(projectPathKey.size()), projectPathKey.data()); + + AZ::IO::FixedMaxPath normalizedProjectPath = path.LexicallyNormal(); + registry.Set(FilePathKey_ProjectPath, normalizedProjectPath.Native()); + + // Add an alias to the project "user" directory + AZ::IO::FixedMaxPath projectUserPath = (normalizedProjectPath / "user").LexicallyNormal(); + registry.Set(FilePathKey_ProjectUserPath, projectUserPath.Native()); + // check for a default write storage path, fall back to the project's user/ directory if not AZStd::optional devWriteStorage = Utils::GetDevWriteStoragePath(); - registry.Set(FilePathKey_DevWriteStorage, - devWriteStorage.has_value() ? - devWriteStorage.value() : - path.LexicallyNormal().Native()); - - // Cache game folder - corresponds to the @assets@ alias - AZStd::to_lower(projectPathValue.begin(), projectPathValue.end()); - path /= projectPathValue; - registry.Set(FilePathKey_CacheGameFolder, path.LexicallyNormal().Native()); + registry.Set(FilePathKey_DevWriteStorage, devWriteStorage.has_value() + ? devWriteStorage.value() + : projectUserPath.Native()); + + // Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name. + auto projectNameKey = + AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) + + "/project_name"; + + AZ::SettingsRegistryInterface::FixedValueString projectName; + if (!registry.Get(projectName, projectNameKey)) + { + projectName = path.Filename().Native(); + registry.Set(projectNameKey, projectName); + } + + // Cache folders - sets up various paths in registry for the cache. + // Make sure the asset platform is set before setting these cache paths. + if (!assetPlatform.empty()) + { + // Cache: project root - no corresponding fileIO alias, but this is where the asset database lives. + // A registry override is accepted using the "project_cache_path" key. + buffer = AZStd::fixed_string::format("%s/project_cache_path", BootstrapSettingsRootKey); + AZStd::string_view projectCacheRootOverrideKey(buffer); + // Clear path to make sure that the `project_cache_path` value isn't concatenated to the project path + path.clear(); + if (registry.Get(path.Native(), projectCacheRootOverrideKey)) + { + registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native()); + path /= assetPlatform; + registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native()); + } + else + { + // Cache: root - same as the @root@ alias, this is the starting path for cache files. + path = normalizedProjectPath / "Cache"; + registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native()); + path /= assetPlatform; + registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native()); + } + } } else { AZ_TracePrintf("SettingsRegistryMergeUtils", - R"(Current Project game folder "%.*s" isn't set in the Settings Registry. Project-related filepaths will not be set)" "\n", - aznumeric_cast(projectPath.size()), projectPath.data()); + R"(Project path isn't set in the Settings Registry at "%.*s". Project-related filepaths will not be set)" "\n", + aznumeric_cast(projectPathKey.size()), projectPathKey.data()); } + +#if !AZ_TRAIT_USE_ASSET_CACHE_FOLDER + // Setup the cache and user paths for Platforms where the Asset Cache Folder isn't used + path = engineRoot; + registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native()); + registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native()); + registry.Set(FilePathKey_DevWriteStorage, path.LexicallyNormal().Native()); + registry.Set(FilePathKey_ProjectUserPath, (path / "user").LexicallyNormal().Native()); +#endif // AZ_TRAIT_USE_ASSET_CACHE_FOLDER } void MergeSettingsToRegistry_TargetBuildDependencyRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, @@ -535,7 +701,7 @@ namespace AZ::SettingsRegistryMergeUtils const SettingsRegistryInterface::Specializations& specializations, AZStd::vector* scratchBuffer) { AZ::SettingsRegistryInterface::FixedValueString sourceGamePath; - if (registry.Get(sourceGamePath, FilePathKey_SourceGameFolder)) + if (registry.Get(sourceGamePath, FilePathKey_ProjectPath)) { AZ::IO::FixedMaxPath mergePath{ sourceGamePath }; mergePath /= SettingsRegistryInterface::RegistryFolder; @@ -543,26 +709,41 @@ namespace AZ::SettingsRegistryMergeUtils } } - void MergeSettingsToRegistry_DevRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, + void MergeSettingsToRegistry_UserRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, const SettingsRegistryInterface::Specializations& specializations, AZStd::vector* scratchBuffer) { // Unlike other paths, the path can't be overwritten by the dev settings because that would create a circular dependency. - auto mergePath = GetAppRoot(®istry); - mergePath /= SettingsRegistryInterface::DevUserRegistryFolder; - registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer); + AZ::IO::FixedMaxPath projectUserPath; + if (registry.Get(projectUserPath.Native(), FilePathKey_ProjectPath)) + { + projectUserPath /= SettingsRegistryInterface::DevUserRegistryFolder; + registry.MergeSettingsFolder(projectUserPath.Native(), specializations, platform, "", scratchBuffer); + } } void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine, bool executeCommands) { - const size_t regsetSwitchValues = commandLine.GetNumSwitchValues("regset"); - for (size_t regsetIndex = 0; regsetIndex < regsetSwitchValues; ++regsetIndex) + // Iterate over all the command line options in order to parse the --regset and --regremove + // arguments in the order they were supplied + for (const CommandLine::CommandArgument& commandArgument : commandLine) { - AZStd::string_view regsetValue = commandLine.GetSwitchValue("regset", regsetIndex); - if (!registry.MergeCommandLineArgument(regsetValue, AZStd::string_view{})) + if (commandArgument.m_option == "regset") { - AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to parse argument for --regset with value of %.*s.", - aznumeric_cast(regsetValue.size()), regsetValue.data()); - continue; + if (!registry.MergeCommandLineArgument(commandArgument.m_value, AZStd::string_view{})) + { + AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to parse argument for --regset with value of %s.", + commandArgument.m_value.c_str()); + continue; + } + } + if (commandArgument.m_option == "regremove") + { + if (!registry.Remove(commandArgument.m_value)) + { + AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to remove value at JSON Pointer %s for --regremove.", + commandArgument.m_value.data()); + continue; + } } } @@ -585,16 +766,8 @@ namespace AZ::SettingsRegistryMergeUtils DumpSettingsRegistryToStream(registry, regdumpValue, outputStream, dumperSettings); } - const size_t regdumpallSwitchValues = commandLine.GetNumSwitchValues("regdumpall"); - if (regdumpallSwitchValues > 0) + if (commandLine.HasSwitch("regdumpall")) { - AZStd::string_view regdumpallValue = commandLine.GetSwitchValue("regdumpall", 0); - if (regdumpallValue.empty()) - { - AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to parse argument for --regdumpall with value of %.*s.", - aznumeric_cast(regdumpallValue.size()), regdumpallValue.data()); - } - DumperSettings dumperSettings{ prettifyOutput }; AZ::IO::StdoutStream outputStream; DumpSettingsRegistryToStream(registry, "", outputStream, dumperSettings); @@ -602,45 +775,54 @@ namespace AZ::SettingsRegistryMergeUtils } } - void MergeSettingsToRegistry_StoreCommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine) + void StoreCommandLineToRegistry(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine) { // Clear out any existing CommandLine settings registry.Remove(CommandLineRootKey); - // Add the positional arguments into the Settings Registry - AZ::SettingsRegistryInterface::FixedValueString miscValueKey{ CommandLineMiscValuesRootKey }; - size_t miscKeyRootSize = miscValueKey.size(); - for (size_t miscIndex = 0; miscIndex < commandLine.GetNumMiscValues(); ++miscIndex) - { - // Push an array for each positional entry - miscValueKey += AZ::SettingsRegistryInterface::FixedValueString::format("/%zu", miscIndex); - registry.Set(miscValueKey, commandLine.GetMiscValue(miscIndex)); - miscValueKey.resize(miscKeyRootSize); + + AZ::SettingsRegistryInterface::FixedValueString commandLinePath{ CommandLineRootKey }; + const size_t commandLineRootSize = commandLinePath.size(); + size_t argumentIndex{}; + for (const CommandLine::CommandArgument& commandArgument : commandLine) + { + commandLinePath += AZ::SettingsRegistryInterface::FixedValueString::format("/%zu", argumentIndex); + registry.Set(commandLinePath + "/Option", commandArgument.m_option); + registry.Set(commandLinePath + "/Value", commandArgument.m_value); + ++argumentIndex; + commandLinePath.resize(commandLineRootSize); } - // Add the option arguments into the SettingsRegistry - for (const auto& [commandOption, value] : commandLine.GetSwitchList()) - { - AZ::SettingsRegistryInterface::FixedValueString switchKey{ CommandLineSwitchRootKey }; - switchKey += '/'; - switchKey += commandOption; - size_t switchKeyRootSize = switchKey.size(); - // Associate an empty array with the commandOption by default - rapidjson::Document commandSwitchDocument; - rapidjson::Pointer pointer(switchKey.c_str(), switchKey.length()); - pointer.Set(commandSwitchDocument, rapidjson::Value(rapidjson::kArrayType));; - rapidjson::StringBuffer documentBuffer; - rapidjson::Writer documentWriter(documentBuffer); - commandSwitchDocument.Accept(documentWriter); - registry.MergeSettings(AZStd::string_view{ documentBuffer.GetString(), documentBuffer.GetSize() }, - AZ::SettingsRegistryInterface::Format::JsonMergePatch); - - for (size_t switchIndex = 0; switchIndex < value.size(); ++switchIndex) - { - // Push an array for each positional entry - switchKey += AZ::SettingsRegistryInterface::FixedValueString::format("/%zu", switchIndex); - registry.Set(switchKey, value[switchIndex]); - switchKey.resize(switchKeyRootSize); + } + + bool GetCommandLineFromRegistry(SettingsRegistryInterface& registry, AZ::CommandLine& commandLine) + { + struct CommandLineVisitor + : AZ::SettingsRegistryInterface::Visitor + { + void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type + , AZStd::string_view value) override + { + if (valueName == "Option" && !value.empty()) + { + m_arguments.push_back(AZStd::string::format("--%.*s", aznumeric_cast(value.size()), value.data())); + } + else if (valueName == "Value" && !value.empty()) + { + m_arguments.push_back(value); + } } + + // The first parameter is skipped by the ComamndLine::Parse function so initialize + // the container with one empty element + AZ::CommandLine::ParamContainer m_arguments{ 1 }; + }; + + CommandLineVisitor commandLineVisitor; + if (!registry.Visit(commandLineVisitor, AZ::SettingsRegistryMergeUtils::CommandLineRootKey)) + { + return false; } + commandLine.Parse(commandLineVisitor.m_arguments); + return true; } bool DumpSettingsRegistryToStream(SettingsRegistryInterface& registry, AZStd::string_view key, @@ -649,38 +831,21 @@ namespace AZ::SettingsRegistryMergeUtils struct SettingsExportVisitor : SettingsRegistryInterface::Visitor { - using SettingsWriter = AZStd::variant< - rapidjson::PrettyWriter, - rapidjson::Writer>; - SettingsWriter m_writer; - AZ::IO::RapidJSONStreamWriter m_rapidJsonStream; - DumperSettings m_dumperSettings; - AZStd::stack m_includeNameStack; - bool m_includeName{}; - bool m_result{ true }; - SettingsExportVisitor(AZ::IO::GenericStream& stream, const DumperSettings& dumperSettings) : m_rapidJsonStream{ &stream } , m_dumperSettings{ dumperSettings } + , m_writer{ m_stringBuffer } { - if (m_dumperSettings.m_prettifyOutput) - { - m_writer.emplace>(m_rapidJsonStream); - } - else - { - m_writer.emplace>(m_rapidJsonStream); - } } - void WriteName(AZStd::string_view name) + bool WriteName(AZStd::string_view name) { - if (m_includeName) + // Write the Key if the include name stack the top element is true + if (!m_includeNameStack.empty() && m_includeNameStack.top()) { - AZStd::visit([&name](auto&& writer) - { - writer.Key(name.data(), aznumeric_caster(name.size())); - }, m_writer); + return m_writer.Key(name.data(), aznumeric_caster(name.size()), false); } + + return true; } AZ::SettingsRegistryInterface::VisitResponse Traverse( AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::VisitAction action, @@ -694,60 +859,43 @@ namespace AZ::SettingsRegistryMergeUtils if (action == AZ::SettingsRegistryInterface::VisitAction::Begin) { - AZ_Assert(type == AZ::SettingsRegistryInterface::Type::Object || type == AZ::SettingsRegistryInterface::Type::Array, - "Unexpected type visited: %i.", type); - WriteName(valueName); + m_result = m_result && WriteName(valueName); if (type == AZ::SettingsRegistryInterface::Type::Object) { - auto StartObject = [](auto&& writer) + m_result = m_result && m_writer.StartObject(); + if (m_result) { - return writer.StartObject(); - }; - m_result = m_result && AZStd::visit(StartObject, m_writer); - m_includeNameStack.push(true); - m_includeName = true; + m_includeNameStack.push(true); + } } else { - auto StartArray = [](auto&& writer) + m_result = m_result && m_writer.StartArray(); + if (m_result) { - return writer.StartArray(); - }; - m_result = m_result && AZStd::visit(StartArray, m_writer); - m_includeNameStack.push(false); - m_includeName = false; + m_includeNameStack.push(false); + } } } else if (action == AZ::SettingsRegistryInterface::VisitAction::End) { if (type == AZ::SettingsRegistryInterface::Type::Object) { - auto EndObject = [](auto&& writer) - { - return writer.EndObject(); - }; - m_result = m_result && AZStd::visit(EndObject, m_writer); + m_result = m_result && m_writer.EndObject(); } else { - auto EndArray = [](auto&& writer) - { - return writer.EndArray(); - }; - m_result = m_result && AZStd::visit(EndArray, m_writer); + m_result = m_result && m_writer.EndArray(); } AZ_Assert(!m_includeNameStack.empty(), "Attempting to close a json array or object that wasn't started."); m_includeNameStack.pop(); - m_includeName = !m_includeNameStack.empty() ? m_includeNameStack.top() : true; } - else if (type == AZ::SettingsRegistryInterface::Type::Null) + else { - WriteName(valueName); - auto WriteNull = [](auto&& writer) + if (type == AZ::SettingsRegistryInterface::Type::Null) { - return writer.Null(); - }; - m_result = m_result && AZStd::visit(WriteNull, m_writer); + m_result = m_result && WriteName(valueName) && m_writer.Null(); + } } return m_result ? @@ -757,42 +905,27 @@ namespace AZ::SettingsRegistryMergeUtils void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value) { - WriteName(valueName); - auto WriteBool = [value](auto&& writer) - { - return writer.Bool(value); - }; - m_result = m_result && AZStd::visit(WriteBool, m_writer); + m_result = m_result && WriteName(valueName) && m_writer.Bool(value); } - void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) + void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) override { - WriteName(valueName); - auto WriteInt64 = [value](auto&& writer) - { - return writer.Int64(value); - }; - m_result = m_result && AZStd::visit(WriteInt64, m_writer); + m_result = m_result && WriteName(valueName) && m_writer.Int64(value); + } + + void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::u64 value) override + { + m_result = m_result && WriteName(valueName) && m_writer.Uint64(value); } void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, double value) { - WriteName(valueName); - auto WriteDouble = [value](auto&& writer) - { - return writer.Double(value); - }; - m_result = m_result && AZStd::visit(WriteDouble, m_writer); + m_result = m_result && WriteName(valueName) && m_writer.Double(value); } void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) { - WriteName(valueName); - auto WriteString = [&value](auto&& writer) - { - return writer.String(value.data(), aznumeric_caster(value.size())); - }; - m_result = m_result && AZStd::visit(WriteString, m_writer); + m_result = m_result && WriteName(valueName) && m_writer.String(value.data(), aznumeric_caster(value.size())); } bool Finalize() @@ -802,8 +935,46 @@ namespace AZ::SettingsRegistryMergeUtils AZ_Assert(false, "m_includeNameStack is expected to be empty. This means that there was an object or array what wasn't closed."); return false; } - return m_result; + + // Root the JSON document underneath the JSON pointer prefix if non-empty + // Parse non-anchored JSON data into a document and then re-root + // that document under the prefix value + rapidjson::Document document; + document.Parse(m_stringBuffer.GetString(), m_stringBuffer.GetSize()); + + rapidjson::Document rootDocument; + AZStd::string_view jsonPrefix{ m_dumperSettings.m_jsonPointerPrefix }; + if (!jsonPrefix.empty()) + { + rapidjson::Pointer rootPointer(jsonPrefix.data(), jsonPrefix.size()); + rapidjson::SetValueByPointer(rootDocument, rootPointer, document); + } + else + { + rootDocument = AZStd::move(document); + } + + if (m_dumperSettings.m_prettifyOutput) + { + rapidjson::PrettyWriter settingsWriter(m_rapidJsonStream); + rootDocument.Accept(settingsWriter); + } + else + { + rapidjson::Writer settingsWriter(m_rapidJsonStream); + rootDocument.Accept(settingsWriter); + } + + return true; } + + rapidjson::StringBuffer m_stringBuffer; + rapidjson::Writer m_writer; + + AZ::IO::RapidJSONStreamWriter m_rapidJsonStream; + DumperSettings m_dumperSettings; + AZStd::stack m_includeNameStack; + bool m_result{ true }; }; SettingsExportVisitor visitor(stream, dumperSettings); diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h index 60dd6be4bf..b86df27b36 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h @@ -36,27 +36,45 @@ namespace AZ::SettingsRegistryMergeUtils inline static constexpr char FilePathsRootKey[] = "/Amazon/AzCore/Runtime/FilePaths"; inline static constexpr char FilePathKey_BinaryFolder[] = "/Amazon/AzCore/Runtime/FilePaths/BinaryFolder"; inline static constexpr char FilePathKey_EngineRootFolder[] = "/Amazon/AzCore/Runtime/FilePaths/EngineRootFolder"; + + //! Stores the absolute path to root of a project's cache. No asset platform in this path, this is where the asset database file lives. + //! i.e. /Cache + inline static constexpr char FilePathKey_CacheProjectRootFolder[] = "/Amazon/AzCore/Runtime/FilePaths/CacheProjectRootFolder"; + + //! Stores the absolute path to the cache root for an asset platform. This is the @root@ alias. + //! i.e. /Cache/ inline static constexpr char FilePathKey_CacheRootFolder[] = "/Amazon/AzCore/Runtime/FilePaths/CacheRootFolder"; - inline static constexpr char FilePathKey_CacheGameFolder[] = "/Amazon/AzCore/Runtime/FilePaths/CacheGameFolder"; - inline static constexpr char FilePathKey_SourceGameFolder[] = "/Amazon/AzCore/Runtime/FilePaths/SourceGameFolder"; - //! Stores the filename of the Game Project Directory which is equivalent to the project name - inline static constexpr char FilePathKey_SourceGameName[] = "/Amazon/AzCore/Runtime/FilePaths/SourceGameName"; + + //! Stores the absolute path of the Game Project Directory + inline static constexpr char FilePathKey_ProjectPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectPath"; + + //! Store the absolute path to the Projects "user" directory, which is a transient directory where per user + //! project settings can be stored + inline static constexpr char FilePathKey_ProjectUserPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectUserPath"; + //! 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"; - //! Root key for where command line are stored at witin the settings registry + //! Root key for where command line are stored at within the settings registry inline static constexpr char CommandLineRootKey[] = "/Amazon/AzCore/Runtime/CommandLine"; - //! Root key for command line switches(arguments that start with "-" or "--") - inline static constexpr char CommandLineSwitchRootKey[] = "/Amazon/AzCore/Runtime/CommandLine/Switches"; - //! Root key for command line positional arguments - inline static constexpr char CommandLineMiscValuesRootKey[] = "/Amazon/AzCore/Runtime/CommandLine/MiscValues"; - - //! Examines the Settings Registry for a "/Amazon/CommandLine/Switches/app-root" key - //! to use as an override for the Application Root. - //! If that key is not found, it then checks the AZ::Utils::GetDefaultAppRootPath and returns that if it is value + + //! Root key where raw project settings (project.json) file is merged to settings registry + inline static constexpr char ProjectSettingsRootKey[] = "/Amazon/Project/Settings"; + + //! Root key where raw engine manifest (o3de_manifest.json) file is merged to settings registry + inline static constexpr char EngineManifestRootKey[] = "/Amazon/Engine/Manifest"; + + //! Root key where raw engine settings (engine.json) file is merged to settings registry + inline static constexpr char EngineSettingsRootKey[] = "/Amazon/Engine/Settings"; + + //! Examines the Settings Registry for a "${BootstrapSettingsRootKey}/engine_path" key + //! to use as an override for the Engine Root. //! Otherwise a directory walk upwards from the executable directory is performed - //! to find the boostrap.cfg file which will be used as the app root - AZ::IO::FixedMaxPath GetAppRoot(SettingsRegistryInterface* settingsRegistry = nullptr); + //! to find the engine.json file which will be used as the engine root + //! If it's still not found, attempt to find the project (by similar means) then reconcile the + //! engine root by inspecting project.json and the engine manifest file. + AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry); + AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry); //! Query the specializations that will be used when loading the Settings Registry. //! The SpecializationsRootKey is visited to retrieve any specializations stored within that section of that registry @@ -151,16 +169,18 @@ namespace AZ::SettingsRegistryMergeUtils void MergeSettingsToRegistry_ProjectRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, const SettingsRegistryInterface::Specializations& specializations, AZStd::vector* scratchBuffer = nullptr); - //! Adds the development settings added by individual users to the Settings Registry. + //! Adds the development settings added by individual users of the project to the Settings Registry. //! Note that this function is only called in development builds and is compiled out in release builds. - void MergeSettingsToRegistry_DevRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, + void MergeSettingsToRegistry_UserRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, const SettingsRegistryInterface::Specializations& specializations, AZStd::vector* scratchBuffer = nullptr); //! Adds the settings set through the command line to the Settings Registry. This will also execute any Settings - //! Registry related arguments. Note that --set will be run first and all other commands are run afterwards and only - //! if executeCommands is true. The following options are supported: + //! Registry related arguments. Note that --regset and -regremove will run in the order in which they are parsed //! --regset Sets a value in the registry. See MergeCommandLineArgument for options for //! example: --regset "/My/String/Value=String value set" + //! --regremove Removes a value in the registry + //! example: --regremove "/My/String/Value" + //! only when executeCommands is true are the following options supported: //! --regdump Dumps the content of the key at path and all it's content/children to output. //! example: --regdump /My/Array/With/Objects //! --regdumpall Dumps the entire settings registry to output. @@ -169,7 +189,11 @@ namespace AZ::SettingsRegistryMergeUtils //! Stores the command line settings into the Setting Registry //! The arguments can be used later anywhere the command line is needed - void MergeSettingsToRegistry_StoreCommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine); + void StoreCommandLineToRegistry(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine); + + //! Query the command line settings from the Setting Registry and stores them + //! into the AZ::CommandLine instance + bool GetCommandLineFromRegistry(SettingsRegistryInterface& registry, AZ::CommandLine& commandLine); //! Structure for configuring how values should be dumped from the Settings Registry struct DumperSettings @@ -179,14 +203,25 @@ namespace AZ::SettingsRegistryMergeUtils //! Include filter which is used to indicate which paths of the Settings Registry //! should be traversed. //! If the include filter is empty then all paths underneath the JSON pointer path are included - //! otherwise the include filter invoked and if it returns true does it proceed with traversal continues down the path + //! otherwise the include filter invoked and if it returns true does it proceed with traversal down the path + //! The supplied JSON pointer will be a complete path from the root of the registry AZStd::function m_includeFilter; + //! JSON pointer prefix to dump all settings underneath + //! For example if the prefix is "/Amazon/Settings", then the dumped settings will be placed underneath + //! an object at that path + //! """ + //! { + //! "Amazon":{ + //! "Settings":{ } + //! } + //! } + AZStd::string_view m_jsonPointerPrefix; }; //! Dumps supplied settings registry from the path specified by key if it exist the the AZ::IO::GenericStream - //! key is a JSON pointer path to dumping settings recursively from - //! stream is an AZ::IO::GenericStream that supports writing - //! dumperSettings are used to determine how to format the dumped output + //! @param key is a JSON pointer to recursively dump settings from + //! @param stream is an AZ::IO::GenericStream that supports writing + //! @param dumperSettings are used to determine how to format the dumped output bool DumpSettingsRegistryToStream(SettingsRegistryInterface& registry, AZStd::string_view key, AZ::IO::GenericStream& stream, const DumperSettings& dumperSettings); diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index bb911f2684..096c1282db 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -418,36 +418,37 @@ namespace AZ::StringFunc::Internal return Strip(inout, { &stripCharacter, 1 }, bCaseSensitive, bStripBeginning, bStripEnding); } - AZStd::string_view LStrip(AZStd::string_view in, AZStd::string_view stripCharacters) +} + +namespace AZ +{ + namespace StringFunc { - if (size_t pos = in.find_first_not_of(stripCharacters); pos != AZStd::string_view::npos) + AZStd::string_view LStrip(AZStd::string_view in, AZStd::string_view stripCharacters) { - return in.substr(pos); - } + if (size_t pos = in.find_first_not_of(stripCharacters); pos != AZStd::string_view::npos) + { + return in.substr(pos); + } - return {}; - }; + return {}; + }; - AZStd::string_view RStrip(AZStd::string_view in, AZStd::string_view stripCharacters) - { - if (size_t pos = in.find_last_not_of(stripCharacters); pos != AZStd::string_view::npos) + AZStd::string_view RStrip(AZStd::string_view in, AZStd::string_view stripCharacters) { - return in.substr(0, pos < in.size() ? pos + 1 : pos); - } + if (size_t pos = in.find_last_not_of(stripCharacters); pos != AZStd::string_view::npos) + { + return in.substr(0, pos < in.size() ? pos + 1 : pos); + } - return {}; - }; + return {}; + }; - AZStd::string_view StripEnds(AZStd::string_view in, AZStd::string_view stripCharacters) - { - return LStrip(RStrip(in, stripCharacters), stripCharacters); - }; -} + AZStd::string_view StripEnds(AZStd::string_view in, AZStd::string_view stripCharacters) + { + return LStrip(RStrip(in, stripCharacters), stripCharacters); + }; -namespace AZ -{ - namespace StringFunc - { bool Equal(const char* inA, const char* inB, bool bCaseSensitive /*= false*/, size_t n /*= 0*/) { if (!inA || !inB) @@ -483,6 +484,14 @@ namespace AZ } } } + bool Equal(AZStd::string_view inA, AZStd::string_view inB, bool bCaseSensitive) + { + const size_t maxCharsToCompare = inA.size(); + + return inA.size() == inB.size() && (bCaseSensitive + ? strncmp(inA.data(), inB.data(), maxCharsToCompare) == 0 + : azstrnicmp(inA.data(), inB.data(), maxCharsToCompare) == 0); + } bool StartsWith(AZStd::string_view sourceValue, AZStd::string_view prefixValue, bool bCaseSensitive) { @@ -496,9 +505,18 @@ namespace AZ && Equal(sourceValue.substr(sourceValue.size() - suffixValue.size(), AZStd::string_view::npos).data(), suffixValue.data(), bCaseSensitive, suffixValue.size()); } - size_t Find(const char* in, char c, size_t pos /*= 0*/, bool bReverse /*= false*/, bool bCaseSensitive /*= false*/) + bool Contains(AZStd::string_view in, char ch, bool bCaseSensitive) { - if (!in) + return Find(in, ch, 0, false, bCaseSensitive) != AZStd::string_view::npos; + } + bool Contains(AZStd::string_view in, AZStd::string_view sv, bool bCaseSensitive) + { + return Find(in, sv, 0, false, bCaseSensitive) != AZStd::string_view::npos; + } + + size_t Find(AZStd::string_view in, char c, size_t pos /*= 0*/, bool bReverse /*= false*/, bool bCaseSensitive /*= false*/) + { + if (in.empty()) { return AZStd::string::npos; } @@ -508,7 +526,7 @@ namespace AZ pos = 0; } - size_t inLen = strlen(in); + size_t inLen = in.size(); if (inLen < pos) { return AZStd::string::npos; @@ -557,7 +575,13 @@ namespace AZ size_t Find(AZStd::string_view in, AZStd::string_view s, size_t offset /*= 0*/, bool bReverse /*= false*/, bool bCaseSensitive /*= false*/) { - if (in.empty() || s.empty()) + // Formally an empty string matches at the offset if it is <= to the size of the input string + if (s.empty() && offset <= in.size()) + { + return offset; + } + + if (in.empty()) { return AZStd::string::npos; } @@ -773,7 +797,7 @@ namespace AZ bool bIsSpaces = false; if (!bIsEmpty) { - AZStd::string_view strippedNextToken = Internal::StripEnds(*nextToken, " "); + AZStd::string_view strippedNextToken = StripEnds(*nextToken, " "); bIsSpaces = strippedNextToken.empty(); } @@ -805,7 +829,7 @@ namespace AZ bool bIsSpaces = false; if (!bIsEmpty) { - AZStd::string_view strippedNextToken = Internal::StripEnds(*nextToken, " "); + AZStd::string_view strippedNextToken = StripEnds(*nextToken, " "); bIsSpaces = strippedNextToken.empty(); } diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h index aa21057890..7dc4b79090 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include @@ -107,6 +108,22 @@ namespace AZ StringFunc::Equal("Hello World", "Hello", true, 3) = true */ bool Equal(const char* inA, const char* inB, bool bCaseSensitive = false, size_t n = 0); + bool Equal(AZStd::string_view inA, AZStd::string_view inB, bool bCaseSensitive = false); + + //! Contains + /*! Checks if the supplied character or string is contained within the @in parameter + * + Example: Case Insensitive contains finds character + StringFunc::Contains("Hello", 'L') == true + Example: Case Sensitive contains finds character + StringFunc::Contains("Hello", 'l', true) = true + Example: Case Insensitive contains does not find string + StringFunc::Contains("Well Hello", "Mello") == false + Example: Case Sensitive contains does not find character + StringFunc::Contains("HeLlo", 'h', true) == false + */ + bool Contains(AZStd::string_view in, char ch, bool bCaseSensitive = false); + bool Contains(AZStd::string_view in, AZStd::string_view sv, bool bCaseSensitive = false); //! Find /*! Find for non AZStd::strings. Ease of use to find the first or last occurrence of a character or substring in a c-string with case sensitivity. @@ -119,7 +136,7 @@ namespace AZ Example: Case Sensitive find first occurrence of substring "Hello" a in a c-string StringFunc::Find("Well Hello", "Hello", false, true) == 5 */ - size_t Find(const char* in, char c, size_t pos = 0, bool bReverse = false, bool bCaseSensitive = false); + size_t Find(AZStd::string_view in, char c, size_t pos = 0, bool bReverse = false, bool bCaseSensitive = false); size_t Find(AZStd::string_view in, AZStd::string_view str, size_t pos = 0, bool bReverse = false, bool bCaseSensitive = false); //! First and Last Character @@ -196,6 +213,33 @@ namespace AZ */ AZStd::string& TrimWhiteSpace(AZStd::string& value, bool leading, bool trailing); + //! LStrip + /*! Strips leading characters in the stripCharacters set + * Example + * Example: Case Insensitive Strip leading 'a' characters + * StringFunc::LStrip(s = "Abracadabra", 'a'); s == "bracadabra" + * Example: Case Sensitive Strip leading 'a' characters + * StringFunc::LStrip(s = "Abracadabra", 'a'); s == "Abracadabra" + */ + //! RStrip + /*! Strips trailing characters in the stripCharacters set + * Example + * Example: Case Insensitive Strip trailing 'a' characters + * StringFunc::RStrip(s = "AbracadabrA", 'a'); s == "Abracadabr" + * Example: Case Sensitive Strip trailing 'a' characters + * StringFunc::RStrip(s = "AbracadabrA", 'a'); s == "AbracadabrA" + */ + //! StripEnds + /*! Strips leading and trailing characters in the stripCharacters set + Example: Case Insensitive Strip all 'a' characters + StringFunc::StripEnds(s = "Abracadabra", 'a'); s == "bracadabr" + Example: Case Sensitive Strip all 'a' characters + StringFunc::StripEnds(s = "Abracadabra", 'a'); s == "Abracadabr" + */ + AZStd::string_view LStrip(AZStd::string_view in, AZStd::string_view stripCharacters = " "); + AZStd::string_view RStrip(AZStd::string_view in, AZStd::string_view stripCharacters = " "); + AZStd::string_view StripEnds(AZStd::string_view in, AZStd::string_view stripCharacters = " "); + //! Strip /*! Strip away the leading, trailing or all character(s) or substring(s) in a AZStd::string with *! case sensitivity. @@ -669,8 +713,7 @@ namespace AZ */ namespace Path { - inline constexpr size_t MaxPathLength = 1024; - using FixedString = AZStd::fixed_string; + using FixedString = AZ::IO::FixedMaxPathString; //! Normalize /*! Normalizes a path and returns returns StringFunc::Path::IsValid() *! strips all AZ_FILESYSTEM_INVALID_CHARACTERS @@ -791,7 +834,7 @@ namespace AZ //! StripFullName /*! gets rid of the full file name if it has one, returns if it removed one or not - *! EX: StringFunc::Path::StripFullName(a="C:\\p4\\game\\info\\some.file") == true; a=="C:\\p4\\game\\info\\" + *! EX: StringFunc::Path::StripFullName(a="C:\\p4\\game\\info\\some.file") == true; a=="C:\\p4\\game\\info" */ void StripFullName(AZStd::string& out); diff --git a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h index d9fd5067ce..309618e196 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h @@ -39,6 +39,7 @@ namespace UnitTest MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); MOCK_CONST_METHOD0(GetAppRoot, const char* ()); + MOCK_CONST_METHOD0(GetEngineRoot, const char* ()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ()); MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&)); diff --git a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h index 96be703e8a..a9466fd765 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h @@ -60,6 +60,7 @@ namespace AZ MOCK_CONST_METHOD2(ConvertToAlias, bool(AZ::IO::FixedMaxPath& aliasPath, const AZ::IO::PathView& path)); MOCK_CONST_METHOD3(ResolvePath, bool(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize)); MOCK_CONST_METHOD2(ResolvePath, bool(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path)); + MOCK_CONST_METHOD2(ReplaceAlias, bool(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path)); MOCK_CONST_METHOD3(GetFilename, bool(HandleType fileHandle, char* filename, AZ::u64 filenameSize)); using FileIOBase::ConvertToAlias; using FileIOBase::ResolvePath; diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index c9c20173db..e20d36b12f 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include namespace AZ::Utils @@ -40,6 +42,47 @@ namespace AZ::Utils return result.m_pathStored; } + AZ::IO::FixedMaxPathString GetEnginePath() + { + if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) + { + AZ::SettingsRegistryInterface::FixedValueString settingsValue; + if (registry->Get(settingsValue, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) + { + return AZ::IO::FixedMaxPathString{settingsValue}; + } + } + return {}; + } + + AZ::IO::FixedMaxPathString GetProjectPath() + { + if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) + { + AZ::SettingsRegistryInterface::FixedValueString settingsValue; + if (registry->Get(settingsValue, AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) + { + return AZ::IO::FixedMaxPathString{settingsValue}; + } + } + return {}; + } + + AZ::SettingsRegistryInterface::FixedValueString GetProjectName() + { + if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) + { + AZ::SettingsRegistryInterface::FixedValueString projectNameKey{ AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey }; + projectNameKey += "/project_name"; + AZ::SettingsRegistryInterface::FixedValueString settingsValue; + if (registry->Get(settingsValue, projectNameKey)) + { + return settingsValue; + } + } + return {}; + } + AZ::Outcome WriteFile(AZStd::string_view content, AZStd::string_view filePath) { AZ::IO::FixedMaxPath filePathFixed = filePath; // Because FileIOStream requires a null-terminated string diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.h b/Code/Framework/AzCore/AzCore/Utils/Utils.h index 9334c0d61f..431bf7487a 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.h +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -24,9 +26,6 @@ namespace AZ { namespace Utils { - // Common cross platform Utils go here - inline constexpr size_t MaxPathLength = 1024; - //! Protects from allocating too much memory. The choice of a 1MB threshold is arbitrary. //! If you need to work with larger files, please use AZ::IO directly instead of these utility functions. inline constexpr size_t DefaultMaxFileSize = 1024 * 1024; @@ -77,10 +76,22 @@ namespace AZ //! @returns a result object that indicates if the executable directory was able to be stored within the buffer ExecutablePathResult GetExecutableDirectory(char* exeStorageBuffer, size_t exeStorageSize); + //! Retrieves the full path to the engine from settings registry + AZ::IO::FixedMaxPathString GetEnginePath(); + + //! Retrieves the full path to the project from settings registry + AZ::IO::FixedMaxPathString GetProjectPath(); + + //! Retrieves the project name from the settings registry + AZ::SettingsRegistryInterface::FixedValueString GetProjectName(); + + //! Retrieves the full path where the manifest file lives, i.e. "/.o3de/o3de_manifest.json" + AZ::IO::FixedMaxPathString GetEngineManifestPath(); + //! Retrieves the App root path to use on the current platform //! If the optional is not engaged the AppRootPath should be calculated based //! on the location of the bootstrap.cfg file - AZStd::optional> GetDefaultAppRootPath(); + AZStd::optional GetDefaultAppRootPath(); //! Retrieves the development write storage path to use on the current platform, may be considered //! temporary or cache storage @@ -88,7 +99,7 @@ namespace AZ // Attempts the supplied path to an absolute path. //! Returns nullopt if path cannot be converted to an absolute path - AZStd::optional> ConvertToAbsolutePath(AZStd::string_view path); + AZStd::optional ConvertToAbsolutePath(AZStd::string_view path); //! Save a string to a file. Otherwise returns a failure with error message. AZ::Outcome WriteFile(AZStd::string_view content, AZStd::string_view filePath); diff --git a/Code/Framework/AzCore/AzCore/std/string/fixed_string.h b/Code/Framework/AzCore/AzCore/std/string/fixed_string.h index 101af77057..2afbded510 100644 --- a/Code/Framework/AzCore/AzCore/std/string/fixed_string.h +++ b/Code/Framework/AzCore/AzCore/std/string/fixed_string.h @@ -249,6 +249,11 @@ namespace AZStd constexpr auto swap(basic_fixed_string& rhs) -> void; + // C++23 contains + constexpr auto contains(const basic_fixed_string& other) const -> bool; + constexpr auto contains(Element ch) const -> bool; + constexpr auto contains(const_pointer s) const -> bool; + constexpr auto find(const basic_fixed_string& rhs, size_type offset = 0) const -> size_type; constexpr auto find(const_pointer ptr, size_type offset, size_type count) const -> size_type; constexpr auto find(const_pointer ptr, size_type offset = 0) const -> size_type; diff --git a/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl b/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl index 242dcf94ea..4d99858d2b 100644 --- a/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl +++ b/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl @@ -1072,6 +1072,23 @@ namespace AZStd Traits::assign(rhs.m_buffer[rhs.m_size], Element{ 0 }); } + // C++23 contains + template + inline constexpr auto basic_fixed_string::contains(const basic_fixed_string& other) const -> bool + { + return find(other) != npos; + } + template + inline constexpr auto basic_fixed_string::contains(value_type c) const -> bool + { + return find(c) != npos; + } + template + inline constexpr auto basic_fixed_string::contains(const_pointer s) const -> bool + { + return find(s) != npos; + } + template inline constexpr auto basic_fixed_string::find(const basic_fixed_string& rhs, size_type offset) const -> size_type { diff --git a/Code/Framework/AzCore/AzCore/std/string/string.h b/Code/Framework/AzCore/AzCore/std/string/string.h index deac35b232..8f15b45db7 100644 --- a/Code/Framework/AzCore/AzCore/std/string/string.h +++ b/Code/Framework/AzCore/AzCore/std/string/string.h @@ -961,6 +961,22 @@ namespace AZStd } } + // C++23 contains + bool contains(const basic_string& other) const + { + return find(other) != npos; + } + + bool contains(value_type c) const + { + return find(c) != npos; + } + + bool contains(const_pointer s) const + { + return find(s) != npos; + } + inline size_type find(const this_type& rhs, size_type offset = 0) const { const_pointer rhsData = SSO_BUF_SIZE <= rhs.m_capacity ? rhs.m_data : rhs.m_buffer; diff --git a/Code/Framework/AzCore/AzCore/std/string/string_view.h b/Code/Framework/AzCore/AzCore/std/string/string_view.h index ce2c912b2a..d00b2a8369 100644 --- a/Code/Framework/AzCore/AzCore/std/string/string_view.h +++ b/Code/Framework/AzCore/AzCore/std/string/string_view.h @@ -669,6 +669,22 @@ namespace AZStd return ends_with(basic_string_view(suffix)); } + // C++23 contains + constexpr bool contains(basic_string_view other) const + { + return find(other) != npos; + } + + constexpr bool contains(value_type c) const + { + return find(c) != npos; + } + + constexpr bool contains(const_pointer s) const + { + return find(s) != npos; + } + // find constexpr size_type find(basic_string_view other, size_type pos = 0) const { diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp index 17883c9b5e..df0030abfa 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp @@ -52,10 +52,10 @@ namespace AZ // in non-release builds. // If a bootstrap.cfg file is not found in the public storage, it is then searched for // within the APK itself - AZStd::optional> GetDefaultAppRootPath() + AZStd::optional GetDefaultAppRootPath() { const char* appRoot = AZ::Android::Utils::FindAssetsDirectory(); - return appRoot ? AZStd::make_optional>(appRoot) : AZStd::nullopt; + return appRoot ? AZStd::make_optional(appRoot) : AZStd::nullopt; } AZStd::optional GetDevWriteStoragePath() @@ -64,10 +64,10 @@ namespace AZ return writeStorage ? AZStd::make_optional(writeStorage) : AZStd::nullopt; } - AZStd::optional> ConvertToAbsolutePath(AZStd::string_view path) + AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) { - AZStd::fixed_string absolutePath; - AZStd::fixed_string srcPath{ path }; + AZ::IO::FixedMaxPathString absolutePath; + AZ::IO::FixedMaxPathString srcPath{ path }; if (AZ::Android::Utils::IsApkPath(srcPath.c_str())) { return srcPath; diff --git a/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake b/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake index d5a03ecd1c..fcb78b4cf1 100644 --- a/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake +++ b/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake @@ -64,6 +64,7 @@ set(FILES AzCore/Socket/AzSocket_Platform.h ../Common/UnixLike/AzCore/std/time_UnixLike.cpp AzCore/Utils/Utils_Android.cpp + ../Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp ../../AzCore/Android/AndroidEnv.cpp ../../AzCore/Android/AndroidEnv.h ../../AzCore/Android/APKFileHandler.cpp diff --git a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp new file mode 100644 index 0000000000..eee242f3b7 --- /dev/null +++ b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp @@ -0,0 +1,22 @@ +/* +* 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. +* +*/ + +#include + +namespace AZ::Utils +{ + AZ::IO::FixedMaxPathString GetEngineManifestPath() + { + return {}; + } + +} // namespace AZ::Utils \ No newline at end of file diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp index 32680c6461..fdd00689c6 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp @@ -12,7 +12,7 @@ #include -#include +#include namespace AZ { @@ -25,10 +25,25 @@ namespace AZ void NativeErrorMessageBox(const char*, const char*) {} - AZStd::optional> ConvertToAbsolutePath(AZStd::string_view path) + AZ::IO::FixedMaxPathString GetEngineManifestPath() { - AZStd::fixed_string absolutePath; - AZStd::fixed_string srcPath{ path }; + if (const char* homePath = std::getenv("HOME"); homePath != nullptr) + { + AZ::IO::FixedMaxPath path{homePath}; + if (!path.empty()) + { + path /= ".o3de"; + path /= "o3de_manifest.json"; + } + return path.Native(); + } + return {}; + } + + AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + { + AZ::IO::FixedMaxPathString absolutePath; + AZ::IO::FixedMaxPathString srcPath{ path }; if (char* result = realpath(srcPath.c_str(), absolutePath.data()); result) { diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp index bc55b803a9..a740ff7472 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp @@ -47,7 +47,7 @@ namespace AZ return result; } - AZStd::optional> GetDefaultAppRootPath() + AZStd::optional GetDefaultAppRootPath() { return AZStd::nullopt; } @@ -57,10 +57,10 @@ namespace AZ return AZStd::nullopt; } - AZStd::optional> ConvertToAbsolutePath(AZStd::string_view path) + AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) { - AZStd::fixed_string absolutePath; - AZStd::fixed_string srcPath{ path }; + AZ::IO::FixedMaxPathString absolutePath; + AZ::IO::FixedMaxPathString srcPath{ path }; char* result = _fullpath(absolutePath.data(), srcPath.c_str(), absolutePath.capacity()); // Force update of the fixed_string size() value absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/Utils/Utils_Linux.cpp b/Code/Framework/AzCore/Platform/Linux/AzCore/Utils/Utils_Linux.cpp index 9f71b9c977..68eff36e02 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/Utils/Utils_Linux.cpp +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/Utils/Utils_Linux.cpp @@ -45,7 +45,7 @@ namespace AZ return result; } - AZStd::optional> GetDefaultAppRootPath() + AZStd::optional GetDefaultAppRootPath() { return AZStd::nullopt; } diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/Utils/Utils_Mac.cpp b/Code/Framework/AzCore/Platform/Mac/AzCore/Utils/Utils_Mac.cpp index 72ffd13c11..a5286462f9 100644 --- a/Code/Framework/AzCore/Platform/Mac/AzCore/Utils/Utils_Mac.cpp +++ b/Code/Framework/AzCore/Platform/Mac/AzCore/Utils/Utils_Mac.cpp @@ -16,7 +16,7 @@ namespace AZ::Utils { - AZStd::optional> GetDefaultAppRootPath() + AZStd::optional GetDefaultAppRootPath() { return AZStd::nullopt; } diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StreamerConfiguration_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StreamerConfiguration_Windows.cpp index cfef7d7936..5d719836dd 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StreamerConfiguration_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StreamerConfiguration_Windows.cpp @@ -376,7 +376,7 @@ namespace AZ::IO hardwareInfo.m_profile = driveList.size() == 1 ? driveList.front().m_profile : "Generic"; hardwareInfo.m_platformData = AZStd::make_any(AZStd::move(driveList)); - return true; + return !driveList.empty(); } else { diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp index 8c3a06264f..5a56ed6b84 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Utils/Utils_Windows.cpp @@ -15,13 +15,27 @@ #include -namespace AZ +namespace AZ::Utils { - namespace Utils + void NativeErrorMessageBox(const char* title, const char* message) { - void NativeErrorMessageBox(const char* title, const char* message) + ::MessageBox(0, message, title, MB_OK | MB_ICONERROR); + } + + AZ::IO::FixedMaxPathString GetEngineManifestPath() + { + char userProfileBuffer[AZ::IO::MaxPathLength] = {0}; + size_t variableSize = 0; + auto err = getenv_s(&variableSize, userProfileBuffer, AZ::IO::MaxPathLength, "USERPROFILE"); + if (!err) { - ::MessageBox(0, message, title, MB_OK | MB_ICONERROR); + AZ::IO::FixedMaxPath path{userProfileBuffer}; + path /= ".o3de"; + path /= "o3de_manifest.json"; + return path.Native(); } - } // namespace Utils -} // namespace AZ \ No newline at end of file + + return {}; + } + +} // namespace AZ::Utils diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/Utils/Utils_iOS.mm b/Code/Framework/AzCore/Platform/iOS/AzCore/Utils/Utils_iOS.mm index bac9b34bdd..f7054fdcea 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/Utils/Utils_iOS.mm +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/Utils/Utils_iOS.mm @@ -19,10 +19,10 @@ namespace AZ::Utils { - AZStd::optional> GetDefaultAppRootPath() + AZStd::optional GetDefaultAppRootPath() { const char* pathToResources = [[[NSBundle mainBundle] resourcePath] UTF8String]; - return AZStd::fixed_string::format("%s/assets", pathToResources); + return AZ::IO::FixedMaxPathString::format("%s/assets", pathToResources); } AZStd::optional GetDevWriteStoragePath() diff --git a/Code/Framework/AzCore/Platform/iOS/platform_ios_files.cmake b/Code/Framework/AzCore/Platform/iOS/platform_ios_files.cmake index 278c5c955b..a09343628c 100644 --- a/Code/Framework/AzCore/Platform/iOS/platform_ios_files.cmake +++ b/Code/Framework/AzCore/Platform/iOS/platform_ios_files.cmake @@ -70,4 +70,5 @@ set(FILES AzCore/Utils/Utils_iOS.mm ../Common/Apple/AzCore/Utils/Utils_Apple.cpp ../Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp + ../Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp ) diff --git a/Code/Framework/AzCore/Tests/AZStd/String.cpp b/Code/Framework/AzCore/Tests/AZStd/String.cpp index fc3d7d9a41..73ea5482c5 100644 --- a/Code/Framework/AzCore/Tests/AZStd/String.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/String.cpp @@ -2391,6 +2391,27 @@ namespace UnitTest EXPECT_STREQ("AB BA", eraseIfTest.c_str()); } + template + class ImmutableStringFunctionsFixture + : public ScopedAllocatorSetupFixture + {}; + using StringTypesToTest = ::testing::Types>; + TYPED_TEST_CASE(ImmutableStringFunctionsFixture, StringTypesToTest); + + TYPED_TEST(ImmutableStringFunctionsFixture, Contains_Succeeds) + { + TypeParam testStrValue{ R"(C:\o3de\Assets\Materials\texture\image.png)" }; + EXPECT_TRUE(testStrValue.contains("Materials")); + EXPECT_FALSE(testStrValue.contains("Animations")); + EXPECT_TRUE(testStrValue.contains('o')); + EXPECT_FALSE(testStrValue.contains('Q')); + + TypeParam typeParamEntry{ R"(texture)" }; + TypeParam typeParamNoEntry{ R"(physics)" }; + EXPECT_TRUE(testStrValue.contains(typeParamEntry)); + EXPECT_FALSE(testStrValue.contains(typeParamNoEntry)); + } + template const T* GetFormatString() { diff --git a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h index 1a0fcf0026..b4ade433cb 100644 --- a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h +++ b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h @@ -54,8 +54,9 @@ namespace UnitTest AZ::SerializeContext* GetSerializeContext() override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return m_behaviorContext; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h b/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h index 28947b2da0..1a7a79b06e 100644 --- a/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h +++ b/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h @@ -416,6 +416,11 @@ public: return false; } + bool ReplaceAlias(AZ::IO::FixedMaxPath&, const AZ::IO::PathView&) const override + { + return false; + } + void SetAlias(const char*, const char*) override { } diff --git a/Code/Framework/AzCore/Tests/Platform/Android/Tests/UtilsTests_Android.cpp b/Code/Framework/AzCore/Tests/Platform/Android/Tests/UtilsTests_Android.cpp index 90a02939e8..1febe5047e 100644 --- a/Code/Framework/AzCore/Tests/Platform/Android/Tests/UtilsTests_Android.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Android/Tests/UtilsTests_Android.cpp @@ -58,22 +58,22 @@ namespace UnitTest TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnRelativePath_Succeeds) { - AZStd::optional> absolutePath = AZ::Utils::ConvertToAbsolutePath("./"); + AZStd::optional absolutePath = AZ::Utils::ConvertToAbsolutePath("./"); EXPECT_TRUE(absolutePath); } TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnAbsolutePath_Succeeds) { - char executableDirectory[AZ::Utils::MaxPathLength]; - AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZ_ARRAY_SIZE(executableDirectory)); + char executableDirectory[AZ::IO::MaxPathLength]; + AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZStd::size(executableDirectory)); EXPECT_EQ(AZ::Utils::ExecutablePathResult::Success, result); - AZStd::optional> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory); + AZStd::optional absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory); ASSERT_TRUE(absolutePath); // Note that ConvertToAbsolutePath will perform a realpath on the result. The result of AZ::Utils::GetExecutableDirectory // uses AZ::Android::AndroidEnv::Get()->GetAppPrivateStoragePath() which will retrieve the storage path, but that path could // be symlinked, so we need to perform a real path on it before comparison - char realExecutableDirectory[AZ::Utils::MaxPathLength]; + char realExecutableDirectory[AZ::IO::MaxPathLength]; ASSERT_TRUE(realpath(executableDirectory, realExecutableDirectory)); EXPECT_STRCASEEQ(realExecutableDirectory, absolutePath->c_str()); diff --git a/Code/Framework/AzCore/Tests/Platform/Common/UnixLike/Tests/UtilsTests_UnixLike.cpp b/Code/Framework/AzCore/Tests/Platform/Common/UnixLike/Tests/UtilsTests_UnixLike.cpp index 86002823ca..8c82d447d4 100644 --- a/Code/Framework/AzCore/Tests/Platform/Common/UnixLike/Tests/UtilsTests_UnixLike.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Common/UnixLike/Tests/UtilsTests_UnixLike.cpp @@ -27,16 +27,16 @@ namespace UnitTest TEST_F(UtilsUnixLikeTestFixture, ConvertToAbsolutePath_OnRelativePath_Succeeds) { - AZStd::optional> absolutePath = AZ::Utils::ConvertToAbsolutePath("./"); + AZStd::optional absolutePath = AZ::Utils::ConvertToAbsolutePath("./"); EXPECT_TRUE(absolutePath); } TEST_F(UtilsUnixLikeTestFixture, ConvertToAbsolutePath_OnAbsolutePath_Succeeds) { - char executableDirectory[AZ::Utils::MaxPathLength]; + char executableDirectory[AZ::IO::MaxPathLength]; AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZ_ARRAY_SIZE(executableDirectory)); EXPECT_EQ(AZ::Utils::ExecutablePathResult::Success, result); - AZStd::optional> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory); + AZStd::optional absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory); ASSERT_TRUE(absolutePath); EXPECT_STRCASEEQ(executableDirectory, absolutePath->c_str()); } diff --git a/Code/Framework/AzCore/Tests/Platform/Common/WinAPI/Tests/UtilsTests_WinAPI.cpp b/Code/Framework/AzCore/Tests/Platform/Common/WinAPI/Tests/UtilsTests_WinAPI.cpp index 1a07cc6d00..00b188ac7e 100644 --- a/Code/Framework/AzCore/Tests/Platform/Common/WinAPI/Tests/UtilsTests_WinAPI.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Common/WinAPI/Tests/UtilsTests_WinAPI.cpp @@ -53,23 +53,23 @@ namespace UnitTest TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnInvalidPath_Fails) { - AZStd::fixed_string invalidPath{ "Z:\\" }; - invalidPath.append(AZ::Utils::MaxPathLength - invalidPath.size(), '@'); + AZ::IO::FixedMaxPathString invalidPath{ "Z:\\" }; + invalidPath.append(invalidPath.max_size() - invalidPath.size(), '@'); EXPECT_FALSE(AZ::Utils::ConvertToAbsolutePath(invalidPath)); } TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnRelativePath_Succeeds) { - AZStd::optional> absolutePath = AZ::Utils::ConvertToAbsolutePath("./"); + AZStd::optional absolutePath = AZ::Utils::ConvertToAbsolutePath("./"); EXPECT_TRUE(absolutePath); } TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnAbsolutePath_Succeeds) { - char executableDirectory[AZ::Utils::MaxPathLength]; + char executableDirectory[AZ::IO::MaxPathLength]; AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZ_ARRAY_SIZE(executableDirectory)); EXPECT_EQ(AZ::Utils::ExecutablePathResult::Success, result); - AZStd::optional> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory); + AZStd::optional absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory); ASSERT_TRUE(absolutePath); EXPECT_STRCASEEQ(executableDirectory, absolutePath->c_str()); } diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index 9e846d9e68..4b20c5e4ab 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -1237,8 +1237,9 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/MathVectorSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/MathVectorSerializerTests.cpp index 49240c3903..34810df7c5 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/MathVectorSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/MathVectorSerializerTests.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,13 @@ namespace JsonSerializationTests constexpr static size_t ElementCount = 4; }; + struct QuaternionDescriptor + { + using VectorType = AZ::Quaternion; + using Serializer = AZ::JsonQuaternionSerializer; + constexpr static size_t ElementCount = 4; + }; + using JsonMathVectorSerializerTypes = ::testing::Types < Vector2Descriptor, Vector3Descriptor, Vector4Descriptor>; TYPED_TEST_CASE(JsonMathVectorSerializerTests, JsonMathVectorSerializerTypes); diff --git a/Code/Framework/AzCore/Tests/Settings/CommandLineTests.cpp b/Code/Framework/AzCore/Tests/Settings/CommandLineTests.cpp index 166599c6e6..45e7406c8c 100644 --- a/Code/Framework/AzCore/Tests/Settings/CommandLineTests.cpp +++ b/Code/Framework/AzCore/Tests/Settings/CommandLineTests.cpp @@ -25,9 +25,11 @@ namespace UnitTest AZ::CommandLine cmd; EXPECT_FALSE(cmd.HasSwitch("")); EXPECT_EQ(cmd.GetNumSwitchValues("haha"), 0); + AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_EQ(cmd.GetSwitchValue("haha", 0), AZStd::string()); - EXPECT_EQ(cmd.GetNumMiscValues(), 0); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_EQ(cmd.GetNumMiscValues(), 0); AZ_TEST_START_TRACE_SUPPRESSION; EXPECT_EQ(cmd.GetMiscValue(1), AZStd::string()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); @@ -379,7 +381,6 @@ namespace UnitTest { AZ::CommandLine origCommandLine{ "-/" }; - const char* argValues[] = { "programname.exe", "/gamefolder", "/RemoteIp", "10.0.0.1", "-ScanFolders", R"(\a\b\c,\d\e\f)", "Foo", "Bat" @@ -396,20 +397,21 @@ namespace UnitTest for (const auto& commandLine : commandLines) { EXPECT_TRUE(commandLine.HasSwitch("gamefolder")); - EXPECT_EQ(0, commandLine.GetNumSwitchValues("gamefolder")); + EXPECT_EQ(1, commandLine.GetNumSwitchValues("gamefolder")); + EXPECT_STREQ("", commandLine.GetSwitchValue("gamefolder", 0).c_str()); EXPECT_TRUE(commandLine.HasSwitch("remoteip")); EXPECT_EQ(1, commandLine.GetNumSwitchValues("remoteip")); - EXPECT_EQ("10.0.0.1", commandLine.GetSwitchValue("remoteip", 0)); + EXPECT_STREQ("10.0.0.1", commandLine.GetSwitchValue("remoteip", 0).c_str()); EXPECT_TRUE(commandLine.HasSwitch("scanfolders")); EXPECT_EQ(2, commandLine.GetNumSwitchValues("scanfolders")); - EXPECT_EQ(R"(\a\b\c)", commandLine.GetSwitchValue("scanfolders", 0)); - EXPECT_EQ(R"(\d\e\f)", commandLine.GetSwitchValue("scanfolders", 1)); + EXPECT_STREQ(R"(\a\b\c)", commandLine.GetSwitchValue("scanfolders", 0).c_str()); + EXPECT_STREQ(R"(\d\e\f)", commandLine.GetSwitchValue("scanfolders", 1).c_str()); EXPECT_EQ(2, commandLine.GetNumMiscValues()); - EXPECT_EQ("Foo", commandLine.GetMiscValue(0)); - EXPECT_EQ("Bat", commandLine.GetMiscValue(1)); + EXPECT_STREQ("Foo", commandLine.GetMiscValue(0).c_str()); + EXPECT_STREQ("Bat", commandLine.GetMiscValue(1).c_str()); } } } // namespace UnitTest diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp b/Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp index 9a40084c01..37ea9f1bc1 100644 --- a/Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp +++ b/Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp @@ -82,23 +82,25 @@ namespace SettingsRegistryMergeUtilsTests DumpSettings, SettingsRegistryMergeUtilsParamFixture, ::testing::Values( - DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonPatch, - R"( [ - { "op": "add", "path": "/Test", "value": { "Object": {} } }, - - { "op": "add", "path": "/Test/Object/NullType", "value": null }, - { "op": "add", "path": "/Test/Object/TrueType", "value": true }, - { "op": "add", "path": "/Test/Object/FalseType", "value": false }, - { "op": "add", "path": "/Test/Object/IntType", "value": -42 }, - { "op": "add", "path": "/Test/Object/UIntType", "value": 42 }, - { "op": "add", "path": "/Test/Object/DoubleType", "value": 42.0 }, - { "op": "add", "path": "/Test/Object/StringType", "value": "Hello world" }, - - { "op": "add", "path": "/Test/Array", "value": [ null, true, false, -42, 42, 42.0, "Hello world" ] } - ])", + DumpSettingsRegistryParams + { + AZ::SettingsRegistryInterface::Format::JsonPatch, + R"([)" "\n" + R"( { "op": "add", "path": "/Test", "value": { "Object": {} } },)" "\n" + R"( { "op": "add", "path": "/Test/Object/NullType", "value": null },)" "\n" + R"( { "op": "add", "path": "/Test/Object/TrueType", "value": true },)" "\n" + R"( { "op": "add", "path": "/Test/Object/FalseType", "value": false },)" "\n" + R"( { "op": "add", "path": "/Test/Object/IntType", "value": -42 },)" "\n" + R"( { "op": "add", "path": "/Test/Object/UIntType", "value": 42 },)" "\n" + R"( { "op": "add", "path": "/Test/Object/DoubleType", "value": 42.0 },)" "\n" + R"( { "op": "add", "path": "/Test/Object/StringType", "value": "Hello world" },)" "\n" + R"( { "op": "add", "path": "/Test/Array", "value": [ null, true, false, -42, 42, 42.0, "Hello world" ] })" "\n" + R"(])" "\n", R"({"Test":{"Object":{"NullType":null,"TrueType":true,"FalseType":false,"IntType":-42,"UIntType":42)" R"(,"DoubleType":42.0,"StringType":"Hello world"},"Array":[null,true,false,-42,42,42.0,"Hello world"]}})", - { false, + AZ::SettingsRegistryMergeUtils::DumperSettings + { + false, [](AZStd::string_view path) { AZStd::string_view prefixPath("/Test"); @@ -106,26 +108,30 @@ namespace SettingsRegistryMergeUtilsTests } } }, - DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonMergePatch, - R"({ - "Test": - { - "Array0": [ 142, 188 ], - "Array1": [ 242, 288 ], - "Array2": [ 342, 388 ] - } - })", + DumpSettingsRegistryParams + { + AZ::SettingsRegistryInterface::Format::JsonMergePatch, + R"({)" "\n" + R"( "Test":)" "\n" + R"( {)" "\n" + R"( "Array0": [ 142, 188 ], )" "\n" + R"( "Array1": [ 242, 288 ], )" "\n" + R"( "Array2": [ 342, 388 ] )" "\n" + R"( })" "\n" + R"(})" "\n", R"({"Test":{"Array0":[142,188],"Array1":[242,288],"Array2":[342,388]}})", - { false, + AZ::SettingsRegistryMergeUtils::DumperSettings{ false, [](AZStd::string_view path) { AZStd::string_view prefixPath("/Test"); return prefixPath.starts_with(path.substr(0, prefixPath.size())); } } - }, - DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonMergePatch, - R"({ + }, + DumpSettingsRegistryParams + { + AZ::SettingsRegistryInterface::Format::JsonMergePatch, + R"({ "Test": { "Array0": [ 142, 188 ], @@ -149,23 +155,27 @@ namespace SettingsRegistryMergeUtilsTests R"( ])""\n" R"( })""\n" R"(})", - { true, + AZ::SettingsRegistryMergeUtils::DumperSettings + { + true, [](AZStd::string_view path) { AZStd::string_view prefixPath("/Test"); return prefixPath.starts_with(path.substr(0, prefixPath.size())); } } - }, - DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonMergePatch, - R"({ + }, + DumpSettingsRegistryParams + { + AZ::SettingsRegistryInterface::Format::JsonMergePatch, + R"({ "Test": { "Array0": [ 142, 188 ], "Array1": [ 242, 288 ], "Array2": [ 342, 388 ] } - })", + })", R"({)""\n" R"( "Array0": [)""\n" R"( 142,)""\n" @@ -180,7 +190,9 @@ namespace SettingsRegistryMergeUtilsTests R"( 388)""\n" R"( ])""\n" R"(})", - { true, + AZ::SettingsRegistryMergeUtils::DumperSettings + { + true, [](AZStd::string_view path) { AZStd::string_view prefixPath("/Test"); @@ -188,8 +200,19 @@ namespace SettingsRegistryMergeUtilsTests } }, "/Test" - } - ) + }, + DumpSettingsRegistryParams{ + AZ::SettingsRegistryInterface::Format::JsonMergePatch, + R"({)" "\n" + R"( "Test":)" "\n" + R"( {)" "\n" + R"( "Array0": [ 142, 188 ])" "\n" + R"( })" "\n" + R"(})", + R"({"Root":{"Path":{"Test":{"Array0":[142,188]}}}})", + AZ::SettingsRegistryMergeUtils::DumperSettings{ false, {}, "/Root/Path/Test" }, + "/Test" + }) ); //! ConfigFile MergeUtils Test @@ -281,9 +304,13 @@ namespace SettingsRegistryMergeUtilsTests AZ::SettingsRegistryMergeUtils::ConfigParserSettings parserSettings; parserSettings.m_commentPrefixFunc = [](AZStd::string_view line) -> AZStd::string_view { - if (line.starts_with("--") || line.starts_with(';') || line.starts_with('#')) + constexpr AZStd::string_view commentPrefixes[]{ "--", ";","#" }; + for (AZStd::string_view commentPrefix : commentPrefixes) { - return {}; + if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos) + { + return line.substr(0, commentOffset); + } } return line; }; @@ -330,7 +357,7 @@ INSTANTIATE_TEST_CASE_P( -- android, ios, mac, linux, windows, etc... -- or left unprefixed, to set all platforms not specified. The rules apply in the order they're declared -sys_game_folder=TestProject +project_path=TestProject -- remote_filesystem - enable Virtual File System (VFS) -- This feature allows a remote instance of the game to run off assets @@ -363,7 +390,7 @@ mac_assets = osx_gl -- Example: 192.168.1.0/24 will allow any address starting with 192.168.1. -- Example: 192.168.0.0/16 will allow any address starting with 192.168. -- Example: 192.168.0.0/8 will allow any address starting with 192. --- white_list = +-- allowed_list = -- IP address and optionally port of the asset processor. -- Set your PC IP here: (and uncomment the next line) @@ -405,7 +432,7 @@ mac_wait_for_connect=0 )" , AZStd::fixed_vector{ - ConfigFileParams::SettingsKeyValuePair{"/sys_game_folder", AZStd::string_view{"TestProject"}}, + ConfigFileParams::SettingsKeyValuePair{"/project_path", AZStd::string_view{"TestProject"}}, ConfigFileParams::SettingsKeyValuePair{"/remote_filesystem", AZ::s64{0}}, ConfigFileParams::SettingsKeyValuePair{"/android_remote_filesystem", AZ::s64{0}}, ConfigFileParams::SettingsKeyValuePair{"/ios_remote_filesystem", AZ::s64{0}}, @@ -428,7 +455,7 @@ mac_wait_for_connect=0 // Parses a fake AssetProcessorPlatformConfig file which contains sections headers // and does not end with a newline ConfigFileParams{ "fake_AssetProcessorPlatformConfig.ini", R"( -; ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default. +; ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default. ; PLATFORM DEFINITIONS ; [Platform (unique identifier)] @@ -452,7 +479,7 @@ test_asset_processor_tag = test_value tags=tools,renderer,dx12,vulkan [Platform es3] -tags=android,mobile,renderer,vulkan +tags=android,mobile,renderer,vulkan ; With Comments at the end [Platform ios] tags=mobile,renderer,metal @@ -489,76 +516,30 @@ tags=tools,renderer,metal)" TEST_F(SettingsRegistryMergeUtilsCommandLineFixture, CommandLineArguments_MergeToSettingsRegistry_Success) { AZ::CommandLine commandLine; - commandLine.Parse({ "programname.exe", "--gamefolder", "--RemoteIp", "10.0.0.1", "--ScanFolders", R"(\a\b\c,\d\e\f)", "Foo", "Bat" }); + commandLine.Parse({ "programname.exe", "--project-path", "--RemoteIp", "10.0.0.1", "--ScanFolders", R"(\a\b\c,\d\e\f)", "Foo", "Bat" }); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_StoreCommandLine(*m_registry, commandLine); + AZ::SettingsRegistryMergeUtils::StoreCommandLineToRegistry(*m_registry, commandLine); + // Clear the CommandLine instance + commandLine = {}; - struct CommandLineVisitor - : AZ::SettingsRegistryInterface::Visitor - { - AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPointer, AZStd::string_view, - AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override - { - if (action == AZ::SettingsRegistryInterface::VisitAction::Begin) - { - // Strip off the last key of the jsonPointer and check if the path is the command line root switch key - // i.e "/../CommandLine/Switches - AZStd::optional optionName = AZ::StringFunc::TokenizeLast(jsonPointer, '/'); - if (jsonPointer == AZ::SettingsRegistryMergeUtils::CommandLineSwitchRootKey && optionName && !optionName->empty()) - { - // Add a empty mapping of option name to values if it is not in the map already - m_optionArguments[*optionName]; - } - } + EXPECT_TRUE(AZ::SettingsRegistryMergeUtils::GetCommandLineFromRegistry(*m_registry, commandLine)); - return AZ::SettingsRegistryInterface::VisitResponse::Continue; - } + ASSERT_TRUE(commandLine.HasSwitch("project-path")); + EXPECT_EQ(1, commandLine.GetNumSwitchValues("project-path")); + EXPECT_STREQ("", commandLine.GetSwitchValue("project-path", 0).c_str()); - void Visit(AZStd::string_view jsonPointer, AZStd::string_view, AZ::SettingsRegistryInterface::Type - , AZStd::string_view value) override - { - // Strip off the last key from the jsonPointer and return that in the option name parameter - AZStd::optional optionName = AZ::StringFunc::TokenizeLast(jsonPointer, '/'); - if (jsonPointer == AZ::SettingsRegistryMergeUtils::CommandLineMiscValuesRootKey) - { - m_positionalArguments.push_back(value); - } - else if (jsonPointer.starts_with(AZ::SettingsRegistryMergeUtils::CommandLineSwitchRootKey) && optionName) - { - // Option arguments are stored in array indices, underneath the option key - // Therefore remove another token from the jsonPointer to retrieve the actual option name - if (optionName = AZ::StringFunc::TokenizeLast(jsonPointer, '/'); optionName && !optionName->empty()) - { - // Add an entry for the option with the specified value - m_optionArguments[*optionName].push_back(value); - } - } - } + ASSERT_TRUE(commandLine.HasSwitch("remoteip")); + ASSERT_EQ(1, commandLine.GetNumSwitchValues("remoteip")); + EXPECT_STREQ("10.0.0.1", commandLine.GetSwitchValue("remoteip", 0).c_str()); - AZ::CommandLine::ParamMap m_optionArguments; - AZ::CommandLine::ParamContainer m_positionalArguments; - }; + ASSERT_TRUE(commandLine.HasSwitch("scanfolders")); + ASSERT_EQ(2, commandLine.GetNumSwitchValues("scanfolders")); + EXPECT_STREQ(R"(\a\b\c)", commandLine.GetSwitchValue("scanfolders", 0).c_str()); + EXPECT_STREQ(R"(\d\e\f)", commandLine.GetSwitchValue("scanfolders", 1).c_str()); - CommandLineVisitor commandLineVisitor; - EXPECT_TRUE(m_registry->Visit(commandLineVisitor, AZ::SettingsRegistryMergeUtils::CommandLineRootKey)); - EXPECT_EQ(3, commandLineVisitor.m_optionArguments.size()); - auto optionIter = commandLineVisitor.m_optionArguments.find("gamefolder"); - ASSERT_NE(commandLineVisitor.m_optionArguments.end(), optionIter); - EXPECT_EQ(0, optionIter->second.size()); - - optionIter = commandLineVisitor.m_optionArguments.find("remoteip"); - ASSERT_NE(commandLineVisitor.m_optionArguments.end(), optionIter); - ASSERT_EQ(1, optionIter->second.size()); - EXPECT_STREQ("10.0.0.1", optionIter->second[0].c_str()); - - optionIter = commandLineVisitor.m_optionArguments.find("scanfolders"); - ASSERT_NE(commandLineVisitor.m_optionArguments.end(), optionIter); - ASSERT_EQ(2, optionIter->second.size()); - EXPECT_STREQ(R"(\a\b\c)", optionIter->second[0].c_str()); - EXPECT_STREQ(R"(\d\e\f)", optionIter->second[1].c_str()); - - ASSERT_EQ(2, commandLineVisitor.m_positionalArguments.size()); - EXPECT_STREQ("Foo", commandLineVisitor.m_positionalArguments[0].c_str()); - EXPECT_STREQ("Bat", commandLineVisitor.m_positionalArguments[1].c_str()); + ASSERT_EQ(3, commandLine.GetNumMiscValues()); + EXPECT_STREQ("programname.exe", commandLine.GetMiscValue(0).c_str()); + EXPECT_STREQ("Foo", commandLine.GetMiscValue(1).c_str()); + EXPECT_STREQ("Bat", commandLine.GetMiscValue(2).c_str()); } -} +} diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp b/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp index e21876c939..f7651664bd 100644 --- a/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp +++ b/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp @@ -499,6 +499,38 @@ namespace SettingsRegistryTests EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test/Object/Type")); } + TEST_F(SettingsRegistryTest, VisitWithVisitor_EndOfPathArguments_MatchesValueNameArgument_ForAllIterations) + { + // Validate that every invocation of the Traverse and Visit command supplies a 'path' parameter + // whose end matches that of the 'valueName' parameter + AZStd::string json{ + R"({ + "Test": + { + "Object":{ "Type": "TestString" } + } + })" + }; + ASSERT_TRUE(this->m_registry->MergeSettings(json.c_str(), AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + struct : public AZ::SettingsRegistryInterface::Visitor + { + AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view path, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction, AZ::SettingsRegistryInterface::Type) override + { + EXPECT_TRUE(path.ends_with(valueName)); + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type , AZStd::string_view)override + { + EXPECT_TRUE(path.ends_with(valueName)); + } + } visitor; + + EXPECT_TRUE(this->m_registry->Visit(visitor, "")); + EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test")); + } + // // Object // @@ -730,7 +762,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object", "Object", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object/NullType", "NullType", SRI::Type::Null, SRI::VisitAction::Value), @@ -752,7 +784,7 @@ namespace SettingsRegistryTests RegistryEntry("/Test/Array/6", "6", SRI::Type::String, SRI::VisitAction::Value), RegistryEntry("/Test/Array", "Array", SRI::Type::Array, SRI::VisitAction::End), - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::End) + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End) }; Visit(expected, "/Test"); @@ -778,11 +810,11 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Layer1/Layer2", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Layer1/Layer2", "Layer2", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Layer1/Layer2/Layer3", "Layer3", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Layer1/Layer2/Layer3/StringType", "StringType", SRI::Type::String, SRI::VisitAction::Value), RegistryEntry("/Layer1/Layer2/Layer3", "Layer3", SRI::Type::Object, SRI::VisitAction::End), - RegistryEntry("/Layer1/Layer2", "", SRI::Type::Object, SRI::VisitAction::End) + RegistryEntry("/Layer1/Layer2", "Layer2", SRI::Type::Object, SRI::VisitAction::End) }; Visit(expected, "/Layer1/Layer2"); @@ -806,9 +838,9 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Object/0/0", "", SRI::Type::Array, SRI::VisitAction::Begin), + RegistryEntry("/Object/0/0", "0", SRI::Type::Array, SRI::VisitAction::Begin), RegistryEntry("/Object/0/0/0", "0", SRI::Type::String, SRI::VisitAction::Value), - RegistryEntry("/Object/0/0", "", SRI::Type::Array, SRI::VisitAction::End) + RegistryEntry("/Object/0/0", "0", SRI::Type::Array, SRI::VisitAction::End) }; Visit(expected, "/Object/0/0"); @@ -830,7 +862,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value), @@ -842,7 +874,7 @@ namespace SettingsRegistryTests RegistryEntry("/Test/Object2/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value), RegistryEntry("/Test/Object2", "Object2", SRI::Type::Object, SRI::VisitAction::End), - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::End) + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End) }; Visit(expected, "/Test"); @@ -864,7 +896,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin), RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value), @@ -878,7 +910,7 @@ namespace SettingsRegistryTests RegistryEntry("/Test/Array2/1", "1", SRI::Type::Integer, SRI::VisitAction::Value), RegistryEntry("/Test/Array2", "Array2", SRI::Type::Array, SRI::VisitAction::End), - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::End) + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End) }; Visit(expected, "/Test"); @@ -900,7 +932,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value), @@ -928,7 +960,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value), @@ -954,7 +986,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin), RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value), @@ -984,7 +1016,7 @@ namespace SettingsRegistryTests AZStd::vector expected = { - RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin), + RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin), RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin), RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value), @@ -1700,11 +1732,7 @@ namespace SettingsRegistryTests EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path")); } -#if AZ_TRAIT_DISABLE_FAILED_MERGESETTINGSFOLDER_CONFLICTINGSPECIALIZATIONS - TEST_F(SettingsRegistryTest, DISABLED_MergeSettingsFolder_ConflictingSpecializations_ReportsErrorAndReturnsFalse) -#else TEST_F(SettingsRegistryTest, MergeSettingsFolder_ConflictingSpecializations_ReportsErrorAndReturnsFalse) -#endif // AZ_TRAIT_DISABLE_FAILED_MERGESETTINGSFOLDER_CONFLICTINGSPECIALIZATIONS { CreateTestFile("Memory.test.editor.setreg", "{}"); CreateTestFile("Memory.editor.test.setreg", "{}"); diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index 0a38b6e9b5..8dcf6eb910 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -22,6 +22,35 @@ namespace AZ using StringFuncTest = AllocatorsFixture; + TEST_F(StringFuncTest, Equal_CaseSensitive_OnNonNullTerminatedStringView_Success) + { + constexpr AZStd::string_view testString1 = "Hello World IceCream"; + constexpr AZStd::string_view testString2 = "IceCream World Hello"; + constexpr bool caseSensitive = true; + EXPECT_TRUE(AZ::StringFunc::Equal(testString1.substr(6,5), testString2.substr(9,5), caseSensitive)); + } + TEST_F(StringFuncTest, Equal_CaseInsensitive_OnNonNullTerminatedStringView_Success) + { + constexpr AZStd::string_view testString1 = "Hello World IceCream"; + constexpr AZStd::string_view testString2 = "IceCream woRLd Hello"; + constexpr bool caseSensitive = false; + EXPECT_TRUE(AZ::StringFunc::Equal(testString1.substr(6, 5), testString2.substr(9, 5), caseSensitive)); + } + TEST_F(StringFuncTest, Equal_CaseSensitive_OnNonNullTerminatedStringView_WithDifferentCases_Fails) + { + constexpr AZStd::string_view testString1 = "Hello World IceCream"; + constexpr AZStd::string_view testString2 = "IceCream woRLd Hello"; + constexpr bool caseSensitive = true; + EXPECT_FALSE(AZ::StringFunc::Equal(testString1.substr(6, 5), testString2.substr(9, 5), caseSensitive)); + } + TEST_F(StringFuncTest, Equal_OnNonNullTerminatedStringView_WithDifferentSize_Fails) + { + constexpr AZStd::string_view testString1 = "Hello World IceCream"; + constexpr AZStd::string_view testString2 = "IceCream World Hello"; + + EXPECT_FALSE(AZ::StringFunc::Equal(testString1.substr(6, 6), testString2.substr(9, 5))); + } + // Strip out any trailing path separators TEST_F(StringFuncTest, Strip_ValidInputExtraEndingPathSeparators_Success) diff --git a/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h b/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h index 6af02c912b..c5a72521fa 100644 --- a/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h +++ b/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h @@ -70,18 +70,12 @@ namespace AzFramework /// Make path relative to the provided root. virtual void MakePathRelative(AZStd::string& /*fullPath*/, const char* /*rootPath*/) {} - /// Retrieves the asset root path for the application. - virtual const char* GetAssetRoot() const { return nullptr; } - /// Gets the engine root path where the modules for the current engine are located. virtual const char* GetEngineRoot() const { return nullptr; } /// Retrieves the app root path for the application. virtual const char* GetAppRoot() const { return nullptr; } - /// Sets the asset root path for the application. - virtual void SetAssetRoot(const char* /*assetRoot*/) {} - #pragma push_macro("GetCommandLine") #undef GetCommandLine /// Get the Command Line arguments passed in. @@ -117,8 +111,8 @@ namespace AzFramework /// Resolve a path thats relative to the engine folder to an absolute path virtual void ResolveEnginePath(AZStd::string& /*engineRelativePath*/) const {} - /// Calculate the branch token from the current application's asset root - virtual void CalculateBranchTokenForAppRoot(AZStd::string& token) const = 0; + /// Calculate the branch token from the current application's engine root + virtual void CalculateBranchTokenForEngineRoot(AZStd::string& token) const = 0; /*! * Returns a Type Uuid of the component for the given componentId and entityId. diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 6b1c4dd756..a363e79523 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -154,12 +154,12 @@ namespace AzFramework return AZ::Success(AZStd::move(loadedDescriptor)); } } - + Application::Application() - : Application(nullptr, nullptr) + : Application(nullptr, nullptr) { } - + Application::Application(int* argc, char*** argv) : ComponentApplication( argc ? *argc : 0, @@ -188,7 +188,6 @@ namespace AzFramework SetFileIOAliases(); } - ApplicationRequests::Bus::Handler::BusConnect(); AZ::UserSettingsFileLocatorBus::Handler::BusConnect(); NetSystemRequestBus::Handler::BusConnect(); @@ -238,14 +237,8 @@ namespace AzFramework { AZ::Entity* systemEntity = Create(descriptor, startupParameters); - // Attempt to use the "CacheGameFolder" key in the settings registry to set the asset root - // If that fails, fallback to using the App root as the asset root - if (!m_settingsRegistry->Get(m_assetRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheGameFolder)) - { - m_assetRoot = GetAppRoot(); - } // Sets FileIOAliases again in case the App root was overridden by the - // startupParamets in ComponentApplication::Create + // startupParameters in ComponentApplication::Create SetFileIOAliases(); if (systemEntity) @@ -268,7 +261,7 @@ namespace AzFramework void Application::PreModuleLoad() { // Calculate the engine root by reading the engine.json file - AZStd::string engineJsonPath = AZStd::string_view{ m_appRoot }; + AZStd::string engineJsonPath = AZStd::string_view{ m_engineRoot }; engineJsonPath += s_engineConfigFileName; AzFramework::StringFunc::Path::Normalize(engineJsonPath); AZ::IO::LocalFileIO localFileIO; @@ -276,7 +269,7 @@ namespace AzFramework if (readJsonResult.IsSuccess()) { - SetRootPath(RootPathType::EngineRoot, m_appRoot.c_str()); + SetRootPath(RootPathType::EngineRoot, m_engineRoot.c_str()); AZ_TracePrintf(s_azFrameworkWarningWindow, "Engine Path: %s\n", m_engineRoot.c_str()); } else @@ -410,17 +403,16 @@ namespace AzFramework azrtti_typeid(), azrtti_typeid(), AZ::Uuid("{624a7be2-3c7e-4119-aee2-1db2bdb6cc89}"), // ScriptDebugAgent - }); + }); return components; } - AZStd::string Application::ResolveFilePath(AZ::u32 providerId) + // UserSettingsFileLocatorBus + AZStd::string Application::ResolveFilePath([[maybe_unused]] AZ::u32 providerId) { - (void)providerId; - AZStd::string result; - AzFramework::StringFunc::Path::Join(GetAppRoot(), "UserSettings.xml", result, /*bCaseInsenitive*/false); + AzFramework::StringFunc::Path::Join(GetEngineRoot(), "UserSettings.xml", result, /*bCaseInsenitive*/false); return result; } @@ -451,11 +443,6 @@ namespace AzFramework outModules.emplace_back(aznew AzFrameworkModule()); } - const char* Application::GetAssetRoot() const - { - return m_assetRoot.c_str(); - } - const char* Application::GetAppRoot() const { return m_appRoot.c_str(); @@ -516,21 +503,15 @@ namespace AzFramework engineRelativePath = fullPath; } - void Application::CalculateBranchTokenForAppRoot(AZStd::string& token) const - { - AzFramework::StringFunc::AssetPath::CalculateBranchToken(AZStd::string(m_appRoot), token); - } - - //////////////////////////////////////////////////////////////////////////// - void Application::SetAssetRoot(const char* assetRoot) + void Application::CalculateBranchTokenForEngineRoot(AZStd::string& token) const { - SetRootPath(RootPathType::AssetRoot, assetRoot); + AzFramework::StringFunc::AssetPath::CalculateBranchToken(AZStd::string(m_engineRoot), token); } //////////////////////////////////////////////////////////////////////////// void Application::MakePathRootRelative(AZStd::string& fullPath) { - MakePathRelative(fullPath, m_appRoot.c_str()); + MakePathRelative(fullPath, m_engineRoot.c_str()); } //////////////////////////////////////////////////////////////////////////// @@ -538,7 +519,12 @@ namespace AzFramework { // relative file paths wrt AssetRoot are always lowercase AZStd::to_lower(fullPath.begin(), fullPath.end()); - MakePathRelative(fullPath, m_assetRoot.c_str()); + AZStd::string cacheAssetPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(cacheAssetPath, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } + MakePathRelative(fullPath, cacheAssetPath.c_str()); } //////////////////////////////////////////////////////////////////////////// @@ -592,8 +578,8 @@ namespace AzFramework //////////////////////////////////////////////////////////////////////////// void Application::PumpSystemEventLoopWhileDoingWorkInNewThread(const AZStd::chrono::milliseconds& eventPumpFrequency, - const AZStd::function& workForNewThread, - const char* newThreadName) + const AZStd::function& workForNewThread, + const char* newThreadName) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework); @@ -604,7 +590,7 @@ namespace AzFramework AZStd::thread newThread([&workForNewThread, &binarySemaphore, &newThreadName] { AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::AzFramework, - "Application::PumpSystemEventLoopWhileDoingWorkInNewThread:ThreadWorker %s", newThreadName); + "Application::PumpSystemEventLoopWhileDoingWorkInNewThread:ThreadWorker %s", newThreadName); workForNewThread(); binarySemaphore.release(); @@ -615,7 +601,7 @@ namespace AzFramework } { AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzFramework, - "Application::PumpSystemEventLoopWhileDoingWorkInNewThread:WaitOnThread %s", newThreadName); + "Application::PumpSystemEventLoopWhileDoingWorkInNewThread:WaitOnThread %s", newThreadName); newThread.join(); } @@ -678,18 +664,6 @@ namespace AzFramework } } break; - case RootPathType::AssetRoot: - { - AZ_Assert(sourceLen < m_assetRoot.max_size(), "String overflow for Asset Root: %s", source); - m_assetRoot = source; - - AZStd::replace(std::begin(m_assetRoot), std::end(m_assetRoot), AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR); - if (appendTrailingPathSep) - { - m_assetRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR); - } - } - break; case RootPathType::EngineRoot: { AZ_Assert(sourceLen < m_engineRoot.max_size(), "String overflow for Engine Root: %s", source); @@ -706,95 +680,102 @@ namespace AzFramework AZ_Assert(false, "Invalid RootPathType (%d)", static_cast(type)); } } + + + static void CreateUserCache(const AZ::IO::FixedMaxPath& cacheUserPath, AZ::IO::FileIOBase& fileIoBase) + { + // The number of max attempts ultimately dictates the number of Lumberyard instances that can run + // simultaneously. This should be a reasonably high number so that it doesn't artificially limit + // the number of instances (ex: parallel level exports via multiple Editor runs). It also shouldn't + // be set *infinitely* high - each cache folder is GBs in size, and finding a free directory is a + // linear search, so the more instances we allow, the longer the search will take. + // 128 seems like a reasonable compromise. + constexpr int maxAttempts = 128; + + constexpr const char* userCachePathFilename{ "Cache" }; + AZ::IO::FixedMaxPath userCachePath = cacheUserPath / userCachePathFilename; +#if AZ_TRAIT_OS_IS_HOST_OS_PLATFORM + int attemptNumber; + for (attemptNumber = 0; attemptNumber < maxAttempts; ++attemptNumber) + { + if (attemptNumber != 0) + { + userCachePath.ReplaceFilename(AZStd::string_view{ AZ::IO::FixedMaxPathString::format("%s%i", userCachePathFilename, attemptNumber) }); + } + + // if the directory already exists, check for locked file + auto cacheLockFilePath = userCachePath / "lockfile.txt"; + + constexpr auto LockFileMode = AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY + | AZ::IO::SystemFile::SF_OPEN_CREATE + | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH; + if (AZ::IO::SystemFile lockFileHandle; lockFileHandle.Open(cacheLockFilePath.c_str(), LockFileMode)) + { + break; + } + } + + if (attemptNumber >= maxAttempts) + { + userCachePath.ReplaceFilename(userCachePathFilename); + AZ_TracePrintf("Application", "Couldn't find a valid asset cache folder after %i attempts." + " Setting cache folder to %s\n", maxAttempts, userCachePath.c_str()); + } +#endif + + fileIoBase.SetAlias("@usercache@", userCachePath.c_str()); + } + void Application::SetFileIOAliases() { - if (AZ::IO::FileIOBase::GetInstance() == m_archiveFileIO.get()) + if (m_archiveFileIO) { auto fileIoBase = m_archiveFileIO.get(); // Set up the default file aliases based on the settings registry - fileIoBase->SetAlias("@root@", GetAppRoot()); - fileIoBase->SetAlias("@assets@", GetAssetRoot()); - fileIoBase->SetAlias("@engroot@", GetAppRoot()); - fileIoBase->SetAlias("@devroot@", GetAppRoot()); - fileIoBase->SetAlias("@devassets@", GetAppRoot()); + fileIoBase->SetAlias("@assets@", ""); + fileIoBase->SetAlias("@root@", GetEngineRoot()); + fileIoBase->SetAlias("@engroot@", GetEngineRoot()); + fileIoBase->SetAlias("@projectroot@", GetEngineRoot()); fileIoBase->SetAlias("@exefolder@", GetExecutableFolder()); + { - AZ::SettingsRegistryInterface::FixedValueString pathAliases; - if (m_settingsRegistry->Get(pathAliases, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) + AZ::IO::FixedMaxPath pathAliases; + if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) { - fileIoBase->SetAlias("@root@", pathAliases.c_str()); + fileIoBase->SetAlias("@projectcache@", pathAliases.c_str()); } pathAliases.clear(); - if (m_settingsRegistry->Get(pathAliases, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheGameFolder)) + if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { + fileIoBase->SetAlias("@projectplatformcache@", pathAliases.c_str()); fileIoBase->SetAlias("@assets@", pathAliases.c_str()); + fileIoBase->SetAlias("@root@", pathAliases.c_str()); // Deprecated Use @projectplatformcache@ } pathAliases.clear(); - if (m_settingsRegistry->Get(pathAliases, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) + if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) { fileIoBase->SetAlias("@engroot@", pathAliases.c_str()); - fileIoBase->SetAlias("@devroot@", pathAliases.c_str()); + fileIoBase->SetAlias("@devroot@", pathAliases.c_str()); // Deprecated - Use @engroot@ } pathAliases.clear(); - if (m_settingsRegistry->Get(pathAliases, AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder)) + if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) { - fileIoBase->SetAlias("@devassets@", pathAliases.c_str()); + fileIoBase->SetAlias("@devassets@", pathAliases.c_str()); // Deprecated - Use @projectsourceassets@ + fileIoBase->SetAlias("@projectroot@", pathAliases.c_str()); + fileIoBase->SetAlias("@projectsourceassets@", (pathAliases / "Assets").c_str()); } } + AZ::IO::FixedMaxPath projectUserPath; + if (m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) { - auto userPath = AZ::StringFunc::Path::FixedString::format("%s" AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "user", fileIoBase->GetAlias("@root@")); - fileIoBase->SetAlias("@user@", userPath.c_str()); - } - - { - auto logPath = AZ::StringFunc::Path::FixedString::format("%s" AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "log", fileIoBase->GetAlias("@user@")); - fileIoBase->SetAlias("@log@", logPath.c_str()); + fileIoBase->SetAlias("@user@", projectUserPath.c_str()); + AZ::IO::FixedMaxPath projectLogPath = projectUserPath / "log"; + fileIoBase->SetAlias("@log@", projectLogPath.c_str()); + fileIoBase->CreatePath(projectLogPath.c_str()); // Create the log directory at this point - // Create the Log folder if it doesn't exist - fileIoBase->CreatePath("@log@"); + CreateUserCache(projectUserPath, *fileIoBase); } - - auto cachePathOriginal = AZ::StringFunc::Path::FixedString::format("%s" AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "cache", fileIoBase->GetAlias("@user@")); - // The number of max attempts ultimately dictates the number of Lumberyard instances that can run - // simultaneously. This should be a reasonably high number so that it doesn't artificially limit - // the number of instances (ex: parallel level exports via multiple Editor runs). It also shouldn't - // be set *infinitely* high - each cache folder is GBs in size, and finding a free directory is a - // linear search, so the more instances we allow, the longer the search will take. - // 128 seems like a reasonable compromise. - constexpr int maxAttempts = 128; - - AZ::StringFunc::Path::FixedString cachePath(cachePathOriginal); - -#if AZ_TRAIT_OS_IS_HOST_OS_PLATFORM - int attemptNumber; - for (attemptNumber = 0; attemptNumber < maxAttempts; ++attemptNumber) - { - if (attemptNumber != 0) - { - cachePath = AZ::StringFunc::Path::FixedString::format("%s%i", cachePathOriginal.c_str(), attemptNumber); - } - - fileIoBase->CreatePath(cachePath.c_str()); - // if the directory already exists, check for locked file - auto cacheLockFilePath = AZ::StringFunc::Path::FixedString::format("%s" AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "lockfile.txt", cachePath.c_str()); - - AZ::IO::HandleType lockFileHandle; - if (fileIoBase->Open(cacheLockFilePath.c_str(), AZ::IO::OpenMode::ModeWrite, lockFileHandle)) - { - fileIoBase->Close(lockFileHandle); - break; - } - } - - if (attemptNumber >= maxAttempts) - { - cachePath = cachePathOriginal; - AZ_TracePrintf("Application", "Couldn't find a valid asset cache folder after %i attempts." - " Setting cache folder to cachePath %s\n", maxAttempts, cachePath.c_str()); - } -#endif - fileIoBase->SetAlias("@cache@", cachePath.c_str()); } } diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.h b/Code/Framework/AzFramework/AzFramework/Application/Application.h index 1fee897260..b4abccd116 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.h +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.h @@ -100,11 +100,10 @@ namespace AzFramework ////////////////////////////////////////////////////////////////////////// //! ApplicationRequests::Bus::Handler - const char* GetAssetRoot() const override; const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } const char* GetAppRoot() const override; void ResolveEnginePath(AZStd::string& engineRelativePath) const override; - void CalculateBranchTokenForAppRoot(AZStd::string& token) const override; + void CalculateBranchTokenForEngineRoot(AZStd::string& token) const override; #pragma push_macro("GetCommandLine") #undef GetCommandLine @@ -112,7 +111,6 @@ namespace AzFramework #pragma pop_macro("GetCommandLine") const CommandLine* GetApplicationCommandLine() override { return &m_commandLine; } - void SetAssetRoot(const char* assetRoot) override; void MakePathRootRelative(AZStd::string& fullPath) override; void MakePathAssetRootRelative(AZStd::string& fullPath) override; void MakePathRelative(AZStd::string& fullPath, const char* rootPath) override; @@ -180,9 +178,6 @@ namespace AzFramework AZ::StringFunc::Path::FixedString m_configFilePath; - AZ::StringFunc::Path::FixedString m_assetRoot; - AZ::StringFunc::Path::FixedString m_engineRoot; ///> Location of the engine root folder that this application is based on - AZStd::unique_ptr m_directFileIO; ///> The Direct file IO instance is a LocalFileIO. AZStd::unique_ptr m_archiveFileIO; ///> The Default file IO instance is a ArchiveFileIO. AZStd::unique_ptr m_archive; ///> The AZ::IO::Instance @@ -194,7 +189,6 @@ namespace AzFramework enum class RootPathType { AppRoot, - AssetRoot, EngineRoot }; void SetRootPath(RootPathType type, const char* source); diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index 1e07555670..0fb85431d1 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -92,7 +92,8 @@ namespace AZ::IO::ArchiveInternal convertedPath->Native().replace(0, aliasToLookFor.size(), aliasToReplaceWith); } // lowercase path if it starts with either the @assets@ or @root@ alias - if (convertedPath->Native().starts_with("@assets@") || convertedPath->Native().starts_with("@root@")) + if (convertedPath->Native().starts_with("@assets@") || convertedPath->Native().starts_with("@root@") + || convertedPath->Native().starts_with("@projectplatformcache@")) { AZStd::to_lower(convertedPath->Native().begin(), convertedPath->Native().end()); } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp index 6a6536a1dd..f0bfa6888e 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp @@ -604,4 +604,14 @@ namespace AZ::IO } return realUnderlyingFileIO->ResolvePath(resolvedPath, path); } + + bool ArchiveFileIO::ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const + { + FileIOBase* realUnderlyingFileIO = FileIOBase::GetDirectInstance(); + if (!realUnderlyingFileIO) + { + return false; + } + return realUnderlyingFileIO->ReplaceAlias(replacedAliasPath, path); + } }//namespace AZ:IO diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h index d5ece5e637..ead0c8caf3 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h @@ -75,6 +75,7 @@ namespace AZ::IO bool ResolvePath(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const override; bool ResolvePath(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ResolvePath; + bool ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const override; bool GetFilename(IO::HandleType fileHandle, char* filename, AZ::u64 filenameSize) const override; //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp index 69f313db15..7cb0090ef5 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -525,7 +526,10 @@ namespace AzFramework AZStd::lock_guard lock(m_registryMutex); // Get asset root from application. - EBUS_EVENT_RESULT(m_assetRoot, AzFramework::ApplicationRequests::Bus, GetAssetRoot); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(m_assetRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } // Reflect registry for serialization. AZ::SerializeContext* serializeContext = nullptr; diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemBus.h b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemBus.h index 33271ad28f..98c3833ec0 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemBus.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemBus.h @@ -67,7 +67,7 @@ namespace AzFramework //! Name of the game project that is used for negotiating a connection with the AssetProcessor //! The AssetProcessor needs to be processing Assets for the specified game project - //! (Can be queried from Settings Registry - "sys_game_folder") + //! (Can be queried from Settings Registry - "project_name" under the ProjectSettingsRootKey) AZStd::fixed_string<64> m_projectName; //! The IP address to use either connect to or from the AssetProcessor //! (Can be queried from Settings Registry - "remote_ip") diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.h b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.h index acad8c2273..f8ad2a5eef 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.h @@ -25,7 +25,6 @@ namespace AzFramework namespace AssetSystem { constexpr char BranchToken[] = "assetProcessor_branch_token"; - constexpr char ProjectName[] = "sys_game_folder"; constexpr char Assets[] = "assets"; constexpr char AssetProcessorRemoteIp[] = "remote_ip"; constexpr char AssetProcessorRemotePort[] = "remote_port"; diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponentHelper.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponentHelper.cpp index 1fcd887d88..618fd92ac1 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponentHelper.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponentHelper.cpp @@ -26,7 +26,7 @@ namespace AzFramework::AssetSystem::Platform // Declare platform specific LaunchAssetProcessor function bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view appRoot, - AZStd::string_view projectName); + AZStd::string_view projectPath); } namespace AzFramework @@ -67,23 +67,21 @@ namespace AzFramework auto settingsRegistry = AZ::SettingsRegistry::Get(); + // Add the engine path to the launch command if available from the Settings Registry AZ::SettingsRegistryInterface::FixedValueString engineRootFolder; - // Add the app-root to the launch command if available from the Settings Registry if (settingsRegistry) { settingsRegistry->Get(engineRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - // Add the active game project to the launch from the Settings Registry - const auto gameProjectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - AZ::SettingsRegistryInterface::FixedValueString gameProjectName; + // Add the active project's path to the launch command if available from the Settings Registry + AZ::SettingsRegistryInterface::FixedValueString projectPath; if (settingsRegistry) { - settingsRegistry->Get(gameProjectName, gameProjectKey); + settingsRegistry->Get(projectPath, AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } - if (!Platform::LaunchAssetProcessor(executableDirectory, engineRootFolder, gameProjectName)) + if (!Platform::LaunchAssetProcessor(executableDirectory, engineRootFolder, projectPath)) { // if we are unable to launch asset processor AzFramework::AssetSystemInfoBus::Broadcast(&AzFramework::AssetSystem::AssetSystemInfoNotifications::OnError, AssetSystemErrors::ASSETSYSTEM_FAILED_TO_LAUNCH_ASSETPROCESSOR); @@ -179,24 +177,22 @@ namespace AzFramework { // Read Branch Token from Settings Registry - AZ::s64 branchToken64; - if (!settingsRegistry->Get(branchToken64, AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", + AZStd::string branchToken; + if (!settingsRegistry->Get(branchToken, AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::BranchToken))) { // The first time the AssetProcessor runs within a branch the bootstrap.cfg does not have a branch token set // Therefore it is not an error for the branch token to not be in the bootstrap.cfg file - AZStd::string branchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, branchToken); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, branchToken); AZ_TracePrintfOnce("AssetSystemComponent", "Failed to read branch token from bootstrap. Calculating Branch Token: %s\n", branchToken.c_str()); outputConnectionSettings.m_branchToken = branchToken; } else { - outputConnectionSettings.m_branchToken = AZStd::fixed_string<32>::format("0x%08X", aznumeric_cast(branchToken64)); + outputConnectionSettings.m_branchToken = AZStd::string_view{ branchToken }; if (outputConnectionSettings.m_branchToken.empty()) { - AZStd::string branchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, branchToken); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, branchToken); AZ_TracePrintfOnce("AssetSystemComponent", "Branch token read from bootstrap is empty. Calculating Branch Token: %s\n", branchToken.c_str()); outputConnectionSettings.m_branchToken = branchToken; } @@ -205,19 +201,14 @@ namespace AzFramework { // Read Project Name from Settings Registry - AZ::SettingsRegistryInterface::FixedValueString projectName; - if (!settingsRegistry->Get(projectName, AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName))) + AZ::SettingsRegistryInterface::FixedValueString projectName = AZ::Utils::GetProjectName(); + if (projectName.empty()) { - AZ_Error("AssetSystemComponent", false, "Failed to read project name from bootstrap"); + AZ_Error("AssetSystemComponent", false, "Failed to read project name from registry"); result = false; } + outputConnectionSettings.m_projectName = projectName; - if (outputConnectionSettings.m_projectName.empty()) - { - AZ_Error("AssetSystemComponent", false, "Project name read from bootstrap is empty"); - result = false; - } } // Read the direction in which a connection to the Asset Processor should be from using the Settings Registry diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp index 0d11b7d065..6108d401aa 100644 --- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp +++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp @@ -244,9 +244,9 @@ namespace AzFramework AZStd::string FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType fileTagType) { AZStd::string destinationFilePath; - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AzFramework::StringFunc::Path::ConstructFull(appRoot, EngineName, fileTagType == FileTagType::Exclude ? ExcludeFileName : IncludeFileName, AzFramework::FileTag::FileTagAsset::Extension(), destinationFilePath, true); + const char* engineRoot = nullptr; + AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AzFramework::StringFunc::Path::ConstructFull(engineRoot, EngineName, fileTagType == FileTagType::Exclude ? ExcludeFileName : IncludeFileName, AzFramework::FileTag::FileTagAsset::Extension(), destinationFilePath, true); return destinationFilePath; } diff --git a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp new file mode 100644 index 0000000000..73a0209692 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp @@ -0,0 +1,95 @@ +/* +* 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. +* +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace AzFramework +{ + GemInfo::GemInfo(AZStd::string name) + : m_gemName(AZStd::move(name)) + { + } + + bool GetGemsInfo(AZStd::vector& gemInfoList, AZ::SettingsRegistryInterface& settingsRegistry) + { + AZStd::vector gemModuleSourcePaths; + + struct GemSourcePathsVisitor + : AZ::SettingsRegistryInterface::Visitor + { + GemSourcePathsVisitor(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::vector& gemInfoList) + : m_settingsRegistry(settingsRegistry) + , m_gemInfoList(gemInfoList) + { + } + + void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type, + AZStd::string_view value) override + { + AZStd::string_view jsonPointerPath{ path }; + // Remove the array index from the path and check if the JSON path ends with "/SourcePaths" + AZ::StringFunc::TokenizeLast(jsonPointerPath, '/'); + if (jsonPointerPath.ends_with("/SourcePaths")) + { + AZStd::string_view gemName; + // The parent key of the "SourcePaths" field is the gem name + AZ::StringFunc::TokenizeLast(jsonPointerPath, '/'); // Peel off "/SourcePaths" + // Retrieve Gem name + if (auto gemNameToken = AZ::StringFunc::TokenizeLast(jsonPointerPath, '/'); gemNameToken.has_value()) + { + gemName = *gemNameToken; + } + + auto FindGemInfoByName = [gemName](const GemInfo& gemInfo) + { + return gemName == gemInfo.m_gemName; + }; + auto gemInfoFoundIter = AZStd::find_if(m_gemInfoList.begin(), m_gemInfoList.end(), FindGemInfoByName); + GemInfo& gemInfo = gemInfoFoundIter != m_gemInfoList.end() ? *gemInfoFoundIter : m_gemInfoList.emplace_back(gemName); + + AZ::IO::Path& gemAbsPath = gemInfo.m_absoluteSourcePaths.emplace_back(value); + // Resolve any file aliases first - Do not use ResolvePath() as that assumes + // any relative path is underneath the @assets@ alias + if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) + { + AZ::IO::FixedMaxPath replacedAliasPath; + if (fileIoBase->ReplaceAlias(replacedAliasPath, value)) + { + gemAbsPath = AZ::IO::PathView(replacedAliasPath); + } + } + + // The current assumption is that the gem source path is the relative to the engine root + AZ::IO::FixedMaxPath engineRootPath; + m_settingsRegistry.Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + gemAbsPath = (engineRootPath / gemAbsPath).LexicallyNormal(); + } + } + + AZ::SettingsRegistryInterface& m_settingsRegistry; + AZStd::vector& m_gemInfoList; + }; + + GemSourcePathsVisitor visitor{ settingsRegistry, gemInfoList }; + constexpr auto gemListKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::OrganizationRootKey) + + "/Gems"; + settingsRegistry.Visit(visitor, gemListKey); + + return true; + } +} diff --git a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h new file mode 100644 index 0000000000..11a8b6a856 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h @@ -0,0 +1,41 @@ +/* +* 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 + +#include +#include +#include +#include + +namespace AZ +{ + class SettingsRegistryInterface; +} + +namespace AzFramework +{ + //! This struct stores gem related information + struct GemInfo + { + AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0); + GemInfo(AZStd::string name); + GemInfo() = default; + AZStd::string m_gemName; //!< A friendly display name, not to be used for any pathing stuff. + AZStd::vector m_absoluteSourcePaths; //!< Where the gem's source path folder are located(as an absolute path) + + static constexpr const char* GetGemAssetFolder() { return "Assets"; } + }; + + //! Returns a list of GemInfo of all the gems that are active for the for the specified game project. + //! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param. + bool GetGemsInfo(AZStd::vector& gemInfoList, AZ::SettingsRegistryInterface& settingsRegistry); +} diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp index a607d2db36..bf60241419 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace AZ @@ -479,10 +480,9 @@ namespace AZ azstrncpy(resolvedPath, resolvedPathSize, path, pathLen + 1); //see if the absolute path uses @assets@ or @root@, if it does lowercase the relative part - if (!LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@assets@"))) - { - LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@root@")); - } + [[maybe_unused]] bool lowercasePath = LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@assets@")) + || LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@root@")) + || LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@projectplatformcache@")); ToUnixSlashes(resolvedPath, resolvedPathSize); return true; @@ -707,10 +707,9 @@ namespace AZ size_t keyLen = alias.first.length(); if (azstrnicmp(resolvedPath, key, keyLen) == 0) // we only support aliases at the front of the path { - if(azstrnicmp(key, "@assets@", 8) == 0 || azstrnicmp(key, "@root@", 6) == 0) - { - AZStd::to_lower(resolvedPath, resolvedPath + resolvedPathSize); - } + [[maybe_unused]] bool lowercasePath = LowerIfBeginsWith(resolvedPath, resolvedPathSize, "@assets@") + || LowerIfBeginsWith(resolvedPath, resolvedPathSize, "@root@") + || LowerIfBeginsWith(resolvedPath, resolvedPathSize, "@projectplatformcache@"); const char* dest = alias.second.c_str(); size_t destLen = alias.second.length(); @@ -742,6 +741,44 @@ namespace AZ return false; } + bool LocalFileIO::ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const + { + if (path.empty()) + { + replacedAliasPath = path; + return true; + } + + AZStd::string_view pathStrView = path.Native(); + for (const auto& [aliasKey, aliasValue] : m_aliases) + { + if (AZ::StringFunc::StartsWith(pathStrView, aliasKey)) + { + // Reduce of the size result result path by the size of the and add the resolved alias size + AZStd::string_view postAliasView = pathStrView.substr(aliasKey.size()); + size_t requiredFixedMaxPathSize = postAliasView.size(); + requiredFixedMaxPathSize += aliasValue.size(); + + // The replaced alias path is greater than 1024 characters, return false + if (requiredFixedMaxPathSize > replacedAliasPath.Native().max_size()) + { + return false; + } + replacedAliasPath.Native() = AZ::IO::FixedMaxPathString(AZStd::string_view{ aliasValue }); + replacedAliasPath.Native() += postAliasView; + return true; + } + } + + if (pathStrView.size() > replacedAliasPath.Native().max_size()) + { + return false; + } + + replacedAliasPath = path; + return true; + } + bool LocalFileIO::GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const { AZStd::lock_guard lock(m_openFileGuard); diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h index dd8e8984a7..1c8289432c 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h @@ -75,6 +75,7 @@ namespace AZ bool ResolvePath(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const override; bool ResolvePath(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ResolvePath; + bool ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const override; bool GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const override; bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const; diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp index 2c3a480bc2..de342f6682 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp @@ -830,6 +830,15 @@ namespace AZ return false; } + bool NetworkFileIO::ReplaceAlias([[maybe_unused]] AZ::IO::FixedMaxPath& replaceAliasPath, [[maybe_unused]] const AZ::IO::PathView& path) const + { + REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::ReplaceAlias(path=%.*s)", + aznumeric_cast(path.Native().size()), path.Native.data()).c_str()); + REMOTEFILE_LOG_APPEND(AZStd::string::format("NetworkFileIO::ReplaceAlias(path=%.*s) return false", + aznumeric_cast(path.Native().size()), path.Native().data()).c_str()); + return false; + } + bool NetworkFileIO::GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const { REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::GetFilename(fileHandle=%u, filename=%s, filenamesize=%u)", fileHandle, filename?filename:"nullptr", filenameSize).c_str()); @@ -1388,6 +1397,11 @@ namespace AZ return m_excludedFileIO ? m_excludedFileIO->ResolvePath(resolvedPath, path) : false; } + bool RemoteFileIO::ReplaceAlias(AZ::IO::FixedMaxPath& replaceAliasPath, const AZ::IO::PathView& path) const + { + return m_excludedFileIO ? m_excludedFileIO->ReplaceAlias(replaceAliasPath, path) : false; + } + #ifdef REMOTEFILEIO_CACHE_FILETREE bool RemoteFileIO::Exists(const char* filePath) { diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h index 98654efe00..aac43e55d2 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h @@ -113,6 +113,7 @@ namespace AZ bool ResolvePath(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const override; bool ResolvePath(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ResolvePath; + bool ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const override; bool GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const override; bool IsRemoteIOEnabled() override; //////////////////////////////////////////////////////////////////////////////////////////// @@ -203,6 +204,7 @@ namespace AZ bool ResolvePath(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const override; bool ResolvePath(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ResolvePath; + bool ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const override; #ifdef REMOTEFILEIO_CACHE_FILETREE bool Exists(const char* filePath) override; diff --git a/Code/Framework/AzFramework/AzFramework/Logging/LogFile.cpp b/Code/Framework/AzFramework/AzFramework/Logging/LogFile.cpp index e9601a563a..8f6a728a8d 100644 --- a/Code/Framework/AzFramework/AzFramework/Logging/LogFile.cpp +++ b/Code/Framework/AzFramework/AzFramework/Logging/LogFile.cpp @@ -59,7 +59,6 @@ namespace AzFramework namespace { const char* suffix = ".log"; - const char* loggingDirectoryName = "logs"; const int maxLogFiles = 5; void TimeNowAsString(char* buffer, size_t len) @@ -155,7 +154,7 @@ namespace AzFramework m_directoryName = AZStd::string(baseDirectory); //Construct the file path - if (!AzFramework::StringFunc::Path::ConstructFull(baseDirectory, loggingDirectoryName, fileName, suffix, m_filePath)) + if (!AzFramework::StringFunc::Path::ConstructFull(baseDirectory, fileName, suffix, m_filePath)) { return; } @@ -193,7 +192,7 @@ namespace AzFramework AZStd::string backupFileName; //Construct the backup file path - if (!AzFramework::StringFunc::Path::ConstructFull(m_directoryName.c_str(), loggingDirectoryName, m_fileName.c_str(), newSuffix.c_str(), backupFileName)) + if (!AzFramework::StringFunc::Path::ConstructFull(m_directoryName.c_str(), m_fileName.c_str(), newSuffix.c_str(), backupFileName)) { AZ_Warning("Log Component", false, "Unable to construct the backup file path"); return ""; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommon_fwd.h b/Code/Framework/AzFramework/AzFramework/Process/ProcessCommon_fwd.h similarity index 95% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommon_fwd.h rename to Code/Framework/AzFramework/AzFramework/Process/ProcessCommon_fwd.h index 9cb4b41040..b605bb9d49 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommon_fwd.h +++ b/Code/Framework/AzFramework/AzFramework/Process/ProcessCommon_fwd.h @@ -12,7 +12,7 @@ #pragma once -namespace AzToolsFramework +namespace AzFramework { // Type of communication between parent and child processes enum ProcessCommunicationType @@ -37,4 +37,4 @@ namespace AzToolsFramework class StdProcessCommunicator; class StdProcessCommunicatorForChildProcess; class CommunicatorHandleImpl; -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommunicator.cpp b/Code/Framework/AzFramework/AzFramework/Process/ProcessCommunicator.cpp similarity index 97% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommunicator.cpp rename to Code/Framework/AzFramework/AzFramework/Process/ProcessCommunicator.cpp index 711fdcc384..bfd5d04ab6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommunicator.cpp +++ b/Code/Framework/AzFramework/AzFramework/Process/ProcessCommunicator.cpp @@ -10,10 +10,9 @@ * */ -#include "AzToolsFramework_precompiled.h" -#include +#include -namespace AzToolsFramework +namespace AzFramework { void ProcessOutput::Clear() { @@ -193,4 +192,4 @@ namespace AzToolsFramework m_stdErrWrite->Close(); m_initialized = false; } -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommunicator.h b/Code/Framework/AzFramework/AzFramework/Process/ProcessCommunicator.h similarity index 90% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommunicator.h rename to Code/Framework/AzFramework/AzFramework/Process/ProcessCommunicator.h index 8d02abe464..fe49ed5d7e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessCommunicator.h +++ b/Code/Framework/AzFramework/AzFramework/Process/ProcessCommunicator.h @@ -15,17 +15,16 @@ #include #include #include -#include - -#if defined(AZ_PLATFORM_WINDOWS) - #include -#elif AZ_TRAIT_OS_PLATFORM_APPLE - #include -#elif defined(AZ_PLATFORM_LINUX) - #include +#include +#include + +#if AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT +#include +#else +#include #endif -namespace AzToolsFramework +namespace AzFramework { class ProcessOutput { @@ -151,7 +150,7 @@ namespace AzToolsFramework : public ProcessCommunicator { public: - virtual bool CreatePipesForProcess(AzToolsFramework::ProcessData* processData) = 0; + virtual bool CreatePipesForProcess(AzFramework::ProcessData* processData) = 0; }; /** @@ -169,7 +168,7 @@ namespace AzToolsFramework ~StdInOutProcessCommunicator(); ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::ProcessCommunicator overrides + // AzFramework::ProcessCommunicator overrides bool IsValid() const override; AZ::u32 ReadError(void* readBuffer, AZ::u32 bufferSize) override; AZ::u32 PeekError() override; @@ -179,7 +178,7 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::StdProcessCommunicator overrides + // AzFramework::StdProcessCommunicator overrides bool CreatePipesForProcess(ProcessData* processData) override; ////////////////////////////////////////////////////////////////////////// @@ -188,7 +187,7 @@ namespace AzToolsFramework void CloseAllHandles(); ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::ProcessCommunicator overrides + // AzFramework::ProcessCommunicator overrides void WaitForReadyOutputs(OutputStatus& outputStatus) const override; ////////////////////////////////////////////////////////////////////////// @@ -214,7 +213,7 @@ namespace AzToolsFramework ~StdInOutProcessCommunicatorForChildProcess(); ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::ProcessCommunicatorForChildProcess overrides + // AzFramework::ProcessCommunicatorForChildProcess overrides bool IsValid() const override; AZ::u32 WriteError(const void* writeBuffer, AZ::u32 bytesToWrite) override; AZ::u32 WriteOutput(const void* writeBuffer, AZ::u32 bytesToWrite) override; @@ -223,7 +222,7 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::StdProcessCommunicatorForChildProcess overrides + // AzFramework::StdProcessCommunicatorForChildProcess overrides bool AttachToExistingPipes() override; ////////////////////////////////////////////////////////////////////////// @@ -236,4 +235,4 @@ namespace AzToolsFramework StdProcessCommunicatorHandle m_stdErrWrite; bool m_initialized = false; }; -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessWatcher.cpp b/Code/Framework/AzFramework/AzFramework/Process/ProcessWatcher.cpp similarity index 90% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessWatcher.cpp rename to Code/Framework/AzFramework/AzFramework/Process/ProcessWatcher.cpp index 219fcf046b..ff3ba2ef25 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessWatcher.cpp +++ b/Code/Framework/AzFramework/AzFramework/Process/ProcessWatcher.cpp @@ -10,22 +10,20 @@ * */ -#include "AzToolsFramework_precompiled.h" #include #include #include #include -#include -#include +#include +#include -namespace AzToolsFramework +namespace AzFramework { - bool ProcessWatcher::LaunchProcessAndRetrieveOutput(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType, AzToolsFramework::ProcessOutput& outProcessOutput) + bool ProcessWatcher::LaunchProcessAndRetrieveOutput(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType, AzFramework::ProcessOutput& outProcessOutput) { // launch the process AZStd::scoped_ptr pWatcher(LaunchProcess(processLaunchInfo, communicationType)); - // this may fail - but that's okay, it means it cannot find the P4 Process. This is not an error situation, the user may not have P4 installed. if (!pWatcher) { AZ_TracePrintf("Process Watcher", "ProcessWatcher::LaunchProcessAndRetrieveOutput: Unable to launch process '%s %s'", processLaunchInfo.m_processExecutableString.c_str(), processLaunchInfo.m_commandlineParameters.c_str()); @@ -108,4 +106,4 @@ namespace AzToolsFramework } return AZStd::shared_ptr{}; } -} +} // AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessWatcher.h b/Code/Framework/AzFramework/AzFramework/Process/ProcessWatcher.h similarity index 95% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessWatcher.h rename to Code/Framework/AzFramework/AzFramework/Process/ProcessWatcher.h index 17bd6e4765..385b734277 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/ProcessWatcher.h +++ b/Code/Framework/AzFramework/AzFramework/Process/ProcessWatcher.h @@ -16,9 +16,9 @@ #include #include #include -#include +#include -namespace AzToolsFramework +namespace AzFramework { namespace ProcessLauncher { @@ -39,7 +39,7 @@ namespace AzToolsFramework * instead we assume windows style use of "double quotes" to escape spaces * for example: params="hello world" "/Users/JOE SMITH/Desktop" * On windows, the command line will be passed as-is to the shell (with quotes) - * on UNIX/OSX, the command line will be converted as appropraite (quotes removed, but used to chop up parameters) + * on UNIX/OSX, the command line will be converted as appropriate (quotes removed, but used to chop up parameters) */ AZStd::string m_commandlineParameters; @@ -68,7 +68,7 @@ namespace AzToolsFramework static ProcessWatcher* LaunchProcess(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType); // Use LaunchProcessAndRetrieveOutput to launch a process via LaunchProcess and return its output, as of now used for fire-and-forget executables (exe's that do something and close immediately) - static bool LaunchProcessAndRetrieveOutput(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType, AzToolsFramework::ProcessOutput& outProcessOutput); + static bool LaunchProcessAndRetrieveOutput(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType, AzFramework::ProcessOutput& outProcessOutput); // GetCommunicatorForChildProcess is used when you are implementing the given child process and want a better interface than std::in/std::out (not required) static AZStd::shared_ptr GetCommunicatorForChildProcess(ProcessCommunicationType communicationType); @@ -106,4 +106,4 @@ namespace AzToolsFramework ProcessCommunicator* m_pCommunicator; ProcessCommunicator* m_pChildCommunicator; }; -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp b/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp index 46a0616e41..ed8fd3a3af 100644 --- a/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp +++ b/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp @@ -11,65 +11,29 @@ */ #include -#include + +#include +#include #include +#include +#include +#include +#include + +#include +#include +#include + namespace AzFramework { namespace ProjectManager { - // Check if any project path appears to have been provided on the command line - bool HasCommandLineProjectName(const int argc, char* argv[]) - { - constexpr int numOptionPrefixes = 3; - static const char* optionPrefixes[numOptionPrefixes] = { "/", "--", "-" }; - constexpr int numOptionNames = 2; - static const char* optionNames[numOptionNames] = { "projectpath", R"(regset="/Amazon/AzCore/Bootstrap/sys_game_folder)" }; - for (int i = 1; i < argc; ++i) - { - int thisPrefix = 0; - for (; thisPrefix < numOptionPrefixes; ++thisPrefix) - { - if (strncmp(argv[i], optionPrefixes[thisPrefix], strlen(optionPrefixes[thisPrefix])) == 0) - { - break; - } - } - // If the argument doesn't start with any of our switch start parameters, this isn't an argument giving us a project - if (thisPrefix == numOptionPrefixes) - { - continue; - } - // We compare the portion of the string after our prefix - int startIndex = strlen(optionPrefixes[thisPrefix]); - // If the whole argument was just one of the prefixes, this also isn't what we were looking for - if (startIndex == strlen(argv[i])) - { - continue; - } - int switchNum = 0; - for (; switchNum < numOptionNames; ++switchNum) - { - // Start the string comparison at startIndex for each string - after the option indicator - if (azstrnicmp(&argv[i][startIndex], optionNames[switchNum], strlen(optionNames[switchNum])) == 0) - { - int expectedOptionLength = strlen(optionNames[switchNum]) + startIndex; - // The option is what we're looking for if it had a space after it (it was the whole argument) or it has an equals next - if (strlen(argv[i]) == (expectedOptionLength) || ((strlen(argv[i]) > expectedOptionLength ) && argv[i][expectedOptionLength] == '=')) - { - // We found one of the acceptable arguments - return true; - } - } - } - } - return false; - } // Check for a project name, if not found, attempt to launch project manager and shut down ProjectPathCheckResult CheckProjectPathProvided(const int argc, char* argv[]) { // If we were able to locate a path to a project, we're done - if (HasProjectName(argc, argv)) + if (HasProjectPath(argc, argv)) { return ProjectPathCheckResult::ProjectPathFound; } @@ -83,142 +47,88 @@ namespace AzFramework return ProjectPathCheckResult::ProjectManagerLaunchFailed; } - } // ProjectManager - - bool ProjectManager::HasProjectName(const int argc, char* argv[]) - { - return HasCommandLineProjectName(argc, argv) || HasBootstrapProjectName(); - } - - // This is a transition method until all projects/tests/etc have been converted to expect and use the projectpath parameter - // If bootstrap.cfg exists and has a valid project name we should assume we're launching using it - // After that time it can be removed - bool ProjectManager::HasBootstrapProjectName(AZStd::string_view projectFolder) - { - AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot(projectFolder); - if (enginePath.empty()) - { - AZ_Warning("ProjectManager", false, "Couldn't find engine root"); - return false; - } - - auto bootstrapPath = enginePath / "bootstrap.cfg"; - - if (!AZ::IO::SystemFile::Exists(bootstrapPath.c_str())) + bool HasProjectPath(const int argc, char* argv[]) { - AZ_Warning("ProjectManager", false, "No bootstrap file found at %s", bootstrapPath.c_str()); - return false; - } - AZStd::fixed_string< MaxBootstrapFileSize> bootstrapString; - auto fileSize = AZ::IO::SystemFile::Length(bootstrapPath.c_str()); - if (fileSize >= MaxBootstrapFileSize) - { - AZ_Warning("ProjectManager", false, "Bootstrap read size at %s is %zu", bootstrapPath.c_str(), fileSize); - bootstrapString.resize_no_construct(MaxBootstrapFileSize); - } - else - { - bootstrapString.resize_no_construct(fileSize); - } - AZ::IO::SystemFile::SizeType bytesRead = AZ::IO::SystemFile::Read(bootstrapPath.c_str(), bootstrapString.data(), MaxBootstrapFileSize - 1); - if (bytesRead == (MaxBootstrapFileSize - 1)) - { - AZ_Warning("ProjectManager", false, "Bootstrap read size at %s was %zu", bootstrapPath.c_str(), bytesRead); - } - if (!ContentHasProjectName(bootstrapString)) - { - AZ_TracePrintf("ProjectManager", "Bootstrap at %s did not contain project name", bootstrapPath.c_str()); - return false; - } - return true; - } - - // This is a transition method until all projects/tests/etc have been converted to expect and use the projectpath parameter - // If bootstrap.cfg exists and has a valid project name we should assume we're launching using it - // After that time it can be removed - bool ProjectManager::ContentHasProjectName(AZStd::fixed_string< MaxBootstrapFileSize>& bootstrapString) - { - static const char* const projectKey = "sys_game_folder"; - size_t searchStart = bootstrapString.find(projectKey); - while (searchStart != bootstrapString.npos) - { - // Once we've found the key we need to search the line forward and backwards. Commented out lines shouldn't count - // and if there's no value after the equals then it's also not set - auto checkPos = searchStart; - // We're at the start already if this is position 0 - bool foundLineStart = checkPos == 0; - if (checkPos) + bool hasProjectPath = false; + bool ownsAllocator = false; + if (!AZ::AllocatorInstance::IsReady()) { - --checkPos; + AZ::AllocatorInstance::Create(); + ownsAllocator = true; } - while (checkPos > 0 && bootstrapString[checkPos] != '-') { - if (bootstrapString[checkPos] == '\n') - { - // Looks like a valid key - foundLineStart = true; - break; - } - if (!std::isspace(bootstrapString[checkPos])) - { - // This appears to be some other character appearing before our key, this isn't valid - break; - } - --checkPos; + AZ::CommandLine commandLine; + commandLine.Parse(argc, argv); + AZ::SettingsRegistryImpl settingsRegistry; + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(settingsRegistry); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(settingsRegistry, commandLine, false); + auto sysGameFolderKey = AZ::SettingsRegistryInterface::FixedValueString( + AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; + AZ::IO::FixedMaxPath registryPath; + hasProjectPath = settingsRegistry.Get(registryPath.Native(), sysGameFolderKey); + } + if (ownsAllocator) + { + AZ::AllocatorInstance::Destroy(); } - if (!foundLineStart) + return hasProjectPath; + } + + bool LaunchProjectManager() + { + bool launchSuccess = false; +#if (AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER) + bool ownsSystemAllocator = false; + if (!AZ::AllocatorInstance::IsReady()) { - // Commented line or other content preceding our key, keep searching - searchStart = bootstrapString.find(projectKey, searchStart + 1); - continue; + ownsSystemAllocator = true; + AZ::AllocatorInstance::Create(); } - checkPos = searchStart + strlen(projectKey); - bool foundEquals = false; - while (checkPos < bootstrapString.length()) { - if (bootstrapString[checkPos] == '\n') - { - // We've reached the end of the line and didn't find anything that seems to be a value for our key - break; - } - if (std::isspace(bootstrapString[checkPos])) + const char projectsScript[] = "projects.py"; + + AZ_Warning("ProjectManager", false, "No project provided - launching project selector."); + + AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot(); + if (enginePath.empty()) { - // Whitespace - keep searching back - ++checkPos; - continue; + AZ_Error("ProjectManager", false, "Couldn't find engine root"); + return false; } - if (bootstrapString[checkPos] == '=') + auto projectManagerPath = enginePath / "scripts" / "project_manager"; + + if (!AZ::IO::SystemFile::Exists((projectManagerPath / projectsScript).c_str())) { - foundEquals = true; - ++checkPos; - continue; + AZ_Error("ProjectManager", false, "%s not found at %s!", projectsScript, projectManagerPath.c_str()); + return false; } - if (foundEquals) + char executablePath[AZ_MAX_PATH_LEN]; + AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath, AZ_MAX_PATH_LEN); + auto exeFolder = AZ::IO::PathView(executablePath).ParentPath().Filename().Native(); + AZStd::fixed_string<8> debugOption; + if (exeFolder == "debug") { - auto nameEnd = bootstrapString.find_first_of(" \n", checkPos); - if (nameEnd == bootstrapString.npos) - { - // End of content, this is valid - nameEnd = bootstrapString.length(); - } - constexpr size_t nameMax = 100; - if (nameEnd - checkPos > nameMax) - { - AZ_Warning("ProjectManager", false, "Project name exceeded %zu characters (%zu)", nameMax, nameEnd - checkPos); - return false; - } - AZStd::fixed_string projectName(&bootstrapString[checkPos], nameEnd - checkPos); - AZ_TracePrintf("ProjectManager", "Found project name of %s", projectName.c_str()); - // This is not a space, we've found our key, and we've found some sort of non space entry, we count this as "it looks like we have a value entered" - return true; + // We need to use the debug version of the python interpreter to load up our debug version of our libraries which work with the debug version of QT living in this folder + debugOption = "debug "; } - // there was some other content on this line after our key before the equals that was not a space, this isn't our key - searchStart = bootstrapString.find(projectKey, searchStart + 1); - break; + AZ::IO::FixedMaxPath pythonPath = enginePath / "python"; + pythonPath /= AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL; + auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRId64, pythonPath.Native().c_str(), + debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath, AZ::Platform::GetCurrentProcessId()); + + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + + processLaunchInfo.m_commandlineParameters = cmdPath; + processLaunchInfo.m_showWindow = false; + launchSuccess = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo); } - searchStart = bootstrapString.find(projectKey, searchStart + 1); + if(ownsSystemAllocator) + { + AZ::AllocatorInstance::Destroy(); + } +#endif // #if defined(AZ_FRAMEWORK_USE_PROJECT_MANAGER) + return launchSuccess; } - return false; - } + } // ProjectManager } // AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.h b/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.h index 36d726a592..fe5c567e7b 100644 --- a/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.h +++ b/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.h @@ -22,7 +22,7 @@ namespace AzFramework constexpr AZ::IO::SystemFile::SizeType MaxBootstrapFileSize = 1024 * 10; // Check if any project name can be found anywhere - bool HasProjectName(const int argc, char* argv[]); + bool HasProjectPath(const int argc, char* argv[]); // Check if any project name can be found on the command line bool HasCommandLineProjectName(const int argc, char* argv[]); // Check if a relative project is being used through bootstrap diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp index 0933ccc5f0..e04299b265 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp @@ -25,6 +25,7 @@ namespace AzFramework if (auto* serializeContext = azrtti_cast(context); serializeContext != nullptr) { + serializeContext->Class(); serializeContext->RegisterGenericType>(); } } @@ -62,7 +63,7 @@ namespace AzFramework else { AZ_Warning("Spawnables", false, "No root spawnable assigned or root spawanble couldnt' be loaded.\n" - "The root spawnable can be assigned in the Settings Registry under the key '$s'.\n", RootSpawnableRegistryKey); + "The root spawnable can be assigned in the Settings Registry under the key '%s'.\n", RootSpawnableRegistryKey); } m_rootSpawnableInitialized = true; diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index 3ae753dcc2..5f2af8c6de 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -145,6 +145,8 @@ set(FILES Components/NonUniformScaleComponent.cpp FileFunc/FileFunc.h FileFunc/FileFunc.cpp + Gem/GemInfo.cpp + Gem/GemInfo.h StringFunc/StringFunc.h InGameUI/UiFrameworkBus.h IO/LocalFileIO.cpp @@ -267,6 +269,11 @@ set(FILES Physics/WorldEventhandler.h Physics/ScriptCanvasPhysicsUtils.h Physics/ScriptCanvasPhysicsUtils.cpp + Process/ProcessCommunicator.cpp + Process/ProcessCommunicator.h + Process/ProcessWatcher.cpp + Process/ProcessWatcher.h + Process/ProcessCommon_fwd.h ProjectManager/ProjectManager.h ProjectManager/ProjectManager.cpp Render/GameIntersectorComponent.h diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/AzFramework_Traits_Android.h b/Code/Framework/AzFramework/Platform/Android/AzFramework/AzFramework_Traits_Android.h index e6061ffd99..528b5e9f61 100644 --- a/Code/Framework/AzFramework/Platform/Android/AzFramework/AzFramework_Traits_Android.h +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/AzFramework_Traits_Android.h @@ -16,3 +16,6 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_C11_LOCALTIME_S 0 #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 1 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 0 +#define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL 0 +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 0 +#define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommon.h b/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommon.h new file mode 100644 index 0000000000..0e233269cf --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommon.h @@ -0,0 +1,51 @@ +/* +* 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 + +namespace AzFramework +{ + class CommunicatorHandleImpl + { + public: + ~CommunicatorHandleImpl() = default; + + bool IsValid() const { return false; } + bool IsBroken() const { return false; } + int GetHandle() const { return -1; } + + void Break() {} + void Close() {} + void SetHandle([[maybe_unused]] int handle) {} + + }; + + struct StartupInfo + { + ~StartupInfo(); + + void SetupHandlesForChildProcess(); + void CloseAllHandles(); + + int m_inputHandleForChild = -1; + int m_outputHandleForChild = -1; + int m_errorHandleForChild = -1; + }; + + struct ProcessData + { + StartupInfo m_startupInfo; + int m_childProcessId = 0; + bool m_childProcessIsDone = false; + }; +} // namespace AzFramework + diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommunicator_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommunicator_Android.cpp new file mode 100644 index 0000000000..b3f06706f0 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessCommunicator_Android.cpp @@ -0,0 +1,50 @@ +/* +* 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. +* +*/ + + +#include + +namespace AzFramework +{ + AZ::u32 StdInOutCommunication::PeekHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle) + { + return 0; + } + + AZ::u32 StdInOutCommunication::ReadDataFromHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle, [[maybe_unused]] void* readBuffer, [[maybe_unused]] AZ::u32 bufferSize) + { + return 0; + } + + AZ::u32 StdInOutCommunication::WriteDataToHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle, [[maybe_unused]] const void* writeBuffer, [[maybe_unused]] AZ::u32 bytesToWrite) + { + return 0; + } + + bool StdInOutProcessCommunicator::CreatePipesForProcess([[maybe_unused]] ProcessData* processData) + { + return false; + } + + void StdInOutProcessCommunicator::WaitForReadyOutputs([[maybe_unused]] OutputStatus& status) const + { + status.outputDeviceReady = false; + status.errorsDeviceReady = false; + status.shouldReadOutput = status.shouldReadErrors = false; + } + + bool StdInOutProcessCommunicatorForChildProcess::AttachToExistingPipes() + { + return false; + } +} // namespace AzFramework + diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessWatcher_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessWatcher_Android.cpp new file mode 100644 index 0000000000..72e685f0e5 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Process/ProcessWatcher_Android.cpp @@ -0,0 +1,90 @@ +/* + * 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. + * + */ + +#include +#include + + +namespace AzFramework +{ + + StartupInfo::~StartupInfo() + { + + } + + void StartupInfo::SetupHandlesForChildProcess() + { + + } + + void StartupInfo::CloseAllHandles() + { + + } + + bool ProcessLauncher::LaunchUnwatchedProcess([[maybe_unused]] const ProcessLaunchInfo& processLaunchInfo) + { + return false; + } + + bool ProcessLauncher::LaunchProcess([[maybe_unused]] const ProcessLaunchInfo& processLaunchInfo, [[maybe_unused]] ProcessData& processData) + { + return false; + } + + StdProcessCommunicator* ProcessWatcher::CreateStdCommunicator() + { + return new StdInOutProcessCommunicator(); + } + + StdProcessCommunicatorForChildProcess* ProcessWatcher::CreateStdCommunicatorForChildProcess() + { + return new StdInOutProcessCommunicatorForChildProcess(); + } + + ProcessWatcher* ProcessWatcher::LaunchProcess([[maybe_unused]] const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, [[maybe_unused]] ProcessCommunicationType communicationType) + { + return nullptr; + } + + void ProcessWatcher::InitProcessData([[maybe_unused]] bool stdProcessData) + { + + } + + ProcessWatcher::ProcessWatcher() + : m_pCommunicator(nullptr) + { + + } + + ProcessWatcher::~ProcessWatcher() + { + + } + + bool ProcessWatcher::IsProcessRunning([[maybe_unused]] AZ::u32* outExitCode) + { + return false; + } + + bool ProcessWatcher::WaitForProcessToExit([[maybe_unused]] AZ::u32 waitTimeInSeconds, [[maybe_unused]] AZ::u32* outExitCode /*= nullptr*/) + { + return true; + } + + void ProcessWatcher::TerminateProcess([[maybe_unused]] AZ::u32 exitCode) + { + + } +} //namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/ProjectManager/ProjectManager_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/ProjectManager/ProjectManager_Android.cpp deleted file mode 100644 index de12a61608..0000000000 --- a/Code/Framework/AzFramework/Platform/Android/AzFramework/ProjectManager/ProjectManager_Android.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - * - */ - -#include -#include - - -namespace AzFramework -{ - namespace ProjectManager - { - bool LaunchProjectManager() - { - return false; - } - } // ProjectManager -} // AzFramework - diff --git a/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake b/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake index cfc470cf03..38d07ec9f5 100644 --- a/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake +++ b/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake @@ -15,7 +15,6 @@ set(FILES AzFramework/API/ApplicationAPI_Platform.h AzFramework/API/ApplicationAPI_Android.h AzFramework/Application/Application_Android.cpp - AzFramework/ProjectManager/ProjectManager_Android.cpp ../Common/Unimplemented/AzFramework/Asset/AssetSystemComponentHelper_Unimplemented.cpp AzFramework/IO/LocalFileIO_Android.cpp ../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp @@ -34,4 +33,7 @@ set(FILES AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard_Android.cpp AzFramework/Archive/ArchiveVars_Platform.h AzFramework/Archive/ArchiveVars_Android.h + AzFramework/Process/ProcessCommon.h + AzFramework/Process/ProcessWatcher_Android.cpp + AzFramework/Process/ProcessCommunicator_Android.cpp ) diff --git a/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommon_Default.h b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommon_Default.h new file mode 100644 index 0000000000..22299e5892 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommon_Default.h @@ -0,0 +1,53 @@ +/* +* 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 + +#define PROCESSCOMMON_DEFAULT 1 + +namespace AzFramework +{ + class CommunicatorHandleImpl + { + public: + ~CommunicatorHandleImpl() = default; + + bool IsValid() const { return false; } + bool IsBroken() const { return false; } + int GetHandle() const { return -1; } + + void Break() {} + void Close() {} + void SetHandle([[maybe_unused]] int handle) {} + + }; + + struct StartupInfo + { + ~StartupInfo(); + + void SetupHandlesForChildProcess(); + void CloseAllHandles(); + + int m_inputHandleForChild = -1; + int m_outputHandleForChild = -1; + int m_errorHandleForChild = -1; + }; + + struct ProcessData + { + StartupInfo m_startupInfo; + int m_childProcessId = 0; + bool m_childProcessIsDone = false; + }; +} // namespace AzFramework + diff --git a/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommunicator_Default.cpp b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommunicator_Default.cpp new file mode 100644 index 0000000000..dce621664f --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessCommunicator_Default.cpp @@ -0,0 +1,51 @@ +/* +* 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. +* +*/ + + +#include "ProcessCommon_Default.h" +#include + +namespace AzFramework +{ + AZ::u32 StdInOutCommunication::PeekHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle) + { + return 0; + } + + AZ::u32 StdInOutCommunication::ReadDataFromHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle, [[maybe_unused]] void* readBuffer, [[maybe_unused]] AZ::u32 bufferSize) + { + return 0; + } + + AZ::u32 StdInOutCommunication::WriteDataToHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle, [[maybe_unused]] const void* writeBuffer, [[maybe_unused]] AZ::u32 bytesToWrite) + { + return 0; + } + + bool StdInOutProcessCommunicator::CreatePipesForProcess([[maybe_unused]] ProcessData* processData) + { + return false; + } + + void StdInOutProcessCommunicator::WaitForReadyOutputs([[maybe_unused]] OutputStatus& status) const + { + status.outputDeviceReady = false; + status.errorsDeviceReady = false; + status.shouldReadOutput = status.shouldReadErrors = false; + } + + bool StdInOutProcessCommunicatorForChildProcess::AttachToExistingPipes() + { + return false; + } +} // namespace AzFramework + diff --git a/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessWatcher_Default.cpp b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessWatcher_Default.cpp new file mode 100644 index 0000000000..72e685f0e5 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/Process/ProcessWatcher_Default.cpp @@ -0,0 +1,90 @@ +/* + * 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. + * + */ + +#include +#include + + +namespace AzFramework +{ + + StartupInfo::~StartupInfo() + { + + } + + void StartupInfo::SetupHandlesForChildProcess() + { + + } + + void StartupInfo::CloseAllHandles() + { + + } + + bool ProcessLauncher::LaunchUnwatchedProcess([[maybe_unused]] const ProcessLaunchInfo& processLaunchInfo) + { + return false; + } + + bool ProcessLauncher::LaunchProcess([[maybe_unused]] const ProcessLaunchInfo& processLaunchInfo, [[maybe_unused]] ProcessData& processData) + { + return false; + } + + StdProcessCommunicator* ProcessWatcher::CreateStdCommunicator() + { + return new StdInOutProcessCommunicator(); + } + + StdProcessCommunicatorForChildProcess* ProcessWatcher::CreateStdCommunicatorForChildProcess() + { + return new StdInOutProcessCommunicatorForChildProcess(); + } + + ProcessWatcher* ProcessWatcher::LaunchProcess([[maybe_unused]] const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, [[maybe_unused]] ProcessCommunicationType communicationType) + { + return nullptr; + } + + void ProcessWatcher::InitProcessData([[maybe_unused]] bool stdProcessData) + { + + } + + ProcessWatcher::ProcessWatcher() + : m_pCommunicator(nullptr) + { + + } + + ProcessWatcher::~ProcessWatcher() + { + + } + + bool ProcessWatcher::IsProcessRunning([[maybe_unused]] AZ::u32* outExitCode) + { + return false; + } + + bool ProcessWatcher::WaitForProcessToExit([[maybe_unused]] AZ::u32 waitTimeInSeconds, [[maybe_unused]] AZ::u32* outExitCode /*= nullptr*/) + { + return true; + } + + void ProcessWatcher::TerminateProcess([[maybe_unused]] AZ::u32 exitCode) + { + + } +} //namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/ProjectManager/ProjectManager_Default.cpp b/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/ProjectManager/ProjectManager_Default.cpp deleted file mode 100644 index c251cfd363..0000000000 --- a/Code/Framework/AzFramework/Platform/Common/Default/AzFramework/ProjectManager/ProjectManager_Default.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - * - */ - -#include -#include - - - -namespace AzFramework -{ - namespace ProjectManager - { - bool LaunchProjectManager() - { - return false; - } - } // ProjectManager -} // AzFramework - diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp index e499865de7..1f71b97a57 100644 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp @@ -25,8 +25,9 @@ namespace AzFramework::AssetSystem::Platform { void AllowAssetProcessorToForeground() {} - bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view appRoot, - AZStd::string_view gameProjectName) + + bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view engineRoot, + AZStd::string_view projectPath) { pid_t firstChildPid = fork(); if (firstChildPid == 0) @@ -55,22 +56,22 @@ namespace AzFramework::AssetSystem::Platform }; int optionalArgPos = 3; - // Add the app-root to the launch command if not empty - AZ::IO::FixedMaxPathString appRootArg; - if (!appRoot.empty()) + // Add the engine path to the launch command if not empty + AZ::IO::FixedMaxPathString engineRootArg; + if (!engineRoot.empty()) { - appRootArg = AZ::IO::FixedMaxPathString::format(R"(--app-root="%.*s")", - aznumeric_cast(appRoot.size()), appRoot.data()); - args[optionalArgPos++] = appRootArg.data(); + engineRootArg = AZ::IO::FixedMaxPathString::format(R"(--engine-path="%.*s")", + aznumeric_cast(engineRoot.size()), engineRoot.data()); + args[optionalArgPos++] = engineRootArg.data(); } - // Add the active game project to the launch command if not empty - AZ::IO::FixedMaxPathString projectArg; - if (!gameProjectName.empty()) + // Add the active project path to the launch command if not empty + AZ::IO::FixedMaxPathString projectPathArg; + if (!projectPath.empty()) { - projectArg = AZ::IO::FixedMaxPathString::format(R"(--regset="/Amazon/AzCore/Bootstrap/sys_game_folder=%.*s")", - aznumeric_cast(gameProjectName.size()), gameProjectName.data()); - args[optionalArgPos++] = projectArg.data(); + projectPathArg = AZ::IO::FixedMaxPathString::format(R"(--regset="/Amazon/AzCore/Bootstrap/project_path=%.*s")", + aznumeric_cast(projectPath.size()), projectPath.data()); + args[optionalArgPos++] = projectPathArg.data(); } AZStd::apply(execl, args); diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h index 8b1c158b2c..c5410d97ce 100644 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h @@ -16,3 +16,6 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_C11_LOCALTIME_S 0 #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 1 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 0 +#define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL "python.sh" +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 0 +#define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessCommon.h similarity index 95% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Linux.h rename to Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessCommon.h index cfd5785355..312220d84a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Linux.h +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessCommon.h @@ -12,7 +12,7 @@ #pragma once -namespace AzToolsFramework +namespace AzFramework { class CommunicatorHandleImpl { @@ -50,5 +50,5 @@ namespace AzToolsFramework int m_childProcessId = 0; bool m_childProcessIsDone = false; }; -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessCommunicator_Linux.cpp similarity index 98% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_Linux.cpp rename to Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessCommunicator_Linux.cpp index dfa60bf0dd..04cd1254ba 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_Linux.cpp +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessCommunicator_Linux.cpp @@ -10,15 +10,14 @@ * */ -#include "AzToolsFramework_precompiled.h" #include #include #include #include -#include +#include -namespace AzToolsFramework +namespace AzFramework { bool CommunicatorHandleImpl::IsValid() const { @@ -243,5 +242,5 @@ namespace AzToolsFramework m_initialized = m_stdInRead->IsValid() && m_stdOutWrite->IsValid() && m_stdErrWrite->IsValid(); return m_initialized; } -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessWatcher_Linux.cpp similarity index 98% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_Linux.cpp rename to Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessWatcher_Linux.cpp index 53b4663a46..b45731901a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_Linux.cpp +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Process/ProcessWatcher_Linux.cpp @@ -10,10 +10,9 @@ * */ -#include "AzToolsFramework_precompiled.h" -#include -#include +#include +#include #include @@ -32,7 +31,7 @@ #include #include -namespace AzToolsFramework +namespace AzFramework { namespace ProcessLauncher { @@ -413,4 +412,4 @@ namespace AzToolsFramework kill(m_pWatcherData->m_childProcessId, SIGKILL); } -} //namespace AzToolsFramework +} //namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/ProjectManager/ProjectManager_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/ProjectManager/ProjectManager_Linux.cpp deleted file mode 100644 index e7f1baf91b..0000000000 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/ProjectManager/ProjectManager_Linux.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - * - */ - -#include -#include - - -namespace AzFramework -{ - namespace ProjectManager - { - bool LaunchProjectManager() - { - return false; - } - } // ProjectManager -} // AzFramework - diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake index 6be5e17f52..d12702d17f 100644 --- a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake @@ -16,7 +16,9 @@ set(FILES AzFramework/API/ApplicationAPI_Linux.h AzFramework/Application/Application_Linux.cpp AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp - AzFramework/ProjectManager/ProjectManager_Linux.cpp + AzFramework/Process/ProcessWatcher_Linux.cpp + AzFramework/Process/ProcessCommon.h + AzFramework/Process/ProcessCommunicator_Linux.cpp ../Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp ../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp ../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp index cb864e88a8..43f7599676 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp @@ -20,8 +20,8 @@ namespace AzFramework::AssetSystem::Platform { void AllowAssetProcessorToForeground() {} - bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view appRoot, - AZStd::string_view gameProjectName) + bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view engineRoot, + AZStd::string_view projectPath) { AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory }; // In Mac the Editor and game is within a bundle, so the path to the sibling app @@ -30,19 +30,19 @@ namespace AzFramework::AssetSystem::Platform assetProcessorPath = assetProcessorPath.LexicallyNormal(); auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"(open -g "%s" --args --start-hidden)", assetProcessorPath.c_str()); - // Add the app-root to the launch command if not empty - if (!appRoot.empty()) + // Add the engine path to the launch command if not empty + if (!engineRoot.empty()) { - fullLaunchCommand += R"( --app-root=")"; - fullLaunchCommand += appRoot; + fullLaunchCommand += R"( --engine-path=")"; + fullLaunchCommand += engineRoot; fullLaunchCommand += '"'; } - // Add the active game project to the launch command if not empty - if (!gameProjectName.empty()) + // Add the active project path to the launch command if not empty + if (!projectPath.empty()) { - fullLaunchCommand += R"( --gameFolder=")"; - fullLaunchCommand += gameProjectName; + fullLaunchCommand += R"( --project-path=")"; + fullLaunchCommand += projectPath; fullLaunchCommand += '"'; } diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h b/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h index 3a119167a8..f1c834a08c 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h @@ -16,3 +16,6 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_C11_LOCALTIME_S 0 #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 1 +#define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL "python.sh" +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 0 +#define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_OSX.h b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessCommon.h similarity index 91% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_OSX.h rename to Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessCommon.h index 71752f57c7..558938971b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_OSX.h +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessCommon.h @@ -12,9 +12,8 @@ #pragma once -#if AZ_TRAIT_OS_PLATFORM_APPLE -namespace AzToolsFramework +namespace AzFramework { class CommunicatorHandleImpl { @@ -52,6 +51,5 @@ namespace AzToolsFramework int m_childProcessId = 0; bool m_childProcessIsDone = false; }; -} // namespace AzToolsFramework +} // namespace AzFramework -#endif // AZ_TRAIT_OS_PLATFORM_APPLE diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_OSX.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessCommunicator_Mac.cpp similarity index 98% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_OSX.cpp rename to Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessCommunicator_Mac.cpp index 7ba3f74580..a3c74ded03 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_OSX.cpp +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessCommunicator_Mac.cpp @@ -10,14 +10,12 @@ * */ -#include "AzToolsFramework_precompiled.h" - #if AZ_TRAIT_OS_PLATFORM_APPLE #include #include -#include +#include -namespace AzToolsFramework +namespace AzFramework { bool CommunicatorHandleImpl::IsValid() const { @@ -242,6 +240,6 @@ namespace AzToolsFramework m_initialized = m_stdInRead->IsValid() && m_stdOutWrite->IsValid() && m_stdErrWrite->IsValid(); return m_initialized; } -} // namespace AzToolsFramework +} // namespace AzFramework #endif // AZ_TRAIT_OS_PLATFORM_APPLE diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_OSX.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessWatcher_Mac.cpp similarity index 98% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_OSX.cpp rename to Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessWatcher_Mac.cpp index 981f1c3990..93bfe57d54 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_OSX.cpp +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Process/ProcessWatcher_Mac.cpp @@ -10,12 +10,11 @@ * */ -#include "AzToolsFramework_precompiled.h" #if AZ_TRAIT_OS_PLATFORM_APPLE -#include -#include +#include +#include #include @@ -32,7 +31,7 @@ #include -namespace AzToolsFramework +namespace AzFramework { namespace { @@ -432,6 +431,6 @@ namespace AzToolsFramework kill(m_pWatcherData->m_childProcessId, SIGKILL); waitpid(m_pWatcherData->m_childProcessId, NULL, 0); } -} //namespace AzToolsFramework +} //namespace AzFramework #endif // AZ_TRAIT_OS_PLATFORM_APPLE diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/ProjectManager/ProjectManager_Mac.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/ProjectManager/ProjectManager_Mac.cpp deleted file mode 100644 index e7f1baf91b..0000000000 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/ProjectManager/ProjectManager_Mac.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - * - */ - -#include -#include - - -namespace AzFramework -{ - namespace ProjectManager - { - bool LaunchProjectManager() - { - return false; - } - } // ProjectManager -} // AzFramework - diff --git a/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake index a0cc1d7afd..9f4a09418f 100644 --- a/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake @@ -16,7 +16,9 @@ set(FILES AzFramework/API/ApplicationAPI_Mac.h AzFramework/Application/Application_Mac.mm AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp - AzFramework/ProjectManager/ProjectManager_Mac.cpp + AzFramework/Process/ProcessWatcher_Mac.cpp + AzFramework/Process/ProcessCommon.h + AzFramework/Process/ProcessCommunicator_Mac.cpp ../Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp ../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp ../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp index a71a618438..3f4dbef22a 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp @@ -61,18 +61,19 @@ namespace AzFramework::AssetSystem::Platform } } - bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view appRoot, - AZStd::string_view gameProjectName) + bool LaunchAssetProcessor(AZStd::string_view executableDirectory, AZStd::string_view engineRoot, + AZStd::string_view projectPath) { AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory }; assetProcessorPath /= "AssetProcessor.exe"; auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"("%s" --start-hidden)", assetProcessorPath.c_str()); - // Add the app-root to the launch command if not empty - if (!appRoot.empty()) + + // Add the engine path to the launch command if not empty + if (!engineRoot.empty()) { - fullLaunchCommand += R"( --app-root=")"; - fullLaunchCommand += appRoot; + fullLaunchCommand += R"( --engine-path=")"; + fullLaunchCommand += engineRoot; // Windows CreateProcess has issues with paths that end with a trailing backslash // so remove it if it exist if (fullLaunchCommand.ends_with(AZ::IO::WindowsPathSeparator)) @@ -82,11 +83,11 @@ namespace AzFramework::AssetSystem::Platform fullLaunchCommand += '"'; } - // Add the active game project to the launch command if not empty - if (!gameProjectName.empty()) + // Add the active project path to the launch command if not empty + if (!projectPath.empty()) { - fullLaunchCommand += R"( --gameFolder=")"; - fullLaunchCommand += gameProjectName; + fullLaunchCommand += R"( --project-path=")"; + fullLaunchCommand += projectPath; fullLaunchCommand += '"'; } diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/AzFramework_Traits_Windows.h b/Code/Framework/AzFramework/Platform/Windows/AzFramework/AzFramework_Traits_Windows.h index 4f4cd0d25e..9713d23d23 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/AzFramework_Traits_Windows.h +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/AzFramework_Traits_Windows.h @@ -16,3 +16,6 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_C11_LOCALTIME_S 1 #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 0 +#define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL "python.cmd" +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 1 +#define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Win.h b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessCommon.h similarity index 98% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Win.h rename to Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessCommon.h index 319156c6be..c37dae49d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommon_Win.h +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessCommon.h @@ -14,7 +14,7 @@ #include -namespace AzToolsFramework +namespace AzFramework { class CommunicatorHandleImpl { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_Win.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessCommunicator_Win.cpp similarity index 98% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_Win.cpp rename to Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessCommunicator_Win.cpp index 3a5f68fc20..72220449c8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessCommunicator_Win.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessCommunicator_Win.cpp @@ -10,11 +10,10 @@ * */ -#include "AzToolsFramework_precompiled.h" -#include +#include -namespace AzToolsFramework +namespace AzFramework { bool CommunicatorHandleImpl::IsPipe() const { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_Win.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessWatcher_Win.cpp similarity index 96% rename from Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_Win.cpp rename to Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessWatcher_Win.cpp index 97963b8a1f..2203e4142f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Process/internal/ProcessWatcher_Win.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessWatcher_Win.cpp @@ -10,20 +10,18 @@ * */ -#include "AzToolsFramework_precompiled.h" - #include #include #include #include -#include -#include -#include +#include +#include +#include #include -namespace AzToolsFramework +namespace AzFramework { ProcessData::ProcessData() { @@ -202,7 +200,7 @@ namespace AzToolsFramework } - ProcessWatcher* ProcessWatcher::LaunchProcess(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType) + ProcessWatcher* ProcessWatcher::LaunchProcess(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, AzFramework::ProcessCommunicationType communicationType) { ProcessWatcher* pWatcher = new ProcessWatcher {}; if (!pWatcher->SpawnProcess(processLaunchInfo, communicationType)) @@ -255,7 +253,7 @@ namespace AzToolsFramework namespace { // Returns true if process exited, false if still running - bool CheckExitCode(const AzToolsFramework::ProcessData* processData, AZ::u32* outExitCode = nullptr) + bool CheckExitCode(const AzFramework::ProcessData* processData, AZ::u32* outExitCode = nullptr) { // Check exit code DWORD exitCode; @@ -361,4 +359,4 @@ namespace AzToolsFramework ::TerminateProcess(m_pWatcherData->processInformation.hProcess, exitCode); } } -} // namespace AzToolsFramework +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/ProjectManager/ProjectManager_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/ProjectManager/ProjectManager_Windows.cpp deleted file mode 100644 index 24417d4195..0000000000 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/ProjectManager/ProjectManager_Windows.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - * - */ - -#include -#include -#include -#include -#include -#include - -namespace AzFramework -{ - namespace ProjectManager - { - bool LaunchProjectManager() - { - const char projectsScript[] = "projects.py"; - - AZ_Warning("ProjectManager", false, "No project provided - launching project selector."); - - AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot(); - if (enginePath.empty()) - { - AZ_Warning("ProjectManager", false, "Couldn't find engine root"); - return false; - } - auto projectManagerPath = enginePath / "scripts" / "project_manager"; - - if (!AZ::IO::SystemFile::Exists((projectManagerPath / projectsScript).c_str())) - { - AZ_Warning("ProjectManager", false, "%s not found at %s!", projectsScript, projectManagerPath.c_str()); - } - char executablePath[AZ_MAX_PATH_LEN]; - AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath, AZ_MAX_PATH_LEN); - auto exeFolder = AZ::IO::PathView(executablePath).ParentPath().Filename().Native(); - AZStd::fixed_string<10> debugOption{ " " }; - if (exeFolder == "debug") - { - // We need to use the debug version of the python interpreter to load up our debug version of our libraries which work with the debug version of QT living in this folder - debugOption = " debug "; - } - AZ::IO::FixedMaxPath pythonPath = enginePath / "python" / "python.cmd"; - auto cmdPath = AZ::IO::FixedMaxPathString::format("%s%s%s --executable_path=%s", pythonPath.Native().c_str(), debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath); - - - STARTUPINFO si; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - PROCESS_INFORMATION pi; - - auto workingPath = AZ::IO::FixedMaxPath{ executablePath }.ParentPath().Native(); - bool launchSuccess = ::CreateProcessA(nullptr, cmdPath.data(), nullptr, nullptr, FALSE, 0, nullptr, projectManagerPath.c_str(), &si, &pi) != 0; - if (launchSuccess) - { - AZ_TracePrintf("ProjectManagerSystemComponent", "Launched Project Manager successfully, shutting down.\n"); - } - else - { - auto someError = GetLastError(); - AZ_Warning("ProjectManagerSystemComponent", false, "Failed to launch project manager with error %d", someError); - } - return launchSuccess; - } - } // ProjectManager -} // AzFramework - diff --git a/Code/Framework/AzFramework/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzFramework/Platform/Windows/platform_windows_files.cmake index 5cd3b20e5a..ac6a64832e 100644 --- a/Code/Framework/AzFramework/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzFramework/Platform/Windows/platform_windows_files.cmake @@ -16,7 +16,9 @@ set(FILES AzFramework/API/ApplicationAPI_Windows.h AzFramework/Application/Application_Windows.cpp AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp - AzFramework/ProjectManager/ProjectManager_Windows.cpp + AzFramework/Process/ProcessWatcher_Win.cpp + AzFramework/Process/ProcessCommon.h + AzFramework/Process/ProcessCommunicator_Win.cpp ../Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp AzFramework/IO/LocalFileIO_Windows.cpp ../Common/WinAPI/AzFramework/Network/AssetProcessorConnection_WinAPI.cpp diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/AzFramework_Traits_iOS.h b/Code/Framework/AzFramework/Platform/iOS/AzFramework/AzFramework_Traits_iOS.h index 61d51493ce..bc365b0872 100644 --- a/Code/Framework/AzFramework/Platform/iOS/AzFramework/AzFramework_Traits_iOS.h +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/AzFramework_Traits_iOS.h @@ -16,3 +16,6 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_C11_LOCALTIME_S 0 #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 1 +#define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL 0 +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 0 +#define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommon.h b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommon.h new file mode 100644 index 0000000000..0e233269cf --- /dev/null +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommon.h @@ -0,0 +1,51 @@ +/* +* 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 + +namespace AzFramework +{ + class CommunicatorHandleImpl + { + public: + ~CommunicatorHandleImpl() = default; + + bool IsValid() const { return false; } + bool IsBroken() const { return false; } + int GetHandle() const { return -1; } + + void Break() {} + void Close() {} + void SetHandle([[maybe_unused]] int handle) {} + + }; + + struct StartupInfo + { + ~StartupInfo(); + + void SetupHandlesForChildProcess(); + void CloseAllHandles(); + + int m_inputHandleForChild = -1; + int m_outputHandleForChild = -1; + int m_errorHandleForChild = -1; + }; + + struct ProcessData + { + StartupInfo m_startupInfo; + int m_childProcessId = 0; + bool m_childProcessIsDone = false; + }; +} // namespace AzFramework + diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommunicator_iOS.cpp b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommunicator_iOS.cpp new file mode 100644 index 0000000000..b3f06706f0 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessCommunicator_iOS.cpp @@ -0,0 +1,50 @@ +/* +* 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. +* +*/ + + +#include + +namespace AzFramework +{ + AZ::u32 StdInOutCommunication::PeekHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle) + { + return 0; + } + + AZ::u32 StdInOutCommunication::ReadDataFromHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle, [[maybe_unused]] void* readBuffer, [[maybe_unused]] AZ::u32 bufferSize) + { + return 0; + } + + AZ::u32 StdInOutCommunication::WriteDataToHandle([[maybe_unused]] StdProcessCommunicatorHandle& handle, [[maybe_unused]] const void* writeBuffer, [[maybe_unused]] AZ::u32 bytesToWrite) + { + return 0; + } + + bool StdInOutProcessCommunicator::CreatePipesForProcess([[maybe_unused]] ProcessData* processData) + { + return false; + } + + void StdInOutProcessCommunicator::WaitForReadyOutputs([[maybe_unused]] OutputStatus& status) const + { + status.outputDeviceReady = false; + status.errorsDeviceReady = false; + status.shouldReadOutput = status.shouldReadErrors = false; + } + + bool StdInOutProcessCommunicatorForChildProcess::AttachToExistingPipes() + { + return false; + } +} // namespace AzFramework + diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessWatcher_iOS.cpp b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessWatcher_iOS.cpp new file mode 100644 index 0000000000..72e685f0e5 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Process/ProcessWatcher_iOS.cpp @@ -0,0 +1,90 @@ +/* + * 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. + * + */ + +#include +#include + + +namespace AzFramework +{ + + StartupInfo::~StartupInfo() + { + + } + + void StartupInfo::SetupHandlesForChildProcess() + { + + } + + void StartupInfo::CloseAllHandles() + { + + } + + bool ProcessLauncher::LaunchUnwatchedProcess([[maybe_unused]] const ProcessLaunchInfo& processLaunchInfo) + { + return false; + } + + bool ProcessLauncher::LaunchProcess([[maybe_unused]] const ProcessLaunchInfo& processLaunchInfo, [[maybe_unused]] ProcessData& processData) + { + return false; + } + + StdProcessCommunicator* ProcessWatcher::CreateStdCommunicator() + { + return new StdInOutProcessCommunicator(); + } + + StdProcessCommunicatorForChildProcess* ProcessWatcher::CreateStdCommunicatorForChildProcess() + { + return new StdInOutProcessCommunicatorForChildProcess(); + } + + ProcessWatcher* ProcessWatcher::LaunchProcess([[maybe_unused]] const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, [[maybe_unused]] ProcessCommunicationType communicationType) + { + return nullptr; + } + + void ProcessWatcher::InitProcessData([[maybe_unused]] bool stdProcessData) + { + + } + + ProcessWatcher::ProcessWatcher() + : m_pCommunicator(nullptr) + { + + } + + ProcessWatcher::~ProcessWatcher() + { + + } + + bool ProcessWatcher::IsProcessRunning([[maybe_unused]] AZ::u32* outExitCode) + { + return false; + } + + bool ProcessWatcher::WaitForProcessToExit([[maybe_unused]] AZ::u32 waitTimeInSeconds, [[maybe_unused]] AZ::u32* outExitCode /*= nullptr*/) + { + return true; + } + + void ProcessWatcher::TerminateProcess([[maybe_unused]] AZ::u32 exitCode) + { + + } +} //namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/ProjectManager/ProjectManager_iOS.cpp b/Code/Framework/AzFramework/Platform/iOS/AzFramework/ProjectManager/ProjectManager_iOS.cpp deleted file mode 100644 index 100f1be5e1..0000000000 --- a/Code/Framework/AzFramework/Platform/iOS/AzFramework/ProjectManager/ProjectManager_iOS.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - * - */ - -#include -#include - - -namespace AzFramework -{ - namespace ProjectManager - { - bool LaunchProjectManager() - { - return false; - } - } // ProjectManager -} // AzFramework - - diff --git a/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake b/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake index 6cb0b6c3ea..c3e5e7b7c1 100644 --- a/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake +++ b/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake @@ -15,7 +15,6 @@ set(FILES AzFramework/API/ApplicationAPI_Platform.h AzFramework/API/ApplicationAPI_iOS.h AzFramework/Application/Application_iOS.mm - AzFramework/ProjectManager/ProjectManager_iOS.cpp ../Common/Unimplemented/AzFramework/Asset/AssetSystemComponentHelper_Unimplemented.cpp ../Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp ../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp @@ -34,5 +33,8 @@ set(FILES ../Common/Apple/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard_Apple.mm AzFramework/Archive/ArchiveVars_Platform.h AzFramework/Archive/ArchiveVars_iOS.h + AzFramework/Process/ProcessCommon.h + AzFramework/Process/ProcessWatcher_iOS.cpp + AzFramework/Process/ProcessCommunicator_iOS.cpp ) diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index f882782ece..5214607edc 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -59,7 +59,7 @@ namespace AzGameFramework AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_DevRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif @@ -75,7 +75,7 @@ namespace AzGameFramework } #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_DevRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif } diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.cpp index 18dce7306c..713c486ac4 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.cpp @@ -11,6 +11,8 @@ */ #include +#include +#include #include #include #include @@ -52,7 +54,8 @@ namespace AzQtComponents } - void StyleManager::addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix) + void StyleManager::addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix, + const AZ::IO::PathView& engineRootPath) { if (!s_instance) { @@ -60,7 +63,7 @@ namespace AzQtComponents return; } - s_instance->m_stylesheetCache->addSearchPaths(searchPrefix, pathOnDisk, qrcPrefix); + s_instance->m_stylesheetCache->addSearchPaths(searchPrefix, pathOnDisk, qrcPrefix, engineRootPath); } bool StyleManager::setStyleSheet(QWidget* widget, QString styleFileName) @@ -153,7 +156,7 @@ namespace AzQtComponents } } - void StyleManager::initialize(QApplication* application) + void StyleManager::initialize([[maybe_unused]] QApplication* application, const AZ::IO::PathView& engineRootPath) { if (s_instance) { @@ -167,7 +170,7 @@ namespace AzQtComponents connect(application, &QCoreApplication::aboutToQuit, this, &StyleManager::cleanupStyles); - initializeSearchPaths(application); + initializeSearchPaths(application, engineRootPath); initializeFonts(); m_titleBarOverdrawHandler = TitleBarOverdrawHandler::createHandler(application, this); @@ -228,10 +231,11 @@ namespace AzQtComponents QFontDatabase::addApplicationFont(openSansPathSpecifier.arg("OpenSans-SemiboldItalic.ttf")); } - void StyleManager::initializeSearchPaths(QApplication* application) + void StyleManager::initializeSearchPaths([[maybe_unused]] QApplication* application, const AZ::IO::PathView& engineRootPath) { // now that QT is initialized, we can use its path manipulation functions to set the rest up: - QString rootDir = FindEngineRootDir(application); + + QString rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size())); if (!rootDir.isEmpty()) { diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.h index 9382b96c99..404c0869cd 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleManager.h @@ -14,6 +14,8 @@ #if !defined(Q_MOC_RUN) #include +#include + #include #include #include @@ -62,7 +64,8 @@ namespace AzQtComponents public: static bool isInstanced() { return s_instance; } - static void addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix); + static void addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix, + const AZ::IO::PathView& engineRootPath); static bool setStyleSheet(QWidget* widget, QString styleFileName); @@ -76,10 +79,10 @@ namespace AzQtComponents /*! * Call to initialize the StyleManager, allowing it to hook into the application and apply the global style + * The AzQtComponents does not hook in the AZ::Environment, so the Settings Registry isn't available + * Therefore the engine root path must be supplied via function arguments */ - void initialize(QApplication* application); - // deprecated; introduced before the new camelCase Qt based method names were adopted. - void Initialize(QApplication* application) { initialize(application); } + void initialize(QApplication* application, const AZ::IO::PathView& engineRootPath); /*! * Call this to force a refresh of the global stylesheet and a reload of any settings files. @@ -108,7 +111,7 @@ namespace AzQtComponents private: void initializeFonts(); - void initializeSearchPaths(QApplication* application); + void initializeSearchPaths(QApplication* application, const AZ::IO::PathView& engineRootPath); void resetWidgetSheets(); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.cpp index e32189f9fb..6da2056692 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,7 +91,8 @@ void StyleSheetCache::registerPathsFoundOnDisk(const QString& pathOnDisk, const } } -void StyleSheetCache::addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix) +void StyleSheetCache::addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix, + const AZ::IO::PathView& engineRootPath) { AZ_Warning("StyleSheetCache", m_prefixes.find(searchPrefix) == m_prefixes.end(), "Style prefix \"%s\" was already registered, ignoring...", searchPrefix.constData()); @@ -98,7 +101,7 @@ void StyleSheetCache::addSearchPaths(const QString& searchPrefix, const QString& QString diskPathToUse = pathOnDisk; if (!QFileInfo(pathOnDisk).isAbsolute()) { - QDir rootDir(AzQtComponents::FindEngineRootDir(qApp)); + QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size())); diskPathToUse = rootDir.absoluteFilePath(pathOnDisk); } diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.h index be07baf18b..dca77903fe 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/StyleSheetCache.h @@ -14,6 +14,8 @@ #if !defined(Q_MOC_RUN) #include +#include + #include #include #include @@ -45,7 +47,8 @@ namespace AzQtComponents public: static const QString& styleSheetExtension(); - void addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix); + void addSearchPaths(const QString& searchPrefix, const QString& pathOnDisk, const QString& qrcPrefix, + const AZ::IO::PathView& engineRootPath); void setFallbackSearchPaths(const QString& fallbackPrefix, const QString& pathOnDisk, const QString& qrcPrefix); QString loadStyleSheet(QString styleFileName); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/StyleSheetPage.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/StyleSheetPage.cpp index 8b71dd0af9..61e12ebd03 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/StyleSheetPage.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/StyleSheetPage.cpp @@ -13,6 +13,9 @@ #include "StyleSheetPage.h" #include "Gallery/ui_StyleSheetPage.h" +#include +#include + #include #include @@ -97,7 +100,12 @@ StyleSheetPage::StyleSheetPage(QWidget* parent) // developers. The style will be loaded from a Qt Resource file if Editor is installed, but // developers with the file on disk will be able to modify the style and have it automatically // reloaded. - AzQtComponents::StyleManager::addSearchPaths("gallery", pathOnDisk, qrcPath); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + AzQtComponents::StyleManager::addSearchPaths("gallery", pathOnDisk, qrcPath, engineRootPath); // The following label shows the intended use: AzQtComponents::StyleManager::setStyleSheet(ui->exampleWidget, "gallery:StyleSheetPage.qss"); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/main.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/main.cpp index d4d356611b..cffe20cb34 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/main.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/main.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -151,7 +153,12 @@ int main(int argc, char **argv) app.installEventFilter(globalEventFilter); AzQtComponents::StyleManager styleManager(&app); - styleManager.Initialize(&app); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + styleManager.initialize(&app, engineRootPath); auto wrapper = new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionNone); auto widget = new ComponentDemoWidget(wrapper); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/PropertyEditorStandalone/main.cpp b/Code/Framework/AzQtComponents/AzQtComponents/PropertyEditorStandalone/main.cpp index 21085a2c0b..3ba2d96451 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/PropertyEditorStandalone/main.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/PropertyEditorStandalone/main.cpp @@ -17,11 +17,14 @@ #include #include +#include +#include +#include +#include #include #include #include #include -#include #include #include @@ -168,6 +171,12 @@ public: int main(int argc, char** argv) { + AZ::IO::FixedMaxPath engineRootPath; + { + AZ::ComponentApplication componentApplication(argc, argv); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } AzQtComponents::PrepareQtPaths(); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); @@ -176,7 +185,7 @@ int main(int argc, char** argv) QApplication qtApp(argc, argv); AzQtComponents::StyleManager styleManager(&qtApp); - styleManager.Initialize(&qtApp); + styleManager.initialize(&qtApp, engineRootPath); StandaloneRPE::RPEApplication app(&argc, &argv); app.Start(AzFramework::Application::Descriptor()); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/StyleGallery/main.cpp b/Code/Framework/AzQtComponents/AzQtComponents/StyleGallery/main.cpp index 3e0aeac2e0..0fc03e58cc 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/StyleGallery/main.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/StyleGallery/main.cpp @@ -10,6 +10,9 @@ * */ #include "mainwidget.h" +#include +#include +#include #include #include #include @@ -173,15 +176,21 @@ static void addMenu(QMainWindow *w, const QString &name) menu->addAction("Longer item 5"); } -int main(int argv, char **argc) +int main(int argc, char **argv) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - QApplication app(argv, argc); + QApplication app(argc, argv); AzQtComponents::LumberyardStylesheet stylesheet(&app); - stylesheet.Initialize(&app); + AZ::IO::FixedMaxPath engineRootPath; + { + AZ::ComponentApplication componentApplication(argc, argv); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + stylesheet.initialize(&app, engineRootPath); auto wrapper = new AzQtComponents::WindowDecorationWrapper(); QMainWindow *w = new MainWindow(); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.cpp index 516d36f3dc..b57c3f98e2 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.cpp @@ -73,30 +73,5 @@ namespace AzQtComponents } #endif } - - QString FindEngineRootDir(QApplication* app) - { - // The QApplication must be initialized before this method is called - // so it must be passed in as a parameter, even if we don't use it. - (void)app; - - // Attempt to locate the engine by looking for 'engineroot.txt' and walking up the folder path until it is found (or not) - QDir appPath(QApplication::applicationDirPath()); - QString engineRootPath; - while (!appPath.isRoot()) - { - if (QFile::exists(appPath.filePath("engine.json"))) - { - engineRootPath = appPath.absolutePath(); - break; - } - if (!appPath.cdUp()) - { - break; - } - } - return engineRootPath; - - } } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.h b/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.h index 0d015ab9db..2f7ac60d0f 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtPluginPaths.h @@ -19,10 +19,6 @@ class QApplication; namespace AzQtComponents { - AZ_QT_COMPONENTS_API void PrepareQtPaths(); - - AZ_QT_COMPONENTS_API QString FindEngineRootDir(QApplication* app); - } // namespace AzQtComponents diff --git a/Code/Framework/AzTest/AzTest/Utils.cpp b/Code/Framework/AzTest/AzTest/Utils.cpp index 0cf0886c56..abf4cdf915 100644 --- a/Code/Framework/AzTest/AzTest/Utils.cpp +++ b/Code/Framework/AzTest/AzTest/Utils.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -170,25 +172,15 @@ namespace AZ AZStd::string GetEngineRootPath() { - static const AZStd::string engineFile = AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "engineroot.txt"; - AZStd::string currentPath = GetCurrentExecutablePath(); - AZStd::string enginePath = currentPath + engineFile; - if (AZ::IO::SystemFile::Exists(enginePath.c_str())) + if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) { - return currentPath; + return AZ::SettingsRegistryMergeUtils::FindEngineRoot(*registry).String(); } - size_t lastPathSeparator = currentPath.find_last_of(AZ_CORRECT_FILESYSTEM_SEPARATOR); - while (lastPathSeparator != AZStd::string::npos) + else { - currentPath.erase(lastPathSeparator); - enginePath = currentPath + engineFile; - if (AZ::IO::SystemFile::Exists(enginePath.c_str())) - { - return currentPath; - } - lastPathSeparator = currentPath.find_last_of(AZ_CORRECT_FILESYSTEM_SEPARATOR); + AZ::SettingsRegistryImpl localRegistry; + return AZ::SettingsRegistryMergeUtils::FindEngineRoot(localRegistry).String(); } - return ""; } AZStd::string ScopedAutoTempDirectory::Resolve(const char* path) const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 0ca97f5471..0ebba3a1d9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -290,15 +290,15 @@ namespace AzToolsFramework } // Initialize the engine config object based on the current - bool Initialize(const char* currentAppRoot) + bool Initialize(const char* currentEngineRoot) { // Start with the app root as the engine root (legacy), but check to see if the engine root // is external to the app root - azstrncpy(m_engineRoot, AZ_ARRAY_SIZE(m_engineRoot), currentAppRoot, strlen(currentAppRoot) + 1); + azstrncpy(m_engineRoot, AZ_ARRAY_SIZE(m_engineRoot), currentEngineRoot, strlen(currentEngineRoot) + 1); // From the appRoot, check and see if we can read any external engine reference in engine.json QString engineJsonFileName = QString(m_fileName); - QString engineJsonFilePath = QDir(currentAppRoot).absoluteFilePath(engineJsonFileName); + QString engineJsonFilePath = QDir(currentEngineRoot).absoluteFilePath(engineJsonFileName); // From the appRoot, check and see if we can read any external engine reference in engine.json if (!QFile::exists(engineJsonFilePath)) @@ -308,7 +308,7 @@ namespace AzToolsFramework } if (!ReadEngineConfigIntoMap(engineJsonFilePath, m_engineConfigMap)) { - AZ_Warning(m_logWindow, false, "Defaulting root engine path to '%s'", currentAppRoot); + AZ_Warning(m_logWindow, false, "Defaulting root engine path to '%s'", currentEngineRoot); return false; } @@ -397,9 +397,9 @@ namespace AzToolsFramework void ToolsApplication::InitializeEngineConfig() { - if (!m_engineConfigImpl->Initialize(GetAppRoot())) + if (!m_engineConfigImpl->Initialize(GetEngineRoot())) { - AZ_Warning(AzToolsFramework::Internal::s_startupLogWindow, false, "Defaulting engine root path to '%s'", GetAppRoot()); + AZ_Warning(AzToolsFramework::Internal::s_startupLogWindow, false, "Defaulting engine root path to '%s'", GetEngineRoot()); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp index a9c162848e..d00f01f422 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Archive/ArchiveComponent.cpp @@ -18,8 +18,8 @@ #include -#include -#include +#include +#include #include namespace AzToolsFramework @@ -46,7 +46,7 @@ namespace AzToolsFramework class ConsoleEchoCommunicator { public: - ConsoleEchoCommunicator(AzToolsFramework::ProcessCommunicator* communicator) + ConsoleEchoCommunicator(AzFramework::ProcessCommunicator* communicator) : m_communicator(communicator) { } @@ -103,7 +103,7 @@ namespace AzToolsFramework } } - AzToolsFramework::ProcessCommunicator* m_communicator = nullptr; + AzFramework::ProcessCommunicator* m_communicator = nullptr; }; void ArchiveComponent::Activate() @@ -372,7 +372,7 @@ namespace AzToolsFramework m_cv.notify_all(); } - ProcessLauncher::ProcessLaunchInfo info; + AzFramework::ProcessLauncher::ProcessLaunchInfo info; info.m_commandlineParameters = exePath + " " + commandLineArgs; info.m_showWindow = false; @@ -380,7 +380,7 @@ namespace AzToolsFramework { info.m_workingDirectory = workingDir; } - AZStd::unique_ptr watcher(ProcessWatcher::LaunchProcess(info, ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT)); + AZStd::unique_ptr watcher(AzFramework::ProcessWatcher::LaunchProcess(info, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT)); AZStd::string consoleOutput; AZ::u32 exitCode = static_cast(SevenZipExitCode::UserStoppedProcess); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp index 92f5ff197d..06b0dae8af 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp @@ -17,444 +17,313 @@ #include #include #include +#include #include #include -#include -#include #include #include -#include -#include -AZ_PUSH_DISABLE_WARNING(4127 4251 4800, "-Wunknown-warning-option") -#include -#include -#include -#include -AZ_POP_DISABLE_WARNING +#include - -namespace AzToolsFramework +namespace AzToolsFramework::AssetUtils::Internal { - namespace AssetUtils + constexpr const char* AssetProcessorSettingsKey{ "/Amazon/AssetProcessor/Settings" }; + + constexpr const char* AssetConfigPlatformDir = "AssetProcessorConfig"; + constexpr const char* RestrictedPlatformDir = "restricted"; + + AZStd::vector FindWildcardMatches(AZStd::string_view sourceFolder, AZStd::string_view relativeName) { - namespace Internal + if (relativeName.empty()) { + return {}; + } + + const int pathLen = sourceFolder.length() + 1; - const char AssetConfigPlatformDir[] = "AssetProcessorConfig"; - const char RestrictedPlatformDir[] = "restricted"; + AZ::IO::Path sourceWildcard{ sourceFolder }; - QStringList FindWildcardMatches(const QString& sourceFolder, QString relativeName) + + AZStd::vector returnList; + + // Walks the sourceFolder and subdirectories to search for the relativeName as a wild card using a breathe-first search + AZStd::queue searchFolders; + searchFolders.push(AZStd::move(sourceWildcard)); + while (!searchFolders.empty()) + { + const AZ::IO::Path& searchFolder = searchFolders.front(); + AZ::IO::SystemFile::FindFileCB findFiles = [&returnList, &relativeName, &searchFolder, &searchFolders](AZStd::string_view fileView, bool isFile) -> bool { - if (relativeName.isEmpty()) + if (fileView == "." || fileView == "..") { - return QStringList(); + return true; } - const int pathLen = sourceFolder.length() + 1; - - relativeName.replace('\\', '/'); - - QStringList returnList; - QRegExp nameMatch{ relativeName, Qt::CaseInsensitive, QRegExp::Wildcard }; - QDirIterator diretoryIterator(sourceFolder, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); - QStringList files; - while (diretoryIterator.hasNext()) + if (isFile) { - diretoryIterator.next(); - if (!diretoryIterator.fileInfo().isFile()) - { - continue; - } - QString pathMatch{ diretoryIterator.filePath().mid(pathLen) }; - if (nameMatch.exactMatch(pathMatch)) + if (AZStd::wildcard_match(relativeName, fileView)) { - returnList.append(diretoryIterator.filePath()); + returnList.emplace_back(searchFolder / fileView); } } - return returnList; - } - - void ReadPlatformInfosFromConfigFile(QString configFile, QStringList& enabledPlatforms) - { - // in the inifile the platform can be missing (commented out) - // in which case it is disabled implicitly by not being there - // or it can be 'disabled' which means that it is explicitly disabled. - // or it can be 'enabled' which means that it is explicitly enabled. - - if (!QFile::exists(configFile)) + else { - return; + // Use the current search directory to append the fileView directory wild card + searchFolders.push(searchFolder / fileView); } - QSettings loader(configFile, QSettings::IniFormat); + return true; + }; - // Read in enabled platforms - loader.beginGroup("Platforms"); - QStringList keys = loader.allKeys(); - for (int idx = 0; idx < keys.count(); idx++) - { - QString val = loader.value(keys[idx]).toString(); - QString platform = keys[idx].toLower().trimmed(); - val = val.toLower().trimmed(); + AZ::IO::SystemFile::FindFiles((searchFolder / "*").c_str(), findFiles); + searchFolders.pop(); + } - if (val == "enabled") - { - if (!enabledPlatforms.contains(val)) - { - enabledPlatforms.push_back(platform); - } - } - else if (val == "disabled") - { - // disable platform explicitly. - int index = enabledPlatforms.indexOf(platform); - if (index != -1) - { - enabledPlatforms.removeAt(index); - } - } - } - loader.endGroup(); - } + return returnList; + } - void AddGemConfigFiles(const AZStd::vector& gemInfoList, QStringList& configFiles) + void AddGemConfigFiles(const AZStd::vector& gemInfoList, AZStd::vector& configFiles) + { + const char* AssetProcessorGemConfigIni = "AssetProcessorGemConfig.ini"; + const char* AssetProcessorGemConfigSetreg = "AssetProcessorGemConfig.setreg"; + for (const AzFramework::GemInfo& gemElement : gemInfoList) + { + for (const AZ::IO::Path& gemAbsoluteSourcePath : gemElement.m_absoluteSourcePaths) { - // there can only be one gam gem per project, so if we find one, we cache the name of it so that - // later we can add it to the very end of the list, giving it the ability to override all other config files. - QString gameConfigPath; - - for (const GemInfo& gemElement : gemInfoList) - { - QString gemAbsolutePath(gemElement.m_absoluteFilePath.c_str()); + configFiles.push_back(gemAbsoluteSourcePath / AssetProcessorGemConfigIni); + configFiles.push_back(gemAbsoluteSourcePath / AssetProcessorGemConfigSetreg); + } + } + } +} - QDir gemDir(gemAbsolutePath); - QString absPathToConfigFile = gemDir.absoluteFilePath("AssetProcessorGemConfig.ini"); - if (gemElement.m_isGameGem) - { - gameConfigPath = absPathToConfigFile; - } - else - { - configFiles.push_back(absPathToConfigFile); - } - } +namespace AzToolsFramework::AssetUtils +{ + // Visitor for reading the "/Amazon/AssetProcessor/Settings/Platforms" entries from the Settings Registry + struct EnabledPlatformsVisitor + : AZ::SettingsRegistryInterface::Visitor + { + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value); - // if a 'game gem' was discovered during the above loop, we want to append it to the END of the list - if (!gameConfigPath.isEmpty()) - { - configFiles.push_back(gameConfigPath); - } - } + AZStd::vector m_enabledPlatforms; + }; - bool AddPlatformConfigFilePaths(const char* root, QStringList& configFilePaths) + void EnabledPlatformsVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) + { + if (value == "enabled") + { + m_enabledPlatforms.emplace_back(valueName); + } + else if (value == "disabled") + { + auto platformEntrySearch = [&valueName](AZStd::string_view platformEntry) { - QString configWildcardName{ "*" }; - configWildcardName.append(AssetProcessorPlatformConfigFileName); - QDir sourceRoot(root); + return valueName == platformEntry; + }; + auto removeIt = AZStd::remove_if(m_enabledPlatforms.begin(), m_enabledPlatforms.end(), platformEntrySearch); + m_enabledPlatforms.erase(removeIt, m_enabledPlatforms.end()); + } + } - // first collect public platform configs - QStringList platformList = FindWildcardMatches(sourceRoot.filePath(AssetConfigPlatformDir), configWildcardName); + void ReadEnabledPlatformsFromSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, + AZStd::vector& enabledPlatforms) + { + // note that the current host platform is enabled by default. + enabledPlatforms.push_back(AzToolsFramework::AssetSystem::GetHostAssetPlatform()); + + // in the setreg the platform can be missing (commented out) + // in which case it is disabled implicitly by not being there + // or it can be 'disabled' which means that it is explicitly disabled. + // or it can be 'enabled' which means that it is explicitly enabled. + EnabledPlatformsVisitor visitor; + settingsRegistry.Visit(visitor, AZ::SettingsRegistryInterface::FixedValueString(Internal::AssetProcessorSettingsKey) + "/Platforms"); + enabledPlatforms.insert(enabledPlatforms.end(), AZStd::make_move_iterator(visitor.m_enabledPlatforms.begin()), + AZStd::make_move_iterator(visitor.m_enabledPlatforms.end())); + } + + AZStd::vector GetEnabledPlatforms(AZ::SettingsRegistryInterface& settingsRegistry, + const AZStd::vector& configFiles) + { + AZStd::vector enabledPlatforms; - // then collect restricted platform configs - QDirIterator it(sourceRoot.filePath(RestrictedPlatformDir), QDir::NoDotAndDotDot | QDir::Dirs); - while (it.hasNext()) + for (const auto& configFile : configFiles) + { + if (AZ::IO::SystemFile::Exists(configFile.c_str())) + { + // If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function + // otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style + // file to the settings registry + if (configFile.Extension() == ".setreg") { - QDir platformDir(it.next()); - platformList << FindWildcardMatches(platformDir.filePath(AssetConfigPlatformDir), configWildcardName); + settingsRegistry.MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch); } - - for (const auto& thisConfig : platformList) + else { - configFilePaths.append(thisConfig); + AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings; + configParserSettings.m_registryRootPointerPath = Internal::AssetProcessorSettingsKey; + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(settingsRegistry, configFile.Native(), configParserSettings); } - return (platformList.size() > 0); } } + ReadEnabledPlatformsFromSettingsRegistry(settingsRegistry, enabledPlatforms); + return enabledPlatforms; + } - const char* AssetProcessorPlatformConfigFileName = "AssetProcessorPlatformConfig.ini"; - const char* AssetProcessorGamePlatformConfigFileName = "AssetProcessorGamePlatformConfig.ini"; - const char GemsDirectoryName[] = "Gems"; - - GemInfo::GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath, AZStd::string identifier, bool isGameGem, bool assetOnlyGem) - : m_gemName(name) - , m_relativeFilePath(relativeFilePath) - , m_absoluteFilePath(absoluteFilePath) - , m_identifier(identifier) - , m_isGameGem(isGameGem) - , m_assetOnly(assetOnlyGem) - { - } + constexpr const char* AssetProcessorPlatformConfigFileName = "AssetProcessorPlatformConfig.ini"; + constexpr const char* AssetProcessorPlatformConfigSetreg = "AssetProcessorPlatformConfig.setreg"; - QStringList GetEnabledPlatforms(QStringList configFiles) - { - QStringList enabledPlatforms; + bool AddPlatformConfigFilePaths(AZStd::string_view engineRoot, AZStd::vector& configFilePaths) + { + auto restrictedRoot = AZ::IO::Path{ engineRoot } / Internal::RestrictedPlatformDir; - // note that the current host platform is enabled by default. - enabledPlatforms.push_back(AzToolsFramework::AssetSystem::GetHostAssetPlatform()); + // first collect public platform configs + AZStd::vector platformDirs{ AZ::IO::Path{ engineRoot } / Internal::AssetConfigPlatformDir }; - for (const QString& configFile : configFiles) + // then collect restricted platform configs + // Append the AssetConfigPlatformDir value to each directory + AZ::IO::SystemFile::FindFileCB findRestrictedAssetConfigs = [&restrictedRoot, &platformDirs](AZStd::string_view fileView, bool isFile) -> bool + { + if (fileView != "." && fileView != "..") { - Internal::ReadPlatformInfosFromConfigFile(configFile, enabledPlatforms); + if (!isFile) + { + platformDirs.push_back(restrictedRoot / fileView / Internal::AssetConfigPlatformDir); + } } - return enabledPlatforms; - } + return true; + }; + AZ::IO::SystemFile::FindFiles((restrictedRoot / "*").c_str(), findRestrictedAssetConfigs); - QStringList GetConfigFiles(const char* root, const char* assetRoot, const char* gameName, bool addPlatformConfigs, bool addGemsConfigs) + // Iterator over all platform directories for platform config files + AZStd::vector allPlatformConfigs; + for (const auto& platformDir : platformDirs) { - QStringList configFiles; - QDir configRoot(root); - - QString rootConfigFile = configRoot.filePath(AssetProcessorPlatformConfigFileName); - - configFiles.push_back(rootConfigFile); - if (addPlatformConfigs) + for (const char* configPath : { AssetProcessorPlatformConfigFileName, AssetProcessorPlatformConfigSetreg }) { - Internal::AddPlatformConfigFilePaths(root, configFiles); + AZStd::vector platformConfigs = Internal::FindWildcardMatches(platformDir.Native(), configPath); + allPlatformConfigs.insert(allPlatformConfigs.end(), AZStd::make_move_iterator(platformConfigs.begin()), AZStd::make_move_iterator(platformConfigs.end())); } + } - if (addGemsConfigs) - { - AZStd::vector gemInfoList; - if (!GetGemsInfo(root, assetRoot, gameName, gemInfoList)) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to read gems for game project (%s).\n", gameName); - return {}; - } - - Internal::AddGemConfigFiles(gemInfoList, configFiles); - } + const bool platformConfigFilePathsAdded = !allPlatformConfigs.empty(); + configFilePaths.insert(configFilePaths.end(), AZStd::make_move_iterator(allPlatformConfigs.begin()), AZStd::make_move_iterator(allPlatformConfigs.end())); + return platformConfigFilePathsAdded; + } - QDir assetRootDir(assetRoot); - assetRootDir.cd(gameName); + AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath, + bool addPlatformConfigs, bool addGemsConfigs, AZ::SettingsRegistryInterface* settingsRegistry) + { + constexpr const char* AssetProcessorGamePlatformConfigFileName = "AssetProcessorGamePlatformConfig.ini"; + constexpr const char* AssetProcessorGamePlatformConfigSetreg = "AssetProcessorGamePlatformConfig.setreg"; + AZStd::vector configFiles; + AZ::IO::Path configRoot(engineRoot); - QString projectConfigFile = assetRootDir.filePath(AssetProcessorGamePlatformConfigFileName); + AZ::IO::Path rootConfigFile = configRoot / AssetProcessorPlatformConfigFileName; + configFiles.push_back(rootConfigFile); - configFiles.push_back(projectConfigFile); + // Add a file entry for the Engine Root AssetProcessor setreg file + rootConfigFile = configRoot / AssetProcessorPlatformConfigSetreg; + configFiles.push_back(rootConfigFile); - return configFiles; + if (addPlatformConfigs) + { + AddPlatformConfigFilePaths(engineRoot, configFiles); } - static GemInfo ParseGemInfo(const rapidjson::Document& gemJsonDocument) + if (addGemsConfigs) { - constexpr AZStd::fixed_string<32> NameKey = "Name"; - constexpr AZStd::fixed_string<32> UuidKey = "Uuid"; - constexpr AZStd::fixed_string<32> LinkTypeKey = "LinkType"; - constexpr AZStd::fixed_string<32> IsGameGemKey = "IsGameGem"; - - GemInfo gemInfo; - auto memberIter = gemJsonDocument.FindMember(NameKey.c_str()); - if (memberIter != gemJsonDocument.MemberEnd()) + AZStd::vector gemInfoList; + if (!AzFramework::GetGemsInfo(gemInfoList, *settingsRegistry)) { - gemInfo.m_gemName.assign(memberIter->value.GetString(), memberIter->value.GetStringLength()); + AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to read gems from project folder(%s).\n", projectPath); + return {}; } - memberIter = gemJsonDocument.FindMember(UuidKey.c_str()); - if (memberIter != gemJsonDocument.MemberEnd()) - { - gemInfo.m_identifier.assign(memberIter->value.GetString(), memberIter->value.GetStringLength()); - } + Internal::AddGemConfigFiles(gemInfoList, configFiles); + } - memberIter = gemJsonDocument.FindMember(IsGameGemKey.c_str()); - if (memberIter != gemJsonDocument.MemberEnd()) - { - gemInfo.m_isGameGem = memberIter->value.GetBool(); - } + AZ::IO::Path assetRootDir(assetRoot); + assetRootDir /= projectPath; + AZ::IO::Path projectConfigFile = assetRootDir / AssetProcessorGamePlatformConfigFileName; + configFiles.push_back(projectConfigFile); - AZStd::string_view linkTypeString; - memberIter = gemJsonDocument.FindMember(LinkTypeKey.c_str()); - if (memberIter != gemJsonDocument.MemberEnd()) - { - linkTypeString = AZStd::string_view{ memberIter->value.GetString(), memberIter->value.GetStringLength() }; - } + // Add a file entry for the Project AssetProcessor setreg file + projectConfigFile = assetRootDir / AssetProcessorGamePlatformConfigSetreg; + configFiles.push_back(projectConfigFile); - gemInfo.m_assetOnly = linkTypeString == "NoCode"; + return configFiles; + } - return gemInfo; + bool UpdateFilePathToCorrectCase(const QString& root, QString& relativePathFromRoot) + { + AZStd::string rootPath(root.toUtf8().data()); + AZStd::string relPathFromRoot(relativePathFromRoot.toUtf8().data()); + AZ::StringFunc::Path::Normalize(relPathFromRoot); + AZStd::vector tokens; + AZ::StringFunc::Tokenize(relPathFromRoot.c_str(), tokens, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); + + AZStd::string validatedPath; + if (rootPath.empty()) + { + AzFramework::ApplicationRequests::Bus::BroadcastResult(validatedPath, &AzFramework::ApplicationRequests::GetEngineRoot); } - - bool GetGemsInfo([[maybe_unused]] const char* root, [[maybe_unused]] const char* assetRoot, [[maybe_unused]] const char* gameName, AZStd::vector& gemInfoList) + else { - AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); - if (settingsRegistry == nullptr) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Settings Registry does not exist, cannot retrieve information about loaded Gem modules"); - return false; - } - - auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); - if (fileIoBase == nullptr) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "File IO, cannot retrieve information about loaded Gem modules"); - return false; - } + validatedPath = rootPath; + } - constexpr AZStd::string_view GemJsonFilename{ "gem.json" }; - AZStd::vector gemModuleSourcePaths; + bool success = true; - struct GemSourcePathsVisitor - : AZ::SettingsRegistryInterface::Visitor + for (int idx = 0; idx < tokens.size(); idx++) + { + AZStd::string element = tokens[idx]; + bool foundAMatch = false; + AZ::IO::FileIOBase::GetInstance()->FindFiles(validatedPath.c_str(), "*", [&](const char* file) { - GemSourcePathsVisitor(AZStd::vector& gemSourcePaths) - : m_gemSourcePaths(gemSourcePaths) - {} - - void Visit(AZStd::string_view path, [[maybe_unused]] AZStd::string_view valueName, [[maybe_unused]] AZ::SettingsRegistryInterface::Type type, - AZStd::string_view value) override + if (idx != tokens.size() - 1 && !AZ::IO::FileIOBase::GetInstance()->IsDirectory(file)) { - if (path.find("SourcePaths") != AZStd::string_view::npos - && AZStd::find(m_gemSourcePaths.begin(), m_gemSourcePaths.end(), value) == m_gemSourcePaths.end()) - { - m_gemSourcePaths.emplace_back(value); - } + // only the last token is supposed to be a filename, we can skip filenames before that + return true; } - AZStd::vector& m_gemSourcePaths; - }; - - GemSourcePathsVisitor visitor{ gemModuleSourcePaths }; - const auto gemListKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/Gems", AZ::SettingsRegistryMergeUtils::OrganizationRootKey); - AZ::SettingsRegistry::Get()->Visit(visitor, gemListKey); - - AZ::IO::FixedMaxPath engineRootPath; - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - if (engineRootPath.empty()) - { - AZ_TracePrintfOnce("AzToolsFramework::AssetUtils", "Engine Root Path is empty. The Gem Module Source Paths will have the @engroot@ alias prepended"); - engineRootPath = "@engroot@"; - } - AZStd::vector gemJsonFileData; - for (const AZ::IO::FixedMaxPath& gemSourcePath : gemModuleSourcePaths) - { - AZ::IO::FixedMaxPath gemJsonPath = engineRootPath / gemSourcePath / GemJsonFilename; - if (AZ::IO::HandleType gemJsonHandle; fileIoBase->Open(gemJsonPath.c_str(), AZ::IO::OpenMode::ModeRead, gemJsonHandle)) + AZStd::string absFilePath(file); + AZ::StringFunc::Path::Normalize(absFilePath); + auto found = absFilePath.rfind(AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); + size_t startingPos = found + 1; + if (found != AZStd::string::npos && absFilePath.size() > startingPos) { - AZ::IO::SizeType gemJsonFileSize; - if (AZ::IO::Result ioResult = fileIoBase->Size(gemJsonHandle, gemJsonFileSize); !ioResult) + AZStd::string componentName = AZStd::string(absFilePath.begin() + startingPos, absFilePath.end()); + if (AZ::StringFunc::Equal(componentName.c_str(), tokens[idx].c_str())) { - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to query file size of gem json at path '%s'.\nResult code %u returned", - gemJsonPath.c_str(), aznumeric_cast(ioResult.GetResultCode())); - fileIoBase->Close(gemJsonHandle); - continue; + tokens[idx] = componentName; + foundAMatch = true; + return false; } - - gemJsonFileData.resize_no_construct(gemJsonFileSize); - AZ::IO::SizeType bytesRead{}; - if (AZ::IO::Result ioResult = fileIoBase->Read(gemJsonHandle, gemJsonFileData.data(), gemJsonFileData.size(), false, &bytesRead); !ioResult) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Reading from gem json at path '%s' has failed with result code %u.\n%zu has been read", - gemJsonPath.c_str(), aznumeric_cast(ioResult.GetResultCode()), bytesRead); - fileIoBase->Close(gemJsonHandle); - continue; - } - - rapidjson::Document gemJsonDocument; - gemJsonDocument.Parse(gemJsonFileData.data(), gemJsonFileData.size()); - if (gemJsonDocument.HasParseError()) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Parsing gem json at path '%s' has json Parse Error: %s", - gemJsonPath.c_str(), rapidjson::GetParseError_En(gemJsonDocument.GetParseError())) - } - - GemInfo gemInfo = ParseGemInfo(gemJsonDocument); - - - char gemJsonResolvePath[AZ::IO::MaxPathLength]; - const bool foundFilename = fileIoBase->GetFilename(gemJsonHandle, AZStd::data(gemJsonResolvePath), AZStd::size(gemJsonResolvePath)); - if (foundFilename) - { - // Set the Absolute path to the folder containing the gem.json file - gemInfo.m_absoluteFilePath = AZ::IO::PathView(gemJsonResolvePath).ParentPath().Native(); - } - else - { - // If unable to retrieve the Filename from the File IO handle the gemJsonPath is used instead - gemInfo.m_absoluteFilePath = gemJsonPath.ParentPath().Native(); - } - - // The gemSourcePath is the relative path - gemInfo.m_relativeFilePath = static_cast(gemSourcePath.Native()); - gemInfoList.push_back(gemInfo); - fileIoBase->Close(gemJsonHandle); } - } - return true; - } + return true; + }); - bool UpdateFilePathToCorrectCase(const QString& root, QString& relativePathFromRoot) - { - AZStd::string rootPath(root.toUtf8().data()); - AZStd::string relPathFromRoot(relativePathFromRoot.toUtf8().data()); - AZ::StringFunc::Path::Normalize(relPathFromRoot); - AZStd::vector tokens; - AZ::StringFunc::Tokenize(relPathFromRoot.c_str(), tokens, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); - - AZStd::string validatedPath; - if (rootPath.empty()) - { - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - validatedPath = AZStd::string(appRoot); - } - else + if (!foundAMatch) { - validatedPath = rootPath; + success = false; + break; } - bool success = true; - - for (int idx = 0; idx < tokens.size(); idx++) - { - AZStd::string element = tokens[idx]; - bool foundAMatch = false; - AZ::IO::FileIOBase::GetInstance()->FindFiles(validatedPath.c_str(), "*", [&](const char* file) - { - if ( idx != tokens.size() - 1 && !AZ::IO::FileIOBase::GetInstance()->IsDirectory(file)) - { - // only the last token is supposed to be a filename, we can skip filenames before that - return true; - } - - AZStd::string absFilePath(file); - AZ::StringFunc::Path::Normalize(absFilePath); - auto found = absFilePath.rfind(AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); - size_t startingPos = found + 1; - if (found != AZStd::string::npos && absFilePath.size() > startingPos) - { - AZStd::string componentName = AZStd::string(absFilePath.begin() + startingPos, absFilePath.end()); - if (AZ::StringFunc::Equal(componentName.c_str(), tokens[idx].c_str())) - { - tokens[idx] = componentName; - foundAMatch = true; - return false; - } - } - - return true; - }); - - if (!foundAMatch) - { - success = false; - break; - } - - AZStd::string absoluteFilePath; - AZ::StringFunc::Path::ConstructFull(validatedPath.c_str(), element.c_str(), absoluteFilePath); - - validatedPath = absoluteFilePath; // go one step deeper. - } + AZStd::string absoluteFilePath; + AZ::StringFunc::Path::ConstructFull(validatedPath.c_str(), element.c_str(), absoluteFilePath); - if (success) - { - relPathFromRoot.clear(); - AZ::StringFunc::Join(relPathFromRoot, tokens.begin(), tokens.end(), AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); - relativePathFromRoot = relPathFromRoot.c_str(); - } + validatedPath = absoluteFilePath; // go one step deeper. + } - return success; + if (success) + { + relPathFromRoot.clear(); + AZ::StringFunc::Join(relPathFromRoot, tokens.begin(), tokens.end(), AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); + relativePathFromRoot = relPathFromRoot.c_str(); } - } //namespace AssetUtils -} //namespace AzToolsFramework + + return success; + } +} //namespace AzToolsFramework::AssetUtils diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h index 1ecdcfb944..463f1b93d5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h @@ -9,64 +9,48 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ - #pragma once + +#include #include #include #include -AZ_PUSH_DISABLE_WARNING(4127 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -namespace AzToolsFramework -{ - namespace AssetUtils - { - extern const char* AssetProcessorPlatformConfigFileName; - extern const char* AssetProcessorGamePlatformConfigFileName; - - //! This struct stores gem related information - struct GemInfo - { - AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0); - GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath, AZStd::string identifier, bool isGameGem, bool assetOnlyGem); - GemInfo() = default; - AZStd::string m_gemName; ///< A friendly display name, not to be used for any pathing stuff. - AZStd::string m_relativeFilePath; ///< Where the gem's folder is (relative to the gems search path(s)) - AZStd::string m_absoluteFilePath; ///< Where the gem's folder is (as an absolute path) - AZStd::string m_identifier; ///< The UUID of the gem. - - bool m_isGameGem = false; //< True if its a 'game project' gem. Only one such gem can exist for any game project. - bool m_assetOnly = false; ///< True if it is an asset only gems. +#include - static AZStd::string GetGemAssetFolder() { return AZStd::string("Assets"); } +class QString; - }; - - //! Returns all the enabledPlatforms by reading the specified config files in order. - QStringList GetEnabledPlatforms(QStringList configFiles); - - //! Returns all the config files including the the platform and gems ones. - //! Please note that config files are order dependent - //! the root config file has the lowest priority. - //! the project configuration file has the absolutely highest priority - //! Also note that if the project has any "game project gems", then those will also be inserted last, - //! and thus have a higher priority than the root or non - project gems. - //! Also note that the game project could be in a different location to the engine therefore we need the assetRoot param. - QStringList GetConfigFiles(const char* root, const char* assetRoot, const char* gameName, bool addPlatformConfigs = true, bool addGemsConfigs = true); - - //! Returns a list of GemInfo of all the gems that are active for the for the specified game project. - //! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param. - bool GetGemsInfo(const char* root, const char* assetRoot, const char* gameName, AZStd::vector& gemInfoList); - - //! A utility function which checks the given path starting at the root and updates the relative path to be the actual case correct path. - //! For example, if you pass it "c:\lumberyard\dev" as the root and "editor\icons\whatever.ico" as the relative path. - //! It may update relativePathFromRoot to be "Editor\Icons\Whatever.ico" if such a casing is the actual physical case on disk already. - //! @param root a trusted already-case-correct path (will not be case corrected). If empty it will be set to appRoot. - //! @param relativePathFromRoot a non-trusted (may be incorrect case) path relative to rootPath, - //! which will be normalized and updated to be correct casing. - //! @return if such a file does NOT exist, it returns FALSE, else returns TRUE. - //! @note A very expensive function! Call sparingly. - bool UpdateFilePathToCorrectCase(const QString& root, QString& relativePathFromRoot); - } //namespace AssetUtils -} //namespace AzToolsFramework +namespace AzToolsFramework::AssetUtils +{ + //! Reads the "/Amazon/AssetProcessor/Settings/Platforms" entry from the settings registry + //! to retrieve all enabled platforms + void ReadEnabledPlatformsFromSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, + AZStd::vector& enabledPlatforms); + + //! Returns all the enabledPlatforms by reading the specified config files in order. + AZStd::vector GetEnabledPlatforms(AZ::SettingsRegistryInterface& settingsRegistry, + const AZStd::vector& configFiles); + + //! Returns the platform specific AssetProcessorPlatformConfig.ini/setreg files + //! Please note that config files are order dependent + bool AddPlatformConfigFilePaths(AZStd::string_view root, AZStd::vector& configFilePaths); + + //! Returns all the config files including the the platform and gems ones. + //! Please note that config files are order dependent + //! the root config file has the lowest priority. + //! the project configuration file has the absolutely highest priority + //! Also note that if the project has any "game project gems", then those will also be inserted last, + //! and thus have a higher priority than the root or non - project gems. + //! Also note that the game project could be in a different location to the engine therefore we need the assetRoot param. + AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath, + bool addPlatformConfigs = true, bool addGemsConfigs = true, AZ::SettingsRegistryInterface* settingsRegistry = nullptr); + + //! A utility function which checks the given path starting at the root and updates the relative path to be the actual case correct path. + //! For example, if you pass it "c:\lumberyard\dev" as the root and "editor\icons\whatever.ico" as the relative path. + //! It may update relativePathFromRoot to be "Editor\Icons\Whatever.ico" if such a casing is the actual physical case on disk already. + //! @param root a trusted already-case-correct path (will not be case corrected). If empty it will be set to appRoot. + //! @param relativePathFromRoot a non-trusted (may be incorrect case) path relative to rootPath, + //! which will be normalized and updated to be correct casing. + //! @return if such a file does NOT exist, it returns FALSE, else returns TRUE. + //! @note A very expensive function! Call sparingly. + bool UpdateFilePathToCorrectCase(const QString& root, QString& relativePathFromRoot); +} //namespace AzToolsFramework::AssetUtils diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.cpp index 37c803f0b0..983f7eb347 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.cpp @@ -13,8 +13,9 @@ #include #include #include -#include -#include +#include +#include +#include namespace AzToolsFramework @@ -54,38 +55,26 @@ namespace AzToolsFramework AZStd::string PlatformAddressedAssetCatalog::GetAssetRootForPlatform(AzFramework::PlatformId platformId) { - const char* assetAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); - if (assetAlias == nullptr) + AZ::IO::Path projectCachePath; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr + || !settingsRegistry->Get(projectCachePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) { - AZ_Error("PlatformAddressedAssetCatalog", false, "Failed to retrieve assetRoot"); - return {}; - } - AZ::IO::PathView assetRoot{ assetAlias }; - // Folder structure is Cache/Projectfolder/platform/projectfolder - // It should have at least one path separator - if (assetRoot.Native().find_first_of(AZ_CORRECT_AND_WRONG_DATABASE_SEPARATOR) == AZStd::string::npos) - { - AZ_Warning("PlatformAddressedAssetCatalog", false, "Failed to retrieve valid asset root - got %.*s", - aznumeric_cast(assetRoot.Native().size()), assetRoot.Native().data()); + AZ_Warning("PlatformAddressedAssetCatalog", false, "Failed to retrieve valid project cache root from Settings Registry at key %s", + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder); return {}; } - AZ::IO::PathView projectFolderLower = assetRoot.Filename(); - assetRoot = assetRoot.ParentPath(); - // Retrieve the Cache/Projectfolder path - AZ::IO::Path platformAssetRoot = assetRoot.ParentPath(); - platformAssetRoot /= GetPlatformName(platformId); - platformAssetRoot /= projectFolderLower; - return platformAssetRoot.Native(); + // Retrieve the ProjectPath/Cache/ path + AZ::IO::Path platformCachePath = projectCachePath / GetPlatformName(platformId); + return platformCachePath.Native(); } //! Returns an absolute path to the AssetCatalog for a given platform AZStd::string PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId platformId) { - AZStd::string assetRoot = GetAssetRootForPlatform(platformId); - AzFramework::StringFunc::Path::Join(assetRoot.c_str(), "assetcatalog.xml", assetRoot); - - return assetRoot; + AZ::IO::Path platformCachePath = GetAssetRootForPlatform(platformId); + return (platformCachePath / "assetcatalog.xml").Native(); } AZStd::string PlatformAddressedAssetCatalog::GetCatalogRegistryPath() const @@ -202,7 +191,7 @@ namespace AzToolsFramework { return AssetCatalog::GetDirectProductDependencies(asset); } - + AZ::Outcome, AZStd::string> PlatformAddressedAssetCatalog::GetAllProductDependencies(const AZ::Data::AssetId& asset) { return AssetCatalog::GetAllProductDependencies(asset); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceComponent.cpp index 02cced4b51..20e3bfc59a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceComponent.cpp @@ -22,7 +22,7 @@ #include -#include +#include #include namespace AzToolsFramework @@ -1251,14 +1251,14 @@ namespace AzToolsFramework return changelistNum; } - ProcessWatcher* pWatcher = s_perforceConn->m_command.ExecuteNewChangelistInput(); + AzFramework::ProcessWatcher* pWatcher = s_perforceConn->m_command.ExecuteNewChangelistInput(); AZ_Assert(pWatcher, "No process found for p4!"); if (!pWatcher) { return 0; } - ProcessCommunicator* pCommunicator = pWatcher->GetCommunicator(); + AzFramework::ProcessCommunicator* pCommunicator = pWatcher->GetCommunicator(); AZ_Assert(pCommunicator, "No communicator found for p4!"); if (!pCommunicator) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.cpp index 6014514457..f492c8c969 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.cpp @@ -13,7 +13,7 @@ #include "AzToolsFramework_precompiled.h" #include -#include +#include #define SCC_WINDOW "Source Control" @@ -331,7 +331,7 @@ namespace AzToolsFramework ExecuteCommand(); } - ProcessWatcher* PerforceCommand::ExecuteNewChangelistInput() + AzFramework::ProcessWatcher* PerforceCommand::ExecuteNewChangelistInput() { m_commandArgs = "change -i"; return ExecuteIOCommand(); @@ -370,31 +370,31 @@ namespace AzToolsFramework void PerforceCommand::ExecuteCommand() { m_rawOutput.Clear(); - ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = "p4 -ztag " + m_commandArgs; processLaunchInfo.m_showWindow = false; - ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, m_rawOutput); - m_applicationFound = processLaunchInfo.m_launchResult == ProcessLauncher::PLR_MissingFile ? false : true; + AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, m_rawOutput); + m_applicationFound = processLaunchInfo.m_launchResult == AzFramework::ProcessLauncher::PLR_MissingFile ? false : true; } - ProcessWatcher* PerforceCommand::ExecuteIOCommand() + AzFramework::ProcessWatcher* PerforceCommand::ExecuteIOCommand() { - ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = "p4 " + m_commandArgs; processLaunchInfo.m_showWindow = false; - ProcessWatcher* processWatcher = ProcessWatcher::LaunchProcess(processLaunchInfo, ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT); - m_applicationFound = processLaunchInfo.m_launchResult == ProcessLauncher::PLR_MissingFile ? false : true; + AzFramework::ProcessWatcher* processWatcher = AzFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT); + m_applicationFound = processLaunchInfo.m_launchResult == AzFramework::ProcessLauncher::PLR_MissingFile ? false : true; return processWatcher; } void PerforceCommand::ExecuteRawCommand() { m_rawOutput.Clear(); - ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = "p4 " + m_commandArgs; processLaunchInfo.m_showWindow = false; - ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, m_rawOutput); - m_applicationFound = processLaunchInfo.m_launchResult == ProcessLauncher::PLR_MissingFile ? false : true; + AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, m_rawOutput); + m_applicationFound = processLaunchInfo.m_launchResult == AzFramework::ProcessLauncher::PLR_MissingFile ? false : true; } AZStd::string PerforceConnection::GetUser() const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.h index e319bc5998..52fa9dee4f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/PerforceConnection.h @@ -13,16 +13,19 @@ #pragma once #include -#include +#include -namespace AzToolsFramework +namespace AzFramework { class ProcessWatcher; +} +namespace AzToolsFramework +{ class PerforceCommand { public: - ProcessOutput m_rawOutput; + AzFramework::ProcessOutput m_rawOutput; PerforceMap m_commandOutputMap; // doesn't allow duplicate kvp's AZStd::vector m_commandOutputMapList; // allows duplicate kvp's @@ -79,7 +82,7 @@ namespace AzToolsFramework void ExecuteTicketStatus(); void ExecuteTrust(bool enable, const AZStd::string& fingerprint); - ProcessWatcher* ExecuteNewChangelistInput(); + AzFramework::ProcessWatcher* ExecuteNewChangelistInput(); void ExecuteNewChangelistOutput(); void ExecuteRevert(const AZStd::string& filePath); void ExecuteShowChangelists(const AZStd::string& currentUser, const AZStd::string& currentClient); @@ -91,7 +94,7 @@ namespace AzToolsFramework bool m_applicationFound = false; virtual void ExecuteCommand(); - virtual ProcessWatcher* ExecuteIOCommand(); + virtual AzFramework::ProcessWatcher* ExecuteIOCommand(); virtual void ExecuteRawCommand(); }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/LegacyFramework/Core/EditorFrameworkApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/LegacyFramework/Core/EditorFrameworkApplication.cpp index 7b0171c5b7..9f4e75bb7c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/LegacyFramework/Core/EditorFrameworkApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/LegacyFramework/Core/EditorFrameworkApplication.cpp @@ -193,18 +193,6 @@ namespace LegacyFramework // if we're in console mode, listen for CTRL+C ::SetConsoleCtrlHandler(CTRL_BREAK_HandlerRoutine, true); #endif - - m_ptrCommandLineParser = aznew AzFramework::CommandLine(); - m_ptrCommandLineParser->Parse(m_desc.m_argc, m_desc.m_argv); - if (m_ptrCommandLineParser->HasSwitch("app-root")) - { - auto appRootOverride = m_ptrCommandLineParser->GetSwitchValue("app-root", 0); - if (!appRootOverride.empty()) - { - m_appRoot = appRootOverride; - } - } - // If we don't have one create a serialize context if (GetSerializeContext() == nullptr) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 76c0fb0569..9bbd719cf3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -18,8 +18,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -147,7 +149,13 @@ namespace AzToolsFramework m_gui = new Ui::EntityOutlinerWidgetUI(); m_gui->setupUi(this); - QDir rootDir(AzQtComponents::FindEngineRootDir(qApp)); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + + QDir rootDir = QString::fromUtf8(engineRootPath.c_str(), aznumeric_cast(engineRootPath.Native().size())); const auto pathOnDisk = rootDir.absoluteFilePath(QStringLiteral("Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/")); const QStringView qrcPath = QStringLiteral(":/EntityOutliner"); @@ -155,7 +163,7 @@ namespace AzToolsFramework // developers. The style will be loaded from a Qt Resource file if Editor is installed, but // developers with the file on disk will be able to modify the style and have it automatically // reloaded. - AzQtComponents::StyleManager::addSearchPaths("outliner", pathOnDisk, qrcPath.toString()); + AzQtComponents::StyleManager::addSearchPaths("outliner", pathOnDisk, qrcPath.toString(), engineRootPath); AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("outliner:EntityOutliner.qss")); m_listModel = aznew EntityOutlinerListModel(this); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index aa49ab17fa..44179eb017 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -194,11 +194,6 @@ set(FILES Manipulators/TranslationManipulators.cpp Manipulators/TranslationManipulators.h Maths/TransformUtils.h - Process/ProcessCommunicator.cpp - Process/ProcessCommunicator.h - Process/ProcessWatcher.cpp - Process/ProcessWatcher.h - Process/ProcessCommon_fwd.h Picking/BoundInterface.h Picking/ContextBoundAPI.h Picking/Manipulators/ManipulatorBoundManager.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_linux_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_linux_files.cmake index 6135979d38..cc9db4d620 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_linux_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_linux_files.cmake @@ -32,8 +32,5 @@ set(FILES UI/UICore/SaveChangesDialog.hxx UI/UICore/SaveChangesDialog.cpp UI/UICore/SaveChangesDialog.ui - Process/internal/ProcessWatcher_Linux.cpp - Process/internal/ProcessCommon_Linux.h - Process/internal/ProcessCommunicator_Linux.cpp ToolsFileUtils/ToolsFileUtils_generic.cpp ) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_mac_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_mac_files.cmake index 9921cd95d6..cc9db4d620 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_mac_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_mac_files.cmake @@ -32,8 +32,5 @@ set(FILES UI/UICore/SaveChangesDialog.hxx UI/UICore/SaveChangesDialog.cpp UI/UICore/SaveChangesDialog.ui - Process/internal/ProcessWatcher_OSX.cpp - Process/internal/ProcessCommon_OSX.h - Process/internal/ProcessCommunicator_OSX.cpp ToolsFileUtils/ToolsFileUtils_generic.cpp ) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_win_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_win_files.cmake index a6b10588cd..97473ce7d2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_win_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_win_files.cmake @@ -33,8 +33,5 @@ set(FILES UI/UICore/SaveChangesDialog.hxx UI/UICore/SaveChangesDialog.cpp UI/UICore/SaveChangesDialog.ui - Process/internal/ProcessWatcher_Win.cpp - Process/internal/ProcessCommon_Win.h - Process/internal/ProcessCommunicator_Win.cpp ToolsFileUtils/ToolsFileUtils_win.cpp ) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_windows_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_windows_files.cmake index a9ee247a4e..0b085a5d31 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_windows_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_windows_files.cmake @@ -33,8 +33,5 @@ set(FILES UI/UICore/SaveChangesDialog.hxx UI/UICore/SaveChangesDialog.cpp UI/UICore/SaveChangesDialog.ui - Process/internal/ProcessWatcher_Win.cpp - Process/internal/ProcessCommon_Win.h - Process/internal/ProcessCommunicator_Win.cpp ToolsFileUtils/ToolsFileUtils_win.cpp ) \ No newline at end of file diff --git a/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp b/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp index 0ea50cf3f6..f71b55bb74 100644 --- a/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp +++ b/Code/Framework/AzToolsFramework/Platform/Windows/AzToolsFramework/Archive/ArchiveComponent_Windows.cpp @@ -35,7 +35,7 @@ namespace AzToolsFramework AZStd::string Get7zExePath() { const char* rootPath = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(rootPath, &AZ::ComponentApplicationRequests::GetAppRoot); + AZ::ComponentApplicationBus::BroadcastResult(rootPath, &AZ::ComponentApplicationRequests::GetEngineRoot); AZStd::string exePath; AzFramework::StringFunc::Path::ConstructFull(rootPath, "Tools", "7za", ".exe", exePath); return exePath; diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp index ff6b645695..13e4d15b96 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace // anonymous { @@ -179,7 +180,7 @@ namespace UnitTest const AZStd::string engroot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str()); - AZ::IO::Path assetRoot(engroot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); diff --git a/Code/Framework/AzToolsFramework/Tests/Main.cpp b/Code/Framework/AzToolsFramework/Tests/Main.cpp index 21a08ddea7..839bc82433 100644 --- a/Code/Framework/AzToolsFramework/Tests/Main.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Main.cpp @@ -11,7 +11,10 @@ */ #include +#include +#include #include +#include #include #include @@ -40,7 +43,13 @@ AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv) ::testing::InitGoogleMock(&argc, argv); QApplication app(argc, argv); auto styleManager = AZStd::make_unique< AzQtComponents::StyleManager>(&app); - styleManager->initialize(&app); + AZ::IO::FixedMaxPath engineRootPath; + { + AZ::ComponentApplication componentApplication(argc, argv); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + styleManager->initialize(&app, engineRootPath); AZ::Test::printUnusedParametersWarning(argc, argv); AZ::Test::addTestEnvironments({ new ToolsFrameworkHook }); int result = RUN_ALL_TESTS(); diff --git a/Code/Framework/Tests/Application.cpp b/Code/Framework/Tests/Application.cpp index 224d1897ac..a260c9f1cd 100644 --- a/Code/Framework/Tests/Application.cpp +++ b/Code/Framework/Tests/Application.cpp @@ -11,7 +11,9 @@ */ #include "FrameworkApplicationFixture.h" -#include +#include +#include +#include #include class ApplicationTest @@ -22,7 +24,14 @@ protected: void SetUp() override { FrameworkApplicationFixture::SetUp(); - m_application->SetAssetRoot(m_tempDirectory.GetDirectory()); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder, m_tempDirectory.GetDirectory()); + } + if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) + { + fileIoBase->SetAlias("@assets@", m_tempDirectory.GetDirectory()); + } } void TearDown() override @@ -31,13 +40,13 @@ protected: } AZStd::string m_root; - AZ::Test::ScopedAutoTempDirectory m_tempDirectory; + AZ::Test::ScopedAutoTempDirectory m_tempDirectory; }; TEST_F(ApplicationTest, MakePathAssetRootRelative_AbsPath_Valid) { AZStd::string inputPath; - AzFramework::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "TestA.txt", inputPath, true); + AZ::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "TestA.txt", inputPath, true); m_application->MakePathAssetRootRelative(inputPath); EXPECT_EQ(inputPath, "testa.txt"); } @@ -45,7 +54,7 @@ TEST_F(ApplicationTest, MakePathAssetRootRelative_AbsPath_Valid) TEST_F(ApplicationTest, MakePathRelative_AbsPath_Valid) { AZStd::string inputPath; - AzFramework::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "TestA.txt", inputPath, true); + AZ::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "TestA.txt", inputPath, true); m_application->MakePathRelative(inputPath, m_tempDirectory.GetDirectory()); EXPECT_EQ(inputPath, "TestA.txt"); } @@ -55,7 +64,7 @@ TEST_F(ApplicationTest, MakePathAssetRootRelative_AbsPath_RootLowerCase_Valid) AZStd::string inputPath; AZStd::string root = m_tempDirectory.GetDirectory(); AZStd::to_lower(root.begin(), root.end()); - AzFramework::StringFunc::Path::ConstructFull(root.c_str(), "TestA.txt", inputPath, true); + AZ::StringFunc::Path::ConstructFull(root.c_str(), "TestA.txt", inputPath, true); m_application->MakePathAssetRootRelative(inputPath); EXPECT_EQ(inputPath, "testa.txt"); } @@ -65,7 +74,7 @@ TEST_F(ApplicationTest, MakePathRelative_AbsPath_RootLowerCase_Valid) AZStd::string inputPath; AZStd::string root = m_tempDirectory.GetDirectory(); AZStd::to_lower(root.begin(), root.end()); - AzFramework::StringFunc::Path::ConstructFull(root.c_str(), "TestA.txt", inputPath, true); + AZ::StringFunc::Path::ConstructFull(root.c_str(), "TestA.txt", inputPath, true); m_application->MakePathRelative(inputPath, root.c_str()); EXPECT_EQ(inputPath, "TestA.txt"); } @@ -74,7 +83,7 @@ TEST_F(ApplicationTest, MakePathRelative_AbsPath_RootLowerCase_Valid) TEST_F(ApplicationTest, MakePathAssetRootRelative_AbsPathWithSubFolders_Valid) { AZStd::string inputPath; - AzFramework::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "Foo/TestA.txt", inputPath, true); + AZ::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "Foo/TestA.txt", inputPath, true); m_application->MakePathAssetRootRelative(inputPath); EXPECT_EQ(inputPath, "foo/testa.txt"); } @@ -82,7 +91,7 @@ TEST_F(ApplicationTest, MakePathAssetRootRelative_AbsPathWithSubFolders_Valid) TEST_F(ApplicationTest, MakePathRelative_AbsPathWithSubFolders_Valid) { AZStd::string inputPath; - AzFramework::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "Foo/TestA.txt", inputPath, true); + AZ::StringFunc::Path::ConstructFull(m_tempDirectory.GetDirectory(), "Foo/TestA.txt", inputPath, true); m_application->MakePathRelative(inputPath, m_tempDirectory.GetDirectory()); EXPECT_EQ(inputPath, "Foo/TestA.txt"); } @@ -141,4 +150,4 @@ TEST_F(ApplicationTest, MakePathRelative_RelPathWithSubFolderStartingWithSeparat AZStd::string inputPath("//Foo/TestA.txt"); m_application->MakePathRelative(inputPath, m_tempDirectory.GetDirectory()); EXPECT_EQ(inputPath, "Foo/TestA.txt"); -} \ No newline at end of file +} diff --git a/Code/Framework/Tests/ArchiveCompressionTests.cpp b/Code/Framework/Tests/ArchiveCompressionTests.cpp index 4cfd01ccb6..fb6beca0b5 100644 --- a/Code/Framework/Tests/ArchiveCompressionTests.cpp +++ b/Code/Framework/Tests/ArchiveCompressionTests.cpp @@ -76,7 +76,7 @@ namespace UnitTest TEST_P(ArchiveCompressionTestFixture, TestArchivePacking_CompressionEmptyArchiveTest_PackIsValid) { // this also coincidentally tests to make sure packs inside aliases work. - AZStd::string testArchivePath = "@cache@/archivetest.pak"; + AZStd::string testArchivePath = "@usercache@/archivetest.pak"; AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); ASSERT_NE(nullptr, fileIo); @@ -99,7 +99,7 @@ namespace UnitTest TEST_P(ArchiveCompressionTestFixture, TestArchivePacking_CompressionFullArchive_PackIsValid) { // ------------ BASIC TEST: Create archive full of standard sizes (including 0) ---------------- - AZStd::string testArchivePath = "@cache@/archivetest.pak"; + AZStd::string testArchivePath = "@usercache@/archivetest.pak"; AZ::IO::IArchive* archive = AZ::Interface::Get(); auto openFlags = AZStd::get<0>(GetParam()); @@ -165,7 +165,7 @@ namespace UnitTest TEST_P(ArchiveCompressionTestFixture, TestArchivePacking_CompressionWithOverridenArchiveData_PackIsValid) { // ---------------- MORE COMPLICATED TEST which involves overwriting elements ---------------- - AZStd::string testArchivePath = "@cache@/archivetest.pak"; + AZStd::string testArchivePath = "@usercache@/archivetest.pak"; AZ::IO::IArchive* archive = AZ::Interface::Get(); auto openFlags = AZStd::get<0>(GetParam()); @@ -275,7 +275,7 @@ namespace UnitTest // we want to make at least one element shrink and one element grow, adjacent to other files // this will include files that become zero size, and also includes new files that were not there before - AZStd::string testArchivePath = "@cache@/archivetest.pak"; + AZStd::string testArchivePath = "@usercache@/archivetest.pak"; AZ::IO::IArchive* archive = AZ::Interface::Get(); auto openFlags = AZStd::get<0>(GetParam()); diff --git a/Code/Framework/Tests/ArchiveTests.cpp b/Code/Framework/Tests/ArchiveTests.cpp index 806df41c50..aaca043c4b 100644 --- a/Code/Framework/Tests/ArchiveTests.cpp +++ b/Code/Framework/Tests/ArchiveTests.cpp @@ -240,14 +240,14 @@ namespace UnitTest ASSERT_NE(nullptr, console); { - AZStd::string testArchivePath_withSubfolders = "@cache@/immediate.pak"; - AZStd::string testArchivePath_withMountPoint = "@cache@/levels/test/flatarchive.pak"; + AZStd::string testArchivePath_withSubfolders = "@usercache@/immediate.pak"; + AZStd::string testArchivePath_withMountPoint = "@usercache@/levels/test/flatarchive.pak"; // delete test files in case they already exist archive->ClosePack(testArchivePath_withSubfolders.c_str()); fileIo->Remove(testArchivePath_withSubfolders.c_str()); fileIo->Remove(testArchivePath_withMountPoint.c_str()); - fileIo->CreatePath("@cache@/levels/test"); + fileIo->CreatePath("@usercache@/levels/test"); // setup test archive and file AZStd::intrusive_ptr pArchive = archive->OpenArchive(testArchivePath_withSubfolders.c_str(), nullptr, AZ::IO::INestedArchive::FLAGS_CREATE_NEW); @@ -314,14 +314,14 @@ namespace UnitTest // and be able to IMMEDIATELY // * read the file in the subfolder // * enumerate the folders (including that subfolder) even though they are 'virtual', not real folders on physical media - // * all of the above even though the mount point for the archive is @assets@ wheras the physical pack lives in @cache@ + // * all of the above even though the mount point for the archive is @assets@ wheras the physical pack lives in @usercache@ // finally, we're going to repeat the above test but with files mounted with subfolders // so for example, the pack will contain levelinfo.xml at the root of it // but it will be mounted at a subfolder (levels/mylevel). // this must cause FindNext and Open to work for levels/mylevel/levelinfo.xml. - constexpr const char* testArchivePath_withSubfolders = "@cache@/immediate.pak"; - constexpr const char* testArchivePath_withMountPoint = "@cache@/levels/test/flatarchive.pak"; + constexpr const char* testArchivePath_withSubfolders = "@usercache@/immediate.pak"; + constexpr const char* testArchivePath_withMountPoint = "@usercache@/levels/test/flatarchive.pak"; AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); ASSERT_NE(nullptr, fileIo); @@ -340,7 +340,7 @@ namespace UnitTest archive->ClosePack(testArchivePath_withMountPoint); fileIo->Remove(testArchivePath_withSubfolders); fileIo->Remove(testArchivePath_withMountPoint); - fileIo->CreatePath("@cache@/levels/test"); + fileIo->CreatePath("@usercache@/levels/test"); AZStd::intrusive_ptr pArchive = archive->OpenArchive(testArchivePath_withSubfolders, {}, AZ::IO::INestedArchive::FLAGS_CREATE_NEW); @@ -435,7 +435,7 @@ namespace UnitTest ASSERT_NE(nullptr, archive); constexpr AZStd::string_view dataString = "HELLO WORLD"; - constexpr const char* testArchivePath_withMountPoint = "@cache@/levels/test/flatarchive.pak"; + constexpr const char* testArchivePath_withMountPoint = "@usercache@/levels/test/flatarchive.pak"; bool found_mylevel_file{}; bool found_mylevel_folder{}; @@ -556,10 +556,10 @@ namespace UnitTest // mount the pack // make sure that the pack and loose file both appear when the PaKFileIO interface is used. using namespace AZ::IO; - AZ::IO::IArchive* archive = AZ::Interface::Get();; + AZ::IO::IArchive* archive = AZ::Interface::Get(); AZ::IO::ArchiveFileIO cpfio(archive); - constexpr const char* genericArchiveFileName = "@cache@/testarchiveio.pak"; + constexpr const char* genericArchiveFileName = "@usercache@/testarchiveio.pak"; ASSERT_NE(nullptr, archive); const char* dataString = "HELLO WORLD"; // other unit tests make sure writing and reading is working, so don't test that here size_t dataLen = strlen(dataString); @@ -599,7 +599,7 @@ namespace UnitTest EXPECT_TRUE(cpfio.Exists("testfile.xml")); EXPECT_TRUE(cpfio.Exists("@assets@/testfile.xml")); // this should be hte same file EXPECT_TRUE(!cpfio.Exists("@log@/testfile.xml")); - EXPECT_TRUE(!cpfio.Exists("@cache@/testfile.xml")); + EXPECT_TRUE(!cpfio.Exists("@usercache@/testfile.xml")); EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml")); // --- Coverage test ---- @@ -715,7 +715,7 @@ namespace UnitTest ASSERT_NE(nullptr, fileIo); // test whether aliasing works as expected. We'll create a archive in the cache, but we'll map it to a bunch of folders - constexpr const char* testArchivePath = "@cache@/archivetest.pak"; + constexpr const char* testArchivePath = "@usercache@/archivetest.pak"; char realNameBuf[AZ_MAX_PATH_LEN] = { 0 }; EXPECT_TRUE(fileIo->ResolvePath(testArchivePath, realNameBuf, AZ_MAX_PATH_LEN)); @@ -737,16 +737,16 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath)); - EXPECT_TRUE(archive->OpenPack("@cache@", realNameBuf)); - EXPECT_TRUE(archive->IsFileExist("@cache@/foundit.dat")); - EXPECT_FALSE(archive->IsFileExist("@cache@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@cache@/notfoundit.dat")); + EXPECT_TRUE(archive->OpenPack("@usercache@", realNameBuf)); + EXPECT_TRUE(archive->IsFileExist("@usercache@/foundit.dat")); + EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@usercache@/notfoundit.dat")); EXPECT_TRUE(archive->ClosePack(realNameBuf)); // change its actual location: EXPECT_TRUE(archive->OpenPack("@assets@", realNameBuf)); EXPECT_TRUE(archive->IsFileExist("@assets@/foundit.dat")); - EXPECT_FALSE(archive->IsFileExist("@cache@/foundit.dat")); // do not find it in the previous location! + EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous location! EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); EXPECT_FALSE(archive->IsFileExist("@assets@/notfoundit.dat")); EXPECT_TRUE(archive->ClosePack(realNameBuf)); @@ -755,7 +755,7 @@ namespace UnitTest EXPECT_TRUE(archive->OpenPack("@assets@/mystuff", realNameBuf)); EXPECT_TRUE(archive->IsFileExist("@assets@/mystuff/foundit.dat")); EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat")); // do not find it in the previous locations! - EXPECT_FALSE(archive->IsFileExist("@cache@/foundit.dat")); // do not find it in the previous locations! + EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous locations! EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); EXPECT_FALSE(archive->IsFileExist("@assets@/mystuff/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); EXPECT_FALSE(archive->IsFileExist("@assets@/notfoundit.dat")); // non-existent file diff --git a/Code/Framework/Tests/AssetCatalog.cpp b/Code/Framework/Tests/AssetCatalog.cpp index 6fc65740dd..8a89ba349c 100644 --- a/Code/Framework/Tests/AssetCatalog.cpp +++ b/Code/Framework/Tests/AssetCatalog.cpp @@ -842,7 +842,6 @@ namespace UnitTest m_application = new AzFramework::Application(); m_assetRoot = UnitTest::GetTestFolderPath(); m_application->NormalizePathKeepCase(m_assetRoot); - m_application->SetAssetRoot(m_assetRoot.c_str()); m_assetCatalog = aznew AzFramework::AssetCatalog(); m_firstAssetId = AssetId(AZ::Uuid::CreateRandom(), 0); diff --git a/Code/Framework/Tests/ComponentAddRemove.cpp b/Code/Framework/Tests/ComponentAddRemove.cpp index db343c6c7f..d29bb54cc2 100644 --- a/Code/Framework/Tests/ComponentAddRemove.cpp +++ b/Code/Framework/Tests/ComponentAddRemove.cpp @@ -1105,8 +1105,9 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Code/Framework/Tests/EntityTestbed.h b/Code/Framework/Tests/EntityTestbed.h index 87d803d6d0..1bfbcdf290 100644 --- a/Code/Framework/Tests/EntityTestbed.h +++ b/Code/Framework/Tests/EntityTestbed.h @@ -184,7 +184,6 @@ namespace UnitTest AzToolsFramework::Components::PropertyManagerComponent::CreateDescriptor(); const char* dir = m_componentApplication->GetExecutableFolder(); - m_componentApplication->SetAssetRoot(dir); m_localFileIO.SetAlias("@assets@", dir); m_localFileIO.SetAlias("@devassets@", dir); diff --git a/Code/Framework/Tests/NetBindingMocks.h b/Code/Framework/Tests/NetBindingMocks.h index 6091381edb..441d41fa66 100644 --- a/Code/Framework/Tests/NetBindingMocks.h +++ b/Code/Framework/Tests/NetBindingMocks.h @@ -283,6 +283,7 @@ namespace UnitTest MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_CONST_METHOD0(GetAppRoot, const char* ()); + MOCK_CONST_METHOD0(GetEngineRoot, const char* ()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ()); MOCK_METHOD0(GetTickDeltaTime, float ()); diff --git a/Code/Framework/Tests/ProcessLaunchMain.cpp b/Code/Framework/Tests/ProcessLaunchMain.cpp index 7162514c82..49a0911937 100644 --- a/Code/Framework/Tests/ProcessLaunchMain.cpp +++ b/Code/Framework/Tests/ProcessLaunchMain.cpp @@ -17,17 +17,16 @@ void OutputArgs(const AzFramework::CommandLine& commandLine) { - const AzFramework::CommandLine::ParamMap& switchList = commandLine.GetSwitchList(); std::cout << "Switch List:" << std::endl; - for (auto& switchPair : switchList) + for (auto& switchPair : commandLine) { // We strip white space from all of our switch names, so "flush" names will start arguments - std::cout << switchPair.first.c_str() << std::endl; - for (auto& switchValue : switchPair.second) + if (!switchPair.m_option.empty()) { - // Auto space every switch value by one space - std::cout << " " << switchValue.c_str() << std::endl; + std::cout << switchPair.m_option.c_str() << std::endl; } + std::cout << " " << switchPair.m_value.c_str() << std::endl; + } std::cout << "End Switch List:" << std::endl; } diff --git a/Code/Framework/Tests/ProcessLaunchParseTests.cpp b/Code/Framework/Tests/ProcessLaunchParseTests.cpp index b46741b5c7..17068c828f 100644 --- a/Code/Framework/Tests/ProcessLaunchParseTests.cpp +++ b/Code/Framework/Tests/ProcessLaunchParseTests.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -76,13 +76,13 @@ namespace UnitTest TEST_F(ProcessLaunchParseTests, ProcessLauncher_LaunchBasicProcess_Success) { - AzToolsFramework::ProcessOutput processOutput; - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessOutput processOutput; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZ_TRAIT_TEST_ROOT_FOLDER "ProcessLaunchTest"; processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath(); processLaunchInfo.m_showWindow = false; - bool launchReturn = AzToolsFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); + bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); EXPECT_EQ(launchReturn, true); EXPECT_EQ(processOutput.outputResult.empty(), false); @@ -91,13 +91,13 @@ namespace UnitTest TEST_F(ProcessLaunchParseTests, ProcessLauncher_BasicParameter_Success) { ProcessLaunchParseTests::ParsedArgMap argMap; - AzToolsFramework::ProcessOutput processOutput; - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessOutput processOutput; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZ_TRAIT_TEST_ROOT_FOLDER "ProcessLaunchTest -param1 param1val -param2=param2val"; processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath(); processLaunchInfo.m_showWindow = false; - bool launchReturn = AzToolsFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); + bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); EXPECT_EQ(launchReturn, true); @@ -125,13 +125,13 @@ namespace UnitTest #endif // AZ_TRAIT_DISABLE_FAILED_PROCESS_LAUNCHER_TESTS { ProcessLaunchParseTests::ParsedArgMap argMap; - AzToolsFramework::ProcessOutput processOutput; - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessOutput processOutput; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZ_TRAIT_TEST_ROOT_FOLDER R"(ProcessLaunchTest -param1 "\"param,1val\"" -param2="\"param2v,al\"")"; processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath(); processLaunchInfo.m_showWindow = false; - bool launchReturn = AzToolsFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); + bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); EXPECT_EQ(launchReturn, true); @@ -159,13 +159,13 @@ namespace UnitTest #endif // AZ_TRAIT_DISABLE_FAILED_PROCESS_LAUNCHER_TESTS { ProcessLaunchParseTests::ParsedArgMap argMap; - AzToolsFramework::ProcessOutput processOutput; - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessOutput processOutput; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZ_TRAIT_TEST_ROOT_FOLDER R"(ProcessLaunchTest -param1 "\"param 1val\"" -param2="\"param2v al\"")"; processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath(); processLaunchInfo.m_showWindow = false; - bool launchReturn = AzToolsFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); + bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); EXPECT_EQ(launchReturn, true); @@ -193,13 +193,13 @@ namespace UnitTest #endif // AZ_TRAIT_DISABLE_FAILED_PROCESS_LAUNCHER_TESTS { ProcessLaunchParseTests::ParsedArgMap argMap; - AzToolsFramework::ProcessOutput processOutput; - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessOutput processOutput; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZ_TRAIT_TEST_ROOT_FOLDER R"(ProcessLaunchTest -param1 "\"par,am 1val\"" -param2="\"param,2v al\"")"; processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath(); processLaunchInfo.m_showWindow = false; - bool launchReturn = AzToolsFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); + bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); EXPECT_EQ(launchReturn, true); @@ -223,13 +223,13 @@ namespace UnitTest TEST_F(ProcessLaunchParseTests, ProcessLauncher_CommaStringNoQuotes_Success) { ProcessLaunchParseTests::ParsedArgMap argMap; - AzToolsFramework::ProcessOutput processOutput; - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessOutput processOutput; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZ_TRAIT_TEST_ROOT_FOLDER "ProcessLaunchTest -param1 param,1val -param2=param2v,al"; processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath(); processLaunchInfo.m_showWindow = false; - bool launchReturn = AzToolsFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); + bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput); EXPECT_EQ(launchReturn, true); diff --git a/Code/Framework/Tests/ProjectManagerTests.cpp b/Code/Framework/Tests/ProjectManagerTests.cpp deleted file mode 100644 index d6788aef71..0000000000 --- a/Code/Framework/Tests/ProjectManagerTests.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* -* 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. -* -*/ - -#include -#include - -#include -#include - -namespace ProjectManagerTests -{ - - - //////////////////////////////////////////////////////////////////////////////////////////////// - class ProjectManagerTest : public ::testing::Test - { - protected: - //////////////////////////////////////////////////////////////////////////////////////////// - void SetUp() override - { - - } - - //////////////////////////////////////////////////////////////////////////////////////////// - void TearDown() override - { - - } - }; - - //////////////////////////////////////////////////////////////////////////////////////////////// - class ProjectManagerBootstrapTest : public ::testing::Test - { - protected: - //////////////////////////////////////////////////////////////////////////////////////////// - void SetUp() override - { - AZ::IO::SystemFile engineFile; - AZ::IO::FixedMaxPath engineFilePath(m_tempDir.GetDirectory()); - - m_projectPath = engineFilePath / "TestProject"; - AZ::IO::SystemFile::CreateDir(m_projectPath.c_str()); - - engineFilePath = engineFilePath / "engine.json"; - engineFile.Open(engineFilePath.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE); - engineFile.Close(); - } - - //////////////////////////////////////////////////////////////////////////////////////////// - void TearDown() override - { - - } - AZ::IO::FixedMaxPath m_projectPath; - UnitTest::ScopedTemporaryDirectory m_tempDir; - }; - - //////////////////////////////////////////////////////////////////////////////////////////////// - TEST_F(ProjectManagerTest, HasProjectNameTest_ProjectNameGivenWithDash_Success) - { - constexpr int numArguments = 2; - static const char* argumentList1[numArguments] = { "C:/somepath/to/exe", "-projectpath" }; - EXPECT_TRUE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList1))); - - static const char* argumentList2[numArguments] = { "C:/somepath/to/exe", "--projectpath" }; - EXPECT_TRUE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList2))); - - static const char* argumentList3[numArguments] = { "C:/somepath/to/exe", "/projectpath" }; - EXPECT_TRUE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList3))); - } - - - TEST_F(ProjectManagerTest, HasProjectNameTest_ProjectNameGivenWithRegSet_Success) - { - constexpr int numArguments = 2; - static const char* argumentList1[numArguments] = { "C:/somepath/to/exe", "-regset=\"/Amazon/AzCore/Bootstrap/sys_game_folder=SomeFolder\"" }; - EXPECT_TRUE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList1))); - - static const char* argumentList2[numArguments] = { "C:/somepath/to/exe", "--regset=\"/Amazon/AzCore/Bootstrap/sys_game_folder=SomeFolder\"" }; - EXPECT_TRUE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList2))); - - static const char* argumentList3[numArguments] = { "C:/somepath/to/exe", "/regset=\"/Amazon/AzCore/Bootstrap/sys_game_folder=SomeFolder\"" }; - EXPECT_TRUE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList3))); - } - - TEST_F(ProjectManagerTest, HasProjectNameTest_ProjectNameGivenWithImroperPrefixes_Fails) - { - constexpr int numArguments = 2; - static const char* argumentList1[numArguments] = { "C:/somepath/to/exe", "projectpath" }; - EXPECT_FALSE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList1))); - - static const char* argumentList2[numArguments] = { "C:/somepath/to/exe", "---projectpath" }; - EXPECT_FALSE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList2))); - - static const char* argumentList3[numArguments] = { "C:/somepath/to/exe", "//projectpath" }; - EXPECT_FALSE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList3))); - - static const char* argumentList4[numArguments] = { "C:/somepath/to/exe", "pprojectpath" }; - EXPECT_FALSE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList4))); - } - //////////////////////////////////////////////////////////////////////////////////////////////// - TEST_F(ProjectManagerTest, HasProjectNameTest_ProjectNameNotGiven_Fails) - { - constexpr int numArguments = 2; - static const char* argumentList[numArguments] = { "C:/somepath/to/exe", "someotherparam" }; - - EXPECT_FALSE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList))); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - TEST_F(ProjectManagerTest, HasProjectNameTest_NoAdditionalParams_Fails) - { - constexpr int numArguments = 1; - static const char* argumentList[numArguments] = { "C:/somepath/to/exe" }; - - EXPECT_FALSE(AzFramework::ProjectManager::HasCommandLineProjectName(numArguments, const_cast(argumentList))); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - TEST_F(ProjectManagerTest, ContentTest_HasValidProjectName_Passes) - { - AZStd::fixed_string testContent = -R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - -sys_game_folder=SamplesProject - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - EXPECT_TRUE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_HasValidProjectNameSpaced_Passes) - { - AZStd::fixed_string testContent = -R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - -sys_game_folder = SamplesProject - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - EXPECT_TRUE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_HasNoProjectName_Fails) - { - AZStd::fixed_string testContent = -R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - -sys_game_folder= - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - EXPECT_FALSE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_HasCommentedProjectName_Fails) - { - AZStd::fixed_string testContent = -R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - --sys_game_folder=SamplesProject - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - EXPECT_FALSE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_HasCommentedThenValidProjectName_Passes) - { - AZStd::fixed_string testContent = -R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - --sys_game_folder=SamplesProject -sys_game_folder=SamplesProject - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - EXPECT_TRUE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_OnlyHasValidKey_Passes) - { - AZStd::fixed_string testContent = - R"(sys_game_folder=SamplesProject)"; - - EXPECT_TRUE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_OnlyHasValidKeyNewline_Passes) - { - AZStd::fixed_string testContent = - R"(sys_game_folder=SamplesProject -)"; - - EXPECT_TRUE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } - - TEST_F(ProjectManagerTest, ContentTest_EmptyContent_Failse) - { - AZStd::fixed_string testContent; - - EXPECT_FALSE(AzFramework::ProjectManager::ContentHasProjectName(testContent)); - } -#if AZ_TRAIT_DISABLE_FAILED_FRAMEWORK_TESTS - TEST_F(ProjectManagerBootstrapTest, DISABLED_BootstrapContentTest_HasValidProjectName_Passes) -#else - TEST_F(ProjectManagerBootstrapTest, BootstrapContentTest_HasValidProjectName_Passes) -#endif // AZ_TRAIT_DISABLE_FAILED_FRAMEWORK_TESTS - { - AZStd::fixed_string testContent = - R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - -sys_game_folder=SamplesProject - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - AZ::IO::SystemFile bootstrapFile; - AZ::IO::FixedMaxPath bootstrapPath(m_tempDir.GetDirectory()); - bootstrapPath /= "bootstrap.cfg"; - bootstrapFile.Open(bootstrapPath.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE); - - bootstrapFile.Write(testContent.data(), testContent.length()); - bootstrapFile.Close(); - EXPECT_TRUE(AzFramework::ProjectManager::HasBootstrapProjectName(m_projectPath.c_str())); - } - -#if AZ_TRAIT_DISABLE_FAILED_FRAMEWORK_TESTS - TEST_F(ProjectManagerBootstrapTest, DISABLED_BootstrapContentTest_HasNoValidProjectName_Fails) -#else - TEST_F(ProjectManagerBootstrapTest, BootstrapContentTest_HasNoValidProjectName_Fails) -#endif // AZ_TRAIT_DISABLE_FAILED_FRAMEWORK_TESTS - { - AZStd::fixed_string testContent = - R"(-- When you see an option that does not have a platform preceeding it, that is the default ---value for anything not specificly set per platform.So if remote_filesystem = 0 and you have --- ios_remote_file_system = 1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name : ---android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified.The rules apply in the order they're declared - -sys_game_folder= - --- remote_filesystem - enable Virtual File System(VFS) ---This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is offand can be overridden for any platform)"; - - AZ::IO::SystemFile bootstrapFile; - AZ::IO::FixedMaxPath bootstrapPath(m_tempDir.GetDirectory()); - bootstrapPath /= "bootstrap.cfg"; - bootstrapFile.Open(bootstrapPath.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE); - - bootstrapFile.Write(testContent.data(), testContent.length()); - bootstrapFile.Close(); - EXPECT_FALSE(AzFramework::ProjectManager::HasBootstrapProjectName(m_projectPath.c_str())); - } -} // ProjectManagerTests diff --git a/Code/Framework/Tests/frameworktests_files.cmake b/Code/Framework/Tests/frameworktests_files.cmake index 1eec30bc14..caebf6d921 100644 --- a/Code/Framework/Tests/frameworktests_files.cmake +++ b/Code/Framework/Tests/frameworktests_files.cmake @@ -43,7 +43,6 @@ set(FILES InterestManagerComponentTests.cpp SQLiteConnectionTests.cpp ProcessLaunchParseTests.cpp - ProjectManagerTests.cpp Application.cpp PlatformHelper.cpp Scene.cpp diff --git a/Code/LauncherUnified/CMakeLists.txt b/Code/LauncherUnified/CMakeLists.txt index 8c5eb3509f..0d056686b8 100644 --- a/Code/LauncherUnified/CMakeLists.txt +++ b/Code/LauncherUnified/CMakeLists.txt @@ -67,8 +67,12 @@ if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) endif() -foreach(project ${LY_PROJECTS_NAME}) - +get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME) +foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS) + # Computes the realpath to the project + # If the project_path is relative, it is evaluated relative to the ${LY_ROOT_FOLDER} + # Otherwise the the absolute project_path is returned with symlinks resolved + file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER}) ################################################################################ # Monolithic game ################################################################################ @@ -77,7 +81,7 @@ foreach(project ${LY_PROJECTS_NAME}) # In the monolithic case, we need to register the gem modules, to do so we will generate a StaticModules.inl # file from StaticModules.in - get_property(game_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project}.GameLauncher) + get_property(game_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.GameLauncher) unset(extern_module_declarations) unset(module_invocations) @@ -96,7 +100,7 @@ foreach(project ${LY_PROJECTS_NAME}) endforeach() configure_file(StaticModules.in - ${CMAKE_CURRENT_BINARY_DIR}/${project}.GameLauncher/Includes/StaticModules.inl + ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.GameLauncher/Includes/StaticModules.inl ) set(game_build_dependencies @@ -107,7 +111,7 @@ foreach(project ${LY_PROJECTS_NAME}) ) if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) - get_property(server_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project}.ServerLauncher) + get_property(server_gem_dependencies GLOBAL PROPERTY LY_DELAYED_DEPENDENCIES_${project_name}.ServerLauncher) unset(extern_module_declarations) unset(module_invocations) @@ -126,7 +130,7 @@ foreach(project ${LY_PROJECTS_NAME}) endforeach() configure_file(StaticModules.in - ${CMAKE_CURRENT_BINARY_DIR}/${project}.ServerLauncher/Includes/StaticModules.inl + ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.ServerLauncher/Includes/StaticModules.inl ) set(server_build_dependencies @@ -156,7 +160,7 @@ foreach(project ${LY_PROJECTS_NAME}) # Game ################################################################################ ly_add_target( - NAME ${project}.GameLauncher ${PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE} + NAME ${project_name}.GameLauncher ${PAL_TRAIT_LAUNCHERUNIFIED_LAUNCHER_TYPE} NAMESPACE AZ FILES_CMAKE launcher_project_files.cmake @@ -165,15 +169,18 @@ foreach(project ${LY_PROJECTS_NAME}) COMPILE_DEFINITIONS PRIVATE # Adds the name of the project/game - LY_GAME_PROJECT_NAME="${project}" - # Adds the ${project}_GameLauncher target as a define so for the Settings Registry to use + LY_PROJECT_NAME="${project_name}" + # Adds the project path supplied to CMake during configuration + # This is used as a fallback to launch the AssetProcessor + LY_PROJECT_CMAKE_PATH="${project_path}" + # Adds the ${project_name}_GameLauncher target as a define so for the Settings Registry to use # when loading .setreg file specializations # This is needed so that only gems for the project game launcher are loaded - LY_CMAKE_TARGET="${project}_GameLauncher" + LY_CMAKE_TARGET="${project_name}_GameLauncher" INCLUDE_DIRECTORIES PRIVATE . - ${CMAKE_CURRENT_BINARY_DIR}/${project}.GameLauncher/Includes # required for StaticModules.inl + ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.GameLauncher/Includes # required for StaticModules.inl BUILD_DEPENDENCIES PRIVATE AZ::Launcher.Static @@ -183,9 +190,9 @@ foreach(project ${LY_PROJECTS_NAME}) ${game_runtime_dependencies} ) # Needs to be set manually after ly_add_target to prevent the default location overriding it - set_target_properties(${project}.GameLauncher + set_target_properties(${project_name}.GameLauncher PROPERTIES - FOLDER ${project} + FOLDER ${project_name} ) ################################################################################ @@ -194,10 +201,10 @@ foreach(project ${LY_PROJECTS_NAME}) if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) get_property(server_projects GLOBAL PROPERTY LY_LAUNCHER_SERVER_PROJECTS) - if(${project} IN_LIST server_projects) + if(${project_name} IN_LIST server_projects) ly_add_target( - NAME ${project}.ServerLauncher APPLICATION + NAME ${project_name}.ServerLauncher APPLICATION NAMESPACE AZ FILES_CMAKE launcher_project_files.cmake @@ -206,15 +213,18 @@ foreach(project ${LY_PROJECTS_NAME}) COMPILE_DEFINITIONS PRIVATE # Adds the name of the project/game - LY_GAME_PROJECT_NAME="${project}" - # Adds the ${project}_ServerLauncher target as a define so for the Settings Registry to use + LY_PROJECT_NAME="${project_name}" + # Adds the project path supplied to CMake during configuration + # This is used as a fallback to launch the AssetProcessor + LY_PROJECT_CMAKE_PATH="${project_path}" + # Adds the ${project_name}_ServerLauncher target as a define so for the Settings Registry to use # when loading .setreg file specializations # This is needed so that only gems for the project server launcher are loaded - LY_CMAKE_TARGET="${project}_ServerLauncher" + LY_CMAKE_TARGET="${project_name}_ServerLauncher" INCLUDE_DIRECTORIES PRIVATE . - ${CMAKE_CURRENT_BINARY_DIR}/${project}.ServerLauncher/Includes # required for StaticModules.inl + ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.ServerLauncher/Includes # required for StaticModules.inl BUILD_DEPENDENCIES PRIVATE AZ::Launcher.Static @@ -224,9 +234,9 @@ foreach(project ${LY_PROJECTS_NAME}) ${server_runtime_dependencies} ) # Needs to be set manually after ly_add_target to prevent the default location overriding it - set_target_properties(${project}.ServerLauncher + set_target_properties(${project_name}.ServerLauncher PROPERTIES - FOLDER ${project} + FOLDER ${project_name} ) endif() diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 29c2199dac..0401802b26 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -26,9 +26,9 @@ #include #include +#include #include #include -#include #include @@ -68,7 +68,7 @@ namespace // argument is strictly to match the API of AZ::DynamicModuleHandle bool Load(bool unused) - { + { AZ_UNUSED(unused); if (IsLoaded()) @@ -90,14 +90,14 @@ namespace return CryFreeLibrary(m_moduleHandle); } - bool IsLoaded() const - { - return m_moduleHandle != nullptr; + bool IsLoaded() const + { + return m_moduleHandle != nullptr; } - const AZ::OSString& GetFilename() const - { - return m_fileName; + const AZ::OSString& GetFilename() const + { + return m_fileName; } template @@ -119,7 +119,7 @@ namespace : m_fileName() , m_moduleHandle(nullptr) { - m_fileName = AZ::OSString::format("%s%s%s", + m_fileName = AZ::OSString::format("%s%s%s", CrySharedLibraryPrefix, fileFullName, CrySharedLibraryExtension); } @@ -296,9 +296,6 @@ namespace LumberyardLauncher case ReturnCode::Success: return "Success"; - case ReturnCode::ErrBootstrapMismatch: - return "Mismatch detected between Launcher compiler defines and bootstrap values (LY_GAMEFOLDER/sys_game_folder)."; - case ReturnCode::ErrCommandLine: return "Failed to copy command line arguments"; @@ -326,99 +323,6 @@ namespace LumberyardLauncher } } - void CopySettingsRegistryToCrySystemInitParams(const AZ::SettingsRegistryInterface& registry, SSystemInitParams& params) - { - constexpr AZStd::string_view DefaultRemoteIp = "127.0.0.1"; - constexpr uint16_t DefaultRemotePort = 45643U; - - AZ::SettingsRegistryInterface::FixedValueString settingsKeyPrefix = AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey; - AZ::SettingsRegistryInterface::FixedValueString settingsValueString; - AZ::s64 settingsValueInt{}; - - // remote filesystem - if (registry.Get(settingsValueInt, settingsKeyPrefix + "/remote_filesystem")) - { - params.remoteFileIO = settingsValueInt != 0; - } - // remote port - if(registry.Get(settingsValueInt, settingsKeyPrefix + "/remote_port")) - { - params.remotePort = aznumeric_cast(settingsValueInt); - } - else - { - params.remotePort = DefaultRemotePort; - } - - // remote ip - if (registry.Get(settingsValueString, settingsKeyPrefix + "/remote_ip")) - { - azstrncpy(AZStd::data(params.remoteIP), AZStd::size(params.remoteIP), settingsValueString.c_str(), settingsValueString.size()); - } - else - { - azstrncpy(AZStd::data(params.remoteIP), AZStd::size(params.remoteIP), DefaultRemoteIp.data(), DefaultRemoteIp.size()); - } - - // connect_to_remote - also supports _connect_to_remote override - if (registry.Get(settingsValueInt, settingsKeyPrefix + "/" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_connect_to_remote") - || registry.Get(settingsValueInt, settingsKeyPrefix + "/connect_to_remote")) - { - params.connectToRemote = settingsValueInt != 0; - } -#if !defined(DEDICATED_SERVER) - // wait_for_connect - also supports _wait_for_connect override - // Dedicated server does not depend on Asset Processor and assumes that assets are already prepared. - if (registry.Get(settingsValueInt, settingsKeyPrefix + "/" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_wait_for_connect") - || registry.Get(settingsValueInt, settingsKeyPrefix + "/wait_for_connect")) - { - params.waitForConnection = settingsValueInt != 0; - } -#endif // defined(DEDICATED_SERVER) - - // assets - also supports _assets override - settingsValueString.clear(); - if (registry.Get(settingsValueString, settingsKeyPrefix + "/" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_assets") - || registry.Get(settingsValueString, settingsKeyPrefix + "/assets")) - { - azstrncpy(AZStd::data(params.assetsPlatform), AZStd::size(params.assetsPlatform), settingsValueString.c_str(), settingsValueString.size()); - } - - // Project name - First tries sys_game_folder - settingsValueString.clear(); - if (registry.Get(settingsValueString, settingsKeyPrefix + "/sys_game_folder")) - { - // sys_game_folder is the current way to do it - azstrncpy(AZStd::data(params.gameFolderName), AZStd::size(params.gameFolderName), settingsValueString.c_str(), settingsValueString.size()); - } - - // assetProcessor_branch_token - if (registry.Get(settingsValueInt, settingsKeyPrefix + "/assetProcessor_branch_token")) - { - azsnprintf(AZStd::data(params.branchToken), AZStd::size(params.branchToken), "0x%llx", settingsValueInt); - } - - // Engine root path(also AppRoot path as well) - settingsValueString.clear(); - if (registry.Get(settingsValueString, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) - { - azstrncpy(AZStd::data(params.rootPath), AZStd::size(params.rootPath), settingsValueString.c_str(), settingsValueString.size()); - } - // Asset Cache Root path - settingsValueString.clear(); - if (registry.Get(settingsValueString, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) - { - azstrncpy(AZStd::data(params.rootPathCache), AZStd::size(params.rootPathCache), settingsValueString.c_str(), settingsValueString.size()); - } - // Asset Cache Game path (Includes as part of path, the current project name) - settingsValueString.clear(); - if (registry.Get(settingsValueString, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheGameFolder)) - { - azstrncpy(AZStd::data(params.assetsPathCache), AZStd::size(params.assetsPathCache), settingsValueString.c_str(), settingsValueString.size()); - azstrncpy(AZStd::data(params.assetsPath), AZStd::size(params.assetsPath), settingsValueString.c_str(), settingsValueString.size()); - } - } - void CompileCriticalAssets(); void CreateRemoteFileIO(); @@ -493,24 +397,37 @@ namespace LumberyardLauncher } //! Add the GameProjectName and Launcher build target name into the settings registry - void AddGameProjectNameToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, AZ::CommandLine& commandLine) + void AddProjectMetadataToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, AZ::CommandLine& commandLine) { - auto gameProjectNameKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - AZ::SettingsRegistryInterface::FixedValueString bootstrapGameProjectName; - settingsRegistry.Get(bootstrapGameProjectName, gameProjectNameKey); - - const AZStd::string_view gameProjectName = GetGameProjectName(); - AZ::SettingsRegistryInterface::FixedValueString gameProjectCommandLineOverride = R"(--regset=)"; - gameProjectCommandLineOverride += gameProjectNameKey; - gameProjectCommandLineOverride += '='; - gameProjectCommandLineOverride += gameProjectName; - - // Inject the Project Name into the CommandLine parameters, so that the Setting Registry - // always is set to the launcher's project name whenever the command line is merged into the Settings Registry - // This happens several times through application such as in GameApplication::Start + // Inject the Project Path and Project into the CommandLine parameters to beginning of the command line + // in order to allow it to used as a fallback if the parameters aren't supplied launch parameters already + // Command Line parameters are the bootstrap settings into the Settings Registry, so they precedence + auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + + "/project_path"; + auto projectNameKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) + + "/project_name"; + AZ::CommandLine::ParamContainer commandLineArgs; commandLine.Dump(commandLineArgs); - commandLineArgs.emplace_back(gameProjectCommandLineOverride); + + // Insert the project_name option to the front + const AZStd::string_view launcherProjectName = GetProjectName(); + if (!launcherProjectName.empty()) + { + auto projectNameOptionOverride = AZ::SettingsRegistryInterface::FixedValueString::format(R"(--regset="%s=%.*s")", + projectNameKey.c_str(), aznumeric_cast(launcherProjectName.size()), launcherProjectName.data()); + commandLineArgs.emplace(commandLineArgs.begin(), projectNameOptionOverride); + } + + // Insert the project_path option to the front + const AZStd::string_view projectPath = GetProjectPath(); + if (!projectPath.empty()) + { + auto projectPathOptionOverride = AZ::SettingsRegistryInterface::FixedValueString::format(R"(--regset="%s=%.*s")", + projectPathKey.c_str(), aznumeric_cast(projectPath.size()), projectPath.data()); + commandLineArgs.emplace(commandLineArgs.begin(), projectPathOptionOverride); + } + commandLine.Parse(commandLineArgs); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(settingsRegistry, commandLine, false); @@ -519,27 +436,16 @@ namespace LumberyardLauncher const AZStd::string_view buildTargetName = LumberyardLauncher::GetBuildTargetName(); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(settingsRegistry, buildTargetName); - // Output a trace message if the sys_game_folder value read from the boostrap.cfg file doesn't match the value of the - // LY_GAMEFOLDER define built into the Launcher. - // This isn't any kind of error or ever warning, but is used as an informational message to the user - // that the launcher will use the always used the injected LY_GAMEFOLDER define - if (bootstrapGameProjectName != gameProjectName) - { - AZ_TracePrintf("Launcher", R"(The game project "%s" read into the Settings Registry from the bootstrap.cfg file)" - R"( does not match the LY_GAMEFOLDER define "%.*s")" "\n", - bootstrapGameProjectName.c_str(), aznumeric_cast(gameProjectName.size()), gameProjectName.data()); - } - - AZ_TracePrintf("Launcher", R"(The game project name of "%.*s" is the value of the LY_GAMEFOLDER define.)" "\n" - R"(That value has been successfully set into the Settings Registry at key "%s/sys_game_folder" for Launcher target "%.*s")" "\n", - aznumeric_cast(gameProjectName.size()), gameProjectName.data(), - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, + AZ_TracePrintf("Launcher", R"(Running project "%.*s.)" "\n" + R"(The project name value has been successfully set in the Settings Registry at key "%s/project_name" for Launcher target "%.*s")" "\n", + aznumeric_cast(launcherProjectName.size()), launcherProjectName.data(), + AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey, aznumeric_cast(buildTargetName.size()), buildTargetName.data()); } ReturnCode Run(const PlatformMainInfo& mainInfo) { - if (mainInfo.m_updateResourceLimits + if (mainInfo.m_updateResourceLimits && !mainInfo.m_updateResourceLimits()) { return ReturnCode::ErrResourceLimit; @@ -562,9 +468,8 @@ namespace LumberyardLauncher // Inject the ${LY_GAMEFOLDER} project name define that from the Launcher build target // into the settings registry - AddGameProjectNameToSettingsRegistry(*settingsRegistry, *gameApplication.GetAzCommandLine()); + AddProjectMetadataToSettingsRegistry(*settingsRegistry, *gameApplication.GetAzCommandLine()); - bool applyAppRootOverride = (AZ_TRAIT_LAUNCHER_SET_APPROOT_OVERRIDE == 1); AZ::SettingsRegistryInterface::FixedValueString pathToAssets; if (!settingsRegistry->Get(pathToAssets, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { @@ -581,51 +486,6 @@ namespace LumberyardLauncher } CryAllocatorsRAII cryAllocatorsRAII; - #if AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE - char appRootOverride[AZ_MAX_PATH_LEN] = { 0 }; - { - // Search for the app root argument (--app-root ) where is the app root path to set for the application - const static char* appRootArgPrefix = "--app-root"; - size_t appRootArgPrefixLen = strlen(appRootArgPrefix); - - const char* appRootArg = nullptr; - - char cmdLineCopy[AZ_COMMAND_LINE_LEN] = { 0 }; - azstrncpy(cmdLineCopy, AZ_COMMAND_LINE_LEN, mainInfo.m_commandLine, mainInfo.m_commandLineLen); - - const char* delimiters = " "; - char* nextToken = nullptr; - char* token = azstrtok(cmdLineCopy, 0, delimiters, &nextToken); - while (token != NULL) - { - if (azstrnicmp(appRootArgPrefix, token, appRootArgPrefixLen) == 0) - { - appRootArg = azstrtok(nullptr, 0, delimiters, &nextToken); - break; - } - token = azstrtok(nullptr, 0, delimiters, &nextToken); - } - - if (appRootArg) - { - AZStd::string_view appRootArgView = appRootArg; - size_t afterStartQuotes = appRootArgView.find_first_not_of(R"(")"); - if (afterStartQuotes != AZStd::string_view::npos) - { - appRootArgView.remove_prefix(afterStartQuotes); - } - size_t beforeEndQuotes = appRootArgView.find_last_not_of(R"(")"); - if (beforeEndQuotes != AZStd::string_view::npos) - { - appRootArgView.remove_suffix(appRootArgView.size() - (beforeEndQuotes + 1)); - } - appRootArgView.copy(appRootOverride, AZ_MAX_PATH_LEN); - appRootOverride[appRootArgView.size()] = '\0'; - pathToAssets = appRootOverride; - applyAppRootOverride = true; - } - } - #endif // AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE // System Init Params ("Legacy" Lumberyard) SSystemInitParams systemInitParams; @@ -634,12 +494,6 @@ namespace LumberyardLauncher { AzGameFramework::GameApplication::StartupParameters gameApplicationStartupParams; - if (applyAppRootOverride) - { - // NOTE: setting this on android doesn't work when assets are packaged in the APK - gameApplicationStartupParams.m_appRootOverride = pathToAssets.c_str(); - } - if (mainInfo.m_allocator) { gameApplicationStartupParams.m_allocator = mainInfo.m_allocator; @@ -654,8 +508,6 @@ namespace LumberyardLauncher gameApplicationStartupParams.m_loadDynamicModules = false; #endif // defined(AZ_MONOLITHIC_BUILD) - CopySettingsRegistryToCrySystemInitParams(*settingsRegistry, systemInitParams); - gameApplication.Start({}, gameApplicationStartupParams); #if defined(REMOTE_ASSET_PROCESSOR) @@ -688,7 +540,7 @@ namespace LumberyardLauncher mainInfo.m_onPostAppStart(); } - azstrncpy(systemInitParams.szSystemCmdLine, sizeof(systemInitParams.szSystemCmdLine), + azstrncpy(systemInitParams.szSystemCmdLine, sizeof(systemInitParams.szSystemCmdLine), mainInfo.m_commandLine, mainInfo.m_commandLineLen); systemInitParams.pSharedEnvironment = AZ::Environment::GetInstance(); @@ -704,7 +556,10 @@ namespace LumberyardLauncher systemInitParams.bDedicatedServer = IsDedicatedServer(); - if (systemInitParams.remoteFileIO) + bool remoteFileSystemEnabled{}; + AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, remoteFileSystemEnabled, + AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "remote_filesystem"); + if (remoteFileSystemEnabled) { AZ_TracePrintf("Launcher", "Application is configured for VFS"); AZ_TracePrintf("Launcher", "Log and cache files will be written to the Cache directory on your host PC"); @@ -716,22 +571,15 @@ namespace LumberyardLauncher { AZ_TracePrintf("Launcher", "%s\n%s", message, mainInfo.m_additionalVfsResolution) } - else + else { AZ_TracePrintf("Launcher", "%s", message) } } else { - AZ_TracePrintf("Launcher", "Application is configured to use device local files at %s\n", systemInitParams.rootPath); + AZ_TracePrintf("Launcher", "Application is configured to use device local files at %s\n", pathToAssets.c_str()); AZ_TracePrintf("Launcher", "Log and cache files will be written to device storage\n"); - - const char* writeStorage = mainInfo.m_appWriteStoragePath; - if (writeStorage) - { - AZ_TracePrintf("Launcher", "User Storage will be set to %s/user\n", writeStorage); - azsnprintf(systemInitParams.userPath, AZ_MAX_PATH_LEN, "%s/user", writeStorage); - } } // Create CrySystem. diff --git a/Code/LauncherUnified/Launcher.h b/Code/LauncherUnified/Launcher.h index 72471ab1e7..49f6a33f3c 100644 --- a/Code/LauncherUnified/Launcher.h +++ b/Code/LauncherUnified/Launcher.h @@ -84,7 +84,6 @@ namespace LumberyardLauncher Success = 0, ErrExePath, //!< Failed to get the executable path - ErrBootstrapMismatch, //!< Failed to validate launcher compiler defines with bootstrap values ErrCommandLine, //!< Failed to copy the command line ErrValidation, //!< Failed to validate secret ErrResourceLimit, //!< Failed to increase unix resource limits @@ -107,10 +106,13 @@ namespace LumberyardLauncher ////////////////////////////////////////////////////////////////////////// //! This function returns the name of the project - const AZStd::string_view GetGameProjectName(); + AZStd::string_view GetProjectName(); + + //! This function returns the path of the project as known by the build system + AZStd::string_view GetProjectPath(); //! This function returns the build system target name - const AZStd::string_view GetBuildTargetName(); + AZStd::string_view GetBuildTargetName(); ////////////////////////////////////////////////////////////////////////// // The following functions are defined per launcher type (e.g. Game/Server) diff --git a/Code/LauncherUnified/LauncherProject.cpp b/Code/LauncherUnified/LauncherProject.cpp index a951d773f8..ebcabb3ffc 100644 --- a/Code/LauncherUnified/LauncherProject.cpp +++ b/Code/LauncherUnified/LauncherProject.cpp @@ -20,7 +20,7 @@ namespace LumberyardLauncher { //! This file is to be added only to the ${project}.[Game|Server]Launcher build target //! This function returns the build system target name - const AZStd::string_view GetBuildTargetName() + AZStd::string_view GetBuildTargetName() { #if !defined (LY_CMAKE_TARGET) #error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" @@ -29,11 +29,22 @@ namespace LumberyardLauncher } - const AZStd::string_view GetGameProjectName() + AZStd::string_view GetProjectName() { -#if !defined (LY_GAME_PROJECT_NAME) -#error "LY_GAME_PROJECT_NAME must be defined in order to for the Launcher to run using a Game Project" +#if !defined (LY_PROJECT_NAME) +#error "LY_PROJECT_NAME must be defined in order to for the Launcher to run using a Game Project" +#endif + return { LY_PROJECT_NAME }; + } + + AZStd::string_view GetProjectPath() + { + // The Project CMake path optional and not required + // It is used as fall back project root path +#if defined LY_PROJECT_CMAKE_PATH + return { LY_PROJECT_CMAKE_PATH }; +#else + return {}; #endif - return { LY_GAME_PROJECT_NAME }; } } diff --git a/Code/LauncherUnified/Platform/Android/Launcher_Traits_Android.h b/Code/LauncherUnified/Platform/Android/Launcher_Traits_Android.h index bb73a7d90d..247299caf4 100644 --- a/Code/LauncherUnified/Platform/Android/Launcher_Traits_Android.h +++ b/Code/LauncherUnified/Platform/Android/Launcher_Traits_Android.h @@ -12,7 +12,5 @@ #pragma once #define AZ_TRAIT_LAUNCHER_LOWER_CASE_PATHS 1 -#define AZ_TRAIT_LAUNCHER_SET_APPROOT_OVERRIDE 0 -#define AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE 0 #define AZ_TRAIT_LAUNCHER_USE_CRY_DYNAMIC_MODULE_HANDLE 1 #define AZ_TRAIT_SHARED_LIBRARY_FILENAME_FORMAT "%s/lib%s.so" diff --git a/Code/LauncherUnified/Platform/Linux/Launcher_Traits_Linux.h b/Code/LauncherUnified/Platform/Linux/Launcher_Traits_Linux.h index 8ed85c91b3..657f8adf3d 100644 --- a/Code/LauncherUnified/Platform/Linux/Launcher_Traits_Linux.h +++ b/Code/LauncherUnified/Platform/Linux/Launcher_Traits_Linux.h @@ -12,7 +12,5 @@ #pragma once #define AZ_TRAIT_LAUNCHER_LOWER_CASE_PATHS 0 -#define AZ_TRAIT_LAUNCHER_SET_APPROOT_OVERRIDE 0 -#define AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE 1 #define AZ_TRAIT_LAUNCHER_USE_CRY_DYNAMIC_MODULE_HANDLE 1 #define AZ_TRAIT_SHARED_LIBRARY_FILENAME_FORMAT "%s/lib%s.so" diff --git a/Code/LauncherUnified/Platform/Mac/Launcher_Traits_Mac.h b/Code/LauncherUnified/Platform/Mac/Launcher_Traits_Mac.h index 1c01f0b598..a3b6665f43 100644 --- a/Code/LauncherUnified/Platform/Mac/Launcher_Traits_Mac.h +++ b/Code/LauncherUnified/Platform/Mac/Launcher_Traits_Mac.h @@ -12,7 +12,5 @@ #pragma once #define AZ_TRAIT_LAUNCHER_LOWER_CASE_PATHS 1 -#define AZ_TRAIT_LAUNCHER_SET_APPROOT_OVERRIDE 1 -#define AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE 1 #define AZ_TRAIT_LAUNCHER_USE_CRY_DYNAMIC_MODULE_HANDLE 1 #define AZ_TRAIT_SHARED_LIBRARY_FILENAME_FORMAT "%s/lib%s.dylib" diff --git a/Code/LauncherUnified/Platform/Mac/launcher_project_mac.cmake b/Code/LauncherUnified/Platform/Mac/launcher_project_mac.cmake index 4e3554b450..8d55ae93b0 100644 --- a/Code/LauncherUnified/Platform/Mac/launcher_project_mac.cmake +++ b/Code/LauncherUnified/Platform/Mac/launcher_project_mac.cmake @@ -20,35 +20,39 @@ else() endif() # Add resources and app icons to launchers -get_target_property(${project}_SOURCE_DIR ${project} SOURCE_DIR) -get_filename_component(${project}_SOURCE_PARENT_DIR ${${project}_SOURCE_DIR} DIRECTORY) - -set(ly_game_resource_folder ${${project}_SOURCE_PARENT_DIR}/Resources/Platform/Mac) -if (NOT EXISTS ${ly_game_resource_folder}) - set(ly_game_resource_folder ${${project}_SOURCE_PARENT_DIR}/Resources/MacLauncher) - if (NOT EXISTS ${ly_game_resource_folder}) - message(FATAL_ERROR "Missing expected resources folder") +list(APPEND candidate_paths ${project_real_path}/Resources/Platform/Mac) +list(APPEND candidate_paths ${project_real_path}/Gem/Resources/Platform/Mac) # Legacy projects +list(APPEND candidate_paths ${project_real_path}/Gem/Resources/MacLauncher) # Legacy projects +foreach(resource_path IN LISTS candidate_paths) + if(EXISTS ${resource_path}) + set(ly_game_resource_folder ${resource_path}) + break() endif() +endforeach() + +if(NOT EXISTS ${ly_game_resource_folder}) + list(JOIN candidate_paths " " formatted_error) + message(FATAL_ERROR "Missing 'Resources' folder. Candidate paths tried were: ${formatted_error}") endif() -target_sources(${project}.GameLauncher PRIVATE ${ly_game_resource_folder}/Images.xcassets) -set_target_properties(${project}.GameLauncher PROPERTIES + +target_sources(${project_name}.GameLauncher PRIVATE ${ly_game_resource_folder}/Images.xcassets) +set_target_properties(${project_name}.GameLauncher PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${ly_game_resource_folder}/Info.plist RESOURCE ${ly_game_resource_folder}/Images.xcassets - XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${project}AppIcon + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${project_name}AppIcon ) set(layout_tool_dir ${LY_ROOT_FOLDER}/cmake/Tools) -add_custom_command(TARGET ${project}.GameLauncher POST_BUILD +add_custom_command(TARGET ${project_name}.GameLauncher POST_BUILD COMMAND ${LY_PYTHON_CMD} layout_tool.py - --dev-root "${LY_ROOT_FOLDER}" -p Mac -a ${LY_ASSET_DEPLOY_ASSET_TYPE} - -g ${project} + --project-path ${project_real_path} -m ${LY_ASSET_DEPLOY_MODE} --create-layout-root - -l $/Contents/Resources/assets + -l $/Contents/Resources/assets --build-config $ --warn-on-missing-assets --verify diff --git a/Code/LauncherUnified/Platform/Windows/Launcher_Traits_Windows.h b/Code/LauncherUnified/Platform/Windows/Launcher_Traits_Windows.h index 839f4dcd8a..f2645eb8e7 100644 --- a/Code/LauncherUnified/Platform/Windows/Launcher_Traits_Windows.h +++ b/Code/LauncherUnified/Platform/Windows/Launcher_Traits_Windows.h @@ -12,7 +12,5 @@ #pragma once #define AZ_TRAIT_LAUNCHER_LOWER_CASE_PATHS 0 -#define AZ_TRAIT_LAUNCHER_SET_APPROOT_OVERRIDE 0 -#define AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE 1 #define AZ_TRAIT_LAUNCHER_USE_CRY_DYNAMIC_MODULE_HANDLE 0 #define AZ_TRAIT_SHARED_LIBRARY_FILENAME_FORMAT R"(%s\%s.dll)" diff --git a/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake b/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake index cdb7950373..fe5183e2f5 100644 --- a/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake +++ b/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake @@ -21,17 +21,14 @@ else() ) endif() -# Find the resource from the game gem -get_target_property(${project}_SOURCE_DIR ${project} SOURCE_DIR) # Point to where the code is -get_filename_component(${project}_SOURCE_PARENT_DIR ${${project}_SOURCE_DIR} DIRECTORY) # Parent directory - -set(ICON_FILE ${${project}_SOURCE_PARENT_DIR}/Resources/GameSDK.ico) +set(ICON_FILE ${project_real_path}/Gem/Resources/GameSDK.ico) if(NOT EXISTS ${ICON_FILE}) # Try the common LauncherUnified icon instead set(ICON_FILE Resources/GameSDK.ico) endif() + if(EXISTS ${ICON_FILE}) - set(target_file ${CMAKE_CURRENT_BINARY_DIR}/${project}.GameLauncher.rc) + set(target_file ${CMAKE_CURRENT_BINARY_DIR}/${project_name}.GameLauncher.rc) configure_file(Platform/Windows/Launcher.rc.in ${target_file} @ONLY diff --git a/Code/LauncherUnified/Platform/iOS/Launcher_Traits_iOS.h b/Code/LauncherUnified/Platform/iOS/Launcher_Traits_iOS.h index 1f867956b6..cc115f7fb9 100644 --- a/Code/LauncherUnified/Platform/iOS/Launcher_Traits_iOS.h +++ b/Code/LauncherUnified/Platform/iOS/Launcher_Traits_iOS.h @@ -12,7 +12,5 @@ #pragma once #define AZ_TRAIT_LAUNCHER_LOWER_CASE_PATHS 1 -#define AZ_TRAIT_LAUNCHER_SET_APPROOT_OVERRIDE 1 -#define AZ_TRAIT_LAUNCHER_ALLOW_CMDLINE_APPROOT_OVERRIDE 0 #define AZ_TRAIT_LAUNCHER_USE_CRY_DYNAMIC_MODULE_HANDLE 0 #define AZ_TRAIT_SHARED_LIBRARY_FILENAME_FORMAT "%s/lib%s.dylib" diff --git a/Code/LauncherUnified/Platform/iOS/launcher_project_ios.cmake b/Code/LauncherUnified/Platform/iOS/launcher_project_ios.cmake index 7339a1e858..8d2bc95eda 100644 --- a/Code/LauncherUnified/Platform/iOS/launcher_project_ios.cmake +++ b/Code/LauncherUnified/Platform/iOS/launcher_project_ios.cmake @@ -21,37 +21,40 @@ else() set(LY_RUNTIME_DEPENDENCIES Legacy::CryRenderMetal) endif() -# Find the resource from the game gem -get_target_property(${project}_SOURCE_DIR ${project} SOURCE_DIR) # Point to where the code is -get_filename_component(${project}_SOURCE_PARENT_DIR ${${project}_SOURCE_DIR} DIRECTORY) # Parent directory - -set(ly_game_resource_folder ${${project}_SOURCE_PARENT_DIR}/Resources/Platform/iOS) -if (NOT EXISTS ${ly_game_resource_folder}) - set(ly_game_resource_folder ${${project}_SOURCE_PARENT_DIR}/Resources/IOSLauncher) - if (NOT EXISTS ${ly_game_resource_folder}) - message(FATAL_ERROR "Missing expected resources folder") +# Add resources and app icons to launchers +list(APPEND candidate_paths ${project_real_path}/Resources/Platform/iOS) +list(APPEND candidate_paths ${project_real_path}/Gem/Resources/Platform/iOS) # Legacy projects +list(APPEND candidate_paths ${project_real_path}/Gem/Resources/IOSLauncher) # Legacy projects +foreach(resource_path IN LISTS candidate_paths) + if(EXISTS ${resource_path}) + set(ly_game_resource_folder ${resource_path}) + break() endif() +endforeach() + +if(NOT EXISTS ${ly_game_resource_folder}) + list(JOIN candidate_paths " " formatted_error) + message(FATAL_ERROR "Missing 'Resources' folder. Candidate paths tried were: ${formatted_error}") endif() -# Add resources and app icons to launchers -target_sources(${project}.GameLauncher PRIVATE ${ly_game_resource_folder}/Images.xcassets) -set_target_properties(${project}.GameLauncher PROPERTIES + +target_sources(${project_name}.GameLauncher PRIVATE ${ly_game_resource_folder}/Images.xcassets) +set_target_properties(${project_name}.GameLauncher PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${ly_game_resource_folder}/Info.plist RESOURCE ${ly_game_resource_folder}/Images.xcassets - XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${project}AppIcon + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${project_name}AppIcon ) set(layout_tool_dir ${LY_ROOT_FOLDER}/cmake/Tools) -add_custom_command(TARGET ${project}.GameLauncher POST_BUILD +add_custom_command(TARGET ${project_name}.GameLauncher POST_BUILD COMMAND ${LY_PYTHON_CMD} layout_tool.py - --dev-root "${LY_ROOT_FOLDER}" -p iOS -a ${LY_ASSET_DEPLOY_ASSET_TYPE} - -g ${project} + --project-path ${project_real_path} -m ${LY_ASSET_DEPLOY_MODE} --create-layout-root - -l $/assets + -l $/assets --build-config $ --warn-on-missing-assets --verify diff --git a/Code/LauncherUnified/Tests/Test.cpp b/Code/LauncherUnified/Tests/Test.cpp index 8ddd0aa023..86b13250a4 100644 --- a/Code/LauncherUnified/Tests/Test.cpp +++ b/Code/LauncherUnified/Tests/Test.cpp @@ -29,7 +29,7 @@ namespace LumberyardLauncher return "@log@/Game.log"; } - const AZStd::string_view GetBuildTargetName() + AZStd::string_view GetBuildTargetName() { #if !defined (LY_CMAKE_TARGET) #error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" @@ -37,7 +37,12 @@ namespace LumberyardLauncher return { LY_CMAKE_TARGET }; } - const AZStd::string_view GetGameProjectName() + AZStd::string_view GetProjectName() + { + return { "Tests" }; + } + + AZStd::string_view GetProjectPath() { return { "Tests" }; } diff --git a/Code/Sandbox/Editor/AssetDatabase/AssetDatabaseLocationListener.cpp b/Code/Sandbox/Editor/AssetDatabase/AssetDatabaseLocationListener.cpp index 30cb1df317..8bf8ecad9a 100644 --- a/Code/Sandbox/Editor/AssetDatabase/AssetDatabaseLocationListener.cpp +++ b/Code/Sandbox/Editor/AssetDatabase/AssetDatabaseLocationListener.cpp @@ -14,6 +14,8 @@ #include "AssetDatabaseLocationListener.h" +#include + // AzToolsFramework #include #include @@ -44,16 +46,20 @@ namespace AssetDatabase return m_assetDatabaseConnection; } - bool AssetDatabaseLocationListener::GetAssetDatabaseLocation( AZStd::string& result ) + bool AssetDatabaseLocationListener::GetAssetDatabaseLocation(AZStd::string& result) { - result = gEnv->pFileIO->GetAlias( "@devroot@" ); - result += "/Cache/"; - ICVar * pCvar = gEnv->pConsole->GetCVar( "sys_game_folder" ); - if( pCvar && pCvar->GetString() ) + if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) { - result += pCvar->GetString(); + AZ::SettingsRegistryInterface::FixedValueString projectCacheRootValue; + if (registry->Get(projectCacheRootValue, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder); + !projectCacheRootValue.empty()) + { + result = projectCacheRootValue; + result += "/assetdb.sqlite"; + return true; + } } - result += "/assetdb.sqlite"; - return true; + + return false; } }//namespace AssetDatabase diff --git a/Code/Sandbox/Editor/Core/QtEditorApplication.cpp b/Code/Sandbox/Editor/Core/QtEditorApplication.cpp index 3e203bc6e8..fa5c982fc8 100644 --- a/Code/Sandbox/Editor/Core/QtEditorApplication.cpp +++ b/Code/Sandbox/Editor/Core/QtEditorApplication.cpp @@ -25,6 +25,9 @@ #include #endif +#include +#include +#include // AzFramework #if defined(AZ_PLATFORM_WINDOWS) # include @@ -267,7 +270,14 @@ namespace Editor QLoggingCategory::setFilterRules(QStringLiteral("lumberyard.editor.input.*=false")); // Initialize our stylesheet here to allow Gems to register stylesheets when their system components activate. - m_stylesheet->initialize(this); + AZ::IO::FixedMaxPath engineRootPath; + { + // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry + AZ::ComponentApplication application(argc, argv); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + m_stylesheet->initialize(this, engineRootPath); } void EditorQtApplication::Initialize() diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp index ca965391a6..bf03c96645 100644 --- a/Code/Sandbox/Editor/CryEdit.cpp +++ b/Code/Sandbox/Editor/CryEdit.cpp @@ -52,6 +52,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include // AzFramework #include @@ -81,7 +82,6 @@ AZ_POP_DISABLE_WARNING #include #include #include -#include // Editor #include "Settings.h" @@ -683,7 +683,6 @@ public: QString dummyString; const std::vector > stringOptions = { - {{"app-root", "Application Root path override", "app-root"}, m_appRoot}, {{"logfile", "File name of the log file to write out to.", "logfile"}, m_logFile}, {{"runpythonargs", "Command-line argument string to pass to the python script if --runpython or --runpythontest was used.", "runpythonargs"}, m_pythonArgs}, {{"exec", "cfg file to run on startup, used for systems like automation", "exec"}, m_execFile}, @@ -691,7 +690,11 @@ public: {{"rhi-device-validation", "Command-line argument to configure rhi validation", "dummyString"}, dummyString }, {{"exec_line", "command to run on startup, used for systems like automation", "exec_line"}, m_execLineCmd}, {{"regset", "Command-line argument to override settings registry values", "regset"}, dummyString}, - {{"regdump", "Sets a value within the global settings registry at the JSON pointer path @key with value of @value)", "regdump"}, dummyString} + {{"regremove", "Deletes a value within the global settings registry at the JSON pointer path @key", "regremove"}, dummyString}, + {{"regdump", "Sets a value within the global settings registry at the JSON pointer path @key with value of @value", "regdump"}, dummyString}, + {{"project-path", "Supplies the path to the project that the Editor should use", "project-path"}, dummyString}, + {{"engine-path", "Supplies the path to the engine", "engine-path"}, dummyString}, + {{"project-cache-path", "Path to the project cache", "project-cache-path"}, dummyString}, // add dummy entries here to prevent QCommandLineParser error-ing out on cmd line args that will be parsed later }; @@ -719,7 +722,11 @@ public: } #endif - parser.process(args); + if (!parser.parse(args)) + { + AZ_TracePrintf("QT CommandLine Parser", "QT command line parsing warned with message %s." + " Has the QCommandLineParser had these options added to it", parser.errorText().toUtf8().constData()); + } // Get boolean options const int numOptions = options.size(); @@ -1217,11 +1224,10 @@ bool CCryEditApp::InitGame() { if (!m_bPreviewMode && !GetIEditor()->IsInMatEditMode()) { - ICVar* pVar = gEnv->pConsole->GetCVar("sys_game_folder"); - const char* sGameFolder = pVar ? pVar->GetString() : nullptr; - Log((QString("sys_game_folder = ") + (sGameFolder && sGameFolder[0] ? sGameFolder : "")).toUtf8().data()); + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + Log((QString("project_path = %1").arg(!projectPath.empty() ? projectPath.c_str() : "")).toUtf8().data()); - pVar = gEnv->pConsole->GetCVar("sys_localization_folder"); + ICVar* pVar = gEnv->pConsole->GetCVar("sys_localization_folder"); const char* sLocalizationFolder = pVar ? pVar->GetString() : nullptr; Log((QString("sys_localization_folder = ") + (sLocalizationFolder && sLocalizationFolder[0] ? sLocalizationFolder : "")).toUtf8().data()); @@ -1740,11 +1746,17 @@ BOOL CCryEditApp::InitInstance() mainWindowWrapper->setGuest(mainWindow); HWND mainWindowWrapperHwnd = (HWND)mainWindowWrapper->winId(); - QDir engineRoot = AzQtComponents::FindEngineRootDir(qApp); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + QDir engineRoot = QString::fromUtf8(engineRootPath.c_str(), aznumeric_cast(engineRootPath.Native().size())); AzQtComponents::StyleManager::addSearchPaths( QStringLiteral("style"), engineRoot.filePath(QStringLiteral("Code/Sandbox/Editor/Style")), - QStringLiteral(":/Editor/Style")); + QStringLiteral(":/Editor/Style"), + engineRootPath); AzQtComponents::StyleManager::setStyleSheet(mainWindow, QStringLiteral("style:Editor.qss")); // Note: we should use getNativeHandle to get the HWND from the widget, but @@ -5496,9 +5508,9 @@ void CCryEditApp::OpenLUAEditor(const char* files) } } - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - AZ_Assert(appRoot != nullptr, "Unable to communicate to AzFramework::ApplicationRequests::Bus"); + const char* engineRoot = nullptr; + AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AZ_Assert(engineRoot != nullptr, "Unable to communicate to AzFramework::ApplicationRequests::Bus"); AZStd::string_view exePath; AZ::ComponentApplicationBus::BroadcastResult(exePath, &AZ::ComponentApplicationRequests::GetExecutableFolder); @@ -5509,7 +5521,7 @@ void CCryEditApp::OpenLUAEditor(const char* files) #endif "\"", aznumeric_cast(exePath.size()), exePath.data()); - AZStd::string processArgs = AZStd::string::format("%s -app-root \"%s\"", args.c_str(), appRoot); + AZStd::string processArgs = AZStd::string::format("%s -engine-path \"%s\"", args.c_str(), engineRoot); StartProcessDetached(process.c_str(), processArgs.c_str()); } diff --git a/Code/Sandbox/Editor/Dialogs/PythonScriptsDialog.cpp b/Code/Sandbox/Editor/Dialogs/PythonScriptsDialog.cpp index 71c956f8a3..b6abac4810 100644 --- a/Code/Sandbox/Editor/Dialogs/PythonScriptsDialog.cpp +++ b/Code/Sandbox/Editor/Dialogs/PythonScriptsDialog.cpp @@ -19,6 +19,8 @@ #include // for AZ::ModuleData #include // for AZ::ModuleManagerRequestBus #include // for AZ::DynamicModuleHandle +#include +#include // AzToolsFramework #include // for AzToolsFramework::ViewPaneOptions @@ -88,26 +90,64 @@ CPythonScriptsDialog::CPythonScriptsDialog(QWidget* parent) } } - ScanFolderForScripts(QString("@devroot@/%1/Editor/Scripts").arg(GetIEditor()->GetProjectName()), scriptFolders); + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + ScanFolderForScripts(QString("%1/Editor/Scripts").arg(projectPath.c_str()), scriptFolders); - auto moduleCallback = [this, &scriptFolders](const AZ::ModuleData& moduleData) -> bool + struct GetGemSourcePathsVisitor + : AZ::SettingsRegistryInterface::Visitor { - if (moduleData.GetDynamicModuleHandle()) + GetGemSourcePathsVisitor(AZ::SettingsRegistryInterface& settingsRegistry) + : m_settingsRegistry(settingsRegistry) + {} + void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type, + AZStd::string_view value) override { - const AZ::OSString& modulePath = moduleData.GetDynamicModuleHandle()->GetFilename(); - AZStd::string fileName; - AzFramework::StringFunc::Path::GetFileName(modulePath.c_str(), fileName); - - AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(fileName.c_str(), tokens, '.'); - if (tokens.size() > 2 && tokens[0] == "Gem") + AZStd::string_view jsonSourcePathPointer{ path }; + // Remove the array index from the path and check if the JSON path ends with "/SourcePaths" + AZ::StringFunc::TokenizeLast(jsonSourcePathPointer, "/"); + if (jsonSourcePathPointer.ends_with("/SourcePaths")) { - ScanFolderForScripts(QString("@engroot@/Gems/%1/Editor/Scripts").arg(tokens[1].c_str()), scriptFolders); + AZ::IO::Path newSourcePath = jsonSourcePathPointer; + // Resolve any file aliases first - Do not use ResolvePath() as that assumes + // any relative path is underneath the @assets@ alias + if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) + { + AZ::IO::FixedMaxPath replacedAliasPath; + if (fileIoBase->ReplaceAlias(replacedAliasPath, value)) + { + newSourcePath = AZ::IO::PathView(replacedAliasPath); + } + } + + // The current assumption is that the gem source path is the relative to the engine root + AZ::IO::Path engineRootPath; + m_settingsRegistry.Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + newSourcePath = (engineRootPath / newSourcePath).LexicallyNormal(); + + if (auto gemSourcePathIter = AZStd::find(m_gemSourcePaths.begin(), m_gemSourcePaths.end(), newSourcePath); + gemSourcePathIter == m_gemSourcePaths.end()) + { + m_gemSourcePaths.emplace_back(AZStd::move(newSourcePath)); + } } } - return true; + + AZStd::vector m_gemSourcePaths; + private: + AZ::SettingsRegistryInterface& m_settingsRegistry; }; - AZ::ModuleManagerRequestBus::Broadcast(&AZ::ModuleManagerRequestBus::Events::EnumerateModules, moduleCallback); + + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + GetGemSourcePathsVisitor visitor{ *settingsRegistry }; + constexpr auto gemListKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::OrganizationRootKey) + + "/Gems"; + settingsRegistry->Visit(visitor, gemListKey); + for (const AZ::IO::Path& gemSourcePath : visitor.m_gemSourcePaths) + { + ScanFolderForScripts(QString("%1/Editor/Scripts").arg(gemSourcePath.c_str()), scriptFolders); + } + } ui->treeView->init(scriptFolders, s_kPythonFileNameSpec, s_kRootElementName, false, false); QObject::connect(ui->treeView, &CFolderTreeCtrl::ItemDoubleClicked, this, &CPythonScriptsDialog::OnExecute); diff --git a/Code/Sandbox/Editor/EditorToolsApplication.cpp b/Code/Sandbox/Editor/EditorToolsApplication.cpp index 3e66f3fe9a..add0bb4ff2 100644 --- a/Code/Sandbox/Editor/EditorToolsApplication.cpp +++ b/Code/Sandbox/Editor/EditorToolsApplication.cpp @@ -23,9 +23,6 @@ #include #include -// CryCommon -#include - // Editor #include "MainWindow.h" #include "CryEdit.h" @@ -109,15 +106,6 @@ namespace EditorInternal { AzFramework::Application::StartupParameters params; - AZStd::string appRootOverride; - const size_t appRootSwitches = m_commandLine.GetNumSwitchValues("app-root"); - if (appRootSwitches != 0) - { - // Use the last --app-root parameter specified on the command line - appRootOverride = m_commandLine.GetSwitchValue("app-root", appRootSwitches - 1); - params.m_appRootOverride = appRootOverride.c_str(); - } - // Must be done before creating QApplication, otherwise asserts when we alloc AzToolsFramework::ToolsApplication::Start({}, params); if (IsStartupAborted() || !m_systemEntity) diff --git a/Code/Sandbox/Editor/GameEngine.cpp b/Code/Sandbox/Editor/GameEngine.cpp index be83858f96..258ed52dbc 100644 --- a/Code/Sandbox/Editor/GameEngine.cpp +++ b/Code/Sandbox/Editor/GameEngine.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include // Editor @@ -415,24 +414,7 @@ AZ::Outcome CGameEngine::Init( (PFNCREATESYSTEMINTERFACE)CryGetProcAddress(m_hSystemHandle, "CreateSystemInterface"); - // Locate the root path - const char* calcRootPath = nullptr; - EBUS_EVENT_RESULT(calcRootPath, AZ::ComponentApplicationBus, GetAppRoot); - if (calcRootPath == nullptr) - { - // If the app root isnt available, default to the engine root - EBUS_EVENT_RESULT(calcRootPath, AzToolsFramework::ToolsApplicationRequestBus, GetEngineRootPath); - } - const char* searchPath[] = { calcRootPath }; - CEngineConfig engineConfig(searchPath,AZ_ARRAY_SIZE(searchPath)); // read the engine config also to see what game is running, and what folder(s) there are. - SSystemInitParams sip; - engineConfig.CopyToStartupParams(sip); - - sip.connectToRemote = true; // editor always connects - sip.waitForConnection = true; // editor REQUIRES connect. - const char localIP[10] = "127.0.0.1"; - azstrncpy(sip.remoteIP, AZ_ARRAY_SIZE(sip.remoteIP), localIP, AZ_ARRAY_SIZE(localIP)); // editor ONLY connects to the local asset processor sip.bEditor = true; sip.bDedicatedServer = false; @@ -457,15 +439,6 @@ AZ::Outcome CGameEngine::Init( sip.pUserCallback = m_pSystemUserCallback; sip.pValidator = GetIEditor()->GetErrorReport(); // Assign validator from Editor. - // Calculate the branch token first based on the app root path if possible - if (calcRootPath!=nullptr) - { - AZStd::string appRoot(calcRootPath); - AZStd::string branchToken; - AzFramework::StringFunc::AssetPath::CalculateBranchToken(appRoot, branchToken); - azstrncpy(sip.branchToken, AZ_ARRAY_SIZE(sip.branchToken), branchToken.c_str(), branchToken.length()); - } - if (sInCmdLine) { azstrncpy(sip.szSystemCmdLine, AZ_COMMAND_LINE_LEN, sInCmdLine, AZ_COMMAND_LINE_LEN); @@ -484,7 +457,7 @@ AZ::Outcome CGameEngine::Init( { sip.bSkipFont = true; } - AssetProcessConnectionStatus apConnectionStatus; + AssetProcessConnectionStatus apConnectionStatus; m_pISystem = pfnCreateSystemInterface(sip); @@ -512,33 +485,16 @@ AZ::Outcome CGameEngine::Init( if (apConnectionStatus.CheckConnectionFailed()) { + AzFramework::AssetSystem::ConnectionSettings connectionSettings; + AzFramework::AssetSystem::ReadConnectionSettingsFromSettingsRegistry(connectionSettings); auto errorMessage = AZStd::string::format("Unable to connect to the local Asset Processor.\n\n" - "The Asset Processor is either not running locally or not accepting connections on port %d. " + "The Asset Processor is either not running locally or not accepting connections on port %hu. " "Check your remote_port settings in bootstrap.cfg or view the Asset Processor's \"Logs\" tab " - "for any errors.", sip.remotePort); + "for any errors.", connectionSettings.m_assetProcessorPort); gEnv = nullptr; return AZ::Failure(errorMessage); } - // because we're the editor here, we also give tool aliases to the original, unaltered roots: - string devAssetsFolder = engineConfig.m_rootFolder + "/" + engineConfig.m_gameFolder; - if (gEnv && gEnv->pFileIO) - { - const char* engineRoot = nullptr; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(engineRoot, &AzToolsFramework::ToolsApplicationRequests::GetEngineRootPath); - if (engineRoot != nullptr) - { - gEnv->pFileIO->SetAlias("@engroot@", engineRoot); - } - else - { - gEnv->pFileIO->SetAlias("@engroot@", engineConfig.m_rootFolder.c_str()); - } - - gEnv->pFileIO->SetAlias("@devroot@", engineConfig.m_rootFolder.c_str()); - gEnv->pFileIO->SetAlias("@devassets@", devAssetsFolder.c_str()); - } - SetEditorCoreEnvironment(gEnv); if (gEnv diff --git a/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp b/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp index ed895b2a4b..afc96def55 100644 --- a/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp +++ b/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp @@ -28,6 +28,8 @@ #include #include +#include + // AzFramework #include #include @@ -975,8 +977,9 @@ void GraphicsSettingsDialog::accept() void GraphicsSettingsDialog::OpenCustomSpecDialog() { - QString projectName = GetIEditor()->GetProjectName(); - QString settingsPath = projectName + "/" + SETTINGS_FILE_PATH; + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + projectPath /= SETTINGS_FILE_PATH.toUtf8().constData(); + QString settingsPath = QString::fromUtf8(projectPath.c_str(), aznumeric_cast(projectPath.Native().size())); CAutoDirectoryRestoreFileDialog importCustomSpecDialog(QFileDialog::AcceptOpen, QFileDialog::ExistingFile, ".cfg", settingsPath, CFG_FILEFILTER, {}, {}, this); @@ -1189,8 +1192,9 @@ void GraphicsSettingsDialog::SaveSystemSettings() // Adding the project name to the path so that the file is created there if it doesn't already exist // as we don't want to modify the version in Engine/config. - QString projectName = GetIEditor()->GetProjectName(); - QString settingsPath = projectName + "/" + SETTINGS_FILE_PATH; + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + projectPath /= SETTINGS_FILE_PATH.toUtf8().constData(); + QString settingsPath = QString::fromUtf8(projectPath.c_str(), aznumeric_cast(projectPath.Native().size())); QString settingsFile = settingsPath + m_cfgFiles[m_currentPlatform][cfgFileIndex].c_str(); diff --git a/Code/Sandbox/Editor/IEditor.h b/Code/Sandbox/Editor/IEditor.h index e566420215..6b96ce6a59 100644 --- a/Code/Sandbox/Editor/IEditor.h +++ b/Code/Sandbox/Editor/IEditor.h @@ -516,8 +516,6 @@ struct IEditor virtual QString GetSearchPath(EEditorPathName path) = 0; //! This folder is supposed to store Sandbox user settings and state virtual QString GetResolvedUserFolder() = 0; - //! Returns the name of the sys_game_folder - virtual QString GetProjectName() = 0; //! Execute application and get console output. virtual bool ExecuteConsoleApp( const QString& CommandLine, diff --git a/Code/Sandbox/Editor/IEditorImpl.cpp b/Code/Sandbox/Editor/IEditorImpl.cpp index 2ae3c4408d..f2ceea58bc 100644 --- a/Code/Sandbox/Editor/IEditorImpl.cpp +++ b/Code/Sandbox/Editor/IEditorImpl.cpp @@ -655,17 +655,6 @@ QString CEditorImpl::GetResolvedUserFolder() return m_userFolder; } -QString CEditorImpl::GetProjectName() -{ - ICVar* pCVar = (gEnv && gEnv->pConsole) ? gEnv->pConsole->GetCVar("sys_game_folder") : nullptr; - if (pCVar && pCVar->GetString()) - { - return QString(pCVar->GetString()); - } - - return tr("unknown"); -} - void CEditorImpl::SetDataModified() { GetDocument()->SetModifiedFlag(TRUE); diff --git a/Code/Sandbox/Editor/IEditorImpl.h b/Code/Sandbox/Editor/IEditorImpl.h index 41cf4f3eb5..d540392a81 100644 --- a/Code/Sandbox/Editor/IEditorImpl.h +++ b/Code/Sandbox/Editor/IEditorImpl.h @@ -146,7 +146,6 @@ public: QString GetLevelDataFolder(); QString GetSearchPath(EEditorPathName path); QString GetResolvedUserFolder(); - QString GetProjectName() override; bool ExecuteConsoleApp(const QString& CommandLine, QString& OutputText, bool bNoTimeOut = false, bool bShowWindow = false); virtual bool IsInGameMode() override; virtual void SetInGameMode(bool inGame) override; diff --git a/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h b/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h index 8a2c7f0b50..2fbbaa00d2 100644 --- a/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h +++ b/Code/Sandbox/Editor/Lib/Tests/IEditorMock.h @@ -61,7 +61,6 @@ public: MOCK_METHOD0(GetLevelDataFolder, QString()); MOCK_METHOD1(GetPrimaryCDFolder, QString(EEditorPathName)); MOCK_METHOD0(GetResolvedUserFolder, QString()); - MOCK_METHOD0(GetProjectName, QString()); MOCK_METHOD4(ExecuteConsoleApp, bool(const QString&,QString&,bool,bool)); MOCK_METHOD0(SetDataModified, void()); MOCK_CONST_METHOD0(IsInitialized, bool()); diff --git a/Code/Sandbox/Editor/MainStatusBar.cpp b/Code/Sandbox/Editor/MainStatusBar.cpp index 6f944bcd5e..578f7d1d62 100644 --- a/Code/Sandbox/Editor/MainStatusBar.cpp +++ b/Code/Sandbox/Editor/MainStatusBar.cpp @@ -15,6 +15,7 @@ #include "MainStatusBar.h" +#include // AzQtComponents #include #include @@ -220,24 +221,16 @@ MainStatusBar::MainStatusBar(QWidget* parent) void MainStatusBar::Init() { //called on mainwindow initialization - const int statusbarTimerUpdateInterval { + const int statusbarTimerUpdateInterval{ 500 }; //in ms, so 2 FPS + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); QString strGameInfo; - ICVar* pCVar = gEnv->pConsole->GetCVar("sys_game_folder"); - if (pCVar) - { - strGameInfo = tr("GameFolder: '%1'").arg(QtUtil::ToQString(pCVar->GetString())); - } - pCVar = gEnv->pConsole->GetCVar("sys_dll_game"); - if (pCVar) - { - strGameInfo += QLatin1String(" - ") + tr("GameDLL: '%1'").arg(QtUtil::ToQString(pCVar->GetString())); - } + strGameInfo = tr("GameFolder: '%1'").arg(projectPath.c_str()); SetItem(QStringLiteral("game_info"), strGameInfo, tr("Game Info"), QPixmap()); - //ask for updates for items regulary. This is basically what MFC does + //ask for updates for items regularly. This is basically what MFC does auto timer = new QTimer(this); timer->setInterval(statusbarTimerUpdateInterval); connect(timer, &QTimer::timeout, this, &MainStatusBar::requestStatusUpdate); diff --git a/Code/Sandbox/Editor/Settings.cpp b/Code/Sandbox/Editor/Settings.cpp index 7e651f316c..316a8aad86 100644 --- a/Code/Sandbox/Editor/Settings.cpp +++ b/Code/Sandbox/Editor/Settings.cpp @@ -24,9 +24,8 @@ #include #include #include - -// AzFramework -#include +#include +#include // AzToolsFramework #include @@ -997,7 +996,7 @@ void SEditorSettings::LoadDefaultGamePaths() } AZStd::string iconsPath; - AzFramework::StringFunc::Path::Join(Path::GetEditingRootFolder().c_str(), "Editor/UI/Icons", iconsPath); + AZ::StringFunc::Path::Join(Path::GetEditingRootFolder().c_str(), "Editor/UI/Icons", iconsPath); searchPaths[EDITOR_PATH_UI_ICONS].push_back(iconsPath.c_str()); } @@ -1166,34 +1165,28 @@ AzToolsFramework::EditorSettingsAPIRequests::SettingOutcome SEditorSettings::Set void SEditorSettings::SaveSettingsRegistryFile() { - auto fileIo = AZ::IO::FileIOBase::GetInstance(); - - // Resolve path to editorpreferences.setreg - AZ::IO::FixedMaxPath editorPreferencesFilePath = "user/Registry/editorpreferences.setreg"; - if (fileIo == nullptr || !fileIo->ResolvePath(editorPreferencesFilePath, "@devroot@/user/Registry/editorpreferences.setreg")) + auto registry = AZ::SettingsRegistry::Get(); + if (registry == nullptr) { - AZ_Warning("SEditorSettings", false, R"(Unable to resolve path "%s" to the Editor Preferences registry file\n)", - editorPreferencesFilePath.c_str()); + AZ_Warning("SEditorSettings", false, "Unable to access global settings registry. Editor Preferences cannot be saved"); return; } + // Resolve path to editorpreferences.setreg + AZ::IO::FixedMaxPath editorPreferencesFilePath = AZ::Utils::GetProjectPath(); + editorPreferencesFilePath /= "user/Registry/editorpreferences.setreg"; + AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings; dumperSettings.m_prettifyOutput = true; - dumperSettings.m_includeFilter = [](AZStd::string_view path) - { - AZStd::string_view prefixPath("/Amazon/Editor/Preferences"); - return prefixPath.starts_with(path.substr(0, prefixPath.size())); - }; + dumperSettings.m_jsonPointerPrefix = "/Amazon/Editor/Preferences"; + AZStd::string stringBuffer; - if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) + AZ::IO::ByteContainerStream stringStream(&stringBuffer); + if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(*registry, "/Amazon/Editor/Preferences", stringStream, dumperSettings)) { - AZ::IO::ByteContainerStream stringStream(&stringBuffer); - if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(*registry, "", stringStream, dumperSettings)) - { - AZ_Warning("SEditorSettings", false, R"(Unable to save changes to the Editor Preferences registry file at "%s"\n)", - editorPreferencesFilePath.c_str()); - return; - } + AZ_Warning("SEditorSettings", false, R"(Unable to save changes to the Editor Preferences registry file at "%s"\n)", + editorPreferencesFilePath.c_str()); + return; } bool saved{}; diff --git a/Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.cpp b/Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.cpp new file mode 100644 index 0000000000..86410a0211 --- /dev/null +++ b/Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.cpp @@ -0,0 +1,124 @@ +/* + * 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. + * + */ + +#include "AtomOutputFrameCapture.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TrackView +{ + void AtomOutputFrameCapture::CreatePipeline( + AZ::RPI::Scene& scene, const AZStd::string& pipelineName, const uint32_t width, const uint32_t height) + { + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; // must be "MainCamera" + pipelineDesc.m_name = pipelineName; + pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; + pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + + if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) + { + renderToTexturePass->ResizeOutput(width, height); + } + + scene.AddRenderPipeline(m_renderPipeline); + + // rendering pipeline has a tree structure + m_passHierarchy.push_back(pipelineName); + m_passHierarchy.push_back("CopyToSwapChain"); + + // retrieve View from the camera that's animating + AZ::Name viewName = AZ::Name("MainCamera"); + m_view = AZ::RPI::View::CreateView(viewName, AZ::RPI::View::UsageCamera); + m_renderPipeline->SetDefaultView(m_view); + } + + void AtomOutputFrameCapture::DestroyPipeline(AZ::RPI::Scene& scene) + { + scene.RemoveRenderPipeline(m_renderPipeline->GetId()); + m_passHierarchy.clear(); + m_renderPipeline.reset(); + m_view.reset(); + } + + void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection) + { + m_view->SetCameraTransform(cameraTransform); + m_view->SetViewToClipMatrix(cameraProjection); + } + + bool AtomOutputFrameCapture::BeginCapture( + const AZ::RPI::AttachmentReadback::CallbackFunction& attachmentReadbackCallback, CaptureFinishedCallback captureFinishedCallback) + { + AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); + + m_captureFinishedCallback = AZStd::move(captureFinishedCallback); + + // note: "Output" (slot name) maps to MainPipeline.pass CopyToSwapChain + bool startedCapture = false; + AZ::Render::FrameCaptureRequestBus::BroadcastResult( + startedCapture, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, + AZStd::string("Output"), attachmentReadbackCallback); + + return startedCapture; + } + + void AtomOutputFrameCapture::OnCaptureFinished( + [[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) + { + m_captureFinishedCallback(); + AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); + } + + AZ::Matrix3x4 TransformFromEntityId(const AZ::EntityId entityId) + { + AZ::Transform cameraTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(cameraTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); + return AZ::Matrix3x4::CreateFromTransform(cameraTransform); + } + + AZ::Matrix4x4 ProjectionFromCameraEntityId(const AZ::EntityId entityId, const float outputWidth, const float outputHeight) + { + float nearDist = 0.0f; + Camera::CameraRequestBus::EventResult(nearDist, entityId, &Camera::CameraRequestBus::Events::GetNearClipDistance); + float farDist = 0.0f; + Camera::CameraRequestBus::EventResult(farDist, entityId, &Camera::CameraRequestBus::Events::GetFarClipDistance); + float fovRad = 0.0f; + Camera::CameraRequestBus::EventResult(fovRad, entityId, &Camera::CameraRequestBus::Events::GetFovRadians); + + const float aspectRatio = outputWidth / outputHeight; + + AZ::Matrix4x4 viewToClipMatrix; + AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, fovRad, aspectRatio, nearDist, farDist, /*reverseDepth=*/true); + return viewToClipMatrix; + } + + AZ::RPI::Scene* SceneFromGameEntityContext() + { + AzFramework::EntityContextId entityContextId; + AzFramework::GameEntityContextRequestBus::BroadcastResult( + entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); + + return AZ::RPI::Scene::GetSceneForEntityContextId(entityContextId); + } +} // namespace TrackView diff --git a/Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.h b/Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.h new file mode 100644 index 0000000000..27b210be27 --- /dev/null +++ b/Code/Sandbox/Editor/TrackView/AtomOutputFrameCapture.h @@ -0,0 +1,74 @@ +/* + * 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 + +#include +#include + +namespace TrackView +{ + //! Provides functionality to capture frames from the "MainCamera". + //! A new pipeline is created (and associated with the scene provided), a callback can be + //! provided to handle the attachment readback (what to do with the captured frame) and also + //! what to do after an individual capture fully completes (called in OnCaptureFinished). + class AtomOutputFrameCapture : private AZ::Render::FrameCaptureNotificationBus::Handler + { + public: + AtomOutputFrameCapture() = default; + + using CaptureFinishedCallback = AZStd::function; + + //! Create a new pipeline associated with a given scene. + //! @note "MainCamera" is the view that is captured. + void CreatePipeline(AZ::RPI::Scene& scene, const AZStd::string& pipelineName, uint32_t width, uint32_t height); + //! Removes the pipeline from the scene provided and then destroys it. + //! @note scene must be the same scene used to create the pipeline. + void DestroyPipeline(AZ::RPI::Scene& scene); + + //! Request a capture to start. + //! @param attachmentReadbackCallback Handles the returned attachment (image data returned by the renderer). + //! @param captureFinishedCallback Logic to run once the capture has completed fully. + bool BeginCapture( + const AZ::RPI::AttachmentReadback::CallbackFunction& attachmentReadbackCallback, + CaptureFinishedCallback captureFinishedCallback); + + //! Update the internal view that is associated with the created pipeline. + void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection); + + private: + AZ::RPI::RenderPipelinePtr m_renderPipeline; //!< The internal render pipeline. + AZ::RPI::ViewPtr m_view; //!< The view associated with the render pipeline. + AZStd::vector m_passHierarchy; //!< Pass hierarchy (includes pipelineName and CopyToSwapChain). + CaptureFinishedCallback m_captureFinishedCallback; //!< Stored callback called from OnCaptureFinished. + + // FrameCaptureNotificationBus overrides ... + void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override; + }; + + inline AZ::EntityId ActiveCameraEntityId() + { + AZ::EntityId activeCameraId; + Camera::CameraSystemRequestBus::BroadcastResult(activeCameraId, &Camera::CameraSystemRequests::GetActiveCamera); + return activeCameraId; + } + + //! Returns the transform for the given EntityId. + AZ::Matrix3x4 TransformFromEntityId(AZ::EntityId entityId); + + //! Returns the projection matrix for the given camera EntityId. + //! @note Must provide a valid camera entity. + AZ::Matrix4x4 ProjectionFromCameraEntityId(AZ::EntityId entityId, float outputWidth, float outputHeight); + + //! Helper to return the GameEntityContext scene. + AZ::RPI::Scene* SceneFromGameEntityContext(); +} // namespace TrackView diff --git a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp index 5f169756fb..9146034738 100644 --- a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -43,7 +43,6 @@ AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - namespace { const int g_useActiveViewportResolution = -1; // reserved value to indicate the use of the active viewport resolution @@ -92,6 +91,14 @@ namespace } } +static void UpdateAtomOutputFrameCaptureView(TrackView::AtomOutputFrameCapture& atomOutputFrameCapture, const int width, const int height) +{ + const AZ::EntityId activeCameraEntityId = TrackView::ActiveCameraEntityId(); + atomOutputFrameCapture.UpdateView( + TrackView::TransformFromEntityId(activeCameraEntityId), + TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, width, height)); +} + CSequenceBatchRenderDialog::CSequenceBatchRenderDialog(float fps, QWidget* pParent /* = nullptr */) : QDialog(pParent) , m_fpsForTimeToFrameConversion(fps) @@ -874,8 +881,6 @@ void CSequenceBatchRenderDialog::InitializeContext() void CSequenceBatchRenderDialog::CaptureItemStart() { - AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); - // Disable most of the UI in group chunks. // (Leave the start/cancel button and feedback elements). m_ui->BATCH_RENDER_LIST_GROUP_BOX->setEnabled(false); @@ -976,20 +981,11 @@ void CSequenceBatchRenderDialog::CaptureItemStart() m_renderContext.cvarCustomResHeightBU = pCVarCustomResHeight->GetIVal(); pCVarCustomResWidth->Set(renderWidth); pCVarCustomResHeight->Set(renderHeight); - - // awaiting ATOM-14859 - // AzFramework::NativeWindowHandle windowHandle = nullptr; - // AzFramework::WindowSystemRequestBus::BroadcastResult( - // windowHandle, &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle); - // AzFramework::WindowRequestBus::Event( - // windowHandle, &AzFramework::WindowRequestBus::Events::ResizeClientArea, - // AzFramework::WindowSize(renderWidth, renderHeight)); } else { // Otherwise, try to adjust the viewport resolution accordingly. - CLayoutViewPane* viewPane = MainWindow::instance()->GetActiveView(); - if (viewPane) + if (CLayoutViewPane* viewPane = MainWindow::instance()->GetActiveView()) { viewPane->ResizeViewport(renderWidth, renderHeight); } @@ -1008,6 +1004,11 @@ void CSequenceBatchRenderDialog::CaptureItemStart() } } + // create a new atom pipeline to capture the frames of the current sequence + m_atomOutputFrameCapture.CreatePipeline( + *TrackView::SceneFromGameEntityContext(), "TrackViewSequencePipeline", renderItem.resW, renderItem.resH); + UpdateAtomOutputFrameCaptureView(m_atomOutputFrameCapture, renderItem.resW, renderItem.resH); + GetIEditor()->GetMovieSystem()->EnableFixedStepForCapture(m_renderContext.captureOptions.timeStep); // The capturing doesn't actually start here. It just flags the warming-up and @@ -1205,7 +1206,7 @@ void CSequenceBatchRenderDialog::OnUpdateFinalize() m_renderContext.frameNumber = 0; m_renderContext.capturingFrame = false; - AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); + m_atomOutputFrameCapture.DestroyPipeline(*TrackView::SceneFromGameEntityContext()); // Check to see if there is more items to process bool done = m_renderContext.currentItemIndex == m_renderItems.size() - 1; @@ -1330,6 +1331,9 @@ void CSequenceBatchRenderDialog::OnKickIdle() // being captured, it's safe to move to the next step of the main update if (!capturing() || !m_renderContext.capturingFrame) { + const auto& renderItem = m_renderItems[m_renderContext.currentItemIndex]; + // update the view given the current camera transform and projection + UpdateAtomOutputFrameCaptureView(m_atomOutputFrameCapture, renderItem.resW, renderItem.resH); GetIEditor()->GetGameEngine()->Update(); // step update (original frame capture) } @@ -1341,14 +1345,24 @@ void CSequenceBatchRenderDialog::OnKickIdle() m_renderContext.captureOptions.folder.c_str(), fileName.c_str(), filePath, /*caseInsensitive=*/true, /*normalize=*/false); - bool capturedScreenshot = false; - AZ::Render::FrameCaptureRequestBus::BroadcastResult( - capturedScreenshot, &AZ::Render::FrameCaptureRequestBus::Events::CaptureScreenshot, filePath); + // track view callback after each frame is captured + const auto captureFinishedCallback = [this]() { + m_renderContext.capturingFrame = false; + GetIEditor()->GetMovieSystem()->EndCapture(); + GetIEditor()->GetMovieSystem()->ControlCapture(); + }; + + // readback result callback (how the image should be captured) + // currently only .dds + const auto readbackCallback = [filePath](const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) { + if (const AZ::Render::FrameCaptureOutputResult result = AZ::Render::DdsFrameCaptureOutput(filePath, readbackResult); + result.m_errorMessage.has_value()) + { + AZ_Printf("TrackView", "Frame capture failed: %s", result.m_errorMessage.value().c_str()); + } + }; - if (capturedScreenshot) - { - m_renderContext.capturingFrame = true; - } + m_renderContext.capturingFrame = m_atomOutputFrameCapture.BeginCapture(readbackCallback, captureFinishedCallback); } } else @@ -1358,14 +1372,6 @@ void CSequenceBatchRenderDialog::OnKickIdle() } } -void CSequenceBatchRenderDialog::OnCaptureFinished( - [[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) -{ - m_renderContext.capturingFrame = false; - GetIEditor()->GetMovieSystem()->EndCapture(); - GetIEditor()->GetMovieSystem()->ControlCapture(); -} - void CSequenceBatchRenderDialog::OnCancelRender() { if (m_renderContext.captureState == CaptureState::Capturing) diff --git a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.h b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.h index 0c0d79a1b9..7db1d5efb6 100644 --- a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.h +++ b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.h @@ -15,8 +15,9 @@ #pragma once +#include "AtomOutputFrameCapture.h" + #include -#include #include #include @@ -33,7 +34,6 @@ namespace Ui class CSequenceBatchRenderDialog : public QDialog , public IMovieListener - , private AZ::Render::FrameCaptureNotificationBus::Handler { public: CSequenceBatchRenderDialog(float fps, QWidget* pParent = nullptr); @@ -219,9 +219,6 @@ protected slots: bool GetResolutionFromCustomResText(const char* customResText, int& retCustomWidth, int& retCustomHeight) const; private: - // FrameCaptureNotificationBus overrides ... - void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override; - void CheckForEnableUpdateButton(); void stashActiveViewportResolution(); void UpdateSpinnerProgressMessage(const char* description); @@ -234,4 +231,6 @@ private: bool m_editorIdleProcessingEnabled; int32 CV_TrackViewRenderOutputCapturing; QScopedPointer m_prefixValidator; + + TrackView::AtomOutputFrameCapture m_atomOutputFrameCapture; }; diff --git a/Code/Sandbox/Editor/Util/FileUtil.cpp b/Code/Sandbox/Editor/Util/FileUtil.cpp index 8a726b5ead..fc5eca1952 100644 --- a/Code/Sandbox/Editor/Util/FileUtil.cpp +++ b/Code/Sandbox/Editor/Util/FileUtil.cpp @@ -26,6 +26,7 @@ // AzCore #include +#include // AzFramework #include @@ -751,10 +752,13 @@ bool CFileUtil::ScanDirectory(const QString& path, const QString& file, IFileUti void CFileUtil::ShowInExplorer([[maybe_unused]] const QString& path) { - const char* assetRoot; - EBUS_EVENT_RESULT(assetRoot, AzFramework::ApplicationRequests::Bus, GetAssetRoot); + AZStd::string assetRoot; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(assetRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } - QString fullpath(assetRoot); + auto fullpath = QString::fromUtf8(assetRoot.c_str(), aznumeric_cast(assetRoot.size())); AzQtComponents::ShowFileOnDesktop(fullpath); } diff --git a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp index 3e5214de5d..168e0a2e85 100644 --- a/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp +++ b/Code/Sandbox/Editor/WelcomeScreen/WelcomeScreenDialog.cpp @@ -25,6 +25,8 @@ #include #include +#include + // AzFramework #include @@ -93,7 +95,8 @@ WelcomeScreenDialog::WelcomeScreenDialog(QWidget* pParent) auto currentProjectButtonMenu = new QMenu(); ui->currentProjectButton->setMenu(currentProjectButtonMenu); - ui->currentProjectButton->setText(gEnv->pConsole->GetCVar("sys_game_folder")->GetString()); + auto projectName = AZ::Utils::GetProjectName(); + ui->currentProjectButton->setText(projectName.c_str()); ui->currentProjectButton->adjustSize(); ui->currentProjectButton->setMinimumWidth(ui->currentProjectButton->width() + 40); @@ -193,10 +196,9 @@ void WelcomeScreenDialog::SetRecentFileList(RecentFileList* pList) const char* engineRoot; EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - AZStd::string gamePathString; - AZ::StringFunc::Path::Join(engineRoot, gEnv->pConsole->GetCVar("sys_game_folder")->GetString(), gamePathString); - QString gamePath = QString(gamePathString.c_str()); + auto projectPath = AZ::Utils::GetProjectPath(); + QString gamePath{projectPath.c_str()}; Path::ConvertSlashToBackSlash(gamePath); gamePath = Path::ToUnixPath(gamePath.toLower()); gamePath = Path::AddSlash(gamePath); diff --git a/Code/Sandbox/Editor/editor_lib_files.cmake b/Code/Sandbox/Editor/editor_lib_files.cmake index af3aab17db..3ff96cd84c 100644 --- a/Code/Sandbox/Editor/editor_lib_files.cmake +++ b/Code/Sandbox/Editor/editor_lib_files.cmake @@ -807,6 +807,8 @@ set(FILES EnvironmentPanel.cpp EnvironmentPanel.h EnvironmentPanel.ui + TrackView/AtomOutputFrameCapture.cpp + TrackView/AtomOutputFrameCapture.h TrackView/TrackViewDialog.qrc TrackView/TrackViewDialog.cpp TrackView/TrackViewDialog.h diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp index 22fbee88f7..3aa3c1510b 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -458,7 +459,10 @@ void AssetCatalogModel::LoadDatabase() clear(); AZStd::string assetRootFolder; - EBUS_EVENT_RESULT(assetRootFolder, AzFramework::ApplicationRequests::Bus, GetAssetRoot); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(assetRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } m_rootPath = assetRootFolder.c_str(); auto startCB = []() {}; diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp index 434129767c..f735048ed0 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp @@ -24,9 +24,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -151,7 +153,12 @@ OutlinerWidget::OutlinerWidget(QWidget* pParent, Qt::WindowFlags flags) m_gui->setupUi(this); - QDir rootDir(AzQtComponents::FindEngineRootDir(qApp)); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + QDir rootDir = QString::fromUtf8(engineRootPath.c_str(), aznumeric_cast(engineRootPath.Native().size())); const auto pathOnDisk = rootDir.absoluteFilePath(QStringLiteral("Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/")); const auto qrcPath = QStringLiteral(":/EntityOutliner/"); @@ -159,7 +166,7 @@ OutlinerWidget::OutlinerWidget(QWidget* pParent, Qt::WindowFlags flags) // developers. The style will be loaded from a Qt Resource file if Editor is installed, but // developers with the file on disk will be able to modify the style and have it automatically // reloaded. - AzQtComponents::StyleManager::addSearchPaths("EntityOutliner", pathOnDisk, qrcPath); + AzQtComponents::StyleManager::addSearchPaths("EntityOutliner", pathOnDisk, qrcPath, engineRootPath); AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("EntityOutliner:EntityOutliner.qss")); m_listModel = aznew OutlinerListModel(this); diff --git a/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.cpp b/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.cpp index 507c90786e..8fdb341f92 100644 --- a/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.cpp +++ b/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.cpp @@ -24,12 +24,11 @@ namespace ProjectSettingsTool if (serialize) { serialize->Class() - ->Version(1) + ->Version(2) ->Field("project_name", &BaseSettings::m_projectName) ->Field("product_name", &BaseSettings::m_productName) ->Field("executable_name", &BaseSettings::m_executableName) - ->Field("sys_game_folder", &BaseSettings::m_sysGameFolder) - ->Field("sys_dll_game", &BaseSettings::m_sysDllGame) + ->Field("project_path", &BaseSettings::m_projectPath) ->Field("project_output_folder", &BaseSettings::m_projectOutputFolder) ->Field("code_folder", &BaseSettings::m_codeFolder) ; @@ -52,7 +51,7 @@ namespace ProjectSettingsTool ->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileName)) ->Attribute(Attributes::PropertyIdentfier, Identfiers::ExecutableName) ->Attribute(Attributes::LinkedProperty, Identfiers::IosExecutableName) - ->DataElement(Handlers::QValidatedLineEdit, &BaseSettings::m_sysGameFolder, "Game Folder", "The name of the project's folder.") + ->DataElement(Handlers::QValidatedLineEdit, &BaseSettings::m_projectPath, "Project Path", "The project root folder path .") ->Attribute(Attributes::FuncValidator, ConvertFunctorToVoid(&Validators::FileNameOrEmpty)) ->Attribute(Attributes::PropertyIdentfier, Identfiers::ProductName) ->Attribute(Attributes::LinkedProperty, Identfiers::ExecutableName) diff --git a/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.h b/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.h index fbdaf23ff4..27bf5594c7 100644 --- a/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.h +++ b/Code/Sandbox/Plugins/ProjectSettingsTool/PlatformSettings_Base.h @@ -26,7 +26,7 @@ namespace ProjectSettingsTool : m_projectName("") , m_productName("") , m_executableName("") - , m_sysGameFolder("") + , m_projectPath("") , m_sysDllGame("") , m_projectOutputFolder("") , m_codeFolder("") @@ -37,7 +37,7 @@ namespace ProjectSettingsTool AZStd::string m_projectName; AZStd::string m_productName; AZStd::string m_executableName; - AZStd::string m_sysGameFolder; + AZStd::string m_projectPath; AZStd::string m_sysDllGame; AZStd::string m_projectOutputFolder; AZStd::string m_codeFolder; diff --git a/Code/Sandbox/Plugins/ProjectSettingsTool/Utils.cpp b/Code/Sandbox/Plugins/ProjectSettingsTool/Utils.cpp index 5dc37f76b2..19ab26dc8d 100644 --- a/Code/Sandbox/Plugins/ProjectSettingsTool/Utils.cpp +++ b/Code/Sandbox/Plugins/ProjectSettingsTool/Utils.cpp @@ -16,6 +16,7 @@ #include #include +#include #include @@ -72,15 +73,15 @@ namespace template<> AZStd::string GetProjectName() { - AZStd::string projectRoot = GetAbsoluteProjectRoot(); - return projectRoot.substr(projectRoot.find_last_of('/') + 1); + auto projectName = AZ::Utils::GetProjectName(); + return AZStd::string{projectName.c_str()}; } template<> QString GetProjectName() { - QString projectRoot = GetAbsoluteProjectRoot(); - return projectRoot.mid(projectRoot.lastIndexOf('/')); + auto projectName = AZ::Utils::GetProjectName(); + return QString::fromUtf8(projectName.c_str(), aznumeric_cast(projectName.size())); } } diff --git a/Code/Tools/Android/ProjectBuilder/root.build.gradle.in b/Code/Tools/Android/ProjectBuilder/root.build.gradle.in index c6d4131dd2..782a1f26b5 100644 --- a/Code/Tools/Android/ProjectBuilder/root.build.gradle.in +++ b/Code/Tools/Android/ProjectBuilder/root.build.gradle.in @@ -35,7 +35,7 @@ subprojects { sdkVer = ${SDK_VER} ndkPlatformVer = ${NDK_PLATFORM_VER} buildToolsVer = '${SDK_BUILD_TOOL_VER}' - lyDevRoot = '${LY_DEV_ROOT}' + lyEngineRoot = '${LY_ENGINE_ROOT}' } } diff --git a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp index 4c5cf274a5..3c09f318de 100644 --- a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp +++ b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include #include #include @@ -38,18 +38,12 @@ #include #include #include +#include namespace AssetBundler { const char compareVariablePrefix = '$'; - GemInfo::GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath) - : m_gemName(name) - , m_relativeFilePath(relativeFilePath) - , m_absoluteFilePath(absoluteFilePath) - { - } - ApplicationManager::ApplicationManager(int* argc, char*** argv) : AzToolsFramework::ToolsApplication(argc, argv) { @@ -123,41 +117,21 @@ namespace AssetBundler } m_showVerboseOutput = ShouldPrintVerbose(parser); - ComputeEngineRoot(); - - const char* devRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(devRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - if (devRoot) - { - AZ_TracePrintf(AssetBundler::AppWindowNameVerbose, "Setting devroot alias to ( %s ).\n", devRoot); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@devroot@", devRoot); - } - - AZStd::string platformName(AzToolsFramework::AssetSystem::GetHostAssetPlatform()); - AZStd::string assetsAlias; - AZStd::string assetCatalogFile; + m_currentProjectName = AZStd::string_view{ AZ::Utils::GetProjectName() }; - AZ::Outcome result = AssetBundler::ComputeAssetAliasAndGameName(platformName, assetCatalogFile, assetsAlias, m_currentProjectName); - if (!result.IsSuccess()) + if (m_currentProjectName.empty()) { - AZ_Error(AppWindowName, false, result.GetError().c_str()); + AZ_Error(AppWindowName, false, "Unable to retrieve project name from the Settings Registry"); return false; } - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - // Gems - if (!AzToolsFramework::AssetUtils::GetGemsInfo(g_cachedEngineRoot, appRoot, m_currentProjectName.c_str(), m_gemInfoList)) + if (!AzFramework::GetGemsInfo(m_gemInfoList, *m_settingsRegistry)) { AZ_Error(AppWindowName, false, "Failed to read Gems for project: %s\n", m_currentProjectName.c_str()); return false; } - // @assets@ alias - AZ_TracePrintf(AssetBundler::AppWindowNameVerbose, "Setting asset alias to ( %s ).\n", assetsAlias.c_str()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetsAlias.c_str()); - m_platformCatalogManager = AZStd::make_unique(); InitArgValidationLists(); @@ -1304,13 +1278,18 @@ namespace AssetBundler AZ::Outcome ApplicationManager::ValidateInputArgs(const AzFramework::CommandLine* parser, const AZStd::vector& validArgList) { - for (const auto& paramInfo : parser->GetSwitchList()) + for (const auto& paramInfo : *parser) { + // Skip positional arguments + if (paramInfo.m_option.empty()) + { + continue; + } bool isValidArg = false; for (const auto& validArg : validArgList) { - if (AzFramework::StringFunc::Equal(paramInfo.first.c_str(), validArg)) + if (AzFramework::StringFunc::Equal(paramInfo.m_option, validArg)) { isValidArg = true; break; @@ -1319,7 +1298,7 @@ namespace AssetBundler if (!isValidArg) { - return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" is not a valid argument for this sub-command.", paramInfo.first.c_str())); + return AZ::Failure(AZStd::string::format("Invalid command: \"--%s\" is not a valid argument for this sub-command.", paramInfo.m_option.c_str())); } } @@ -1407,7 +1386,7 @@ namespace AssetBundler const char* appRoot = nullptr; AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(g_cachedEngineRoot, appRoot, m_currentProjectName.c_str()); + AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(GetEngineRoot(), appRoot, AZ::Utils::GetProjectPath().c_str()); auto platformsString = AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(platformFlags); AZ_TracePrintf(AppWindowName, "No platform specified, defaulting to platforms ( %s ).\n", platformsString.c_str()); @@ -1573,7 +1552,8 @@ namespace AssetBundler // Add Default Seed List Files if (params.m_addDefaultSeedListFiles) { - AZStd::unordered_map defaultSeedListFiles = GetDefaultSeedListFiles(AssetBundler::g_cachedEngineRoot, m_currentProjectName.c_str(), m_gemInfoList, params.m_platformFlags); + AZStd::unordered_map defaultSeedListFiles = GetDefaultSeedListFiles(GetEngineRoot(), AZ::Utils::GetProjectPath(), + m_gemInfoList, params.m_platformFlags); if (defaultSeedListFiles.empty()) { // Error has already been thrown @@ -1590,7 +1570,7 @@ namespace AssetBundler } } - AZStd::vector defaultSeeds = GetDefaultSeeds(AssetBundler::g_cachedEngineRoot, m_currentProjectName.c_str()); + AZStd::vector defaultSeeds = GetDefaultSeeds(GetEngineRoot(), AZ::Utils::GetProjectPath(), m_currentProjectName); if (defaultSeeds.empty()) { // Error has already been thrown @@ -1830,9 +1810,9 @@ namespace AssetBundler bool hasError = false; - for (const AZStd::string_view& platformName : AzFramework::PlatformHelper::GetPlatformsInterpreted(paramsOutcome.GetValue().m_platformFlags)) + for (AZStd::string platformName : AzFramework::PlatformHelper::GetPlatformsInterpreted(paramsOutcome.GetValue().m_platformFlags)) { - AZ_TracePrintf(AssetBundler::AppWindowName, "Running Compare command for the %.*s platform...\n", aznumeric_cast(platformName.size()), platformName.data()); + AZ_TracePrintf(AssetBundler::AppWindowName, "Running Compare command for the %s platform...\n", platformName.c_str()); ComparisonParams params = paramsOutcome.GetValue(); AddPlatformToAllComparisonParams(params, platformName); @@ -2687,7 +2667,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " \"path\" - This refers to an Engine-Root-Relative path.\n"); AZ_Printf(AppWindowName, " - Example: \"C:\\Lumberyard\\dev\\SamplesProject\\test.txt\" can be represented as \"SamplesProject\\test.txt\".\n"); AZ_Printf(AppWindowName, " \"cache path\" - This refers to a Cache-Relative path.\n"); - AZ_Printf(AppWindowName, " - Example: \"C:\\Lumberyard\\dev\\Cache\\SamplesProject\\pc\\samplesproject\\animations\\skeletonlist.xml\" is represented as \"animations\\skeletonlist.xml\".\n"); + AZ_Printf(AppWindowName, " - Example: \"C:\\Lumberyard\\dev\\SamplesProject\\Cache\\pc\\animations\\skeletonlist.xml\" is represented as \"animations\\skeletonlist.xml\".\n"); AZ_Printf(AppWindowName, "\n"); OutputHelpSeeds(); @@ -2718,7 +2698,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset.\n", ""); AZ_Printf(AppWindowName, " --%-25s-Removes the asset from the list of root assets for the specified platform.\n", RemoveSeedArg); AZ_Printf(AppWindowName, "%-31s---To completely remove the asset, it must be removed for all platforms.\n", ""); - AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"...\\dev\\Cache\\ProjectName\\platform\\projectname\\\"\n", ""); + AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"ProjectPath\\Cache\\platform\\\"\n", ""); AZ_Printf(AppWindowName, " --%-25s-Adds the specified platform to every Seed in the Seed List file, if possible.\n", AddPlatformToAllSeedsFlag); AZ_Printf(AppWindowName, " --%-25s-Removes the specified platform from every Seed in the Seed List file, if possible.\n", RemovePlatformFromAllSeedsFlag); AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Seed List file after performing any specified operations.\n", PrintFlag); @@ -2730,7 +2710,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-Allows input file path to still match if the file path case is different than on disk.\n", IgnoreFileCaseFlag); AZ_Printf(AppWindowName, " --%-25s-[Testing] Specifies the Asset Catalog file referenced by all Seed operations.\n", AssetCatalogFileArg); AZ_Printf(AppWindowName, "%-31s---Designed to be used in Unit Tests.\n", ""); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } void ApplicationManager::OutputHelpAssetLists() @@ -2740,7 +2720,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-Specifies the Asset List file to operate on by path. Must include (.%s) file extension.\n", AssetListFileArg, AssetSeedManager::GetAssetListFileExtension()); AZ_Printf(AppWindowName, " --%-25s-Specifies the Seed List file(s) that will be used as root(s) when generating this Asset List file.\n", SeedListFileArg); AZ_Printf(AppWindowName, " --%-25s-Specifies the Seed(s) to use as root(s) when generating this Asset List File.\n", AddSeedArg); - AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"...\\dev\\Cache\\ProjectName\\platform\\projectname\\\"\n", ""); + AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"ProjectPath\\Cache\\platform\\\"\n", ""); AZ_Printf(AppWindowName, " --%-25s-The specified files and all dependencies will be ignored when generating the Asset List file.\n", SkipArg); AZ_Printf(AppWindowName, "%-31s---Takes in a comma-separated list of either: cache paths to pre-processed assets, or wildcard patterns.\n", ""); AZ_Printf(AppWindowName, " --%-25s-Automatically include all default Seed List files in generated Asset List File.\n", AddDefaultSeedListFilesFlag); @@ -2754,7 +2734,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-Run all input commands, without saving to the specified Asset List file.\n", DryRunFlag); AZ_Printf(AppWindowName, " --%-25s-Generates a human-readable file that maps every entry in the Asset List file to the Seed that generated it.\n", GenerateDebugFileFlag); AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } void ApplicationManager::OutputHelpComparisonRules() @@ -2781,7 +2761,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-The Token name of the Comparison Step you wish to use as the second input of this Comparison Step.\n", ComparisonSecondInputArg); AZ_Printf(AppWindowName, "%-31s---Comparison Steps of the ( FilePattern ) type only accept one input Token, and cannot be used with this arg.\n", ""); AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Comparison Rules file after performing any specified operations.\n", PrintFlag); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } void ApplicationManager::OutputHelpCompare() @@ -2813,7 +2793,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, "%-31s---All input Asset List files must exist for all specified platforms\n", ""); AZ_Printf(AppWindowName, "%-31s---Defaults to all enabled platforms. Platforms can be changed by modifying AssetProcessorPlatformConfig.ini.\n", ""); AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } void ApplicationManager::OutputHelpBundleSettings() @@ -2829,7 +2809,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) referenced by all Bundle Settings operations.\n", PlatformArg); AZ_Printf(AppWindowName, "%-31s---Defaults to all enabled platforms. Platforms can be changed by modifying AssetProcessorPlatformConfig.ini.\n", ""); AZ_Printf(AppWindowName, " --%-25s-Outputs the contents of the Bundle Settings file after modifying any specified values.\n", PrintFlag); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } void ApplicationManager::OutputHelpBundles() @@ -2846,7 +2826,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-Specifies the platform(s) that will be referenced when generating Bundles.\n", PlatformArg); AZ_Printf(AppWindowName, "%-31s---If no platforms are specified, Bundles will be generated for all available platforms.\n", ""); AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } void ApplicationManager::OutputHelpBundleSeed() @@ -2854,7 +2834,7 @@ namespace AssetBundler using namespace AzToolsFramework; AZ_Printf(AppWindowName, "\n%-25s-Subcommand for generating bundles directly from seeds. Must provide either (--%s) or (--%s).\n", BundleSeedCommand, BundleSettingsFileArg, OutputBundlePathArg); AZ_Printf(AppWindowName, " --%-25s-Adds the asset to the list of root assets for the specified platform.\n", AddSeedArg); - AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"...\\dev\\Cache\\ProjectName\\platform\\projectname\\\"\n", ""); + AZ_Printf(AppWindowName, "%-31s---Takes in a cache path to a pre-processed asset. A cache path is a path relative to \"ProjectPath\\Cache\\platform\\\"\n", ""); AZ_Printf(AppWindowName, " --%-25s-Specifies the Bundle Settings file to operate on by path. Must include (.%s) file extension.\n", BundleSettingsFileArg, AssetBundleSettings::GetBundleSettingsFileExtension()); AZ_Printf(AppWindowName, " --%-25s-Sets the path where generated Bundles will be stored. Must include (.%s) file extension.\n", OutputBundlePathArg, AssetBundleSettings::GetBundleFileExtension()); AZ_Printf(AppWindowName, " --%-25s-Determines which version of Lumberyard Bundles to generate. Current version is (%i).\n", BundleVersionArg, AzFramework::AssetBundleManifest::CurrentBundleVersion); @@ -2865,7 +2845,7 @@ namespace AssetBundler AZ_Printf(AppWindowName, " --%-25s-Allow destructive overwrites of files. Include this arg in automation.\n", AllowOverwritesFlag); AZ_Printf(AppWindowName, " --%-25s-[Testing] Specifies the Asset Catalog file referenced by all Bundle operations.\n", AssetCatalogFileArg); AZ_Printf(AppWindowName, "%-31s---Designed to be used in Unit Tests.\n", ""); - AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootsrap.cfg's sys_game_folder.\n", ProjectArg); + AZ_Printf(AppWindowName, " --%-25s-Specifies the game project to use rather than the current default project set in bootstrap.cfg's project_path.\n", ProjectArg); } //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Code/Tools/AssetBundler/source/utils/applicationManager.h b/Code/Tools/AssetBundler/source/utils/applicationManager.h index 2c373df225..01f180a77a 100644 --- a/Code/Tools/AssetBundler/source/utils/applicationManager.h +++ b/Code/Tools/AssetBundler/source/utils/applicationManager.h @@ -185,7 +185,7 @@ namespace AssetBundler //////////////////////////////////////////////////////////////////////////////////////////// AZStd::string GetCurrentProjectName() { return m_currentProjectName; } - AZStd::vector GetGemInfoList() { return m_gemInfoList; } + AZStd::vector GetGemInfoList() { return m_gemInfoList; } protected: //////////////////////////////////////////////////////////////////////////////////////////// @@ -288,7 +288,7 @@ namespace AssetBundler AZStd::unique_ptr m_assetSeedManager; AZStd::unique_ptr m_platformCatalogManager; - AZStd::vector m_gemInfoList; + AZStd::vector m_gemInfoList; bool m_showVerboseOutput = false; AZStd::string m_currentProjectName; diff --git a/Code/Tools/AssetBundler/source/utils/utils.cpp b/Code/Tools/AssetBundler/source/utils/utils.cpp index 697d05aa97..d0c808a355 100644 --- a/Code/Tools/AssetBundler/source/utils/utils.cpp +++ b/Code/Tools/AssetBundler/source/utils/utils.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option") @@ -57,8 +58,8 @@ namespace AssetBundler const char* RemovePlatformFromAllSeedsFlag = "removePlatformFromSeeds"; const char* UpdateSeedPathArg = "updateSeedPath"; const char* RemoveSeedPathArg = "removeSeedPath"; - const char* DefaultProjectTemplatePath = "ProjectTemplates/DefaultTemplate/${ProjectName}"; - const char* ProjectName = "${ProjectName}"; + const char* DefaultProjectTemplatePath = "Templates/DefaultProject/Template"; + const char* ProjectName = "${Name}"; const char* DependenciesFileSuffix = "_Dependencies"; const char* DependenciesFileExtension = "xml"; @@ -107,8 +108,6 @@ namespace AssetBundler const char* AssetCatalogFilename = "assetcatalog.xml"; - char g_cachedEngineRoot[AZ_MAX_PATH_LEN]; - const char EngineDirectoryName[] = "Engine"; const char RestrictedDirectoryName[] = "restricted"; @@ -124,16 +123,15 @@ namespace AssetBundler const AZ::u32 PlatformFlags_RESTRICTED = aznumeric_cast(AzFramework::PlatformFlags::Platform_JASPER | AzFramework::PlatformFlags::Platform_PROVO | AzFramework::PlatformFlags::Platform_SALEM); void AddPlatformSeeds( - AZStd::string rootFolder, + const AZ::IO::Path& engineDirectory, const AZStd::string& rootFolderDisplayName, AZStd::unordered_map& defaultSeedLists, AzFramework::PlatformFlags platformFlags) { AZ::IO::FixedMaxPath engineRoot(GetEngineRoot()); - AZ::IO::FixedMaxPath engineRestrcitedRoot = engineRoot / RestrictedDirectoryName; + AZ::IO::FixedMaxPath engineRestrictedRoot = engineRoot / RestrictedDirectoryName; - AZ::IO::FixedMaxPath inputPath = AZ::IO::FixedMaxPath(rootFolder); - AZ::IO::FixedMaxPath engineLocalPath = inputPath.LexicallyRelative(engineRoot); + AZ::IO::FixedMaxPath engineLocalPath = AZ::IO::PathView(engineDirectory.LexicallyRelative(engineRoot)); AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); auto platformsIdxList = AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(platformFlags); @@ -146,11 +144,11 @@ namespace AssetBundler AZ::IO::FixedMaxPath platformDirectory; if (aznumeric_cast(platformFlag) & PlatformFlags_RESTRICTED) { - platformDirectory = engineRestrcitedRoot / platformDirName / engineLocalPath; + platformDirectory = engineRestrictedRoot / platformDirName / engineLocalPath; } else { - platformDirectory = inputPath / PlatformsDirectoryName / platformDirName; + platformDirectory = engineDirectory / PlatformsDirectoryName / platformDirName; } if (fileIO->Exists(platformDirectory.c_str())) @@ -174,7 +172,7 @@ namespace AssetBundler } void AddPlatformsDirectorySeeds( - const AZStd::string& rootFolder, + const AZ::IO::Path& engineDirectory, const AZStd::string& rootFolderDisplayName, AZStd::unordered_map& defaultSeedLists, AzFramework::PlatformFlags platformFlags) @@ -185,8 +183,7 @@ namespace AssetBundler // Check whether platforms directory exists inside the root, if yes than add // * All seed files from the platforms directory // * All platform specific seed files based on the platform flags specified. - AZStd::string platformsDirectory; - AzFramework::StringFunc::Path::Join(rootFolder.c_str(), PlatformsDirectoryName, platformsDirectory); + auto platformsDirectory = engineDirectory / PlatformsDirectoryName; if (fileIO->Exists(platformsDirectory.c_str())) { fileIO->FindFiles(platformsDirectory.c_str(), @@ -200,119 +197,19 @@ namespace AssetBundler }); } - AddPlatformSeeds(rootFolder, rootFolderDisplayName, defaultSeedLists, platformFlags); - } - } - - bool ComputeEngineRoot() - { - if (g_cachedEngineRoot[0]) - { - return true; + AddPlatformSeeds(engineDirectory, rootFolderDisplayName, defaultSeedLists, platformFlags); } - - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - if (!engineRoot) - { - AZ_Error(AssetBundler::AppWindowName, false, "Unable to locate engine root.\n"); - return false; - } - - azstrcpy(g_cachedEngineRoot, AZ_MAX_PATH_LEN, engineRoot); - return true; } - const char* GetEngineRoot() + AZ::IO::FixedMaxPath GetEngineRoot() { - if (!g_cachedEngineRoot[0]) + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - ComputeEngineRoot(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - return g_cachedEngineRoot; - } - - AZ::Outcome ComputeAssetAliasAndGameName(const AZStd::string& platformIdentifier, const AZStd::string& assetCatalogFile, AZStd::string& assetAlias, AZStd::string& gameName) - { - AZStd::string assetPath; - AZStd::string gameFolder; - if (!ComputeEngineRoot()) - { - return AZ::Failure(AZStd::string("Unable to compute engine root.\n")); - } - if (assetCatalogFile.empty()) - { - if (gameName.empty()) - { - bool checkPlatform = false; - bool result{}; - - auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName); - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - result = settingsRegistry->Get(gameFolder, gameFolderKey); - } - - if (!result) - { - return AZ::Failure(AZStd::string("Unable to locate game name in bootstrap.\n")); - } - - gameName = gameFolder; - } - else - { - gameFolder = gameName; - } - - // Appending Cache/%gamename%/%platform%/%gameName% to the engine root - bool success = AzFramework::StringFunc::Path::ConstructFull(g_cachedEngineRoot, "Cache", assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), gameFolder.c_str(), assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), platformIdentifier.c_str(), assetPath); - if (success) - { - AZStd::to_lower(gameFolder.begin(), gameFolder.end()); - success = AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), gameFolder.c_str(), assetPath); // game name is lowercase - } - - if (success) - { - assetAlias = assetPath; - } - } - else if (AzFramework::StringFunc::Path::GetFullPath(assetCatalogFile.c_str(), assetPath)) - { - AzFramework::StringFunc::Strip(assetPath, AZ_CORRECT_FILESYSTEM_SEPARATOR, false, false, true); - assetAlias = assetPath; - - // 3rd component from reverse should give us the correct case game name because the assetalias directory - // looks like ./Cache/%GameName%/%platform%/%gameName%/assetcatalog.xml - // GetComponent util method returns the component with the separator appended at the end - // therefore we need to strip the separator to get the game name string - gameFolder = AZ::IO::PathView(assetPath).ParentPath().ParentPath().Filename().Native(); - if (gameFolder.empty()) - { - return AZ::Failure(AZStd::string::format("Unable to retrieve game name from assetCatalog file (%s).\n", assetCatalogFile.c_str())); - } - - if (!AzFramework::StringFunc::Strip(gameFolder, AZ_CORRECT_FILESYSTEM_SEPARATOR, false, false, true)) - { - return AZ::Failure(AZStd::string::format("Unable to strip separator from game name (%s).\n", gameFolder.c_str())); - } - - if (!gameName.empty() && !AzFramework::StringFunc::Equal(gameFolder.c_str(), gameName.c_str())) - { - return AZ::Failure(AZStd::string::format("Game name retrieved from the assetCatalog file (%s) does not match the inputted game name (%s).\n", gameFolder.c_str(), gameName.c_str())); - } - else - { - gameName = gameFolder; - } - } - - return AZ::Success(); + return engineRootPath; } void AddPlatformIdentifier(AZStd::string& filePath, const AZStd::string& platformIdentifier) @@ -346,7 +243,8 @@ namespace AssetBundler return platformFlags; } - AZStd::unordered_map GetDefaultSeedListFiles(const char* root, const char* projectName, const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlag) + AZStd::unordered_map GetDefaultSeedListFiles(AZStd::string_view enginePath, AZStd::string_view projectPath, + const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlag) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "AZ::IO::FileIOBase must be ready for use.\n"); @@ -354,63 +252,65 @@ namespace AssetBundler // Add all seed list files of enabled gems for the given project AZStd::unordered_map defaultSeedLists = GetGemSeedListFilePathToGemNameMap(gemInfoList, platformFlag); + // Add the engine seed list file - AZStd::string engineDirectory; - AzFramework::StringFunc::Path::Join(root, EngineDirectoryName, engineDirectory); - AZStd::string absoluteEngineSeedFilePath; - AzFramework::StringFunc::Path::ConstructFull(engineDirectory.c_str(), EngineSeedFileName, AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteEngineSeedFilePath, true); + AZ::IO::Path engineDirectory = AZ::IO::Path(enginePath) / EngineDirectoryName; + auto absoluteEngineSeedFilePath = engineDirectory / EngineSeedFileName; + absoluteEngineSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension()); if (fileIO->Exists(absoluteEngineSeedFilePath.c_str())) { - defaultSeedLists[absoluteEngineSeedFilePath] = EngineDirectoryName; + defaultSeedLists[absoluteEngineSeedFilePath.Native()] = EngineDirectoryName; } // Add Seed Lists from the Platforms directory Internal::AddPlatformsDirectorySeeds(engineDirectory, EngineDirectoryName, defaultSeedLists, platformFlag); - - AZStd::string absoluteProjectDefaultSeedFilePath; - AzFramework::StringFunc::Path::ConstructFull(root, projectName, EngineSeedFileName, AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteProjectDefaultSeedFilePath, true); + auto absoluteProjectDefaultSeedFilePath = AZ::IO::Path(projectPath) / EngineSeedFileName; + absoluteProjectDefaultSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension()); if (fileIO->Exists(absoluteProjectDefaultSeedFilePath.c_str())) { - defaultSeedLists[absoluteProjectDefaultSeedFilePath] = projectName; + defaultSeedLists[absoluteProjectDefaultSeedFilePath.Native()] = projectPath; } return defaultSeedLists; } - AZStd::vector GetDefaultSeeds(const char* root, const char* projectName) + AZStd::vector GetDefaultSeeds(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName) { AZStd::vector defaultSeeds; - defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(root, projectName)); + defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(enginePath, projectPath, projectName)); return defaultSeeds; } - AZStd::string GetProjectDependenciesFile(const char* root, const char* projectName) + AZ::IO::Path GetProjectDependenciesFile(AZStd::string_view projectPath, AZStd::string_view projectName) { - AZStd::string projectDependenciesFilePath = AZStd::string::format("%s%s", projectName, DependenciesFileSuffix); - AzFramework::StringFunc::Path::ConstructFull(root, projectName, projectDependenciesFilePath.c_str(), DependenciesFileExtension, projectDependenciesFilePath, true); - return projectDependenciesFilePath; + AZ::IO::Path projectDependenciesFilePath = projectPath; + projectDependenciesFilePath /= AZStd::string::format("%.*s%s", aznumeric_cast(projectName.size()), projectName.data(), + DependenciesFileSuffix); + projectDependenciesFilePath.ReplaceExtension(DependenciesFileExtension); + return projectDependenciesFilePath.LexicallyNormal(); } - AZStd::string GetProjectDependenciesFileTemplate(const char* root) + AZ::IO::Path GetProjectDependenciesFileTemplate(AZStd::string_view engineRoot) { - AZStd::string projectDependenciesFileTemplate = ProjectName; - projectDependenciesFileTemplate += DependenciesFileSuffix; - AzFramework::StringFunc::Path::ConstructFull(root, DefaultProjectTemplatePath, projectDependenciesFileTemplate.c_str(), DependenciesFileExtension, projectDependenciesFileTemplate, true); - return projectDependenciesFileTemplate; + AZ::IO::Path projectDependenciesFileTemplate = engineRoot; + projectDependenciesFileTemplate /= DefaultProjectTemplatePath; + projectDependenciesFileTemplate /= AZStd::string::format("%s%s", ProjectName, DependenciesFileSuffix); + projectDependenciesFileTemplate.ReplaceExtension(DependenciesFileExtension); + return projectDependenciesFileTemplate.LexicallyNormal(); } - AZStd::string GetProjectDependenciesAssetPath(const char* root, const char* projectName) + AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName) { - AZStd::string projectDependenciesFile = AZStd::move(GetProjectDependenciesFile(root, projectName)); + AZ::IO::Path projectDependenciesFile = GetProjectDependenciesFile(projectPath, projectName); if (!AZ::IO::FileIOBase::GetInstance()->Exists(projectDependenciesFile.c_str())) { AZ_TracePrintf(AssetBundler::AppWindowName, "Project dependencies file %s doesn't exist.\n", projectDependenciesFile.c_str()); - AZStd::string projectDependenciesFileTemplate = AZStd::move(GetProjectDependenciesFileTemplate(root)); + AZ::IO::Path projectDependenciesFileTemplate = GetProjectDependenciesFileTemplate(enginePath); if (AZ::IO::FileIOBase::GetInstance()->Copy(projectDependenciesFileTemplate.c_str(), projectDependenciesFile.c_str())) { AZ_TracePrintf(AssetBundler::AppWindowName, "Copied project dependencies file template %s to the current project.\n", @@ -425,37 +325,39 @@ namespace AssetBundler } // Turn the absolute path into a cache-relative path - AZStd::string relativeProductPath; - AzFramework::StringFunc::Path::GetFullFileName(projectDependenciesFile.c_str(), relativeProductPath); - AZStd::to_lower(relativeProductPath.begin(), relativeProductPath.end()); + AZ::IO::Path relativeProductPath = projectDependenciesFile.Filename().Native(); + AZStd::to_lower(relativeProductPath.Native().begin(), relativeProductPath.Native().end()); return relativeProductPath; } - AZStd::unordered_map GetGemSeedListFilePathToGemNameMap(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags) + AZStd::unordered_map GetGemSeedListFilePathToGemNameMap(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags) { AZStd::unordered_map filePathToGemNameMap; - for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : gemInfoList) + for (const AzFramework::GemInfo& gemInfo : gemInfoList) { - AZ::IO::Path gemInfoAssetFilePath = gemInfo.m_absoluteFilePath; - gemInfoAssetFilePath /= gemInfo.GetGemAssetFolder(); - AZ::IO::Path absoluteGemSeedFilePath = gemInfoAssetFilePath / GemsSeedFileName; - absoluteGemSeedFilePath.ReplaceExtension(AZ::IO::PathView{ AzToolsFramework::AssetSeedManager::GetSeedFileExtension() }); - absoluteGemSeedFilePath = absoluteGemSeedFilePath.LexicallyNormal(); - - AZStd::string gemName = gemInfo.m_gemName + " Gem"; - if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteGemSeedFilePath.c_str())) + for (const AZ::IO::Path& gemAbsoluteSourcePath : gemInfo.m_absoluteSourcePaths) { - filePathToGemNameMap[absoluteGemSeedFilePath.Native()] = gemName; - } + AZ::IO::Path gemInfoAssetFilePath = gemAbsoluteSourcePath; + gemInfoAssetFilePath /= gemInfo.GetGemAssetFolder(); + AZ::IO::Path absoluteGemSeedFilePath = gemInfoAssetFilePath / GemsSeedFileName; + absoluteGemSeedFilePath.ReplaceExtension(AZ::IO::PathView{ AzToolsFramework::AssetSeedManager::GetSeedFileExtension() }); + absoluteGemSeedFilePath = absoluteGemSeedFilePath.LexicallyNormal(); + + AZStd::string gemName = gemInfo.m_gemName + " Gem"; + if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteGemSeedFilePath.c_str())) + { + filePathToGemNameMap[absoluteGemSeedFilePath.Native()] = gemName; + } - Internal::AddPlatformsDirectorySeeds(gemInfoAssetFilePath.Native(), gemName, filePathToGemNameMap, platformFlags); + Internal::AddPlatformsDirectorySeeds(gemInfoAssetFilePath.Native(), gemName, filePathToGemNameMap, platformFlags); + } } return filePathToGemNameMap; } - bool IsGemSeedFilePathValid(const char* root, AZStd::string seedAbsoluteFilePath, const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags) + bool IsGemSeedFilePathValid(AZStd::string_view engineRoot, AZStd::string seedAbsoluteFilePath, const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "AZ::IO::FileIOBase must be ready for use.\n"); @@ -465,9 +367,8 @@ namespace AssetBundler return false; } - AZ::IO::Path gemsFolder{ root }; + AZ::IO::Path gemsFolder{ engineRoot }; gemsFolder /= GemsDirectoryName; - gemsFolder /= GemsAssetsDirectoryName; gemsFolder = gemsFolder.LexicallyNormal(); if (!AzFramework::StringFunc::StartsWith(seedAbsoluteFilePath, gemsFolder.Native())) { @@ -476,36 +377,45 @@ namespace AssetBundler return true; } - for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : gemInfoList) + for (const AzFramework::GemInfo& gemInfo : gemInfoList) { - // We want to check the path before going through the effort of creating the default Seed List file map - if (!AzFramework::StringFunc::StartsWith(seedAbsoluteFilePath, gemInfo.m_absoluteFilePath)) + for (const AZ::IO::Path& gemAbsoluteSourcePath : gemInfo.m_absoluteSourcePaths) { - continue; - } + // We want to check the path before going through the effort of creating the default Seed List file map + if (!AzFramework::StringFunc::StartsWith(seedAbsoluteFilePath, gemAbsoluteSourcePath.Native())) + { + continue; + } - AZStd::unordered_map seeds = GetGemSeedListFilePathToGemNameMap({gemInfo}, platformFlags); + AZStd::unordered_map seeds = GetGemSeedListFilePathToGemNameMap({ gemInfo }, platformFlags); - if (seeds.find(seedAbsoluteFilePath) != seeds.end()) - { - return true; + if (seeds.find(seedAbsoluteFilePath) != seeds.end()) + { + return true; + } + // If we have not validated the input path yet, we need to keep looking, or we will return false negatives + // for Gems that have the same prefix in their name } - // If we have not validated the input path yet, we need to keep looking, or we will return false negatives - // for Gems that have the same prefix in their name } return false; } - AzFramework::PlatformFlags GetEnabledPlatformFlags(const char* root, const char* assetRoot, const char* gameName) + AzFramework::PlatformFlags GetEnabledPlatformFlags(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath) { - QStringList configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(root, assetRoot, gameName, true, true); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) + { + AZ_Error(AssetBundler::AppWindowName, false, "Settings Registry is not available, enabled platform flags cannot be queried"); + return AzFramework::PlatformFlags::Platform_NONE; + } - QStringList enabaledPlatformList = AzToolsFramework::AssetUtils::GetEnabledPlatforms(configFiles); + auto configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(engineRoot, assetRoot, projectPath, true, true, settingsRegistry); + auto enabledPlatformList = AzToolsFramework::AssetUtils::GetEnabledPlatforms(*settingsRegistry, configFiles); AzFramework::PlatformFlags platformFlags = AzFramework::PlatformFlags::Platform_NONE; - for (const QString& enabledPlatform : enabaledPlatformList) + for (const auto& enabledPlatform : enabledPlatformList) { - AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlag(enabledPlatform.toUtf8().data()); + AzFramework::PlatformFlags platformFlag = AzFramework::PlatformHelper::GetPlatformFlag(enabledPlatform); if (platformFlag != AzFramework::PlatformFlags::Platform_NONE) { @@ -513,7 +423,7 @@ namespace AssetBundler } else { - AZ_Warning(AssetBundler::AppWindowName, false, "Platform Helper is not aware of the platform (%s).\n ", enabledPlatform.toUtf8().data()); + AZ_Warning(AssetBundler::AppWindowName, false, "Platform Helper is not aware of the platform (%s).\n ", enabledPlatform.c_str()); } } @@ -535,68 +445,60 @@ namespace AssetBundler AZ::Outcome GetCurrentProjectName() { - AZStd::string gameName; - bool result{ false }; - auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName); - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + AZStd::string projectName{ AZStd::string_view(AZ::Utils::GetProjectName()) }; + if (!projectName.empty()) { - result = settingsRegistry->Get(gameName, gameFolderKey); - } - - if (result) - { - return AZ::Success(gameName); + return AZ::Success(projectName); } else { - return AZ::Failure(AZStd::string("Unable to locate current project name in bootstrap.cfg")); + return AZ::Failure(AZStd::string("Unable to obtain current project name from registry")); } } - AZ::Outcome GetProjectFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName) + AZ::Outcome GetProjectFolderPath() { - AZStd::string projectFolderPath; - bool success = AzFramework::StringFunc::Path::ConstructFull(engineRoot.c_str(), projectName.c_str(), projectFolderPath); - - if (success && AZ::IO::FileIOBase::GetInstance()->Exists(projectFolderPath.c_str())) + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) { - return AZ::Success(projectFolderPath); + return AZ::Success(AZ::IO::Path{ AZ::IO::PathView(projectPath) }); } else { - return AZ::Failure(AZStd::string::format( "Unable to locate the current Project folder: %s", projectName.c_str())); + return AZ::Failure(AZStd::string::format("Unable to obtain current project path from registry")); } } - AZ::Outcome GetProjectCacheFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName) + AZ::Outcome GetProjectCacheFolderPath() { - AZStd::string projectCacheFolderPath; + AZ::IO::Path projectCacheFolderPath; - bool success = AzFramework::StringFunc::Path::ConstructFull(engineRoot.c_str(), "Cache", projectCacheFolderPath); - if (!success || !AZ::IO::FileIOBase::GetInstance()->Exists(projectCacheFolderPath.c_str())) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry && settingsRegistry->Get(projectCacheFolderPath.Native(), + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) { - return AZ::Failure(AZStd::string::format( - "Unable to locate the Cache in the engine directory: %s. Please run the Lumberyard Asset Processor to generate a Cache and build assets.", - engineRoot.c_str())); + if (AZ::IO::FileIOBase::GetInstance()->Exists(projectCacheFolderPath.c_str())) + { + return AZ::Success(projectCacheFolderPath); + } } - success = AzFramework::StringFunc::Path::ConstructFull(projectCacheFolderPath.c_str(), projectName.c_str(), projectCacheFolderPath); - if (success && AZ::IO::FileIOBase::GetInstance()->Exists(projectCacheFolderPath.c_str())) - { - return AZ::Success(projectCacheFolderPath); - } - else - { - return AZ::Failure(AZStd::string::format( - "Unable to locate the current Project in the Cache folder: %s. Please run the Lumberyard Asset Processor to generate a Cache and build assets.", - projectName.c_str())); - } + return AZ::Failure(AZStd::string::format( + "Unable to locate the Project Cache path from Settings Registry at key %s." + " Please run the Lumberyard Asset Processor to generate a Cache and build assets.", + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)); } - AZ::Outcome GetPlatformNamesFromCacheFolder(const AZStd::string& projectCacheFolder, AZStd::vector& platformNames) + AZ::Outcome GetPlatformNamesFromCacheFolder(AZStd::vector& platformNames) { - QDir projectCacheDir(QString(projectCacheFolder.c_str())); + AZ::Outcome projectCacheRootFolder = GetProjectCacheFolderPath(); + if (!projectCacheRootFolder) + { + return AZ::Failure(projectCacheRootFolder.TakeError()); + } + + const AZStd::string& projectCacheRootPath = projectCacheRootFolder.GetValue().Native(); + QDir projectCacheDir(QString::fromUtf8(projectCacheRootPath.c_str(), aznumeric_cast(projectCacheRootPath.size()))); auto tempPlatformList = projectCacheDir.entryList(QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot); if (tempPlatformList.empty()) @@ -612,66 +514,33 @@ namespace AssetBundler return AZ::Success(); } - AZ::Outcome GetAssetCatalogFilePath(const char* pathToCacheFolder, const char* platformIdentifier, const char* projectName) + AZ::Outcome GetAssetCatalogFilePath() { - AZStd::string assetCatalogFilePath; - bool success = AzFramework::StringFunc::Path::ConstructFull(pathToCacheFolder, platformIdentifier, assetCatalogFilePath, true); - - if (!success) + AZ::IO::Path assetCatalogFilePath = GetPlatformSpecificCacheFolderPath(); + if (assetCatalogFilePath.empty()) { return AZ::Failure(AZStd::string::format( - "Unable to find platform folder %s in cache found at: %s. Please run the Lumberyard Asset Processor to generate platform-specific cache folders and build assets.", - platformIdentifier, - pathToCacheFolder)); - } - - // Project name is lower case in the platform-specific cache folder - AZStd::string lowerCaseProjectName = AZStd::string(projectName); - AZStd::to_lower(lowerCaseProjectName.begin(), lowerCaseProjectName.end()); - success = AzFramework::StringFunc::Path::ConstructFull(assetCatalogFilePath.c_str(), lowerCaseProjectName.c_str(), assetCatalogFilePath) - && AzFramework::StringFunc::Path::ConstructFull(assetCatalogFilePath.c_str(), AssetCatalogFilename, assetCatalogFilePath); - - if (!success) - { - return AZ::Failure(AZStd::string("Unable to find the asset catalog. Please run the Lumberyard Asset Processor to generate a Cache and build assets.")); + "Unable to retrieve cache platform path from Settings Registry at key: %s. Please run the Lumberyard Asset Processor to generate platform-specific cache folders and build assets.", + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)); } + assetCatalogFilePath /= AssetCatalogFilename; return AZ::Success(assetCatalogFilePath); } - AZStd::string GetPlatformSpecificCacheFolderPath(const AZStd::string& projectSpecificCacheFolderAbsolutePath, const AZStd::string& platform, const AZStd::string& projectName) + AZ::IO::Path GetPlatformSpecificCacheFolderPath() { - // C:/dev/Cache/ProjectName -> C:/dev/Cache/ProjectName/platform - AZStd::string platformSpecificCacheFolderPath; - AzFramework::StringFunc::Path::ConstructFull(projectSpecificCacheFolderAbsolutePath.c_str(), platform.c_str(), platformSpecificCacheFolderPath, true); - - // C:/dev/Cache/ProjectName/platform -> C:/dev/Cache/ProjectName/platform/projectname - AZStd::string lowerCaseProjectName = AZStd::string(projectName); - AZStd::to_lower(lowerCaseProjectName.begin(), lowerCaseProjectName.end()); - AzFramework::StringFunc::Path::ConstructFull(platformSpecificCacheFolderPath.c_str(), lowerCaseProjectName.c_str(), platformSpecificCacheFolderPath, true); - + AZ::IO::Path platformSpecificCacheFolderPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(platformSpecificCacheFolderPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder); + } return platformSpecificCacheFolderPath; } - AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath) - { - AZStd::string key(absoluteFilePath); - AzFramework::StringFunc::Path::Normalize(key); - AzFramework::StringFunc::Path::StripDrive(key); - return key; - } - - void ConvertToRelativePath(const AZStd::string& parentFolderPath, AZStd::string& absoluteFilePath) + void ConvertToRelativePath(AZStd::string_view parentFolderPath, AZStd::string& absoluteFilePath) { - // Qt and AZ return different Drive Letter formats, so strip them away before doing a comparison - AZStd::string parentFolderPathWithoutDrive(parentFolderPath); - AzFramework::StringFunc::Path::StripDrive(parentFolderPathWithoutDrive); - AzFramework::StringFunc::Path::Normalize(parentFolderPathWithoutDrive); - - AzFramework::StringFunc::Path::StripDrive(absoluteFilePath); - AzFramework::StringFunc::Path::Normalize(absoluteFilePath); - - AzFramework::StringFunc::Replace(absoluteFilePath, parentFolderPathWithoutDrive.c_str(), ""); + absoluteFilePath = AZ::IO::PathView(absoluteFilePath).LexicallyRelative(parentFolderPath).String(); } AZ::Outcome MakePath(const AZStd::string& path) diff --git a/Code/Tools/AssetBundler/source/utils/utils.h b/Code/Tools/AssetBundler/source/utils/utils.h index ea20d95d20..277338f372 100644 --- a/Code/Tools/AssetBundler/source/utils/utils.h +++ b/Code/Tools/AssetBundler/source/utils/utils.h @@ -120,20 +120,8 @@ namespace AssetBundler //////////////////////////////////////////////////////////////////////////////////////////// extern const char* AssetCatalogFilename; - extern char g_cachedEngineRoot[AZ_MAX_PATH_LEN]; static const size_t MaxErrorMessageLength = 4096; - //! This struct stores gem related information - struct GemInfo - { - AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0); - GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath); - GemInfo() = default; - AZStd::string m_gemName; - AZStd::string m_relativeFilePath; - AZStd::string m_absoluteFilePath; - }; - // The Warning Absorber is used to absorb warnings // One case that this is being used is during loading of the asset catalog. @@ -149,14 +137,8 @@ namespace AssetBundler bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override; }; - // computes the asset alias and game name either through the asset catalog file provided by the user or using the platform and game folder - AZ::Outcome ComputeAssetAliasAndGameName(const AZStd::string& platformIdentifier, const AZStd::string& assetCatalogFile, AZStd::string& assetAlias, AZStd::string& gameName); - - // Computes the engine root and cache it locally - bool ComputeEngineRoot(); - - // Retrurns the engine root - const char* GetEngineRoot(); + // Returns the engine root + AZ::IO::FixedMaxPath GetEngineRoot(); /** * Determines the name of the currently enabled game project @@ -166,58 +148,51 @@ namespace AssetBundler /** - * Constructs an absolute path to the project folder found at: dev/ProjectName - * @param engineRoot The absolute path of the dev/ folder - * @param projectName A project present in the dev/ folder + * Retrieve the project path from the Settings Registry * @return Absolute path of the Project Folder on success, error message on failure */ - AZ::Outcome GetProjectFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName); + AZ::Outcome GetProjectFolderPath(); /** - * Constructs an absolute path to the project-specific cache folder found at: dev/Cache/ProjectName - * @param engineRoot The absolute path of the dev/ folder - * @param projectName A project present in the dev/ folder + * Retrieve the project path from the Settings Registry * @return Absolute path of the project-specific cache folder on success, error message on failure */ - AZ::Outcome GetProjectCacheFolderPath(const AZStd::string& engineRoot, const AZStd::string& projectName); + AZ::Outcome GetProjectCacheFolderPath(); /** * Calculates the list of enabled platforms for the input project by reading the folder names inside the project-specific cache folder. - * If the Asset Processor has not been run yet, or has not been run since the enabled platform list inside AssetProcessorPlatformConfig.ini + * If the Asset Processor has not been run yet, or has not been run since the enabled platform list inside AssetProcessorPlatformConfig.setreg * was changed, the output of this function will be incorrect. * - * @param projectCacheFolder The directory of a project-specific cache folder: dev/Cache/ProjectName + * @param projectCacheFolder The directory of a project-specific cache folder: /ProjectPath/Cache * @param platformNames [out] The list of platforms enabled in the project * @return void on success, error message on failure */ - AZ::Outcome GetPlatformNamesFromCacheFolder(const AZStd::string& projectCacheFolder, AZStd::vector& platformNames); + AZ::Outcome GetPlatformNamesFromCacheFolder(AZStd::vector& platformNames); /** * Computes the absolute path to the Asset Catalog file for a specified project and platform. - * With platform set as "pc" and project as "ProjectName", the path will resemble: C:/dev/Cache/ProjectName/pc/projectname/assetcatalog.xml + * With platform set as "pc" and project as "ProjectName", the path will resemble: C:/ProjectPath/Cache/pc/assetcatalog.xml * - * @param pathToCacheFolder The absolute path to the Cache folder. ex: C:/dev/Cache + * @param pathToCacheFolder The absolute path to the Cache folder. ex: C:/ProjectPath/Cache * @param platformIdentifier The platform identifier of the desired Asset Catalog. Valid inputs can be found by reading the folder names - * found inside dev/Cache/ProjectName + * found inside ProjectPath/Cache * @param projectName The name of the project you want to search * @return Absolute Path to the Asset Catalog file on success, error message on failure */ - AZ::Outcome GetAssetCatalogFilePath(const char* pathToCacheFolder, const char* platformIdentifier, const char* projectName); + AZ::Outcome GetAssetCatalogFilePath(); /** * Computes the absolute path to the platform-specific Cache folder where product assets are stored. - * With platform set as "pc" and project as "ProjectName", the path will resemble: C:/dev/Cache/ProjectName/pc/projectname/ + * With platform set as "pc" the path will resemble: C:/ProjectPath/Cache/pc/projectname/ * - * @param projectSpecificCacheFolderAbsolutePath The absolute path to the Cache folder. Example: C:/dev/Cache/ProjectName + * @param projectSpecificCacheFolderAbsolutePath The absolute path to the Cache folder. Example: C:/ProjectPath/Cache * @param platform the platform of the desired cache location - * @param projectName The name of the current project * @return Absolute path to the platform-specific Cache folder where product assets are stored */ - AZStd::string GetPlatformSpecificCacheFolderPath(const AZStd::string& projectSpecificCacheFolderAbsolutePath, const AZStd::string& platform, const AZStd::string& projectName); - - AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath); + AZ::IO::Path GetPlatformSpecificCacheFolderPath(); - void ConvertToRelativePath(const AZStd::string& parentFolderPath, AZStd::string& absoluteFilePath); + void ConvertToRelativePath(AZStd::string_view parentFolderPath, AZStd::string& absoluteFilePath); AZ::Outcome MakePath(const AZStd::string& path); @@ -228,30 +203,31 @@ namespace AssetBundler AzFramework::PlatformFlags GetPlatformsOnDiskForPlatformSpecificFile(const AZStd::string& platformIndependentAbsolutePath); //! Returns a map of of all default Seed List files for the current game project. - AZStd::unordered_map GetDefaultSeedListFiles(const char* root, const char* projectName, const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); + AZStd::unordered_map GetDefaultSeedListFiles(AZStd::string_view enginePath, AZStd::string_view projectPath, + const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); //! Returns a vector of relative paths to Assets that should be included as default Seeds, but are not already in a Seed List file. - AZStd::vector GetDefaultSeeds(const char* root, const char* projectName); + AZStd::vector GetDefaultSeeds(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName); //! Returns the absolute path of {ProjectName}_Dependencies.xml - AZStd::string GetProjectDependenciesFile(const char* root, const char* projectName); + AZ::IO::Path GetProjectDependenciesFile(AZStd::string_view productPath, AZStd::string_view projectName); //! Returns the absolute path of the project dependencies file in the default project template - AZStd::string GetProjectDependenciesFileTemplate(const char* root); + AZ::IO::Path GetProjectDependenciesFileTemplate(AZStd::string_view enginePath); //! Creates the ProjectName_Dependencies.xml file if it does not exist, and adds returns the relative path to the asset in the Cache. - AZStd::string GetProjectDependenciesAssetPath(const char* root, const char* projectName); + AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName); //! Returns the map from gem seed list file path to gem name - AZStd::unordered_map GetGemSeedListFilePathToGemNameMap(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); + AZStd::unordered_map GetGemSeedListFilePathToGemNameMap(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); //! Given an absolute gem seed file path determines whether the file is valid for the current game project. //! This method is for validating gem seed list files only. - bool IsGemSeedFilePathValid(const char* root, AZStd::string seedAbsoluteFilePath, const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); + bool IsGemSeedFilePathValid(AZStd::string_view enginePath, AZStd::string seedAbsoluteFilePath, const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); //! Returns platformFlags of all enabled platforms by parsing all the asset processor config files. //! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param. - AzFramework::PlatformFlags GetEnabledPlatformFlags(const char* root, const char* assetRoot, const char* gameName); + AzFramework::PlatformFlags GetEnabledPlatformFlags(AZStd::string_view enginePath, AZStd::string_view assetRoot, AZStd::string_view projectPath); //! Filepath is a helper class that is used to find the absolute path of a file //! if the inputted file path is an absolute path than it does nothing diff --git a/Code/Tools/AssetBundler/tests/DummyProject/gems.json b/Code/Tools/AssetBundler/tests/DummyProject/gems.json deleted file mode 100644 index 5c3d4676f8..0000000000 --- a/Code/Tools/AssetBundler/tests/DummyProject/gems.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "GemListFormatVersion": 2, - "Gems": [ - { - "Path": "Gems/GemA", - "Uuid": "044a63ea67d04479aa5daf62ded9d9cb", - "Version": "0.1.0", - "_comment": "GemA" - }, - { - "Path": "Gems/GemB", - "Uuid": "07375b61b1a2424bb03088bbdf28b2c9", - "Version": "0.1.0", - "_comment": "GemB" - }, - { - "Path": "Gems/GemC", - "Uuid": "0945e21b7ae848ac80b4ec1f34c459cd", - "Version": "0.1.0", - "_comment": "GemC" - } - ] -} - - diff --git a/Code/Tools/AssetBundler/tests/UtilsTests.cpp b/Code/Tools/AssetBundler/tests/UtilsTests.cpp index edf3377edc..ffbab40eeb 100644 --- a/Code/Tools/AssetBundler/tests/UtilsTests.cpp +++ b/Code/Tools/AssetBundler/tests/UtilsTests.cpp @@ -51,7 +51,7 @@ namespace AssetBundler // AzFramework::ApplicationRequests::Bus::Handler interface void NormalizePath(AZStd::string& /*path*/) override {} void NormalizePathKeepCase(AZStd::string& /*path*/) override {} - void CalculateBranchTokenForAppRoot(AZStd::string& /*token*/) const override {} + void CalculateBranchTokenForEngineRoot(AZStd::string& /*token*/) const override {} const char* GetAppRoot() const override { diff --git a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp index 9c9de98ea5..4156a6790d 100644 --- a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp +++ b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp @@ -115,9 +115,9 @@ namespace AssetBundler settingsRegistry->Set(gemSourcePathKey, gemSourcePath.Native()); } - AzToolsFramework::AssetUtils::GetGemsInfo(m_data->m_testEngineRoot.c_str(), m_data->m_testEngineRoot.c_str(), DummyProjectName, m_data->m_applicationManager->m_gemInfoList); + AzFramework::GetGemsInfo(m_data->m_applicationManager->m_gemInfoList, *settingsRegistry); EXPECT_GE(m_data->m_applicationManager->m_gemInfoList.size(), 3); - for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : m_data->m_applicationManager->m_gemInfoList) + for (const AzFramework::GemInfo& gemInfo : m_data->m_applicationManager->m_gemInfoList) { gemsNameMap.erase(gemInfo.m_gemName); } diff --git a/Code/Tools/AssetBundler/tests/tests_main.cpp b/Code/Tools/AssetBundler/tests/tests_main.cpp index e5a1e69e3f..e1535bf0f5 100644 --- a/Code/Tools/AssetBundler/tests/tests_main.cpp +++ b/Code/Tools/AssetBundler/tests/tests_main.cpp @@ -128,7 +128,7 @@ namespace AssetBundler // underneath code assumes that we might be leaking the previous instance AZ::IO::FileIOBase::SetInstance(nullptr); AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO); - + AddGemData(m_data->m_testEngineRoot.c_str(), "GemA"); AddGemData(m_data->m_testEngineRoot.c_str(), "GemB"); @@ -169,20 +169,21 @@ namespace AssetBundler m_data->m_gemSeedFilePairList.emplace_back(absoluteGemSeedFilePath, seedFileExists); - m_data->m_gemInfoList.emplace_back(AzToolsFramework::AssetUtils::GemInfo(gemName, relativeGemPath.Native(), absoluteGemPath.Native(), AZ::Uuid::CreateRandom().ToString().c_str(), false, false)); - + m_data->m_gemInfoList.emplace_back(gemName); + m_data->m_gemInfoList.back().m_absoluteSourcePaths.push_back(absoluteGemPath.Native()); + AZ::IO::Path platformsDirectory = absoluteGemPath / "Assets" / PlatformsFolder; if (m_data->m_localFileIO->Exists(platformsDirectory.c_str())) { m_data->m_localFileIO->FindFiles(platformsDirectory.c_str(), AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(), [&](const char* fileName) - { - AZStd::string normalizedFilePath = fileName; - AzFramework::StringFunc::Path::Normalize(normalizedFilePath); - m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(normalizedFilePath, seedFileExists)); - return true; - }); + { + AZStd::string normalizedFilePath = fileName; + AzFramework::StringFunc::Path::Normalize(normalizedFilePath); + m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(normalizedFilePath, seedFileExists)); + return true; + }); } AZ::IO::Path iosDirectory = platformsDirectory / AzFramework::PlatformIOS; @@ -195,7 +196,7 @@ namespace AssetBundler if (result.IsSuccess()) { AZStd::list seedFiles = result.TakeValue(); - for(AZStd::string& seedFile : seedFiles) + for (AZStd::string& seedFile : seedFiles) { AZStd::string normalizedFilePath = seedFile; AzFramework::StringFunc::Path::Normalize(normalizedFilePath); @@ -207,7 +208,7 @@ namespace AssetBundler struct StaticData { - AZStd::vector m_gemInfoList; + AZStd::vector m_gemInfoList; AZStd::vector> m_gemSeedFilePairList; AZStd::unique_ptr m_application = {}; AZ::IO::FileIOBase* m_priorFileIO = nullptr; @@ -230,7 +231,8 @@ namespace AssetBundler TEST_F(AssetBundlerGemsUtilTest, GetDefaultSeedFiles_AllSeedFiles_Found) { // DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/ - auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), DummyProjectFolder, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC); + auto dummyProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder; + auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC); ASSERT_EQ(defaultSeedList.size(), 5); //adding one for the engine seed file and one for the project file // Validate whether both GemA and GemB seed file are present @@ -246,7 +248,8 @@ namespace AssetBundler TEST_F(AssetBundlerGemsUtilTest, GetDefaultSeedFilesForMultiplePlatforms_AllSeedFiles_Found) { // DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/ - auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), DummyProjectFolder, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS); + auto dummyProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder; + auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS); ASSERT_EQ(defaultSeedList.size(), 6); //adding one for the engine seed file and one for the project file @@ -264,135 +267,11 @@ namespace AssetBundler TEST_F(AssetBundlerGemsUtilTest, IsSeedFileValid_Ok) { - for (const auto& pair : m_data->m_gemSeedFilePairList) + for (const auto& pair : m_data->m_gemSeedFilePairList) { bool result = IsGemSeedFilePathValid(m_data->m_testEngineRoot.c_str(), pair.first, m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS); - EXPECT_EQ(result,pair.second); - } - } - - const char TestProject[] = "TestProject"; - const char TestProjectLowerCase[] = "testproject"; -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - const char TestRoot[] = "D:\\Dummy\\Test\\dev\\"; -#else - const char TestRoot[] = "/Dummy/Test/dev/"; -#endif - - class MockApplication - : public AzFramework::ApplicationRequests::Bus::Handler - { - public: - MockApplication() - { - // ensure the cached engine root from previous tests is cleared - // so the mock application behaves properly - g_cachedEngineRoot[0] = 0; - - if (AZ::SettingsRegistry::Get() == nullptr) - { - m_settingsRegistry = AZStd::make_unique(); - AZ::SettingsRegistry::Register(m_settingsRegistry.get()); - - auto gameProjectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "sys_game_folder"); - m_settingsRegistry->Set(gameProjectKey, TestProject); - } - AzFramework::ApplicationRequests::Bus::Handler::BusConnect(); + EXPECT_EQ(result, pair.second); } - ~MockApplication() - { - AzFramework::ApplicationRequests::Bus::Handler::BusDisconnect(); - if (m_settingsRegistry.get() == AZ::SettingsRegistry::Get()) - { - AZ::SettingsRegistry::Unregister(m_settingsRegistry.get()); - } - } - // AzFramework::ApplicationRequests::Bus::Handler interface - void NormalizePath(AZStd::string& /*path*/) override {}; - void NormalizePathKeepCase(AZStd::string& /*path*/) override {}; - void CalculateBranchTokenForAppRoot(AZStd::string& /*token*/) const override {}; - const char* GetEngineRoot() const { return TestRoot; } - - private: - AZStd::unique_ptr m_settingsRegistry; - }; - - class AssetBundlerPathUtilTest - : public UnitTest::ScopedAllocatorSetupFixture - { - public: - - void SetUp() override - { - UnitTest::ScopedAllocatorSetupFixture::SetUp(); - m_data = AZStd::make_unique(); - } - - void TearDown() override - { - m_data.reset(); - UnitTest::ScopedAllocatorSetupFixture::TearDown(); - } - - struct StaticData - { - MockApplication m_mockApplication; - }; - - AZStd::unique_ptr m_data; - }; - - - TEST_F(AssetBundlerPathUtilTest, ComputeAssetAliasAndGameName_AssetCatalogPathNotProvided_Valid) - { - AZStd::string platformIdentifier = "pc"; - AZStd::string assetCatalogFile; - AZStd::string assetAlias; - AZStd::string gameName; - EXPECT_TRUE(ComputeAssetAliasAndGameName(platformIdentifier, assetCatalogFile, assetAlias, gameName).IsSuccess()); - EXPECT_TRUE(gameName == TestProject); - - AZStd::string assetPath; - bool success = AzFramework::StringFunc::Path::ConstructFull(TestRoot, "Cache", assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), TestProject, assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), platformIdentifier.c_str(), assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), TestProjectLowerCase, assetPath); - EXPECT_EQ(assetAlias, assetPath); - } - - TEST_F(AssetBundlerPathUtilTest, ComputeAssetAliasAndGameName_AssetCatalogPathProvided_Valid) - { - AZStd::string platformIdentifier = "pc"; -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - AZStd::string assetCatalogFile = "D:\\Dummy\\Test\\dev\\Cache\\TestProject1\\pc\\testproject1\\assetcatalog.xml"; -#else - AZStd::string assetCatalogFile = "/Dummy/Test/dev/Cache/TestProject1/pc/testproject1/assetcatalog.xml"; -#endif - AZStd::string assetAlias; - AZStd::string gameName; - EXPECT_TRUE(ComputeAssetAliasAndGameName(platformIdentifier, assetCatalogFile, assetAlias, gameName).IsSuccess()); - EXPECT_EQ(gameName, "TestProject1"); - - AZStd::string assetPath; - bool success = AzFramework::StringFunc::Path::ConstructFull(TestRoot, "Cache", assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), "TestProject1", assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), platformIdentifier.c_str(), assetPath) && - AzFramework::StringFunc::Path::ConstructFull(assetPath.c_str(), "testproject1", assetPath); - EXPECT_EQ(assetAlias, assetPath); - } - - TEST_F(AssetBundlerPathUtilTest, ComputeAssetAliasAndGameName_GameNameMismatch_Failure) - { - AZStd::string platformIdentifier = "pc"; -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - AZStd::string assetCatalogFile = "D:\\Dummy\\Cache\\TestProject1\\pc\\testproject1\\assetcatalog.xml"; -#else - AZStd::string assetCatalogFile = "/Dummy/Cache/TestProject1/pc/testproject1/assetcatalog.xml"; -#endif - AZStd::string assetAlias; - AZStd::string gameName="SomeOtherGamename"; - EXPECT_FALSE(ComputeAssetAliasAndGameName(platformIdentifier, assetCatalogFile, assetAlias, gameName).IsSuccess()); } } diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp index 712386c200..411b9deabd 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -97,21 +98,6 @@ AssetBuilderApplication::AssetBuilderApplication(int* argc, char*** argv) AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( *settingsRegistry, AssetBuilder::GetBuildTargetName()); - // Override the /Amazon/AzCore/Bootstrap/sys_game_folder entry in the Settings Registry using the -gameName parameter - if (m_commandLine.GetNumSwitchValues("gameName") > 0) - { - const AZStd::string& gameFolderOverride = m_commandLine.GetSwitchValue("gameName", 0); - auto gameFolderCommandLineOverride = AZStd::string::format("--regset=%s/sys_game_folder=%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, - gameFolderOverride.c_str()); - - AZ::CommandLine::ParamContainer commandLineArgs; - m_commandLine.Dump(commandLineArgs); - commandLineArgs.emplace_back(gameFolderCommandLineOverride); - m_commandLine.Parse(commandLineArgs); - - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, m_commandLine, false); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry); - } AZ::Interface::Register(this); } @@ -123,7 +109,7 @@ AssetBuilderApplication::~AssetBuilderApplication() void AssetBuilderApplication::RegisterCoreComponents() { AzToolsFramework::ToolsApplication::RegisterCoreComponents(); - + RegisterComponentDescriptor(AssetBuilderComponent::CreateDescriptor()); RegisterComponentDescriptor(AssetProcessor::ToolsAssetCatalogComponent::CreateDescriptor()); } @@ -134,32 +120,8 @@ void AssetBuilderApplication::StartCommon(AZ::Entity* systemEntity) // Merge in the SettingsRegistry for the game being processed. This does not // necessarily correspond to the project name in the bootstrap.cfg since it - // the AssetBuilder supports overriding the gameName on the command line + // the AssetBuilder supports overriding the project-path on the command line AZ::SettingsRegistryInterface& registry = *AZ::SettingsRegistry::Get(); - AZ::SettingsRegistryInterface::FixedValueString gameName; - if (m_commandLine.GetNumSwitchValues("gameName") > 0) - { - gameName = AZStd::string_view(m_commandLine.GetSwitchValue("gameName", 0)); - } - - // Add the supplied gameName to the specialization key in the registry - if (!gameName.empty()) - { - auto gameNameSpecialization = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%.*s", - AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, aznumeric_cast(gameName.size()), gameName.data()); - registry.Set(gameNameSpecialization, true); - } - else - { - // Add the project name as a registry specialization - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - if (AZ::SettingsRegistryInterface::FixedValueString bootstrapGameName; registry.Get(bootstrapGameName, projectKey) && !bootstrapGameName.empty()) - { - registry.Set(AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, bootstrapGameName.c_str()), - true); - } - } // Retrieve specializations from the Settings Registry and ComponentApplication derived classes AZ::SettingsRegistryInterface::Specializations specializations; @@ -177,41 +139,25 @@ void AssetBuilderApplication::StartCommon(AZ::Entity* systemEntity) // the executable, we need to set the PATH environment variable. AZStd::string exeFolder; AZ::ComponentApplicationBus::BroadcastResult(exeFolder, &AZ::ComponentApplicationBus::Events::GetExecutableFolder); - + setenv("PATH", exeFolder.c_str(), 1); #endif // AZ_PLATFORM_MAC - AZStd::string gameRoot; - - if (m_commandLine.GetNumSwitchValues("gameRoot") > 0) - { - gameRoot = m_commandLine.GetSwitchValue("gameRoot", 0); - } - - if (gameRoot.empty()) + // Make sure a project path was set to settings registry and error/warn if not. + auto projectPath = AZ::Utils::GetProjectPath(); + if (projectPath.empty()) { if (IsInDebugMode()) { - if (!AZ::SettingsRegistry::Get()->Get(gameRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder)) - { - AZ_Error("AssetBuilder", false, "Unable to determine the game root automatically. " - "Make sure a default project has been set or provide a default option on the command line. (See -help for more info.)"); - return; - } + AZ_Error("AssetBuilder", false, "Unable to determine the project path automatically. " + "Make sure a default project path has been set or provide a --project-path option on the command line. " + "(See -help for more info.)"); + return; } else { - AZ_Printf(AssetBuilderSDK::InfoWindow, "gameRoot not specified on the command line, assuming current directory.\n"); - AZ_Printf(AssetBuilderSDK::InfoWindow, "gameRoot is best specified as the full path to the game's asset folder."); - } - } - - if (!gameRoot.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO) - { - fileIO->SetAlias("@devassets@", gameRoot.c_str()); + AZ_Printf(AssetBuilderSDK::InfoWindow, "project-path not specified on the command line, assuming current directory.\n"); + AZ_Printf(AssetBuilderSDK::InfoWindow, "project-path is best specified as the full path to the project's folder."); } } @@ -227,7 +173,7 @@ void AssetBuilderApplication::StartCommon(AZ::Entity* systemEntity) // Disable parallel dependency loads since the builders can't count on all other assets and their info being ready. // Specifically, asset builders can trigger asset loads during the building process. The ToolsAssetCatalog doesn't // implement the dependency APIs, so the asset loads will fail to load any dependent assets. - // + // // NOTE: The ToolsAssetCatalog could *potentially* implement the dependency APIs by querying the live Asset Processor instance, // but this will return incomplete dependency information based on the subset of assets that have already processed. // In theory, if the Asset Builder dependencies are set up correctly, the needed subset should always be processed first, @@ -242,61 +188,6 @@ bool AssetBuilderApplication::IsInDebugMode() const return AssetBuilderComponent::IsInDebugMode(m_commandLine); } -bool AssetBuilderApplication::GetOptionalAppRootArg(char destinationRootArgBuffer[], size_t destinationRootArgBufferSize) const -{ - // Only continue if the application received any arguments from the command line - if ((!this->m_argC) || (!this->m_argV)) - { - return false; - } - - int argc = this->m_argC; - char** argv = this->m_argV; - - // Search for the app root argument (-approot=) where is the app root path to set for the application - const static char* appRootArgPrefix = "-approot="; - size_t appRootArgPrefixLen = strlen(appRootArgPrefix); - - const char* appRootArg = nullptr; - for (int index = 0; index < argc; index++) - { - if (strncmp(appRootArgPrefix, argv[index], appRootArgPrefixLen) == 0) - { - appRootArg = &argv[index][appRootArgPrefixLen]; - break; - } - } - - if (appRootArg) - { - AZStd::string_view appRootArgView = appRootArg; - size_t afterStartQuotes = appRootArgView.find_first_not_of(R"(")"); - if (afterStartQuotes != AZStd::string_view::npos) - { - appRootArgView.remove_prefix(afterStartQuotes); - } - size_t beforeEndQuotes = appRootArgView.find_last_not_of(R"(")"); - if (beforeEndQuotes != AZStd::string_view::npos) - { - appRootArgView.remove_suffix(appRootArgView.size() - (beforeEndQuotes + 1)); - } - appRootArgView.copy(destinationRootArgBuffer, destinationRootArgBufferSize); - destinationRootArgBuffer[appRootArgView.size()] = '\0'; - - const char lastChar = destinationRootArgBuffer[strlen(destinationRootArgBuffer) - 1]; - bool needsTrailingPathDelim = (lastChar != AZ_CORRECT_FILESYSTEM_SEPARATOR) && (lastChar != AZ_WRONG_FILESYSTEM_SEPARATOR); - if (needsTrailingPathDelim) - { - azstrncat(destinationRootArgBuffer, destinationRootArgBufferSize, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING, 1); - } - return true; - } - else - { - return false; - } -} - void AssetBuilderApplication::InitializeBuilderComponents() { CreateAndAddEntityFromComponentTags(AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder }), "AssetBuilders Entity"); diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.h b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.h index 4f3b4d40f2..535ac56305 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.h +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.h @@ -45,8 +45,6 @@ public: bool IsInDebugMode() const; - bool GetOptionalAppRootArg(char destinationRootArgBuffer[], size_t destinationRootArgBufferSize) const; - void InitializeBuilderComponents() override; private: diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp index d44a149562..155f44f803 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp @@ -19,13 +19,15 @@ #include #include #include -#include #include +#include +#include +#include #include #include #include -#include #include +#include #include #include #include @@ -40,8 +42,8 @@ // Command-line parameter options: static const char* const s_paramHelp = "help"; // Print help information. static const char* const s_paramTask = "task"; // Task to run. -static const char* const s_paramGameName = "gamename"; // Name of the current project. -static const char* const s_paramGameCache = "gamecache"; // Full path to the project cache folder. +static const char* const s_paramProjectName = "project-name"; // Name of the current project. +static const char* const s_paramProjectCacheRoot = "project-cache-path"; // Full path to the project cache folder. static const char* const s_paramModule = "module"; // For resident mode, the path to the builder dll folder, otherwise the full path to a single builder dll to use. static const char* const s_paramPort = "port"; // Optional, port number to use to connect to the AP. static const char* const s_paramIp = "remoteip"; // optional, IP address to use to connect to the AP @@ -63,6 +65,78 @@ static const char* const s_taskDebug = "debug"; // runs a one shot job in a fake static const char* const s_taskDebugCreate = "debug_create"; // runs a one shot job in a fake environment for a specified file. static const char* const s_taskDebugProcess = "debug_process"; // runs a one shot job in a fake environment for a specified file. +//! Scoped Setters for the SettingsRegistry to its previous value on destruction +struct ScopedSettingsRegistrySetter +{ + using SettingsRegistrySetterTypes = AZStd::variant; + using SettingsRegistryGetterTypes = AZStd::variant; + + ScopedSettingsRegistrySetter(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view jsonPointer, + SettingsRegistrySetterTypes newValue) + : m_settingsRegistry(settingsRegistry) + , m_jsonPointer(jsonPointer) + { + AZStd::string oldValue; + if (m_settingsRegistry.Get(oldValue, jsonPointer)) + { + m_oldValue = AZStd::move(oldValue); + } + + AZStd::visit([this](auto&& value) {m_settingsRegistry.Set(m_jsonPointer, AZStd::move(value)); }, AZStd::move(newValue)); + } + + ~ScopedSettingsRegistrySetter() + { + // Reset the old value within the Settings Registry if it was set + // Or remove it if not + if (m_oldValue) + { + AZStd::visit([this](auto&& value) {m_settingsRegistry.Set(m_jsonPointer, AZStd::move(value)); }, AZStd::move(*m_oldValue)); + } + else + { + m_settingsRegistry.Remove(m_jsonPointer); + } + } + AZ::SettingsRegistryInterface& m_settingsRegistry; + AZStd::string_view m_jsonPointer; + AZStd::optional m_oldValue; +}; + +//! FileIO classes which resets the set key to its previous value on destruction +struct ScopedAliasSetter +{ + ScopedAliasSetter(AZ::IO::FileIOBase& fileIoBase, const char* alias, + const char* newValue) + : m_fileIoBase(fileIoBase) + , m_alias(alias) + { + + if (const char* oldValue = m_fileIoBase.GetAlias(m_alias); oldValue != nullptr) + { + m_oldValue = oldValue; + } + + m_fileIoBase.SetAlias(alias, newValue); + } + + ~ScopedAliasSetter() + { + // Reset the old alias if it was set or clear it if not + if (m_oldValue) + { + m_fileIoBase.SetAlias(m_alias, m_oldValue->c_str()); + } + else + { + m_fileIoBase.ClearAlias(m_alias); + } + } + AZ::IO::FileIOBase& m_fileIoBase; + const char* m_alias; + AZStd::optional m_oldValue; +}; + ////////////////////////////////////////////////////////////////////////// void AssetBuilderComponent::PrintHelp() @@ -71,8 +145,8 @@ void AssetBuilderComponent::PrintHelp() AZ_TracePrintf("Help", "The following command line options are available for the AssetBuilder.\n"); AZ_TracePrintf("Help", "%s - Print help information.\n", s_paramHelp); AZ_TracePrintf("Help", "%s - Task to run.\n", s_paramTask); - AZ_TracePrintf("Help", "%s - Name of the current project.\n", s_paramGameName); - AZ_TracePrintf("Help", "%s - Full path to the project cache folder.\n", s_paramGameCache); + AZ_TracePrintf("Help", "%s - Name of the current project.\n", s_paramProjectName); + AZ_TracePrintf("Help", "%s - Full path to the project cache folder.\n", s_paramProjectCacheRoot); AZ_TracePrintf("Help", "%s - For resident mode, the path to the builder dll folder, otherwise the full path to a single builder dll to use.\n", s_paramModule); AZ_TracePrintf("Help", "%s - Optional, port number to use to connect to the AP.\n", s_paramPort); AZ_TracePrintf("Help", "%s - UUID string that identifies the builder. Only used for resident mode when the AP directly starts up the AssetBuilder.\n", s_paramId); @@ -106,6 +180,7 @@ bool AssetBuilderComponent::IsInDebugMode(const AzFramework::CommandLine& comman return false; } + void AssetBuilderComponent::Activate() { BuilderBus::Handler::BusConnect(); @@ -168,17 +243,12 @@ bool AssetBuilderComponent::Run() } bool isDebugTask = (task == s_taskDebug || task == s_taskDebugCreate || task == s_taskDebugProcess); - if (!GetParameter(s_paramGameName, m_gameName, !isDebugTask)) + if (!GetParameter(s_paramProjectName, m_gameName, !isDebugTask)) { - auto gameNameKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName); - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - settingsRegistry->Get(m_gameName, gameNameKey); - } + m_gameName = AZ::Utils::GetProjectName(); } - if (!GetParameter(s_paramGameCache, m_gameCache, !isDebugTask)) + if (!GetParameter(s_paramProjectCacheRoot, m_gameCache, !isDebugTask)) { if (!isDebugTask) { @@ -283,7 +353,7 @@ bool AssetBuilderComponent::ConnectToAssetProcessor() //the asset builder may have been given an optional project name to use AZStd::string overrideProjectName; - if (GetParameter(s_paramGameName, overrideProjectName, false)) + if (GetParameter(s_paramProjectName, overrideProjectName, false)) { connectionSettings.m_projectName = overrideProjectName; } @@ -380,21 +450,15 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea return false; } } - AzFramework::StringFunc::Path::Normalize(debugFile); + AZ::StringFunc::Path::Normalize(debugFile); - if (!GetParameter(s_paramGameCache, m_gameCache, false)) + if (!GetParameter(s_paramProjectCacheRoot, m_gameCache, false)) { if (m_gameCache.empty()) { - // Setup the cache path - AZStd::string assetRoot; - AzFramework::ApplicationRequests::Bus::BroadcastResult(assetRoot, &AzFramework::ApplicationRequests::GetAssetRoot); - if (!assetRoot.empty()) - { - AZStd::string tempString = AZStd::string::format("Cache/%s", m_gameName.c_str()); - AzFramework::StringFunc::Path::Join(assetRoot.c_str(), tempString.c_str(), m_gameCache); - } - else + // Query the project cache root path from the Settings Registry + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (!settingsRegistry || !settingsRegistry->Get(m_gameCache, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) { m_gameCache = "."; } @@ -415,7 +479,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea AZStd::string module; if (GetParameter(s_paramModule, module, false)) { - AzFramework::StringFunc::Path::GetFullPath(module.c_str(), binDir); + AZ::StringFunc::Path::GetFullPath(module.c_str(), binDir); if (!LoadBuilder(module)) { AZ_Error("AssetBuilder", false, "Failed to load module '%s'.", module.c_str()); @@ -432,7 +496,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea return false; } - AzFramework::StringFunc::Path::Join(executableFolder, "Builders", binDir); + AZ::StringFunc::Path::Join(executableFolder, "Builders", binDir); if (!LoadBuilders(binDir)) { @@ -445,11 +509,11 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea if (!GetParameter(s_paramOutput, baseTempDirPath, false)) { AZStd::string fileName; - AzFramework::StringFunc::Path::GetFullFileName(debugFile.c_str(), fileName); + AZ::StringFunc::Path::GetFullFileName(debugFile.c_str(), fileName); AZStd::replace(fileName.begin(), fileName.end(), '.', '_'); - AzFramework::StringFunc::Path::Join(binDir.c_str(), "Debug", baseTempDirPath); - AzFramework::StringFunc::Path::Join(baseTempDirPath.c_str(), fileName.c_str(), baseTempDirPath); + AZ::StringFunc::Path::Join(binDir.c_str(), "Debug", baseTempDirPath); + AZ::StringFunc::Path::Join(baseTempDirPath.c_str(), fileName.c_str(), baseTempDirPath); } // Default tags for the debug task are "tools" and "debug" @@ -489,7 +553,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Debugging builder '%s'.\n", builder->m_name.c_str()); AZStd::string tempDirPath; - AzFramework::StringFunc::Path::Join(baseTempDirPath.c_str(), builder->m_name.c_str(), tempDirPath); + AZ::StringFunc::Path::Join(baseTempDirPath.c_str(), builder->m_name.c_str(), tempDirPath); AZStd::vector enabledDebugPlatformInfos = { @@ -502,7 +566,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea if (runCreateJobs) { AZStd::string createJobsTempDirPath; - AzFramework::StringFunc::Path::Join(tempDirPath.c_str(), "CreateJobs", createJobsTempDirPath); + AZ::StringFunc::Path::Join(tempDirPath.c_str(), "CreateJobs", createJobsTempDirPath); AZ::IO::Result fileResult = fileIO->CreatePath(createJobsTempDirPath.c_str()); if (!fileResult) { @@ -520,7 +584,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea builder->m_createJobFunction(createRequest, createResponse); AZStd::string responseFile; - AzFramework::StringFunc::Path::Join(createJobsTempDirPath.c_str(), "CreateJobsResponse.xml", responseFile); + AZ::StringFunc::Path::Join(createJobsTempDirPath.c_str(), "CreateJobsResponse.xml", responseFile); if (!AZ::Utils::SaveObjectToFile(responseFile, AZ::DataStream::ST_XML, &createResponse)) { AZ_Error("AssetBuilder", false, "Failed to serialize response to file: %s", responseFile.c_str()); @@ -538,7 +602,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea if (runProcessJob) { AZStd::string processJobTempDirPath; - AzFramework::StringFunc::Path::Join(tempDirPath.c_str(), "ProcessJobs", processJobTempDirPath); + AZ::StringFunc::Path::Join(tempDirPath.c_str(), "ProcessJobs", processJobTempDirPath); AZ::IO::Result fileResult = fileIO->CreatePath(processJobTempDirPath.c_str()); if (!fileResult) { @@ -555,7 +619,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea processRequest.m_sourceFile = info.m_relativePath; processRequest.m_platformInfo = enabledDebugPlatformInfo; processRequest.m_sourceFileUUID = info.m_assetId.m_guid; - AzFramework::StringFunc::AssetDatabasePath::Join(processRequest.m_watchFolder.c_str(), processRequest.m_sourceFile.c_str(), processRequest.m_fullPath); + AZ::StringFunc::AssetDatabasePath::Join(processRequest.m_watchFolder.c_str(), processRequest.m_sourceFile.c_str(), processRequest.m_fullPath); processRequest.m_tempDirPath = processJobTempDirPath; processRequest.m_jobId = 0; processRequest.m_builderGuid = builder->m_busId; @@ -585,7 +649,7 @@ bool AssetBuilderComponent::RunDebugTask(AZStd::string&& debugFile, bool runCrea ProcessJob(builder->m_processJobFunction, processRequest, processResponse); AZStd::string responseFile; - AzFramework::StringFunc::Path::Join(processJobTempDirPath.c_str(), + AZ::StringFunc::Path::Join(processJobTempDirPath.c_str(), AZStd::string::format("%zu_%s", i, AssetBuilderSDK::s_processJobResponseFileName).c_str(), responseFile); if (!AZ::Utils::SaveObjectToFile(responseFile, AZ::DataStream::ST_XML, &processResponse)) { @@ -619,36 +683,39 @@ void AssetBuilderComponent::ProcessJob(const AssetBuilderSDK::ProcessJobFunction auto ioBase = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(ioBase != nullptr, "AZ::IO::FileIOBase must be ready for use."); - // Save out the prior paths. - const char* priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); - AZStd::string priorAssets = priorAlias ? priorAlias : AZStd::string(); - - priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@root@"); - AZStd::string priorRoot = priorAlias ? priorAlias : AZStd::string(); - - priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@log@"); - AZStd::string priorLog = priorAlias ? priorAlias : AZStd::string(); - - // The game name needs to be lower case within the cache area itself. - AZStd::string gameName = m_gameName; - AZStd::to_lower(gameName.begin(), gameName.end()); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ_Assert(settingsRegistry != nullptr, "SettingsRegistry must be ready for use in the AssetBuilder."); // The root path is the cache plus the platform name. AZ::IO::FixedMaxPath newRoot(m_gameCache); - newRoot /= request.m_platformInfo.m_identifier; + // Check if the platform identifier is a valid "asset platform" + // If so, use it, other wise use the OS default platform as a fail safe + // This is to make sure the "debug platform" isn't added as a path segment + // the Cache Root folder + if (AzFramework::PlatformHelper::GetPlatformIdFromName(request.m_platformInfo.m_identifier) != AzFramework::PlatformId::Invalid) + { + newRoot /= request.m_platformInfo.m_identifier; + } + else + { + newRoot /= AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); + } // The asset path is root and the lower case game name. - AZ::IO::FixedMaxPath newAssets = newRoot / gameName; - - // The log path is the asset - AZ::IO::FixedMaxPath newLog = newRoot / "user" / "log"; + AZ::IO::FixedMaxPath newAssets = newRoot; // Now set the paths and run the job. - ioBase->SetAlias("@assets@", newAssets.c_str()); - ioBase->SetAlias("@root@", newRoot.c_str()); - ioBase->SetAlias("@log@", newLog.c_str()); - - job(request, outResponse); + { + // Save out the prior paths. + ScopedAliasSetter assetAliasScope(*ioBase, "@assets@", newAssets.c_str()); + ScopedAliasSetter rootAliasScope(*ioBase, "@root@", newRoot.c_str()); + ScopedAliasSetter projectplatformCacheAliasScope(*ioBase, "@projectplatformcache@", newRoot.c_str()); + ScopedSettingsRegistrySetter cacheRootFolderScope(*settingsRegistry, + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder, newRoot.Native()); + + // Invoke the Process Job function + job(request, outResponse); + } // The asset building ProcessJob method might read any number of source files while processing the asset. // Ensure that any exclusive file handle locks caused by this are cleared so that other AssetBuilder processes @@ -656,37 +723,6 @@ void AssetBuilderComponent::ProcessJob(const AssetBuilderSDK::ProcessJobFunction // This needs to occur after the ProcessJob call, but before the file aliases get cleared. FlushFileStreamerCache(); - // Clean up the paths. - // Restore previous @assets@ alias - if (priorAssets.empty()) - { - ioBase->ClearAlias("@assets"); - } - else - { - ioBase->SetAlias("@assets@", priorAssets.c_str()); - } - - // Restore previous @root@ alias - if (priorRoot.empty()) - { - ioBase->ClearAlias("@root@"); - } - else - { - ioBase->SetAlias("@root@", priorRoot.c_str()); - } - - // Restore previous @log@ alias - if (priorLog.empty()) - { - ioBase->ClearAlias("@log@"); - } - else - { - ioBase->SetAlias("@log@", priorLog.c_str()); - } - UpdateResultCode(request, outResponse); } @@ -707,8 +743,8 @@ bool AssetBuilderComponent::RunOneShotTask(const AZStd::string& task) return false; } - AzFramework::StringFunc::Path::Normalize(inputFilePath); - AzFramework::StringFunc::Path::Normalize(outputFilePath); + AZ::StringFunc::Path::Normalize(inputFilePath); + AZ::StringFunc::Path::Normalize(outputFilePath); if (task == s_taskRegisterBuilder) { return HandleRegisterBuilder(inputFilePath, outputFilePath); @@ -1021,7 +1057,11 @@ bool AssetBuilderComponent::GetParameter(const char* paramName, AZStd::string& o const AzFramework::CommandLine* commandLine = nullptr; AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine); - outValue = commandLine->GetSwitchValue(paramName, 0); + size_t optionCount = commandLine->GetNumSwitchValues(paramName); + if (optionCount > 0) + { + outValue = commandLine->GetSwitchValue(paramName, optionCount - 1); + } if (outValue.empty()) { diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.h b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.h index f3a1ce080e..8f3e695eb2 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.h +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.h @@ -165,5 +165,6 @@ protected: AZStd::unique_ptr m_queuedJob; AZStd::string m_gameName; + AZStd::string m_projectPath; AZStd::string m_gameCache; }; diff --git a/Code/Tools/AssetProcessor/AssetBuilder/Tests/AssetBuilderApplicationTests.cpp b/Code/Tools/AssetProcessor/AssetBuilder/Tests/AssetBuilderApplicationTests.cpp index a7098647e2..f2a01ba10d 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/Tests/AssetBuilderApplicationTests.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/Tests/AssetBuilderApplicationTests.cpp @@ -26,62 +26,6 @@ namespace AssetBuilder using AssetBuilderAppTest = AllocatorsFixture; - TEST_F(AssetBuilderAppTest, GetAppRootArg_AssetBuilderAppNoArgs_NoExtraction) - { - AssetBuilderApplication app(nullptr, nullptr); - - char appRootBuffer[AZ_MAX_PATH_LEN]; - ASSERT_FALSE(app.GetOptionalAppRootArg(appRootBuffer, AZ_MAX_PATH_LEN)); - } - - TEST_F(AssetBuilderAppTest, GetAppRootArg_AssetBuilderAppQuotedAppRoot_Success) - { - #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - const char* appRootArg = R"str(-approot="C:\path\to\app\root\")str"; - const char* expectedResult = R"str(C:\path\to\app\root\)str"; - #else - const char* appRootArg = R"str(-approot="/path/to/app/root")str"; - const char* expectedResult = R"str(/path/to/app/root/)str"; - #endif - - const char* argArray[] = { - appRootArg - }; - int argc = AZ_ARRAY_SIZE(argArray); - char** argv = const_cast(argArray); // this is unfortunately necessary to get around osx's strict non-const string literal stance - - AssetBuilderApplication app(&argc, &argv); - - char appRootBuffer[AZ_MAX_PATH_LEN] = { 0 }; - - ASSERT_TRUE(app.GetOptionalAppRootArg(appRootBuffer, AZ_ARRAY_SIZE(appRootBuffer))); - ASSERT_STREQ(appRootBuffer, expectedResult); - } - - TEST_F(AssetBuilderAppTest, GetAppRootArg_AssetBuilderAppNoQuotedAppRoot_Success) - { - #if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - const char* appRootArg = R"str(-approot=C:\path\to\app\root\)str"; - const char* expectedResult = R"str(C:\path\to\app\root\)str"; - #else - const char* appRootArg = R"str(-approot=/path/to/app/root)str"; - const char* expectedResult = R"str(/path/to/app/root/)str"; - #endif - - const char* argArray[] = { - appRootArg - }; - int argc = AZ_ARRAY_SIZE(argArray); - char** argv = const_cast(argArray); // this is unfortunately necessary to get around osx's strict non-const string literal stance - - AssetBuilderApplication app(&argc, &argv); - - char appRootBuffer[AZ_MAX_PATH_LEN] = { 0 }; - - ASSERT_TRUE(app.GetOptionalAppRootArg(appRootBuffer, AZ_ARRAY_SIZE(appRootBuffer))); - ASSERT_STREQ(appRootBuffer, expectedResult); - } - TEST_F(AssetBuilderAppTest, AssetBuilder_EditorScriptingComponents_Exists) { AssetBuilderApplication app(nullptr, nullptr); diff --git a/Code/Tools/AssetProcessor/AssetBuilder/main.cpp b/Code/Tools/AssetProcessor/AssetBuilder/main.cpp index 3b85d8203e..4cd64316d0 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/main.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/main.cpp @@ -20,13 +20,7 @@ int main(int argc, char** argv) traceMessageHook.EnableTraceContext(true); AZ::Debug::Trace::HandleExceptions(true); - // Perform an additional check for an override app root argument, and set it in the startup params if appropriate - char destinationRootArgBuffer[AZ_MAX_PATH_LEN]; AZ::ComponentApplication::StartupParameters startupParams; - if (app.GetOptionalAppRootArg(destinationRootArgBuffer, AZ_MAX_PATH_LEN)) - { - startupParams.m_appRootOverride = destinationRootArgBuffer; - } startupParams.m_loadDynamicModules = false; app.Start(AzFramework::Application::Descriptor(), startupParams); diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp index f3f1e22adc..7a119dc739 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp @@ -494,8 +494,8 @@ namespace AssetBuilderSDK } #endif // defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT) - PlatformInfo::PlatformInfo(const char* identifier, const AZStd::unordered_set& tags) - : m_identifier(identifier) + PlatformInfo::PlatformInfo(AZStd::string identifier, const AZStd::unordered_set& tags) + : m_identifier(AZStd::move(identifier)) , m_tags(tags) { } diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h index 15c3d3f777..d090b16703 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h @@ -185,7 +185,7 @@ namespace AssetBuilderSDK }; AZStd::string m_pattern; - PatternType m_type; + PatternType m_type{}; AssetBuilderPattern() = default; AssetBuilderPattern(const AssetBuilderPattern& src) = default; @@ -221,8 +221,8 @@ namespace AssetBuilderSDK AssetBuilderSDK::AssetBuilderPattern m_pattern; RegexType m_regex; AZStd::string m_errorString; - bool m_isRegex; - bool m_isValid; + bool m_isRegex{}; + bool m_isValid{}; }; //!Information that builders will send to the assetprocessor @@ -503,7 +503,7 @@ namespace AssetBuilderSDK AZStd::unordered_set m_tags; ///< The tags like "console" or "tools" on that platform PlatformInfo() = default; - PlatformInfo(const char* identifier, const AZStd::unordered_set& tags); + PlatformInfo(AZStd::string identifier, const AZStd::unordered_set& tags); bool operator==(const PlatformInfo& other); ///! utility function. It just searches the set for you: diff --git a/Code/Tools/AssetProcessor/CMakeLists.txt b/Code/Tools/AssetProcessor/CMakeLists.txt index 14fc2c0d3b..1fbb5045d7 100644 --- a/Code/Tools/AssetProcessor/CMakeLists.txt +++ b/Code/Tools/AssetProcessor/CMakeLists.txt @@ -176,6 +176,71 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) VALUES LY_CMAKE_BINARY_DIR="${CMAKE_BINARY_DIR}" ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/config_broken_badplatform/AssetProcessorPlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/config_broken_badplatform + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/config_broken_noscans/AssetProcessorPlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/config_broken_noscans + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/config_broken_recognizers/AssetProcessorPlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/config_broken_recognizers + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/config_broken_noplatform/AssetProcessorPlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/config_broken_noplatform + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/config_regular/AssetProcessorPlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/config_regular + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/config_regular_platform_scanfolder + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/EmptyDummyProject/AssetProcessorGamePlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/EmptyDummyProject + ) + ly_add_target_files( + TARGETS + AssetProcessor.Tests + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testdata/DummyProject/AssetProcessorGamePlatformConfig.ini + OUTPUT_SUBDIRECTORY + testdata/DummyProject + ) + # Have the AssetProcessorTest use the LY_CMAKE_TARGET define of AssetProcessorBatch for the purpose # of looking up the generated cmake build dependencies settings registry .setreg file # It is tied to the UnitTestRunner.cpp file diff --git a/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake b/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake index 19b11d0206..257f044ffd 100644 --- a/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake +++ b/Code/Tools/AssetProcessor/assetprocessor_test_files.cmake @@ -10,7 +10,6 @@ # set(FILES - testdata/unittests.qrc testdata/config_broken_badplatform/AssetProcessorPlatformConfig.ini testdata/config_broken_noplatform/AssetProcessorPlatformConfig.ini testdata/config_broken_noscans/AssetProcessorPlatformConfig.ini diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp index aad2255ed3..538c3dc441 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp @@ -12,11 +12,12 @@ #include "native/AssetManager/AssetCatalog.h" +#include #include #include -#include #include #include +#include #include #include "PathDependencyManager.h" @@ -45,14 +46,12 @@ namespace AssetProcessor m_absoluteDevFolderPath[0] = 0; m_absoluteDevGameFolderPath[0] = 0; - AZStd::string appRoot; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, appRoot.c_str()); - - AZStd::string gameFolderPath; - AzFramework::StringFunc::Path::Join(appRoot.c_str(), AssetUtilities::ComputeGameName().toUtf8().constData(), gameFolderPath); - azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, gameFolderPath.c_str()); + AZStd::string engineRoot; + AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, engineRoot.c_str()); + AZStd::string gameFolderPath{AssetUtilities::ComputeProjectPath().toUtf8().constData()}; + azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, gameFolderPath.c_str()); AssetUtilities::ComputeProjectCacheRoot(m_cacheRootDir); @@ -340,9 +339,13 @@ namespace AssetProcessor } else { + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::SettingsRegistryInterface::FixedValueString cacheRootFolder; + settingsRegistry->Get(cacheRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + QString tempRegistryFile = QString("%1/%2").arg(workSpace).arg("assetcatalog.xml.tmp"); - QString platformGameDir = QString("%1/%2/").arg(m_cacheRoot.absoluteFilePath(platform)).arg(AssetUtilities::ComputeGameName().toLower()); - QString actualRegistryFile = QString("%1%2").arg(platformGameDir).arg("assetcatalog.xml"); + QString platformCacheDir = QString::fromUtf8(cacheRootFolder.c_str(), aznumeric_cast(cacheRootFolder.size())); + QString actualRegistryFile = QString("%1/%2").arg(platformCacheDir).arg("assetcatalog.xml"); AZ_TracePrintf(AssetProcessor::DebugChannel, "Creating asset catalog: %s --> %s\n", tempRegistryFile.toUtf8().constData(), actualRegistryFile.toUtf8().constData()); AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; @@ -352,12 +355,12 @@ namespace AssetProcessor AZ::IO::FileIOBase::GetInstance()->Close(fileHandle); // Make sure that the destination folder of the registry file exists - QDir registryDir(platformGameDir); + QDir registryDir(platformCacheDir); if (!registryDir.exists()) { QString absPath = registryDir.absolutePath(); bool makeDirResult = AZ::IO::SystemFile::CreateDir(absPath.toUtf8().constData()); - AZ_Warning(AssetProcessor::ConsoleChannel, makeDirResult, "Failed create folder %s", platformGameDir.toUtf8().constData()); + AZ_Warning(AssetProcessor::ConsoleChannel, makeDirResult, "Failed create folder %s", platformCacheDir.toUtf8().constData()); } // if we succeeded in doing this, then use "rename" to move the file over the previous copy. @@ -488,9 +491,7 @@ namespace AssetProcessor AZ::Data::AssetId assetId(combined.m_sourceGuid, combined.m_subID); // relative file path is gotten by removing the platform and game from the product name - QString relativeProductPath = combined.m_productName.c_str(); - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // remove PLATFORM and an extra slash - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // remove GAMENAME and an extra slash + QString relativeProductPath = AssetUtilities::StripAssetPlatform(combined.m_productName); QString fullProductPath = m_cacheRoot.absoluteFilePath(combined.m_productName.c_str()); AZ::Data::AssetInfo info; @@ -1133,31 +1134,17 @@ namespace AssetProcessor return assetInfo; } - bool ConvertDatabaseProductPathToProductFileName(QString dbPath, QString& productFileName) + bool ConvertDatabaseProductPathToProductFilename(AZStd::string_view dbPath, QString& productFileName) { - QString gameName = AssetUtilities::ComputeGameName(); - bool result = false; - int gameNameIndex = dbPath.indexOf(gameName, 0, Qt::CaseInsensitive); - if (gameNameIndex != -1) - { - //we will now remove the gameName and the native separator to get the assetId - dbPath.remove(0, gameNameIndex + gameName.length() + 1); // adding one for the native separator also - result = true; - } - else + // Always strip the leading directory from the product path + // The leading directory can be either an asset platform path or a subfolder + AZ::StringFunc::TokenizeNext(dbPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR); + if (!dbPath.empty()) { - //we will just remove the platform and the native separator to get the assetId - int separatorIndex = dbPath.indexOf("/"); - if (separatorIndex != -1) - { - dbPath.remove(0, separatorIndex + 1); // adding one for the native separator - result = true; - } + productFileName = QString::fromUtf8(dbPath.data(), aznumeric_cast(dbPath.size())); + return true; } - - productFileName = dbPath; - - return result; + return false; } void AssetCatalog::ProcessGetRelativeProductPathFromFullSourceOrProductPathRequest(const AZStd::string& fullPath, AZStd::string& relativeProductPath) @@ -1166,7 +1153,7 @@ namespace AssetProcessor QString normalizedSourceOrProductPath = AssetUtilities::NormalizeFilePath(sourceOrProductPath); QString productFileName; - int resultCode = 0; + bool resultCode = false; QDir inputPath(normalizedSourceOrProductPath); AZ_TracePrintf(AssetProcessor::DebugChannel, "ProcessGetRelativeProductPath: %s...\n", sourceOrProductPath.toUtf8().constData()); @@ -1175,7 +1162,7 @@ namespace AssetProcessor { //if the path coming in is already a relative path,we just send it back productFileName = sourceOrProductPath; - resultCode = 1; + resultCode = true; } else { @@ -1196,7 +1183,7 @@ namespace AssetProcessor // Now after removing the cache root,normalizedInputAssetPath can either be $Platform/$Game/xxx/yyy or something like $Platform/zzz // and the corresponding assetId have to be either xxx/yyy or zzz - resultCode = ConvertDatabaseProductPathToProductFileName(normalizedSourceOrProductPath, productFileName); + resultCode = ConvertDatabaseProductPathToProductFilename(normalizedSourceOrProductPath.toUtf8().data(), productFileName); } else { @@ -1224,12 +1211,12 @@ namespace AssetProcessor if (m_db->GetProductsBySourceName(relativeName, products)) { - resultCode = ConvertDatabaseProductPathToProductFileName(products[0].m_productName.c_str(), productFileName); + resultCode = ConvertDatabaseProductPathToProductFilename(products[0].m_productName, productFileName); } else { productFileName = relativeName; - resultCode = 1; + resultCode = true; } } } @@ -1242,7 +1229,6 @@ namespace AssetProcessor } relativeProductPath = productFileName.toUtf8().data(); - } void AssetCatalog::ProcessGetFullSourcePathFromRelativeProductPathRequest(const AZStd::string& relPath, AZStd::string& fullSourcePath) diff --git a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp index ca6cc1c28d..40ff212768 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp @@ -30,7 +30,7 @@ namespace AssetProcessor PathDependencyManager::PathDependencyManager(AZStd::shared_ptr stateData, PlatformConfiguration* platformConfig) : m_stateData(stateData), m_platformConfig(platformConfig) { - + } void PathDependencyManager::SaveUnresolvedDependenciesToDatabase(AssetBuilderSDK::ProductPathDependencySet& unresolvedDependencies, const AzToolsFramework::AssetDatabase::ProductDatabaseEntry& productEntry, const AZStd::string& platform) @@ -55,7 +55,7 @@ namespace AssetProcessor // other problems. This string says that something went wrong in this function. AZStd::string("INVALID_PATH"), dependencyType); - + AZStd::string path = AssetUtilities::NormalizeFilePath(unresolvedPathDep.m_dependencyPath.c_str()).toUtf8().constData(); bool isExactDependency = IsExactDependency(path); @@ -81,7 +81,7 @@ namespace AssetProcessor dependencyContainer.push_back(placeholderDependency); } - if(!m_stateData->UpdateProductDependencies(dependencyContainer)) + if (!m_stateData->UpdateProductDependencies(dependencyContainer)) { AZ_Error(AssetProcessor::ConsoleChannel, false, "Failed to save unresolved dependencies to database for product %d (%s)", productEntry.m_productID, productEntry.m_productName.c_str()); @@ -111,8 +111,8 @@ namespace AssetProcessor const DependencyProductMap& excludedPathDependencyIds = handleProductDependencies ? exclusionMaps.m_productPathDependencyIds : exclusionMaps.m_sourcePathDependencyIds; const DependencyProductMap& excludedWildcardPathDependencyIds = handleProductDependencies ? exclusionMaps.m_wildcardProductPathDependencyIds : exclusionMaps.m_wildcardSourcePathDependencyIds; - // strip path of /// - AZStd::string strippedPath = handleProductDependencies ? StripPlatformAndProject(assetName) : sourceEntry.m_sourceName; + // strip asset platform from path + AZStd::string strippedPath = handleProductDependencies ? AssetUtilities::StripAssetPlatform(assetName).toUtf8().constData() : sourceEntry.m_sourceName; SanitizeForDatabase(strippedPath); auto unresolvedIter = excludedPathDependencyIds.find(ExcludedDependenciesSymbol + strippedPath); @@ -137,13 +137,6 @@ namespace AssetProcessor } } - AZStd::string PathDependencyManager::StripPlatformAndProject(AZStd::string_view productName) - { - auto nextSlash = productName.find('/'); // platform/ - nextSlash = productName.find('/', nextSlash + 1) + 1; // project/ - return productName.substr(nextSlash, productName.size() - nextSlash); - } - PathDependencyManager::DependencyProductMap& PathDependencyManager::SelectMap(MapSet& mapSet, bool wildcard, AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry::DependencyType type) { const bool isSource = type == AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry::DependencyType::ProductDep_SourceFile; @@ -193,7 +186,7 @@ namespace AssetProcessor void PathDependencyManager::NotifyResolvedDependencies(const AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer& dependencyContainer) const { - if(!m_dependencyResolvedCallback) + if (!m_dependencyResolvedCallback) { return; } @@ -226,7 +219,7 @@ namespace AssetProcessor const bool isExactDependency = IsExactDependency(productDependencyDatabaseEntry.m_unresolvedPath); AZ::s64 dependencyId = isExactDependency ? productDependencyDatabaseEntry.m_productDependencyID : AzToolsFramework::AssetDatabase::InvalidEntryId; - if(isSourceDependency && !isExactDependency && matchedPath == sourceNameWithScanFolder) + if (isSourceDependency && !isExactDependency && matchedPath == sourceNameWithScanFolder) { // Since we did a search for the source 2 different ways, filter one out // Scanfolder-prefixes are only for exact dependencies @@ -239,14 +232,14 @@ namespace AssetProcessor AZStd::vector> exclusions; // bool = is exact dependency GetMatchedExclusions(sourceEntry, matchedProduct, exclusions, productDependencyDatabaseEntry.m_dependencyType, exclusionMaps); - if(!exclusions.empty()) + if (!exclusions.empty()) { bool isExclusionForThisProduct = false; bool isExclusionExact = false; for (const auto& exclusionPair : exclusions) { - if(exclusionPair.first.m_productId == productDependencyDatabaseEntry.m_productPK && exclusionPair.first.m_platform == productDependencyDatabaseEntry.m_platform) + if (exclusionPair.first.m_productId == productDependencyDatabaseEntry.m_productPK && exclusionPair.first.m_platform == productDependencyDatabaseEntry.m_platform) { isExclusionExact = exclusionPair.second; isExclusionForThisProduct = true; @@ -254,7 +247,7 @@ namespace AssetProcessor } } - if(isExclusionForThisProduct) + if (isExclusionForThisProduct) { if (isExactDependency && isExclusionExact) { @@ -314,8 +307,8 @@ namespace AssetProcessor { const AZStd::string& productName = productEntry.m_productName; - // strip path of /// - AZStd::string strippedPath = StripPlatformAndProject(productName); + // strip path of the / + AZStd::string strippedPath = AssetUtilities::StripAssetPlatform(productName).toUtf8().constData(); SanitizeForDatabase(strippedPath); searchPaths.push_back(strippedPath); @@ -347,7 +340,7 @@ namespace AssetProcessor AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer matchedProducts; // Figure out the list of products to work with, for a source match, use all the products, otherwise just use the matched products - if(isSourceDependency) + if (isSourceDependency) { matchedProducts = products; } @@ -357,11 +350,11 @@ namespace AssetProcessor { const AZStd::string& productName = productEntry.m_productName; - // strip path of /// - AZStd::string strippedPath = StripPlatformAndProject(productName); + // strip path of the leading asset platform / + AZStd::string strippedPath = AssetUtilities::StripAssetPlatform(productName).toUtf8().constData(); SanitizeForDatabase(strippedPath); - if(strippedPath == matchedPath) + if (strippedPath == matchedPath) { matchedProducts.push_back(productEntry); } @@ -373,7 +366,7 @@ namespace AssetProcessor } // Save everything to the db - if(!m_stateData->UpdateProductDependencies(dependencyContainer)) + if (!m_stateData->UpdateProductDependencies(dependencyContainer)) { AZ_Error("PathDependencyManager", false, "Failed to update product dependencies"); } @@ -386,7 +379,7 @@ namespace AssetProcessor void CleanupPathDependency(AssetBuilderSDK::ProductPathDependency& pathDependency) { - if(pathDependency.m_dependencyType == AssetBuilderSDK::ProductPathDependencyType::SourceFile) + if (pathDependency.m_dependencyType == AssetBuilderSDK::ProductPathDependencyType::SourceFile) { // Nothing to cleanup if the dependency type was already pointing at source. return; @@ -411,7 +404,7 @@ namespace AssetProcessor { const AZ::Data::ProductDependencyInfo::ProductDependencyFlags productDependencyFlags = AZ::Data::ProductDependencyInfo::CreateFlags(AZ::Data::AssetLoadBehavior::NoLoad); - const QString gameName = AssetUtilities::ComputeGameName(); + AZStd::vector excludedDeps; // Check the path dependency set and find any conflict (include and exclude the same path dependency) @@ -458,9 +451,8 @@ namespace AssetProcessor { AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer productInfoContainer; QString productNameWithPlatform = QString("%1%2%3").arg(platform.c_str(), AZ_CORRECT_DATABASE_SEPARATOR_STRING, dependencyPathSearch.c_str()); - QString productNameWithPlatformAndGameName = QString("%1%2%3%2%4").arg(platform.c_str(), AZ_CORRECT_DATABASE_SEPARATOR_STRING, gameName, dependencyPathSearch.c_str()); - if (AzFramework::StringFunc::Equal(productNameWithPlatformAndGameName.toUtf8().data(), productName.c_str())) + if (AzFramework::StringFunc::Equal(productNameWithPlatform.toUtf8().data(), productName.c_str())) { AZ_Warning(AssetProcessor::ConsoleChannel, false, "Invalid dependency: Product Asset ( %s ) has listed itself as one of its own Product Dependencies.", @@ -471,18 +463,15 @@ namespace AssetProcessor if (isExactDependency) { - m_stateData->GetProductsByProductName(productNameWithPlatformAndGameName, productInfoContainer); - // Not all products will be in the game subfolder. - // Items in dev, like bootstrap.cfg, end up in just the root platform folder. - // These two checks search for products in both location. - // Example: If a path dependency was just "bootstrap.cfg" in SamplesProject on PC, this would search both - // "cache/SamplesProject/pc/bootstrap.cfg" and "cache/SamplesProject/pc/SamplesProject/bootstrap.cfg". + // Search for products in the cache platform folder + // Example: If a path dependency is "test1.asset" in SamplesProject on PC, this would search + // "SamplesProject/Cache/pc/test1.asset" m_stateData->GetProductsByProductName(productNameWithPlatform, productInfoContainer); } else { - m_stateData->GetProductsLikeProductName(productNameWithPlatformAndGameName, AzToolsFramework::AssetDatabase::AssetDatabaseConnection::LikeType::Raw, productInfoContainer); + m_stateData->GetProductsLikeProductName(productNameWithPlatform, AzToolsFramework::AssetDatabase::AssetDatabaseConnection::LikeType::Raw, productInfoContainer); } // See if path matches any product files diff --git a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h index f95d4ba5b8..c2db8ec1fb 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.h @@ -76,9 +76,6 @@ namespace AssetProcessor /// Returns false if a path contains wildcards, true otherwise static bool IsExactDependency(AZStd::string_view path); - /// Removes /platform/project/ from the start of a product path - static AZStd::string StripPlatformAndProject(AZStd::string_view relativeProductPath); - /// Prefixes the scanFolderId to the relativePath AZStd::string ToScanFolderPrefixedPath(int scanFolderId, const char* relativePath) const; diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index 84e5f98155..c78e77cba8 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -67,8 +67,7 @@ namespace AssetProcessor if (AssetUtilities::ComputeAssetRoot(assetRoot)) { azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, assetRoot.absolutePath().toUtf8().constData()); - QString absoluteDevGameFolderPath = assetRoot.absoluteFilePath(AssetUtilities::ComputeGameName()); - azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, absoluteDevGameFolderPath.toUtf8().constData()); + azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, AssetUtilities::ComputeProjectPath().toUtf8().constData()); } using namespace AZStd::placeholders; @@ -1067,7 +1066,7 @@ namespace AssetProcessor AZStd::vector > newLegacySubIDs; // each product has a vector of legacy subids; for (const AssetBuilderSDK::JobProduct& product : processedAsset.m_response.m_outputProducts) { - // prior products, if present, will be in the form "platform/game/subfolders/productfile", convert + // prior products, if present, will be in the form "platform/subfolders/productfile", convert // our new products to the same thing by removing the cache root QString newProductName = product.m_productFileName.c_str(); newProductName = AssetUtilities::NormalizeFilePath(newProductName); @@ -1093,7 +1092,8 @@ namespace AssetProcessor //This is the legacy product guid, its only use is for backward compatibility as before the asset id's guid was created off of the relative product name. // Right now when we query for an asset guid we first match on the source guid which is correct and secondarily match on the product guid. Eventually this will go away. newProductName = newProductName.right(newProductName.length() - newProductName.indexOf('/') - 1); // remove PLATFORM and an extra slash - newProductName = newProductName.right(newProductName.length() - newProductName.indexOf('/') - 1); // remove GAMENAME and an extra slash + // Strip the from the front of a relative product path + newProductName = AssetUtilities::StripAssetPlatform(newProductName.toUtf8().constData()); newProduct.m_legacyGuid = AZ::Uuid::CreateName(newProductName.toUtf8().constData()); //push back the new product into the new products list @@ -1115,7 +1115,7 @@ namespace AssetProcessor // we need to delete these product files from the disk as they no longer exist and inform everyone we did so for (const auto& priorProduct : priorProducts) { - // product name will be in the form "platform/game/relativeProductPath" + // product name will be in the form "platform/relativeProductPath" // and will always already be a lowercase string, because its relative to the cache. QString productName = priorProduct.m_productName.c_str(); @@ -1123,10 +1123,8 @@ namespace AssetProcessor // this is case sensitive since it refers to a real location on disk. QString fullProductPath = m_cacheRootDir.absoluteFilePath(productName); - // relative file path is gotten by removing the platform and game from the product name - QString relativeProductPath = productName; - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // remove PLATFORM and an extra slash - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // remove GAMENAME and an extra slash + // Strip the from the front of a relative product path + QString relativeProductPath = AssetUtilities::StripAssetPlatform(priorProduct.m_productName); AZ::Data::AssetId assetId(source.m_sourceGuid, priorProduct.m_subID); @@ -1302,16 +1300,15 @@ namespace AssetProcessor AzToolsFramework::AssetDatabase::ProductDatabaseEntry& newProduct = pair.first; AZStd::vector& subIds = newLegacySubIDs[productIdx]; - // product name will be in the form "platform/game/relativeProductPath" + // product name will be in the form "platform/relativeProductPath" QString productName = QString::fromUtf8(newProduct.m_productName.c_str()); // the full file path is gotten by adding the product name to the cache root QString fullProductPath = m_cacheRootDir.absoluteFilePath(productName); // relative file path is gotten by removing the platform and game from the product name - QString relativeProductPath = productName; - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // remove PLATFORM and an extra slash - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // remove GAMENAME and an extra slash + // Strip the from the front of a relative product path + QString relativeProductPath = AssetUtilities::StripAssetPlatform(productName.toUtf8().constData()); AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetChanged, newProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str()); AZ::Data::AssetId assetId(source.m_sourceGuid, newProduct.m_subID); @@ -1572,10 +1569,10 @@ namespace AssetProcessor // this might be interesting, but only if its a known product! // the dictionary in statedata stores only the relative path, not the platform. // which means right now we have, for example - // d:/game/root/Cache/SamplesProject/IOS/SamplesProject/textures/favorite.tga - // ^^^^^^^^^^^^ engine root - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cache root - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ platform root + // d:/SamplesProject/Cache/ios/textures/favorite.tga + // ^^^^^^^^^ projectroot + // ^^^^^^^^^^^^^^^^^^^^^ cache root + // ^^^^^^^^^^^^^^^^^^^^^^^^^ platform root { QMutexLocker locker(&m_processingJobMutex); auto found = m_processingProductInfoList.find(fullProductFile.toUtf8().constData()); @@ -1596,7 +1593,7 @@ namespace AssetProcessor QString relativeProductFile = m_cacheRootDir.relativeFilePath(fullProductFile); //platform - QString platform = relativeProductFile;// currently // + QString platform = relativeProductFile;// currently / platform = platform.left(platform.indexOf('/')); // also consume the extra slash - remove PLATFORM //we are going to force the processor to re process the source file associated with this product @@ -1652,11 +1649,8 @@ namespace AssetProcessor } } - // currently // - // remove PLATFORM and GAMENAME so that we only have the relative asset path which should match the db - QString relativePath(relativeProductFile); - relativePath = relativePath.right(relativePath.length() - relativePath.indexOf('/') - 1); // also consume the extra slash - remove PLATFORM - relativePath = relativePath.right(relativePath.length() - relativePath.indexOf('/') - 1); // also consume the extra slash - remove GAMENAME + // Strip the from the front of a relative product path + QString relativePath = AssetUtilities::StripAssetPlatform(relativeProductFile.toUtf8().constData()); //set the fingerprint on the job that made this product for (auto& job : jobs) @@ -1687,9 +1681,9 @@ namespace AssetProcessor { bool successfullyRemoved = true; // delete the products. - // products have names like "pc/SamplesProject/textures/blah.dds" and do include platform roots! + // products have names like "pc/textures/blah.dds" and do include platform roots! // this means the actual full path is something like - // [cache root] / [platform] / [product name] + // [cache root] / [platform] for (const auto& product : products) { //get the source for this product @@ -1700,9 +1694,7 @@ namespace AssetProcessor } QString fullProductPath = m_cacheRootDir.absoluteFilePath(product.m_productName.c_str()); - QString relativeProductPath(product.m_productName.c_str()); - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // also consume the extra slash - remove PLATFORM - relativeProductPath = relativeProductPath.right(relativeProductPath.length() - relativeProductPath.indexOf('/') - 1); // also consume the extra slash - remove GAMENAME + QString relativeProductPath(AssetUtilities::StripAssetPlatform(product.m_productName)); QFileInfo productFileInfo(fullProductPath); if (productFileInfo.exists()) { @@ -2144,15 +2136,7 @@ namespace AssetProcessor pathRel = QString(); } - if (jobDetails.m_scanFolder->IsRoot()) - { - // stuff which is found in the root continues to go to the root, rather than GAMENAME folder... - lowerCasePath += pathRel; - } - else - { - lowerCasePath += "/" + AssetUtilities::ComputeGameName() + pathRel; - } + lowerCasePath += pathRel; lowerCasePath = lowerCasePath.toLower(); jobDetails.m_destinationPath = m_cacheRootDir.absoluteFilePath(lowerCasePath); @@ -3471,8 +3455,16 @@ namespace AssetProcessor AssetProcessor::BuilderConfigurationRequestBus::Broadcast(&AssetProcessor::BuilderConfigurationRequests::UpdateJobDescriptor, jobDescriptor.m_jobKey, jobDescriptor); const AssetBuilderSDK::PlatformInfo* const infoForPlatform = m_platformConfig->GetPlatformByIdentifier(jobDescriptor.GetPlatformIdentifier().c_str()); - AZ_Assert(infoForPlatform, "Somehow, a platform for a job was created in createjobs which cannot be found in the list of enabled platforms."); - if (infoForPlatform) + + if (!infoForPlatform) + { + AZ_Warning(AssetProcessor::ConsoleChannel, infoForPlatform, + "CODE BUG: Builder %s emitted jobs for a platform that isn't enabled (%s). This job will be " + "discarded. Builders should check the input list of platforms and only emit jobs for platforms " + "in that list", builderInfo.m_name.c_str(), jobDescriptor.GetPlatformIdentifier().c_str()); + continue; + } + { JobDetails newJob; newJob.m_assetBuilderDesc = builderInfo; @@ -4614,7 +4606,7 @@ namespace AssetProcessor QString metaDataFileName; QDir assetRoot; AssetUtilities::ComputeAssetRoot(assetRoot); - QString gameName = AssetUtilities::ComputeGameName(); + QString projectPath = AssetUtilities::ComputeProjectPath(); QString fullPathToFile(absolutePathToFileToCheck); if (!m_cachedMetaFilesExistMap) @@ -4624,7 +4616,7 @@ namespace AssetProcessor for (int idx = 0; idx < m_platformConfig->MetaDataFileTypesCount(); idx++) { QPair metaDataFileType = m_platformConfig->GetMetaDataFileTypeAt(idx); - QString fullMetaPath = assetRoot.filePath(gameName + "/" + metaDataFileType.first); + QString fullMetaPath = QDir(projectPath).filePath(metaDataFileType.first); if (QFileInfo::exists(fullMetaPath)) { m_metaFilesWhichActuallyExistOnDisk.insert(metaDataFileType.first); @@ -4644,7 +4636,7 @@ namespace AssetProcessor if (m_metaFilesWhichActuallyExistOnDisk.find(metaDataFileType.first) != m_metaFilesWhichActuallyExistOnDisk.end()) { - QString fullMetaPath = assetRoot.filePath(gameName + "/" + metaDataFileType.first); + QString fullMetaPath = QDir(projectPath).filePath(metaDataFileType.first); metaDataFileName = fullMetaPath; } else diff --git a/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp b/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp index f93bdd3a3c..ffc5499f79 100644 --- a/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp +++ b/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp @@ -21,6 +21,9 @@ #include "native/utilities/assetUtils.h" +#include +#include + #include using namespace AZ::IO; @@ -114,20 +117,20 @@ void FileServer::ConnectionAdded(unsigned int connId, Connection* connection) { projectCacheRoot = QDir(projectCacheRoot.absoluteFilePath(assetPlatform)); } - fileIO->SetAlias("@root@", projectCacheRoot.absolutePath().toUtf8().data()); + const char* projectCachePath = projectCacheRoot.absolutePath().toUtf8().data(); + fileIO->SetAlias("@assets@", projectCachePath); + fileIO->SetAlias("@root@", projectCachePath); - QString userDir = projectCacheRoot.absoluteFilePath("user"); - userDir = QDir::toNativeSeparators(userDir); - fileIO->SetAlias("@user@", userDir.toUtf8().data()); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + AZ::IO::Path projectUserPath; + settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + fileIO->SetAlias("@user@", projectUserPath.c_str()); - QString logDir = QDir(userDir).absoluteFilePath("log"); - logDir = QDir::toNativeSeparators(logDir); - fileIO->SetAlias("@log@", logDir.toUtf8().data()); + AZ::IO::Path logUserPath = projectUserPath / "log"; + fileIO->SetAlias("@log@", logUserPath.c_str()); + } - QString gameName = AssetUtilities::ComputeGameName(); - QString gameDir = projectCacheRoot.absoluteFilePath(gameName); - gameDir = QDir::toNativeSeparators(gameDir); - fileIO->SetAlias("@assets@", gameDir.toUtf8().data()); // note that the cache folder is auto-created only upon first use of VFS. } @@ -145,13 +148,20 @@ void FileServer::EnsureCacheFolderExists(int connId) { return; } - if (fileIO->GetAlias("@cache@")) + if (fileIO->GetAlias("@usercache@")) { // already created. return; } - QString cacheDir = QDir(fileIO->GetAlias("@user@")).absoluteFilePath("cache"); + AZ::IO::FixedMaxPath cacheUserPath; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry->Get(cacheUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) + { + cacheUserPath /= "Cache"; + } + + auto cacheDir = QString::fromUtf8(cacheUserPath.c_str(), aznumeric_cast(cacheUserPath.Native().size())); cacheDir = QDir::toNativeSeparators(cacheDir); // the Cache-dir is special in that we don't allow sharing of cache dirs for multiple running // apps of the same platform at the same time. @@ -207,7 +217,7 @@ void FileServer::EnsureCacheFolderExists(int connId) } #endif - fileIO->SetAlias("@cache@", cacheDir.toUtf8().data()); + fileIO->SetAlias("@usercache@", cacheDir.toUtf8().data()); } void FileServer::ConnectionRemoved(unsigned int connId) @@ -944,7 +954,7 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig } auto fileIO = m_fileIOs[connId]; - + FileTreeResponse::FileList files; FileTreeResponse::FolderList folders; @@ -954,10 +964,10 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig folders.push_back("@assets@"); untestedFolders.push_back("@assets@"); } - if (fileIO->IsDirectory("@cache@")) + if (fileIO->IsDirectory("@usercache@")) { - folders.push_back("@cache@"); - untestedFolders.push_back("@cache@"); + folders.push_back("@usercache@"); + untestedFolders.push_back("@usercache@"); } if (fileIO->IsDirectory("@user@")) { @@ -976,7 +986,7 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig } AZ::IO::Result res = ResultCode::Success; - + while (untestedFolders.size() && res == ResultCode::Success) { AZ::OSString folderName = untestedFolders.back(); @@ -1006,9 +1016,9 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig } uint32_t resultCode = static_cast(res.GetResultCode()); - + FileTreeResponse response(resultCode, files, folders); - + Send(connId, serial, response); } diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp index 45854a2f64..8f9f82c127 100644 --- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp +++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include namespace AssetProcessor { @@ -210,6 +212,8 @@ namespace AssetProcessor response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; AZStd::vector excludes = ReadExcludesFromRegistry(); + // Exclude the AssetProcessor settings from the game regsitry + excludes.emplace_back(AssetProcessor::AssetProcessorSettingsKey); AZStd::vector scratchBuffer; scratchBuffer.reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer; @@ -228,19 +232,16 @@ namespace AssetProcessor }; // Add the project specific specializations - if (auto settingsRegistry = AZ::Interface::Get(); settingsRegistry) + auto projectName = AZ::Utils::GetProjectName(); + if (!projectName.empty()) { - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - if (AZ::SettingsRegistryInterface::FixedValueString projectName; settingsRegistry->Get(projectName, projectKey)) + for (AZ::SettingsRegistryInterface::Specializations& specialization : specializations) { - for (AZ::SettingsRegistryInterface::Specializations& specialization : specializations) - { - specialization.Append(projectName); - // The Game Launcher normally has a build target name of Launcher - // Add that as a specialization to pick up the gem dependencies files that are specialized - // on a the Game Launcher target if the asset platform isn't "server" - specialization.Append(projectName + launcherType); - } + specialization.Append(projectName); + // The Game Launcher normally has a build target name of Launcher + // Add that as a specialization to pick up the gem dependencies files that are specialized + // on a the Game Launcher target if the asset platform isn't "server" + specialization.Append(projectName + launcherType); } } @@ -255,8 +256,9 @@ namespace AssetProcessor for (AZStd::string_view platform : platformCodes) { AZ::u32 productSubID = static_cast(AZStd::hash{}(platform)); // Deliberately ignoring half the bits. - for (size_t i = 0; i < AZ_ARRAY_SIZE(specializations); ++i) + for (size_t i = 0; i < AZStd::size(specializations); ++i) { + const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i]; if (m_isShuttingDown) { response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled; @@ -269,12 +271,12 @@ namespace AssetProcessor if (auto settingsRegistry = AZ::Interface::Get(); settingsRegistry != nullptr) { AZStd::array settingsToCopy{ - AZStd::string::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey), + AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey), AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_BinaryFolder}, AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder}, - AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder}, + AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath}, + AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder}, AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder}, - AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_CacheGameFolder} }; for (const auto& settingsKey : settingsToCopy) @@ -288,14 +290,14 @@ namespace AssetProcessor } AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(registry); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, platform, specializations[i], &scratchBuffer); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, platform, specializations[i], &scratchBuffer); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, platform, specializations[i], &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, platform, specialization, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, platform, specialization, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, platform, specialization, &scratchBuffer); // Merge the Developer User settings registry only in non-release builds - if (!specializations->Contains("release")) + if (!specialization.Contains("release")) { - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_DevRegistry(registry, platform, specializations[i], &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, platform, specialization, &scratchBuffer); } AZ::ComponentApplicationBus::Broadcast([®istry](AZ::ComponentApplicationRequests* appRequests) @@ -314,7 +316,7 @@ namespace AssetProcessor return; } - outputPath += specializations[i].GetSpecialization(0); // Append configuration + outputPath += specialization.GetSpecialization(0); // Append configuration outputPath += '.'; outputPath += platform; outputPath += ".setreg"; diff --git a/Code/Tools/AssetProcessor/native/connection/connectionManager.cpp b/Code/Tools/AssetProcessor/native/connection/connectionManager.cpp index 2ca93e7bbc..3044296dda 100644 --- a/Code/Tools/AssetProcessor/native/connection/connectionManager.cpp +++ b/Code/Tools/AssetProcessor/native/connection/connectionManager.cpp @@ -506,7 +506,7 @@ void ConnectionManager::AddAddressToAllowedList(QString address) UpdateAllowedListFromBootStrap(); while (m_allowedListAddresses.removeOne(address)) {} m_allowedListAddresses << address; - AssetUtilities::WriteAllowedlistToBootstrap(m_allowedListAddresses); + AssetUtilities::WriteAllowedlistToSettingsRegistry(m_allowedListAddresses); Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses); } @@ -514,7 +514,7 @@ void ConnectionManager::RemoveAddressFromAllowedList(QString address) { UpdateAllowedListFromBootStrap(); while (m_allowedListAddresses.removeOne(address)) {} - AssetUtilities::WriteAllowedlistToBootstrap(m_allowedListAddresses); + AssetUtilities::WriteAllowedlistToSettingsRegistry(m_allowedListAddresses); Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses); } diff --git a/Code/Tools/AssetProcessor/native/connection/connectionworker.cpp b/Code/Tools/AssetProcessor/native/connection/connectionworker.cpp index 189974698c..7d6aa1c531 100644 --- a/Code/Tools/AssetProcessor/native/connection/connectionworker.cpp +++ b/Code/Tools/AssetProcessor/native/connection/connectionworker.cpp @@ -235,9 +235,9 @@ bool ConnectionWorker::NegotiateDirect(bool initiate) using namespace AzFramework::AssetSystem; AZStd::string azBranchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, azBranchToken); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, azBranchToken); QString branchToken(azBranchToken.c_str()); - QString projectName = AssetUtilities::ComputeGameName(); + QString projectName = AssetUtilities::ComputeProjectName(); NegotiationMessage myInfo; @@ -316,7 +316,7 @@ bool ConnectionWorker::NegotiateDirect(bool initiate) QString incomingBranchToken(engineInfo.m_negotiationInfoMap[NegotiationInfo_BranchIndentifier].c_str()); if (QString::compare(incomingBranchToken, branchToken, Qt::CaseInsensitive) != 0) { - //if we are here it means that the editor/game which is negotiating is running on a different branch + // if we are here it means that the editor/game which is negotiating is running on a different branch // note that it could have just read nothing from the engine or a repeat packet, in that case, discard it silently and try again. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "ConnectionWorker::NegotiateDirect: branch token mismatch from %s - %p - %s vs %s\n", engineInfo.m_identifier.c_str(), this, incomingBranchToken.toUtf8().data(), branchToken.toUtf8().data()); AssetProcessor::MessageInfoBus::Broadcast(&AssetProcessor::MessageInfoBus::Events::NegotiationFailed); @@ -325,7 +325,7 @@ bool ConnectionWorker::NegotiateDirect(bool initiate) } QString incomingProjectName(engineInfo.m_negotiationInfoMap[NegotiationInfo_ProjectName].c_str()); - // Do a case-insensitive compare for the project name because some (case-sensitive) platforms will blower-case the incoming project name + // Do a case-insensitive compare for the project name because some (case-sensitive) platforms will lower-case the incoming project name if(QString::compare(incomingProjectName, projectName, Qt::CaseInsensitive) != 0) { AZ_TracePrintf(AssetProcessor::ConsoleChannel, "ConnectionWorker::NegotiateDirect: project name mismatch from %s - %p - %s vs %s\n", engineInfo.m_identifier.c_str(), this, incomingProjectName.toUtf8().constData(), projectName.toUtf8().constData()); diff --git a/Code/Tools/AssetProcessor/native/resourcecompiler/RCBuilder.cpp b/Code/Tools/AssetProcessor/native/resourcecompiler/RCBuilder.cpp index 9fa18d69c7..dfc7de18c4 100644 --- a/Code/Tools/AssetProcessor/native/resourcecompiler/RCBuilder.cpp +++ b/Code/Tools/AssetProcessor/native/resourcecompiler/RCBuilder.cpp @@ -24,8 +24,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -164,7 +164,7 @@ namespace AssetProcessor // build the command line: QString commandString = NativeLegacyRCCompiler::BuildCommand(inputFile, watchFolder, platformIdentifier, params, dest); - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; // while it might be tempting to set the executable in processLaunchInfo.m_processExecutableString, it turns out that RC.EXE // won't work if you do that because it assumes the first command line param is the exe name, which is not the case if you do it that way... @@ -173,12 +173,12 @@ namespace AssetProcessor processLaunchInfo.m_commandlineParameters = QString(formatter).arg(m_rcExecutableFullPath).arg(commandString).toUtf8().data(); processLaunchInfo.m_showWindow = false; processLaunchInfo.m_workingDirectory = m_systemRoot.absolutePath().toUtf8().data(); - processLaunchInfo.m_processPriority = AzToolsFramework::PROCESSPRIORITY_IDLE; + processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_IDLE; AZ_TracePrintf("RC Builder", "Executing RC.EXE: '%s' ...\n", processLaunchInfo.m_commandlineParameters.c_str()); AZ_TracePrintf("Rc Builder", "Executing RC.EXE with working directory: '%s' ...\n", processLaunchInfo.m_workingDirectory.c_str()); - AzToolsFramework::ProcessWatcher* watcher = AzToolsFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzToolsFramework::COMMUNICATOR_TYPE_STDINOUT); + AzFramework::ProcessWatcher* watcher = AzFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT); if (!watcher) { @@ -256,18 +256,16 @@ namespace AssetProcessor QString cmdLine; if (!dest.isEmpty()) { - QString gameName = AssetUtilities::ComputeGameName(); + QString projectName = AssetUtilities::ComputeProjectName(); + QString projectPath = AssetUtilities::ComputeProjectPath(); int portNumber = 0; ApplicationServerBus::BroadcastResult(portNumber, &ApplicationServerBus::Events::GetServerListeningPort); - QDir assetRoot; - AssetUtilities::ComputeAssetRoot(assetRoot); - QString gameRoot = assetRoot.absoluteFilePath(AssetUtilities::ComputeGameName()); AZStd::string appBranchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, appBranchToken); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, appBranchToken); cmdLine = QString("\"%1\" /p=%2 %3 /unattended=true /gameroot=\"%4\" /watchfolder=\"%6\" /targetroot=\"%5\" /logprefix=\"%5/\" /port=%7 /gamesubdirectory=\"%8\" /branchtoken=\"%9\""); - cmdLine = cmdLine.arg(inputFile, platformIdentifier, params, gameRoot, dest, watchFolder).arg(portNumber).arg(gameName).arg(appBranchToken.c_str()); + cmdLine = cmdLine.arg(inputFile, platformIdentifier, params, projectPath, dest, watchFolder).arg(portNumber).arg(projectName).arg(appBranchToken.c_str()); } else { diff --git a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp index 866bb1dbd0..c1c56447ac 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,7 @@ namespace AssetProcessor public: AssetCatalogForUnitTest(QObject* parent, AssetProcessor::PlatformConfiguration* platformConfiguration) : AssetCatalog(parent, platformConfiguration) {} - + // prevent automatic save on shutdown, no point in doing that in unit test mode, just wastes time. virtual ~AssetCatalogForUnitTest() { @@ -68,7 +69,7 @@ namespace AssetProcessor : public ScopedAllocatorSetupFixture { protected: - + // store all data we create here so that it can be destroyed on shutdown before we remove allocators struct DataMembers { @@ -89,7 +90,7 @@ namespace AssetProcessor int argc = 0; DataMembers() : coreApp(argc, nullptr) { - + } }; @@ -108,23 +109,28 @@ namespace AssetProcessor m_systemEntity = m_app->Create(desc); m_data = azcreate(DataMembers, ()); - + AssetUtilities::ComputeAssetRoot(m_data->m_priorAssetRoot); AssetUtilities::ResetAssetRoot(); // the canonicalization of the path here is to get around the fact that on some platforms // the "temporary" folder location could be junctioned into some other folder and getting "QDir::current()" - // and other similar functions may actually return a different string but still be referring to the same folder + // and other similar functions may actually return a different string but still be referring to the same folder m_data->m_temporarySourceDir = QDir(m_data->m_temporaryDir.path()); QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(m_data->m_temporarySourceDir.canonicalPath()); m_data->m_temporarySourceDir = QDir(canonicalTempDirPath); m_data->m_scopedDir.Setup(m_data->m_temporarySourceDir.path()); - m_data->m_gameName = AssetUtilities::ComputeGameName("SamplesProject"); // uses the above file. + m_data->m_gameName = AssetUtilities::ComputeProjectName("SamplesProject"); // uses the above file. AssetUtilities::ResetAssetRoot(); QDir newRoot; // throwaway dummy var - we just want to invoke the below function AssetUtilities::ComputeAssetRoot(newRoot, &m_data->m_temporarySourceDir); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + auto cacheRootKey = + AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_cache_path"; + settingsRegistry->Set(cacheRootKey, m_data->m_temporarySourceDir.absoluteFilePath("Cache").toUtf8().constData()); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry); AssetUtilities::ComputeProjectCacheRoot(m_data->m_cacheRootDir); QString normalizedCacheRoot = AssetUtilities::NormalizeDirectoryPath(m_data->m_cacheRootDir.absolutePath()); m_data->m_cacheRootDir = QDir(normalizedCacheRoot); @@ -181,7 +187,7 @@ namespace AssetProcessor m_data->m_databaseLocationListener.BusConnect(); m_data->m_dbConn.OpenDatabase(); - + BuildConfig(m_data->m_temporarySourceDir, &(m_data->m_dbConn), m_data->m_config); m_data->m_assetCatalog.reset(new AssetCatalogForUnitTest(nullptr, &(m_data->m_config))); } @@ -331,7 +337,7 @@ namespace AssetProcessor { bool relPathfound = false; AZStd::string relPath; - AZStd::string fullPath(fileToCheck.toStdString().c_str()); + AZStd::string fullPath(fileToCheck.toUtf8().constData()); AzToolsFramework::AssetSystemRequestBus::BroadcastResult(relPathfound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetRelativeProductPathFromFullSourceOrProductPath, fullPath, relPath); @@ -356,7 +362,7 @@ namespace AssetProcessor { bool fullPathfound = false; AZStd::string fullPath; - AZStd::string relPath(fileToCheck.toStdString().c_str()); + AZStd::string relPath(fileToCheck.toUtf8().constData()); AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathfound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetFullSourcePathFromRelativeProductPath, relPath, fullPath); @@ -419,7 +425,7 @@ namespace AssetProcessor ASSERT_EQ(m_data->m_absorber.m_numAssertsAbsorbed, 2); // reset the absorber before we leave this assert-test, so that it doesn't cause failure of the test itself m_data->m_absorber.Clear(); - + ASSERT_TRUE(TestGetRelativeProductPath("", false, { "" })); ASSERT_TRUE(TestGetFullSourcePath("", m_data->m_temporarySourceDir, false, "")); } @@ -444,75 +450,76 @@ namespace AssetProcessor TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_WithGameName_ReturnsFileInGameFolder) { - // feed it a product path with gamename and a platform name, returns it without gamename - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName + "/aaa/basefile.txt"); + // feed it a product path with a platform name, returns it + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/aaa/basefile.txt"); ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_WithoutGameName_ReturnsFileInRootFolder) { - // feed it a product path without gamename, just the file name since its supposed to be a root file + // feed it a product path, just the file name since its supposed to be a root file QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/basefile.txt"); ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "basefile.txt" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_BadCasingInPlatform_ReturnsRelativePath) { - // feed it a product path with gamename but poor casing (test 1: the pc platform is not matching case) - QString fileToCheck = m_data->m_cacheRootDir.filePath("Pc/" + m_data->m_gameName + "/aaa/basefile.txt"); + // feed it a product path but with poor casing (test 1: the pc platform is not matching case) + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("Pc") + "/aaa/basefile.txt"); ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_BadCasingInGameName_ReturnsRelativePath) { - //feed it a product path with gamename but poor casing (test 2: the gameName is not matching case) - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toUpper() + "/aaa/basefile.txt"); + //feed it a product path but with poor casing (test 2: the gameName is not matching case) + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/aaa/basefile.txt"); ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_FolderName_ReturnsFolderNameOnly) { - // feed it a product path that resolves to a directory name instead of a file. GameName is 'incorrect' (upper) - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toUpper() + "/aaa"); + // feed it a product path that resolves to a directory name instead of a file. + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/aaa"); ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_FolderNameExtraSlash_ReturnsFolderNameOnlyNoExtraSlash) { - // make sure it doesn't keep any trailing slashes. GameName is 'incorrect' (upper) - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toUpper() + "/aaa/"); // extra trailing slash + // make sure it doesn't keep any trailing slashes. + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/aaa/"); // extra trailing slash ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa" })); // the API should never result in a trailing slash } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_FolderNameExtraWrongWaySlash_ReturnsFolderNameOnlyNoExtraWrongSlash) { - // make sure it doesn't keep any trailing slashes. GameName is 'incorrect' (upper) - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toUpper() + "/aaa\\"); // extra trailing wrongway slash + // make sure it doesn't keep any trailing slashes. + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/aaa\\"); // extra trailing wrongway slash ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa" })); // the API should never result in a trailing slash } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_RelativeDirectoryNameWhichDoesNotExist_ReturnsFolderNameOnly) { - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toLower() + "/nonexistantfolder"); // extra trailing wrongway slash - ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "nonexistantfolder" })); + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/nonexistantfolder"); // extra trailing wrongway slash + ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "nonexistantfolder" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_RelativeDirectoryNameWhichDoesNotExistWithExtraSlash_ReturnsFolderNameOnly) { - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toLower() + "/nonexistantfolder/"); // extra trailing wrongway slash + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/nonexistantfolder/"); // extra trailing wrongway slash ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "nonexistantfolder" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_RelativeDirectoryNameWhichDoesNotExistWithExtraWrongWaySlash_ReturnsFolderNameOnly) { - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc\\" + m_data->m_gameName.toLower() + "\\nonexistantfolder\\"); // extra trailing wrongway slash + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "\\nonexistantfolder\\"); // extra trailing wrongway slash ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "nonexistantfolder" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_RelativePathToSourceFile_ReturnsProductFilePath) { QString fileToCheck = m_data->m_temporarySourceDir.absoluteFilePath("subfolder3/BaseFile.txt"); - ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "basefilez.arc2", "basefileaz.azm2", "basefile.arc2", "basefile.azm2" })); + ASSERT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "basefilez.arc2", "basefileaz.azm2", + "basefile.arc2", "basefile.azm2" })); } TEST_F(AssetCatalogTestWithProducts, GetRelativeProductPathFromFullSourceOrProductPath_RelativePathToSourceFile_BadCasing_ReturnsProductFilePath) @@ -533,9 +540,9 @@ namespace AssetProcessor // ----- Test the ProcessGetFullAssetPath function on product files { QStringList pcouts; - pcouts.push_back(m_data->m_cacheRootDir.filePath(QString("pc/") + m_data->m_gameName + "/subfolder3/randomfileoutput.random")); - pcouts.push_back(m_data->m_cacheRootDir.filePath(QString("pc/") + m_data->m_gameName + "/subfolder3/randomfileoutput.random1")); - pcouts.push_back(m_data->m_cacheRootDir.filePath(QString("pc/") + m_data->m_gameName + "/subfolder3/randomfileoutput.random2")); + pcouts.push_back(m_data->m_cacheRootDir.filePath(QString("pc") + "/subfolder3/randomfileoutput.random")); + pcouts.push_back(m_data->m_cacheRootDir.filePath(QString("pc") + "/subfolder3/randomfileoutput.random1")); + pcouts.push_back(m_data->m_cacheRootDir.filePath(QString("pc") + "/subfolder3/randomfileoutput.random2")); AZ::s64 jobId; ASSERT_TRUE(AddSourceAndJob("subfolder3", "somerandomfile.random", &(m_data->m_dbConn), jobId)); @@ -591,32 +598,32 @@ namespace AssetProcessor QString fileToCheck = "@somerandomalias@/subfolder3/randomfileoutput.random1"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } - + TEST_F(AssetCatalogTest_GetFullSourcePath, InvalidAliasMissingSeperator_ReturnsAbsolutePathToSource) { //feed it a path with some random alias and asset id but no separator QString fileToCheck = "@somerandomalias@subfolder3/randomfileoutput.random1"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } - + TEST_F(AssetCatalogTest_GetFullSourcePath, InvalidSourcePathContainingCacheAlias_ReturnsAbsolutePathToSource) { //feed it a path with alias and input name QString fileToCheck = "@assets@/somerandomfile.random"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } - + TEST_F(AssetCatalogTest_GetFullSourcePath, AbsolutePathToCache_ReturnsAbsolutePathToSource) { //feed it an absolute path with cacheroot - QString fileToCheck = m_data->m_cacheRootDir.filePath("pc/" + m_data->m_gameName.toLower() + "/subfolder3/randomfileoutput.random1"); + QString fileToCheck = m_data->m_cacheRootDir.filePath(QString("pc") + "/subfolder3/randomfileoutput.random1"); EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } - + TEST_F(AssetCatalogTest_GetFullSourcePath, ProductNameIncludingPlatformAndGameName_ReturnsAbsolutePathToSource) { //feed it a productName directly - QString fileToCheck = "pc/" + m_data->m_gameName + "/subfolder3/randomfileoutput.random1"; + QString fileToCheck = QString("pc") + "/subfolder3/randomfileoutput.random1"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } @@ -624,7 +631,7 @@ namespace AssetProcessor : public AssetCatalogTest { public: - + struct AssetCatalogTest_AssetInfo_DataMembers { AssetId m_assetA = AssetId(Uuid::CreateRandom(), 0); @@ -650,7 +657,7 @@ namespace AssetProcessor AzFramework::StringFunc::Path::Join(m_customDataMembers->m_subfolder1AbsolutePath.c_str(), m_customDataMembers->m_assetASourceRelPath.c_str(), m_customDataMembers->m_assetAFullPath); CreateDummyFile(QString::fromUtf8(m_customDataMembers->m_assetAFullPath.c_str()), m_customDataMembers->m_assetTestString.c_str()); - + AzFramework::StringFunc::Path::Join(m_data->m_cacheRootDir.absolutePath().toUtf8().constData(), m_customDataMembers->m_assetAProductRelPath.c_str(), m_customDataMembers->m_assetAProductFullPath); CreateDummyFile(QString::fromUtf8(m_customDataMembers->m_assetAProductFullPath.c_str()), m_customDataMembers->m_productTestString.c_str()); } @@ -724,7 +731,7 @@ namespace AssetProcessor return true; }; - void TearDown() override + void TearDown() override { azdestroy(m_customDataMembers); AssetCatalogTest::TearDown(); @@ -848,7 +855,7 @@ namespace AssetProcessor using namespace AzFramework::AssetSystem; PlatformConfiguration config; - + config.EnablePlatform(AssetBuilderSDK::PlatformInfo("pc", { "test" })); { @@ -1060,7 +1067,7 @@ namespace AssetProcessor productDependency.m_dependencySourceGuid = m_sourceFileWithDifferentProductsPerPlatform; productDependency.m_unresolvedPath = AZStd::string(); - QString platformGameDir = QDir(cacheRoot.absoluteFilePath(productDependency.m_platform.c_str())).filePath(AssetUtilities::ComputeGameName().toLower()); + QString platformGameDir = QDir(cacheRoot.absoluteFilePath(productDependency.m_platform.c_str())).filePath(AssetUtilities::ComputeProjectName().toLower()); QString assetCatalogFile = QDir(platformGameDir).filePath("assetcatalog.xml"); QFileInfo fileInfo(assetCatalogFile); @@ -1071,7 +1078,7 @@ namespace AssetProcessor // process all events QCoreApplication::processEvents(QEventLoop::AllEvents); - // This ensures that no save catalog event was queued when we resolve dependency + // This ensures that no save catalog event was queued when we resolve dependency EXPECT_FALSE(fileInfo.exists()); } diff --git a/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp index b555165cd1..baa8b980e3 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp @@ -106,7 +106,7 @@ namespace AssetProcessorMessagesTests m_batchApplicationManager->BeforeRun(); // Override Game Name to be "SamplesProject" - AssetUtilities::ComputeGameName("SamplesProject", true); + AssetUtilities::ComputeProjectName("SamplesProject", true); m_batchApplicationManager->m_platformConfiguration = new PlatformConfiguration(); m_batchApplicationManager->InitAssetProcessorManager(); @@ -144,7 +144,7 @@ namespace AssetProcessorMessagesTests RunNetworkRequest([]() { AZStd::string appBranchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, appBranchToken); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, appBranchToken); AzFramework::AssetSystem::ConnectionSettings connectionSettings; connectionSettings.m_assetProcessorIp = "127.0.0.1"; diff --git a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp index 2c227d2cd4..852d68cba2 100644 --- a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp @@ -181,9 +181,11 @@ namespace UnitTests ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/testfolder/file.foo"))); ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/testfolder/File.bar"))); - - AZ::IO::FileIOBase::SetInstance(nullptr); // The API requires the old instance to be destroyed first - AZ::IO::FileIOBase::SetInstance(new AZ::IO::LocalFileIO()); + if (AZ::IO::FileIOBase::GetInstance() == nullptr) + { + m_localFileIo = AZStd::make_unique(); + AZ::IO::FileIOBase::SetInstance(m_localFileIo.get()); + } m_data->m_reporter = AZStd::make_unique(m_data->m_connection, &m_data->m_platformConfig); @@ -204,6 +206,12 @@ namespace UnitTests void TearDown() override { + if (AZ::IO::FileIOBase::GetInstance() == m_localFileIo.get()) + { + AZ::IO::FileIOBase::SetInstance(nullptr); + } + m_localFileIo.reset(); + AZ::JobContext::SetGlobalContext(nullptr); delete m_data->m_jobContext; delete m_data->m_jobManager; @@ -405,6 +413,7 @@ namespace UnitTests // we store the above data in a unique_ptr so that its memory can be cleared during TearDown() in one call, before we destroy the memory // allocator, reducing the chance of missing or forgetting to destroy one in the future. AZStd::unique_ptr m_data; + AZStd::unique_ptr m_localFileIo; }; TEST_F(SourceFileRelocatorTest, GetSources_SingleFile_Succeeds) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 86932c8690..6b4a2ac746 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -12,6 +12,7 @@ #include "AssetProcessorManagerTest.h" #include "native/AssetManager/PathDependencyManager.h" +#include #include #include @@ -41,7 +42,7 @@ public: friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_WithDifferentTypes_BasicTest); friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_Reverse_BasicTest); friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_MissingFiles_ReturnsNoPathWithPlaceholders); - + friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_BeforeComputingDirtiness_AllDirty); friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_EmptyDatabase_AllDirty); friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, BuilderDirtiness_SameAsLastTime_NoneDirty); @@ -206,6 +207,12 @@ void AssetProcessorManagerTest::SetUp() m_scopeDir->Setup(m_tempDir.path()); QDir tempPath(m_tempDir.path()); + auto registry = AZ::SettingsRegistry::Get(); + auto cacheRootKey = + AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_cache_path"; + registry->Set(cacheRootKey, tempPath.absoluteFilePath("Cache").toUtf8().constData()); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); + m_data->m_databaseLocationListener.BusConnect(); // in other unit tests we may open the database called ":memory:" to use an in-memory database instead of one on disk. @@ -220,7 +227,7 @@ void AssetProcessorManagerTest::SetUp() SetArgReferee<0>(m_data->m_databaseLocation), Return(true))); - m_gameName = AssetUtilities::ComputeGameName("SamplesProject", true); + m_gameName = AssetUtilities::ComputeProjectName("SamplesProject", true); AssetUtilities::ResetAssetRoot(); QDir newRoot; @@ -230,7 +237,6 @@ void AssetProcessorManagerTest::SetUp() AssetUtilities::ComputeProjectCacheRoot(cacheRoot); QString normalizedCacheRoot = AssetUtilities::NormalizeDirectoryPath(cacheRoot.absolutePath()); - QString normalizedDirPathCheck = AssetUtilities::NormalizeDirectoryPath(QDir::current().absoluteFilePath("Cache/" + m_gameName)); m_normalizedCacheRootDir.setPath(normalizedCacheRoot); UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder1/assetProcessorManagerTest.txt")); @@ -357,7 +363,7 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess) TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase) { // This tests the JobDiagnosticTracker: Warnings/errors reported to it should be recorded in the database when AssetProcessed is fired and able to be retrieved when querying job status - + using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; @@ -471,7 +477,7 @@ TEST_F(AssetProcessorManagerTest, UnitTestForOutPutPrefix) } }); - + m_isIdling = false; // tell the APM about the files: QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, tempPath.absoluteFilePath("subfolder2/test.txt"))); @@ -626,10 +632,10 @@ TEST_F(AssetProcessorManagerTest, BuilderDirtiness_EmptyDatabase_AllDirty) MockBuilderResponder mockBuilderResponder; mockBuilderResponder.BusConnect(); - + mockBuilderResponder.AddBuilder("builder1", { AssetBuilderSDK::AssetBuilderPattern("*.egg", AssetBuilderPattern::Wildcard) }, AZ::Uuid::CreateRandom(), 1, "fingerprint1"); mockBuilderResponder.AddBuilder("builder2", { AssetBuilderSDK::AssetBuilderPattern("*.foo", AssetBuilderPattern::Wildcard) }, AZ::Uuid::CreateRandom(), 1, "fingerprint2"); - + m_assetProcessorManager->ComputeBuilderDirty(); EXPECT_TRUE(m_assetProcessorManager->m_anyBuilderChange); @@ -666,7 +672,7 @@ TEST_F(AssetProcessorManagerTest, BuilderDirtiness_SameAsLastTime_NoneDirty) mockBuilderResponder.BusDisconnect(); } -// when a new builder appears, the new builder should be dirty, +// when a new builder appears, the new builder should be dirty, TEST_F(AssetProcessorManagerTest, BuilderDirtiness_MoreThanLastTime_NewOneIsDirty) { using namespace AzToolsFramework::AssetSystem; @@ -677,13 +683,13 @@ TEST_F(AssetProcessorManagerTest, BuilderDirtiness_MoreThanLastTime_NewOneIsDirt mockBuilderResponder.BusConnect(); mockBuilderResponder.AddBuilder("builder1", { AssetBuilderSDK::AssetBuilderPattern("*.egg", AssetBuilderPattern::Wildcard) }, AZ::Uuid::CreateRandom(), 1, "fingerprint1"); - + m_assetProcessorManager->ComputeBuilderDirty(); mockBuilderResponder.AddBuilder("builder2", { AssetBuilderSDK::AssetBuilderPattern("*.foo", AssetBuilderPattern::Wildcard) }, AZ::Uuid::CreateRandom(), 1, "fingerprint2"); m_assetProcessorManager->ComputeBuilderDirty(); - + // one new builder should have been dirty: EXPECT_TRUE(m_assetProcessorManager->m_anyBuilderChange); EXPECT_TRUE(m_assetProcessorManager->m_buildersAddedOrRemoved); @@ -892,7 +898,7 @@ TEST_F(AssetProcessorManagerTest, BuilderDirtiness_NewAnalysisFingerprint_IsNotA TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_BasicTest) { using SourceFileDependencyEntry = AzToolsFramework::AssetDatabase::SourceFileDependencyEntry; - + // A depends on B, which depends on both C and D QDir tempPath(m_tempDir.path()); @@ -941,7 +947,7 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_BasicTe dependencies.clear(); m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("b.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, false); - EXPECT_EQ(dependencies.size(), 3); // b depends on c, and d + EXPECT_EQ(dependencies.size(), 3); // b depends on c, and d EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/b.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/c.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/d.txt").toUtf8().constData()), dependencies.end()); @@ -961,7 +967,7 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_WithDif { // test to make sure that different TYPES of dependencies work as expected. using SourceFileDependencyEntry = AzToolsFramework::AssetDatabase::SourceFileDependencyEntry; - + QDir tempPath(m_tempDir.path()); UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder1/a.txt"), QString("tempdata\n")); @@ -998,7 +1004,7 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_WithDif m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("a.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, false); // note that a depends on b, c, and d - with the latter two being indirect. // however, since b's dependency on C is via JOB, and we're asking for SOURCE only, we should not see C. - EXPECT_EQ(dependencies.size(), 3); + EXPECT_EQ(dependencies.size(), 3); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/a.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/b.txt").toUtf8().constData()), dependencies.end()); @@ -1007,7 +1013,7 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_WithDif dependencies.clear(); m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("b.txt", dependencies, SourceFileDependencyEntry::DEP_JobToJob, false); // b depends on c, and d - but we're asking for job dependencies only, so we should not get anything except C and B - EXPECT_EQ(dependencies.size(), 2); + EXPECT_EQ(dependencies.size(), 2); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/b.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/c.txt").toUtf8().constData()), dependencies.end()); @@ -1063,13 +1069,13 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_Reverse AssetProcessor::SourceFilesForFingerprintingContainer dependencies; // sanity: what Depends on a? the only result should be a itself. m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("a.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, true /*reverse*/); - EXPECT_EQ(dependencies.size(), 1); + EXPECT_EQ(dependencies.size(), 1); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/a.txt").toUtf8().constData()), dependencies.end()); dependencies.clear(); // what depends on d? b and a should (indirectly) m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("d.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, true); - EXPECT_EQ(dependencies.size(), 3); + EXPECT_EQ(dependencies.size(), 3); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/a.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/b.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/d.txt").toUtf8().constData()), dependencies.end()); @@ -1077,7 +1083,7 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_Reverse // what depends on c? b and a should. dependencies.clear(); m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("c.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, true); - EXPECT_EQ(dependencies.size(), 3); // b depends on c, and d + EXPECT_EQ(dependencies.size(), 3); // b depends on c, and d EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/c.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/b.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/a.txt").toUtf8().constData()), dependencies.end()); @@ -1092,7 +1098,7 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_Reverse EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/c.txt").toUtf8().constData()), dependencies.end()); } -// since we need these files to still produce a 0-based fingerprint, we need them to +// since we need these files to still produce a 0-based fingerprint, we need them to // still do a best guess at absolute path, when they are missing. TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_MissingFiles_ReturnsNoPathWithPlaceholders) { @@ -1131,13 +1137,13 @@ TEST_F(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_Missing AssetProcessor::SourceFilesForFingerprintingContainer dependencies; m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("a.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, false); EXPECT_EQ(dependencies.size(), 2); // a depends on b, c, and d - with the latter two being indirect. - + EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/a.txt").toUtf8().constData()), dependencies.end()); EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/d.txt").toUtf8().constData()), dependencies.end()); dependencies.clear(); m_assetProcessorManager->QueryAbsolutePathDependenciesRecursive("b.txt", dependencies, SourceFileDependencyEntry::DEP_SourceToSource, false); - EXPECT_EQ(dependencies.size(), 1); // b depends on c, and d + EXPECT_EQ(dependencies.size(), 1); // b depends on c, and d EXPECT_NE(dependencies.find(tempPath.absoluteFilePath("subfolder1/d.txt").toUtf8().constData()), dependencies.end()); // eliminate b --> c @@ -1161,7 +1167,7 @@ TEST_F(AssetProcessorManagerTest, BuilderSDK_API_CreateJobs_HasValidParameters_W m_isIdling = false; QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absPath)); - + // wait for AP to become idle. ASSERT_TRUE(BlockUntilIdle(5000)); @@ -1189,10 +1195,10 @@ TEST_F(AssetProcessorManagerTest, BuilderSDK_API_CreateJobs_HasValidParameters_W UnitTestUtils::CreateDummyFile(absPath); m_mockApplicationManager->ResetMockBuilderCreateJobCalls(); - + m_isIdling = false; QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absPath)); - + ASSERT_TRUE(BlockUntilIdle(5000)); ASSERT_EQ(m_mockApplicationManager->GetMockBuilderCreateJobCalls(), 1); @@ -1461,14 +1467,14 @@ bool PathDependencyTest::ProcessAsset(TestAsset& asset, const OutputAssetSet& ou { ProcessJobResponse processJobResponse; processJobResponse.m_resultCode = ProcessJobResult_Success; - + for (const char* outputExtension : outputSet) { if(jobSet >= capturedDetails.size() || capturedDetails[jobSet].m_destinationPath.isEmpty()) { return false; } - + QString outputAssetPath = QDir(capturedDetails[jobSet].m_destinationPath).absoluteFilePath(QString(asset.m_name.c_str()) + outputExtension); UnitTestUtils::CreateDummyFile(outputAssetPath, "this is a test output asset"); @@ -1508,7 +1514,7 @@ bool SearchDependencies(AzToolsFramework::AssetDatabase::ProductDependencyDataba void VerifyDependencies(AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer, AZStd::initializer_list assetIds, AZStd::initializer_list unresolvedPaths = {}) { EXPECT_EQ(dependencyContainer.size(), assetIds.size() + unresolvedPaths.size()); - + for (const AZ::Data::AssetId& assetId : assetIds) { bool found = false; @@ -1635,19 +1641,19 @@ TEST_F(PathDependencyTest, NoLongerProcessedFile_IsRemoved) { details = message; }); - + QDir tempPath(m_tempDir.path()); QString absPath(tempPath.absoluteFilePath("subfolder1/test1.txt")); TestAsset testAsset("test1"); - + ASSERT_TRUE(ProcessAsset(testAsset, { {".asset1"} })); AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer products; m_sharedConnection->GetProductsBySourceName("test1.txt", products); ASSERT_EQ(products.size(), 1); - ASSERT_TRUE(QFile::exists(m_normalizedCacheRootDir.absoluteFilePath("pc/samplesproject/test1.asset1").toUtf8().constData())); + ASSERT_TRUE(QFile::exists(m_normalizedCacheRootDir.absoluteFilePath("pc/test1.asset1").toUtf8().constData())); m_mockApplicationManager->UnRegisterAllBuilders(); @@ -1723,15 +1729,15 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_DeferredPathResolution) AZStd::vector dependencySources = { "dep1", "dep2" }; // Start with mixed casing. ProductPathDependencySet dependencies = { {"Dep1.txt", AssetBuilderSDK::ProductPathDependencyType::SourceFile}, {"DEP2.asset2", AssetBuilderSDK::ProductPathDependencyType::ProductFile}, {"dep2.asset3", AssetBuilderSDK::ProductPathDependencyType::ProductFile} }; // Test depending on a source asset, and on a subset of product assets - + TestAsset mainFile("test_text"); ASSERT_TRUE(ProcessAsset(mainFile, { { ".asset" }, {} }, dependencies)); - + // ---------- Verify that we have unresolved path in ProductDependencies table ---------- AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; ASSERT_TRUE(m_sharedConnection->GetProductDependencies(dependencyContainer)); ASSERT_EQ(dependencyContainer.size(), dependencies.size()); - + // All dependencies are stored lowercase in the database. Make the expected dependencies lowercase here to match that. for(auto& dependency : dependencies) { @@ -1752,12 +1758,12 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_DeferredPathResolution) { ASSERT_TRUE(ProcessAsset(dependency, { { ".asset1", ".asset2" }, { ".asset3" } }, {})); } - + // ---------- Verify that path has been found and resolved ---------- dependencyContainer.clear(); ASSERT_TRUE(m_sharedConnection->GetProductDependencies(dependencyContainer)); - VerifyDependencies(dependencyContainer, + VerifyDependencies(dependencyContainer, { dependencySources[0].m_products[0], dependencySources[0].m_products[1], @@ -1780,19 +1786,19 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_DeferredPathResolutionAlreadyReso // create dependees TestAsset dep1("dep1"); TestAsset dep2("deP2"); // random casing to make sure the search is case-insensitive - + ASSERT_TRUE(ProcessAsset(dep1, { {".asset1"}, {".asset2"} })); ASSERT_TRUE(ProcessAsset(dep2, { {".asset1", ".asset2"}, {".asset3"} })); - + // -------- Make main test asset, with dependencies on products we just created ----- TestAsset primaryFile("test_text"); ASSERT_TRUE(ProcessAsset(primaryFile, { { ".asset" }, {} }, { {"dep1.txt", ProductPathDependencyType::SourceFile}, {"DEP2.asset2", ProductPathDependencyType::ProductFile}, {"Dep2.asset3", ProductPathDependencyType::ProductFile} })); - + // ---------- Verify that the dependency was recorded, and did not keep the path after resolution ---------- AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; ASSERT_TRUE(m_sharedConnection->GetProductDependencies(dependencyContainer)); - VerifyDependencies(dependencyContainer, + VerifyDependencies(dependencyContainer, { dep1.m_products[0], dep1.m_products[1], @@ -1887,13 +1893,13 @@ TEST_F(PathDependencyTest, WildcardDependencies_Existing_ResolveCorrectly) bool result = ProcessAsset(dep1, { {".asset1"}, {".asset2"} }); ASSERT_TRUE(result) << "Failed to Process Assets"; - + result = ProcessAsset(dep2, { {".asset1", ".asset2"}, {".asset3"} }); ASSERT_TRUE(result) << "Failed to Process Assets"; - + result = ProcessAsset(dep3, { {".asset1", ".asset2"}, {".asset3"} }); ASSERT_TRUE(result) << "Failed to Process Assets"; - + result = ProcessAsset(dep4, { {".asset1"}, {".asset3"} }); // This product will match on both dependencies, this will check to make sure we don't get duplicates ASSERT_TRUE(result) << "Failed to Process Assets"; @@ -1906,7 +1912,7 @@ TEST_F(PathDependencyTest, WildcardDependencies_Existing_ResolveCorrectly) AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; result = m_sharedConnection->GetProductDependencies(dependencyContainer); ASSERT_TRUE(result)<< "Failed to Get Product Dependencies"; - + VerifyDependencies(dependencyContainer, { dep1.m_products[0], @@ -2054,14 +2060,14 @@ TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly) AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; ASSERT_TRUE(m_sharedConnection->GetProductDependencies(dependencyContainer)); - VerifyDependencies(dependencyContainer, + VerifyDependencies(dependencyContainer, { dep1.m_products[0], dep1.m_products[1], dep2.m_products[2], dep3.m_products[2], dep4.m_products[0] - }, + }, { "*p1.txt", "*.asset3" } ); } @@ -2204,14 +2210,14 @@ void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, Asset ASSERT_TRUE(ProcessAsset(matchingDepDeeperFolderMixedSlashes, { {".asset"}, {} })) << "Failed to Process " << matchingDepDeeperFolderMixedSlashes.m_name.c_str(); ASSERT_TRUE(ProcessAsset(notMatchingDepInSubfolder, { {".asset"}, {} })) << "Failed to Process " << notMatchingDepInSubfolder.m_name.c_str(); } - + // -------- Make main test asset, with dependencies on products we just created ----- TestAsset primaryFile("test_text"); const char* databaseSeparator = useCorrectDatabaseSeparator ? AZ_CORRECT_DATABASE_SEPARATOR_STRING : AZ_WRONG_DATABASE_SEPARATOR_STRING; - + AZStd::string extension = (pathDependencyType == ProductPathDependencyType::SourceFile) ? "txt" : "asset"; AZStd::string wildcardString = AZStd::string::format("*testFolder%s*.%s", databaseSeparator, extension.c_str()); - + ASSERT_TRUE(ProcessAsset(primaryFile, { { ".asset" }, {} }, { {wildcardString.c_str(), pathDependencyType}, })) << "Failed to Process " << primaryFile.m_name.c_str(); if (!buildDependenciesFirst) @@ -2354,7 +2360,7 @@ TEST_F(PathDependencyTest, AbsoluteDependencies_Deferred_ResolveCorrectly) // -------- Make main test asset, with dependencies on products that don't exist yet ----- TestAsset primaryFile("test_text"); ASSERT_TRUE(ProcessAsset(primaryFile, { { ".asset" }, {} }, - { + { {absPathDep1.toUtf8().constData(), ProductPathDependencyType::SourceFile}, {absPathDep2.toUtf8().constData(), ProductPathDependencyType::SourceFile}, {absPathDep3.toUtf8().constData(), ProductPathDependencyType::SourceFile}, @@ -2418,7 +2424,7 @@ TEST_F(PathDependencyTest, ChangeDependencies_Existing_ResolveCorrectly) // Update again with different dependencies ASSERT_TRUE(ProcessAsset(primaryFile, { {".asset"} , {} }, { {absPath.toUtf8().constData(), ProductPathDependencyType::SourceFile} })); - + // ---------- Verify that the dependency was recorded, and did not keep the path after resolution ---------- dependencyContainer.clear(); ASSERT_TRUE(m_sharedConnection->GetProductDependencies(dependencyContainer)); @@ -2582,7 +2588,7 @@ TEST_F(PathDependencyTest, SourceFileDependencyWithPrefix_Deferred_ResolvesCorre AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntryContainer dependencyContainer; ASSERT_TRUE(m_sharedConnection->GetProductDependencies(dependencyContainer)); - VerifyDependencies(dependencyContainer, + VerifyDependencies(dependencyContainer, { dep2.m_products[0], dep2.m_products[1], @@ -2834,7 +2840,7 @@ TEST_F(AssetProcessorManagerTest, AssetProcessedImpl_DifferentProductDependencie // and correctly stored the results into the dependency table. //-------------------------------- EVALUATION PHASE ------------------------- - // at this point, the AP will have filed the asset away in its database and we can now validate that it actually + // at this point, the AP will have filed the asset away in its database and we can now validate that it actually // did it correctly. // We expect to see two dependencies in the dependency table, each with the correct dependency, no duplicates, no lost data. AssetDatabaseConnection* sharedConnection = m_assetProcessorManager->m_stateData.get(); @@ -2856,7 +2862,7 @@ TEST_F(AssetProcessorManagerTest, AssetProcessedImpl_DifferentProductDependencie // this also asserts uniqueness. ASSERT_EQ(countFound, 2); ASSERT_EQ(capturedTableEntries.size(), countFound); // if they were not unique asset IDs, they would have collapsed on top of each other. - + // make sure both assetIds are present: ASSERT_NE(capturedTableEntries.find(expectedIdOfProductA), capturedTableEntries.end()); ASSERT_NE(capturedTableEntries.find(expectedIdOfProductB), capturedTableEntries.end()); @@ -2927,7 +2933,7 @@ TEST_F(AssetProcessorManagerTest, AssessDeletedFile_OnJobInFlight_IsIgnored) m_isIdling = false; m_assetProcessorManager->AssetProcessed(capturedDetails.m_jobEntry, response); ASSERT_TRUE(BlockUntilIdle(5000)); - + // at this point, everything should be up to date and ready for the test - there should be one source in the database // with numOutputsToSimulate products. // now, we simulate a job running to process the asset again, by modifying the timestamp on the file to be at least one second later. @@ -2959,7 +2965,7 @@ TEST_F(AssetProcessorManagerTest, AssessDeletedFile_OnJobInFlight_IsIgnored) ASSERT_FALSE(capturedDetails.m_destinationPath.isEmpty()); // ----------------------------- TEST BEGINS HERE ----------------------------- // simulte a very slow computer processing the file one output at a time and feeding file change notifies: - + // FROM THIS POINT ON we should see no new job create / cancellation or anything since we're just going to be messing with the cache. bool gotUnexpectedAssetToProcess = false; connection = QObject::connect(m_assetProcessorManager.get(), &AssetProcessorManager::AssetToProcess, [&gotUnexpectedAssetToProcess](JobDetails /*jobDetails*/) @@ -2994,7 +3000,7 @@ TEST_F(AssetProcessorManagerTest, AssessDeletedFile_OnJobInFlight_IsIgnored) QString fileNameToGenerate = QString("test%1.txt").arg(outputIdx); QString filePathToGenerate = QDir(capturedDetails.m_destinationPath).absoluteFilePath(fileNameToGenerate); - + JobProduct product(filePathToGenerate.toUtf8().constData(), AZ::Uuid::CreateRandom(), static_cast(outputIdx)); response.m_outputProducts.push_back(product); @@ -3005,7 +3011,7 @@ TEST_F(AssetProcessorManagerTest, AssessDeletedFile_OnJobInFlight_IsIgnored) // simulate the file watcher showing the deletion occuring: notifyAPM("AssessDeletedFile", filePathToGenerate, shouldBlockAndWaitThisTime); UnitTestUtils::CreateDummyFile(filePathToGenerate, "an output"); - + // let the APM go for a significant amount of time so that it simulates a slow thread copying a large file with lots of events about it pouring in. for (int repeatLoop = 0; repeatLoop < 100; ++repeatLoop) { @@ -3020,7 +3026,7 @@ TEST_F(AssetProcessorManagerTest, AssessDeletedFile_OnJobInFlight_IsIgnored) QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, QString(filePathToGenerate))); QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents, 1); ASSERT_FALSE(gotUnexpectedAssetToProcess); - + // now tell it to stop ignoring the cache delete and let it do the next one. EBUS_EVENT(AssetProcessor::ProcessingJobInfoBus, EndCacheFileUpdate, filePathToGenerate.toUtf8().data(), false); @@ -3075,7 +3081,7 @@ TEST_F(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_BasicTest // each file we will take a different approach to publishing: rel path, and UUID: job.m_sourceFileDependencies.push_back(AZStd::make_pair(dummyBuilderUUID, { "a.txt", AZ::Uuid::CreateNull() })); job.m_sourceFileDependencies.push_back(AZStd::make_pair(dummyBuilderUUID, { "", uuidOfB })); - + // it is currently assumed that the only fields that we care about in JobDetails is the builder busId and the job dependencies themselves: JobDetails newDetails; newDetails.m_assetBuilderDesc.m_busId = dummyBuilderUUID; @@ -3267,7 +3273,7 @@ TEST_F(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_MissingFi // this indirectly verifies the QueryAbsolutePathDependenciesRecursive function also but it has its own dedicated tests, above. AssetProcessor::SourceFilesForFingerprintingContainer deps; m_assetProcessorManager.get()->QueryAbsolutePathDependenciesRecursive(QString::fromUtf8("assetProcessorManagerTest.txt"), deps, AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceToSource, false); - + // we should find all of the deps, but not the placeholders. EXPECT_EQ(deps.size(), 2); @@ -3453,7 +3459,7 @@ TEST_F(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_MissingFi EXPECT_EQ(deps.size(), 2); EXPECT_NE(deps.find(absPath.toUtf8().constData()), deps.end()); EXPECT_NE(deps.find(dependsOnFile1_Job.toUtf8().constData()), deps.end()); // c - + // in addition, we expect to have the original file that depends on B appear in the analysis queue, since something it depends on appeared: QString normalizedSourcePath = AssetUtilities::NormalizeFilePath(absPath); EXPECT_TRUE(m_assetProcessorManager->m_alreadyActiveFiles.contains(normalizedSourcePath)); @@ -4407,7 +4413,7 @@ TEST_F(AssetProcessorManagerTest, SourceFileProcessFailure_ClearsFingerprint) ASSERT_TRUE(found); ASSERT_NE(source.m_analysisFingerprint, ""); - + // Modify the file and run it through AP again, but this time signal a failure { @@ -4655,12 +4661,12 @@ TEST_F(ModtimeScanningTest, ModtimeSkipping_EnablePlatform_ShouldProcessFilesFor // Enable the features we're testing m_assetProcessorManager->m_allowModtimeSkippingFeature = true; AssetUtilities::SetUseFileHashOverride(true, true); - + // Enable es3 platform after the initial SetUp has already processed the files for pc QDir tempPath(m_tempDir.path()); AssetBuilderSDK::PlatformInfo es3Platform("es3", { "host", "renderer" }); m_config->EnablePlatform(es3Platform, true); - + // There's no way to remove scanfolders and adding a new one after enabling the platform will cause the pc assets to build as well, which we don't want // Instead we'll just const cast the vector and modify the enabled platforms for the scanfolder auto& platforms = const_cast&>(m_config->GetScanFolderAt(0).GetPlatforms()); @@ -4743,7 +4749,7 @@ TEST_F(ModtimeScanningTest, ModtimeSkipping_ModifyFile) using namespace AzToolsFramework::AssetSystem; SetFileContents(m_data->m_absolutePath[1].toUtf8().constData(), "hello world"); - + // Enable the features we're testing m_assetProcessorManager->m_allowModtimeSkippingFeature = true; AssetUtilities::SetUseFileHashOverride(true, true); @@ -4861,7 +4867,7 @@ TEST_F(ModtimeScanningTest, ModtimeSkipping_DeleteFile) { QCoreApplication::processEvents(QEventLoop::AllEvents, 10); } while (m_data->m_deletedSources.size() < m_data->m_relativePathFromWatchFolder[0].size() && timer.elapsed() < 5000); - + ASSERT_EQ(m_data->m_mockBuilderInfoHandler.m_createJobsCount, 0); ASSERT_EQ(m_data->m_processResults.size(), 0); ASSERT_THAT(m_data->m_deletedSources, testing::ElementsAre(m_data->m_relativePathFromWatchFolder[0])); @@ -4885,7 +4891,7 @@ TEST_F(ModtimeScanningTest, ReprocessRequest_SourceWithDependency_BothWillProces using SourceFileDependencyEntry = AzToolsFramework::AssetDatabase::SourceFileDependencyEntry; - SourceFileDependencyEntry newEntry1; + SourceFileDependencyEntry newEntry1; newEntry1.m_sourceDependencyID = AzToolsFramework::AssetDatabase::InvalidEntryId; newEntry1.m_builderGuid = AZ::Uuid::CreateRandom(); newEntry1.m_source = m_data->m_absolutePath[0].toUtf8().constData(); @@ -4953,7 +4959,7 @@ void MockBuilderInfoHandler::CreateJobs(const AssetBuilderSDK::CreateJobsRequest if (!m_jobDependencyFilePath.isEmpty()) { - jobDescriptor.m_jobDependencyList.push_back(AssetBuilderSDK::JobDependency("Mock Job", "pc", AssetBuilderSDK::JobDependencyType::Order, + jobDescriptor.m_jobDependencyList.push_back(AssetBuilderSDK::JobDependency("Mock Job", "pc", AssetBuilderSDK::JobDependencyType::Order, AssetBuilderSDK::SourceFileDependency(m_jobDependencyFilePath.toUtf8().constData(), AZ::Uuid::CreateNull()))); } @@ -5127,7 +5133,7 @@ TEST_F(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_WildcardM m_assetProcessorManager.get()->m_stateData->QueryDependsOnSourceBySourceDependency("wildcardTest.txt", nullptr, AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceLikeMatch, callbackFunction); EXPECT_EQ(wildcardDeps.size(), 2); - // The database should have the wildcard record and the individual dependency on b and c at this point, now we add new files + // The database should have the wildcard record and the individual dependency on b and c at this point, now we add new files ASSERT_TRUE(UnitTestUtils::CreateDummyFile(dependsOnFileb1_Source, QString("tempdata\n"))); ASSERT_TRUE(UnitTestUtils::CreateDummyFile(dependsOnFilec1_Job, QString("tempdata\n"))); @@ -5307,7 +5313,7 @@ TEST_F(DuplicateProductsTest, SameSource_MultipleBuilder_DuplicateProductJobs_Em QDir tempPath(m_tempDir.path()); QString sourceFile; AZStd::vector jobDetails; - + ProcessJobResponse response; SetupDuplicateProductsTest(sourceFile, tempPath, productFile, jobDetails, response, false, "txt"); @@ -5397,7 +5403,7 @@ void JobDependencyTest::SetUp() m_data->m_mockBuilderInfoHandler.BusConnect(); QDir tempPath(m_tempDir.path()); - + QString watchFolderPath = tempPath.absoluteFilePath("subfolder1"); const ScanFolderInfo* scanFolder = m_config->GetScanFolderByPath(watchFolderPath); @@ -5460,7 +5466,7 @@ TEST_F(JobDependencyTest, JobDependency_ThatWasJustRun_IsFound) TEST_F(JobDependencyTest, JobDependency_ThatHasNotRun_IsNotFound) { AZStd::vector capturedDetails; - + capturedDetails.clear(); m_data->m_mockBuilderInfoHandler.m_jobDependencyFilePath = "c.txt"; CaptureJobs(capturedDetails, "subfolder1/b.txt"); @@ -5654,7 +5660,7 @@ TEST_F(ChainJobDependencyTest, TestChainDependency_Multi) { QCoreApplication::processEvents(QEventLoop::AllEvents, 10); } while (finishedJobs.size() < capturedDetails.size() && timer.elapsed() < 5000); - + ASSERT_EQ(finishedJobs.size(), capturedDetails.size()); // Test that the jobs completed in the correct order (captureDetails has the correct ordering) @@ -5775,7 +5781,7 @@ TEST_F(DeleteTest, DeleteFolderSharedAcrossTwoScanFolders_CorrectFileAndFolderAr QDir tempPath(m_tempDir.path()); QString absPath(tempPath.absoluteFilePath("subfolder1/textures")); QDir(absPath).removeRecursively(); - + AZStd::vector deletedFolders; QObject::connect(m_assetProcessorManager.get(), &AssetProcessorManager::SourceFolderDeleted, [&deletedFolders](QString file) { diff --git a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp index e066a5e289..24f028a3a7 100644 --- a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp @@ -15,7 +15,7 @@ #include -const char TestAppRoot[] = ":/testdata"; +const char TestAppRoot[] = "@exefolder@/testdata"; const char EmptyDummyProjectName[] = "EmptyDummyProject"; const char DummyProjectName[] = "DummyProject"; @@ -54,10 +54,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_BadPlatform) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_broken_badplatform"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_badplatform"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -67,10 +69,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_NoPlatform) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_broken_noplatform"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_noplatform"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -79,10 +83,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_NoScanFolders) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_broken_noscans"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_noscans"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -91,10 +97,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_BrokenRecognizers) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_broken_recognizers"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_recognizers"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -103,10 +111,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Regular_Platforms) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_regular"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); // verify the data. @@ -127,42 +137,43 @@ TEST_F(PlatformConfigurationUnitTests, TestReadScanFolderRoot_FromSettingsRegist auto settingsRegistry = AZ::SettingsRegistry::Get(); ASSERT_NE(nullptr, settingsRegistry); - AZ::SettingsRegistryInterface::Specializations apSpecializations; - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(*settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, apSpecializations); - - struct ScanFolderVisitor - : AZ::SettingsRegistryInterface::Visitor + QTemporaryDir tempEngineRoot; + QDir tempPath(tempEngineRoot.path()); + QString testScanFolderSetregPath = tempPath.absoluteFilePath("test.setreg"); + UnitTestUtils::CreateDummyFile(testScanFolderSetregPath, QString(R"({ "Amazon": { - void Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) - { - if (valueName == "recursive") - { - m_isRecursive = value != 0; - } - else if (valueName == "order") - { - m_scanOrder = value; - } - } - void Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) + "AssetProcessor": { - if (valueName == "watch") - { - m_watchPath = value; + "Settings": + { + "ScanFolder SettingsRegistryTest": + { + "watch": "_TestPath", + "recursive": false, + "order": 20000 + } } } - AZ::SettingsRegistryInterface::FixedValueString m_watchPath; - bool m_isRecursive{}; - int m_scanOrder{}; - }; + } + }\n)")); + + EXPECT_TRUE(AssetProcessor::PlatformConfiguration::MergeConfigFileToSettingsRegistry(*settingsRegistry, testScanFolderSetregPath.toUtf8().data())); - ScanFolderVisitor scanFolderVisitor; - EXPECT_TRUE(settingsRegistry->Visit(scanFolderVisitor, "/Amazon/AssetProcessor/Settings/ScanFolder Root")); + AZStd::string watchPath; + bool recurseScanFolder{ true }; + AZ::s64 scanOrder{}; + + EXPECT_TRUE(settingsRegistry->Get(watchPath, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey) + + "/ScanFolder SettingsRegistryTest/watch")); + EXPECT_TRUE(settingsRegistry->Get(recurseScanFolder, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey) + + "/ScanFolder SettingsRegistryTest/recursive")); + EXPECT_TRUE(settingsRegistry->Get(scanOrder, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey) + + "/ScanFolder SettingsRegistryTest/order")); // These test values come from the /Engine/Registry/AssetProcessorPlatformConfig.setreg file - EXPECT_STREQ("@ROOT@", scanFolderVisitor.m_watchPath.c_str()); - EXPECT_FALSE(scanFolderVisitor.m_isRecursive); - EXPECT_EQ(10000, scanFolderVisitor.m_scanOrder); + EXPECT_STREQ("_TestPath", watchPath.c_str()); + EXPECT_FALSE(recurseScanFolder); + EXPECT_EQ(20000, scanOrder); } @@ -340,34 +351,36 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolder) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_regular"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + AssetUtilities::ComputeProjectName(EmptyDummyProjectName, true); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 3); // the two, and then the one that has the same data as prior but different identifier. - QString scanName = AssetUtilities::ComputeGameName() + " Scan Folder"; + QString scanName = AssetUtilities::ComputeProjectPath() + " Scan Folder"; ASSERT_EQ(config.GetScanFolderAt(0).GetDisplayName(), scanName); ASSERT_EQ(config.GetScanFolderAt(0).GetOutputPrefix(), QString()); ASSERT_EQ(config.GetScanFolderAt(0).RecurseSubFolders(), true); ASSERT_EQ(config.GetScanFolderAt(0).GetOrder(), 0); - // its important that this does NOT change and this makes sure the old way of doing it (case-sensitive name) persists - ASSERT_EQ(config.GetScanFolderAt(0).GetPortableKey(), QString("from-ini-file-Game")); + ASSERT_EQ(config.GetScanFolderAt(0).GetPortableKey(), QString("Game")); ASSERT_EQ(config.GetScanFolderAt(1).GetDisplayName(), QString("FeatureTests")); ASSERT_EQ(config.GetScanFolderAt(1).GetOutputPrefix(), QString("featuretestsoutputfolder")); // to prove its not related to display name ASSERT_EQ(config.GetScanFolderAt(1).RecurseSubFolders(), false); ASSERT_EQ(config.GetScanFolderAt(1).GetOrder(), 5000); // this proves that the featuretests name is used instead of the output prefix - ASSERT_EQ(config.GetScanFolderAt(1).GetPortableKey(), QString("from-ini-file-FeatureTests")); + ASSERT_EQ(config.GetScanFolderAt(1).GetPortableKey(), QString("FeatureTests")); ASSERT_EQ(config.GetScanFolderAt(2).GetDisplayName(), QString("FeatureTests2")); ASSERT_EQ(config.GetScanFolderAt(2).GetOutputPrefix(), QString("featuretestsoutputfolder")); // to prove its not related to display name ASSERT_EQ(config.GetScanFolderAt(2).RecurseSubFolders(), false); ASSERT_EQ(config.GetScanFolderAt(2).GetOrder(), 6000); // this proves that the featuretests name is used instead of the output prefix - ASSERT_EQ(config.GetScanFolderAt(2).GetPortableKey(), QString("from-ini-file-FeatureTests2")); + ASSERT_EQ(config.GetScanFolderAt(2).GetPortableKey(), QString("FeatureTests2")); } TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolderPlatformSpecific) @@ -375,10 +388,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolderP using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_regular_platform_scanfolder"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular_platform_scanfolder"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 5); @@ -419,10 +434,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_regular"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_TRUE(config.IsFileExcluded("blahblah/$tmp_01.test")); @@ -446,10 +463,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Recognizers) const char* platformWhichIsNotCurrentPlatform = "pc"; #endif - const char* configRoot = ":/testdata/config_regular"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -519,11 +538,13 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Overrides) { using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_regular"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, DummyProjectName, false, false)); + + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), DummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -565,7 +586,7 @@ TEST_F(PlatformConfigurationUnitTests, Test_GemHandling) QTemporaryDir tempEngineRoot; QDir tempPath(tempEngineRoot.path()); AssetUtilities::ResetAssetRoot(); - AssetUtilities::ComputeGameName("SamplesProject", true); + AssetUtilities::ComputeProjectName("SamplesProject", true); QDir computedEngineRoot; ASSERT_TRUE(AssetUtilities::ComputeAssetRoot(computedEngineRoot, &tempPath)); @@ -576,9 +597,11 @@ TEST_F(PlatformConfigurationUnitTests, Test_GemHandling) ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("Gems/LyShine/AssetProcessorGemConfig.ini"), ";nothing to see here")); // note that it is expected that the gems system gives us absolute paths. - AZStd::vector fakeGems; - fakeGems.push_back({ "LyShine", "Gems/LyShine", tempPath.absoluteFilePath("Gems/LyShine").toUtf8().constData(), "0fefab3f13364722b2eab3b96ce2bf20", true, false });// true = pretend this is a game gem. - fakeGems.push_back({ "LmbrCentral", "Gems/LmbrCentral/v2", tempPath.absoluteFilePath("Gems/LmbrCentral/v2").toUtf8().constData(), "ff06785f7145416b9d46fde39098cb0c", false, false }); + AZStd::vector fakeGems; + fakeGems.emplace_back("LyShine");// true = pretend this is a game gem. + fakeGems.back().m_absoluteSourcePaths.push_back(tempPath.absoluteFilePath("Gems/LyShine").toUtf8().constData()); + fakeGems.emplace_back("LmbrCentral"); + fakeGems.back().m_absoluteSourcePaths.push_back(tempPath.absoluteFilePath("Gems/LmbrCentral/v2").toUtf8().constData()); // reading gems via the Gems System is already to be tested in the actual Gems API tests. // to avoid trying to load those DLLs we avoid calling the actual ReadGems function @@ -593,8 +616,7 @@ TEST_F(PlatformConfigurationUnitTests, Test_GemHandling) EXPECT_TRUE(config.GetScanFolderAt(0).GetOutputPrefix().isEmpty()); EXPECT_TRUE(config.GetScanFolderAt(0).RecurseSubFolders()); // the first one is a game gem, so its order should be above 1 but below 100. - EXPECT_GE(config.GetScanFolderAt(0).GetOrder(), 1); - EXPECT_LE(config.GetScanFolderAt(0).GetOrder(), 100); + EXPECT_GE(config.GetScanFolderAt(0).GetOrder(), 100); EXPECT_EQ(0, config.GetScanFolderAt(0).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive)); // for each gem, there are currently 1 scan folder, the gem assets folder, with no output prefix @@ -618,15 +640,17 @@ TEST_F(PlatformConfigurationUnitTests, Test_MetaFileTypes) ASSERT_TRUE(QString::compare(config.GetMetaDataFileTypeAt(1).second, "zzzz", Qt::CaseInsensitive) == 0); } -TEST_F(PlatformConfigurationUnitTests, ReadCheckSever_FromConfig_Valid) +TEST_F(PlatformConfigurationUnitTests, ReadCheckServer_FromConfig_Valid) { using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; - const char* configRoot = ":/testdata/config_regular"; + const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); + ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot, TestAppRoot, EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -642,7 +666,11 @@ TEST_F(PlatformConfigurationUnitTests, PlatformConfigFile_IsPresent_Found) QTemporaryDir tempEngineRoot; QDir tempPath(tempEngineRoot.path()); AssetUtilities::ResetAssetRoot(); - AssetUtilities::ComputeGameName("SamplesProject", true); + AssetUtilities::ComputeProjectName("SamplesProject", true); + + auto settingsRegistry = AZ::SettingsRegistry::Get(); + ASSERT_NE(nullptr, settingsRegistry); + settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder, tempPath.absolutePath().toUtf8().constData()); QDir computedEngineRoot; ASSERT_TRUE(AssetUtilities::ComputeAssetRoot(computedEngineRoot, &tempPath)); @@ -655,7 +683,7 @@ TEST_F(PlatformConfigurationUnitTests, PlatformConfigFile_IsPresent_Found) platformConfigPath.append("TestPlatform/"); platformConfigPath.append(AssetProcessor::AssetProcessorPlatformConfigFileName); - QStringList platformConfigList; + AZStd::vector platformConfigList; ASSERT_FALSE(config.AddPlatformConfigFilePaths(platformConfigList)); ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath(platformConfigPath), ";nothing to see here")); ASSERT_TRUE(config.AddPlatformConfigFilePaths(platformConfigList)); diff --git a/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp b/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp index b2badf7b52..5ed392d12b 100644 --- a/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp @@ -13,6 +13,8 @@ #include #include "native/tests/AssetProcessorTest.h" +#include +#include #include #include @@ -519,11 +521,18 @@ TEST_F(AssetUtilitiesTest, GetServerAddress_ReadFromConfig_Valid) QTemporaryDir tempDir; QDir tempPath(tempDir.path()); QString assetServerAddress("T:/AssetServerCacheDummyFolder"); - UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("AssetProcessorPlatformConfig.ini"), QString("[Server]\ncacheServerAddress=%1\n").arg(assetServerAddress)); + QString assetProcesorPlatformConfigPath = tempPath.absoluteFilePath("AssetProcessorPlatformConfig.ini"); + UnitTestUtils::CreateDummyFile(assetProcesorPlatformConfigPath, QString("[Server]\ncacheServerAddress=%1\n").arg(assetServerAddress)); AssetUtilities::ResetAssetRoot(); QDir newRoot; AssetUtilities::ComputeEngineRoot(newRoot, &tempPath); + + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings; + configParserSettings.m_registryRootPointerPath = AssetProcessor::AssetProcessorSettingsKey; + AssetProcessor::PlatformConfiguration::MergeConfigFileToSettingsRegistry(*settingsRegistry, + assetProcesorPlatformConfigPath.toUtf8().data()); QString assetServerAddressReturned = AssetUtilities::ServerAddress(); EXPECT_STREQ(assetServerAddressReturned.toUtf8().data(), assetServerAddress.toUtf8().data()); } diff --git a/Code/Tools/AssetProcessor/native/ui/MainWindow.cpp b/Code/Tools/AssetProcessor/native/ui/MainWindow.cpp index 5fabd49892..3a874a464c 100644 --- a/Code/Tools/AssetProcessor/native/ui/MainWindow.cpp +++ b/Code/Tools/AssetProcessor/native/ui/MainWindow.cpp @@ -136,7 +136,7 @@ void MainWindow::Activate() ui->projectLabel->setText(QStringLiteral("%1: %2") .arg(tr("Project")) - .arg(m_guiApplicationManager->GetGameName())); + .arg(QDir{m_guiApplicationManager->GetProjectPath()}.absolutePath())); ui->rootLabel->setText(QStringLiteral("%1: %2") .arg(tr("Root")) diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/AssetCatalogUnitTests.cpp deleted file mode 100644 index ad5a58a5ea..0000000000 --- a/Code/Tools/AssetProcessor/native/unittests/AssetCatalogUnitTests.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/* -* 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. -* -*/ -#if defined(UNIT_TEST) - -#include - -#include "AssetCatalogUnitTests.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AssetProcessor -{ - using namespace UnitTestUtils; - using namespace AzFramework::AssetSystem; - using namespace AzToolsFramework::AssetSystem; - using namespace AzToolsFramework::AssetDatabase; - - REGISTER_UNIT_TEST(AssetCatalogUnitTests) - REGISTER_UNIT_TEST(AssetCatalogUnitTests_AssetInfo) - - namespace - { - - // a utility class to redirect the location the database is stored to a different location so that we don't - // touch real data during unit tests. - class FakeDatabaseLocationListener - : protected AzToolsFramework::AssetDatabase::AssetDatabaseRequests::Bus::Handler - { - public: - FakeDatabaseLocationListener(const char* desiredLocation, const char* assetPath) - : m_location(desiredLocation) - , m_assetPath(assetPath) - { - AzToolsFramework::AssetDatabase::AssetDatabaseRequests::Bus::Handler::BusConnect(); - } - ~FakeDatabaseLocationListener() - { - AzToolsFramework::AssetDatabase::AssetDatabaseRequests::Bus::Handler::BusDisconnect(); - } - protected: - // IMPLEMENTATION OF -------------- AzToolsFramework::AssetDatabase::AssetDatabaseRequests::Bus::Listener - bool GetAssetDatabaseLocation(AZStd::string& location) override - { - location = m_location; - return true; - } - - // ------------------------------------------------------------ - - private: - AZStd::string m_location; - AZStd::string m_assetPath; - }; - - // Adds a scan folder to the config and to the database - void AddScanFolder(const ScanFolderInfo& scanFolderInfo, PlatformConfiguration& config, AssetDatabaseConnection* dbConn) - { - config.AddScanFolder(scanFolderInfo); - ScanFolderDatabaseEntry newScanFolder( - scanFolderInfo.ScanPath().toStdString().c_str(), - scanFolderInfo.GetDisplayName().toStdString().c_str(), - scanFolderInfo.GetPortableKey().toStdString().c_str(), - scanFolderInfo.GetOutputPrefix().toStdString().c_str(), - scanFolderInfo.IsRoot()); - dbConn->SetScanFolder(newScanFolder); - } - - void BuildConfig(const QDir& tempPath, AssetDatabaseConnection* dbConn, PlatformConfiguration& config) - { - config.EnablePlatform({ "pc" ,{ "desktop", "renderer" } }, true); - config.EnablePlatform({ "es3" ,{ "mobile", "renderer" } }, true); - config.EnablePlatform({ "fandango" ,{ "console", "renderer" } }, false); - AZStd::vector platforms; - config.PopulatePlatformsForScanFolder(platforms); - // PATH DisplayName PortKey outputfolder root recurse platforms order - AddScanFolder(ScanFolderInfo(tempPath.filePath("subfolder4"), "subfolder4", "subfolder4", "", false, false, platforms, -6), config, dbConn); // subfolder 4 overrides subfolder3 - AddScanFolder(ScanFolderInfo(tempPath.filePath("subfolder3"), "subfolder3", "subfolder3", "", false, false, platforms, -5), config, dbConn); // subfolder 3 overrides subfolder2 - AddScanFolder(ScanFolderInfo(tempPath.filePath("subfolder2"), "subfolder2", "subfolder2", "", false, true, platforms, -2), config, dbConn); // subfolder 2 overrides subfolder1 - AddScanFolder(ScanFolderInfo(tempPath.filePath("subfolder1"), "subfolder1", "subfolder1", "editor", false, true, platforms, -1), config, dbConn); // subfolder1 overrides root - AddScanFolder(ScanFolderInfo(tempPath.absolutePath(), "temp", "tempfolder", "", true, false, platforms, 0), config, dbConn); // add the root - - config.AddMetaDataType("exportsettings", QString()); - - AZ::Uuid buildIDRcLegacy; - BUILDER_ID_RC.GetUuid(buildIDRcLegacy); - - AssetRecognizer rec; - AssetPlatformSpec specpc; - AssetPlatformSpec speces3; - - speces3.m_extraRCParams = "somerandomparam"; - rec.m_name = "random files"; - rec.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.random", AssetBuilderSDK::AssetBuilderPattern::Wildcard); - rec.m_platformSpecs.insert("pc", specpc); - config.AddRecognizer(rec); - - specpc.m_extraRCParams = ""; // blank must work - speces3.m_extraRCParams = "testextraparams"; - - const char* builderTxt1Name = "txt files"; - rec.m_name = builderTxt1Name; - rec.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.txt", AssetBuilderSDK::AssetBuilderPattern::Wildcard); - rec.m_platformSpecs.insert("pc", specpc); - rec.m_platformSpecs.insert("es3", speces3); - - config.AddRecognizer(rec); - - // Ignore recognizer - AssetPlatformSpec ignore_spec; - ignore_spec.m_extraRCParams = "skip"; - AssetRecognizer ignore_rec; - ignore_rec.m_name = "ignore files"; - ignore_rec.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("*.ignore", AssetBuilderSDK::AssetBuilderPattern::Wildcard); - ignore_rec.m_platformSpecs.insert("pc", specpc); - ignore_rec.m_platformSpecs.insert("es3", ignore_spec); - config.AddRecognizer(ignore_rec); - - ExcludeAssetRecognizer excludeRecogniser; - excludeRecogniser.m_name = "backup"; - excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); - config.AddExcludeRecognizer(excludeRecogniser); - } - - // Adds a source file and job entry to the database, jobId is output - bool AddSourceAndJob(const char* scanFolder, const char* sourceRelPath, AssetDatabaseConnection* dbConn, AZ::s64& jobId, AZ::Uuid assetId = AZ::Uuid::CreateRandom()) - { - ScanFolderDatabaseEntry scanFolderEntry; - bool result = dbConn->GetScanFolderByPortableKey(scanFolder, scanFolderEntry); - - if(!result) - { - return false; - } - - SourceDatabaseEntry sourceEntry(scanFolderEntry.m_scanFolderID, sourceRelPath, assetId, "fingerprint"); - dbConn->SetSource(sourceEntry); - - JobDatabaseEntry jobEntry(sourceEntry.m_sourceID, "test", 1234, "pc", assetId, AzToolsFramework::AssetSystem::JobStatus::Completed, 12345); - dbConn->SetJob(jobEntry); - - jobId = jobEntry.m_jobID; - return true; - }; - - // Calls the GetRelativeProductPathFromFullSourceOrProductPath function and checks the return results, returning true if it matches both of the expected results - bool TestGetRelativeProductPath(const QString fileToCheck, bool expectedToFind, AZStd::initializer_list expectedPaths) - { - bool relPathfound = false; - AZStd::string relPath; - AZStd::string fullPath(fileToCheck.toStdString().c_str()); - - EBUS_EVENT_RESULT(relPathfound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullPath, relPath); - - if (relPathfound != expectedToFind) - { - return false; - } - - for (auto& path : expectedPaths) - { - if (relPath == path) - { - return true; - } - } - - return false; - } - - // Calls the GetFullSourcePathFromRelativeProductPath function and checks the return results, returning true if it matches both of the expected results - bool TestGetFullSourcePath(const QString& fileToCheck, const QDir& tempPath, bool expectToFind, const char* expectedPath) - { - bool fullPathfound = false; - AZStd::string fullPath; - AZStd::string relPath(fileToCheck.toStdString().c_str()); - - EBUS_EVENT_RESULT(fullPathfound, AzToolsFramework::AssetSystemRequestBus, GetFullSourcePathFromRelativeProductPath, relPath, fullPath); - - if (fullPathfound != expectToFind) - { - return false; - } - - QString output(fullPath.c_str()); - output.remove(0, tempPath.path().length() + 1); //adding one for the native separator - - return (output == expectedPath); - } - - } // end anon namespace - - void AssetCatalogUnitTests::StartTest() - { - QDir oldRoot; - AssetUtilities::ComputeAssetRoot(oldRoot); - AssetUtilities::ResetAssetRoot(); - - // the canonicalization of the path here is to get around the fact that on some platforms - // the "temporary" folder location could be junctioned into some other folder and getting "QDir::current()" - // and other similar functions may actually return a different string but still be referring to the same folder - QTemporaryDir dir; - QDir tempPath(dir.path()); - QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath()); - UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath); - tempPath = QDir(canonicalTempDirPath); - NetworkRequestID requestId(1, 1); - - FakeDatabaseLocationListener listener(tempPath.filePath("statedatabase.sqlite").toUtf8().constData(), "displayString"); - - AZStd::unique_ptr dbConn = AZStd::make_unique(); - dbConn->OpenDatabase(); - - CreateDummyFile(tempPath.absoluteFilePath("bootstrap.cfg"), QString("sys_game_folder=SamplesProject\n")); - - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(); - - // update the engine root - AssetUtilities::ResetAssetRoot(); - QDir newRoot; - AssetUtilities::ComputeAssetRoot(newRoot, &tempPath); - - UNIT_TEST_EXPECT_FALSE(gameName.isEmpty()); - // should create cache folder in the root, and read everything from there. - - QSet expectedFiles; - // set up some interesting files: - expectedFiles << tempPath.absoluteFilePath("rootfile2.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder1/rootfile1.txt"); // note: Must override the actual root file - expectedFiles << tempPath.absoluteFilePath("subfolder1/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder2/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/bbb/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/bbb/ccc/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/bbb/ccc/ddd/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder3/BaseFile.txt"); // note the case upper here - expectedFiles << tempPath.absoluteFilePath("subfolder8/a/b/c/test.txt"); - - // subfolder3 is not recursive so none of these should show up in any scan or override check - expectedFiles << tempPath.absoluteFilePath("subfolder3/aaa/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder3/aaa/bbb/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder3/aaa/bbb/ccc/basefile.txt"); - - expectedFiles << tempPath.absoluteFilePath("subfolder3/uniquefile.txt"); // only exists in subfolder3 - expectedFiles << tempPath.absoluteFilePath("subfolder3/uniquefile.ignore"); // only exists in subfolder3 - - expectedFiles << tempPath.absoluteFilePath("subfolder3/rootfile3.txt"); // must override rootfile3 in root - expectedFiles << tempPath.absoluteFilePath("rootfile1.txt"); - expectedFiles << tempPath.absoluteFilePath("rootfile3.txt"); - expectedFiles << tempPath.absoluteFilePath("unrecognised.file"); // a file that should not be recognised - expectedFiles << tempPath.absoluteFilePath("unrecognised2.file"); // a file that should not be recognised - expectedFiles << tempPath.absoluteFilePath("subfolder1/test/test.format"); // a file that should be recognised - expectedFiles << tempPath.absoluteFilePath("test.format"); // a file that should NOT be recognised - expectedFiles << tempPath.absoluteFilePath("subfolder3/somefile.xxx"); - expectedFiles << tempPath.absoluteFilePath("subfolder3/savebackup/test.txt");//file that should be excluded - expectedFiles << tempPath.absoluteFilePath("subfolder3/somerandomfile.random"); - - for (const QString& expect : expectedFiles) - { - UNIT_TEST_EXPECT_TRUE(CreateDummyFile(expect)); - AZ_TracePrintf(AssetProcessor::DebugChannel, "Created file %s with msecs %llu\n", expect.toUtf8().constData(), - QFileInfo(expect).lastModified().toMSecsSinceEpoch()); - -#if defined(AZ_PLATFORM_WINDOWS) - QThread::msleep(35); // give at least some milliseconds so that the files never share the same timestamp exactly -#else - // on platforms such as mac, the file time resolution is only a second :( - QThread::msleep(1001); -#endif - } - - PlatformConfiguration config; - BuildConfig(tempPath, dbConn.get(), config); - - AssetCatalog assetCatalog(nullptr, &config); - QDir cacheRoot; - UNIT_TEST_EXPECT_TRUE(AssetUtilities::ComputeProjectCacheRoot(cacheRoot)); - QString normalizedCacheRoot = AssetUtilities::NormalizeDirectoryPath(cacheRoot.absolutePath()); - - // make sure it picked up the one in the current folder - - QString normalizedDirPathCheck = AssetUtilities::NormalizeDirectoryPath(tempPath.absoluteFilePath("Cache/" + gameName)); - UNIT_TEST_EXPECT_TRUE(normalizedCacheRoot == normalizedDirPathCheck); - QDir normalizedCacheRootDir(normalizedCacheRoot); - - // ----- Test the get asset path functions, which given a full path to an asset, checks the mappings and turns it into an Asset ID --- - { - // sanity check - make sure it does not crash or misbehave when given empty names - QString fileToCheck = ""; - { - UnitTestUtils::AssertAbsorber absorb; - // empty requests should generate an assert. - GetRelativeProductPathFromFullSourceOrProductPathRequest request(fileToCheck.toUtf8().constData()); - UNIT_TEST_EXPECT_TRUE(absorb.m_numAssertsAbsorbed == 1); - GetFullSourcePathFromRelativeProductPathRequest sourceRequest(fileToCheck.toUtf8().constData()); - UNIT_TEST_EXPECT_TRUE(absorb.m_numAssertsAbsorbed == 2); - } - - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath("", false, {""})); - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath("", tempPath, false, "")); - - // Add a source file with 4 products - { - AZ::s64 jobId; - bool result = AddSourceAndJob("subfolder3", "BaseFile.txt", dbConn.get(), jobId); - UNIT_TEST_EXPECT_TRUE(result); - - AZ::u32 productSubId = 0; - for (auto& relativeProductPath : { "subfolder3/basefilez.arc2", "subfolder3/basefileaz.azm2", "subfolder3/basefile.arc2", "subfolder3/basefile.azm2" }) - { - ProductDatabaseEntry newProduct(jobId, productSubId++, cacheRoot.relativeFilePath(relativeProductPath).toStdString().c_str(), AZ::Data::AssetType::CreateRandom()); - dbConn->SetProduct(newProduct); - } - } - - // GetRelativeProductPathFromFullSourceOrProductPath has 4 code paths: - // 1) Relative input paths are returned straight away - // 2) Paths inside the cache folder are transformed to product paths, no database involvement - // 3) Source files that have a product return the product path - // 4) Source files that don't have a product return the source file's relative path since that is the path a product might have - - // Failure case -#if defined(AZ_PLATFORM_WINDOWS) - fileToCheck = "d:\\test.txt"; -#else - fileToCheck = "/test.txt"; // rooted -#endif - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, false, { fileToCheck.toStdString().c_str() })); - - // (Case 1) feed it a relative path - fileToCheck = "\test.txt"; - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "\test.txt" })); - - // (Case 2) feed it a product path with gamename - fileToCheck = normalizedCacheRootDir.filePath("pc/" + gameName + "/aaa/basefile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); - - // (Case 2) feed it a product path without gamename - fileToCheck = normalizedCacheRootDir.filePath("pc/basefile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "basefile.txt" })); - - // (Case 2) feed it a product path with gamename but poor casing (test 1: the pc platform is not matching case) - fileToCheck = normalizedCacheRootDir.filePath("Pc/" + gameName + "/aaa/basefile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); - - // (Case 2) feed it a product path with gamename but poor casing (test 2: the gameName is not matching case) - fileToCheck = normalizedCacheRootDir.filePath("pc/" + gameName.toUpper() + "/aaa/basefile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); - - // (Case 2) feed it a product path that resolves to a directory name instead of a file. - fileToCheck = normalizedCacheRootDir.filePath("pc/" + gameName.toUpper() + "/aaa"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa" })); - - // Case 3 - fileToCheck = tempPath.absoluteFilePath("subfolder3/BaseFile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "basefilez.arc2", "basefileaz.azm2", "basefile.arc2", "basefile.azm2" })); - - // Case 4 - fileToCheck = tempPath.absoluteFilePath("subfolder2/aaa/basefile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetRelativeProductPath(fileToCheck, true, { "aaa/basefile.txt" })); - - // ----- Test the ProcessGetFullAssetPath function - { - QStringList pcouts; - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/subfolder3/randomfileoutput.random")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/subfolder3/randomfileoutput.random1")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/subfolder3/randomfileoutput.random2")); - - AZ::s64 jobId; - bool result = AddSourceAndJob("subfolder3", "somerandomfile.random", dbConn.get(), jobId); - UNIT_TEST_EXPECT_TRUE(result); - - AZ::u32 productSubID = 0; - for (auto& product : pcouts) - { - ProductDatabaseEntry newProduct(jobId, productSubID++, cacheRoot.relativeFilePath(product).toStdString().c_str(), AZ::Data::AssetType::CreateRandom()); - dbConn->SetProduct(newProduct); - } - } - - //feed it an relative product, and expect a full, absolute source file path in return. - fileToCheck = "subfolder3/randomfileoutput.random1"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it another relative product - fileToCheck = "subfolder3/randomfileoutput.random2"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it the same relative product with different separators - fileToCheck = "subfolder3\\randomfileoutput.random2"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it a full path - fileToCheck = tempPath.filePath("somefolder/somefile.txt"); - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "somefolder/somefile.txt")); - - //feed it a path with alias and asset id - fileToCheck = "@assets@/subfolder3/randomfileoutput.random1"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it a path with some random alias and asset id - fileToCheck = "@somerandomalias@/subfolder3/randomfileoutput.random1"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it a path with some random alias and asset id but no separator - fileToCheck = "@somerandomalias@subfolder3/randomfileoutput.random1"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it a path with alias and input name - fileToCheck = "@assets@/somerandomfile.random"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it an absolute path with cacheroot - fileToCheck = normalizedCacheRootDir.filePath("pc/" + gameName + "/subfolder3/randomfileoutput.random1"); - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - - //feed it a productName directly - fileToCheck = "pc/" + gameName + "/subfolder3/randomfileoutput.random1"; - UNIT_TEST_EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, tempPath, true, "subfolder3/somerandomfile.random")); - } - - Q_EMIT UnitTestPassed(); - } - - ////////////////////////////////////////////////////////////////////////// - - void AssetCatalogUnitTests_AssetInfo::StartTest() - { - using namespace AZ::Data; - using namespace AzToolsFramework; - - // the canonicalization of the path here is to get around the fact that on some platforms - // the "temporary" folder location could be junctioned into some other folder and getting "QDir::current()" - // and other similar functions may actually return a different string but still be referring to the same folder - QTemporaryDir dir; - QDir tempPath(dir.path()); - QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath()); - UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath); - tempPath = QDir(canonicalTempDirPath); - - CreateDummyFile(tempPath.absoluteFilePath("bootstrap.cfg"), QString("sys_game_folder=SamplesProject\n")); - - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(); - - // update the engine root - AssetUtilities::ResetAssetRoot(); - QDir newRoot; - AssetUtilities::ComputeAssetRoot(newRoot, &tempPath); - QDir cacheRoot; - AssetUtilities::ComputeProjectCacheRoot(cacheRoot); - AZStd::string cacheRootPath = cacheRoot.absolutePath().toStdString().c_str(); - - FakeDatabaseLocationListener listener(tempPath.filePath("statedatabase.sqlite").toUtf8().constData(), "displayString"); - - AZStd::unique_ptr dbConn = AZStd::make_unique(); - dbConn->OpenDatabase(); - - PlatformConfiguration config; - BuildConfig(tempPath, dbConn.get(), config); - - AssetCatalog assetCatalog(nullptr, &config); - - ////////////////////////////////////////////////////////////////////////// - - AssetId assetA(AZ::Uuid::CreateRandom(), 0); - AZ::Uuid assetALegacyUuid = AZ::Uuid::CreateRandom(); - AssetType assetAType = AssetType::CreateRandom(); - AZStd::string assetAFileFilter = "*.source"; - AZStd::string subfolder1AbsolutePath = tempPath.absoluteFilePath("subfolder1").toStdString().c_str(); - AZStd::string assetASourceRelPath = "assetA.source"; - AZStd::string assetASourceDatabasePath = "editor/assetA.source"; - AZStd::string assetAProductRelPath = "editor/assetA.product"; - - AZStd::string assetAFullPath; - AzFramework::StringFunc::Path::Join(subfolder1AbsolutePath.c_str(), assetASourceRelPath.c_str(), assetAFullPath); - CreateDummyFile(QString::fromUtf8(assetAFullPath.c_str()), "Its the Asset A"); // 15 bytes of data - - AZStd::string assetAProductFullPath; - AzFramework::StringFunc::Path::Join(cacheRootPath.c_str(), assetAProductRelPath.c_str(), assetAProductFullPath); - CreateDummyFile(QString::fromUtf8(assetAProductFullPath.c_str()), "Its a product A"); // 15 bytes of data - - auto getAssetInfoById = [assetA, assetAType, subfolder1AbsolutePath](bool expectedResult, AZStd::string expectedRelPath, AZStd::string expectedRootPath, AssetType assetType) -> bool - { - bool result = false; - AssetInfo assetInfo; - AZStd::string rootPath; - AssetSystemRequestBus::BroadcastResult(result, &AssetSystem::AssetSystemRequest::GetAssetInfoById, assetA, assetType, assetInfo, rootPath); - - if (result != expectedResult) - { - return false; - } - - if (expectedResult) - { - return (assetInfo.m_assetId == assetA) - && (assetInfo.m_assetType == assetAType) - && (assetInfo.m_relativePath == expectedRelPath) - && (assetInfo.m_sizeBytes == 15) - && (rootPath == expectedRootPath); - } - - return true; - }; - - auto getAssetInfoByIdPair = [&](bool expectedResult, AZStd::string expectedRelPath, AZStd::string expectedRootPath) -> bool - { - // First test without providing the assetType - bool result = getAssetInfoById(expectedResult, expectedRelPath, expectedRootPath, AssetType::CreateNull()); - - // If successful, test again, this time providing the assetType - if (result) - { - result = getAssetInfoById(expectedResult, expectedRelPath, expectedRootPath, assetAType); - } - - return result; - }; - - auto getSourceInfoBySourcePath = [](bool expectedResult, AZStd::string sourcePath, AZ::Uuid expectedUuid, AZStd::string expectedRelPath, AZStd::string expectedRootPath, AZ::Data::AssetType expectedType = AZ::Data::s_invalidAssetType) -> bool - { - bool result = false; - AssetInfo assetInfo; - AZStd::string rootPath; - AssetSystemRequestBus::BroadcastResult(result, &AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, sourcePath.c_str(), assetInfo, rootPath); - - if (result != expectedResult) - { - return false; - } - - if (expectedResult) - { - return (assetInfo.m_assetId == expectedUuid) - && (assetInfo.m_assetType == expectedType) - && (assetInfo.m_relativePath == expectedRelPath) - && (assetInfo.m_sizeBytes == 15) - && (rootPath == expectedRootPath) - ; - } - - return true; - }; - - //Test 1: Asset not in database - UNIT_TEST_EXPECT_TRUE(getAssetInfoByIdPair(false, "", "")); - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(false, "", AZ::Uuid::CreateNull(), "", "")); - - // Add asset to database - AZ::s64 jobId; - UNIT_TEST_EXPECT_TRUE(AddSourceAndJob("subfolder1", assetASourceDatabasePath.c_str(), dbConn.get(), jobId, assetA.m_guid)); - ProductDatabaseEntry newProductEntry(jobId, 0, assetAProductRelPath.c_str(), assetAType); - dbConn->SetProduct(newProductEntry); - - // Test 2: Asset in database, not registered as source asset - // note that when asking for products, a performance improvement causes the catalog to use its REGISTRY - // rather than the database to ask for products, so to set this up the registry must be present and must have the asset registered within it - AzFramework::AssetSystem::AssetNotificationMessage message(assetAProductRelPath.c_str(), AssetNotificationMessage::AssetChanged, assetAType); - message.m_sizeBytes = 15; - message.m_assetId = AZ::Data::AssetId(assetA.m_guid, 0); - assetCatalog.OnAssetMessage("pc", message); - - // also of note: When looking up products, you don't get a root path since they are all in the cache. - // its important here that we specifically get an empty root path. - UNIT_TEST_EXPECT_TRUE(getAssetInfoByIdPair(true, assetAProductRelPath, "")); - - // this call has to work with full and relative path. - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetASourceRelPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str())); - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetAFullPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str())); - - dbConn->RemoveProductsByJobID(jobId); - - // similar to the above, because its not the DB that is used for products, we have to inform the catalog that its gone - message.m_type = AssetNotificationMessage::AssetRemoved; - assetCatalog.OnAssetMessage("pc", message); - - // Add to queue - assetCatalog.OnSourceQueued(assetA.m_guid, assetALegacyUuid, subfolder1AbsolutePath.c_str(), assetASourceRelPath.c_str()); - - //Test 3: Asset in queue, not registered as source asset - UNIT_TEST_EXPECT_TRUE(getAssetInfoByIdPair(false, "", "")); - - // this call should STILL work even after the above call to "OnSourceQueued" since its explicitly asking for the source details. - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetASourceRelPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str())); - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetAFullPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str())); - - // Register as source type - // note that once this call has been made, ALL REQUESTS for this type of asset should always include an appropriate type (non zero) - ToolsAssetSystemBus::Broadcast(&ToolsAssetSystemRequests::RegisterSourceAssetType, assetAType, assetAFileFilter.c_str()); - - //Test 4: Asset in queue, registered as source asset - UNIT_TEST_EXPECT_TRUE(getAssetInfoByIdPair(true, assetASourceRelPath, subfolder1AbsolutePath)); - - // these calls are identical to the two above, but should continue to work even though we have registered the asset type as a source asset type. - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetASourceRelPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str(), assetAType)); - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetAFullPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str(), assetAType)); - - // Remove from queue - assetCatalog.OnSourceFinished(assetA.m_guid, assetALegacyUuid); - - // Add asset to database - ProductDatabaseEntry assetAEntry(jobId, 0, assetAProductRelPath.c_str(), assetAType); - dbConn->SetProduct(assetAEntry); - - //Test 5: Asset in database, registered as source asset - UNIT_TEST_EXPECT_TRUE(getAssetInfoByIdPair(true, assetASourceRelPath, subfolder1AbsolutePath)); - - // at this point the details about the asset in question is no longer in memory, only the database. However, these calls should continue find the - // information, because the system is supposed check both the database AND the in-memory queue in the to find the info being requested. - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetASourceRelPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str(), assetAType)); - UNIT_TEST_EXPECT_TRUE(getSourceInfoBySourcePath(true, assetAFullPath.c_str(), assetA.m_guid, assetASourceRelPath.c_str(), subfolder1AbsolutePath.c_str(), assetAType)); - - Q_EMIT UnitTestPassed(); - } - -#include -} // namespace AssetProcessor - -#endif diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp index 2cca9ad795..ae68d5f872 100644 --- a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp @@ -15,7 +15,7 @@ #include "AssetProcessorManagerUnitTests.h" #include - +#include #include "MockApplicationManager.h" #include "native/FileWatcher/FileWatcher.h" @@ -56,7 +56,7 @@ namespace AssetProcessor using GetFullSourcePathFromRelativeProductPathResponse = AzFramework::AssetSystem::GetFullSourcePathFromRelativeProductPathResponse; }; - + REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests_ScanFolders) @@ -138,7 +138,7 @@ namespace AssetProcessor AssetUtilities::ComputeAssetRoot(oldRoot); AssetUtilities::ResetAssetRoot(); FileWatcher fileWatcher; - + UNIT_TEST_EXPECT_TRUE(QDir::temp().exists()); QString tmpDirPath = AssetUtilities::NormalizeDirectoryPath(QDir::tempPath()); @@ -153,8 +153,7 @@ namespace AssetProcessor UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath); NetworkRequestID requestId(1, 1); - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(AssetProcessorManagerTestGameProject); + QString gameName = AssetUtilities::ComputeProjectName(AssetProcessorManagerTestGameProject); // update the engine root AssetUtilities::ResetAssetRoot(); @@ -162,6 +161,13 @@ namespace AssetProcessor AssetUtilities::ComputeAssetRoot(newRoot, &tempPath); // create a dummy file in the cache folder, so the folder structure gets created + // Override the cache folder to be the within the temporary directory + auto projectCacheRootKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Set(projectCacheRootKey, tempPath.absoluteFilePath("Cache").toUtf8().data()); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry); + } QDir projectCacheRoot; AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); CreateDummyFile(projectCacheRoot.absoluteFilePath("placeholder.txt")); @@ -343,7 +349,7 @@ namespace AssetProcessor // make sure it picked up the one in the cache and not for example the real working folder - QString normalizedDirPathCheck = AssetUtilities::NormalizeDirectoryPath(QDir(canonicalTempDirPath).absoluteFilePath("Cache/" + gameName)); + QString normalizedDirPathCheck = AssetUtilities::NormalizeDirectoryPath(QDir(canonicalTempDirPath).absoluteFilePath("Cache")); UNIT_TEST_EXPECT_TRUE(normalizedCacheRoot == normalizedDirPathCheck); QDir normalizedCacheRootDir(normalizedCacheRoot); @@ -441,7 +447,7 @@ namespace AssetProcessor QString relativePathFromWatchFolder = "uniquefile.txt"; QString watchFolderPath = tempPath.absoluteFilePath("subfolder3"); QString absolutePath = AssetUtilities::NormalizeFilePath(watchFolderPath + "/" + relativePathFromWatchFolder); - + QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absolutePath)); UNIT_TEST_EXPECT_TRUE(BlockUntil(idling, 5000)); @@ -469,7 +475,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(processResults[checkIdx].m_jobEntry.m_watchFolderPath == AssetUtilities::NormalizeFilePath(watchFolderPath)); UNIT_TEST_EXPECT_TRUE(processResults[checkIdx].m_jobEntry.m_pathRelativeToWatchFolder == "uniquefile.txt"); UNIT_TEST_EXPECT_TRUE(processResults[checkIdx].m_jobEntry.m_databaseSourceName == "uniquefile.txt"); - QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str()) + "/" + gameName.toLower()); + QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str())); platformFolder = AssetUtilities::NormalizeDirectoryPath(platformFolder); UNIT_TEST_EXPECT_TRUE(processResults[checkIdx].m_destinationPath.startsWith(platformFolder)); UNIT_TEST_EXPECT_TRUE(processResults[checkIdx].m_jobEntry.m_computedFingerprint != 0); @@ -659,8 +665,8 @@ namespace AssetProcessor QStringList es3outs; - es3outs.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefile.arc1")); - es3outs.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefile.arc2")); + es3outs.push_back(cacheRoot.filePath(QString("es3/basefile.arc1"))); + es3outs.push_back(cacheRoot.filePath(QString("es3/basefile.arc2"))); // feed it the messages its waiting for (create the files) UNIT_TEST_EXPECT_TRUE(CreateDummyFile(es3outs[0], "products.")); @@ -790,7 +796,7 @@ namespace AssetProcessor assetMessages.clear(); es3outs.clear(); - es3outs.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefile.azm")); + es3outs.push_back(cacheRoot.filePath(QString("es3/basefile.azm"))); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(es3outs[0], "products.")); //Invoke Asset Processed for es3 platform , txt files2 job description @@ -815,7 +821,7 @@ namespace AssetProcessor assetMessages.clear(); QStringList pcouts; - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.arc1")); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.arc1"))); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "products.")); response.m_outputProducts.clear(); @@ -843,7 +849,7 @@ namespace AssetProcessor assetMessages.clear(); pcouts.clear(); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.azm")); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.azm"))); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "products.")); response.m_outputProducts.clear(); @@ -1012,7 +1018,7 @@ namespace AssetProcessor { QString processFile1 = processResults[checkIdx].m_jobEntry.GetAbsoluteSourcePath(); UNIT_TEST_EXPECT_TRUE(AssetUtilities::NormalizeFilePath(processFile1) == AssetUtilities::NormalizeFilePath(absolutePath)); - QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str()) + "/" + gameName.toLower()); + QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str())); platformFolder = AssetUtilities::NormalizeDirectoryPath(platformFolder); processFile1 = processResults[checkIdx].m_destinationPath; UNIT_TEST_EXPECT_TRUE(processFile1.startsWith(platformFolder)); @@ -1029,12 +1035,12 @@ namespace AssetProcessor QStringList pcouts2; es3outs.clear(); pcouts.clear(); - es3outs.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefilea.arc1")); - es3outs2.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefilea.azm")); + es3outs.push_back(cacheRoot.filePath(QString("es3/basefilea.arc1"))); + es3outs2.push_back(cacheRoot.filePath(QString("es3/basefilea.azm"))); // note that the ES3 outs have changed // but the pc outs are still the same. - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.arc1")); - pcouts2.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.azm")); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.arc1"))); + pcouts2.push_back(cacheRoot.filePath(QString("pc/basefile.azm"))); // feed it the messages its waiting for (create the files) UNIT_TEST_EXPECT_TRUE(CreateDummyFile(es3outs[0], "newfile.")); @@ -1155,7 +1161,7 @@ namespace AssetProcessor { QString processFile1 = processResults[checkIdx].m_jobEntry.GetAbsoluteSourcePath(); UNIT_TEST_EXPECT_TRUE(AssetUtilities::NormalizeFilePath(processFile1) == AssetUtilities::NormalizeFilePath(absolutePath)); - QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str()) + "/" + gameName.toLower()); + QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str())); platformFolder = AssetUtilities::NormalizeDirectoryPath(platformFolder); processFile1 = processResults[checkIdx].m_destinationPath; UNIT_TEST_EXPECT_TRUE(processFile1.startsWith(platformFolder)); @@ -1261,7 +1267,7 @@ namespace AssetProcessor // 4 * file claimed for the produce file to be able to update it safely. // 4 * file released for the produce file so it's free for other tools to use it again. UNIT_TEST_EXPECT_TRUE(payloadList.size() == 9); - unsigned int messageLoadCount = 0; + unsigned int messageLoadCount = 0; for (auto payload : payloadList) { if (payload.first == SourceFileNotificationMessage::MessageType) @@ -1487,9 +1493,9 @@ namespace AssetProcessor pcouts.clear(); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/subfolder3/randomfileoutput.random")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/subfolder3/randomfileoutput.random1")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/subfolder3/randomfileoutput.random2")); + pcouts.push_back(cacheRoot.filePath(QString("pc/subfolder3/randomfileoutput.random"))); + pcouts.push_back(cacheRoot.filePath(QString("pc/subfolder3/randomfileoutput.random1"))); + pcouts.push_back(cacheRoot.filePath(QString("pc/subfolder3/randomfileoutput.random2"))); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "products.")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[1], "products.")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[2], "products.")); @@ -1535,12 +1541,12 @@ namespace AssetProcessor es3outs2.clear(); pcouts.clear(); pcouts2.clear(); - es3outs.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefilez.arc2")); - es3outs2.push_back(cacheRoot.filePath(QString("es3/") + gameName + "/basefileaz.azm2")); + es3outs.push_back(cacheRoot.filePath(QString("es3/basefilez.arc2"))); + es3outs2.push_back(cacheRoot.filePath(QString("es3/basefileaz.azm2"))); // note that the ES3 outs have changed // but the pc outs are still the same. - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.arc2")); - pcouts2.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.azm2")); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.arc2"))); + pcouts2.push_back(cacheRoot.filePath(QString("pc/basefile.azm2"))); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(es3outs[0], "newfile.")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "newfile.")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(es3outs2[0], "newfile.")); @@ -1629,7 +1635,7 @@ namespace AssetProcessor { QString processFile1 = processResults[checkIdx].m_jobEntry.GetAbsoluteSourcePath(); UNIT_TEST_EXPECT_TRUE(processFile1 == expectedReplacementInputFile); - QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str()) + "/" + gameName.toLower()); + QString platformFolder = cacheRoot.filePath(QString::fromUtf8(processResults[checkIdx].m_jobEntry.m_platformInfo.m_identifier.c_str())); platformFolder = AssetUtilities::NormalizeDirectoryPath(platformFolder); processFile1 = processResults[checkIdx].m_destinationPath; UNIT_TEST_EXPECT_TRUE(processFile1.startsWith(platformFolder)); @@ -1951,13 +1957,13 @@ namespace AssetProcessor } UNIT_TEST_EXPECT_TRUE(BlockUntil(idling, 5000)); - + // it now believes that there are a whole bunch of assets in subfolder1/done_renaming and they resulted in // a whole bunch of files to have been created in the asset cache, listed in processresults, and they exist in outputscreated... // rename the output folder: - QString originalCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/" + gameName.toLower() + "/done_renaming"; - QString newCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/" + gameName.toLower() + "/renamed_again"; + QString originalCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/done_renaming"; + QString newCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/renamed_again"; UNIT_TEST_EXPECT_TRUE(renamer.rename(originalCacheFolderName, newCacheFolderName)); @@ -2017,8 +2023,8 @@ namespace AssetProcessor // setup complete. now RENAME that folder. - originalCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/" + gameName.toLower() + "/rename_this_secondly"; - newCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/" + gameName.toLower() + "/done_renaming_again"; + originalCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/rename_this_secondly"; + newCacheFolderName = normalizedCacheRootDir.absoluteFilePath("pc") + "/done_renaming_again"; UNIT_TEST_EXPECT_TRUE(renamer.rename(originalCacheFolderName, newCacheFolderName)); @@ -2305,8 +2311,7 @@ namespace AssetProcessor UnitTestUtils::ScopedDir changeDir(dir.path()); QDir tempPath(dir.path()); - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(AssetProcessorManagerTestGameProject); + QString gameName = AssetUtilities::ComputeProjectName(AssetProcessorManagerTestGameProject); // update the engine root AssetUtilities::ResetAssetRoot(); @@ -2382,8 +2387,8 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_jobKey.compare(processResults[1].m_jobEntry.m_jobKey) != 0); QStringList pcouts; - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.arc1")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.arc2")); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.arc1"))); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.arc2"))); // Create the product files for the first job UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "product1")); @@ -2416,7 +2421,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(AssetUtilities::NormalizeFilePath(changedInputResults[0].first) == AssetUtilities::NormalizeFilePath(sourceFile)); pcouts.clear(); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/basefile.arc3")); + pcouts.push_back(cacheRoot.filePath(QString("pc/basefile.arc3"))); // Create the product files for the second job UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "product1")); @@ -2515,9 +2520,7 @@ namespace AssetProcessor UnitTestUtils::ScopedDir changeDir(dir.path()); QDir tempPath(dir.path()); - - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(AssetProcessorManagerTestGameProject); + QString gameName = AssetUtilities::ComputeProjectName(AssetProcessorManagerTestGameProject); // update the engine root AssetUtilities::ResetAssetRoot(); @@ -2745,7 +2748,7 @@ namespace AssetProcessor } response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; }; - + AssetProcessor::AssetBuilderInfoBus::Handler::BusConnect(); QDir oldRoot; AssetUtilities::ComputeAssetRoot(oldRoot); @@ -2757,8 +2760,7 @@ namespace AssetProcessor UnitTestUtils::ScopedDir changeDir(dir.path()); QDir tempPath(dir.path()); - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(AssetProcessorManagerTestGameProject); + QString gameName = AssetUtilities::ComputeProjectName(AssetProcessorManagerTestGameProject); // update the engine root AssetUtilities::ResetAssetRoot(); @@ -2803,11 +2805,11 @@ namespace AssetProcessor QDir cacheRoot; UNIT_TEST_EXPECT_TRUE(AssetUtilities::ComputeProjectCacheRoot(cacheRoot)); - QString productFileAPath = cacheRoot.filePath(QString("pc/") + gameName + "/FileAProduct.txt"); - QString productFileBPath = cacheRoot.filePath(QString("pc/") + gameName + "/FileBProduct1.txt"); - QString product2FileBPath = cacheRoot.filePath(QString("pc/") + gameName + "/FileBProduct2.txt"); - QString productFileCPath = cacheRoot.filePath(QString("pc/") + gameName + "/FileCProduct.txt"); - QString product2FileCPath = cacheRoot.filePath(QString("pc/") + gameName + "/FileCProduct2.txt"); + QString productFileAPath = cacheRoot.filePath(QString("pc/FileAProduct.txt")); + QString productFileBPath = cacheRoot.filePath(QString("pc/FileBProduct1.txt")); + QString product2FileBPath = cacheRoot.filePath(QString("pc/FileBProduct2.txt")); + QString productFileCPath = cacheRoot.filePath(QString("pc/FileCProduct.txt")); + QString product2FileCPath = cacheRoot.filePath(QString("pc/FileCProduct2.txt")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(sourceFileAPath, "")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(sourceFileBPath, "")); @@ -2817,7 +2819,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(CreateDummyFile(product2FileBPath, "product")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(productFileCPath, "product")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(product2FileCPath, "product")); - + // Analyze FileA QMetaObject::invokeMethod(&apm, "AssessAddedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileAPath)); @@ -2927,7 +2929,7 @@ namespace AssetProcessor { // Ensure that we are processing the right FileB job UNIT_TEST_EXPECT_TRUE(QString(jobDetail.m_jobEntry.m_jobKey).compare("yyy") == 0); - + response.m_outputProducts.clear(); response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct(product2FileBPath.toUtf8().constData())); QMetaObject::invokeMethod(&apm, "AssetProcessed", Qt::QueuedConnection, Q_ARG(JobEntry, jobDetail.m_jobEntry), Q_ARG(AssetBuilderSDK::ProcessJobResponse, response)); @@ -2981,7 +2983,7 @@ namespace AssetProcessor processResults.clear(); // Modify fingerprint of Job("FileA", "xxx", "pc") and analyze FileA again, - changeJobAFingerprint = false; // This will revert back the changes in the extra info used for fingerprinting of this job + changeJobAFingerprint = false; // This will revert back the changes in the extra info used for fingerprinting of this job QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileAPath)); @@ -3001,7 +3003,7 @@ namespace AssetProcessor { // Verify FileB jobinfo UNIT_TEST_EXPECT_TRUE(QString(jobDetail.m_jobEntry.m_jobKey).compare("yyy") == 0); - + } else if (QString(jobDetail.m_jobEntry.m_pathRelativeToWatchFolder).endsWith("FileC.txt")) { @@ -3011,14 +3013,14 @@ namespace AssetProcessor } - // Since one of the FileC job("FileC.txt","zzz") have emitted a job dependency on a FileB job("FileB.txt", "yyy") - // which also have a job dependency on a FileA job("FileA.txt", "xxx") therefore deleting File A source file should + // Since one of the FileC job("FileC.txt","zzz") have emitted a job dependency on a FileB job("FileB.txt", "yyy") + // which also have a job dependency on a FileA job("FileA.txt", "xxx") therefore deleting File A source file should // cause both jobs (File B and File C) to be processed again. - + processResults.clear(); QFile::remove(sourceFileAPath); - + QMetaObject::invokeMethod(&apm, "AssessDeletedFile", Qt::QueuedConnection, Q_ARG(QString, sourceFileAPath)); UNIT_TEST_EXPECT_TRUE(BlockUntil(idling, 5000)); @@ -3053,7 +3055,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(BlockUntil(idling, 5000)); - + UNIT_TEST_EXPECT_TRUE(processResults.size() == 3); for (JobDetails& jobDetail : processResults) @@ -3091,15 +3093,14 @@ namespace AssetProcessor // the canonicalization of the path here is to get around the fact that on some platforms // the "temporary" folder location could be junctioned into some other folder and getting "QDir::current()" - // and other similar functions may actually return a different string but still be referring to the same folder + // and other similar functions may actually return a different string but still be referring to the same folder QTemporaryDir dir; QDir tempPath(dir.path()); QString canonicalTempDirPath = AssetUtilities::NormalizeDirectoryPath(tempPath.canonicalPath()); UnitTestUtils::ScopedDir changeDir(canonicalTempDirPath); tempPath = QDir(canonicalTempDirPath); - // system is already actually initialized, along with gEnv, so this will always return that game name. - QString gameName = AssetUtilities::ComputeGameName(AssetProcessorManagerTestGameProject); + QString gameName = AssetUtilities::ComputeProjectName(AssetProcessorManagerTestGameProject); // update the engine root AssetUtilities::ResetAssetRoot(); @@ -3116,7 +3117,7 @@ namespace AssetProcessor // note: the crux of this test is that we ar redirecting output into the cache at a different location instead of default. // so our scan folder has a "redirected" folder. - config.AddScanFolder(ScanFolderInfo(tempPath.filePath("subfolder1"), "subfolder1", "subfolder1", "redirected", false, true, platforms, -1)); + config.AddScanFolder(ScanFolderInfo(tempPath.filePath("subfolder1"), "subfolder1", "subfolder1", "redirected", false, true, platforms, -1)); AssetProcessorManager_Test apm(&config); @@ -3173,7 +3174,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_watchFolderPath == tempPath.filePath("subfolder1")); QStringList pcouts; - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/redirected/basefile.arc1")); + pcouts.push_back(cacheRoot.filePath(QString("pc/redirected/basefile.arc1"))); // Create the product files for the first job UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "product1")); @@ -3230,7 +3231,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_databaseSourceName == "redirected/basefile.foo"); UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_watchFolderPath == tempPath.absoluteFilePath("subfolder1")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/redirected/basefile.arc1")); + pcouts.push_back(cacheRoot.filePath(QString("pc/redirected/basefile.arc1"))); // Create the product files for the first job UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "product1")); @@ -3260,7 +3261,7 @@ namespace AssetProcessor assetMessages.clear(); changedInputResults.clear(); - QString deletedProductPath = cacheRoot.filePath(QString("pc/") + gameName + "/redirected/basefile.arc1"); + QString deletedProductPath = cacheRoot.filePath(QString("pc/redirected/basefile.arc1")); QFile::remove(deletedProductPath); @@ -3279,7 +3280,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_databaseSourceName == "redirected/basefile.foo"); UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_watchFolderPath == tempPath.absoluteFilePath("subfolder1")); - pcouts.push_back(cacheRoot.filePath(QString("pc/") + gameName + "/redirected/basefile.arc1")); + pcouts.push_back(cacheRoot.filePath(QString("pc/redirected/basefile.arc1"))); // Create the product files for the first job UNIT_TEST_EXPECT_TRUE(CreateDummyFile(pcouts[0], "product1")); diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.cpp index 85327e3804..4e48886689 100644 --- a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.cpp @@ -78,9 +78,8 @@ void AssetProcessorServerUnitTest::RunFirstPartOfUnitTestsForAssetProcessorServe void AssetProcessorServerUnitTest::RunAssetProcessorConnectionStressTest(bool failNegotiation) { - AZStd::string azAppRoot = AZStd::string(QDir::current().absolutePath().toUtf8().constData()); AZStd::string azBranchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, azBranchToken); + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, azBranchToken); QString branchToken(azBranchToken.c_str()); @@ -99,7 +98,7 @@ void AssetProcessorServerUnitTest::RunAssetProcessorConnectionStressTest(bool fa for (int idx = 0; idx < NUMBER_OF_TRIES; ++idx) { AzFramework::AssetSystem::AssetProcessorConnection connection; - connection.Configure(branchToken.toUtf8().data(), "pc", "UNITTEST", AssetUtilities::ComputeGameName().toUtf8().constData()); // UNITTEST identifier will skip the processID validation during negotiation + connection.Configure(branchToken.toUtf8().data(), "pc", "UNITTEST", AssetUtilities::ComputeProjectName().toUtf8().constData()); // UNITTEST identifier will skip the processID validation during negotiation connection.Connect("127.0.0.1", FEATURE_TEST_LISTEN_PORT); while (!connection.IsConnected() && !connection.NegotiationFailed()) { diff --git a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h index 88aba7daa6..8180b77cd6 100644 --- a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h +++ b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h @@ -268,7 +268,7 @@ namespace UnitTestUtils m_localFileIO->SetAlias("@assets@", (newDir + QString("/ALIAS/assets")).toUtf8().constData()); m_localFileIO->SetAlias("@log@", (newDir + QString("/ALIAS/logs")).toUtf8().constData()); - m_localFileIO->SetAlias("@cache@", (newDir + QString("/ALIAS/cache")).toUtf8().constData()); + m_localFileIO->SetAlias("@usercache@", (newDir + QString("/ALIAS/cache")).toUtf8().constData()); m_localFileIO->SetAlias("@user@", (newDir + QString("/ALIAS/user")).toUtf8().constData()); m_localFileIO->SetAlias("@root@", (newDir + QString("/ALIAS/root")).toUtf8().constData()); } diff --git a/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp index b700e16f06..1eada874d9 100644 --- a/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp @@ -35,7 +35,7 @@ using namespace AssetProcessor; namespace AssetProcessor { const char* const TEST_BOOTSTRAP_DATA = - "sys_game_folder = TestProject \r\n\ + "project_path = TestProject \r\n\ assets = pc \r\n\ -- ip and port of the asset processor.Only if you need to change defaults \r\n\ -- remote_ip = 127.0.0.1 \r\n\ diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.cpp b/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.cpp index 3da65a3fe5..04f029285b 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.cpp @@ -13,6 +13,7 @@ #include "native/utilities/ApplicationManager.h" #include +#include #include #include @@ -83,7 +84,7 @@ namespace AssetProcessor // we are in a job thread - return early to make it so that the global log file does not get this message // there will also be a log listener in the actual job log thread which will get the message too, and that one // will write it to the individual log. - return; + return; } AzFramework::LogComponent::OutputMessage(severity, window, message); @@ -119,29 +120,14 @@ AssetProcessorAZApplication::AssetProcessorAZApplication(int* argc, char*** argv *AZ::SettingsRegistry::Get(), AssetProcessorBuildTarget::GetBuildTargetName()); // Adding the PreModuleLoad event to the AssetProcessor application for logging when a gem loads - m_preModuleLoadHandler = AZ::ModuleManagerRequests::PreModuleLoadEvent::Handler{ []([[maybe_unused]] AZStd::string_view modulePath) - { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Loading (Gem) Module '%.*s'...\n", aznumeric_cast(modulePath.size()), modulePath.data()); - } }; + m_preModuleLoadHandler = AZ::ModuleManagerRequests::PreModuleLoadEvent::Handler{ + []([[maybe_unused]] AZStd::string_view modulePath) + { + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Loading (Gem) Module '%.*s'...\n", aznumeric_cast(modulePath.size()), modulePath.data()); + } + }; m_preModuleLoadHandler.Connect(m_moduleManager->m_preModuleLoadEvent); - - // Override the /Amazon/AzCore/Bootstrap/sys_game_folder entry in the Settings Registry using the -gamefolder parameter - auto settingsRegistry = AZ::SettingsRegistry::Get(); - if (m_commandLine.GetNumSwitchValues("gamefolder") > 0) - { - const AZStd::string& gameFolderOverride = m_commandLine.GetSwitchValue("gamefolder", 0); - auto gameFolderCommandLineOverride = AZStd::string::format("--regset=%s/sys_game_folder=%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, - gameFolderOverride.c_str()); - - AZ::CommandLine::ParamContainer commandLineArgs; - m_commandLine.Dump(commandLineArgs); - commandLineArgs.emplace_back(gameFolderCommandLineOverride); - m_commandLine.Parse(commandLineArgs); - - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, m_commandLine, false); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry); - } } AZ::ComponentTypeList AssetProcessorAZApplication::GetRequiredSystemComponents() const @@ -155,7 +141,7 @@ AZ::ComponentTypeList AssetProcessorAZApplication::GetRequiredSystemComponents() || *iter == AZ::Uuid("{624a7be2-3c7e-4119-aee2-1db2bdb6cc89}") // ScriptDebugAgent || *iter == AZ::Uuid("{CAF3A025-FAC9-4537-B99E-0A800A9326DF}") // InputSystemComponent || *iter == azrtti_typeid() - ) + ) { // AP does not require the above components to be active iter = components.erase(iter); @@ -274,7 +260,7 @@ void ApplicationManager::GetExternalBuilderFileList(QStringList& externalBuilder if (externalBuilderModules.empty()) { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "AssetProcessor was unable to locate any builders\n"); + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "AssetProcessor was unable to locate any external builders\n"); } } @@ -284,9 +270,16 @@ QDir ApplicationManager::GetSystemRoot() const { return m_systemRoot; } -QString ApplicationManager::GetGameName() const +QString ApplicationManager::GetProjectPath() const { - return m_gameName; + auto projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) + { + return QString::fromUtf8(projectPath.c_str(), aznumeric_cast(projectPath.size())); + } + + AZ_Warning("AssetUtils", false, "Unable to obtain the Project Path from the settings registry."); + return {}; } QCoreApplication* ApplicationManager::GetQtApplication() @@ -451,7 +444,7 @@ void ApplicationManager::PopulateApplicationDependencies() m_filesOfInterest.push_back(applicationPath); // add some known-dependent files (this can be removed when they are no longer a dependency) - // Note that its not necessary for any of these files to actually exist. It is considered a "change" if they + // Note that its not necessary for any of these files to actually exist. It is considered a "change" if they // change their file modtime, or if they go from existing to not existing, or if they go from not existing, to existing. // any of those should cause AP to drop. for (const QString& pathName : { "CrySystem", @@ -475,11 +468,10 @@ void ApplicationManager::PopulateApplicationDependencies() QDir assetRoot; AssetUtilities::ComputeAssetRoot(assetRoot); - QString globalConfigPath = assetRoot.filePath("AssetProcessorPlatformConfig.ini"); + QString globalConfigPath = assetRoot.filePath("AssetProcessorPlatformConfig.setreg"); m_filesOfInterest.push_back(globalConfigPath); - QString gameName = AssetUtilities::ComputeGameName(); - QString gamePlatformConfigPath = assetRoot.filePath(gameName + "/AssetProcessorGamePlatformConfig.ini"); + QString gamePlatformConfigPath = QDir(AssetUtilities::ComputeProjectPath()).filePath("AssetProcessorGamePlatformConfig.setreg"); m_filesOfInterest.push_back(gamePlatformConfigPath); // add app modules @@ -510,43 +502,14 @@ void ApplicationManager::PopulateApplicationDependencies() } } -bool ApplicationManager::StartAZFramework(QString appRootOverride) +bool ApplicationManager::StartAZFramework() { AzFramework::Application::Descriptor appDescriptor; AZ::ComponentApplication::StartupParameters params; - QString gameName = AssetUtilities::ComputeGameName(); + QString projectName = AssetUtilities::ComputeProjectName(); AZ::SettingsRegistryInterface& registry = *AZ::SettingsRegistry::Get(); - // Add the supplied gameName as specialization key in the registry - if (!gameName.isEmpty()) - { - auto gameNameSpecialization = QString("%1/%2").arg(AZ::SettingsRegistryMergeUtils::SpecializationsRootKey).arg(gameName); - QByteArray specializationByteArray = gameNameSpecialization.toUtf8(); - registry.Set(AZStd::string_view(specializationByteArray.data(), specializationByteArray.size()), true); - } - else - { - // Add the project name as a registry specialization - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - if (AZ::SettingsRegistryInterface::FixedValueString bootstrapProjectName; registry.Get(bootstrapProjectName, projectKey) && !bootstrapProjectName.empty()) - { - registry.Set(AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, bootstrapProjectName.c_str()), - true); - } - } - // The application will live in a bin folder one level up from the app root. - static char s_storageForRootPath[AZ_MAX_PATH_LEN] = { 0 }; - if (!appRootOverride.isEmpty()) - { - azstrcpy(s_storageForRootPath, AZ_MAX_PATH_LEN, appRootOverride.toUtf8().data()); - params.m_appRootOverride = s_storageForRootPath; - } - else - { - params.m_appRootOverride = nullptr; - } // Prevent loading of gems in the Create method of the ComponentApplication params.m_loadDynamicModules = false; @@ -556,17 +519,12 @@ bool ApplicationManager::StartAZFramework(QString appRootOverride) AZ::Debug::Trace::HandleExceptions(true); m_frameworkApp.Start(appDescriptor, params); - + //Registering all the Components m_frameworkApp.RegisterComponentDescriptor(AzFramework::LogComponent::CreateDescriptor()); - - Reflect(); - QDir engineRoot; - AssetUtilities::ComputeEngineRoot(engineRoot); - - AZ::IO::FileIOBase::GetInstance()->SetAlias("@devroot@", engineRoot.absolutePath().toUtf8().data()); + Reflect(); const AzFramework::CommandLine* commandLine = nullptr; AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine); @@ -574,13 +532,14 @@ bool ApplicationManager::StartAZFramework(QString appRootOverride) { AZ::IO::FileIOBase::GetInstance()->SetAlias("@log@", commandLine->GetSwitchValue("logDir", 0).c_str()); } - else + else if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - char executableDirectory[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(executableDirectory, AZStd::size(executableDirectory)) == AZ::Utils::ExecutablePathResult::Success) - { - AZ::IO::FileIOBase::GetInstance()->SetAlias("@log@", executableDirectory); - } + AZ::IO::Path projectUserPath; + settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + + AZ::IO::Path logUserPath = projectUserPath / "log"; + auto fileIo = AZ::IO::FileIOBase::GetInstance(); + fileIo->SetAlias("@log@", logUserPath.c_str()); } m_entity = aznew AZ::Entity("Application Entity"); if (m_entity) @@ -622,7 +581,6 @@ bool ApplicationManager::ActivateModules() AZ_Error(AssetProcessor::ConsoleChannel, false, "Cannot compute the asset root folder. Is AssetProcessor being run from the appropriate folder?"); return false; } - assetRoot.cd(AssetUtilities::ComputeGameName()); m_frameworkApp.LoadDynamicModules(); return true; @@ -633,89 +591,13 @@ void ApplicationManager::addRunningThread(AssetProcessor::ThreadWorker* thread) m_runningThreads.push_back(thread); } -QString ApplicationManager::ParseOptionAppRootArgument() -{ - AZ_Assert(m_qApp!=nullptr,"m_qApp not initialized. QT application must be created before this call.") - // Parse any parameters. - static const char* app_root_parameter = "app-root"; - static const char* app_root_parameter_desc = "Optional external path outside of the current engine to set as the application root."; - QCommandLineOption appRootPathOption(QString(app_root_parameter), tr(app_root_parameter_desc), QString("path")); - QCommandLineParser parser; - parser.setApplicationDescription("Asset Processor"); - parser.addOption(appRootPathOption); - parser.parse(m_qApp->arguments()); - - QString appRootArgValue = parser.value(appRootPathOption); - appRootArgValue.remove(QChar('\"')); - return appRootArgValue.trimmed(); -} - -bool ApplicationManager::ValidateExternalAppRoot(QString appRootPath) const -{ - static const char* bootstrap_cfg_name = "bootstrap.cfg"; - - QDir testAppRootPath(appRootPath); - - // Make sure the path exists - if (!testAppRootPath.exists()) - { - AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. Directory does not exist.\n", appRootPath.toUtf8().data()); - return false; - } - - // Make sure the path contains bootstrap.cfg - if (!testAppRootPath.exists(bootstrap_cfg_name)) - { - AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. Directory does not contain %s.\n", appRootPath.toUtf8().data(), bootstrap_cfg_name); - return false; - } - - // Make sure we can read the 'sys_game_folder' settings from bootstrap.cfg - QSettings settings(testAppRootPath.absoluteFilePath(bootstrap_cfg_name), QSettings::Format::IniFormat); - static const char* sysGameFolderKeyName = "sys_game_folder"; - auto sysGameFolderSettings = settings.value(sysGameFolderKeyName); - if (!sysGameFolderSettings.isValid() || sysGameFolderSettings.isNull()) - { - AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. %s in the path is not valid.\n", appRootPath.toUtf8().data(), bootstrap_cfg_name); - return false; - } - - // Make sure the 'sys_game_folder' value in the external bootstrap.cfg points to a valid subfolder in that path - QString sysGameFolder = sysGameFolderSettings.toString(); - QDir gameFolderPath(appRootPath); - if (!gameFolderPath.cd(sysGameFolder)) - { - AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. Configured Game folder %s in the path is not valid.\n", appRootPath.toUtf8().data(), sysGameFolder.toUtf8().data()); - return false; - } - - return true; -} ApplicationManager::BeforeRunStatus ApplicationManager::BeforeRun() { // Create the Qt Application CreateQtApplication(); - // Calculate the override app root path if provided and validate it before passing it along - QString overrideAppRootPath = ParseOptionAppRootArgument(); - - if (!overrideAppRootPath.isEmpty()) - { - if (ValidateExternalAppRoot(overrideAppRootPath)) - { - QDir overrideAppRoot(overrideAppRootPath); - QDir resultAppRoot; - AssetUtilities::ComputeAssetRoot(resultAppRoot, &overrideAppRoot); - } - else - { - AZ_Error(AssetProcessor::ConsoleChannel, false, "Invalid override app root folder '%s'.", overrideAppRootPath.toUtf8().data()); - return ApplicationManager::BeforeRunStatus::Status_Failure; - } - } - - if (!StartAZFramework(overrideAppRootPath)) + if (!StartAZFramework()) { return ApplicationManager::BeforeRunStatus::Status_Failure; } @@ -742,14 +624,13 @@ bool ApplicationManager::Activate() return false; } - m_gameName = AssetUtilities::ComputeGameName(); - - if (m_gameName.isEmpty()) + auto projectName = AssetUtilities::ComputeProjectName(); + if (projectName.isEmpty()) { AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to detect name of current game project. Is bootstrap.cfg appropriately configured?"); return false; } - + // the following controls what registry keys (or on mac or linux what entries in home folder) are used // so they should not be translated! qApp->setOrganizationName(GetOrganizationName()); diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.h b/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.h index 6dca29484c..cb5c03f9e5 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.h +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManager.h @@ -101,7 +101,7 @@ public: QCoreApplication* GetQtApplication(); QDir GetSystemRoot() const; - QString GetGameName() const; + QString GetProjectPath() const; void RegisterComponentDescriptor(const AZ::ComponentDescriptor* descriptor); @@ -163,9 +163,7 @@ protected: virtual const char* GetLogBaseName() = 0; virtual RegistryCheckInstructions PopupRegistryProblemsMessage(QString warningText) = 0; private: - bool StartAZFramework(QString appRootOverride); - bool ValidateExternalAppRoot(QString appRootPath) const; - QString ParseOptionAppRootArgument(); + bool StartAZFramework(); // QuitPair - Object pointer and "is ready" boolean pair. typedef QPair QuitPair; @@ -178,7 +176,6 @@ private: bool m_needRestart = false; bool m_queuedCheckQuit = false; QDir m_systemRoot; - QString m_gameName; AZ::Entity* m_entity = nullptr; }; diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp index ed0af840c7..a2c3b0a1a6 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp @@ -337,13 +337,13 @@ bool ApplicationManagerBase::InitPlatformConfiguration() m_platformConfiguration = new AssetProcessor::PlatformConfiguration(); QDir assetRoot; AssetUtilities::ComputeAssetRoot(assetRoot); - return m_platformConfiguration->InitializeFromConfigFiles(GetSystemRoot().absolutePath(), assetRoot.absolutePath(), GetGameName()); + return m_platformConfiguration->InitializeFromConfigFiles(GetSystemRoot().absolutePath(), assetRoot.absolutePath(), GetProjectPath()); } bool ApplicationManagerBase::InitBuilderConfiguration() { m_builderConfig = AZStd::make_unique(); - QString configFile = GetSystemRoot().absoluteFilePath(GetGameName() + "/" + AssetProcessor::BuilderConfigFile); + QString configFile = QDir(GetProjectPath()).absoluteFilePath(AssetProcessor::BuilderConfigFile); if (!QFile::exists(configFile)) { @@ -1193,7 +1193,8 @@ bool ApplicationManagerBase::Activate() return false; } - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "AssetProcessor will process assets from gameproject %s.\n", AssetUtilities::ComputeGameName().toUtf8().data()); + AZ_TracePrintf(AssetProcessor::ConsoleChannel, + "AssetProcessor will process assets from project root %s.\n", AssetUtilities::ComputeProjectPath().toUtf8().data()); // Shutdown if the disk has less than 128MB of free space if (!CheckSufficientDiskSpace(projectCache.absolutePath(), 128 * 1024 * 1024, true)) @@ -1219,7 +1220,7 @@ bool ApplicationManagerBase::Activate() if (!InitPlatformConfiguration()) { - AZ_Error("AssetProcessor", false, "Failed to Initialize from AssetProcessorPlatformConfig.ini - check the log files in the logs/ subfolder for more information."); + AZ_Error("AssetProcessor", false, "Failed to Initialize from AssetProcessorPlatformConfig.setreg - check the log files in the logs/ subfolder for more information."); return false; } @@ -1401,7 +1402,7 @@ bool ApplicationManagerBase::InitializeExternalBuilders() return true; } -bool ApplicationManagerBase::WaitForBuilderExit(AzToolsFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds) +bool ApplicationManagerBase::WaitForBuilderExit(AzFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds) { AZ::u32 exitCode = 0; bool finishedOK = false; diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h index 71e796b955..9aafaa1b76 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h @@ -177,7 +177,7 @@ protected: AssetProcessor::AssetCatalog* GetAssetCatalog() const { return m_assetCatalog; } - static bool WaitForBuilderExit(AzToolsFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds); + static bool WaitForBuilderExit(AzFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds); ApplicationServer* m_applicationServer = nullptr; ConnectionManager* m_connectionManager = nullptr; diff --git a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.cpp b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.cpp index 377bf06098..68ed75ebfb 100644 --- a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.cpp @@ -142,10 +142,6 @@ namespace AssetProcessor bool Builder::Start() { - // Get the app root to locate the builders - AZStd::string appRootString; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRootString, &AzFramework::ApplicationRequests::GetAppRoot); - // Get the current BinXXX folder based on the current running AP QString applicationDir = QCoreApplication::instance()->applicationDirPath(); @@ -190,24 +186,26 @@ namespace AssetProcessor QDir projectCacheRoot; AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); - QString gameName = AssetUtilities::ComputeGameName(); - - AZStd::string appRootString; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRootString, &AzFramework::ApplicationRequests::GetAppRoot); - QDir appRoot(QString(appRootString.c_str())); - QString gameRoot = appRoot.absoluteFilePath(gameName); + QString gameName = AssetUtilities::ComputeProjectName(); + QString projectPath = AssetUtilities::ComputeProjectPath(); + QDir engineRoot; + AssetUtilities::ComputeEngineRoot(engineRoot); int portNumber = 0; ApplicationServerBus::BroadcastResult(portNumber, &ApplicationServerBus::Events::GetServerListeningPort); AZStd::string params; - #if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - params = AZStd::string::format(R"(-task=%s -id="%s" -gamename="%s" -gamecache="%s" -gameroot="%s" -port %d)", - task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(), gameRoot.toUtf8().constData(), portNumber); - #else - params = AZStd::string::format(R"(-task=%s -id="%s" -gamename="\"%s\"" -gamecache="\"%s\"" -gameroot="\"%s\"" -port %d)", - task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(), gameRoot.toUtf8().constData(), portNumber); - #endif // !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS +#if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS + params = AZStd::string::format( + R"(-task=%s -id="%s" -project-name="%s" -project-cache-path="%s" -project-path="%s" -engine-path="%s" -port %d)", task, + builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(), + projectPath.toUtf8().constData(), engineRoot.absolutePath().toUtf8().constData(), portNumber); +#else + params = AZStd::string::format( + R"(-task=%s -id="%s" -project-name="\"%s\"" -project-cache-path="\"%s\"" -project-path="\"%s\"" -engine-path="\"%s\"" -port %d)", + task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(), + projectPath.toUtf8().constData(), engineRoot.absolutePath().toUtf8().constData(), portNumber); +#endif // !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS if (moduleFilePath && moduleFilePath[0]) { @@ -230,17 +228,17 @@ namespace AssetProcessor return params; } - AZStd::unique_ptr Builder::LaunchProcess(const char* fullExePath, const AZStd::string& params) const + AZStd::unique_ptr Builder::LaunchProcess(const char* fullExePath, const AZStd::string& params) const { - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_processExecutableString = fullExePath; processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" %s", fullExePath, params.c_str()); processLaunchInfo.m_showWindow = false; - processLaunchInfo.m_processPriority = AzToolsFramework::ProcessPriority::PROCESSPRIORITY_IDLE; + processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_IDLE; AZ_TracePrintf(AssetProcessor::DebugChannel, "Executing AssetBuilder with parameters: %s\n", processLaunchInfo.m_commandlineParameters.c_str()); - auto processWatcher = AZStd::unique_ptr(AzToolsFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzToolsFramework::COMMUNICATOR_TYPE_STDINOUT)); + auto processWatcher = AZStd::unique_ptr(AzFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT)); AZ_Error(AssetProcessor::ConsoleChannel, processWatcher, "Failed to start %s", fullExePath); diff --git a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.h b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.h index b9296cd36c..ef30395bff 100644 --- a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.h +++ b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include @@ -108,7 +108,7 @@ namespace AssetProcessor void SetConnection(AZ::u32 connId); AZStd::string BuildParams(const char* task, const char* moduleFilePath, const AZStd::string& builderGuid, const AZStd::string& jobDescriptionFile, const AZStd::string& jobResponseFile) const; - AZStd::unique_ptr LaunchProcess(const char* fullExePath, const AZStd::string& params) const; + AZStd::unique_ptr LaunchProcess(const char* fullExePath, const AZStd::string& params) const; //! Waits for the builder exe to send the job response and pumps stdout/err BuilderRunJobOutcome WaitForBuilderResponse(AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds, AZStd::binary_semaphore* waitEvent) const; @@ -128,7 +128,7 @@ namespace AssetProcessor AZStd::binary_semaphore m_connectionEvent; //! Optional process watcher - AZStd::unique_ptr m_processWatcher = nullptr; + AZStd::unique_ptr m_processWatcher = nullptr; //! Optional communicator, only available if we have a process watcher AZStd::unique_ptr m_tracePrinter = nullptr; diff --git a/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.cpp b/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.cpp index 205067a461..2f6af2141c 100644 --- a/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.cpp @@ -12,7 +12,7 @@ #include "CommunicatorTracePrinter.h" -CommunicatorTracePrinter::CommunicatorTracePrinter(AzToolsFramework::ProcessCommunicator* communicator, const char* window) : +CommunicatorTracePrinter::CommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window) : m_communicator(communicator), m_window(window) { diff --git a/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.h b/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.h index 85f56aba14..ee22d6b088 100644 --- a/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.h +++ b/Code/Tools/AssetProcessor/native/utilities/CommunicatorTracePrinter.h @@ -12,14 +12,14 @@ #pragma once -#include +#include //! CommunicatorTracePrinter listens to stderr and stdout of a running process and writes its output to the AZ_Trace system //! Importantly, it does not do any blocking operations. class CommunicatorTracePrinter { public: - CommunicatorTracePrinter(AzToolsFramework::ProcessCommunicator* communicator, const char* window); + CommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window); ~CommunicatorTracePrinter(); // call this periodically to drain the buffers and write them. @@ -32,7 +32,7 @@ public: private: AZStd::string m_window; - AzToolsFramework::ProcessCommunicator* m_communicator; + AzFramework::ProcessCommunicator* m_communicator; char m_streamBuffer[128]; AZStd::string m_stringBeingConcatenated; AZStd::string m_errorStringBeingConcatenated; diff --git a/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp b/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp index 5112bc0b6e..78be834dba 100644 --- a/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp @@ -130,37 +130,36 @@ ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun() m_qtFileWatcher.addPath(assetDbPath); // if our Gems file changes, make sure we watch that, too. - QString gameName = AssetUtilities::ComputeGameName(); - QString gemsConfigFile = devRoot.filePath(gameName + "/gems.json"); - - m_qtFileWatcher.addPath(gemsConfigFile); + QString projectPath = AssetUtilities::ComputeProjectPath(); QObject::connect(&m_qtFileWatcher, &QFileSystemWatcher::fileChanged, this, &GUIApplicationManager::FileChanged); QObject::connect(&m_qtFileWatcher, &QFileSystemWatcher::directoryChanged, this, &GUIApplicationManager::DirectoryChanged); - // Register a notifier for when the sys_game_folder property changes within the SettingsRegistry + // Register a notifier for when the project_path property changes within the SettingsRegistry if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - auto onBootStrapGameFolderChanged = [this, cachedGameName = gameName](AZStd::string_view path, AZ::SettingsRegistryInterface::Type type) + // Needs to be updated to project_path. + auto OnProjectPathChanged = [this, cachedProjectPath = projectPath](AZStd::string_view path, AZ::SettingsRegistryInterface::Type) { - constexpr auto projectKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) - + "/sys_game_folder"; - if (projectKey == path && type == AZ::SettingsRegistryInterface::Type::String) + constexpr auto projectPathKey = + AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + + "/project_path"; + if (projectPathKey == path) { - auto registry = AZ::SettingsRegistry::Get(); - AZ::SettingsRegistryInterface::FixedValueString newGameName; - if (registry->Get(newGameName, path)) + AZ::SettingsRegistryInterface::FixedValueString newProjectPath; + if (auto registry = AZ::SettingsRegistry::Get(); registry && registry->Get(newProjectPath, path)) { - // we only have to quit if the actual project name has changed, not if just the bootstrap has changed. - if (cachedGameName.compare(newGameName.c_str()) != 0) + // we only have to quit if the project path has changed, not if just the bootstrap has changed. + if (cachedProjectPath.compare(newProjectPath.c_str()) != 0) { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Bootstrap.cfg Game Name changed from %s to %s. Quitting\n", cachedGameName.toUtf8().constData(), newGameName.c_str()); + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "bootstrap.cfg Project Path changed from %s to %s. Quitting\n", + cachedProjectPath.toUtf8().constData(), newProjectPath.c_str()); QMetaObject::invokeMethod(this, "QuitRequested", Qt::QueuedConnection); } } } }; - m_bootstrapGameFolderChangedHandler = settingsRegistry->RegisterNotifier(AZStd::move(onBootStrapGameFolderChanged)); + m_bootstrapGameFolderChangedHandler = settingsRegistry->RegisterNotifier(AZStd::move(OnProjectPathChanged)); } return ApplicationManager::BeforeRunStatus::Status_Success; @@ -189,8 +188,13 @@ bool GUIApplicationManager::Run() qRegisterMetaType("AZ::u32"); qRegisterMetaType("AZ::Uuid"); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } AzQtComponents::StyleManager* styleManager = new AzQtComponents::StyleManager(qApp); - styleManager->Initialize(qApp); + styleManager->initialize(qApp, engineRootPath); QDir engineRoot; AssetUtilities::ComputeAssetRoot(engineRoot); @@ -198,7 +202,8 @@ bool GUIApplicationManager::Run() AzQtComponents::StyleManager::addSearchPaths( QStringLiteral("style"), engineRoot.filePath(QStringLiteral("Code/Tools/AssetProcessor/native/ui/style")), - QStringLiteral(":/AssetProcessor/style")); + QStringLiteral(":/AssetProcessor/style"), + engineRootPath); m_mainWindow = new MainWindow(this); auto wrapper = new AzQtComponents::WindowDecorationWrapper( @@ -485,7 +490,7 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message) QVariant settingValue = loader.value("Game Projects/enabled_game_projects"); QStringList compiledProjects = settingValue.toStringList(); - if(compiledProjects.isEmpty()) + if (compiledProjects.isEmpty()) { QByteArray byteArray; QFile jsonFile; @@ -497,12 +502,12 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message) QJsonObject settingsObject = QJsonDocument::fromJson(byteArray).object(); QJsonArray projectsArray = settingsObject["Game Projects"].toArray(); - if(!projectsArray.isEmpty()) + if (!projectsArray.isEmpty()) { auto projectObject = projectsArray[0].toObject(); QString projects = projectObject["default_value"].toString(); - if(!projects.isEmpty()) + if (!projects.isEmpty()) { compiledProjects = projects.split(','); usingDefaults = true; @@ -515,13 +520,13 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message) compiledProjects[i] = compiledProjects[i].trimmed(); } - QString enabledProject = AssetUtilities::ComputeGameName(); + QString enabledProject = AssetUtilities::ComputeProjectName(); - if(!compiledProjects.contains(enabledProject)) + if (!compiledProjects.contains(enabledProject)) { QString projectSourceLine; - if(usingDefaults) + if (usingDefaults) { projectSourceLine = QString("The currently compiled projects according to the defaults in %1 are '%2'").arg(defaultSettingsFile); } @@ -531,7 +536,6 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message) } projectSourceLine = projectSourceLine.arg(compiledProjects.join(", ")); - friendlyErrorMessage = QString("An error occurred while loading gems.\n" "The enabled game project is not in the list of compiled projects.\n" "Please configure the enabled project to be compiled and rebuild or change the enabled project.\n" @@ -539,13 +543,12 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message) "%2\n" "Full error text:\n" "%3" - ).arg(enabledProject).arg(projectSourceLine).arg(message).arg(AssetUtilities::GameFolderOverrideParameter); + ).arg(enabledProject).arg(projectSourceLine).arg(message).arg(AssetUtilities::ProjectPathOverrideParameter); } } - if(friendlyErrorMessage.isEmpty()) + if (friendlyErrorMessage.isEmpty()) { - friendlyErrorMessage = QString("An error occurred while loading gems.\n" "This can happen when new gems are added to a project, but those gems need to be built in order to function.\n" "This can also happen when switching to a different project, one which uses gems which are not yet built.\n" @@ -631,34 +634,18 @@ void GUIApplicationManager::CreateQtApplication() m_qApp = new QApplication(*m_frameworkApp.GetArgC(), *m_frameworkApp.GetArgV()); } -void GUIApplicationManager::DirectoryChanged(QString path) +void GUIApplicationManager::DirectoryChanged([[maybe_unused]] QString path) { - AZ_UNUSED(path); - QDir devRoot = ApplicationManager::GetSystemRoot(); - QString cacheRoot = devRoot.filePath("Cache"); - if (!QDir(cacheRoot).exists()) + QDir projectCacheRoot; + AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); + if (!projectCacheRoot.exists() || !projectCacheRoot.exists("assetdb.sqlite")) { - //Cache directory is removed we need to restart + // If either the Cache directory or database file has been removed, we need to restart QTimer::singleShot(200, this, [this]() { QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection); }); } - else - { - QDir projectCacheRoot; - AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); - QString assetDbPath = projectCacheRoot.filePath("assetdb.sqlite"); - - if (!QFile::exists(assetDbPath)) - { - // even if cache directory exists but the the database file is missing we need to restart - QTimer::singleShot(200, this, [this]() - { - QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection); - }); - } - } } void GUIApplicationManager::FileChanged(QString path) @@ -696,70 +683,6 @@ void GUIApplicationManager::FileChanged(QString path) }); } } - else if (AssetUtilities::NormalizeFilePath(path).endsWith("gems.json", Qt::CaseInsensitive)) - { - AZStd::vector oldGemsList = GetPlatformConfiguration()->GetGemsInformation(); - AZStd::vector newGemsList; - QDir assetRoot; - AssetUtilities::ComputeAssetRoot(assetRoot); - AzToolsFramework::AssetUtils::GetGemsInfo(GetSystemRoot().absolutePath().toUtf8().constData(), assetRoot.absolutePath().toUtf8().constData(), GetGameName().toUtf8().constData(), newGemsList); - - for (auto oldGemIter = oldGemsList.begin(); oldGemIter != oldGemsList.end();) - { - bool gemMatch = false; - for (auto newGemIter = newGemsList.begin(); newGemIter != newGemsList.end();) - { - if (AzFramework::StringFunc::Equal(oldGemIter->m_identifier.c_str(), newGemIter->m_identifier.c_str())) - { - gemMatch = true; - newGemIter = newGemsList.erase(newGemIter); - break; - } - newGemIter++; - } - - if (gemMatch) - { - oldGemIter = oldGemsList.erase(oldGemIter); - } - else - { - oldGemIter++; - } - } - - // oldGemslist should contain the list of gems that got removed and newGemsList should contain the list of gems that were added to the project - // if the project requires to be built again then we will quit otherwise we can restart - bool exitApp = false; - for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : newGemsList) - { - if (!gemInfo.m_assetOnly) - { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Gem %s was added to the project and require building. Quitting\n", gemInfo.m_gemName.c_str()); - exitApp = true; - } - } - - if (exitApp) - { - QuitRequested(); - } - else - { - if (oldGemsList.size() || newGemsList.size()) - { - if (oldGemsList.size()) - { - AZ_TracePrintf(AssetProcessor::DebugChannel, "Gem(s) were removed from the project. Restarting\n"); - } - else if (newGemsList.size()) - { - AZ_TracePrintf(AssetProcessor::DebugChannel, "Assets only gem(s) were added to the project. Restarting\n"); - } - QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection); - } - } - } } bool GUIApplicationManager::InitApplicationServer() diff --git a/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.cpp b/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.cpp index fe3e191ecc..73125fd58a 100644 --- a/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.cpp @@ -20,43 +20,48 @@ AZ_POP_DISABLE_WARNING #include "native/AssetDatabase/AssetDatabase.h" #include "native/assetprocessor.h" #include +#include #include #include -#include -#include #include #include +#include #include +#include #include namespace AssetProcessor { const char* EngineFolder = "Engine"; - AZStd::string GetXMLDependenciesFile(const AZStd::string& fullPath, const AZStd::vector& gemInfoList, AZStd::string& tokenName) + AZStd::string GetXMLDependenciesFile(const AZStd::string& fullPath, const AZStd::vector& gemInfoList, AZStd::string& tokenName) { - AZStd::string xmlDependenciesFileFullPath; + AZ::IO::Path xmlDependenciesFileFullPath; tokenName = EngineFolder; - for (const AzToolsFramework::AssetUtils::GemInfo& gemElement : gemInfoList) + for (const AzFramework::GemInfo& gemElement : gemInfoList) { - if (AzFramework::StringFunc::StartsWith(fullPath.c_str(), gemElement.m_absoluteFilePath.c_str()) || AzFramework::StringFunc::Equal(gemElement.m_absoluteFilePath.c_str(), fullPath.c_str())) + for (const AZ::IO::Path& absoluteSourcePath : gemElement.m_absoluteSourcePaths) { - AZStd::string fileName = AZStd::string::format("%s_Dependencies.xml", gemElement.m_gemName.c_str()); - AzFramework::StringFunc::Path::ConstructFull(gemElement.m_absoluteFilePath.c_str(), AzToolsFramework::AssetUtils::GemInfo::GetGemAssetFolder().c_str(), fileName.c_str() , "xml", xmlDependenciesFileFullPath); - if (AZ::IO::FileIOBase::GetInstance()->Exists(xmlDependenciesFileFullPath.c_str())) + if (AZ::StringFunc::StartsWith(fullPath, absoluteSourcePath.Native()) || AZ::StringFunc::Equal(absoluteSourcePath.Native(), fullPath)) { - tokenName = gemElement.m_gemName; - return xmlDependenciesFileFullPath; + xmlDependenciesFileFullPath /= AzFramework::GemInfo::GetGemAssetFolder(); + xmlDependenciesFileFullPath /= AZStd::string::format("%s_Dependencies.xml", gemElement.m_gemName.c_str());; + if (AZ::IO::FileIOBase::GetInstance()->Exists(xmlDependenciesFileFullPath.c_str())) + { + tokenName = gemElement.m_gemName; + return xmlDependenciesFileFullPath.Native(); + } } } } // if we are here than either the %gemName%_Dependencies.xml file does not exists or the user inputted path is not inside a gems folder, // in both the cases we will return the engine dependencies file - const char* devRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); - AzFramework::StringFunc::Path::ConstructFull(devRoot, EngineFolder, "Engine_Dependencies.xml", "xml", xmlDependenciesFileFullPath); + xmlDependenciesFileFullPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); + xmlDependenciesFileFullPath /= EngineFolder; + xmlDependenciesFileFullPath /= "Engine_Dependencies.xml"; - return xmlDependenciesFileFullPath; + return xmlDependenciesFileFullPath.Native(); } const int MissingDependencyScanner::DefaultMaxScanIteration = 800; @@ -731,7 +736,7 @@ namespace AssetProcessor } } - bool MissingDependencyScanner::PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector& gemInfoList, AZStd::string& dependencyTokenName) + bool MissingDependencyScanner::PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector& gemInfoList, AZStd::string& dependencyTokenName) { AZStd::string xmlDependenciesFullFilePath = GetXMLDependenciesFile(scanFolderPath, gemInfoList, dependencyTokenName); if (xmlDependenciesFullFilePath.empty()) diff --git a/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.h b/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.h index 3ee1e36be1..95e5e92548 100644 --- a/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.h +++ b/Code/Tools/AssetProcessor/native/utilities/MissingDependencyScanner.h @@ -131,7 +131,7 @@ namespace AssetProcessor void RegisterSpecializedScanner(AZStd::shared_ptr scanner); - bool PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector& gemInfoList, AZStd::string& dependencyTokenName); + bool PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector& gemInfoList, AZStd::string& dependencyTokenName); protected: bool RunScan( diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp index 62dc7acc10..28adb622d6 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp @@ -14,23 +14,663 @@ #include -#include - +#include +#include #include +#include namespace { // the starting order in the file for gems. const int g_gemStartingOrder = 100; +} + +namespace AssetProcessor +{ + struct PlatformsInfoVisitor + : AZ::SettingsRegistryInterface::Visitor + { + AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override + { + constexpr AZStd::string_view PlatformInfoPrefix = "Platform "; + switch (action) + { + case AZ::SettingsRegistryInterface::VisitAction::Begin: + { + // Only continue traversal if the path is exactly the AssetProcessorSettingsKey (which indicates the start of traversal) + // or if a "Platform *" object and it's children are being traversed + if (jsonPath == AssetProcessorSettingsKey) + { + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + if (valueName.starts_with(PlatformInfoPrefix)) + { + // Retrieve the platform name from the rest of valueName portion of the key "Platform (.*)" + AZStd::string platformIdentifier = valueName.substr(PlatformInfoPrefix.size()); + // Lowercase the platformIdentifier and store it in the stack + AZStd::to_lower(platformIdentifier.begin(), platformIdentifier.end()); + + m_platformIdentifierStack.push(AZStd::move(platformIdentifier)); + } + } + break; + case AZ::SettingsRegistryInterface::VisitAction::End: + { + if (valueName.starts_with(PlatformInfoPrefix)) + { + AZ_Assert(!m_platformIdentifierStack.empty(), "PlatformInfo stack should not be empty. More stack pops, than pushes"); + m_platformIdentifierStack.pop(); + } + } + break; + + default: + break; + } + + return !m_platformIdentifierStack.empty() ? AZ::SettingsRegistryInterface::VisitResponse::Continue + : AZ::SettingsRegistryInterface::VisitResponse::Skip; + } + void Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override + { + if (m_platformIdentifierStack.empty()) + { + return; + } + + if (valueName == "tags") + { + AZStd::string_view platformIdentifier = m_platformIdentifierStack.top(); + AZStd::unordered_set platformTags; + auto JoinTags = [&platformTags](AZStd::string_view token) + { + AZStd::string cleanedTag{ token }; + AZStd::to_lower(cleanedTag.begin(), cleanedTag.end()); + platformTags.insert(AZStd::move(cleanedTag)); + }; + AZ::StringFunc::TokenizeVisitor(value, JoinTags, ','); + m_platformInfos.emplace_back(platformIdentifier, platformTags); + } + } + + AZStd::vector m_platformInfos; + private: + AZStd::stack m_platformIdentifierStack; + }; + + struct MetaDataTypesVisitor + : AZ::SettingsRegistryInterface::Visitor + { + void Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override + { + m_metaDataTypes.push_back({ AZ::IO::PathView(valueName, AZ::IO::PosixPathSeparator).LexicallyNormal().String(), value }); + } + + struct MetaDataType + { + AZStd::string m_fileType; + AZStd::string m_extensionType; + }; + AZStd::vector m_metaDataTypes; + }; + + AZ::SettingsRegistryInterface::VisitResponse ScanFolderVisitor::Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) + { + constexpr AZStd::string_view ScanFolderInfoPrefix = "ScanFolder "; + switch (action) + { + case AZ::SettingsRegistryInterface::VisitAction::Begin: + { + if (jsonPath == AssetProcessorSettingsKey) + { + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + if (valueName.starts_with(ScanFolderInfoPrefix)) + { + // Retrieve the ScanFolder identifier from "Scan Folder *" + AZStd::string scanFolderDisplayName = valueName.substr(ScanFolderInfoPrefix.size()); + m_scanFolderStack.push(scanFolderDisplayName); + + ScanFolderInfo& scanFolderInfo = m_scanFolderInfos.emplace_back(); + scanFolderInfo.m_scanFolderIdentifier = scanFolderDisplayName; + scanFolderInfo.m_scanFolderDisplayName = AZStd::move(scanFolderDisplayName); + } + } + break; + case AZ::SettingsRegistryInterface::VisitAction::End: + { + if (valueName.starts_with(ScanFolderInfoPrefix)) + { + AZ_Assert(!m_scanFolderStack.empty(), "ScanFolder identifier stack should not be empty. More stack pops, than pushes"); + m_scanFolderStack.pop(); + } + } + break; + + default: + break; + } + + return !m_scanFolderStack.empty() ? AZ::SettingsRegistryInterface::VisitResponse::Continue + : AZ::SettingsRegistryInterface::VisitResponse::Skip; + } + void ScanFolderVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) + { + // Check if a "ScanFolder *" element is being traversed + if (m_scanFolderStack.empty()) + { + return; + } + + AZStd::string_view currentScanFolderIdentifier = m_scanFolderStack.top(); + + // Find ScanFolder element being iterated over. + // It should be the last element in ScanFolderInfo vector + auto scanFolderEntryIt = AZStd::find_if(m_scanFolderInfos.rbegin(), m_scanFolderInfos.rend(), + [¤tScanFolderIdentifier](const ScanFolderInfo& scanFolderInfo) + { + return scanFolderInfo.m_scanFolderIdentifier == currentScanFolderIdentifier; + }); + if (scanFolderEntryIt == m_scanFolderInfos.rend()) + { + return; + } + + ScanFolderInfo& scanFolderEntry = *scanFolderEntryIt; + if (valueName == "recursive") + { + scanFolderEntry.m_isRecursive = value != 0; + } + else if (valueName == "order") + { + scanFolderEntry.m_scanOrder = value; + } + } + + void ScanFolderVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) + { + // Check if a "ScanFolder *" element is being traversed + if (m_scanFolderStack.empty()) + { + return; + } + + AZStd::string_view currentScanFolderIdentifier = m_scanFolderStack.top(); + + // Find ScanFolder element being iterated over. + // It should be the last element in ScanFolderInfo vector + auto scanFolderEntryIt = AZStd::find_if(m_scanFolderInfos.rbegin(), m_scanFolderInfos.rend(), + [¤tScanFolderIdentifier](const ScanFolderInfo& scanFolderInfo) + { + return scanFolderInfo.m_scanFolderIdentifier == currentScanFolderIdentifier; + }); + if (scanFolderEntryIt == m_scanFolderInfos.rend()) + { + return; + } + + ScanFolderInfo& scanFolderEntry = *scanFolderEntryIt; + if (valueName == "watch") + { + scanFolderEntry.m_watchPath = value; + } + else if (valueName == "output") + { + scanFolderEntry.m_outputPrefix = value; + } + else if (valueName == "display" && !value.empty()) + { + scanFolderEntry.m_scanFolderDisplayName = value; + } + else if (valueName == "include") + { + auto JoinTags = [&scanFolderEntry](AZStd::string_view token) + { + scanFolderEntry.m_includeIdentifiers.push_back(token); + }; + AZ::StringFunc::TokenizeVisitor(value, JoinTags, ','); + } + else if (valueName == "exclude") + { + auto JoinTags = [&scanFolderEntry](AZStd::string_view token) + { + scanFolderEntry.m_excludeIdentifiers.push_back(token); + }; + AZ::StringFunc::TokenizeVisitor(value, JoinTags, ','); + } + } + + AZ::SettingsRegistryInterface::VisitResponse ExcludeVisitor::Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) + { + constexpr AZStd::string_view ExcludeNamePrefix = "Exclude "; + switch (action) + { + case AZ::SettingsRegistryInterface::VisitAction::Begin: + { + if (jsonPath == AssetProcessorSettingsKey) + { + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + if (valueName.starts_with(ExcludeNamePrefix)) + { + // Extract the substr that is part of the valueName "Exclude *" + AZStd::string excludeName = valueName.substr(ExcludeNamePrefix.size()); + m_excludeNameStack.push(excludeName); + + ExcludeAssetRecognizer& excludeAssetRecognizer = m_excludeAssetRecognizers.emplace_back(); + excludeAssetRecognizer.m_name = QString::fromUtf8(excludeName.c_str(), aznumeric_cast(excludeName.size())); + } + } + break; + case AZ::SettingsRegistryInterface::VisitAction::End: + { + if (valueName.starts_with(ExcludeNamePrefix)) + { + AZ_Assert(!m_excludeNameStack.empty(), "Exclude stack should not be empty. More stack pops, than pushes"); + m_excludeNameStack.pop(); + } + } + break; + + default: + break; + } + + return !m_excludeNameStack.empty() ? AZ::SettingsRegistryInterface::VisitResponse::Continue + : AZ::SettingsRegistryInterface::VisitResponse::Skip; + } + + void ExcludeVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) + { + if (m_excludeNameStack.empty()) + { + return; + } + + AZStd::string_view excludeNameView = m_excludeNameStack.top(); + auto excludeName = QString::fromUtf8(excludeNameView.data(), aznumeric_cast(excludeNameView.size())); + + // Find ScanFolder element being iterated over. + // It should be the last element in ScanFolderInfo vector + auto excludeAssetRecognizerEntryIt = AZStd::find_if(m_excludeAssetRecognizers.rbegin(), m_excludeAssetRecognizers.rend(), + [&excludeName](const ExcludeAssetRecognizer& excludeAssetRecognizer) + { + return excludeAssetRecognizer.m_name == excludeName; + }); + if (excludeAssetRecognizerEntryIt == m_excludeAssetRecognizers.rend()) + { + return; + } + + ExcludeAssetRecognizer& excludeAssetRecognizer = *excludeAssetRecognizerEntryIt; + + // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values + // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the + // backslash character used to escape other characters, therefore causing a "double escape" + // situation + auto UnescapePattern = [](AZStd::string_view pattern) + { + constexpr AZStd::string_view backslashEscape = R"(\\)"; + AZStd::string unescapedResult; + while (!pattern.empty()) + { + size_t pos = pattern.find(backslashEscape); + if (pos != AZStd::string_view::npos) + { + unescapedResult += pattern.substr(0, pos); + unescapedResult += '\\'; + // Move the pattern string after the double backslash characters + pattern = pattern.substr(pos + backslashEscape.size()); + } + else + { + unescapedResult += pattern; + pattern = {}; + } + } + + return unescapedResult; + }; + + if (valueName == "pattern") + { + if (!value.empty()) + { + const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex; + excludeAssetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType); + } + } + else if (valueName == "glob") + { + if (!excludeAssetRecognizer.m_patternMatcher.IsValid()) + { + const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard; + excludeAssetRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType); + } + } + } + + AZ::SettingsRegistryInterface::VisitResponse RCVisitor::Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) + { + constexpr AZStd::string_view RCNamePrefix = "RC "; + switch (action) + { + case AZ::SettingsRegistryInterface::VisitAction::Begin: + { + if (jsonPath == AssetProcessorSettingsKey) + { + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + if (valueName.starts_with(RCNamePrefix)) + { + // Extract the substr that is part of the valueName "Exclude *" + AZStd::string rcName = valueName.substr(RCNamePrefix.size()); + m_rcNameStack.push(rcName); + + RCAssetRecognizer& assetRecognizer = m_assetRecognizers.emplace_back(); + assetRecognizer.m_recognizer.m_name = QString::fromUtf8(rcName.c_str(), aznumeric_cast(rcName.size())); + } + } + break; + case AZ::SettingsRegistryInterface::VisitAction::End: + { + if (valueName.starts_with(RCNamePrefix)) + { + AZ_Assert(!m_rcNameStack.empty(), "RC name stack should not be empty. More stack pops, than pushes"); + ApplyParamsOverrides(jsonPath); + m_rcNameStack.pop(); + } + } + break; + + default: + break; + } + + return !m_rcNameStack.empty() ? AZ::SettingsRegistryInterface::VisitResponse::Continue + : AZ::SettingsRegistryInterface::VisitResponse::Skip; + } + + void RCVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value) + { + if (m_rcNameStack.empty()) + { + return; + } + + AZStd::string_view rcNameView = m_rcNameStack.top(); + auto rcName = QString::fromUtf8(rcNameView.data(), aznumeric_cast(rcNameView.size())); + + // Find AssetRecognizer identified by the top entry in the name stack + auto assetRecognizerEntryIt = AZStd::find_if(m_assetRecognizers.rbegin(), m_assetRecognizers.rend(), + [&rcName](const RCAssetRecognizer& assetRecognizer) + { + return assetRecognizer.m_recognizer.m_name == rcName; + }); + if (assetRecognizerEntryIt == m_assetRecognizers.rend()) + { + return; + } + + RCAssetRecognizer& assetRecognizer = *assetRecognizerEntryIt; + if (valueName == "ignore") + { + assetRecognizer.m_ignore = value; + } + else if (valueName == "lockSource") + { + assetRecognizer.m_recognizer.m_testLockSource = value; + } + else if (valueName == "critical") + { + assetRecognizer.m_recognizer.m_isCritical = value; + } + else if (valueName == "checkServer") + { + assetRecognizer.m_recognizer.m_checkServer = value; + } + else if (valueName == "supportsCreateJobs") + { + assetRecognizer.m_recognizer.m_supportsCreateJobs = value; + } + else if (valueName == "outputProductDependencies") + { + assetRecognizer.m_recognizer.m_outputProductDependencies = value; + } + } + + void RCVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) + { + if (m_rcNameStack.empty()) + { + return; + } + + AZStd::string_view rcNameView = m_rcNameStack.top(); + auto rcName = QString::fromUtf8(rcNameView.data(), aznumeric_cast(rcNameView.size())); + + // Find AssetRecognizer identified by the top entry in the name stack + auto assetRecognizerEntryIt = AZStd::find_if(m_assetRecognizers.rbegin(), m_assetRecognizers.rend(), + [&rcName](const RCAssetRecognizer& assetRecognizer) + { + return assetRecognizer.m_recognizer.m_name == rcName; + }); + if (assetRecognizerEntryIt == m_assetRecognizers.rend()) + { + return; + } + + RCAssetRecognizer& assetRecognizer = *assetRecognizerEntryIt; + if (valueName == "priority") + { + assetRecognizer.m_recognizer.m_priority = value; + } + } + + void RCVisitor::Visit([[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) + { + if (m_rcNameStack.empty()) + { + return; + } + + // Find AssetRecognizer identified by the top entry in the name stack + AZStd::string_view rcNameView = m_rcNameStack.top(); + auto rcName = QString::fromUtf8(rcNameView.data(), aznumeric_cast(rcNameView.size())); + + auto assetRecognizerEntryIt = AZStd::find_if(m_assetRecognizers.rbegin(), m_assetRecognizers.rend(), + [&rcName](const RCAssetRecognizer& assetRecognizer) + { + return assetRecognizer.m_recognizer.m_name == rcName; + }); + if (assetRecognizerEntryIt == m_assetRecognizers.rend()) + { + return; + } + + RCAssetRecognizer& assetRecognizer = *assetRecognizerEntryIt; + + // The "pattern" and "glob" entries were previously parsed by QSettings which un-escapes the values + // To compensate for it the AssetProcessorPlatformConfig.ini was escaping the + // backslash character used to escape other characters, therefore causing a "double escape" + // situation + auto UnescapePattern = [](AZStd::string_view pattern) + { + constexpr AZStd::string_view backslashEscape = R"(\\)"; + AZStd::string unescapedResult; + while (!pattern.empty()) + { + size_t pos = pattern.find(backslashEscape); + if (pos != AZStd::string_view::npos) + { + unescapedResult += pattern.substr(0, pos); + unescapedResult += '\\'; + // Move the pattern string after the double backslash characters + pattern = pattern.substr(pos + backslashEscape.size()); + } + else + { + unescapedResult += pattern; + pattern = {}; + } + } + + return unescapedResult; + }; + + if (valueName == "pattern") + { + if (!value.empty()) + { + const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Regex; + assetRecognizer.m_recognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType); + } + } + else if (valueName == "glob") + { + // Add the glob pattern if it the matter matcher doesn't already contain a valid regex pattern + if (!assetRecognizer.m_recognizer.m_patternMatcher.IsValid()) + { + const auto patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard; + assetRecognizer.m_recognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(UnescapePattern(value), patternType); + } + } + else if (valueName == "version") + { + assetRecognizer.m_recognizer.m_version = QString::fromUtf8(value.data(), aznumeric_cast(value.size())); + } + else if (valueName == "productAssetType") + { + if (!value.empty()) + { + AZ::Uuid productAssetType{ value.data(), value.size() }; + if (!productAssetType.IsNull()) + { + assetRecognizer.m_recognizer.m_productAssetType = productAssetType; + } + } + } + else if (valueName == "params") + { + assetRecognizer.m_defaultParams = value; + } + } + + void RCVisitor::ApplyParamsOverrides(AZStd::string_view path) + { + if (m_rcNameStack.empty()) + { + return; + } + + AZStd::string_view rcNameView = m_rcNameStack.top(); + auto rcName = QString::fromUtf8(rcNameView.data(), aznumeric_cast(rcNameView.size())); + + // Find AssetRecognizer identified by the top entry in the name stack + auto assetRecognizerEntryIt = AZStd::find_if(m_assetRecognizers.rbegin(), m_assetRecognizers.rend(), + [&rcName](const RCAssetRecognizer& assetRecognizer) + { + return assetRecognizer.m_recognizer.m_name == rcName; + }); + if (assetRecognizerEntryIt == m_assetRecognizers.rend()) + { + return; + } + + RCAssetRecognizer& assetRecognizer = *assetRecognizerEntryIt; + + /* so in this particular case we want to end up with an AssetPlatformSpec struct that + has only got the platforms that 'matter' in it + so for example, if you have the following enabled platforms + [Platform PC] + tags=blah + [Platform Mac] + tags=whatever + [Platform android] + tags=mobile + + and you encounter a recognizer like: + [RC blahblah] + pattern=whatever + params=abc + mac=skip + mobile=hijklmnop + android=1234 + + then the outcome should be a recognizer which has: + pattern=whatever + pc=abc -- no tags or platforms matched but we do have a default params + android=1234 -- because even though it matched the mobile tag, platforms explicitly specified take precedence + (and no mac) -- because it matched a skip rule + + So the strategy will be to read the default params + - if present, we pre-populate all the platforms with it + - If missing, we pre-populate nothing + + Then loop over the other params and + if the key matches a tag, if it does we add/change that platform + (if its 'skip' we remove it) + if the key matches a platform, if it does we add/change that platform + (if its 'skip' we remove it) + */ + for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms) + { + AZStd::string_view currentRCParams = assetRecognizer.m_defaultParams; + // The "/Amazon/AssetProcessor/Settings/RC */" entry will be queried + AZ::IO::Path overrideParamsKey = AZ::IO::Path(AZ::IO::PosixPathSeparator); + overrideParamsKey /= path; + overrideParamsKey /= platform.m_identifier; + + AZ::SettingsRegistryInterface::FixedValueString overrideParamsValue; + // Check if the enabled platform identifier matches a key within the "RC *" object + if (m_registry.Get(overrideParamsValue, overrideParamsKey.Native())) + { + currentRCParams = overrideParamsValue; + } + else + { + // otherwise check for tags associated with the platform + for (const AZStd::string& tag : platform.m_tags) + { + overrideParamsKey.ReplaceFilename(AZ::IO::PathView(tag)); + if (m_registry.Get(overrideParamsValue, overrideParamsKey.Native())) + { + // if we get here it means we found a tag that applies to this platform + currentRCParams = overrideParamsValue; + break; + } + } + } - unsigned int GetCrc(const char* name) - { - return AssetUtilities::ComputeCRC32(name); + // now generate a platform spec as long as we're not skipping + if (!AZ::StringFunc::Equal(currentRCParams, "skip")) + { + auto platformIdentifier = QString::fromUtf8(platform.m_identifier.data(), + aznumeric_cast(platform.m_identifier.size())); + AssetPlatformSpec spec; + // a special case exists where this is "overriding" an underlying version. + // in this case, unless some string was specified for the overrider, we use the underlying one + if (!currentRCParams.empty()) + { + spec.m_extraRCParams = QString::fromUtf8(currentRCParams.data(), aznumeric_cast(currentRCParams.size())); + } + else + { + if (assetRecognizer.m_recognizer.m_platformSpecs.contains(platformIdentifier)) + { + // carry over the prior + spec.m_extraRCParams = assetRecognizer.m_recognizer.m_platformSpecs[platformIdentifier].m_extraRCParams; + } + } + assetRecognizer.m_recognizer.m_platformSpecs[platformIdentifier] = spec; + } + } } -} -namespace AssetProcessor -{ const char AssetConfigPlatformDir[] = "AssetProcessorConfig/"; const char AssetProcessorPlatformConfigFileName[] = "AssetProcessorPlatformConfig.ini"; const char RestrictedPlatformDir[] = "restricted"; @@ -42,32 +682,27 @@ namespace AssetProcessor { } - bool PlatformConfiguration::AddPlatformConfigFilePaths(QStringList& configFilePaths) + bool PlatformConfiguration::AddPlatformConfigFilePaths(AZStd::vector& configFilePaths) { - QDir engineRoot; - AssetUtilities::ComputeEngineRoot(engineRoot); - QString configWildcardName{ "*" }; - configWildcardName.append(AssetProcessorPlatformConfigFileName); - - // first collect public platform configs - QStringList platformList = FindWildcardMatches(engineRoot.filePath(AssetConfigPlatformDir), configWildcardName); - - // then collect restricted platform configs - QDirIterator it(engineRoot.filePath(RestrictedPlatformDir), QDir::NoDotAndDotDot | QDir::Dirs); - while (it.hasNext()) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) { - QDir platformDir(it.next()); - platformList << FindWildcardMatches(platformDir.filePath(AssetConfigPlatformDir), configWildcardName); + AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not available, the " + "Engine Root folder cannot be queried") + return false; } - - for (const auto& thisConfig : platformList) + AZ::IO::FixedMaxPath engineRoot; + if (!settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) { - configFilePaths.append(thisConfig); + AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to find Engine Root in Settings Registry"); + return false; } - return (platformList.size() > 0); + + return AzToolsFramework::AssetUtils::AddPlatformConfigFilePaths(engineRoot.Native(), configFilePaths); } - bool PlatformConfiguration::InitializeFromConfigFiles(QString absoluteSystemRoot, QString absoluteAssetRoot, QString gameName, bool addPlatformConfigs, bool addGemsConfigs) + bool PlatformConfiguration::InitializeFromConfigFiles(const QString& absoluteSystemRoot, const QString& absoluteAssetRoot, + const QString& projectPath, bool addPlatformConfigs, bool addGemsConfigs) { // this function may look strange, but the point here is that each section in the config file // can depend on entries from the prior section, but also, each section can be overridden by @@ -87,27 +722,53 @@ namespace AssetProcessor static const char ScanFolderPatternOption[] = "scanfolderpattern"; QStringList scanFolderPatterns; - if (commandLine->HasSwitch(ScanFolderPatternOption)) + if (commandLine && commandLine->HasSwitch(ScanFolderPatternOption)) { for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(ScanFolderPatternOption); idx++) { scanFolderPatterns.push_back(commandLine->GetSwitchValue(ScanFolderPatternOption, idx).c_str()); } } - QStringList configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(absoluteSystemRoot.toUtf8().constData(), absoluteAssetRoot.toUtf8().constData(), gameName.toUtf8().constData(), addPlatformConfigs, addGemsConfigs && !noGemScanFolders); - // first, read the platform informations. - for (QString configFile : configFiles) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) + { + AZ_Error(AssetProcessor::ConsoleChannel, false, "There is no Global Settings Registry set." + " Unable to merge AssetProcessor config files(*.ini) and Asset processor settings registry files(*.setreg)"); + return false; + } + + AZStd::vector configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(absoluteSystemRoot.toUtf8().constData(), + absoluteAssetRoot.toUtf8().constData(), projectPath.toUtf8().constData(), + addPlatformConfigs, addGemsConfigs && !noGemScanFolders, settingsRegistry); + + // First Merge all Engine, Gem and Project specific AssetProcessor*Config.setreg/.inifiles + for (const AZ::IO::Path& configFile : configFiles) + { + if (AZ::IO::SystemFile::Exists(configFile.c_str())) + { + MergeConfigFileToSettingsRegistry(*settingsRegistry, configFile); + } + } + + // Merge the Command Line to the Settings Registry after merging the AssetProcessor*Config.setreg/ini files + // to allow the command line to override the settings + #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) + if (commandLine) { - ReadPlatformInfosFromConfigFile(configFile); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, *commandLine, true); } + #endif + + // first, read the platform informations. + ReadPlatformInfosFromSettingsRegistry(); // now read which platforms are currently enabled - this may alter the platform infos array and eradicate // the ones that are not suitable and currently enabled, leaving only the ones enabled either on command line // or config files. - // the command line can always takes precidence - but can only turn on and off platforms, it cannot describe them. + // the command line can always takes precedence - but can only turn on and off platforms, it cannot describe them. - PopulateEnabledPlatforms(configFiles); + PopulateEnabledPlatforms(); FinalizeEnabledPlatforms(); @@ -133,22 +794,19 @@ namespace AssetProcessor } } // Then read recognizers (which depend on platforms) - for (QString configFile : configFiles) + if (!ReadRecognizersFromSettingsRegistry(absoluteAssetRoot, noConfigScanFolders, scanFolderPatterns)) { - if (!ReadRecognizersFromConfigFile(configFile, noConfigScanFolders, scanFolderPatterns)) + if (m_fatalError.empty()) { - if (m_fatalError.empty()) - { - m_fatalError = "Unable to read recognizers specified in the configuration files during load. Please check the Asset Processor platform ini files for errors."; - } - return IsValid(); + m_fatalError = "Unable to read recognizers specified in the configuration files during load. Please check the Asset Processor platform ini files for errors."; } + return IsValid(); } if (!noGemScanFolders && addGemsConfigs) { - if (!AzToolsFramework::AssetUtils::GetGemsInfo(absoluteSystemRoot.toUtf8().constData(), absoluteAssetRoot.toUtf8().constData(), gameName.toUtf8().constData(), m_gemInfoList)) + if (settingsRegistry == nullptr || !AzFramework::GetGemsInfo(m_gemInfoList, *settingsRegistry)) { - AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to Get Gems Info for the project (%s).", gameName.toUtf8().constData()); + AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to Get Gems Info for the project (%s).", projectPath.toUtf8().constData()); return false; } @@ -156,10 +814,7 @@ namespace AssetProcessor AddGemScanFolders(m_gemInfoList); } // Then read metadata (which depends on scan folders) - for (QString configFile : configFiles) - { - ReadMetaDataFromConfigFile(configFile); - } + ReadMetaDataFromSettingsRegistry(); // at this point there should be at least some watch folders besides gems. if (m_scanFolders.empty()) @@ -171,17 +826,18 @@ namespace AssetProcessor return IsValid(); } - void PlatformConfiguration::PopulateEnabledPlatforms(QStringList configFiles) + void PlatformConfiguration::PopulateEnabledPlatforms() { // if there are no platform informations inside the ini file, there's no point in proceeding // since we are unaware of the existence of the platform at all if (m_enabledPlatforms.empty()) { - AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no [Platform xxxxxx] entries present in the config file(s). We cannot proceed."); + AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no \"%s/Platform xxxxxx\" entries present in the settings registry. We cannot proceed.", + AssetProcessorSettingsKey); return; } - // the command line can always takes precidence - but can only turn on and off platforms, it cannot describe them. + // the command line can always takes precedence - but can only turn on and off platforms, it cannot describe them. QStringList commandLinePlatforms = AssetUtilities::ReadPlatformsFromCommandLine(); if (!commandLinePlatforms.isEmpty()) @@ -194,34 +850,42 @@ namespace AssetProcessor QString platform = platformFromCommandLine.toLower().trimmed(); if (!platform.isEmpty()) { - if (!m_tempEnabledPlatforms.contains(platform)) + AZStd::string platformOverride{ platform.toUtf8().data() }; + if (auto foundIt = AZStd::find(m_tempEnabledPlatforms.begin(), m_tempEnabledPlatforms.end(), platformOverride); + foundIt == m_tempEnabledPlatforms.end()) { - m_tempEnabledPlatforms.push_back(platform); + m_tempEnabledPlatforms.push_back(AZStd::move(platformOverride)); } } } return; // command line wins! } - // command line isn't active, read from config files instead. - QStringList enabledPlatforms = AzToolsFramework::AssetUtils::GetEnabledPlatforms(configFiles); - - for (const QString& enabledPlatform : enabledPlatforms) + // command line isn't active, read from settings registry instead. + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) { - m_tempEnabledPlatforms.push_back(enabledPlatform); + AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platforms")" + " settings paths", AssetProcessorSettingsKey); + return; } + AZStd::vector enabledPlatforms; + AzToolsFramework::AssetUtils::ReadEnabledPlatformsFromSettingsRegistry(*settingsRegistry, enabledPlatforms); + + m_tempEnabledPlatforms.insert(m_tempEnabledPlatforms.end(), AZStd::make_move_iterator(enabledPlatforms.begin()), + AZStd::make_move_iterator(enabledPlatforms.end())); } void PlatformConfiguration::FinalizeEnabledPlatforms() { #if defined(AZ_ENABLE_TRACING) // verify command line platforms are valid: - for (const QString& enabledPlatformFromConfigs : m_tempEnabledPlatforms) + for (const auto& enabledPlatformFromConfigs : m_tempEnabledPlatforms) { bool found = false; for (const AssetBuilderSDK::PlatformInfo& platformInfo : m_enabledPlatforms) { - if (platformInfo.m_identifier == enabledPlatformFromConfigs.toUtf8().data()) + if (platformInfo.m_identifier == enabledPlatformFromConfigs) { found = true; break; @@ -229,7 +893,9 @@ namespace AssetProcessor } if (!found) { - m_fatalError = AZStd::string::format("Platform in config file or command line '%s' matches no [Platform xxxxxx] entries present in the config file(s) - check command line and config files for errors!", enabledPlatformFromConfigs.toUtf8().constData()); + + m_fatalError = AZStd::string::format(R"(The list of enabled platforms in the settings registry does not contain platform "%s")" + " entries - check command line and settings registry files for errors!", enabledPlatformFromConfigs.c_str()); return; } } @@ -240,7 +906,8 @@ namespace AssetProcessor { const AssetBuilderSDK::PlatformInfo& platformInfo = m_enabledPlatforms[enabledPlatformIdx]; - if (!m_tempEnabledPlatforms.contains(platformInfo.m_identifier.c_str())) + if (auto foundIt = AZStd::find(m_tempEnabledPlatforms.begin(), m_tempEnabledPlatforms.end(), platformInfo.m_identifier); + foundIt == m_tempEnabledPlatforms.end()) { m_enabledPlatforms.erase(m_enabledPlatforms.cbegin() + enabledPlatformIdx); } @@ -248,94 +915,41 @@ namespace AssetProcessor if (m_enabledPlatforms.empty()) { - AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no [Platform xxxxxx] entries present in the config file(s) after parsing files and command line. We cannot proceed."); + AZ_Warning(AssetProcessor::ConsoleChannel, false, "There are no \"%s/Platform xxxxxx\" entry present in the settings registry. We cannot proceed.", + AssetProcessorSettingsKey); return; } m_tempEnabledPlatforms.clear(); } - void PlatformConfiguration::ReadPlatformInfosFromConfigFile(QString iniPath) + void PlatformConfiguration::ReadPlatformInfosFromSettingsRegistry() { - if (QFile::exists(iniPath)) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) { - QSettings loader(iniPath, QSettings::IniFormat); - - QStringList groups = loader.childGroups(); - for (QString group : groups) - { - if (!group.startsWith("Platform ", Qt::CaseInsensitive)) - { - continue; - } - - loader.beginGroup(group); - QString platformIdentifier = group.mid(9); // chop off the "Platform " and you're left with the remainder name - platformIdentifier = platformIdentifier.trimmed().toLower(); - - QVariant paramValue = loader.value("tags", QString()); - QString platformTagString = paramValue.type() == QVariant::StringList ? paramValue.toStringList().join(",") : paramValue.toString(); - - QStringList platformTagsQt = platformTagString.split(QChar(','), Qt::SkipEmptyParts); - AZStd::unordered_set platformTagsAZ; - - for (const QString& tag : platformTagsQt) - { - QString cleaned = tag.trimmed().toLower(); - if (!cleaned.isEmpty()) - { - QByteArray utf8Encoded = tag.toUtf8(); - platformTagsAZ.insert(utf8Encoded.constData()); - } - } - - EnablePlatform(AssetBuilderSDK::PlatformInfo(platformIdentifier.toUtf8().constData(), platformTagsAZ), true); - - loader.endGroup(); - } + AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platform *")" + " settings paths", AssetProcessorSettingsKey); + return; + } + PlatformsInfoVisitor visitor; + settingsRegistry->Visit(visitor, AssetProcessorSettingsKey); + for (const AssetBuilderSDK::PlatformInfo& platformInfo : visitor.m_platformInfos) + { + EnablePlatform(platformInfo, true); } } - void PlatformConfiguration::ReadEnabledPlatformsFromConfigFile(QString iniPath) + void PlatformConfiguration::ReadEnabledPlatformsFromSettingsRegistry() { - // in the inifile the platform can be missing (commented out) - // in which case it is disabled implicitly by not being there - // or it can be 'disabled' which means that it is explicitly enabled. - // or it can be 'enabled' which means that it is explicitly enabled. - - if (QFile::exists(iniPath)) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) { - QSettings loader(iniPath, QSettings::IniFormat); - - // Read in enabled platforms - loader.beginGroup("Platforms"); - QStringList keys = loader.allKeys(); - for (int idx = 0; idx < keys.count(); idx++) - { - QString val = loader.value(keys[idx]).toString(); - QString platform = keys[idx].toLower().trimmed(); - - val = val.toLower().trimmed(); - - if (val == "enabled") - { - if (!m_tempEnabledPlatforms.contains(val)) - { - m_tempEnabledPlatforms.push_back(platform); - } - } - else if (val == "disabled") - { - // disable platform explicitly. - int index = m_tempEnabledPlatforms.indexOf(platform); - if (index != -1) - { - m_tempEnabledPlatforms.removeAt(index); - } - } - } - loader.endGroup(); + AZ_Error(AssetProcessor::ConsoleChannel, false, R"(Global Settings Registry is not available, unable to read the "%s/Platforms")" + " settings paths", AssetProcessorSettingsKey); + return; } + AzToolsFramework::AssetUtils::ReadEnabledPlatformsFromSettingsRegistry(*settingsRegistry, m_tempEnabledPlatforms); } void PlatformConfiguration::PopulatePlatformsForScanFolder(AZStd::vector& platformsList, QStringList includeTagsList, QStringList excludeTagsList) @@ -386,212 +1000,175 @@ namespace AssetProcessor } } - bool PlatformConfiguration::ReadRecognizersFromConfigFile(QString iniPath, bool skipScanFolders, QStringList scanFolderPatterns) + bool PlatformConfiguration::ReadRecognizersFromSettingsRegistry(const QString& assetRoot, bool skipScanFolders, QStringList scanFolderPatterns) { - QDir assetRoot; - AssetUtilities::ComputeAssetRoot(assetRoot); - const QString normalizedRoot = AssetUtilities::NormalizeDirectoryPath(assetRoot.absolutePath()); - const QString gameName = AssetUtilities::ComputeGameName(); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) + { + AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not set." + " Unable to read recognizers Asset Processor Settings"); + return false; + } - QDir engineRoot; - AssetUtilities::ComputeEngineRoot(engineRoot); - const QString normalizedEngineRoot = AssetUtilities::NormalizeDirectoryPath(engineRoot.absolutePath()); + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + AZ::IO::FixedMaxPath engineRoot(AZ::IO::PosixPathSeparator); + settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + engineRoot = engineRoot.LexicallyNormal(); // Normalize the path to use posix slashes - if (QFile::exists(iniPath)) + AZ::s64 jobCount = m_minJobs; + if (settingsRegistry->Get(jobCount, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/Jobs/minJobs")) { - QSettings loader(iniPath, QSettings::IniFormat); + m_minJobs = aznumeric_cast(jobCount); + } - loader.beginGroup("Jobs"); - m_minJobs = loader.value("minJobs", m_minJobs).toInt(); - m_maxJobs = loader.value("maxJobs", m_maxJobs).toInt(); - loader.endGroup(); + jobCount = m_maxJobs; + if (settingsRegistry->Get(jobCount, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/Jobs/maxJobs")) + { + m_maxJobs = aznumeric_cast(jobCount); + } - // Read in scan folders and RC flags per asset/platform - QStringList groups = loader.childGroups(); - for (QString group : groups) + if (!skipScanFolders) + { + ScanFolderVisitor visitor; + settingsRegistry->Visit(visitor, AssetProcessorSettingsKey); + for (auto& scanFolderEntry : visitor.m_scanFolderInfos) { - if (!skipScanFolders && group.startsWith("ScanFolder ", Qt::CaseInsensitive)) + if (scanFolderEntry.m_watchPath.empty()) { - // its a scan folder! - loader.beginGroup(group); - QString watchFolder = loader.value("watch", QString()).toString(); - if (!scanFolderPatterns.empty()) - { - bool foundPattern{ false }; - for (auto& thisPattern : scanFolderPatterns) - { - QRegExp nameMatch{ thisPattern, Qt::CaseInsensitive, QRegExp::Wildcard }; - if (nameMatch.exactMatch(watchFolder)) - { - foundPattern = true; - break; - } - } - if (foundPattern == false) - { - continue; - } - } - int order = loader.value("order", 0).toInt(); - - watchFolder.replace("@root@", normalizedRoot, Qt::CaseInsensitive); - watchFolder.replace("@GAMENAME@", gameName, Qt::CaseInsensitive); - watchFolder.replace("@engineroot@", normalizedEngineRoot, Qt::CaseInsensitive); - watchFolder = AssetUtilities::NormalizeDirectoryPath(watchFolder); - - QVariant includeParams = loader.value("include", QString()); - QVariant excludeParams = loader.value("exclude", QString()); - - QString includeTagString = includeParams.type() == QVariant::StringList ? includeParams.toStringList().join(",") : includeParams.toString(); - QString excludeTagString = excludeParams.type() == QVariant::StringList ? excludeParams.toStringList().join(",") : excludeParams.toString(); - - QStringList includeIdentifiers = includeTagString.split(QChar(','), Qt::SkipEmptyParts); - QStringList excludeIdentifiers = excludeTagString.split(QChar(','), Qt::SkipEmptyParts); - - AZStd::vector platforms; - PopulatePlatformsForScanFolder(platforms, includeIdentifiers, excludeIdentifiers); - - QString outputPrefix = loader.value("output", QString()).toString(); - - // note that the old way of computing the scan folder portable key is retained below - // for purposes of database compatibility - so that assets are not recompiled unnecessarily - // this does mean that for old compatibility you may not have a watch folder configuration that has non-unique first part - // after the ScanFolder section here, meaning the following would be in conflict: - // [ScanFolder My Game] - // [ScanFolder My Gem] - // the portable key should absolutely not include the outputprefix because you can map - // multiple folders into the same output prefix, it is not a suitable unique identifier. - QString oldDisplayName = group.split(" ", Qt::SkipEmptyParts)[1]; - QString scanFolderPortableKey = QString("from-ini-file-%1").arg(oldDisplayName); - - // the new way of computing the display name involves taking everything after the "[ScanFolder " section name. - // mid(11) is everything after "ScanFolder ", so it can include spaces in its display name. - QString scanFolderDisplayName = group.mid(11); - - // Override display name and normalize outputPrefix only after the portable key has been generated. - // Since the portable key is built up using the display name, - // existing databases would see recompile on all assets within this watch folder if these aleady exist - outputPrefix = AssetUtilities::NormalizeDirectoryPath(outputPrefix); - QString overrideDisplayName = loader.value("display", QString()).toString(); - if (!overrideDisplayName.isEmpty()) - { - scanFolderDisplayName = overrideDisplayName; - } - - // you are allowed to use macros in your display name. - scanFolderDisplayName.replace("@GAMENAME@", gameName, Qt::CaseInsensitive); - scanFolderDisplayName.replace("@root@", normalizedRoot, Qt::CaseInsensitive); - scanFolderDisplayName.replace("@engineroot@", normalizedEngineRoot, Qt::CaseInsensitive); + continue; + } - bool recurse = (loader.value("recursive", 1).toInt() == 1); - bool isRoot = (watchFolder.compare(normalizedRoot, Qt::CaseInsensitive) == 0); - recurse &= !isRoot; // root never recurses + auto scanFolderMatch = [watchFolderQt = QString::fromUtf8(scanFolderEntry.m_watchPath.c_str(), + aznumeric_cast(scanFolderEntry.m_watchPath.Native().size()))](const QString& scanFolderPattern) + { + QRegExp nameMatch(scanFolderPattern, Qt::CaseInsensitive, QRegExp::Wildcard); + return nameMatch.exactMatch(watchFolderQt); + }; + if (!scanFolderPatterns.empty() && AZStd::none_of(scanFolderPatterns.begin(), scanFolderPatterns.end(), scanFolderMatch)) + { + // Continue to the next iteration if the watch folder doesn't match any of the supplied patterns + continue; + } - // New assets can be saved in any scan folder defined except for the engine root. - const bool canSaveNewAssets = !isRoot; + // Substitute macro values into the watch path and the scan folder display name + AZStd::string assetRootPath = assetRoot.toUtf8().data(); + AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@ROOT@", assetRootPath.c_str()); + AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@PROJECTROOT@", projectPath.c_str()); + AZ::StringFunc::Replace(scanFolderEntry.m_watchPath.Native(), "@ENGINEROOT@", engineRoot.c_str()); + // Normalize path make sure it is using posix slashes + scanFolderEntry.m_watchPath = scanFolderEntry.m_watchPath.LexicallyNormal(); - if (!watchFolder.isEmpty()) - { - AddScanFolder(ScanFolderInfo( - watchFolder, - scanFolderDisplayName, - scanFolderPortableKey, - outputPrefix, - isRoot, - recurse, - platforms, - order, - /*scanFolderId*/ 0, - canSaveNewAssets)); - } + AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@ROOT@", assetRootPath.c_str()); + AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@PROJECTROOT@", projectPath.c_str()); + AZ::StringFunc::Replace(scanFolderEntry.m_scanFolderDisplayName, "@ENGINEROOT@", engineRoot.c_str()); - loader.endGroup(); + QStringList includeIdentifiers; + for (AZStd::string_view includeIdentifier : scanFolderEntry.m_includeIdentifiers) + { + includeIdentifiers.push_back(QString::fromUtf8(includeIdentifier.data(), aznumeric_cast(includeIdentifier.size()))); } - - if (group.startsWith("Exclude ", Qt::CaseInsensitive)) + QStringList excludeIdentifiers; + for (AZStd::string_view excludeIdentifier : scanFolderEntry.m_excludeIdentifiers) { - loader.beginGroup(group); - - ExcludeAssetRecognizer excludeRecognizer; - excludeRecognizer.m_name = group.mid(8); // chop off the "Exclude " and you're left with the remainder name - QString pattern = loader.value("pattern", QString()).toString(); - AssetBuilderSDK::AssetBuilderPattern::PatternType patternType = AssetBuilderSDK::AssetBuilderPattern::Regex; - if (pattern.isEmpty()) - { - patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard; - pattern = loader.value("glob", QString()).toString(); - } - AZStd::string excludePattern(pattern.toUtf8().data()); - excludeRecognizer.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(excludePattern, patternType); - m_excludeAssetRecognizers[excludeRecognizer.m_name] = excludeRecognizer; - loader.endGroup(); + excludeIdentifiers.push_back(QString::fromUtf8(excludeIdentifier.data(), aznumeric_cast(excludeIdentifier.size()))); } - if (group.startsWith("RC ", Qt::CaseInsensitive)) - { - loader.beginGroup(group); + AZStd::vector platforms; + PopulatePlatformsForScanFolder(platforms, includeIdentifiers, excludeIdentifiers); - AssetRecognizer rec; - rec.m_name = group.mid(3); // chop off the "RC " and you're left with the remainder name - if (loader.value("ignore", false).toBool()) - { - // This allows a game-specific configuration to remove an AssetRecognizer that exists in - // the default configuration. For example, some projects may provide an AssetBuilder for - // a file type that normally uses RC by default. - m_assetRecognizers.remove(rec.m_name); - } - else - { - if (m_assetRecognizers.find(rec.m_name) != m_assetRecognizers.end()) - { - rec = m_assetRecognizers[rec.m_name]; - } + // Normalize the OutputPrefix to use PosixPathSeparators + scanFolderEntry.m_outputPrefix = AZ::IO::PathView(scanFolderEntry.m_outputPrefix, AZ::IO::PosixPathSeparator).LexicallyNormal().String(); - if (!ReadRecognizerFromConfig(rec, loader)) - { - return false; - } - if (!rec.m_platformSpecs.empty()) - { - m_assetRecognizers[rec.m_name] = rec; - } - } + const bool isEngineRoot = scanFolderEntry.m_watchPath == engineRoot; + // If the scan folder happens to be the engine root, it is not recursive + scanFolderEntry.m_isRecursive = scanFolderEntry.m_isRecursive && !isEngineRoot; - loader.endGroup(); - } + // New assets can be saved in any scan folder defined except for the engine root. + const bool canSaveNewAssets = !isEngineRoot; + AddScanFolder(ScanFolderInfo( + QString::fromUtf8(scanFolderEntry.m_watchPath.c_str(), aznumeric_cast(scanFolderEntry.m_watchPath.Native().size())), + QString::fromUtf8(scanFolderEntry.m_scanFolderDisplayName.c_str(), aznumeric_cast(scanFolderEntry.m_scanFolderDisplayName.size())), + QString::fromUtf8(scanFolderEntry.m_scanFolderIdentifier.c_str(), aznumeric_cast(scanFolderEntry.m_scanFolderIdentifier.size())), + QString::fromUtf8(scanFolderEntry.m_outputPrefix.c_str(), aznumeric_cast(scanFolderEntry.m_outputPrefix.size())), + isEngineRoot, + scanFolderEntry.m_isRecursive, + platforms, + scanFolderEntry.m_scanOrder, + 0, + canSaveNewAssets + )); + } + } + + ExcludeVisitor excludeVisitor; + settingsRegistry->Visit(excludeVisitor, AssetProcessorSettingsKey); + for (auto&& excludeRecognizer: excludeVisitor.m_excludeAssetRecognizers) + { + m_excludeAssetRecognizers[excludeRecognizer.m_name] = AZStd::move(excludeRecognizer); + } + + RCVisitor rcVisitor(*settingsRegistry, m_enabledPlatforms); + settingsRegistry->Visit(rcVisitor, AssetProcessorSettingsKey); + for (auto&& rcRecognizer : rcVisitor.m_assetRecognizers) + { + if (rcRecognizer.m_ignore) + { + m_assetRecognizers.remove(rcRecognizer.m_recognizer.m_name); + } + else if (!rcRecognizer.m_recognizer.m_platformSpecs.empty()) + { + m_assetRecognizers[rcRecognizer.m_recognizer.m_name] = rcRecognizer.m_recognizer; } } + return true; } - void PlatformConfiguration::ReadMetaDataFromConfigFile(QString iniPath) + void PlatformConfiguration::ReadMetaDataFromSettingsRegistry() { - if (QFile::exists(iniPath)) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry == nullptr) { - QSettings loader(iniPath, QSettings::IniFormat); + AZ_Error(AssetProcessor::ConsoleChannel, false, "Global Settings Registry is not set." + " MetaDataTypes entries cannot be read from Asset Processor Settings"); + return; + } - //Read in Metadata types - loader.beginGroup("MetaDataTypes"); - QStringList fileExtensions = loader.allKeys(); - for (int idx = 0; idx < fileExtensions.count(); idx++) - { - QString fileType = AssetUtilities::NormalizeFilePath(fileExtensions[idx]); - QString extensionType = loader.value(fileType, QString()).toString(); + MetaDataTypesVisitor visitor; + settingsRegistry->Visit(visitor, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorSettingsKey) + "/MetaDataTypes"); + for (const auto& metaDataType : visitor.m_metaDataTypes) + { + QString fileType = AssetUtilities::NormalizeFilePath(QString::fromUtf8(metaDataType.m_fileType.c_str(), + aznumeric_cast(metaDataType.m_fileType.size()))); + auto extensionType = QString::fromUtf8(metaDataType.m_extensionType.c_str(), + aznumeric_cast(metaDataType.m_extensionType.size())); - AddMetaDataType(fileType, extensionType); + AddMetaDataType(fileType, extensionType); - // Check if the Metadata 'file type' is a real file - QString fullPath = FindFirstMatchingFile(fileType); - if (!fullPath.isEmpty()) - { - m_metaDataRealFiles.insert(fileType.toLower()); - } + // Check if the Metadata 'file type' is a real file + QString fullPath = FindFirstMatchingFile(fileType); + if (!fullPath.isEmpty()) + { + m_metaDataRealFiles.insert(fileType.toLower()); } + } + } - loader.endGroup(); + bool PlatformConfiguration::MergeConfigFileToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, const AZ::IO::PathView& configFile) + { + // If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function + // otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style + // file to the settings registry + if (configFile.Extension() == ".setreg") + { + return settingsRegistry.MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch); } + + AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings; + configParserSettings.m_registryRootPointerPath = AssetProcessorSettingsKey; + return AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(settingsRegistry, configFile.Native(), configParserSettings); } const AZStd::vector& PlatformConfiguration::GetEnabledPlatforms() const @@ -626,9 +1203,9 @@ namespace AssetProcessor { // remove it if present. auto platformIt = std::find_if(m_enabledPlatforms.begin(), m_enabledPlatforms.end(), [&](const AssetBuilderSDK::PlatformInfo& info) - { - return info.m_identifier == platform.m_identifier; - }); + { + return info.m_identifier == platform.m_identifier; + }); if (platformIt != m_enabledPlatforms.end()) @@ -679,7 +1256,7 @@ namespace AssetProcessor return aznumeric_caster(m_scanFolders.size()); } - AZStd::vector PlatformConfiguration::GetGemsInformation() const + AZStd::vector PlatformConfiguration::GetGemsInformation() const { return m_gemInfoList; } @@ -702,9 +1279,9 @@ namespace AssetProcessor // Find and remove any previous matching entry, last entry wins auto it = std::find_if(m_scanFolders.begin(), m_scanFolders.end(), [&source](const ScanFolderInfo& info) - { - return info.GetPortableKey().toLower() == source.GetPortableKey().toLower(); - }); + { + return info.GetPortableKey().toLower() == source.GetPortableKey().toLower(); + }); if (it != m_scanFolders.end()) { m_scanFolders.erase(it); @@ -713,9 +1290,9 @@ namespace AssetProcessor m_scanFolders.push_back(source); std::stable_sort(m_scanFolders.begin(), m_scanFolders.end(), [](const ScanFolderInfo& a, const ScanFolderInfo& b) - { - return a.GetOrder() < b.GetOrder(); - } + { + return a.GetOrder() < b.GetOrder(); + } ); } @@ -963,199 +1540,58 @@ namespace AssetProcessor return m_maxJobs; } - - bool PlatformConfiguration::ReadRecognizerFromConfig(AssetRecognizer& target, QSettings& loader) - { - AssetBuilderSDK::AssetBuilderPattern::PatternType patternType = AssetBuilderSDK::AssetBuilderPattern::Regex; - QString pattern = loader.value("pattern", QString()).toString(); - if (pattern.isEmpty()) - { - patternType = AssetBuilderSDK::AssetBuilderPattern::Wildcard; - pattern = loader.value("glob", QString()).toString(); - } - - if (pattern.isEmpty()) - { - if (!target.m_patternMatcher.IsValid()) - { - // no pattern present and we are NOT overriding an existing one. - AZ_Warning(AssetProcessor::ConsoleChannel, false, "No pattern was found in config %s while reading platform config.\n", target.m_name.toUtf8().data()); - return false; - } - } - else - { - // we have provided a non-empty one, override the existing one. - target.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(AZStd::string(pattern.toUtf8().data()), patternType); - - if (!target.m_patternMatcher.IsValid()) - { - // no pattern present - AZ_Warning(AssetProcessor::ConsoleChannel, false, "Invalid pattern in %s while reading platform config : %s \n", - target.m_name.toUtf8().data(), - target.m_patternMatcher.GetErrorString().c_str()); - return false; - } - } - - /* so in this particular case we want to end up with an AssetPlatformSpec struct that - has only got the platforms that 'matter' in it - so for example, if you have the following enabled platforms - [Platform PC] - tags=blah - [Platform Mac] - tags=whatever - [Platform android] - tags=mobile - - and you encounter a recognizer like: - [RC blahblah] - pattern=whatever - params=abc - mac=skip - mobile=hijklmnop - android=1234 - - then the outcome should be a recognizer which has: - pattern=whatever - pc=abc -- no tags or platforms matched but we do have a default params - android=1234 -- because even though it matched the mobile tag, platforms explicitly specified take precidence - (and no mac) -- because it matched a skip rule - - So the stragegy will be to read the default params - - if present, we prepopulate all th platforms with it - - If missing, we prepopulate nothing - - Then loop over the other params and - if the key matches a tag, if it does we add/change that platform - (if its 'skip' we remove it) - if the key matches a platform, if it does we add/change that platform - (if its 'skip' we remove it) - */ - - // Qt actually has a custom INI parse which treats commas as string lists. - // so if we want the original (with commas) we have to check for that - QVariant paramValue = loader.value("params", QString()); - QString defaultParams = paramValue.type() == QVariant::StringList ? paramValue.toStringList().join(",") : paramValue.toString(); - - for (const AssetBuilderSDK::PlatformInfo& platform : m_enabledPlatforms) - { - QString platformIdentifier = QString::fromUtf8(platform.m_identifier.c_str()); - QString currentRCParams = defaultParams; // blank default is okay. - - // first, iterate over tags - for (const AZStd::string& tag : platform.m_tags) - { - paramValue = loader.value(tag.c_str(), QString()); - QString tagParams = paramValue.type() == QVariant::StringList ? paramValue.toStringList().join(",") : paramValue.toString(); - - if (!tagParams.isEmpty()) - { - // if we get here it means we found a tag that applies to this platform int he rc block. - currentRCParams = tagParams; - } - } - - // now check if there's a specific platform tag (like "Pc"=whatever) - paramValue = loader.value(platformIdentifier, QString()); - QString platformSpecificParams = paramValue.type() == QVariant::StringList ? paramValue.toStringList().join(",") : paramValue.toString(); - - if (!platformSpecificParams.isEmpty()) - { - currentRCParams = platformSpecificParams; - } - - // now generate a platform spec as long as we're not skipping - if (currentRCParams.trimmed().compare("skip", Qt::CaseInsensitive) != 0) - { - AssetPlatformSpec spec; - // a special case exists where this is "overriding" an underlying version. - // in this case, unless some string was specified for the overrider, we use the underlying one - if (!currentRCParams.isEmpty()) - { - spec.m_extraRCParams = currentRCParams; - } - else - { - if (target.m_platformSpecs.contains(platformIdentifier)) - { - // carry over the prior - spec.m_extraRCParams = target.m_platformSpecs[platformIdentifier].m_extraRCParams; - } - } - target.m_platformSpecs[platformIdentifier] = spec; - } - } - - target.m_version = loader.value("version", QString()).toString(); - target.m_testLockSource = loader.value("lockSource", false).toBool(); - target.m_isCritical = loader.value("critical", false).toBool(); - target.m_checkServer = loader.value("checkServer", false).toBool(); - target.m_supportsCreateJobs = loader.value("supportsCreateJobs", false).toBool(); - target.m_priority = loader.value("priority", 0).toInt(); - QString assetTypeString = loader.value("productAssetType", QString()).toString(); - target.m_outputProductDependencies = loader.value("outputProductDependencies", false).toBool(); - if (!assetTypeString.isEmpty()) - { - target.m_productAssetType = AZ::Uuid(assetTypeString.toUtf8().data()); - if (target.m_productAssetType.IsNull()) - { - // you specified a UUID and it did not read. A warning will have already been issued - return false; - } - } - - - return true; - } - - void PlatformConfiguration::AddGemScanFolders(const AZStd::vector& gemInfoList) + void PlatformConfiguration::AddGemScanFolders(const AZStd::vector& gemInfoList) { int gemOrder = g_gemStartingOrder; - int gemGameOrder = 1; // game gems are very high priority, start at 1 onwards. AZStd::vector platforms; PopulatePlatformsForScanFolder(platforms); - for (const AzToolsFramework::AssetUtils::GemInfo& gemElement : gemInfoList) - { - QString gemGuid = gemElement.m_identifier.c_str(); - QString gemAbsolutePath = gemElement.m_absoluteFilePath.c_str(); // this is an absolute path! - QString gemDisplayName = gemElement.m_gemName.c_str(); - QString gemRelativePath = gemElement.m_relativeFilePath.c_str(); - - QDir gemDir(gemAbsolutePath); - - // The gems /Assets/ folders are always added to the watch list, we want the following params - // Watched folder: (absolute path to the gem /Assets/ folder) MUST BE CORRECT CASE - // Display name: "Gems/GemName/Assets" // uppercase, for human eyes - // portable Key: "gemassets-(UUID Of Gem)" - // Output Prefix: "" // empty string - this means put it in @assets@ as per default - // Is Root: False - // Recursive: True - QString gemFolder = gemDir.absoluteFilePath(AzToolsFramework::AssetUtils::GemInfo::GetGemAssetFolder().c_str()); - - // note that we normalize this gem path with slashes so that there's nothing special about it compared to other scan folders - gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder); - - QString assetBrowserDisplayName = AzToolsFramework::AssetUtils::GemInfo::GetGemAssetFolder().c_str(); // Gems always use assets folder as their displayname... - QString portableKey = QString("gemassets-%1").arg(gemGuid); - QString outputPrefix; // empty intentionally here - bool isRoot = false; - bool isRecursive = true; - int order = gemElement.m_isGameGem ? gemGameOrder++ : gemOrder++; - - AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM assets folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data()); - AddScanFolder(ScanFolderInfo( - gemFolder, - assetBrowserDisplayName, - portableKey, - outputPrefix, - isRoot, - isRecursive, - platforms, - order, - /*scanFolderId*/ 0, - /*canSaveNewAssets*/ true)); // Users can create assets like slices in Gem asset folders. + for (const AzFramework::GemInfo& gemElement : gemInfoList) + { + for (size_t sourcePathIndex{}; sourcePathIndex < gemElement.m_absoluteSourcePaths.size(); ++sourcePathIndex) + { + const AZ::IO::Path& absoluteSourcePath = gemElement.m_absoluteSourcePaths[sourcePathIndex]; + QString gemAbsolutePath = QString::fromUtf8(absoluteSourcePath.c_str(), aznumeric_cast(absoluteSourcePath.Native().size())); // this is an absolute path! + // Append the index of the source path array element to make a unique portable key is created for each path of a gem + AZ::Uuid gemNameUuid = AZ::Uuid::CreateName((gemElement.m_gemName + AZStd::to_string(sourcePathIndex)).c_str()); + char gemNameToUuidBuffer[AZ::Uuid::MaxStringBuffer]; + gemNameUuid.ToString(gemNameToUuidBuffer); + QString gemNameAsUuid(gemNameToUuidBuffer); + + QDir gemDir(gemAbsolutePath); + + // The gems /Assets/ folders are always added to the watch list, we want the following params + // Watched folder: (absolute path to the gem /Assets/ folder) MUST BE CORRECT CASE + // Display name: "Gems/GemName/Assets" // uppercase, for human eyes + // portable Key: "gemassets-(UUID Of Gem)" + // Output Prefix: "" // empty string - this means put it in @assets@ as per default + // Is Root: False + // Recursive: True + QString gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemAssetFolder()); + + // note that we normalize this gem path with slashes so that there's nothing special about it compared to other scan folders + gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder); + + QString assetBrowserDisplayName = AzFramework::GemInfo::GetGemAssetFolder(); // Gems always use assets folder as their displayname... + QString portableKey = QString("gemassets-%1").arg(gemNameAsUuid); + QString outputPrefix; // empty intentionally here + bool isRoot = false; + bool isRecursive = true; + gemOrder++; + + AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM assets folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data()); + AddScanFolder(ScanFolderInfo( + gemFolder, + assetBrowserDisplayName, + portableKey, + outputPrefix, + isRoot, + isRecursive, + platforms, + gemOrder, + /*scanFolderId*/ 0, + /*canSaveNewAssets*/ true)); // Users can create assets like slices in Gem asset folders. + } } } @@ -1201,15 +1637,15 @@ namespace AssetProcessor { if (m_enabledPlatforms.empty()) { - m_fatalError = "The configuration is invalid - no platforms appear to be enabled. Check to make sure that the AssetProcessorPlatformConfig.ini file(s) are present and correct."; + m_fatalError = "The configuration is invalid - no platforms appear to be enabled. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct."; } else if (m_assetRecognizers.empty()) { - m_fatalError = "The configuration is invalid - no matching asset recognizers appear valid. Check to make sure that the AssetProcessorPlatformConfig.ini file(s) are present and correct."; + m_fatalError = "The configuration is invalid - no matching asset recognizers appear valid. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct."; } else if (m_scanFolders.empty()) { - m_fatalError = "The configuration is invalid - no scan folders defined. Check to make sure that the AssetProcessorPlatformConfig.ini file(s) are present and correct."; + m_fatalError = "The configuration is invalid - no scan folders defined. Check to make sure that the AssetProcessorPlatformConfig.setreg file(s) are present and correct."; } } diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.h b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.h index 61c00035e6..f10493ea42 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.h +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -29,10 +30,15 @@ #include #endif -class QSettings; + +namespace AZ +{ + class SettingsRegistryInterface; +} namespace AssetProcessor { + inline constexpr const char* AssetProcessorSettingsKey{ "/Amazon/AssetProcessor/Settings" }; class PlatformConfiguration; class ScanFolderInfo; extern const char AssetConfigPlatformDir[]; @@ -105,6 +111,73 @@ namespace AssetProcessor virtual const ExcludeRecognizerContainer& GetExcludeAssetRecognizerContainer() const = 0; }; + //! Visitor for reading the "/Amazon/AssetProcessor/Settings/ScanFolder *" entries from the Settings Registry + //! Expects the key to path to the visitor to be "/Amazon/AssetProcessor/Settings" + struct ScanFolderVisitor + : AZ::SettingsRegistryInterface::Visitor + { + AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override; + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) override; + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override; + + struct ScanFolderInfo + { + AZStd::string m_scanFolderIdentifier; + AZStd::string m_scanFolderDisplayName; + AZ::IO::Path m_watchPath{ AZ::IO::PosixPathSeparator }; + AZStd::vector m_includeIdentifiers; + AZStd::vector m_excludeIdentifiers; + AZStd::string m_outputPrefix; + int m_scanOrder{}; + bool m_isRecursive{}; + }; + AZStd::vector m_scanFolderInfos; + private: + AZStd::stack m_scanFolderStack; + }; + + struct ExcludeVisitor + : AZ::SettingsRegistryInterface::Visitor + { + AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override; + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override; + + AZStd::vector m_excludeAssetRecognizers; + private: + AZStd::stack m_excludeNameStack; + }; + + struct RCVisitor + : AZ::SettingsRegistryInterface::Visitor + { + RCVisitor(const AZ::SettingsRegistryInterface& settingsRegistry, const AZStd::vector& enabledPlatforms) + : m_registry(settingsRegistry) + , m_enabledPlatforms(enabledPlatforms) + { + } + AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override; + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value) override; + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) override; + void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override; + + struct RCAssetRecognizer + { + AssetRecognizer m_recognizer; + AZStd::string m_defaultParams; + bool m_ignore{}; + }; + AZStd::vector m_assetRecognizers; + private: + void ApplyParamsOverrides(AZStd::string_view path); + + AZStd::stack m_rcNameStack; + const AZ::SettingsRegistryInterface& m_registry; + const AZStd::vector& m_enabledPlatforms; + }; + /** Reads the platform ini configuration file to determine * platforms for which assets needs to be build */ @@ -127,22 +200,23 @@ namespace AssetProcessor * Note that order of the config files is relevant - later files override settings in * files that are earlier. **/ - bool InitializeFromConfigFiles(QString absoluteSystemRoot, QString absoluteAssetRoot, QString gameName, bool addPlatformConfigs = true, bool addGemsConfigs = true); + bool InitializeFromConfigFiles(const QString& absoluteSystemRoot, const QString& absoluteAssetRoot, const QString& projectPath, bool addPlatformConfigs = true, bool addGemsConfigs = true); - QString PlatformName(unsigned int platformCrc) const; - QString RendererName(unsigned int rendererCrc) const; + //! Merge an AssetProcessor*Config.ini path to the Settings Registry + //! The settings are anchored underneath the AssetProcessor::AssetProcessorSettingsKey JSON pointer + static bool MergeConfigFileToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, const AZ::IO::PathView& filePathView); const AZStd::vector& GetEnabledPlatforms() const; const AssetBuilderSDK::PlatformInfo* const GetPlatformByIdentifier(const char* identifier) const; //! Add AssetProcessor config files from platform specific folders - bool AddPlatformConfigFilePaths(QStringList& configList); + bool AddPlatformConfigFilePaths(AZStd::vector& configList); int MetaDataFileTypesCount() const { return m_metaDataFileTypes.count(); } // Metadata file types are (meta file extension, original file extension - or blank if its tacked on the end instead of replacing). // so for example if its // blah.tif + blah.tif.metadata, then its ("metadata", "") - // but if its blah.tif + blah.metadata (rplacing tif, data is lost) then its ("metadata", "tif") + // but if its blah.tif + blah.metadata (replacing tif, data is lost) then its ("metadata", "tif") QPair GetMetaDataFileTypeAt(int pos) const; // Metadata extensions can also be a real file, to create a dependency on file types if a specific file changes @@ -160,7 +234,7 @@ namespace AssetProcessor int GetScanFolderCount() const; //! Return the gems info list - AZStd::vector GetGemsInformation() const; + AZStd::vector GetGemsInformation() const; //! Retrieve the scan folder at a given index. AssetProcessor::ScanFolderInfo& GetScanFolderAt(int index); @@ -249,18 +323,18 @@ namespace AssetProcessor protected: // call this first, to populate the list of platform informations - void ReadPlatformInfosFromConfigFile(QString fileSource); + void ReadPlatformInfosFromSettingsRegistry(); // call this next, in order to find out what platforms are enabled - void PopulateEnabledPlatforms(QStringList configFiles); - // finaly, call this, in order to delete the platforminfos for non-enabled platforms + void PopulateEnabledPlatforms(); + // finally, call this, in order to delete the platforminfos for non-enabled platforms void FinalizeEnabledPlatforms(); // iterate over all the gems and add their folders to the "scan folders" list as appropriate. - void AddGemScanFolders(const AZStd::vector& gemInfoList); + void AddGemScanFolders(const AZStd::vector& gemInfoList); - void ReadEnabledPlatformsFromConfigFile(QString fileSource); - bool ReadRecognizersFromConfigFile(QString fileSource, bool skipScanFolders = false, QStringList scanFolderPatterns = QStringList() ); - void ReadMetaDataFromConfigFile(QString fileSource); + void ReadEnabledPlatformsFromSettingsRegistry(); + bool ReadRecognizersFromSettingsRegistry(const QString& assetRoot, bool skipScanFolders = false, QStringList scanFolderPatterns = QStringList() ); + void ReadMetaDataFromSettingsRegistry(); private: AZStd::vector m_enabledPlatforms; @@ -269,15 +343,13 @@ namespace AssetProcessor AZStd::vector m_scanFolders; QList > m_metaDataFileTypes; QSet m_metaDataRealFiles; - AZStd::vector m_gemInfoList; + AZStd::vector m_gemInfoList; int m_minJobs = 1; int m_maxJobs = 3; // used only during file read, keeps the total running list of all the enabled platforms from all config files and command lines - QStringList m_tempEnabledPlatforms; - - bool ReadRecognizerFromConfig(AssetRecognizer& target, QSettings& loader); // assumes the group is already selected + AZStd::vector m_tempEnabledPlatforms; ///! if non-empty, fatalError contains the error that occurred during read. ///! it will be printed out to the log when diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index de7130227a..b6df2dd28a 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -38,7 +37,9 @@ #include #include +#include #include +#include #include #include @@ -77,7 +78,7 @@ namespace AssetUtilsInternal { if (waitTimeInSeconds < 0) { - AZ_Warning("Asset Processor", waitTimeInSeconds >= 0, "Invalid timeout specified by the user") + AZ_Warning("Asset Processor", waitTimeInSeconds >= 0, "Invalid timeout specified by the user"); waitTimeInSeconds = 0; } bool failureOccurredOnce = false; // used for logging. @@ -152,12 +153,64 @@ namespace AssetUtilsInternal return true; } + + static bool DumpAssetProcessorUserSettingsToFile(AZ::SettingsRegistryInterface& settingsRegistry, + const AZ::IO::FixedMaxPath& setregPath) + { + // The AssetProcessor settings are currently under the Bootstrap object(This may change in the future + constexpr AZStd::string_view AssetProcessorUserSettingsRootKey = AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey; + AZStd::string apSettingsJson; + AZ::IO::ByteContainerStream apSettingsStream(&apSettingsJson); + + AZ::SettingsRegistryMergeUtils::DumperSettings apDumperSettings; + apDumperSettings.m_prettifyOutput = true; + apDumperSettings.m_includeFilter = [&AssetProcessorUserSettingsRootKey](AZStd::string_view path) + { + // The AssetUtils only updates the following keys in the registry + // Dump them all out to the setreg file + auto allowedListKey = AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorUserSettingsRootKey) + + "/allowed_list"; + auto branchTokenKey = AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorUserSettingsRootKey) + + "/assetProcessor_branch_token"; + // The objects leading up to the keys to dump must be included in order the keys to be dumped + return allowedListKey.starts_with(path.substr(0, allowedListKey.size())) + || branchTokenKey.starts_with(path.substr(0, branchTokenKey.size())); + }; + apDumperSettings.m_jsonPointerPrefix = AssetProcessorUserSettingsRootKey; + + if (AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(settingsRegistry, AssetProcessorUserSettingsRootKey, + apSettingsStream, apDumperSettings)) + { + + constexpr auto modeFlags = AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE + | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH; + if (AZ::IO::SystemFile apSetregFile; apSetregFile.Open(setregPath.c_str(), modeFlags)) + { + size_t bytesWritten = apSetregFile.Write(apSettingsJson.data(), apSettingsJson.size()); + return bytesWritten == apSettingsJson.size(); + } + else + { + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to open AssetProcessor user setreg file (%s)\n", setregPath.c_str()); + } + } + else + { + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Dump of AssetProcessor User Settings failed at JSON pointer %.*s \n", + aznumeric_cast(AssetProcessorUserSettingsRootKey.size()), AssetProcessorUserSettingsRootKey.data()); + } + + return false; + } } namespace AssetUtilities { + constexpr AZStd::string_view AssetProcessorUserSetregRelPath = "user/Registry/asset_processor.setreg"; + // do not place Qt objects in global scope, they allocate and refcount threaded data. - AZ::SettingsRegistryInterface::FixedValueString s_gameName; + AZ::SettingsRegistryInterface::FixedValueString s_projectPath; + AZ::SettingsRegistryInterface::FixedValueString s_projectName; AZ::SettingsRegistryInterface::FixedValueString s_assetRoot; AZ::SettingsRegistryInterface::FixedValueString s_assetServerAddress; AZ::SettingsRegistryInterface::FixedValueString s_cachedEngineRoot; @@ -191,7 +244,7 @@ namespace AssetUtilities void ResetGameName() { - s_gameName = {}; + s_projectName = {}; } bool CopyDirectory(QDir source, QDir destination) @@ -245,7 +298,7 @@ namespace AssetUtilities return true; } - bool ComputeAssetRoot(QDir& root, const QDir* appRootOverride) + bool ComputeAssetRoot(QDir& root, const QDir* rootOverride) { if (!s_assetRoot.empty()) { @@ -253,10 +306,10 @@ namespace AssetUtilities return true; } - // Use the appRoot if supplied is supplied and not an empty string - if (appRootOverride && !appRootOverride->path().isEmpty()) + // Use the override if supplied and not an empty string + if (rootOverride && !rootOverride->path().isEmpty()) { - root = *appRootOverride; + root = *rootOverride; s_assetRoot = root.absolutePath().toUtf8().constData(); return true; } @@ -288,7 +341,7 @@ namespace AssetUtilities return true; } - // The EngineRootFolder Key has not been found in the SettingsRegistry, log an warning about + // The EngineRootFolder Key has not been found in the SettingsRegistry auto engineRootError = AZ::SettingsRegistryInterface::FixedValueString::format("The EngineRootFolder is not set in the SettingsRegistry at key %s.", AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); AssetProcessor::MessageInfoBus::Broadcast(&AssetProcessor::MessageInfoBusTraits::OnErrorMessage, engineRootError.c_str()); @@ -296,7 +349,7 @@ namespace AssetUtilities return false; } - //! Get the engine root folder + //! Get the external engine root folder if the engine is external to the current root folder. //! If the current root folder is also the engine folder, then this behaves the same as ComputeEngineRoot bool ComputeEngineRoot(QDir& root, const QDir* engineRootOverride) { @@ -312,6 +365,7 @@ namespace AssetUtilities AssetUtilities::ComputeAssetRoot(root, engineRootOverride); } + AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); // Use the engineRootOverride if supplied and not empty if (engineRootOverride && !engineRootOverride->path().isEmpty()) { @@ -320,11 +374,11 @@ namespace AssetUtilities return true; } - AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); if (settingsRegistry == nullptr) { return false; } + AZ::IO::FixedMaxPathString engineRootFolder; if (settingsRegistry->Get(engineRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) { @@ -336,7 +390,7 @@ namespace AssetUtilities return false; } - bool MakeFileWritable(QString fileName) + bool MakeFileWritable(const QString& fileName) { #if defined WIN32 DWORD fileAttributes = GetFileAttributesA(fileName.toUtf8()); @@ -386,7 +440,7 @@ namespace AssetUtilities #endif } - bool CheckCanLock(QString fileName) + bool CheckCanLock(const QString& fileName) { #if defined(AZ_PLATFORM_WINDOWS) AZStd::wstring usableFileName; @@ -419,42 +473,55 @@ namespace AssetUtilities #endif } - QString ComputeGameName(QString gameNameOverride, bool force) + QString ComputeProjectName(QString gameNameOverride, bool force) { - if (force || s_gameName.empty()) + if (force || s_projectName.empty()) { - // if its been specified on the command line, then ignore bootstrap: + // Override Game Name if a non-empty override string has been supplied + if (!gameNameOverride.isEmpty()) + { + s_projectName = gameNameOverride.toUtf8().constData(); + } + else + { + s_projectName = AZ::Utils::GetProjectName(); + } + } + + return QString::fromUtf8(s_projectName.c_str(), aznumeric_cast(s_projectName.size())); + } + + QString ComputeProjectPath() + { + if (s_projectPath.empty()) + { + // Check command-line args first QStringList args = QCoreApplication::arguments(); for (QString arg : args) { - if (arg.contains(QString("/%1=").arg(GameFolderOverrideParameter), Qt::CaseInsensitive) || arg.contains(QString("--%1=").arg(GameFolderOverrideParameter), Qt::CaseInsensitive)) + if (arg.contains(QString("/%1=").arg(ProjectPathOverrideParameter), Qt::CaseInsensitive) + || arg.contains(QString("--%1=").arg(ProjectPathOverrideParameter), Qt::CaseInsensitive)) { QString rawValueString = arg.split("=")[1].trimmed(); if (!rawValueString.isEmpty()) { - s_gameName = rawValueString.toUtf8().constData(); - return rawValueString; + QDir path(rawValueString); + if (path.isAbsolute()) + { + s_projectPath = rawValueString.toUtf8().constData(); + break; + } } } } + } - // Override Game Name if a non-empty override string has been supplied - if (!gameNameOverride.isEmpty()) - { - s_gameName = gameNameOverride.toUtf8().constData(); - } - else - { - QDir engineRoot; - if (!AssetUtilities::ComputeEngineRoot(engineRoot)) - { - return QString(); - } - s_gameName = ReadGameNameFromSettingsRegistry(engineRoot.absolutePath()).toUtf8().constData(); - } + if (s_projectPath.empty()) + { + s_projectPath = AZ::Utils::GetProjectPath(); } - return QString::fromUtf8(s_gameName.c_str(), aznumeric_cast(s_gameName.size())); + return QString::fromUtf8(s_projectPath.c_str(), aznumeric_cast(s_projectPath.size())); } bool InServerMode() @@ -479,7 +546,7 @@ namespace AssetUtilities } else { - AZ_Warning(AssetProcessor::ConsoleChannel, false, "Invalid server address, please check the AssetProcessorPlatformConfig.ini file \ + AZ_Warning(AssetProcessor::ConsoleChannel, false, "Invalid server address, please check the AssetProcessorPlatformConfig.setreg file \ to ensure that the address is correct. Asset Processor won't be running in server mode."); } @@ -517,19 +584,18 @@ to ensure that the address is correct. Asset Processor won't be running in serve } } - QDir engineRoot; - ComputeEngineRoot(engineRoot); - QString rootConfigFile = engineRoot.absoluteFilePath("AssetProcessorPlatformConfig.ini"); - - if (QFile::exists(rootConfigFile)) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) { - QString address; - QSettings loader(rootConfigFile, QSettings::IniFormat); - loader.beginGroup("Server"); - address = loader.value("cacheServerAddress", QString()).toString(); - loader.endGroup(); - s_assetServerAddress = address.toUtf8().constData(); - return address; + AZStd::string address; + if (settingsRegistry->Get(address, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey) + + "/Server/cacheServerAddress")) + { + AZ_TracePrintf(AssetProcessor::DebugChannel, "Server Address: %s\n", address.c_str()); + } + s_assetServerAddress = address; + + return QString::fromUtf8(address.data(), aznumeric_cast(address.size())); } return QString(); @@ -549,18 +615,12 @@ to ensure that the address is correct. Asset Processor won't be running in serve return *s_fileHashSetting; } - QDir engineRoot; - ComputeEngineRoot(engineRoot); - QString rootConfigFile = engineRoot.absoluteFilePath("AssetProcessorPlatformConfig.ini"); - - if (QFile::exists(rootConfigFile)) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) { - bool curValue; - QSettings loader(rootConfigFile, QSettings::IniFormat); - loader.beginGroup("Fingerprinting"); - curValue = loader.value("UseFileHashing", true).toBool(); - loader.endGroup(); - + bool curValue = true; + settingsRegistry->Get(curValue, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey) + + "/Fingerprinting/UseFileHashing"); AZ_TracePrintf(AssetProcessor::DebugChannel, "UseFileHashing: %s\n", curValue ? "True" : "False"); s_fileHashSetting = curValue; @@ -573,46 +633,8 @@ to ensure that the address is correct. Asset Processor won't be running in serve return *s_fileHashSetting; } - QString ReadGameNameFromSettingsRegistry(QString initialFolder /*= QString()*/) + QString ReadAllowedlistFromSettingsRegistry([[maybe_unused]] QString initialFolder) { - if (initialFolder.isEmpty()) - { - QDir engineRoot; - if (!AssetUtilities::ComputeEngineRoot(engineRoot)) - { - return QString(); - } - - initialFolder = engineRoot.absolutePath(); - } - - constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits::length("/sys_game_folder"); - AZStd::fixed_string projectKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey }; - projectKey += "/sys_game_folder"; - - AZ::SettingsRegistryInterface::FixedValueString projectName; - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry && settingsRegistry->Get(projectName, projectKey)) - { - return QString::fromUtf8(projectName.c_str(), aznumeric_cast(projectName.size())); - } - - AZ_Warning("AssetUtils", false, "Unable to find the Project Name(sys_game_folder) key in the settings registry"); - return {}; - } - - QString ReadAllowedlistFromSettingsRegistry(QString initialFolder /*= QString()*/) - { - if (initialFolder.isEmpty()) - { - QDir assetRoot; - if (!AssetUtilities::ComputeAssetRoot(assetRoot)) - { - return QString(); - } - - initialFolder = assetRoot.absolutePath(); - } - constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits::length("/allowed_list"); AZStd::fixed_string allowedListKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey }; allowedListKey += "/allowed_list"; @@ -626,18 +648,8 @@ to ensure that the address is correct. Asset Processor won't be running in serve return {}; } - QString ReadRemoteIpFromSettingsRegistry(QString initialFolder /*= QString()*/) + QString ReadRemoteIpFromSettingsRegistry([[maybe_unused]] QString initialFolder) { - if (initialFolder.isEmpty()) - { - QDir engineRoot; - if (!AssetUtilities::ComputeEngineRoot(engineRoot)) - { - return QString(); - } - - initialFolder = engineRoot.absolutePath(); - } constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits::length("/remote_ip"); AZStd::fixed_string remoteIpKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey }; remoteIpKey += "/remote_ip"; @@ -651,159 +663,44 @@ to ensure that the address is correct. Asset Processor won't be running in serve return {}; } - bool WriteAllowedlistToBootstrap(QStringList newAllowedList) + bool WriteAllowedlistToSettingsRegistry(const QStringList& newAllowedList) { - QDir assetRoot; - ComputeAssetRoot(assetRoot); - QString bootstrapFilename = assetRoot.filePath("bootstrap.cfg"); - QFile bootstrapFile(bootstrapFilename); + AZ::IO::FixedMaxPath assetProcessorUserSetregPath = AZ::Utils::GetProjectPath(); + assetProcessorUserSetregPath /= AssetProcessorUserSetregRelPath; - // do not alter the branch file unless we are able to obtain an exclusive lock. Other apps (such as NPP) may actually write 0 bytes first, then slowly spool out the remainder) - if (!CheckCanLock(bootstrapFilename)) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (!settingsRegistry) { + AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable access Settings Registry. Branch Token cannot be updated"); return false; } - if (!bootstrapFile.open(QIODevice::ReadOnly)) + auto allowedListKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + + "/allowed_list"; + AZStd::string currentAllowedList; + if (settingsRegistry->Get(currentAllowedList, allowedListKey)) { - return false; - } - - // regexp that matches either the beginning of the file, some whitespace, and allowed_list, or, - // matches a newline, then whitespace, then allowed_list it will not match comments. - QRegExp allowedListPattern("(^|\\n)\\s*allowed_list\\s*=\\s*(.+)", Qt::CaseInsensitive, QRegExp::RegExp); + // Split the current allowedList into an array and compare against the new allowed list + AZStd::vector allowedListArray; + auto AppendAllowedIpTokens = [&allowedListArray](AZStd::string_view token) { allowedListArray.emplace_back(token); }; + AZ::StringFunc::TokenizeVisitor(currentAllowedList, AppendAllowedIpTokens, ','); - //read the file line by line and try to find the allowed_list line - QString readAllowedList; - QString allowedListline; - while (!bootstrapFile.atEnd()) - { - QString contents(bootstrapFile.readLine()); - int matchIdx = allowedListPattern.indexIn(contents); - if (matchIdx != -1) + auto CompareQListToAzVector = [](AZStd::string_view currentAllowedIp, const QString& newAllowedIp) { - allowedListline = contents; - readAllowedList = allowedListPattern.cap(2); - break; - } - } - - //read the entire file into so we can do a buffer replacement - bootstrapFile.seek(0); - QString fileContents; - fileContents = bootstrapFile.readAll(); - bootstrapFile.close(); - - //format the new allowed list - QString formattedNewAllowedList = newAllowedList.join(", "); - - //if we didn't find a allowed_list entry then append one - if (allowedListline.isEmpty()) - { - fileContents.append("\nallowed_list = " + formattedNewAllowedList + "\n"); - } - else if (QString::compare(formattedNewAllowedList, readAllowedList, Qt::CaseInsensitive) == 0) - { - // no need to update, they match - return true; - } - else - { - //Replace the found line with a new one - fileContents.replace(allowedListline, "allowed_list = " + formattedNewAllowedList + "\n"); - } - - // Make the bootstrap file writable - if (!MakeFileWritable(bootstrapFilename)) - { - AZ_Warning(AssetProcessor::ConsoleChannel, false, "Failed to make the bootstrap file writable.") - return false; - } - if (!bootstrapFile.open(QIODevice::WriteOnly)) - { - return false; - } - - QTextStream output(&bootstrapFile); - output << fileContents; - bootstrapFile.close(); - return true; - } - - bool WriteRemoteIpToBootstrap(QString newRemoteIp) - { - QDir assetRoot; - ComputeAssetRoot(assetRoot); - QString bootstrapFilename = assetRoot.filePath("bootstrap.cfg"); - QFile bootstrapFile(bootstrapFilename); - - // do not alter the branch file unless we are able to obtain an exclusive lock. Other apps (such as NPP) may actually write 0 bytes first, then slowly spool out the remainder) - if (!CheckCanLock(bootstrapFilename)) - { - return false; - } - - if (!bootstrapFile.open(QIODevice::ReadOnly)) - { - return false; - } - - // regexp that matches either the beginning of the file, and remote_ip, or, - // matches a newline, then whitespace, then remote_ip it will not match comments. - QRegExp remoteIpPattern("(^|\\n)\\s*remote_ip\\s*=\\s*(.+)", Qt::CaseInsensitive, QRegExp::RegExp); - - //read the file line by line and try to find the remote_ip line - QString readRemoteIp; - QString remoteIpline; - while (!bootstrapFile.atEnd()) - { - QString contents(bootstrapFile.readLine()); - int matchIdx = remoteIpPattern.indexIn(contents); - if (matchIdx != -1) + return currentAllowedIp == newAllowedIp.toUtf8().constData(); + }; + if (AZStd::equal(allowedListArray.begin(), allowedListArray.end(), newAllowedList.begin(), newAllowedList.end(), CompareQListToAzVector)) { - remoteIpline = contents; - readRemoteIp = remoteIpPattern.cap(2); - break; + // no need to update, remote_ip already matches + return true; } } - //read the entire file into so we can do a buffer replacement - bootstrapFile.seek(0); - QString fileContents; - fileContents = bootstrapFile.readAll(); - bootstrapFile.close(); + // Update Settings Registry with new token + AZStd::string azNewAllowedList{ newAllowedList.join(', ').toUtf8().constData() }; + settingsRegistry->Set(allowedListKey, azNewAllowedList); - //if we didn't find a remote_ip entry then append one - if (remoteIpline.isEmpty()) - { - fileContents.append("\nremote_ip = " + newRemoteIp + "\n"); - } - else if (QString::compare(newRemoteIp, readRemoteIp, Qt::CaseInsensitive) == 0) - { - // no need to update, they match - return true; - } - else - { - //Replace the found line with a new one - fileContents.replace(remoteIpline, "remote_ip = " + newRemoteIp + "\n"); - } - - // Make the bootstrap file writable - if (!MakeFileWritable(bootstrapFilename)) - { - AZ_Warning(AssetProcessor::ConsoleChannel, false, "Failed to make the bootstrap file writable.") - return false; - } - if (!bootstrapFile.open(QIODevice::WriteOnly)) - { - return false; - } - - QTextStream output(&bootstrapFile); - output << fileContents; - bootstrapFile.close(); - return true; + return AssetUtilsInternal::DumpAssetProcessorUserSettingsToFile(*settingsRegistry, assetProcessorUserSetregPath); } quint16 ReadListeningPortFromSettingsRegistry(QString initialFolder /*= QString()*/) @@ -923,23 +820,20 @@ to ensure that the address is correct. Asset Processor won't be running in serve bool ComputeProjectCacheRoot(QDir& projectCacheRoot) { - QDir assetRoot; - if (!ComputeAssetRoot(assetRoot)) - { - return false; // failed to detect engine root - } - - QString gameDir = ComputeGameName(assetRoot.absolutePath()); - if (gameDir.isEmpty()) + if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr) { - return false; + AZ::SettingsRegistryInterface::FixedValueString projectCacheRootValue; + if (registry->Get(projectCacheRootValue, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder); + !projectCacheRootValue.empty()) + { + projectCacheRoot = QDir(QString::fromUtf8(projectCacheRootValue.c_str(), aznumeric_cast(projectCacheRootValue.size()))); + return true; + } } - projectCacheRoot = QDir(assetRoot.filePath("Cache/" + gameDir)); - return true; + return false; } - bool ComputeFenceDirectory(QDir& fenceDir) { QDir cacheRoot; @@ -951,6 +845,25 @@ to ensure that the address is correct. Asset Processor won't be running in serve return true; } + QString StripAssetPlatform(AZStd::string_view relativeProductPath) + { + // Skip over the assetPlatform path segment if it is matches one of the platform defaults + // Otherwise return the path unchanged + AZStd::string_view strippedProductPath{ relativeProductPath }; + if (AZStd::optional pathSegment = AZ::StringFunc::TokenizeNext(strippedProductPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR); + pathSegment.has_value()) + { + AZ::IO::FixedMaxPathString assetPlatformSegmentLower{ *pathSegment }; + AZStd::to_lower(assetPlatformSegmentLower.begin(), assetPlatformSegmentLower.end()); + if (AzFramework::PlatformHelper::GetPlatformIdFromName(assetPlatformSegmentLower) != AzFramework::PlatformId::Invalid) + { + return QString::fromUtf8(strippedProductPath.data(), aznumeric_cast(strippedProductPath.size())); + } + } + + return QString::fromUtf8(relativeProductPath.data(), aznumeric_cast(relativeProductPath.size())); + } + QString NormalizeFilePath(const QString& filePath) { // do NOT convert to absolute paths here, we just want to manipulate the string itself. @@ -1035,92 +948,41 @@ to ensure that the address is correct. Asset Processor won't be running in serve bool UpdateBranchToken() { - QDir assetRoot; - ComputeAssetRoot(assetRoot); - QString bootstrapFilename = assetRoot.filePath("bootstrap.cfg"); - QFile bootstrapFile(bootstrapFilename); - QString fileContents; - - // do not alter the branch file unless we are able to obtain an exclusive lock. Other apps (such as NPP) may actually write 0 bytes first, then slowly spool out the remainder) - QElapsedTimer timer; - timer.start(); - bool hasLock = false; - do - { - if (CheckCanLock(bootstrapFilename)) - { - hasLock = true; - break; - } + AZ::IO::FixedMaxPath assetProcessorUserSetregPath = AZ::Utils::GetProjectPath(); + assetProcessorUserSetregPath /= AssetProcessorUserSetregRelPath; - QThread::msleep(AssetUtilsInternal::g_RetryWaitInterval); + AZStd::string appBranchToken; + AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, appBranchToken); - } while (!timer.hasExpired(10 * AssetUtilsInternal::g_RetryWaitInterval)); - if (!hasLock) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (!settingsRegistry) { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to lock bootstrap file at: %s\n", bootstrapFilename.toUtf8().constData()); + AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable access Settings Registry. Branch Token cannot be updated"); return false; } - if (!bootstrapFile.open(QIODevice::ReadOnly)) + AZStd::string registryBranchToken; + auto branchTokenKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/assetProcessor_branch_token"; + if (settingsRegistry->Get(registryBranchToken, branchTokenKey)) { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to open bootstrap file at: %s\n", bootstrapFilename.toUtf8().constData()); - return false; - } - - fileContents = bootstrapFile.readAll(); - bootstrapFile.close(); - - AZStd::string appBranchToken; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, appBranchToken); - QString currentBranchToken(appBranchToken.c_str()); - QString readBranchToken; - - // regexp that matches either the beginning of the file, some whitespace, and assetProcessor_branch_token, or, - // matches a newline, then whitespace, then assetProcessor_branch_token - // it will not match comments. - QRegExp branchTokenPattern("(^|\\n)\\s*assetProcessor_branch_token\\s*=\\s*(\\S+)\\b", Qt::CaseInsensitive, QRegExp::RegExp); - - int matchIdx = branchTokenPattern.indexIn(fileContents); - if (matchIdx != -1) - { - readBranchToken = branchTokenPattern.cap(2); - } + if (appBranchToken == registryBranchToken) + { + // no need to update, branch token match + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Branch token (%s) is already correct in (%s)\n", appBranchToken.c_str(), assetProcessorUserSetregPath.c_str()); + return true; + } - if (readBranchToken.isEmpty()) - { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "adding branch token (%s) in (%s)\n", currentBranchToken.toUtf8().constData(), bootstrapFilename.toUtf8().constData()); - fileContents.append("\nassetProcessor_branch_token = " + currentBranchToken + "\n"); - } - else if (QString::compare(currentBranchToken, readBranchToken, Qt::CaseInsensitive) == 0) - { - // no need to update, branch token match - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Branch token (%s) is already correct in (%s)\n", currentBranchToken.toUtf8().constData(), bootstrapFilename.toUtf8().constData()); - return true; + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Updating branch token (%s) in (%s)\n", appBranchToken.c_str(), assetProcessorUserSetregPath.c_str()); } else { - //Updating branch token - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Updating branch token (%s) in (%s)\n", currentBranchToken.toUtf8().constData(), bootstrapFilename.toUtf8().constData()); - fileContents.replace(branchTokenPattern.cap(0), "\nassetProcessor_branch_token = " + currentBranchToken + "\n"); + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Adding branch token (%s) in (%s)\n", appBranchToken.c_str(), assetProcessorUserSetregPath.c_str()); } - // Make the bootstrap file writable - if (!MakeFileWritable(bootstrapFilename)) - { - AZ_Warning(AssetProcessor::ConsoleChannel, false, "Failed to make the bootstrap file writable.") - return false; - } - if (!bootstrapFile.open(QIODevice::WriteOnly)) - { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to open bootstrap file (%s)\n", bootstrapFilename.toUtf8().constData()); - return false; - } + // Update Settings Registry with new token + settingsRegistry->Set(branchTokenKey, appBranchToken); - QTextStream output(&bootstrapFile); - output << fileContents; - bootstrapFile.close(); - return true; + return AssetUtilsInternal::DumpAssetProcessorUserSettingsToFile(*settingsRegistry, assetProcessorUserSetregPath); } QString ComputeJobDescription(const AssetProcessor::AssetRecognizer* recognizer) @@ -1130,7 +992,7 @@ to ensure that the address is correct. Asset Processor won't be running in serve AZStd::string ComputeJobLogFolder() { - return AZStd::string::format("@log@/logs/JobLogs"); + return AZStd::string::format("@log@/JobLogs"); } AZStd::string ComputeJobLogFileName(const AzToolsFramework::AssetSystem::JobInfo& jobInfo) @@ -1477,14 +1339,28 @@ to ensure that the address is correct. Asset Processor won't be running in serve bool CreateTempWorkspace(QString& result) { - // Use the engine root as a temp workspace folder - // this works better for numerous reasons - // * Its on the same drive as the /Cache/ so we will be moving files instead of copying from drive to drive + // Use the project user folder as a temp workspace folder + // The benefits are + // * It's on the same drive as the Cache/ so we will be moving files instead of copying from drive to drive // * It is discoverable by the user and thus deletable and we can also tell people to send us that folder without them having to go digging for it - // * If you can't write to it you have much bigger problems QDir rootDir; - if (ComputeAssetRoot(rootDir)) + bool foundValidPath{}; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (AZ::IO::Path userPath; settingsRegistry->Get(userPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) + { + rootDir.setPath(QString::fromUtf8(userPath.c_str(), aznumeric_cast(userPath.Native().size()))); + foundValidPath = true; + } + } + + if (!foundValidPath) + { + foundValidPath = ComputeAssetRoot(rootDir); + } + + if (foundValidPath) { QString tempPath = rootDir.absolutePath(); return CreateTempWorkspace(tempPath, result); @@ -1499,7 +1375,6 @@ to ensure that the address is correct. Asset Processor won't be running in serve QString inputName; QString platformName; QString jobDescription; - QString gameName = AssetUtilities::ComputeGameName(); AZ::Uuid guid = AZ::Uuid::CreateNull(); using namespace AzToolsFramework::AssetDatabase; @@ -1513,16 +1388,16 @@ to ensure that the address is correct. Asset Processor won't be running in serve platform = AzToolsFramework::AssetSystem::GetHostAssetPlatform(); } - QString platformPrepend = QString("%1/%2/").arg(platform, gameName); - QString productNameWithPlatformAndGameName = productName; + QString platformPrepend = QString("%1/").arg(platform); + QString productNameWithPlatform = productName; if (!productName.startsWith(platformPrepend, Qt::CaseInsensitive)) { - productNameWithPlatformAndGameName = productName = QString("%1/%2/%3").arg(platform, gameName, productName); + productNameWithPlatform = productName = QString("%1/%2").arg(platform, productName); } ProductDatabaseEntryContainer products; - if (databaseConnection->GetProductsByProductName(productNameWithPlatformAndGameName, products)) + if (databaseConnection->GetProductsByProductName(productNameWithPlatform, products)) { // if we find stuff, then return immediately, productName is already a productName. return productName; @@ -1535,24 +1410,9 @@ to ensure that the address is correct. Asset Processor won't be running in serve return productName; } - if (!databaseConnection->GetProductsLikeProductName(productNameWithPlatformAndGameName, AssetDatabaseConnection::LikeType::StartsWith, products)) + if (!databaseConnection->GetProductsLikeProductName(productNameWithPlatform, AssetDatabaseConnection::LikeType::StartsWith, products)) { - //if we are here it means that the asset database does not know about this product, - //we will now remove the gameName and try again ,so now the path will only have $PLATFORM/ in front of it - int gameNameIndex = productName.indexOf(gameName, 0, Qt::CaseInsensitive); - - if (gameNameIndex != -1) - { - //we will now remove the gameName and the separator - productName.remove(gameNameIndex, gameName.length() + 1);// adding one for the native separator - } - - //Search the database for this product - if (!databaseConnection->GetProductsLikeProductName(productName, AssetDatabaseConnection::LikeType::StartsWith, products)) - { - //return empty string if the database still does not have any idea about the product - productName = QString(); - } + return {}; } return productName.toLower(); } diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.h b/Code/Tools/AssetProcessor/native/utilities/assetUtils.h index 70bdf9cb4e..e0633068a7 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.h +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.h @@ -51,8 +51,7 @@ namespace AssetProcessor namespace AssetUtilities { - - inline constexpr char GameFolderOverrideParameter[] = "gamefolder"; + inline constexpr char ProjectPathOverrideParameter[] = "project-path"; //! Set precision fingerprint timestamps will be truncated to avoid mismatches across systems/packaging with different file timestamp precisions //! Timestamps default to milliseconds. A value of 1 will keep the default millisecond precision. A value of 1000 will reduce the precision to seconds @@ -79,10 +78,10 @@ namespace AssetUtilities //! makes the file writable //! return true if operation is successful, otherwise return false - bool MakeFileWritable(QString filename); + bool MakeFileWritable(const QString& filename); //! Check to see if we can Lock the file - bool CheckCanLock(QString filename); + bool CheckCanLock(const QString& filename); //! Updates the branch token in the bootstrap file bool UpdateBranchToken(); @@ -98,11 +97,14 @@ namespace AssetUtilities bool ShouldUseFileHashing(); - //! Determine the name of the current game - for example, SamplesProject - //! Can be overridden by passing in a non-empty gameNameOverride - //! The override will persist if the GameName wasn't set previously or + //! Determine the name of the current project - for example, SamplesProject + //! Can be overridden by passing in a non-empty projectNameOverride + //! The override will persist if the project name wasn't set previously or //! force=true is supplied - QString ComputeGameName(QString gameNameOverride = QString(), bool force = false); + QString ComputeProjectName(QString projectNameOverride = QString(), bool force = false); + + //! Determine the absolute path of the current project + QString ComputeProjectPath(); //! Reads the allowed list directly from the bootstrap file QString ReadAllowedlistFromSettingsRegistry(QString initialFolder = QString()); @@ -111,13 +113,7 @@ namespace AssetUtilities QString ReadRemoteIpFromSettingsRegistry(QString initialFolder = QString()); //! Writes the allowed list directly to the bootstrap file - bool WriteAllowedlistToBootstrap(QStringList allowedList); - - //! Writes the remote ip directly to the bootstrap file - bool WriteRemoteIpToBootstrap(QString remoteIp); - - //! Reads the game name directly from the bootstrap file - QString ReadGameNameFromSettingsRegistry(QString initialFolder = QString()); + bool WriteAllowedlistToSettingsRegistry(const QStringList& allowedList); //! Reads the listening port from the bootstrap file //! By default the listening port is 45643 @@ -143,13 +139,24 @@ namespace AssetUtilities QString ComputeJobDescription(const AssetProcessor::AssetRecognizer* recognizer); //! Compute the root of the cache for the current project. - //! This is generally the "cache" folder, subfolder gamedir. + //! This is generally the "/Cache" folder bool ComputeProjectCacheRoot(QDir& projectCacheRoot); //! Compute the folder that will be used for fence files. bool ComputeFenceDirectory(QDir& fenceDir); - //! Converts all slashes to forward slashes, removes double slashes, + //! Strips the first "asset platform" from the first path segment of a relative product path + //! This is meant for removing the asset platform for paths such as "pc/MyAssetFolder/MyAsset.asset" + //! Therefore the result here becomes "MyAssetFolder/MyAsset" + //! + //! Similarly invoking this function on relative path that begins with the "server" platform + //! "server/AssetFolder/Server.asset2" -> "AssetFolder/Server.asset2" + //! This function does not strip an asset platform from anywhere, but the first path segment + //! Therefore invoking strip Asset on "MyProject/Cache/pc/MyAsset/MyAsset.asset" + //! would return a copy of the relative path + QString StripAssetPlatform(AZStd::string_view relativeProductPath); + + //! Converts all slashes to forward slashes, removes double slashes, //! replaces all indirections such as '.' or '..' as appropriate. //! On windows, the drive letter (if present) is converted to uppercase. //! Besides that, all case is preserved. diff --git a/Code/Tools/AssetProcessor/testdata/config_broken_badplatform/AssetProcessorPlatformConfig.ini b/Code/Tools/AssetProcessor/testdata/config_broken_badplatform/AssetProcessorPlatformConfig.ini index 765f56a1bc..874625bf1b 100644 --- a/Code/Tools/AssetProcessor/testdata/config_broken_badplatform/AssetProcessorPlatformConfig.ini +++ b/Code/Tools/AssetProcessor/testdata/config_broken_badplatform/AssetProcessorPlatformConfig.ini @@ -11,7 +11,7 @@ es3=enabled ; note - bad platform - its not one of the above ones! ; without a scan folder, it is an invalid file. [ScanFolder Game] -watch=@ROOT@/@GAMENAME@ +watch=@PROJECTROOT@ recursive=1 order=0 diff --git a/Code/Tools/AssetProcessor/testdata/config_broken_noplatform/AssetProcessorPlatformConfig.ini b/Code/Tools/AssetProcessor/testdata/config_broken_noplatform/AssetProcessorPlatformConfig.ini index 39711c763b..5b776865a6 100644 --- a/Code/Tools/AssetProcessor/testdata/config_broken_noplatform/AssetProcessorPlatformConfig.ini +++ b/Code/Tools/AssetProcessor/testdata/config_broken_noplatform/AssetProcessorPlatformConfig.ini @@ -2,7 +2,7 @@ ; without a scan folder, it is an invalid file. [ScanFolder Game] -watch=@ROOT@/@GAMENAME@ +watch=@PROJECTROOT@ recursive=1 order=0 diff --git a/Code/Tools/AssetProcessor/testdata/config_broken_recognizers/AssetProcessorPlatformConfig.ini b/Code/Tools/AssetProcessor/testdata/config_broken_recognizers/AssetProcessorPlatformConfig.ini index d3e46d644c..14d95cff5f 100644 --- a/Code/Tools/AssetProcessor/testdata/config_broken_recognizers/AssetProcessorPlatformConfig.ini +++ b/Code/Tools/AssetProcessor/testdata/config_broken_recognizers/AssetProcessorPlatformConfig.ini @@ -8,7 +8,7 @@ tags=tools,renderer ; without a scan folder, it is an invalid file. [ScanFolder Game] -watch=@ROOT@/@GAMENAME@ +watch=@PROJECTROOT@ recursive=1 order=0 diff --git a/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.ini b/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.ini index 95c24f3c54..77750779cb 100644 --- a/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.ini +++ b/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.ini @@ -35,16 +35,16 @@ cbc=abc fbx.assetinfo=fbx [ScanFolder Game] -watch=@ROOT@/@GAMENAME@ +watch=@PROJECTROOT@ ; use a special display name here to make sure macros work -display=@GAMENAME@ Scan Folder +display=@PROJECTROOT@ Scan Folder recursive=1 order=0 ; this test makes sure that those macros make sense and are present as well as that order is preserved. ; it also makes sure that the friendly name ("FeatureTests") is used, if no display is present and does not lose its case. [ScanFolder FeatureTests] -watch=@ROOT@/@GAMENAME@FeatureTests +watch=@PROJECTROOT@FeatureTests output=featuretestsoutputfolder recursive=0 order=5000 @@ -53,7 +53,7 @@ order=5000 ; (which is constructed from its name in the square brackets) ; instead of other attributes such as the watch folder, or output prefix. [ScanFolder FeatureTests2] -watch=@ROOT@/@GAMENAME@FeatureTests +watch=@PROJECTROOT@FeatureTests output=featuretestsoutputfolder recursive=0 order=6000 diff --git a/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.ini b/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.ini index 0642e176ee..c210c23d0d 100644 --- a/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.ini +++ b/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.ini @@ -42,7 +42,7 @@ cbc=abc fbx.assetinfo=fbx [ScanFolder Game] -watch=@ROOT@/@GAMENAME@ +watch=@PROJECTROOT@ display=gameoutput recursive=1 order=0 diff --git a/Code/Tools/AssetProcessor/testdata/unittests.qrc b/Code/Tools/AssetProcessor/testdata/unittests.qrc deleted file mode 100644 index eb31e55a46..0000000000 --- a/Code/Tools/AssetProcessor/testdata/unittests.qrc +++ /dev/null @@ -1,12 +0,0 @@ - - - config_broken_badplatform/AssetProcessorPlatformConfig.ini - config_broken_noscans/AssetProcessorPlatformConfig.ini - config_broken_recognizers/AssetProcessorPlatformConfig.ini - config_broken_noplatform/AssetProcessorPlatformConfig.ini - config_regular/AssetProcessorPlatformConfig.ini - config_regular_platform_scanfolder/AssetProcessorPlatformConfig.ini - EmptyDummyProject/AssetProcessorGamePlatformConfig.ini - DummyProject/AssetProcessorGamePlatformConfig.ini - - diff --git a/Code/Tools/CMakeLists.txt b/Code/Tools/CMakeLists.txt index fb96187f90..b96ebae1ac 100644 --- a/Code/Tools/CMakeLists.txt +++ b/Code/Tools/CMakeLists.txt @@ -16,7 +16,6 @@ add_subdirectory(AzTestRunner) add_subdirectory(CryCommonTools) add_subdirectory(CrySCompileServer) add_subdirectory(CryXML) -add_subdirectory(GemRegistry) add_subdirectory(HLSLCrossCompiler) add_subdirectory(HLSLCrossCompilerMETAL) add_subdirectory(News) diff --git a/Code/Tools/CrashHandler/Tools/Uploader/ToolsCrashUploader.cpp b/Code/Tools/CrashHandler/Tools/Uploader/ToolsCrashUploader.cpp index 0b69ef2190..9fb85fc585 100644 --- a/Code/Tools/CrashHandler/Tools/Uploader/ToolsCrashUploader.cpp +++ b/Code/Tools/CrashHandler/Tools/Uploader/ToolsCrashUploader.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include +#include #include #include @@ -82,7 +85,13 @@ namespace Lumberyard AzQtComponents::StyleManager styleManager{ nullptr }; QApplication app{ argCount, nullptr }; - styleManager.Initialize(&app); + AZ::IO::FixedMaxPath engineRootPath; + { + AZ::ComponentApplication componentApplication; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + styleManager.initialize(&app, engineRootPath); QString reportPath{ GetReportString(report.file_path.value()) }; diff --git a/Code/Tools/GemRegistry/CMakeLists.txt b/Code/Tools/GemRegistry/CMakeLists.txt deleted file mode 100644 index 8fb1a91162..0000000000 --- a/Code/Tools/GemRegistry/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -# -# 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. -# - -ly_add_target( - NAME GemRegistry.Static STATIC - NAMESPACE AZ - FILES_CMAKE - gemregistry_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - include - BUILD_DEPENDENCIES - PUBLIC - AZ::AzCore - AZ::AzFramework -) - -ly_add_target( - NAME GemRegistry ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} - NAMESPACE AZ - FILES_CMAKE - gemregistry_shared_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - include - BUILD_DEPENDENCIES - PRIVATE - AZ::GemRegistry.Static -) - -################################################################################ -# Tests -################################################################################ -if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) - - ly_add_target( - NAME GemRegistry.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} - NAMESPACE AZ - FILES_CMAKE - gemregistry_test_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - Tests - source - BUILD_DEPENDENCIES - PRIVATE - AZ::AzTest - AZ::GemRegistry.Static - ) - ly_add_googletest( - NAME AZ::GemRegistry.Tests - ) -endif() - diff --git a/Code/Tools/GemRegistry/gemregistry_shared_files.cmake b/Code/Tools/GemRegistry/gemregistry_shared_files.cmake deleted file mode 100644 index 35feb3e44f..0000000000 --- a/Code/Tools/GemRegistry/gemregistry_shared_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# 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. -# - -set(FILES - source/GemRegistry.h - source/GemRegistry.cpp -) \ No newline at end of file diff --git a/Code/Tools/GemRegistry/include/GemRegistry/Dependency.h b/Code/Tools/GemRegistry/include/GemRegistry/Dependency.h deleted file mode 100644 index 0ae99986d2..0000000000 --- a/Code/Tools/GemRegistry/include/GemRegistry/Dependency.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -* 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 - -#include -#include -#include -#include -#include - -#include "GemRegistry/Version.h" - -namespace Gems -{ - using EngineSpecifier = AzFramework::Specifier; - using GemSpecifier = AzFramework::Specifier; - using EngineDependency = AzFramework::Dependency; - using GemDependency = AzFramework::Dependency; -} // namespace Gems diff --git a/Code/Tools/GemRegistry/include/GemRegistry/IGemRegistry.h b/Code/Tools/GemRegistry/include/GemRegistry/IGemRegistry.h deleted file mode 100644 index d4a4a1ada8..0000000000 --- a/Code/Tools/GemRegistry/include/GemRegistry/IGemRegistry.h +++ /dev/null @@ -1,399 +0,0 @@ -/* -* 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 - -#include -#include -#include -#include -#include -#include - -#include "GemRegistry/Dependency.h" -#include "GemRegistry/Version.h" - -namespace Gems -{ - /// Describes how other Gems (and the final executable) will link against this Gem (valid only for Type::GameModule and Type::ServerModule). - enum class LinkType - { - /// Do not link against this Gem, it is loaded as a Dynamic Library at runtime. - Dynamic, - /// Link against this Gem, it is also loaded as a Dynamic Library at runtime. - DynamicStatic, - /// Gem has no code, there is nothing to link against. - NoCode, - }; - - /** - * Defines a module produced by a Gem. - */ - struct ModuleDefinition - { - enum class Type - { - GameModule, - EditorModule, - StaticLib, - Builder, - Standalone, - ServerModule, - }; - - /// The type of module this represents - Type m_type; - /// The name of the module (for dll naming) - AZStd::string m_name; - /// If this module is type GameModule, how is it linked? - LinkType m_linkType = LinkType::NoCode; - /// The complete name of the file produced (for all Types but StaticLib) - AZStd::string m_fileName; - /// If the module extends another module, this points to that - AZStd::weak_ptr m_parent; - /// All of the modules that extend this module - AZStd::vector> m_children; - - // Construction and Destruction is trivial - ModuleDefinition() = default; - ~ModuleDefinition() = default; - - // Disallow copying and moving - ModuleDefinition(const ModuleDefinition&) = delete; - ModuleDefinition& operator=(const ModuleDefinition&) = delete; - ModuleDefinition(ModuleDefinition&&) = delete; - ModuleDefinition& operator=(ModuleDefinition&& rhs) = delete; - }; - using ModuleDefinitionConstPtr = AZStd::shared_ptr; - using ModuleDefinitionVector = AZStd::vector; - - /** - * Describes an instance of a Gem. - */ - class IGemDescription - { - public: - /// The ID of the Gem - virtual const AZ::Uuid& GetID() const = 0; - /// The name of the Gem - virtual const AZStd::string& GetName() const = 0; - /// The UI-friendly name of the Gem - virtual const AZStd::string& GetDisplayName() const = 0; - /// The version of the Gem - virtual const GemVersion& GetVersion() const = 0; - /// Relative path to the folder of this Gem - virtual const AZStd::string& GetPath() const = 0; - /// Absolute path to the folder of this Gem - virtual const AZStd::string& GetAbsolutePath() const = 0; - /// Summary description of the Gem - virtual const AZStd::string& GetSummary() const = 0; - /// Icon path of the gem - virtual const AZStd::string& GetIconPath() const = 0; - /// Tags to associated with the Gem - virtual const AZStd::vector& GetTags() const = 0; - /// Get the list of modules produced by the Gem - virtual const ModuleDefinitionVector& GetModules() const = 0; - /// Get all modules to be loaded for a given function - /// This method traverses children to find the most derived module of each type per tree - virtual const ModuleDefinitionVector& GetModulesOfType(ModuleDefinition::Type type) const = 0; - /// The name of the engine module class to initialize - virtual const AZStd::string& GetEngineModuleClass() const = 0; - /// Get the Gem's other gems dependencies - virtual const AZStd::vector >& GetGemDependencies() const = 0; - /// Get the Gem's engine dependency - virtual const AZStd::shared_ptr GetEngineDependency() const = 0; - /// Determine if this is a Game Gem - virtual const bool IsGameGem() const = 0; - /// Determine if this is a required Gem - virtual const bool IsRequired() const = 0; - - virtual ~IGemDescription() = default; - }; - using IGemDescriptionConstPtr = AZStd::shared_ptr; - - /// A specific Gem known to a Project. - /// The Gem is not used unless it is enabled. - struct ProjectGemSpecifier - : public GemSpecifier - { - /// Folder in which this specific Gem can be found. - AZStd::string m_path; - - ProjectGemSpecifier(const AZ::Uuid& id, const GemVersion& version, const AZStd::string& path) - : GemSpecifier(id, version) - , m_path(path) - {} - ~ProjectGemSpecifier() override = default; - }; - using ProjectGemSpecifierMap = AZStd::unordered_map; - - /** - * Stores project-specific settings, such as which Gems are enabled and which versions are required. - */ - class IProjectSettings - { - public: - /** - * Initializes the ProjectSettings with a project name to load the settings from. - * - * \param[in] appRootFolder The application root folder where the project sub folder resides - * \param[in] projectSubFolder The folder in which the project's assets reside (and the configuration file) - * - * \returns True on success, false on failure. - */ - virtual AZ::Outcome Initialize(const AZStd::string& appRootFolder, const AZStd::string& projectSubFolder) = 0; - - /** - * Enables the specified instance of a Gem. - * - * \param[in] spec The specific Gem to enable. - * - * \returns True on success, False on failure. - */ - virtual bool EnableGem(const ProjectGemSpecifier& spec) = 0; - - /** - * Disables the specified instance of a Gem. - * - * \param[in] spec The specific Gem to disable. - * - * \returns True on success, False on failure. - */ - virtual bool DisableGem(const GemSpecifier& spec) = 0; - - /** - * Checks if a Gem of the specified description is enabled. - * - * \param[in] spec The specific Gem to check. - * - * \returns True if the Gem is enabled, False if it is disabled. - */ - virtual bool IsGemEnabled(const GemSpecifier& spec) const = 0; - - /** - * Checks if a Gem of the specified ID and version constraints is enabled. - * - * \param[in] id The ID of the Gem to check. - * \param[in] versionConstraints An array of strings, each of which is a condition using the gem dependency syntax - * - * \returns True if the Gem is enabled and passes every version constraint condition, False if it is disabled or does not match the version constraints. - */ - virtual bool IsGemEnabled(const AZ::Uuid& id, const AZStd::vector& versionConstraints) const = 0; - - /** - * Checks if a Gem of the specified dependency is enabled. - * - * \param[in] dep The dependency to validate. - * - * \returns True if the Gem is enabled, False if it is disabled. - */ - virtual bool IsGemDependencyMet(const AZStd::shared_ptr dep) const = 0; - - /** - * Checks if the engine dependency is met. - * - * \param[in] dep The dependency to validate. - * \param[in] againstVersion - * The version of the engine to validate against - * - * \returns True if the Gem is enabled, False if it is disabled. - */ - virtual bool IsEngineDependencyMet(const AZStd::shared_ptr dep, const EngineVersion& againstVersion) const = 0; - - /** - * Gets the Gems known to this project. - * Only enabled Gems are actually used at runtime. - * A project can only reference one version of a Gem. - * - * \returns The vector of enabled Gems. - */ - virtual const ProjectGemSpecifierMap& GetGems() const = 0; - - /** - * Sets the Gem map to the passed in list. Used when resetting after a failed save. - */ - virtual void SetGems(const ProjectGemSpecifierMap& newGemMap) = 0; - - /** - * Checks that all installed Gems have their dependencies met. - * Any unmet dependencies can be found via IGemRegistry::GetErrorMessage(); - * - * \param[in] engineVersion - * The version of the engine to validate against - * - * \returns Void on success, error message on failure. - */ - virtual AZ::Outcome ValidateDependencies(const EngineVersion& engineVersion = EngineVersion()) const = 0; - - /** - * Saves the current state of the project settings to it's project configuration file. - * - * \returns Void on success, error message on failure. - */ - virtual AZ::Outcome Save() const = 0; - - /** - * Get the project name that this project settings represents - - * \returns The project name. - */ - virtual const AZStd::string& GetProjectName() const = 0; - - /** - * Get the app root folder for the project - - * \returns The project root path. - */ - virtual const AZStd::string& GetProjectRootPath() const = 0; - - virtual ~IProjectSettings() = default; - }; - - /** - * Defines how to search for Gems. - */ - struct SearchPath - { - /// The root path to search - AZStd::string m_path; - /// The filter to apply to TOP LEVEL searching - AZStd::string m_filter; - - explicit SearchPath(const AZStd::string& path) - : m_path(path) - , m_filter("*") - { } - SearchPath(const AZStd::string& path, const AZStd::string& filter) - : m_path(path) - , m_filter(filter) - { } - }; - - inline bool operator==(const SearchPath& left, const SearchPath& right) - { - return left.m_path == right.m_path - && left.m_filter == right.m_filter; - } - - /** - * Manages installed Gems. - */ - class IGemRegistry - { - public: - /** - * Add to the list of paths to search for Gems when calling LoadAllGemsFromDisk - * - * \param[in] searchPath The path to add - * \param[in] loadGemsNow Load Gems from searchPath now - * - * \returns Void on success, error message on failure. - */ - virtual AZ::Outcome AddSearchPath(const SearchPath& searchPath, bool loadGemsNow) = 0; - - /** - * Scans the Gems/ folder for all installed Gems. - * - * In the event of an error loading a Gem, the error will be recorded, - * the Gem will not be loaded, and false will be returned. - * - * Loaded Gems can be accessed via GetGemDescription() or GetAllGemDescriptions(). - * - * \returns AZ::Success if the search succeeded - * AZ::Failure with error message if any errors occurred. - */ - virtual AZ::Outcome LoadAllGemsFromDisk() = 0; - - /** - * Looks for a gems.json file in the given folder and returns a IGemDescriptionConstPtr if found - * - * \param[in] gemFolderRelPath A valid path on disk to a directory that contains a gem.json file relative to the engine root - * - * \returns IGemDescriptionConstPtr if a gem.json file could be parsed out of the gemFolderPath, - * AZ::Failure with error message if any errors occurred. - */ - virtual AZ::Outcome ParseToGemDescriptionPtr(const AZStd::string& gemFolderRelPath, const char* absoluteFilePath) = 0; - - /** - * Loads Gems for the specified project. - * May be called for multiple projects. - * - * \param[in] settings The project to load Gems for. - * \param[in] resetPreviousProjects If true, reset any setting/gem descriptors that any previous calls to LoadProject may have added - * - * \returns Void on success, error message on failure. - */ - virtual AZ::Outcome LoadProject(const IProjectSettings& settings, bool resetPreviousProjects) = 0; - - /** - * Gets the description for a Gem. - * - * \param[in] spec The specific Gem to search for. - * - * \returns A pointer to the Gem's description if it exists, otherwise nullptr. - */ - virtual IGemDescriptionConstPtr GetGemDescription(const GemSpecifier& spec) const = 0; - - /** - * Gets the description for the latest version of a Gem. - * - * \param[in] uuid The specific uuid of the Gem to search for. - * - * \returns A pointer to the Gem's description highest version if it exists, otherwise nullptr. - */ - virtual IGemDescriptionConstPtr GetLatestGem(const AZ::Uuid& uuid) const = 0; - - /** - * Gets a list of all loaded Gem descriptions. - */ - virtual AZStd::vector GetAllGemDescriptions() const = 0; - - /** - * Gets a list of all loaded required Gem descriptions. - */ - virtual AZStd::vector GetAllRequiredGemDescriptions() const = 0; - - - /** - * Get the project-specific gem description if any - */ - virtual IGemDescriptionConstPtr GetProjectGemDescription(const AZStd::string& projectName) const = 0; - - - /** - * Creates a new instance of IProjectSettings. - * - * \returns A new project settings object. - */ - virtual IProjectSettings* CreateProjectSettings() = 0; - - /** - * Destroys an instance of IProjectSettings. - * - * \params[in] settings The settings instance to destroy. - */ - virtual void DestroyProjectSettings(IProjectSettings* settings) = 0; - - virtual ~IGemRegistry() = default; - }; - - /** - * The type of function exported for creating a new GemRegistry. - */ - using RegistryCreatorFunction = IGemRegistry * (*)(); - #define GEMS_REGISTRY_CREATOR_FUNCTION_NAME "CreateGemRegistry" - - /** - * The type of function exported for destroying a GemRegistry. - */ - using RegistryDestroyerFunction = void(*)(IGemRegistry*); - #define GEMS_REGISTRY_DESTROYER_FUNCTION_NAME "DestroyGemRegistry" -} // namespace Gems diff --git a/Code/Tools/GemRegistry/include/GemRegistry/Version.h b/Code/Tools/GemRegistry/include/GemRegistry/Version.h deleted file mode 100644 index 82b28c1f12..0000000000 --- a/Code/Tools/GemRegistry/include/GemRegistry/Version.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* 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 - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace Gems -{ - using GemVersion = AzFramework::SemanticVersion; - - // /** - // * Represents a version of the Lumberyard Game Engine - // */ - using EngineVersion = AzFramework::Version<4>; -} // namespace Gems - -namespace AZStd -{ - template - struct hash> - { - size_t operator()(const AzFramework::Version& ver) const - { - return AZStd::hash_range(ver.m_parts.begin(), ver.m_parts.end()); - } - }; - - template <> - struct hash - : public hash> - { }; -} // namespace AZStd diff --git a/Code/Tools/GemRegistry/source/GemDescription.cpp b/Code/Tools/GemRegistry/source/GemDescription.cpp deleted file mode 100644 index 6c56815e1f..0000000000 --- a/Code/Tools/GemRegistry/source/GemDescription.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* -* 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. -* -*/ -#include "GemDescription.h" -#include "GemRegistry.h" - -#include -#include -#include - -// For LinkTypeFromString -#include -#include - -namespace Gems -{ - GemDescription::GemDescription() - : m_id(AZ::Uuid::CreateNull()) - , m_name() - , m_displayName() - , m_version() - , m_path() - , m_absolutePath() - , m_summary() - , m_iconPath() - , m_tags() - , m_modules() - , m_modulesByType() - , m_engineModuleClass() - , m_gemDependencies() - , m_gameGem(false) - , m_required(false) - , m_engineDependency(nullptr) - { - m_modulesByType.emplace(ModuleDefinition::Type::GameModule); - m_modulesByType.emplace(ModuleDefinition::Type::ServerModule); - m_modulesByType.emplace(ModuleDefinition::Type::EditorModule); - m_modulesByType.emplace(ModuleDefinition::Type::StaticLib); - m_modulesByType.emplace(ModuleDefinition::Type::Builder); - m_modulesByType.emplace(ModuleDefinition::Type::Standalone); - } - - GemDescription::GemDescription(const GemDescription& rhs) - : m_id(rhs.m_id) - , m_name(rhs.m_name) - , m_displayName(rhs.m_displayName) - , m_version(rhs.m_version) - , m_path(rhs.m_path) - , m_absolutePath(rhs.m_absolutePath) - , m_summary(rhs.m_summary) - , m_iconPath(rhs.m_iconPath) - , m_tags(rhs.m_tags) - , m_modules(rhs.m_modules) - , m_modulesByType(rhs.m_modulesByType) - , m_engineModuleClass(rhs.m_engineModuleClass) - , m_gemDependencies(rhs.m_gemDependencies) - , m_gameGem(rhs.m_gameGem) - , m_required(rhs.m_required) - , m_engineDependency(rhs.m_engineDependency) - { - } - - - GemDescription::GemDescription(GemDescription&& rhs) - : m_id(rhs.m_id) - , m_name(AZStd::move(rhs.m_name)) - , m_displayName(AZStd::move(rhs.m_displayName)) - , m_path(AZStd::move(rhs.m_path)) - , m_absolutePath(AZStd::move(rhs.m_absolutePath)) - , m_summary(AZStd::move(rhs.m_summary)) - , m_iconPath(AZStd::move(rhs.m_iconPath)) - , m_tags(AZStd::move(rhs.m_tags)) - , m_version(rhs.m_version) - , m_modules(AZStd::move(rhs.m_modules)) - , m_modulesByType(AZStd::move(rhs.m_modulesByType)) - , m_engineModuleClass(AZStd::move(rhs.m_engineModuleClass)) - , m_gemDependencies(AZStd::move(rhs.m_gemDependencies)) - , m_gameGem(AZStd::move(rhs.m_gameGem)) - , m_required(AZStd::move(rhs.m_required)) - , m_engineDependency(AZStd::move(rhs.m_engineDependency)) - { - rhs.m_id = AZ::Uuid::CreateNull(); - rhs.m_version = GemVersion { 0, 0, 0 }; - } - - // returns whether conversion was successful - static bool LinkTypeFromString(const char* value, LinkType& linkTypeOut) - { - // static map for lookups - static const std::unordered_map linkNameToType = { - { GPF_TAG_LINK_TYPE_DYNAMIC, LinkType::Dynamic }, - { GPF_TAG_LINK_TYPE_DYNAMIC_STATIC, LinkType::DynamicStatic }, - { GPF_TAG_LINK_TYPE_NO_CODE, LinkType::NoCode }, - }; - - auto found = linkNameToType.find(value); - if (found != linkNameToType.end()) - { - linkTypeOut = found->second; - return true; - } - else - { - return false; - } - } - - static bool ModuleTypeFromString(const char* value, ModuleDefinition::Type& moduleTypeOut) - { - static const std::unordered_map moduleNameToType = { - { GPF_TAG_MODULE_TYPE_GAME_MODULE, ModuleDefinition::Type::GameModule }, - { GPF_TAG_MODULE_TYPE_SERVER_MODULE, ModuleDefinition::Type::ServerModule }, - { GPF_TAG_MODULE_TYPE_EDITOR_MODULE, ModuleDefinition::Type::EditorModule }, - { GPF_TAG_MODULE_TYPE_STATIC_LIB, ModuleDefinition::Type::StaticLib }, - { GPF_TAG_MODULE_TYPE_BUILDER, ModuleDefinition::Type::Builder }, - { GPF_TAG_MODULE_TYPE_STANDALONE, ModuleDefinition::Type::Standalone }, - }; - - auto found = AZStd::find_if(moduleNameToType.begin(), moduleNameToType.end(), [&value](decltype(moduleNameToType)::const_reference pair) { - return strcmp(pair.first, value) == 0; - }); - - if (found != moduleNameToType.end()) - { - moduleTypeOut = found->second; - return true; - } - else - { - return false; - } - } - - // Bring contents of file up to current version. - AZ::Outcome UpgradeGemDescriptionJson(rapidjson::Document& descNode) - { - // get format version - if (!RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_FORMAT_VERSION, IsInt)) - { - return AZ::Failure(AZStd::string(GPF_TAG_FORMAT_VERSION " int is required.")); - } - - int gemFormatVersion = descNode[GPF_TAG_FORMAT_VERSION].GetInt(); - - // decline ancient and future versions - if (gemFormatVersion < 2 || gemFormatVersion > GEM_DEF_FILE_VERSION) - { - return AZ::Failure(AZStd::string::format(GPF_TAG_FORMAT_VERSION " is version %d, but %d is expected.", - gemFormatVersion, GEM_DEF_FILE_VERSION)); - } - - // upgrade v2 -> v3 - if (gemFormatVersion < 3) - { - // beginning in v3 Gems contain an AZ::Module, in the past they contained an IGem - descNode.AddMember("IsLegacyIGem", true, descNode.GetAllocator()); - } - - // upgrade v3 -> v4 - if (gemFormatVersion < 4) - { - // read link type, if not NoCode, migrate to GameModule - if (!RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_LINK_TYPE, IsString)) - { - return AZ::Failure(AZStd::string(GPF_TAG_LINK_TYPE " string must not be empty.")); - } - // Explicitly copy string so we can remove it from the object - AZStd::string linkTypeString = descNode[GPF_TAG_LINK_TYPE].GetString(); - descNode.RemoveMember(GPF_TAG_LINK_TYPE); - - LinkType linkType; - if (!LinkTypeFromString(linkTypeString.c_str(), linkType)) - { - return AZ::Failure(AZStd::string(GPF_TAG_LINK_TYPE " string is invalid.")); - } - - // If no-code, don't make module definitions - if (linkType != LinkType::NoCode) - { - // Create modules list - rapidjson::Value modulesList{ rapidjson::kArrayType }; - - // Create module definition - { - rapidjson::Value gameModule{ rapidjson::kObjectType }; - gameModule.AddMember(GPF_TAG_MODULE_TYPE, GPF_TAG_MODULE_TYPE_GAME_MODULE, descNode.GetAllocator()); - gameModule.AddMember(GPF_TAG_LINK_TYPE, rapidjson::Value(linkTypeString.c_str(), descNode.GetAllocator()), descNode.GetAllocator()); - - modulesList.PushBack(AZStd::move(gameModule), descNode.GetAllocator()); - } - - // Create server module definition - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_MODULE_TYPE_SERVER_MODULE, IsBool) && descNode[GPF_TAG_MODULE_TYPE_SERVER_MODULE].GetBool()) - { - rapidjson::Value serverModule{ rapidjson::kObjectType }; - serverModule.AddMember(GPF_TAG_MODULE_TYPE, GPF_TAG_MODULE_TYPE_SERVER_MODULE, descNode.GetAllocator()); - serverModule.AddMember(GPF_TAG_LINK_TYPE, rapidjson::Value(linkTypeString.c_str(), descNode.GetAllocator()), descNode.GetAllocator()); - serverModule.AddMember(GPF_TAG_MODULE_NAME, "Server", descNode.GetAllocator()); - modulesList.PushBack(AZStd::move(serverModule), descNode.GetAllocator()); - } - - // Create editor module definition - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_EDITOR_MODULE, IsBool) && descNode[GPF_TAG_EDITOR_MODULE].GetBool()) - { - rapidjson::Value editorModule{ rapidjson::kObjectType }; - editorModule.AddMember(GPF_TAG_MODULE_TYPE, GPF_TAG_MODULE_TYPE_EDITOR_MODULE, descNode.GetAllocator()); - editorModule.AddMember(GPF_TAG_MODULE_NAME, "Editor", descNode.GetAllocator()); - editorModule.AddMember(GPF_TAG_MODULE_EXTENDS, "GameModule", descNode.GetAllocator()); - - modulesList.PushBack(AZStd::move(editorModule), descNode.GetAllocator()); - } - descNode.RemoveMember(GPF_TAG_EDITOR_MODULE); - - // Add modules list to - descNode.AddMember(GPF_TAG_MODULES, modulesList, descNode.GetAllocator()); - } - } - - // file is now up to date - descNode[GPF_TAG_FORMAT_VERSION] = GEM_DEF_FILE_VERSION; - return AZ::Success(); - } - - AZ::Outcome GemDescription::CreateFromJson( - rapidjson::Document& descNode, - const AZStd::string& gemFolderPath, - const AZStd::string& absoluteFilePath) - { - // gem to build - GemDescription gem; - - gem.m_path = gemFolderPath; - gem.m_absolutePath = absoluteFilePath; - AzFramework::StringFunc::Path::StripFullName(gem.m_absolutePath); - AzFramework::StringFunc::RChop(gem.m_absolutePath, 1); - - if (!descNode.IsObject()) - { - return AZ::Failure(AZStd::string("Json root element must be an object.")); - } - - // upgrade contents to current version - auto upgradeOutcome = UpgradeGemDescriptionJson(descNode); - if (!upgradeOutcome.IsSuccess()) - { - return AZ::Failure(upgradeOutcome.TakeError()); - } - - // read name - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_NAME, IsString)) - { - gem.m_name = descNode[GPF_TAG_NAME].GetString(); - } - else - { - return AZ::Failure(AZStd::string(GPF_TAG_NAME " string must not be empty.")); - } - - // read display name - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_DISPLAY_NAME, IsString)) - { - gem.m_displayName = descNode[GPF_TAG_DISPLAY_NAME].GetString(); - } - - // read id - if (!RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_UUID, IsString)) - { - return AZ::Failure(AZStd::string(GPF_TAG_UUID " string is required.")); - } - gem.m_id = AZ::Uuid::CreateString(descNode[GPF_TAG_UUID].GetString()); - if (gem.m_id.IsNull()) - { - return AZ::Failure(AZStd::string::format(GPF_TAG_UUID " string \"%s\" is invalid.", descNode[GPF_TAG_UUID].GetString())); - } - - // read version - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_VERSION, IsString)) - { - auto versionOutcome = GemVersion::ParseFromString(descNode[GPF_TAG_VERSION].GetString()); - - if (versionOutcome) - { - gem.m_version = versionOutcome.GetValue(); - } - else - { - return AZ::Failure(AZStd::string(versionOutcome.GetError())); - } - } - else - { - return AZ::Failure(AZStd::string(GPF_TAG_VERSION " string is required.")); - } - - // To reduce the potential for user error, a Gem depending on the Lumberyard engine version - // supports both arrays and strings. - if (descNode.HasMember(GPF_TAG_LY_VERSION)) - { - AZStd::vector versionConstraints; - // read version constraints - // Check if the version constraint is a string first. - if(RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_LY_VERSION, IsString)) - { - AZStd::string constraintString = descNode[GPF_TAG_LY_VERSION].GetString(); - versionConstraints.push_back(constraintString); - } - // If it wasn't a string, make sure it's an array. If not, error out. - else if (!RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_LY_VERSION, IsArray)) - { - return AZ::Failure(AZStd::string(GPF_TAG_LY_VERSION " array is required for engine version.")); - } - // If it's an empty array, ignore it. - // For ease of use editing the Gem.json files, we support empty arrays, so users - // can leave the engine version key in without providing a value. - else if (descNode[GPF_TAG_LY_VERSION].Size() > 0) - { - const auto& constraints = descNode[GPF_TAG_LY_VERSION]; - const auto& end = constraints.End(); - for (auto it = constraints.Begin(); it != end; ++it) - { - const auto& constraint = *it; - if (!constraint.IsString()) - { - return AZ::Failure(AZStd::string(GPF_TAG_LY_VERSION " array for engine version must contain strings.")); - } - versionConstraints.push_back(constraint.GetString()); - } - } - // If constraints were actually provided, create the dependency. - if(versionConstraints.size() > 0) - { - EngineDependency dep; - dep.SetID(AZ::Uuid::CreateNull()); - AZ::Outcome outcome = dep.ParseVersions(versionConstraints); - if (!outcome) - { - return AZ::Failure(AZStd::string::format(GPF_TAG_LY_VERSION " for engine version is invalid. %s", outcome.GetError().c_str())); - } - gem.m_engineDependency = AZStd::make_shared(dep); - } - } - - // dependencies - if (descNode.HasMember(GPF_TAG_DEPENDENCIES)) - { - if (!descNode[GPF_TAG_DEPENDENCIES].IsArray()) - { - return AZ::Failure(AZStd::string(GPF_TAG_DEPENDENCIES " must be an array.")); - } - - // List of descriptions of Gems we depend upon - const rapidjson::Value& depsNode = descNode[GPF_TAG_DEPENDENCIES]; - const auto& end = depsNode.End(); - for (auto it = depsNode.Begin(); it != end; ++it) - { - const auto& depNode = *it; - if (!depNode.IsObject()) - { - return AZ::Failure(AZStd::string(GPF_TAG_DEPENDENCIES " must contain objects.")); - } - - // read id - if (!RAPIDJSON_IS_VALID_MEMBER(depNode, GPF_TAG_UUID, IsString)) - { - return AZ::Failure(AZStd::string(GPF_TAG_UUID " string is required for dependency.")); - } - - const char* idStr = depNode[GPF_TAG_UUID].GetString(); - AZ::Uuid id(idStr); - if (id.IsNull()) - { - return AZ::Failure(AZStd::string::format(GPF_TAG_UUID " in dependency is invalid: %s.", idStr)); - } - - // read version constraints - if (!RAPIDJSON_IS_VALID_MEMBER(depNode, GPF_TAG_VERSION_CONSTRAINTS, IsArray)) - { - return AZ::Failure(AZStd::string(GPF_TAG_VERSION_CONSTRAINTS " array is required for dependency.")); - } - - // Make sure versions are specified - if (depNode[GPF_TAG_VERSION_CONSTRAINTS].Size() < 1) - { - return AZ::Failure(AZStd::string(GPF_TAG_VERSION_CONSTRAINTS " must have at least 1 entry for dependency.")); - } - - AZStd::vector versionConstraints; - const auto& constraints = depNode[GPF_TAG_VERSION_CONSTRAINTS]; - const auto& constraintsEnd(constraints.End()); - for (auto constraintIt = constraints.Begin(); constraintIt != constraintsEnd; ++constraintIt) - { - const auto& constraint = *constraintIt; - if (!constraint.IsString()) - { - return AZ::Failure(AZStd::string(GPF_TAG_VERSION_CONSTRAINTS " array for dependency must contain strings.")); - } - versionConstraints.push_back(constraint.GetString()); - } - - // create Dependency - GemDependency dep; - dep.SetID(id); - if (!dep.ParseVersions(versionConstraints)) - { - return AZ::Failure(AZStd::string(GPF_TAG_VERSION_CONSTRAINTS " for dependency is invalid")); - } - gem.m_gemDependencies.push_back(AZStd::make_shared(dep)); - } - } - - // Is Game Gem? flag - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_IS_GAME_GEM, IsBool)) - { - gem.m_gameGem = descNode[GPF_TAG_IS_GAME_GEM].GetBool(); - } - else - { - gem.m_gameGem = false; - } - - // Is Required? flag - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_IS_REQUIRED, IsBool)) - { - gem.m_required = descNode[GPF_TAG_IS_REQUIRED].GetBool(); - } - else - { - gem.m_required = false; - } - - // optional metadata - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_SUMMARY, IsString)) - { - gem.m_summary = descNode[GPF_TAG_SUMMARY].GetString(); - } - - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_ICON_PATH, IsString)) - { - gem.m_iconPath = descNode[GPF_TAG_ICON_PATH].GetString(); - } - - if (descNode.HasMember(GPF_TAG_TAGS)) - { - const rapidjson::Value& tags = descNode[GPF_TAG_TAGS]; - if (tags.IsArray()) - { - const auto& end = tags.End(); - for (auto it = tags.Begin(); it != end; ++it) - { - const auto& tag = *it; - gem.m_tags.push_back(tag.GetString()); - } - } - else - { - return AZ::Failure(AZStd::string("Value for key " GPF_TAG_TAGS " must be an array.")); - } - } - - // engine module class - gem.m_engineModuleClass = RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_MODULE_CLASS, IsString) - ? descNode[GPF_TAG_MODULE_CLASS].GetString() - : gem.GetName() + AZStd::string("Gem"); - - // Cache constants - char idStr[UUID_STR_BUF_LEN]; - gem.GetID().ToString(idStr, UUID_STR_BUF_LEN, false, false); - AZStd::to_lower(idStr, idStr + strlen(idStr)); - - // Read the modules list - if (RAPIDJSON_IS_VALID_MEMBER(descNode, GPF_TAG_MODULES, IsArray)) - { - bool foundDefaultModule = false; - AZStd::unordered_map> modulesByName; - AZStd::vector, AZStd::string>> dependencies; - - const rapidjson::Value& modulesNode = descNode[GPF_TAG_MODULES]; - for (auto moduleObjPtr = modulesNode.Begin(); moduleObjPtr != modulesNode.End(); ++moduleObjPtr) - { - const rapidjson::Value& moduleObj = *moduleObjPtr; - if (!moduleObj.IsObject()) - { - return AZ::Failure(AZStd::string("Each object in " GPF_TAG_MODULES " must be an object!")); - } - - auto modulePtr = AZStd::make_shared(); - gem.m_modules.emplace_back(modulePtr); - - // Get the module type - if (!RAPIDJSON_IS_VALID_MEMBER(moduleObj, GPF_TAG_MODULE_TYPE, IsString)) - { - return AZ::Failure(AZStd::string("Each module requires a " GPF_TAG_MODULE_TYPE " field.")); - } - const char* moduleTypeStr = moduleObj[GPF_TAG_MODULE_TYPE].GetString(); - if (!ModuleTypeFromString(moduleTypeStr, modulePtr->m_type)) - { - return AZ::Failure(AZStd::string::format("Module type %s is invalid!", moduleTypeStr)); - } - - // Get the module name (default to the type) - if (RAPIDJSON_IS_VALID_MEMBER(moduleObj, GPF_TAG_MODULE_NAME, IsString)) - { - modulePtr->m_name = moduleObj[GPF_TAG_MODULE_NAME].GetString(); - } - else if (modulePtr->m_type == ModuleDefinition::Type::GameModule || modulePtr->m_type == ModuleDefinition::Type::ServerModule) - { - modulePtr->m_name = moduleTypeStr; - } - else - { - return AZ::Failure(AZStd::string::format("Default \"" GPF_TAG_MODULE_NAME "\" field is only supported for modules of type \"GameModule\", not %s.", moduleTypeStr)); - } - - // Check for duplicate names - if (modulesByName.find(modulePtr->m_name) != modulesByName.end()) - { - return AZ::Failure(AZStd::string::format("Module name \"%s\" is used more than once!", modulePtr->m_name.c_str())); - } - - // If the type is GameModule, omit name from file name (maintains functionality of v3) - if (modulePtr->m_type == ModuleDefinition::Type::GameModule || modulePtr->m_type == ModuleDefinition::Type::ServerModule) - { - if (!foundDefaultModule) - { - foundDefaultModule = true; - // if the module name for 'GameModule' type is specified, such as 'Private' then it needs to be appended into the gem name - if (modulePtr->m_name != moduleTypeStr) - { - modulePtr->m_fileName = AZStd::string::format("Gem.%s.%s.%s.v%s", gem.GetName().c_str(), modulePtr->m_name.c_str(), idStr, gem.GetVersion().ToString().c_str()); - } - else - { - modulePtr->m_fileName = AZStd::string::format("Gem.%s.%s.v%s", gem.GetName().c_str(), idStr, gem.GetVersion().ToString().c_str()); - } - } - - // If LinkType is specified, read and validate it. - if (RAPIDJSON_IS_VALID_MEMBER(moduleObj, GPF_TAG_LINK_TYPE, IsString)) - { - const char* linkTypeStr = moduleObj[GPF_TAG_LINK_TYPE].GetString(); - if (!LinkTypeFromString(linkTypeStr, modulePtr->m_linkType)) - { - return AZ::Failure(AZStd::string::format(GPF_TAG_LINK_TYPE " specified (\"%s\") is invalid", linkTypeStr)); - } - } - } - - // If the module needs a file name, populate it. - if (modulePtr->m_fileName.empty() && modulePtr->m_type != ModuleDefinition::Type::StaticLib) - { - modulePtr->m_fileName = AZStd::string::format("Gem.%s.%s.%s.v%s", gem.GetName().c_str(), modulePtr->m_name.c_str(), idStr, gem.GetVersion().ToString().c_str()); - } - - modulesByName.emplace(modulePtr->m_name, modulePtr); - - // Populate extensions - if (modulePtr->m_type != ModuleDefinition::Type::StaticLib && - RAPIDJSON_IS_VALID_MEMBER(moduleObj, GPF_TAG_MODULE_EXTENDS, IsString)) - { - dependencies.emplace_back(modulePtr, AZStd::string(moduleObj[GPF_TAG_MODULE_EXTENDS].GetString())); - } - } - - // Populate dependencies - for (const auto& dependencyPair : dependencies) - { - auto dependencyIterator = modulesByName.find(dependencyPair.second); - if (dependencyIterator == modulesByName.end()) - { - return AZ::Failure(AZStd::string::format("Module \"%s\" depends on \"" GPF_TAG_MODULE_EXTENDS "\" invalid module \"%s\"", dependencyPair.first->m_name.c_str(), dependencyPair.second.c_str())); - } - - if (dependencyIterator->second->m_type != ModuleDefinition::Type::GameModule && dependencyIterator->second->m_type != ModuleDefinition::Type::ServerModule) - { - return AZ::Failure(AZStd::string::format("Modules may only \"" GPF_TAG_MODULE_EXTENDS "\" modules of type \"" GPF_TAG_MODULE_TYPE_GAME_MODULE "\", " GPF_TAG_MODULE_TYPE_SERVER_MODULE "\".")); - } - - dependencyPair.first->m_parent = dependencyIterator->second; - dependencyIterator->second->m_children.emplace_back(dependencyPair.first); - } - - // Populate modulesByType - for (const auto& modulePtr : gem.m_modules) - { - gem.m_modulesByType[modulePtr->m_type].emplace_back(modulePtr); - - // If this module is a GameModule, and there is no Editor override, apply it to Editor as well. - if (modulePtr->m_type == ModuleDefinition::Type::GameModule) - { - bool foundEditorModule = false; - // Check children for editor modules - for (const auto& childWeak : modulePtr->m_children) - { - auto child = childWeak.lock(); - AZ_Assert(child, "Child somehow out of scope already!"); - if (child->m_type == ModuleDefinition::Type::EditorModule) - { - foundEditorModule = true; - break; - } - } - if (!foundEditorModule) - { - // If no children are for editor, add module to editor list - gem.m_modulesByType[ModuleDefinition::Type::EditorModule].emplace_back(modulePtr); - } - } - } - } - - return AZ::Success(AZStd::move(gem)); - } -} // namespace Gems diff --git a/Code/Tools/GemRegistry/source/GemDescription.h b/Code/Tools/GemRegistry/source/GemDescription.h deleted file mode 100644 index f780949feb..0000000000 --- a/Code/Tools/GemRegistry/source/GemDescription.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -* 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 - -#include "GemRegistry/IGemRegistry.h" - -#include -#include - -namespace Gems -{ - class GemDescription - : public IGemDescription - { - public: - GemDescription(const GemDescription& rhs); - GemDescription(GemDescription&& rhs); - ~GemDescription() override = default; - - // IGemDescription - const AZ::Uuid& GetID() const override { return m_id; } - const AZStd::string& GetName() const override { return m_name; } - const AZStd::string& GetDisplayName() const override { return m_displayName.empty() ? m_name : m_displayName; } - const GemVersion& GetVersion() const override { return m_version; } - const AZStd::string& GetPath() const override { return m_path; } - const AZStd::string& GetAbsolutePath() const override { return m_absolutePath; } - const AZStd::string& GetSummary() const override { return m_summary; } - const AZStd::string& GetIconPath() const override { return m_iconPath; } - const AZStd::vector& GetTags() const override { return m_tags; } - const ModuleDefinitionVector& GetModules() const override { return m_modules; } - const ModuleDefinitionVector& GetModulesOfType(ModuleDefinition::Type type) const override { return m_modulesByType.find(type)->second; } - const AZStd::string& GetEngineModuleClass() const override { return m_engineModuleClass; } - const AZStd::vector >& GetGemDependencies() const override { return m_gemDependencies; } - const bool IsGameGem() const override { return m_gameGem; } - const bool IsRequired() const override { return m_required; } - const AZStd::shared_ptr GetEngineDependency() const override { return m_engineDependency; } - - // ~IGemDescription - - // Internal methods - - /// Create GemDescription from Json. - /// - /// \param[in] json Json object to parse. json may be modified during parse. - /// \param[in] gemFolderPath Relative path from engine root to Gem folder. - /// - /// \returns If successful, the GemDescription. - /// If unsuccessful, an explanation why parsing failed. - static AZ::Outcome CreateFromJson( - rapidjson::Document& json, - const AZStd::string& gemFolderPath, - const AZStd::string& absoluteFilePath); - - private: - // Outsiders may not create an empty GemDescription - GemDescription(); - - /// The ID of the Gem - AZ::Uuid m_id; - /// The name of the Gem - AZStd::string m_name; - /// The UI-friendly name of the Gem - AZStd::string m_displayName; - /// The version of the Gem - GemVersion m_version; - /// Relative path to Gem folder - AZStd::string m_path; - /// Absolute path to Gem folder - AZStd::string m_absolutePath; - /// Summary description of the Gem - AZStd::string m_summary; - /// Icon path of the gem - AZStd::string m_iconPath; - /// Tags to associate with the Gem - AZStd::vector m_tags; - /// List of modules produced by the Gem - ModuleDefinitionVector m_modules; - /// All modules to be loaded for a given function - AZStd::unordered_map m_modulesByType; - /// The name of the engine module class to initialize - AZStd::string m_engineModuleClass; - /// A Gem's dependencies - AZStd::vector > m_gemDependencies; - /// Flag to indicate if this is a Game GEM - bool m_gameGem; - /// Flag to indicate that this is a required GEM - bool m_required; - /// A Gem's engine dependency - AZStd::shared_ptr m_engineDependency = nullptr; - }; -} // namespace Gems diff --git a/Code/Tools/GemRegistry/source/GemRegistry.cpp b/Code/Tools/GemRegistry/source/GemRegistry.cpp deleted file mode 100644 index 83664fc07b..0000000000 --- a/Code/Tools/GemRegistry/source/GemRegistry.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* -* 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. -* -*/ -#include "ProjectSettings.h" -#include "GemRegistry.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Gems -{ - AZ_CLASS_ALLOCATOR_IMPL(GemRegistry, AZ::SystemAllocator, 0) - - AZ::Outcome GemRegistry::AddSearchPath(const SearchPath& searchPathIn, bool loadGemsNow) - { - SearchPath searchPath = searchPathIn; - - // Remove trailing slash if present - char lastChar = *(searchPath.m_path.end() - 1); - if (lastChar == '/' || - lastChar == '\\') - { - AzFramework::StringFunc::RChop(searchPath.m_path, 1); - } - - if (AZStd::find(m_searchPaths.begin(), m_searchPaths.end(), searchPath) == m_searchPaths.end()) - { - m_searchPaths.emplace_back(searchPath); - } - - if (loadGemsNow) - { - return LoadGemsFromDir(searchPath); - } - else - { - return AZ::Success(); - } - } - - AZ::Outcome GemRegistry::LoadAllGemsFromDisk() - { - AZStd::string errorString; - for (const auto& searchPath : m_searchPaths) - { - auto pathOutcome = LoadGemsFromDir(searchPath); - if (!pathOutcome.IsSuccess()) - { - errorString += pathOutcome.GetError() + "\n"; - } - } - - if (errorString.empty()) - { - return AZ::Success(); - } - else - { - // Remove trailing \n - return AZ::Failure(errorString.substr(0, errorString.length() - 1)); - } - } - - AZ::Outcome GemRegistry::LoadProject(const IProjectSettings& settings, bool resetPreviousProjects) - { - if (resetPreviousProjects) - { - m_gemDescs.clear(); - } - for (const auto& pair : settings.GetGems()) - { - const char* absolutePath = nullptr; - - // First priority goes to the project root's folder - AZStd::string testGemPath = settings.GetProjectRootPath(); - if (AzFramework::StringFunc::Path::ConstructFull(settings.GetProjectRootPath().c_str(), pair.second.m_path.c_str(), testGemPath, true)) - { - if (AzFramework::StringFunc::Path::Join(testGemPath.c_str(), GEM_DEF_FILE, testGemPath)) - { - if (AZ::IO::SystemFile::Exists(testGemPath.c_str())) - { - absolutePath = testGemPath.c_str(); - } - } - } - - auto loadOutcome = LoadGemDescription(pair.second.m_path, absolutePath); - if (!loadOutcome.IsSuccess()) - { - return AZ::Failure(loadOutcome.GetError()); - } - } - return AZ::Success(); - } - - IGemDescriptionConstPtr GemRegistry::GetGemDescription(const GemSpecifier& spec) const - { - IGemDescriptionConstPtr result; - - auto idIt = m_gemDescs.find(spec.m_id); - if (idIt != m_gemDescs.end()) - { - auto versionIt = idIt->second.find(spec.m_version); - if (versionIt != idIt->second.end()) - { - result = AZStd::static_pointer_cast(versionIt->second); - } - } - - return result; - } - - IGemDescriptionConstPtr GemRegistry::GetLatestGem(const AZ::Uuid& uuid) const - { - IGemDescriptionConstPtr result; - auto idIt = m_gemDescs.find(uuid); - if (idIt != m_gemDescs.end()) - { - GemVersion latestVersion; - GemDescriptionPtr desc; - - for (const auto& pair : idIt->second) - { - if (pair.first > latestVersion) - { - latestVersion = pair.first; - desc = pair.second; - } - } - - if (!latestVersion.IsZero()) - { - result = AZStd::static_pointer_cast(desc); - } - } - - return result; - } - - AZStd::vector GemRegistry::GetAllGemDescriptions() const - { - AZStd::vector results; - - for (auto && idIt : m_gemDescs) - { - for (auto && versionIt : idIt.second) - { - results.push_back(AZStd::static_pointer_cast(versionIt.second)); - } - } - - return results; - } - - AZStd::vector GemRegistry::GetAllRequiredGemDescriptions() const - { - AZStd::vector results; - - for (auto && idIt : m_gemDescs) - { - for (auto && versionIt : idIt.second) - { - if (versionIt.second->IsRequired()) - { - results.push_back(AZStd::static_pointer_cast(versionIt.second)); - } - } - } - return results; - } - - IGemDescriptionConstPtr GemRegistry::GetProjectGemDescription(const AZStd::string& projectName) const - { - IGemDescriptionConstPtr result; - - // We know searchPaths[0] is the old engine root, so we'll just use that to avoid a search - AZStd::string gemFolderPath = projectName + "/Gem"; - auto descOutcome = ParseToGemDescription(gemFolderPath, nullptr); - if (descOutcome) - { - result = AZStd::make_shared(descOutcome.TakeValue()); - } - - return result; - } - - - IProjectSettings* GemRegistry::CreateProjectSettings() - { - return aznew ProjectSettings(this); - } - - void GemRegistry::DestroyProjectSettings(IProjectSettings* settings) - { - delete settings; - } - - AZ::Outcome GemRegistry::LoadGemsFromDir(const SearchPath& searchPath) - { - AZ::IO::LocalFileIO fileIo; - AZStd::string errorString; - - // Handles each file and directory found - // Safe to capture all by reference because the find will run sync - AZ::IO::LocalFileIO::FindFilesCallbackType fileFinderCb; - fileFinderCb = [&](const char* fullPath) -> bool - { - if (fileIo.IsDirectory(fullPath)) - { - // recurse into subdirectory - // "*" filter will match all files/directories except specials ('.', '..', etc.) with the fewest compares - fileIo.FindFiles(fullPath, "*", fileFinderCb); - } - else - { - AZStd::string fileName; - AzFramework::StringFunc::Path::GetFullFileName(fullPath, fileName); - if (0 == azstricmp(fileName.c_str(), GEM_DEF_FILE)) - { - // need relative path to gem folder, so strip searchPath from front and Gem.json from back - AZStd::string gemFolderRelPath = fullPath + searchPath.m_path.length(); - AzFramework::StringFunc::Path::StripFullName(gemFolderRelPath); - AzFramework::StringFunc::RChop(gemFolderRelPath, 1); // Remove trailing '/' - auto skipPathFirstSepIndex = gemFolderRelPath.find_first_not_of("/\\"); - gemFolderRelPath = gemFolderRelPath.substr(skipPathFirstSepIndex); - - auto loadOutcome = LoadGemDescription(gemFolderRelPath, fullPath); - if (loadOutcome.IsSuccess() == false) - { - errorString += AZStd::string::format("Fail to load Gems from path %s disk. %s\n", searchPath.m_path.c_str(), loadOutcome.GetError().c_str()); - } - - // We found the Gem.json file but we have to keep looking to support nested gems - } - } - - return true; // keep searching - }; - - // Scans subdirectories - fileIo.FindFiles(searchPath.m_path.c_str(), searchPath.m_filter.c_str(), fileFinderCb); - - if (errorString.empty()) - { - return AZ::Success(); - } - else - { - // Remove trailing \n - return AZ::Failure(errorString.substr(0, errorString.length() - 1)); - } - } - - AZ::Outcome GemRegistry::LoadGemDescription(const AZStd::string& gemFolderPath, const char* absoluteFilePath) - { - auto descOutcome = ParseToGemDescription(gemFolderPath, absoluteFilePath); - if (!descOutcome) - { - return AZ::Failure(AZStd::string::format("An error occurred while parsing %s: %s", gemFolderPath.c_str(), descOutcome.GetError().c_str())); - } - - auto desc = AZStd::make_shared(descOutcome.TakeValue()); - - // If the Gem hasn't been loaded yet, add it's id to the root map - auto idIt = m_gemDescs.find(desc->GetID()); - if (idIt == m_gemDescs.end()) - { - idIt = m_gemDescs.emplace(desc->GetID(), AZStd::unordered_map()).first; - } - - // If the Gem's version doesn't exist, add it, otherwise update it - auto versionIt = idIt->second.find(desc->GetVersion()); - if (versionIt == idIt->second.end()) - { - idIt->second.emplace(desc->GetVersion(), AZStd::move(desc)); - } - else - { - versionIt->second = desc; - } - - return AZ::Success(AZStd::static_pointer_cast(desc)); - } - - AZ::Outcome GemRegistry::ParseToGemDescriptionPtr(const AZStd::string& gemFolderRelPath, const char* absoluteFilePath) - { - auto descOutcome = ParseToGemDescription(gemFolderRelPath, absoluteFilePath); - if (!descOutcome) - { - return AZ::Failure(AZStd::string::format("An error occurred while parsing %s: %s", gemFolderRelPath.c_str(), descOutcome.GetError().c_str())); - } - - auto desc = AZStd::make_shared(descOutcome.TakeValue()); - - return AZ::Success(AZStd::static_pointer_cast(desc)); - } - - AZ::Outcome GemRegistry::ParseToGemDescription(const AZStd::string& gemFolderPath, const char* absoluteFilePath) const - { - // do we have a pluggable, engine-compatible fileIO? For things like tools, we may not be plugged - // into a game engine, and thus, we may need to use raw file io. - AZ::IO::FileIOBase* fileReader = AZ::IO::FileIOBase::GetInstance(); - - // build absolute path to gem file - AZStd::string filePath; - - if (absoluteFilePath) - { - filePath = absoluteFilePath; - } - else - { - for (const auto& searchPath : m_searchPaths) - { - // Append relative path to search path - AzFramework::StringFunc::Path::Join(searchPath.m_path.c_str(), gemFolderPath.c_str(), filePath); - // Append file name to file path - AzFramework::StringFunc::Path::Join(filePath.c_str(), GEM_DEF_FILE, filePath); - // note that paths are case sensitive on some systems. - - if (fileReader) - { - if (fileReader->Exists(filePath.c_str())) - { - break; - } - } - else - { - if (AZ::IO::SystemFile::Exists(filePath.c_str())) - { - break; - } - } - } - } - - // read json - AZStd::string fileBuf; - if (fileReader) - { - // an engine compatible file reader has been attached, so use that. - AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; - AZ::u64 fileSize = 0; - if (!fileReader->Open(filePath.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary, fileHandle)) - { - return AZ::Failure(AZStd::string::format("Failed to read %s - file read failed.", filePath.c_str())); - } - - if ((!fileReader->Size(fileHandle, fileSize)) || (fileSize == 0)) - { - fileReader->Close(fileHandle); - return AZ::Failure(AZStd::string::format("Failed to read %s - file read failed.", filePath.c_str())); - } - - fileBuf.resize(fileSize); - if (!fileReader->Read(fileHandle, fileBuf.data(), fileSize, true)) - { - fileReader->Close(fileHandle); - return AZ::Failure(AZStd::string::format("Failed to read %s - file read failed.", filePath.c_str())); - } - fileReader->Close(fileHandle); - } - else - { - // we don't have an engine file io, use raw file IO. - AZ::IO::SystemFile rawFile; - if (!rawFile.Open(filePath.c_str(), AZ::IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY)) - { - return AZ::Failure(AZStd::string::format("Failed to read %s - file read failed.", filePath.c_str())); - } - fileBuf.resize(rawFile.Length()); - if (fileBuf.size() == 0) - { - return AZ::Failure(AZStd::string::format("Failed to read %s - file read failed.", filePath.c_str())); - } - if (rawFile.Read(fileBuf.size(), fileBuf.data()) != fileBuf.size()) - { - return AZ::Failure(AZStd::string::format("Failed to read %s - file read failed.", filePath.c_str())); - } - } - - rapidjson::Document document; - document.Parse(fileBuf.data()); - if (document.HasParseError()) - { - const char* errorStr = rapidjson::GetParseError_En(document.GetParseError()); - return AZ::Failure(AZStd::string::format("Failed to parse %s: %s", filePath.c_str(), errorStr)); - } - - return GemDescription::CreateFromJson(document, gemFolderPath, filePath); - } -} // namespace Gems - -////////////////////////////////////////////////////////////////////////// -// DLL Exported Functions -////////////////////////////////////////////////////////////////////////// - -#ifndef AZ_MONOLITHIC_BUILD // Module init functions, only required when building as a DLL. -AZ_DECLARE_MODULE_INITIALIZATION -#endif//AZ_MONOLITHIC_BUILD - -extern "C" AZ_DLL_EXPORT Gems::IGemRegistry * CreateGemRegistry() -{ - return aznew Gems::GemRegistry(); -} - -extern "C" AZ_DLL_EXPORT void DestroyGemRegistry(Gems::IGemRegistry* reg) -{ - delete reg; -} diff --git a/Code/Tools/GemRegistry/source/GemRegistry.h b/Code/Tools/GemRegistry/source/GemRegistry.h deleted file mode 100644 index 4ec9462b5a..0000000000 --- a/Code/Tools/GemRegistry/source/GemRegistry.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -* 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 - -#include "GemRegistry/IGemRegistry.h" -#include "GemDescription.h" - -#include -#include - -// Constants -#define UUID_STR_BUF_LEN 64 -#define GEMS_ASSETS_FOLDER "Assets" -#define GEM_DEF_FILE "gem.json" -#define GEM_DEF_FILE_VERSION 4 -#define GEMS_PROJECT_FILE "gems.json" -#define GEMS_PROJECT_FILE_VERSION 2 -#define PROJECT_CONFIG_FILE "project.json" - -// Gem project file JSON tags -#define GPF_TAG_FORMAT_VERSION "GemFormatVersion" -#define GPF_TAG_LIST_FORMAT_VERSION "GemListFormatVersion" -#define GPF_TAG_NAME "Name" -#define GPF_TAG_DISPLAY_NAME "DisplayName" -#define GPF_TAG_GEM_ARRAY "Gems" -#define GPF_TAG_UUID "Uuid" -#define GPF_TAG_LY_VERSION "LumberyardVersion" -#define GPF_TAG_VERSION "Version" -#define GPF_TAG_DEPENDENCIES "Dependencies" -#define GPF_TAG_VERSION_CONSTRAINTS "VersionConstraints" -#define GPF_TAG_PATH "Path" -#define GPF_TAG_MODULE_CLASS "EngineModuleClass" -#define GPF_TAG_EDITOR_MODULE "EditorModule" -#define GPF_TAG_SUMMARY "Summary" -#define GPF_TAG_ICON_PATH "IconPath" -#define GPF_TAG_TAGS "Tags" -#define GPF_TAG_LINK_TYPE "LinkType" -#define GPF_TAG_LINK_TYPE_DYNAMIC "Dynamic" -#define GPF_TAG_LINK_TYPE_DYNAMIC_STATIC "DynamicStatic" -#define GPF_TAG_LINK_TYPE_NO_CODE "NoCode" -#define GPF_TAG_MODULES "Modules" -#define GPF_TAG_MODULE_NAME "Name" -#define GPF_TAG_MODULE_TYPE "Type" -#define GPF_TAG_MODULE_TYPE_GAME_MODULE "GameModule" -#define GPF_TAG_MODULE_TYPE_SERVER_MODULE "ServerModule" -#define GPF_TAG_MODULE_TYPE_EDITOR_MODULE "EditorModule" -#define GPF_TAG_MODULE_TYPE_STATIC_LIB "StaticLib" -#define GPF_TAG_MODULE_TYPE_BUILDER "Builder" -#define GPF_TAG_MODULE_TYPE_STANDALONE "Standalone" -#define GPF_TAG_MODULE_EXTENDS "Extends" -#define GPF_TAG_IS_GAME_GEM "IsGameGem" -#define GPF_TAG_IS_REQUIRED "IsRequired" -#define GPF_TAG_COMMENT "_comment" - -namespace Gems -{ - class GemRegistry - : public IGemRegistry - { - public: - AZ_CLASS_ALLOCATOR_DECL; - - ////////////////////////////////////////////////////////////////////////// - // IGemRegistry - AZ::Outcome AddSearchPath(const SearchPath& searchPath, bool loadGemsNow) override; - AZ::Outcome LoadAllGemsFromDisk() override; - AZ::Outcome LoadProject(const IProjectSettings& settings, bool resetPreviousProjects) override; - - AZ::Outcome ParseToGemDescriptionPtr(const AZStd::string& gemFolderRelPath, const char* absoluteFilePath) override; - IGemDescriptionConstPtr GetGemDescription(const GemSpecifier& spec) const override; - IGemDescriptionConstPtr GetLatestGem(const AZ::Uuid& uuid) const override; - AZStd::vector GetAllGemDescriptions() const override; - AZStd::vector GetAllRequiredGemDescriptions() const override; - IGemDescriptionConstPtr GetProjectGemDescription(const AZStd::string& projectName) const override; - - IProjectSettings* CreateProjectSettings() override; - void DestroyProjectSettings(IProjectSettings* settings) override; - - ~GemRegistry() override = default; - ////////////////////////////////////////////////////////////////////////// - - private: - using GemDescriptionPtr = AZStd::shared_ptr; - - AZ::Outcome LoadGemsFromDir(const SearchPath& searchPath); - // Pass nullptr for absoluteFolderPath to do a search for the Gem - AZ::Outcome LoadGemDescription(const AZStd::string& gemFolderPath, const char* absoluteFilePath); - AZ::Outcome ParseToGemDescription(const AZStd::string& gemFolderPath, const char* absoluteFilePath) const; - - AZStd::vector m_searchPaths; // Explictly ordered so that AddSearchPath() order matters - AZStd::unordered_map > m_gemDescs; - }; -} // namespace Gems - -extern "C" AZ_DLL_EXPORT Gems::IGemRegistry * CreateGemRegistry(); -extern "C" AZ_DLL_EXPORT void DestroyGemRegistry(Gems::IGemRegistry* reg); diff --git a/Code/Tools/GemRegistry/source/ProjectSettings.cpp b/Code/Tools/GemRegistry/source/ProjectSettings.cpp deleted file mode 100644 index 61cfe8b5ec..0000000000 --- a/Code/Tools/GemRegistry/source/ProjectSettings.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/* -* 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. -* -*/ -#include "ProjectSettings.h" -#include "GemRegistry.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#if defined(AZ_PLATFORM_ANDROID) -#include -#endif - -#define MAX_ERROR_STRING_SIZE 512 - -namespace Gems -{ - AZ_CLASS_ALLOCATOR_IMPL(ProjectSettings, AZ::SystemAllocator, 0) - - ProjectSettings::ProjectSettings(GemRegistry* registry) - : m_registry(registry) - , m_initialized(false) - { - } - - AZ::Outcome ProjectSettings::Initialize(const AZStd::string& appRootFolder, const AZStd::string& projectSubFolder) - { - AZ_Assert(!m_initialized, "ProjectSettings has been initialized already."); - - // Initialize the app root folder - m_projectRootPath = appRootFolder; - - // Project gems file lives in (ProjectFolder)/gems.json - which might be @assets@/gems.json or an absolute path (in tools) - m_gemsSettingsFilePath = appRootFolder; - AzFramework::StringFunc::Path::Join(m_gemsSettingsFilePath.c_str(), projectSubFolder.c_str(), m_gemsSettingsFilePath); - AzFramework::StringFunc::Path::Join(m_gemsSettingsFilePath.c_str(), GEMS_PROJECT_FILE, m_gemsSettingsFilePath); - - // Project config file lives in (ProjectFolder)/project.json - which might be @assets@/project.json or an absolute path (in tools) - m_projectSettingsFilePath = appRootFolder; - AzFramework::StringFunc::Path::Join(m_projectSettingsFilePath.c_str(), projectSubFolder.c_str(), m_projectSettingsFilePath); - AzFramework::StringFunc::Path::Join(m_projectSettingsFilePath.c_str(), PROJECT_CONFIG_FILE, m_projectSettingsFilePath); - - auto loadOutcome = LoadSettings(); - m_initialized = loadOutcome.IsSuccess(); - return loadOutcome; - } - - bool ProjectSettings::EnableGem(const ProjectGemSpecifier& spec) - { - auto it = m_gems.find(spec.m_id); - if (it != m_gems.end()) - { - // If the Gem is already enabled, update the version and path of the entry. - it->second.m_version = spec.m_version; - it->second.m_path = spec.m_path; - } - else - { - // create entry based on data from registry - m_gems.insert(AZStd::make_pair(spec.m_id, spec)); - } - return true; - } - - bool ProjectSettings::DisableGem(const GemSpecifier& spec) - { - auto it = m_gems.find(spec.m_id); - // If the Gem is enabled at the version specified, disable it. - if (it != m_gems.end()) - { - if (spec.m_version != it->second.m_version) - { - return false; - } - - m_gems.erase(it); - } - return true; - } - - bool ProjectSettings::IsGemEnabled(const GemSpecifier& spec) const - { - auto it = m_gems.find(spec.m_id); - return it != m_gems.end() - && it->second.m_version == spec.m_version; - } - - bool ProjectSettings::IsGemEnabled(const AZ::Uuid& id, const AZStd::vector& versionConstraints) const - { - AZStd::shared_ptr dependency = AZStd::make_shared(); - dependency->SetID(id); - auto parseOutcome = dependency->ParseVersions(versionConstraints); - if (!parseOutcome.IsSuccess()) - { - AZ_Assert(false, parseOutcome.GetError().c_str()); - return false; - } - - return IsGemDependencyMet(dependency); - } - - bool ProjectSettings::IsGemDependencyMet(const AZStd::shared_ptr dep) const - { - // Gems can depend on other Gems - auto it = m_gems.find(dep->GetID()); - return it != m_gems.end() - && dep->IsFullfilledBy(it->second); - } - - bool ProjectSettings::IsEngineDependencyMet(const AZStd::shared_ptr dep, const EngineVersion& againstVersion) const - { - EngineSpecifier engineSpecifier(AZ::Uuid::CreateNull(), againstVersion); - return dep->IsFullfilledBy(engineSpecifier); - } - - class GemDependencyInfo : public GemDependency - { - - public: - - GemDependencyInfo(IGemDescriptionConstPtr gem) - : GemDependency() - , m_gem{gem} - { - } - - IGemDescriptionConstPtr GetGem() const - { - return m_gem; - } - - private: - - IGemDescriptionConstPtr m_gem; - - }; - - AZ::Outcome ProjectSettings::ValidateDependencies(const EngineVersion& engineVersion) const - { - AZStd::unordered_map globalDeps; - - // Build list of required Gems - for (const auto& pair : m_gems) - { - const ProjectGemSpecifier& spec = pair.second; - - auto gem = m_registry->GetGemDescription(spec); - if (!gem) - { - return AZ::Failure(AZStd::string::format("Gem with Id \"%s\" not found.", pair.first.ToString().c_str())); - } - - for (auto && gemDep : gem->GetGemDependencies()) - { - const AZ::Uuid id = gemDep->GetID(); - GemDependency* dep; - - // If the dependency isn't tracked globally, create a new one - auto depIt = globalDeps.find(id); - if (depIt == globalDeps.end()) - { - globalDeps.insert(AZStd::make_pair(id, GemDependencyInfo(gem))); - dep = &globalDeps.at(id); - dep->m_id = id; - } - else - { - dep = &depIt->second; - } - - // These bounds should be normalized before verification to make sure there aren't conflicting bounds - dep->m_bounds.insert(dep->m_bounds.end(), gemDep->GetBounds().begin(), gemDep->GetBounds().end()); - } - } - - AZStd::string errorString; - bool isTreeValid = true; - - // Verify all engine dependencies are met - for(const auto& pair : m_gems) - { - const ProjectGemSpecifier& spec = pair.second; - - auto gem = m_registry->GetGemDescription(spec); - if (!gem) - { - errorString += AZStd::string::format("Gem with Id \"%s\" not found.", pair.first.ToString().c_str()); - isTreeValid = false; - continue; - } - - // do not verify the engine version if input is default constructed - if (engineVersion == EngineVersion()) - { - continue; - } - - // Check the Gem's engine dependency - auto engineDepPtr = gem->GetEngineDependency(); - if (engineDepPtr && !IsEngineDependencyMet(engineDepPtr, engineVersion)) - { - AZStd::string errmsg = AZStd::string::format("Gem with Id \"%s\" does not meet the Lumberyard engine version requirement.\n", - pair.first.ToString().c_str()); - - // do not force an assertion to happen here, we are just printing the warning and letting the user - // decide on how to handle it if the engine start up fails. - errorString += errmsg; - AZ_Warning("GemRegistry", false, errmsg.c_str()); - } - } - - // attempt to construct a complete gem registry for unmet dependency ID to name resolution - GemRegistry completeRegistry; - - const char* gemsSearchFilter = "Gems"; - - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - if (appRoot) - { - completeRegistry.AddSearchPath({ appRoot, gemsSearchFilter }, false); - } - - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - if (engineRoot) - { - completeRegistry.AddSearchPath({ engineRoot, gemsSearchFilter }, false); - } - - completeRegistry.LoadAllGemsFromDisk(); - - // Verify all gems dependencies are all met - for (auto && pair : globalDeps) - { - const GemDependencyInfo& dep = pair.second; - - // Find candidate in project's listed gems - auto candidateIt = m_gems.find(dep.GetID()); - if (candidateIt == m_gems.end()) - { - // no candidate found - char depIdStr[UUID_STR_BUF_LEN]; - dep.GetID().ToString(depIdStr, UUID_STR_BUF_LEN, true, true); - - char gemIdStr[UUID_STR_BUF_LEN]; - dep.GetGem()->GetID().ToString(gemIdStr, UUID_STR_BUF_LEN, true, true); - - // don't care about the version, just need the gem name - IGemDescriptionConstPtr depDesc = completeRegistry.GetLatestGem(dep.GetID()); - if (depDesc) - { - errorString += AZStd::string::format( - "Gem \"%s\" (%s) dependency on Gem \"%s\" (%s) is unmet.\n", - dep.GetGem()->GetDisplayName().c_str(), - gemIdStr, - depDesc->GetDisplayName().c_str(), - depIdStr - ); - } - else - { - errorString += AZStd::string::format( - "Gem \"%s\" (%s) dependency on unresolved Gem with ID %s is unmet.\n", - dep.GetGem()->GetDisplayName().c_str(), - gemIdStr, - depIdStr - ); - } - - isTreeValid = false; - } - else if (!dep.IsFullfilledBy(candidateIt->second)) - { - // candidate found, but it doesn't fulfill all dependency requirements - AZStd::string boundsStr; - for (auto && bound : dep.m_bounds) - { - if (boundsStr.length() == 0) - { - boundsStr = bound.ToString(); - } - else - { - boundsStr += ", " + bound.ToString(); - } - } - - char depIdStr[UUID_STR_BUF_LEN]; - dep.GetID().ToString(depIdStr, UUID_STR_BUF_LEN, true, true); - - char gemIdStr[UUID_STR_BUF_LEN]; - dep.GetGem()->GetID().ToString(gemIdStr, UUID_STR_BUF_LEN, true, true); - - // don't care about the version, just need the gem name - IGemDescriptionConstPtr depDesc = completeRegistry.GetLatestGem(dep.GetID()); - if (depDesc) - { - errorString += AZStd::string::format( - "Gem \"%s\" (%s) dependency on Gem \"%s\" (%s) is unmet. It must fall within the following version bounds: [%s]\n", - dep.GetGem()->GetDisplayName().c_str(), - gemIdStr, - depDesc->GetDisplayName().c_str(), - depIdStr, - boundsStr.c_str() - ); - } - else - { - errorString += AZStd::string::format( - "Gem \"%s\" (%s) dependency on unresolved Gem with ID %s is unmet. It must fall within the following version bounds: [%s]\n", - dep.GetGem()->GetDisplayName().c_str(), - gemIdStr, - depIdStr, - boundsStr.c_str() - ); - } - - isTreeValid = false; - } - } - - if (!isTreeValid) - { - return AZ::Failure(errorString); - } - - return AZ::Success(); - } - - AZ::Outcome ProjectSettings::Save() const - { - using namespace AZ::IO; - FileIOBase* fileIo = FileIOBase::GetInstance(); - - HandleType projectSettingsHandle = InvalidHandle; - if (fileIo->Open(m_gemsSettingsFilePath.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, projectSettingsHandle)) - { - rapidjson::Document jsonRep = GetJsonRepresentation(); - - rapidjson::StringBuffer buffer; - rapidjson::PrettyWriter writer(buffer); - jsonRep.Accept(writer); - - AZ::u64 bytesWritten = 0; - if (!fileIo->Write(projectSettingsHandle, buffer.GetString(), buffer.GetSize(), &bytesWritten)) - { - return AZ::Failure(AZStd::string::format("Failed to write Gems settings to file: %s", m_gemsSettingsFilePath.c_str())); - } - - if (bytesWritten != buffer.GetSize()) - { - return AZ::Failure(AZStd::string::format("Failed to write complete Gems settings to file: %s", m_gemsSettingsFilePath.c_str())); - } - - fileIo->Close(projectSettingsHandle); - - return AZ::Success(); - } - else - { - char errorBuffer[MAX_ERROR_STRING_SIZE]; -#if defined(AZ_PLATFORM_WINDOWS) - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - errorBuffer, - MAX_ERROR_STRING_SIZE, - nullptr); -#else - azstrerror_s(errorBuffer, MAX_ERROR_STRING_SIZE, errno); -#endif // defined(AZ_PLATFORM_WINDOWS) - return AZ::Failure(AZStd::string::format("Failed to open %s for write: %s", m_gemsSettingsFilePath.c_str(), errorBuffer)); - } - } - - const AZStd::string& ProjectSettings::GetProjectName() const - { - return m_projectName; - } - - const AZStd::string& ProjectSettings::GetProjectRootPath() const - { - return m_projectRootPath; - } - - AZ::Outcome ProjectSettings::LoadSettings() - { - // an engine compatible file reader has been attached, so use that. - AZ::IO::FileIOBase* fileReader = AZ::IO::FileIOBase::GetInstance(); - - // Read and parse the gems.json file - { - AZ::IO::Path gemsSettingsPath(m_gemsSettingsFilePath); - auto readGemsJsonResult = AzFramework::FileFunc::ReadJsonFile(gemsSettingsPath, fileReader); - if (!readGemsJsonResult.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("Failed to read Json file %s: %s", - m_gemsSettingsFilePath.c_str(), readGemsJsonResult.GetError().c_str())); - } - auto parseGemsJsonResult = ParseGemsJson(readGemsJsonResult.GetValue()); - if (!parseGemsJsonResult.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("Failed to parse Json file %s: %s", - m_gemsSettingsFilePath.c_str(), parseGemsJsonResult.GetError().c_str())); - } - } - - // Read and parse the project.json file - { - AZ::IO::Path projectSettingsPath(m_projectSettingsFilePath); - auto readProjectJsonResult = AzFramework::FileFunc::ReadJsonFile(projectSettingsPath, fileReader); - if (!readProjectJsonResult.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("Failed to read Json file %s: %s", - m_gemsSettingsFilePath.c_str(), readProjectJsonResult.GetError().c_str())); - } - auto parseProjectJsonResult = ParseProjectJson(readProjectJsonResult.GetValue()); - if (!parseProjectJsonResult.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("Failed to parse Json file %s: %s", - m_gemsSettingsFilePath.c_str(), parseProjectJsonResult.GetError().c_str())); - } - } - - return AZ::Success(); - } - - rapidjson::Document ProjectSettings::GetJsonRepresentation() const - { - rapidjson::Document rootObj(rapidjson::kObjectType); - rootObj.AddMember(GPF_TAG_LIST_FORMAT_VERSION, GEMS_PROJECT_FILE_VERSION, rootObj.GetAllocator()); - - // We want to write out Gems in the same order each time. - // Create vector for sorting. - AZStd::vector sortedGems(m_gems.size()); - auto transformFn = [](const ProjectGemSpecifierMap::value_type& pair) { return &pair.second; }; - AZStd::transform(m_gems.begin(), m_gems.end(), sortedGems.begin(), transformFn); - - // we'll sort based on ID. - AZStd::sort(sortedGems.begin(), sortedGems.end(), [](const ProjectGemSpecifier* a, const ProjectGemSpecifier* b) -> bool - { - return a->m_id < b->m_id; - }); - - auto addMember = [&rootObj](rapidjson::Value& obj, const char* key, const char* str) - { - rapidjson::Value k(rapidjson::StringRef(key), rootObj.GetAllocator()); - rapidjson::Value v(rapidjson::StringRef(str), rootObj.GetAllocator()); - obj.AddMember(k.Move(), v.Move(), rootObj.GetAllocator()); - }; - - // build Gems array - rapidjson::Value gemsArray(rapidjson::kArrayType); - for (const ProjectGemSpecifier* gemSpec : sortedGems) - { - char idStr[UUID_STR_BUF_LEN]; - gemSpec->m_id.ToString(idStr, UUID_STR_BUF_LEN, false, false); - AZStd::to_lower(idStr, idStr + strlen(idStr)); - - AZStd::string path = gemSpec->m_path; - // Replace '\' with '/' - AZStd::replace(path.begin(), path.end(), '\\', '/'); - // Remove trailing slash - if (*path.rbegin() == '/') - { - path.pop_back(); - } - - rapidjson::Value gemObj(rapidjson::kObjectType); - addMember(gemObj, GPF_TAG_PATH, path.c_str()); - addMember(gemObj, GPF_TAG_UUID, idStr); - addMember(gemObj, GPF_TAG_VERSION, gemSpec->m_version.ToString().c_str()); - - // write name in comment (if possible) - if (IGemDescriptionConstPtr gemDesc = m_registry->GetGemDescription(*gemSpec)) - { - addMember(gemObj, GPF_TAG_COMMENT, gemDesc->GetName().c_str()); - } - - gemsArray.PushBack(gemObj, rootObj.GetAllocator()); - } - rootObj.AddMember(GPF_TAG_GEM_ARRAY, gemsArray, rootObj.GetAllocator()); - - return rootObj; - } - - AZ::Outcome ProjectSettings::ParseGemsJson(const rapidjson::Document& jsonRep) - { - // check version - if (!RAPIDJSON_IS_VALID_MEMBER(jsonRep, GPF_TAG_LIST_FORMAT_VERSION, IsInt)) - { - return AZ::Failure(AZStd::string(GPF_TAG_LIST_FORMAT_VERSION " number is required.")); - } - - int gemListFormatVersion = jsonRep[GPF_TAG_LIST_FORMAT_VERSION].GetInt(); - if (gemListFormatVersion != GEMS_PROJECT_FILE_VERSION) - { - return AZ::Failure(AZStd::string::format( - GPF_TAG_LIST_FORMAT_VERSION " is version %d, but %d is expected.", - gemListFormatVersion, - GEMS_PROJECT_FILE_VERSION)); - } - - // read gems - if (!RAPIDJSON_IS_VALID_MEMBER(jsonRep, GPF_TAG_GEM_ARRAY, IsArray)) - { - return AZ::Failure(AZStd::string(GPF_TAG_GEM_ARRAY " list is required")); - } - - const rapidjson::Value& gemList = jsonRep[GPF_TAG_GEM_ARRAY]; - const auto& end = gemList.End(); - for (auto it = gemList.Begin(); it != end; ++it) - { - const auto& elem = *it; - - // gem id - if (!RAPIDJSON_IS_VALID_MEMBER(elem, GPF_TAG_UUID, IsString)) - { - return AZ::Failure(AZStd::string(GPF_TAG_UUID " string is required for Gem.")); - } - const char* idStr = elem[GPF_TAG_UUID].GetString(); - AZ::Uuid id = AZ::Uuid::CreateString(idStr); - if (id.IsNull()) - { - return AZ::Failure(AZStd::string(GPF_TAG_UUID " string is invalid for Gem.")); - } - - // gem version - if (!RAPIDJSON_IS_VALID_MEMBER(elem, GPF_TAG_VERSION, IsString)) - { - return AZ::Failure(AZStd::string::format( - GPF_TAG_VERSION " string is missing for Gem with ID %s.", - idStr)); - } - - auto versionOutcome = GemVersion::ParseFromString(elem[GPF_TAG_VERSION].GetString()); - if (!versionOutcome) - { - return AZ::Failure(AZStd::string::format( - GPF_TAG_VERSION " string is invalid for Gem with ID %s: %s", - idStr, versionOutcome.GetError().c_str())); - } - GemVersion version = versionOutcome.GetValue(); - - // gem path - if (!RAPIDJSON_IS_VALID_MEMBER(elem, GPF_TAG_PATH, IsString)) - { - return AZ::Failure(AZStd::string(GPF_TAG_PATH " string is required for Gem")); - } - const char* path = elem[GPF_TAG_PATH].GetString(); - - EnableGem(ProjectGemSpecifier(id, version, path)); - } - - return AZ::Success(); - } - - AZ::Outcome ProjectSettings::ParseProjectJson(const rapidjson::Document& json) - { - // For now, we only - static const char* project_name_key = "project_name"; - if (!RAPIDJSON_IS_VALID_MEMBER(json, project_name_key, IsString)) - { - return AZ::Failure(AZStd::string::format("Missing/Invalid key '%s' in project.json.", project_name_key)); - } - m_projectName = json[project_name_key].GetString(); - return AZ::Success(); - } - -} // namespace Gems diff --git a/Code/Tools/GemRegistry/source/ProjectSettings.h b/Code/Tools/GemRegistry/source/ProjectSettings.h deleted file mode 100644 index 17c38bdbeb..0000000000 --- a/Code/Tools/GemRegistry/source/ProjectSettings.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -* 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 - -#include -#include - -#include "GemRegistry.h" - -namespace Gems -{ - class ProjectSettings - : public IProjectSettings - { - public: - AZ_CLASS_ALLOCATOR_DECL - - ProjectSettings(GemRegistry* registry); - ~ProjectSettings() override = default; - - // IProjectSettings - AZ::Outcome Initialize(const AZStd::string& appRootFolder, const AZStd::string& projectSubFolder) override; - - bool EnableGem(const ProjectGemSpecifier& spec) override; - bool DisableGem(const GemSpecifier& spec) override; - bool IsGemEnabled(const GemSpecifier& spec) const override; - bool IsGemEnabled(const AZ::Uuid& id, const AZStd::vector& versionConstraints) const override; - bool IsGemDependencyMet(const AZStd::shared_ptr dep) const override; - bool IsEngineDependencyMet(const AZStd::shared_ptr dep, const EngineVersion& againstVersion) const override; - - const ProjectGemSpecifierMap& GetGems() const override { return m_gems; } - void SetGems(const ProjectGemSpecifierMap& newGemMap) override { m_gems = newGemMap; } - AZ::Outcome ValidateDependencies(const EngineVersion& engineVersion) const override; - - AZ::Outcome Save() const override; - const AZStd::string& GetProjectName() const override; - const AZStd::string& GetProjectRootPath() const override; - - // ~IProjectSettings - - // Internal methods - /// Loads settings from the path provided by m_settingsFilePath - AZ::Outcome LoadSettings(); - /// Converts the ProjectGemSpecifierMap (m_gems) into it's Json representation for saving - rapidjson::Document GetJsonRepresentation() const; - /// Converts GEMS Json into the ProjectGemSpecifierMap (m_gems) - AZ::Outcome ParseGemsJson(const rapidjson::Document& json); - /// Reads from project.json to initialize project-specific values - AZ::Outcome ParseProjectJson(const rapidjson::Document& json); - - private: - ProjectGemSpecifierMap m_gems; - GemRegistry* m_registry; - AZStd::string m_gemsSettingsFilePath; - AZStd::string m_projectSettingsFilePath; - AZStd::string m_projectName; - AZStd::string m_projectRootPath; - bool m_initialized; - }; -} // namespace Gems diff --git a/Code/Tools/GemRegistry/tests/DependencyTest.cpp b/Code/Tools/GemRegistry/tests/DependencyTest.cpp deleted file mode 100644 index ffa3198c21..0000000000 --- a/Code/Tools/GemRegistry/tests/DependencyTest.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* -* 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. -* -*/ -#include -#include - -using namespace Gems; -using GemComp = GemDependency::Bound::Comparison; -using EngineComp = EngineDependency::Bound::Comparison; - -class DependencyTest - : public ::testing::Test -{ -protected: - enum class Bound - { - Upper, - Lower - }; - - void SetUp() override - { - m_errCopyCtorFailed = "Failed to copy Dependency instance."; - m_errParseInvalidSucceeded = "Failed to report invalid version."; - m_errParseFailed = "Failed to parse valid version string."; - m_errIncorrectBoundCount = "Improper number of bounds generated."; - m_errComparisonMismatch = "Comparison generated does not match "; - m_errSpecFulfillsFailed = "Spec that fulfills dependency was reported as invalid."; - m_errInvalidSpecFulfills = "Spec that does not fulfill dependency was reported as valid."; - m_errToStringIncorrect = "ToString result is incorrect."; - } - - const char* ErrComparisonMismatch(const char* op) - { - return AZStd::string::format("Comparison generated does not match %s.", op).c_str(); - } - - const char* ErrInvalidBound(Bound b) - { - return AZStd::string::format("Version generated does not match %s bound.", b == Bound::Upper ? "upper" : "lower").c_str(); - } - - const char* m_errCopyCtorFailed; - const char* m_errParseInvalidSucceeded; - const char* m_errParseFailed; - const char* m_errIncorrectBoundCount; - const char* m_errComparisonMismatch; - const char* m_errSpecFulfillsFailed; - const char* m_errInvalidSpecFulfills; - const char* m_errToStringIncorrect; -}; - -TEST_F(DependencyTest, MiscTests) -{ - { - GemDependency dep1; - dep1.m_id = AZ::Uuid::CreateRandom(); - dep1.m_bounds.push_back(GemDependency::Bound{}); - - GemDependency dep2{ - dep1 - }; - EXPECT_EQ(dep2.m_id, dep1.m_id) << m_errCopyCtorFailed; - EXPECT_EQ(dep2.m_bounds.size(), dep1.m_bounds.size()) << m_errCopyCtorFailed; - } - - { - EngineDependency dep1; - dep1.m_id = AZ::Uuid::CreateRandom(); - dep1.m_bounds.push_back(EngineDependency::Bound{}); - - EngineDependency dep2 { - dep1 - }; - EXPECT_EQ(dep2.m_id, dep1.m_id) << m_errCopyCtorFailed; - EXPECT_EQ(dep2.m_bounds.size(), dep1.m_bounds.size()) << m_errCopyCtorFailed; - } -} - -TEST_F(DependencyTest, FailureTest) -{ - { - GemDependency dep; - - EXPECT_FALSE(dep.ParseVersions({ "Not a version requirement!" }).IsSuccess()) << m_errParseInvalidSucceeded; - EXPECT_FALSE(dep.ParseVersions({ "~>1" }).IsSuccess()) << m_errParseInvalidSucceeded; - EXPECT_FALSE(dep.ParseVersions({ "~>1.invalid" }).IsSuccess()) << m_errParseInvalidSucceeded; - } - - { - EngineDependency dep; - - EXPECT_FALSE(dep.ParseVersions({ "Not a version requirement!" }).IsSuccess()) << m_errParseInvalidSucceeded; - EXPECT_FALSE(dep.ParseVersions({ "~>1" }).IsSuccess()) << m_errParseInvalidSucceeded; - EXPECT_FALSE(dep.ParseVersions({ "~>1.invalid" }).IsSuccess()) << m_errParseInvalidSucceeded; - } -} - -TEST_F(DependencyTest, TwiddleWakkaTest) -{ - { - GemDependency dep; - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::TwiddleWakka) << ErrComparisonMismatch("Twiddle Wakka"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(1, 0, 0)) << ErrInvalidBound(Bound::Lower); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::TwiddleWakka) << ErrComparisonMismatch("Twiddle Wakka"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(1, 0, 1)) << ErrInvalidBound(Bound::Lower); - } - - { - EngineDependency dep; - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::TwiddleWakka) << ErrComparisonMismatch("Twiddle Wakka"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 1, 0, 0, 0 })) << ErrInvalidBound(Bound::Lower); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::TwiddleWakka) << ErrComparisonMismatch("Twiddle Wakka"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 1, 0, 1, 0 })) << ErrInvalidBound(Bound::Lower); - } -} - -TEST_F(DependencyTest, SingleVersionTest) -{ - { - GemDependency dep; - - ASSERT_TRUE(dep.ParseVersions({ ">=1.0.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::GreaterThan | GemComp::EqualTo) << ErrComparisonMismatch(">="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(1, 0, 0)) << ErrInvalidBound(Bound::Lower); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">2.20.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::GreaterThan) << ErrComparisonMismatch(">"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(2, 20, 0)) << ErrInvalidBound(Bound::Lower); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "==3.4.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::EqualTo) << ErrComparisonMismatch("=="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(3, 4, 0)) << ErrInvalidBound(Bound::Lower); - } - - { - EngineDependency dep; - - ASSERT_TRUE(dep.ParseVersions({ ">=1.0.0.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::GreaterThan | EngineComp::EqualTo) << ErrComparisonMismatch(">="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 1, 0, 0, 0 })) << ErrInvalidBound(Bound::Lower); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">2.20.0.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::GreaterThan) << ErrComparisonMismatch(">"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 2, 20, 0, 0 })) << ErrInvalidBound(Bound::Lower); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "==3.4.0.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::EqualTo) << ErrComparisonMismatch("=="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 3, 4, 0, 0 })) << ErrInvalidBound(Bound::Lower); - } -} - -TEST_F(DependencyTest, DoubleVersionTest) -{ - { - GemDependency dep; - - ASSERT_TRUE(dep.ParseVersions({ ">=1.0.0", "<2.0.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::GreaterThan | GemComp::EqualTo) << ErrComparisonMismatch(">="); - EXPECT_EQ(dep.GetBounds()[1].GetComparison(), GemComp::LessThan) << ErrComparisonMismatch("<"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(1, 0, 0)) << ErrInvalidBound(Bound::Lower); - EXPECT_EQ(dep.GetBounds()[1].GetVersion(), GemVersion(2, 0, 0)) << ErrInvalidBound(Bound::Upper); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">2.20.0", "<=3" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::GreaterThan) << ErrComparisonMismatch(">"); - EXPECT_EQ(dep.GetBounds()[1].GetComparison(), GemComp::LessThan | GemComp::EqualTo) << ErrComparisonMismatch("<="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(2, 20, 0)) << ErrInvalidBound(Bound::Lower); - EXPECT_EQ(dep.GetBounds()[1].GetVersion(), GemVersion(3, 0, 0)) << ErrInvalidBound(Bound::Upper); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "<3.4.0", ">=20.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), GemComp::LessThan) << ErrComparisonMismatch("<"); - EXPECT_EQ(dep.GetBounds()[1].GetComparison(), GemComp::GreaterThan | GemComp::EqualTo) << ErrComparisonMismatch(">="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), GemVersion(3, 4, 0)) << ErrInvalidBound(Bound::Lower); - EXPECT_EQ(dep.GetBounds()[1].GetVersion(), GemVersion(20, 1, 0)) << ErrInvalidBound(Bound::Upper); - } - - { - EngineDependency dep; - - ASSERT_TRUE(dep.ParseVersions({ ">=1.0.0.0", "<2.0.0.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::GreaterThan | EngineComp::EqualTo) << ErrComparisonMismatch(">="); - EXPECT_EQ(dep.GetBounds()[1].GetComparison(), EngineComp::LessThan) << ErrComparisonMismatch("<"); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 1, 0, 0, 0 })) << ErrInvalidBound(Bound::Lower); - EXPECT_EQ(dep.GetBounds()[1].GetVersion(), EngineVersion({ 2, 0, 0, 0 })) << ErrInvalidBound(Bound::Upper); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">2.20.0.0", "<=3" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::GreaterThan) << ErrComparisonMismatch(">"); - EXPECT_EQ(dep.GetBounds()[1].GetComparison(), EngineComp::LessThan | EngineComp::EqualTo) << ErrComparisonMismatch("<="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 2, 20, 0, 0 })) << ErrInvalidBound(Bound::Lower); - EXPECT_EQ(dep.GetBounds()[1].GetVersion(), EngineVersion({ 3, 0, 0, 0 })) << ErrInvalidBound(Bound::Upper); - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "<3.4.0.0", ">=20.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_EQ(dep.GetBounds()[0].GetComparison(), EngineComp::LessThan) << ErrComparisonMismatch("<"); - EXPECT_EQ(dep.GetBounds()[1].GetComparison(), EngineComp::GreaterThan | EngineComp::EqualTo) << ErrComparisonMismatch(">="); - EXPECT_EQ(dep.GetBounds()[0].GetVersion(), EngineVersion({ 3, 4, 0, 0 })) << ErrInvalidBound(Bound::Lower); - EXPECT_EQ(dep.GetBounds()[1].GetVersion(), EngineVersion({ 20, 1, 0, 0 })) << ErrInvalidBound(Bound::Upper); - } -} - -TEST_F(DependencyTest, FullfillmentTest) -{ - { - AZ::Uuid gemId = AZ::Uuid::CreateRandom(); - - GemDependency dep; - dep.SetID(gemId); - - GemSpecifier spec1 = { gemId, GemVersion(1, 0, 0) }; - GemSpecifier specR = { AZ::Uuid::CreateRandom(), GemVersion(0, 0, 0) }; - - ASSERT_TRUE(dep.ParseVersions(AZStd::vector()).IsSuccess())<< m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 0) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy(spec1)) << m_errSpecFulfillsFailed; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">=1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy(spec1)) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy(specR)) << m_errInvalidSpecFulfills; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">0", "<1.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy(spec1)) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy(specR)) << m_errInvalidSpecFulfills; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">1", "<2", "==1.2" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 3) << m_errIncorrectBoundCount; - EXPECT_FALSE(dep.IsFullfilledBy(spec1)) << m_errInvalidSpecFulfills; - EXPECT_FALSE(dep.IsFullfilledBy(specR)) << m_errInvalidSpecFulfills; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy({ gemId, GemVersion(1, 0, 0) })) << m_errSpecFulfillsFailed; - EXPECT_TRUE(dep.IsFullfilledBy({ gemId, GemVersion(1, 1, 0) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ gemId, GemVersion(2, 0, 0) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ gemId, GemVersion(0, 0, 1) })) << m_errSpecFulfillsFailed; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy({ gemId, GemVersion(1, 0, 1) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ gemId, GemVersion(1, 1, 0) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ gemId, GemVersion(1, 0, 0) })) << m_errSpecFulfillsFailed; - } - - { - AZ::Uuid engineId = AZ::Uuid::CreateRandom(); - - EngineDependency dep; - dep.SetID(engineId); - - EngineSpecifier spec1 = { engineId, EngineVersion({ 1, 0, 0, 0 }) }; - EngineSpecifier specR = { AZ::Uuid::CreateRandom(), EngineVersion({ 0, 0, 0, 0 }) }; - - ASSERT_TRUE(dep.ParseVersions(AZStd::vector()).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 0) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy(spec1)) << m_errSpecFulfillsFailed; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">=1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy(spec1)) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy(specR)) << m_errInvalidSpecFulfills; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">0", "<1.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 2) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy(spec1)) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy(specR)) << m_errInvalidSpecFulfills; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ ">1", "<2", "==1.2" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 3) << m_errIncorrectBoundCount; - EXPECT_FALSE(dep.IsFullfilledBy(spec1)) << m_errInvalidSpecFulfills; - EXPECT_FALSE(dep.IsFullfilledBy(specR)) << m_errInvalidSpecFulfills; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy({ engineId, EngineVersion({ 1, 0, 0, 0 }) })) << m_errSpecFulfillsFailed; - EXPECT_TRUE(dep.IsFullfilledBy({ engineId, EngineVersion({ 1, 1, 0, 0 }) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ engineId, EngineVersion({ 2, 0, 0, 0 }) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ engineId, EngineVersion({ 0, 0, 1, 0 }) })) << m_errSpecFulfillsFailed; - - dep.m_bounds.clear(); - - ASSERT_TRUE(dep.ParseVersions({ "~>1.0.1" }).IsSuccess()) << m_errParseFailed; - ASSERT_EQ(dep.GetBounds().size(), 1) << m_errIncorrectBoundCount; - EXPECT_TRUE(dep.IsFullfilledBy({ engineId, EngineVersion({ 1, 0, 1, 0 }) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ engineId, EngineVersion({ 1, 1, 0, 0 }) })) << m_errSpecFulfillsFailed; - EXPECT_FALSE(dep.IsFullfilledBy({ engineId, EngineVersion({ 1, 0, 0, 0 }) })) << m_errSpecFulfillsFailed; - } -} - -TEST_F(DependencyTest, BoundToStringTest) -{ - { - GemVersion v1 { - 1, 0, 0 - }; - - GemDependency::Bound bnd; - bnd.SetVersion(v1); - - bnd.SetComparison(GemComp::EqualTo); - EXPECT_STREQ(bnd.ToString().c_str(), "==1.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(GemComp::GreaterThan); - EXPECT_STREQ(bnd.ToString().c_str(), ">1.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(GemComp::LessThan); - EXPECT_STREQ(bnd.ToString().c_str(), "<1.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(GemComp::GreaterThan | GemComp::EqualTo); - EXPECT_STREQ(bnd.ToString().c_str(), ">=1.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(GemComp::LessThan | GemComp::EqualTo); - EXPECT_STREQ(bnd.ToString().c_str(), "<=1.0.0") << m_errToStringIncorrect; - } - - { - EngineVersion v1{ - 1, 0, 0, 0 - }; - - EngineDependency::Bound bnd; - bnd.SetVersion(v1); - - bnd.SetComparison(EngineComp::EqualTo); - EXPECT_STREQ(bnd.ToString().c_str(), "==1.0.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(EngineComp::GreaterThan); - EXPECT_STREQ(bnd.ToString().c_str(), ">1.0.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(EngineComp::LessThan); - EXPECT_STREQ(bnd.ToString().c_str(), "<1.0.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(EngineComp::GreaterThan | EngineComp::EqualTo); - EXPECT_STREQ(bnd.ToString().c_str(), ">=1.0.0.0") << m_errToStringIncorrect; - - bnd.SetComparison(EngineComp::LessThan | EngineComp::EqualTo); - EXPECT_STREQ(bnd.ToString().c_str(), "<=1.0.0.0") << m_errToStringIncorrect; - } -} diff --git a/Code/Tools/GemRegistry/tests/DescriptionTest.cpp b/Code/Tools/GemRegistry/tests/DescriptionTest.cpp deleted file mode 100644 index 4b7b307552..0000000000 --- a/Code/Tools/GemRegistry/tests/DescriptionTest.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * 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. - * - */ -#include -#include "GemDescription.h" - -using Gems::GemDescription; -using Gems::ModuleDefinition; - -class DescriptionTest - : public ::testing::Test -{ -protected: - void SetUp() override - { - } - - void TearDown() override - { - - } - - /// Helper to parse json text to a GemDescription result - static AZ::Outcome CreateFromString(const char* text) - { - rapidjson::Document document; - document.Parse(text); - EXPECT_FALSE(document.HasParseError()); - - return GemDescription::CreateFromJson(document, "", ""); - } - - /// Helper to parse json text (that should compile) to a GemDescription - static GemDescription ParseString(const char* text) - { - auto result = CreateFromString(text); - EXPECT_TRUE(result.IsSuccess()); - - return AZStd::move(result.GetValue()); - } -}; - -// Helper asserts -#define EXPECT_MODULE_COUNT(desc, expectedCount) EXPECT_EQ(expectedCount, desc.GetModules().size()); -#define EXPECT_MODULE_TYPE_COUNT(desc, type, expectedCount) EXPECT_EQ(expectedCount, desc.GetModulesOfType(ModuleDefinition::Type::type).size()) - -//////////////////////////////////////////////////////////////////////// -// Success tests -//////////////////////////////////////////////////////////////////////// - -// Test for parsing V3 Gem Descriptions -TEST_F(DescriptionTest, ParseJson_V3_GameModule) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 3, - "Uuid": "ff06785f7145416b9d46fde39098cb0c", - "Name": "LmbrCentral", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Required LmbrCentral Engine Gem.", - "Tags": ["Untagged"], - "IconPath": "preview.png", - "IsRequired": true -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 1); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -// Test for parsing V3 Gem Descriptions with an editor module -TEST_F(DescriptionTest, ParseJson_V3_EditorModule) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 3, - "Uuid": "ff06785f7145416b9d46fde39098cb0c", - "Name": "LmbrCentral", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Required LmbrCentral Engine Gem.", - "Tags": ["Untagged"], - "IconPath": "preview.png", - "EditorModule": true, - "IsRequired": true -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 2); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -// Test for parsing V4 Gem Descriptions with a game module -TEST_F(DescriptionTest, ParseJson_V4_GameModule) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - } - ] -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 1); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -// Test for parsing V4 Gem Descriptions with an editor module -TEST_F(DescriptionTest, ParseJson_V4_EditorModule) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Editor", - "Type": "EditorModule" - } - ] -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 1); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -// Test for parsing V4 Gem Descriptions with a game and an editor module (that extends the editor module -TEST_F(DescriptionTest, ParseJson_V4_EditorModuleExtends) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "GameModule" - } - ] -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 2); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 1); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -// Test for parsing V4 Gem Descriptions with a static lib -TEST_F(DescriptionTest, ParseJson_V4_StaticLib) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "CameraHelper", - "Type": "StaticLib" - } - ] -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 1); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 1); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -// Test for parsing V4 Gem Descriptions with a static lib -TEST_F(DescriptionTest, ParseJson_V4_Standalone) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "CameraHelper", - "Type": "Standalone" - } - ] -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 1); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 1); -} - -// Test for parsing V4 Gem Descriptions with a builder module -TEST_F(DescriptionTest, ParseJson_V4_BuilderModule) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "CameraBuilder", - "Type": "Builder" - } - ] -} -)JSON"; - - GemDescription desc = ParseString(description); - - EXPECT_MODULE_COUNT(desc, 1); - - EXPECT_MODULE_TYPE_COUNT(desc, GameModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, EditorModule, 0); - EXPECT_MODULE_TYPE_COUNT(desc, StaticLib, 0); - EXPECT_MODULE_TYPE_COUNT(desc, Builder, 1); - EXPECT_MODULE_TYPE_COUNT(desc, Standalone, 0); -} - -//////////////////////////////////////////////////////////////////////// -// Failure tests -//////////////////////////////////////////////////////////////////////// - -// Test for parsing V4 Gem Descriptions with an invalid extends -TEST_F(DescriptionTest, ParseJson_V4_ExtendsNonExistantModule) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "ModuleThatDoesntExist" - } - ] -} -)JSON"; - - EXPECT_FALSE(CreateFromString(description).IsSuccess()); -} - -// Test for parsing V4 Gem Descriptions with an invalid extends -TEST_F(DescriptionTest, ParseJson_V4_ExtendsStaticLib) -{ - static const char* description = R"JSON( -{ - "GemFormatVersion": 4, - "Uuid": "f910686b6725452fbfc4671f95f733c6", - "Name": "Camera", - "Version": "0.1.0", - "DisplayName": "Camera", - "Tags": ["Camera"], - "Summary": "The Camera Gem includes a basic camera component that defines a frustum for runtime rendering.", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "CameraHelper", - "Type": "StaticLib" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "CameraHelper" - } - ] -} -)JSON"; - - EXPECT_FALSE(CreateFromString(description).IsSuccess()); -} \ No newline at end of file diff --git a/Code/Tools/GemRegistry/tests/ProjectSettingsTest.cpp b/Code/Tools/GemRegistry/tests/ProjectSettingsTest.cpp deleted file mode 100644 index 8f4d654b3d..0000000000 --- a/Code/Tools/GemRegistry/tests/ProjectSettingsTest.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* -* 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. -* -*/ -#include -#include "ProjectSettings.h" -#include "GemDescription.h" - -using Gems::ProjectSettings; -using Gems::ProjectGemSpecifier; -using AzFramework::Specifier; -using Gems::GemVersion; - -class ProjectSettingsTest - : public ::testing::Test -{ -protected: - void SetUp() override - { - m_registry = aznew Gems::GemRegistry(); - m_errCreationFailed = "Failed to create a ProjectSettings instance."; - m_errNonEmptyEnabledGems = "EnabledGems should start empty."; - m_errEnableGemFailed = "Failed to enable valid Gem Spec."; - m_errIsGemEnabledFailed = "Failed to accurately determine if a gem was enabled or not"; - m_errDescriptionParseFailed = "Failed to parse valid Description: "; - m_errInvalidDescriptionParseSucceeded = "Parsing of invalid Description succeeded."; - } - - void TearDown() override - { - delete m_registry; - } - - enum GenerateJsonFlags : AZ::u8 - { - GJF_IncludeID = 1 << 0, - GJF_IncludeVersion = 1 << 1, - GJF_IncludePath = 1 << 2, - GJF_All = GJF_IncludeID | GJF_IncludeVersion | GJF_IncludePath, - }; - - rapidjson::Document ParseFromString(AZStd::string document) - { - rapidjson::Document root(rapidjson::kObjectType); - root.Parse(document.c_str()); - return root; - } - - void GenerateJson(rapidjson::Document& rootObj, AZ::Uuid id, GemVersion version, const AZStd::string& path, AZ::u8 flags) - { - rootObj.SetObject(); - rootObj.AddMember(GPF_TAG_LIST_FORMAT_VERSION, GEMS_PROJECT_FILE_VERSION, rootObj.GetAllocator()); - - rapidjson::Value gemsArray(rapidjson::kArrayType); - - if (flags != 0) - { - // build a gem - rapidjson::Value gemObj(rapidjson::kObjectType); - - if (flags & GJF_IncludeID) - { - char idstr[UUID_STR_BUF_LEN]; - id.ToString(idstr, UUID_STR_BUF_LEN, false, false); - rapidjson::Value v(idstr, rootObj.GetAllocator()); - gemObj.AddMember(GPF_TAG_UUID, v.Move(), rootObj.GetAllocator()); - } - - if (flags & GJF_IncludeVersion) - { - rapidjson::Value v(version.ToString().c_str(), rootObj.GetAllocator()); - gemObj.AddMember(GPF_TAG_VERSION, v.Move(), rootObj.GetAllocator()); - } - - if (flags & GJF_IncludePath) - { - rapidjson::Value v(path.c_str(), rootObj.GetAllocator()); - gemObj.AddMember(GPF_TAG_PATH, v.Move(), rootObj.GetAllocator()); - } - - gemsArray.PushBack(gemObj.Move(), rootObj.GetAllocator()); // copy into array - } - - rootObj.AddMember(GPF_TAG_GEM_ARRAY, gemsArray.Move(), rootObj.GetAllocator()); // copy into root object - } - - Gems::GemRegistry* m_registry; - const char* m_errCreationFailed; - const char* m_errNonEmptyEnabledGems; - const char* m_errEnableGemFailed; - const char* m_errIsGemEnabledFailed; - const char* m_errDescriptionParseFailed; - const char* m_errInvalidDescriptionParseSucceeded; -}; - -TEST_F(ProjectSettingsTest, CreateAndDestroyTest) -{ - Gems::IProjectSettings* ps = m_registry->CreateProjectSettings(); - EXPECT_NE(ps, nullptr) << m_errCreationFailed; - m_registry->DestroyProjectSettings(ps); -} - -TEST_F(ProjectSettingsTest, EnableDisableTest) -{ - ProjectSettings ps { - m_registry - }; - AZ::Uuid id = AZ::Uuid::CreateRandom(); - GemVersion v1 { - 1, 0, 0 - }; - AZStd::string path { - "some\\path" - }; - ProjectGemSpecifier s0 { - id, v1, path - }; - - EXPECT_TRUE(ps.EnableGem(s0)) << m_errEnableGemFailed; - EXPECT_TRUE(ps.IsGemEnabled(s0)) << m_errEnableGemFailed; - - EXPECT_TRUE(ps.DisableGem(s0)) << m_errEnableGemFailed; - EXPECT_FALSE(ps.IsGemEnabled(s0)) << m_errEnableGemFailed; -} - -TEST_F(ProjectSettingsTest, IsEnabledTest) -{ - ProjectSettings ps { - m_registry - }; - ProjectGemSpecifier enabledGemSpecifier { - AZ::Uuid::CreateRandom(), GemVersion { - 1, 0, 0 - }, "some\\path" - }; - - EXPECT_TRUE(ps.EnableGem(enabledGemSpecifier)) << m_errEnableGemFailed; - - // Compare 1.0.0 to 1.0.0 - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<=1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "==1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">1.0.0" })) << m_errIsGemEnabledFailed; - - // Compare 1.0.0 to 1.0.1 - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<1.0.1" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<=1.0.1" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "==1.0.1" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=1.0.1" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">1.0.1" })) << m_errIsGemEnabledFailed; - - // Compare 1.0.0 to 0.1.1 - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<0.1.1" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<=0.1.1" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "==0.1.1" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=0.1.1" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">0.1.1" })) << m_errIsGemEnabledFailed; - - // Test ranges around the enabled gem - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=0.1.0", "<=1.1.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "<=1.1.0", ">=0.1.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "~>1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "~>1.0" })) << m_errIsGemEnabledFailed; - - // Test ranges at or above the enabled gem - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=1.0.0", "<=1.1.0" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">1.0.0", "<=1.1.0" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "~>1.1.0" })) << m_errIsGemEnabledFailed; - - //// Test ranges at or below the enabled gem - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=0.1.0", "<1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_TRUE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { ">=0.1.0", "<=1.0.0" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "~>0.1.0" })) << m_errIsGemEnabledFailed; - EXPECT_FALSE(ps.IsGemEnabled(enabledGemSpecifier.m_id, { "~>0.1" })) << m_errIsGemEnabledFailed; -} - -TEST_F(ProjectSettingsTest, ParseTest) -{ - ProjectSettings ps { - m_registry - }; - AZ::Uuid id = AZ::Uuid::CreateRandom(); - GemVersion v1 { - 1, 0, 0 - }; - AZStd::string path("Some\\Path"); - - rapidjson::Document json(rapidjson::kObjectType); - GenerateJson(json, id, v1, path, GJF_All); - AZ::Outcome outcome = ps.ParseGemsJson(json); - ASSERT_TRUE(outcome.IsSuccess()) << m_errDescriptionParseFailed << outcome.GetError().c_str(); - auto gemMap = ps.GetGems(); - EXPECT_EQ(gemMap.size(), 1) << m_errDescriptionParseFailed << outcome.GetError().c_str(); - EXPECT_EQ(gemMap.begin()->second.m_id, id) << m_errDescriptionParseFailed << outcome.GetError().c_str(); - EXPECT_EQ(gemMap.begin()->second.m_version, v1) << m_errDescriptionParseFailed << outcome.GetError().c_str(); - - GenerateJson(json, id, v1, path, GJF_IncludeVersion | GJF_IncludePath); - EXPECT_FALSE(ps.ParseGemsJson(json)) << m_errInvalidDescriptionParseSucceeded; - - GenerateJson(json, id, v1, path, GJF_IncludeID | GJF_IncludePath); - EXPECT_FALSE(ps.ParseGemsJson(json)) << m_errInvalidDescriptionParseSucceeded; - - GenerateJson(json, id, v1, path, GJF_IncludeVersion | GJF_IncludeID); - EXPECT_FALSE(ps.ParseGemsJson(json)) << m_errInvalidDescriptionParseSucceeded; - - GenerateJson(json, id, v1, path, GJF_IncludeID | GJF_IncludeVersion | GJF_IncludePath); - EXPECT_TRUE(ps.ParseGemsJson(json)) << m_errDescriptionParseFailed; -} - -TEST_F(ProjectSettingsTest, SaveTest) -{ - ProjectSettings ps { - m_registry - }; - AZ::Uuid id = AZ::Uuid::CreateRandom(); - char idStr[UUID_STR_BUF_LEN]; - id.ToString(idStr, UUID_STR_BUF_LEN, false, false); - GemVersion v1 { - 1, 0, 0 - }; - AZStd::string path("Some\\Path"); - - rapidjson::Document json(rapidjson::kObjectType); - GenerateJson(json, id, v1, path, GJF_All); - ASSERT_TRUE(ps.ParseGemsJson(json)) << m_errDescriptionParseFailed; - EXPECT_TRUE(json.HasMember(GPF_TAG_LIST_FORMAT_VERSION)) << m_errDescriptionParseFailed; - EXPECT_TRUE(json[GPF_TAG_LIST_FORMAT_VERSION].IsInt()) << m_errDescriptionParseFailed; - EXPECT_EQ(json[GPF_TAG_LIST_FORMAT_VERSION].GetInt(), GEMS_PROJECT_FILE_VERSION) << m_errDescriptionParseFailed; - ASSERT_TRUE(json.HasMember(GPF_TAG_GEM_ARRAY)) << m_errDescriptionParseFailed; - ASSERT_TRUE(json[GPF_TAG_GEM_ARRAY].IsArray()) << m_errDescriptionParseFailed; - ASSERT_EQ(json[GPF_TAG_GEM_ARRAY].Size(), 1) << m_errDescriptionParseFailed; - EXPECT_STRCASEEQ(json[GPF_TAG_GEM_ARRAY][0][GPF_TAG_UUID].GetString(), idStr) << m_errDescriptionParseFailed; - EXPECT_STRCASEEQ(json[GPF_TAG_GEM_ARRAY][0][GPF_TAG_VERSION].GetString(), v1.ToString().c_str()) << m_errDescriptionParseFailed; - EXPECT_STRCASEEQ(json[GPF_TAG_GEM_ARRAY][0][GPF_TAG_PATH].GetString(), path.c_str()) << m_errDescriptionParseFailed; - - ps.DisableGem({ id, v1 }); - json = ps.GetJsonRepresentation(); - ASSERT_EQ(json[GPF_TAG_GEM_ARRAY].Size(), 0); -} diff --git a/Code/Tools/GemRegistry/tests/RegistryTest.cpp b/Code/Tools/GemRegistry/tests/RegistryTest.cpp deleted file mode 100644 index b6984193dd..0000000000 --- a/Code/Tools/GemRegistry/tests/RegistryTest.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -* 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. -* -*/ -#include -#include "GemRegistry.h" - -using Gems::GemRegistry; - -class RegistryTest - : public ::testing::Test -{ -protected: - void SetUp() override - { - m_errCreationFailed = "Failed to create a GemRegistry instance."; - m_errInvalidErrorMessage = "Error message is not what it was set to."; - } - - const char* m_errCreationFailed; - const char* m_errInvalidErrorMessage; -}; - -TEST_F(RegistryTest, CreateAndDestroyTest) -{ - Gems::IGemRegistry* gr = CreateGemRegistry(); - ASSERT_NE(gr, nullptr) << m_errCreationFailed; - DestroyGemRegistry(gr); -} \ No newline at end of file diff --git a/Code/Tools/GemRegistry/tests/VersionTest.cpp b/Code/Tools/GemRegistry/tests/VersionTest.cpp deleted file mode 100644 index 42cad26ba5..0000000000 --- a/Code/Tools/GemRegistry/tests/VersionTest.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* -* 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. -* -*/ -#include - -#include -#include - -using Gems::GemVersion; -using Gems::EngineVersion; - -class VersionTest - : public ::testing::Test -{ -protected: - void SetUp() override - { - m_errParseFailed = "Failed to parse valid version string."; - m_errParseInvalidSucceeded = "Parsing invalid version string succeeded."; - m_errParseInvalid = "ParseFromString resulted in incorrect version."; - m_errCompareIncorrect = "Result of Compare is incorrect."; - m_errToStringIncorrect = "ToString result is incorrect."; - m_errHasherIncorrect = "Did not get back the same value from hash map."; - } - - const char* m_errParseFailed; - const char* m_errParseInvalidSucceeded; - const char* m_errParseInvalid; - const char* m_errCompareIncorrect; - const char* m_errToStringIncorrect; - const char* m_errHasherIncorrect; -}; - -TEST_F(VersionTest, InitializerListConstructor_ValidValues_ReturnSameValues) -{ - GemVersion v0 = { 1, 2, 3 }; - - ASSERT_EQ(v0.m_parts[0], 1) << m_errParseInvalid; - ASSERT_EQ(v0.m_parts[1], 2) << m_errParseInvalid; - ASSERT_EQ(v0.m_parts[2], 3) << m_errParseInvalid; - - EngineVersion v1 = { 1, 2, 3, 4 }; - - ASSERT_EQ(v1.m_parts[0], 1) << m_errParseInvalid; - ASSERT_EQ(v1.m_parts[1], 2) << m_errParseInvalid; - ASSERT_EQ(v1.m_parts[2], 3) << m_errParseInvalid; - ASSERT_EQ(v1.m_parts[3], 4) << m_errParseInvalid; -} - -TEST_F(VersionTest, ParseFromString_ValidString_ReturnSuccessOutcomeWithCorrectValues) -{ - auto version0Outcome = GemVersion::ParseFromString("1.2.3"); - ASSERT_TRUE(version0Outcome.IsSuccess()) << m_errParseFailed; - - GemVersion v0 = version0Outcome.GetValue(); - - ASSERT_EQ(v0.GetMajor(), 1) << m_errParseInvalid; - ASSERT_EQ(v0.GetMinor(), 2) << m_errParseInvalid; - ASSERT_EQ(v0.GetPatch(), 3) << m_errParseInvalid; - - auto version1Outcome = EngineVersion::ParseFromString("1.2.3.4"); - ASSERT_TRUE(version1Outcome.IsSuccess()) << m_errParseFailed; - - EngineVersion v1 = version1Outcome.GetValue(); - - ASSERT_EQ(v1.m_parts[0], 1) << m_errParseInvalid; - ASSERT_EQ(v1.m_parts[1], 2) << m_errParseInvalid; - ASSERT_EQ(v1.m_parts[2], 3) << m_errParseInvalid; - ASSERT_EQ(v1.m_parts[3], 4) << m_errParseInvalid; -} - -TEST_F(VersionTest, ParseFromString_EmptyString_ReturnFailureOutcome) -{ - ASSERT_FALSE(GemVersion::ParseFromString("").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(EngineVersion::ParseFromString("").IsSuccess()) << m_errParseInvalidSucceeded; -} - -TEST_F(VersionTest, ParseFromString_InvalidPartSize_ReturnFailureOutcome) -{ - ASSERT_FALSE(GemVersion::ParseFromString("1.2").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(GemVersion::ParseFromString("1.2.3.4").IsSuccess()) << m_errParseInvalidSucceeded; - - ASSERT_FALSE(EngineVersion::ParseFromString("1.4.2.1.1").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(EngineVersion::ParseFromString("1.2.3").IsSuccess()) << m_errParseInvalidSucceeded; -} - -TEST_F(VersionTest, ParseFromString_InvalidCharactersString_ReturnFailureOutcome) -{ - ASSERT_FALSE(GemVersion::ParseFromString("NotAVersion").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(GemVersion::ParseFromString("NotAVersion.2.3").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(GemVersion::ParseFromString("1.NotAVersion.3").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(GemVersion::ParseFromString("1.2.NotAVersion").IsSuccess()) << m_errParseInvalidSucceeded; - - ASSERT_FALSE(EngineVersion::ParseFromString("NotBVersion").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(EngineVersion::ParseFromString("NotBVersion.2.3").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(EngineVersion::ParseFromString("1.NotBVersion.3").IsSuccess()) << m_errParseInvalidSucceeded; - ASSERT_FALSE(EngineVersion::ParseFromString("1.2.NotBVersion").IsSuccess()) << m_errParseInvalidSucceeded; -} - -TEST_F(VersionTest, ParseFromString_InvalidSeparator_ReturnFailureOutcome) -{ - ASSERT_FALSE(GemVersion::ParseFromString("1,2,3").IsSuccess()) << m_errParseInvalidSucceeded; - - ASSERT_FALSE(EngineVersion::ParseFromString("1,2,3,4").IsSuccess()) << m_errParseInvalidSucceeded; -} - -TEST_F(VersionTest, Compare_DifferentMajor_ReturnLesserThanZero) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 2, 0, 0 }; - - ASSERT_LT(GemVersion::Compare(v1, v2), 0) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 2, 0, 0, 0 }; - - ASSERT_LT(EngineVersion::Compare(v3, v4), 0) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, Compare_DifferentMinor_ReturnLesserThanZero) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 1, 1, 0 }; - - ASSERT_LT(GemVersion::Compare(v1, v2), 0) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 1, 1, 0, 0 }; - - ASSERT_LT(EngineVersion::Compare(v3, v4), 0) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, Compare_DifferentMajorAndMinor_ReturnGreaterThanZero) -{ - GemVersion v1 = { 2, 0, 0 }; - GemVersion v2 = { 1, 1, 0 }; - - ASSERT_GT(GemVersion::Compare(v1, v2), 0) << m_errCompareIncorrect; - - EngineVersion v3 = { 2, 0, 0, 0 }; - EngineVersion v4 = { 1, 1, 0, 0 }; - - ASSERT_GT(EngineVersion::Compare(v3, v4), 0) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, Compare_SameValue_ReturnZero) -{ - GemVersion v1 = { 1, 1, 0 }; - GemVersion v2 = { 1, 1, 0 }; - - ASSERT_EQ(GemVersion::Compare(v1, v2), 0) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 1, 0, 0 }; - EngineVersion v4 = { 1, 1, 0, 0 }; - - ASSERT_EQ(EngineVersion::Compare(v3, v4), 0) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareLesserThan_DifferentMajor_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 2, 0, 0 }; - - ASSERT_TRUE(v1 < v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 2, 0, 0, 0 }; - - ASSERT_TRUE(v3 < v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareLesserThan_SameMajor_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 1, 1, 0 }; - - ASSERT_TRUE(v1 < v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 1, 1, 0, 0 }; - - ASSERT_TRUE(v3 < v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareLesserEqualsTo_DifferentMajor_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 2, 0, 0 }; - - ASSERT_TRUE(v1 <= v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 2, 0, 0, 0 }; - - ASSERT_TRUE(v3 <= v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareLesserEqualsTo_SameMajorSmallerMinor_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 1, 1, 0 }; - - ASSERT_TRUE(v1 <= v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 1, 1, 0, 0 }; - - ASSERT_TRUE(v3 <= v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareLesserEqualsTo_Samevalues_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 1, 0, 0 }; - - ASSERT_TRUE(v1 <= v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 1, 0, 0, 0 }; - - ASSERT_TRUE(v3 <= v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareGreaterThan_DifferentMajor_ReturnTrue) -{ - GemVersion v1 = { 2, 0, 0 }; - GemVersion v2 = { 1, 0, 0 }; - - ASSERT_TRUE(v1 > v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 2, 0, 0, 0 }; - EngineVersion v4 = { 1, 0, 0, 0 }; - - ASSERT_TRUE(v3 > v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareGreaterThan_SameMajor_ReturnTrue) -{ - GemVersion v1 = { 1, 1, 0 }; - GemVersion v2 = { 1, 0, 0 }; - - ASSERT_TRUE(v1 > v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 1, 0, 0 }; - EngineVersion v4 = { 1, 0, 0, 0 }; - - ASSERT_TRUE(v3 > v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareGreaterEqualsTo_DifferentMajor_ReturnTrue) -{ - GemVersion v1 = { 2, 0, 0 }; - GemVersion v2 = { 1, 0, 0 }; - - ASSERT_TRUE(v1 >= v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 2, 0, 0, 0 }; - EngineVersion v4 = { 1, 0, 0, 0 }; - - ASSERT_TRUE(v3 >= v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareGreaterEqualsTo_SameMajorSmallerMinor_ReturnTrue) -{ - GemVersion v1 = { 1, 1, 0 }; - GemVersion v2 = { 1, 0, 0 }; - - ASSERT_TRUE(v1 >= v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 1, 0, 0 }; - EngineVersion v4 = { 1, 0, 0, 0 }; - - ASSERT_TRUE(v3 >= v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareGreaterEqualsTo_Samevalues_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 1, 0, 0 }; - - ASSERT_TRUE(v1 >= v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 1, 0, 0, 0 }; - - ASSERT_TRUE(v3 >= v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareEqualsTo_SameValue_ReturnTrue) -{ - GemVersion v1 = { 1, 1, 0 }; - GemVersion v2 = { 1, 1, 0 }; - - ASSERT_TRUE(v1 == v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 1, 0, 0 }; - EngineVersion v4 = { 1, 1, 0, 0 }; - - ASSERT_TRUE(v3 == v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareEqualsTo_DifferentValue_ReturnFalse) -{ - GemVersion v1 = { 1, 1, 0 }; - GemVersion v2 = { 0, 1, 0 }; - - ASSERT_FALSE(v1 == v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 1, 0, 0 }; - EngineVersion v4 = { 0, 1, 0, 0 }; - - ASSERT_FALSE(v3 == v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareNotEqualsTo_DifferentValues_ReturnTrue) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 2, 0, 0 }; - - ASSERT_TRUE(v1 != v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 1, 0, 0, 0 }; - EngineVersion v4 = { 2, 0, 0, 0 }; - - ASSERT_TRUE(v3 != v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, CompareNotEqualsTo_SameValues_ReturnFalse) -{ - GemVersion v1 = { 2, 0, 1 }; - GemVersion v2 = { 2, 0, 1 }; - - ASSERT_FALSE(v1 != v2) << m_errCompareIncorrect; - - EngineVersion v3 = { 2, 0, 1, 0 }; - EngineVersion v4 = { 2, 0, 1, 0 }; - - ASSERT_FALSE(v3 != v4) << m_errCompareIncorrect; -} - -TEST_F(VersionTest, ToString_VariousValues_ReturnsCorrectStringOutput) -{ - GemVersion v1 = { 1, 0, 0 }; - GemVersion v2 = { 2, 0, 0 }; - GemVersion v3 = { 1, 1, 0 }; - GemVersion v4 = { 1, 1, 0 }; - - ASSERT_STREQ(v1.ToString().c_str(), "1.0.0") << m_errToStringIncorrect; - ASSERT_STREQ(v2.ToString().c_str(), "2.0.0") << m_errToStringIncorrect; - ASSERT_STREQ(v3.ToString().c_str(), "1.1.0") << m_errToStringIncorrect; - ASSERT_STREQ(v4.ToString().c_str(), "1.1.0") << m_errToStringIncorrect; - - - EngineVersion v5 = { 1, 0, 0, 0 }; - EngineVersion v6 = { 2, 0, 0, 0 }; - EngineVersion v7 = { 1, 1, 0, 0 }; - EngineVersion v8 = { 1, 1, 0, 0 }; - - ASSERT_STREQ(v5.ToString().c_str(), "1.0.0.0") << m_errToStringIncorrect; - ASSERT_STREQ(v6.ToString().c_str(), "2.0.0.0") << m_errToStringIncorrect; - ASSERT_STREQ(v7.ToString().c_str(), "1.1.0.0") << m_errToStringIncorrect; - ASSERT_STREQ(v8.ToString().c_str(), "1.1.0.0") << m_errToStringIncorrect; -} - -TEST_F(VersionTest, ToString_ToStringFromParseStringValue_ReturnSameStringFromInput) -{ - const char* version0String = "1.2.3"; - - auto version0Outcome = GemVersion::ParseFromString(version0String); - GemVersion v0 = version0Outcome.GetValue(); - - ASSERT_TRUE(version0Outcome.IsSuccess()) << m_errParseFailed; - ASSERT_STREQ(v0.ToString().c_str(), version0String) << m_errToStringIncorrect; - - - const char* version1String = "1.2.3.4"; - - auto version1Outcome = EngineVersion::ParseFromString(version1String); - EngineVersion v1 = version1Outcome.GetValue(); - - ASSERT_TRUE(version1Outcome.IsSuccess()) << m_errParseFailed; - ASSERT_STREQ(v1.ToString().c_str(), version1String) << m_errToStringIncorrect; -} - -TEST_F(VersionTest, Hasher_DifferentValues_GetBackSameValue) -{ - { - AZStd::unordered_map unorderedMap; - GemVersion v1 = { 1, 0, 0 }; - int v1value = 1; - GemVersion v2 = { 2, 0, 0 }; - int v2value = 2; - GemVersion v3 = { 1, 1, 0 }; - int v3value = 3; - GemVersion v4 = { 1, 1, 1 }; - int v4value = 4; - - unorderedMap[v1] = v1value; - unorderedMap[v2] = v2value; - unorderedMap[v3] = v3value; - unorderedMap[v4] = v4value; - - ASSERT_EQ(unorderedMap[v1], v1value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap[v2], v2value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap[v3], v3value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap[v4], v4value) << m_errHasherIncorrect; - } - - { - AZStd::unordered_map unorderedMap; - EngineVersion v1 = { 1, 0, 0, 0 }; - int v1value = 1; - EngineVersion v2 = { 2, 0, 0, 0 }; - int v2value = 2; - EngineVersion v3 = { 1, 1, 0, 0 }; - int v3value = 3; - EngineVersion v4 = { 1, 1, 1, 0 }; - int v4value = 4; - - unorderedMap[v1] = v1value; - unorderedMap[v2] = v2value; - unorderedMap[v3] = v3value; - unorderedMap[v4] = v4value; - - ASSERT_EQ(unorderedMap[v1], v1value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap[v2], v2value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap[v3], v3value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap[v4], v4value) << m_errHasherIncorrect; - } -} - -TEST_F(VersionTest, Hasher_SameValues_GetBackSameValue) -{ - { - AZStd::unordered_map unorderedMap; - GemVersion v1 = { 1, 1, 1 }; - GemVersion v2 = { 1, 1, 1 }; - int v12value = 1; - - unorderedMap[v1] = v12value; - - ASSERT_EQ(unorderedMap.at(v1), v12value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap.at(v2), v12value) << m_errHasherIncorrect; - } - - { - AZStd::unordered_map unorderedMap; - EngineVersion v1 = { 1, 1, 1, 0 }; - EngineVersion v2 = { 1, 1, 1, 0 }; - int v12value = 1; - - unorderedMap[v1] = v12value; - - ASSERT_EQ(unorderedMap.at(v1), v12value) << m_errHasherIncorrect; - ASSERT_EQ(unorderedMap.at(v2), v12value) << m_errHasherIncorrect; - } -} \ No newline at end of file diff --git a/Code/Tools/GemRegistry/tests/main.cpp b/Code/Tools/GemRegistry/tests/main.cpp deleted file mode 100644 index 13419f923f..0000000000 --- a/Code/Tools/GemRegistry/tests/main.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -* 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. -* -*/ -#include -#include -#include -#include - -class GemRegistryTestEnvironment - : public AZ::Test::ITestEnvironment -{ -public: - virtual ~GemRegistryTestEnvironment() - {} - -protected: - void SetupEnvironment() override - { - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - } - - void TeardownEnvironment() override - { - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - } -}; - -AZ_UNIT_TEST_HOOK(new GemRegistryTestEnvironment); diff --git a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp b/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp index 19512103b3..e505b52256 100644 --- a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp +++ b/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp @@ -11,6 +11,7 @@ */ #include +#include #include "NewsBuilder.h" #include "Qt/ArticleDetails.h" #include "Qt/BuilderArticleViewContainer.h" @@ -39,8 +40,7 @@ AZ_POP_DISABLE_WARNING namespace News { - - NewsBuilder::NewsBuilder(QWidget* parent) + NewsBuilder::NewsBuilder(QWidget* parent, const AZ::IO::PathView& engineRootPath) : QMainWindow(parent) , m_ui(new Ui::NewsBuilderClass()) , m_manifest(new BuilderResourceManifest( @@ -51,15 +51,16 @@ namespace News , m_articleViewContainer(new BuilderArticleViewContainer(this, *m_manifest)) , m_logContainer(new LogContainer(this)) { + AzQtComponents::StyleManager* m_styleSheet = new AzQtComponents::StyleManager(this); - m_styleSheet->initialize(qApp); + m_styleSheet->initialize(qApp, engineRootPath); m_ui->setupUi(this); - QDir rootDir(AzQtComponents::FindEngineRootDir(qApp)); + QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size())); const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/News/NewsBuilder/Resources"); const auto qrcPath = QStringLiteral(":/NewsBuilder"); - AzQtComponents::StyleManager::addSearchPaths("newsbuilder", pathOnDisk, qrcPath); + AzQtComponents::StyleManager::addSearchPaths("newsbuilder", pathOnDisk, qrcPath, engineRootPath); AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("newsbuilder:NewsBuilder.qss")); diff --git a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h b/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h index f36b187927..2bfa87c506 100644 --- a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h +++ b/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h @@ -17,6 +17,8 @@ #include "NewsShared/LogType.h" #include "NewsShared/ErrorCodes.h" + +#include #endif class QSignalMapper; @@ -41,7 +43,7 @@ namespace News Q_OBJECT public: - explicit NewsBuilder(QWidget* parent = nullptr); + explicit NewsBuilder(QWidget* parent, const AZ::IO::PathView& engineRootPath); ~NewsBuilder(); private: diff --git a/Code/Tools/News/NewsBuilder/main.cpp b/Code/Tools/News/NewsBuilder/main.cpp index 52e11dec6b..e3338b4aa7 100644 --- a/Code/Tools/News/NewsBuilder/main.cpp +++ b/Code/Tools/News/NewsBuilder/main.cpp @@ -15,19 +15,26 @@ #include "Qt/NewsBuilder.h" #include +#include +#include +#include int main(int argc, char *argv[]) { - // Must be set before QApplication is initialized, so that we support HighDpi monitors, like the Retina displays // on Windows 10 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QApplication a(argc, argv); - - News::NewsBuilder w; + AZ::IO::FixedMaxPath engineRootPath; + { + AZ::ComponentApplication componentApplication; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + News::NewsBuilder w(nullptr, engineRootPath); w.show(); return a.exec(); } diff --git a/Code/Tools/ProfVis/ProfVis.sln b/Code/Tools/ProfVis/ProfVis.sln deleted file mode 100644 index 7408ca3eff..0000000000 --- a/Code/Tools/ProfVis/ProfVis.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProfVis", "ProfVis\ProfVis.csproj", "{3AF4C1C6-4DF2-4F3E-9997-B2844D461DF8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3AF4C1C6-4DF2-4F3E-9997-B2844D461DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3AF4C1C6-4DF2-4F3E-9997-B2844D461DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3AF4C1C6-4DF2-4F3E-9997-B2844D461DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3AF4C1C6-4DF2-4F3E-9997-B2844D461DF8}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Code/Tools/ProfVis/ProfVis/App.config b/Code/Tools/ProfVis/ProfVis/App.config deleted file mode 100644 index 8e15646352..0000000000 --- a/Code/Tools/ProfVis/ProfVis/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Form1.Designer.cs b/Code/Tools/ProfVis/ProfVis/Form1.Designer.cs deleted file mode 100644 index f10f196695..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Form1.Designer.cs +++ /dev/null @@ -1,162 +0,0 @@ -/* -* 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. -* -*/ - -namespace ProfVis -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.menuStrip1 = new System.Windows.Forms.MenuStrip(); - this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.reloadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.progressBar1 = new System.Windows.Forms.ProgressBar(); - this.searchTextBox = new System.Windows.Forms.TextBox(); - this.dataGridView_Prof = new ProfVis.DGW(); - this.menuStrip1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridView_Prof)).BeginInit(); - this.SuspendLayout(); - // - // menuStrip1 - // - this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.fileToolStripMenuItem, - this.reloadToolStripMenuItem}); - this.menuStrip1.Location = new System.Drawing.Point(0, 0); - this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Size = new System.Drawing.Size(869, 24); - this.menuStrip1.TabIndex = 6; - this.menuStrip1.Text = "menuStrip1"; - // - // fileToolStripMenuItem - // - this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.openToolStripMenuItem}); - this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); - this.fileToolStripMenuItem.Text = "File"; - // - // openToolStripMenuItem - // - this.openToolStripMenuItem.Name = "openToolStripMenuItem"; - this.openToolStripMenuItem.Size = new System.Drawing.Size(112, 22); - this.openToolStripMenuItem.Text = "&Open..."; - this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); - // - // reloadToolStripMenuItem - // - this.reloadToolStripMenuItem.Name = "reloadToolStripMenuItem"; - this.reloadToolStripMenuItem.Size = new System.Drawing.Size(55, 20); - this.reloadToolStripMenuItem.Text = "Reload"; - this.reloadToolStripMenuItem.Click += new System.EventHandler(this.reloadToolStripMenuItem_Click); - // - // progressBar1 - // - this.progressBar1.Dock = System.Windows.Forms.DockStyle.Top; - this.progressBar1.Location = new System.Drawing.Point(0, 24); - this.progressBar1.MarqueeAnimationSpeed = 5; - this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(869, 23); - this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; - this.progressBar1.TabIndex = 7; - this.progressBar1.Visible = false; - // - // searchTextBox - // - this.searchTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.searchTextBox.Location = new System.Drawing.Point(646, 2); - this.searchTextBox.Name = "searchTextBox"; - this.searchTextBox.Size = new System.Drawing.Size(221, 20); - this.searchTextBox.TabIndex = 8; - this.searchTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.searchTextBox_KeyUp); - // - // dataGridView_Prof - // - this.dataGridView_Prof.AllowUserToAddRows = false; - this.dataGridView_Prof.AllowUserToDeleteRows = false; - this.dataGridView_Prof.AllowUserToResizeColumns = false; - this.dataGridView_Prof.AllowUserToResizeRows = false; - this.dataGridView_Prof.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.dataGridView_Prof.Location = new System.Drawing.Point(37, 29); - this.dataGridView_Prof.Name = "dataGridView_Prof"; - this.dataGridView_Prof.ReadOnly = true; - this.dataGridView_Prof.RowTemplate.ReadOnly = true; - this.dataGridView_Prof.ShowCellToolTips = false; - this.dataGridView_Prof.Size = new System.Drawing.Size(408, 351); - this.dataGridView_Prof.TabIndex = 5; - this.dataGridView_Prof.CellPainting += new System.Windows.Forms.DataGridViewCellPaintingEventHandler(this.dataGridView_Prof_CellPainting); - this.dataGridView_Prof.MouseMove += new System.Windows.Forms.MouseEventHandler(this.dataGridView_Prof_MouseMove); - // - // Form1 - // - this.AllowDrop = true; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(869, 548); - this.Controls.Add(this.searchTextBox); - this.Controls.Add(this.progressBar1); - this.Controls.Add(this.dataGridView_Prof); - this.Controls.Add(this.menuStrip1); - this.MainMenuStrip = this.menuStrip1; - this.Name = "Form1"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.WindowState = System.Windows.Forms.FormWindowState.Maximized; - this.Load += new System.EventHandler(this.Form1_Load); - this.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form1_DragDrop); - this.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form1_DragEnter); - this.menuStrip1.ResumeLayout(false); - this.menuStrip1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridView_Prof)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.MenuStrip menuStrip1; - private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem reloadToolStripMenuItem; - public DGW dataGridView_Prof; - private System.Windows.Forms.ProgressBar progressBar1; - private System.Windows.Forms.TextBox searchTextBox; - - - } -} - diff --git a/Code/Tools/ProfVis/ProfVis/Form1.cs b/Code/Tools/ProfVis/ProfVis/Form1.cs deleted file mode 100644 index d7550a8013..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Form1.cs +++ /dev/null @@ -1,891 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using System.Xml; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; - - -namespace ProfVis -{ - public partial class Form1 : Form - { - public Form1(string[] args) - { - InitializeComponent(); - - Show(); - - if (args.Length >= 1) - { - OpenSession(args[0]); - } - } - - public static Color[] s_clrBack = { Color.FromArgb(235, 235, 235), Color.White }; - public static Color[] s_clrBars = { Color.FromArgb(140, 198, 63), - Color.FromArgb(247, 148, 30), - Color.FromArgb(37, 170, 225), - Color.FromArgb(122, 45, 24), - Color.FromArgb(239, 62, 54), - }; - - - private ToolTip m_tooltip; //TODO: kill this and use some custom panel to prevent flickering - public List m_BarsBrushes; - public Font m_barFont; - - private static Random m_random; - - // session - private string m_sessionName; - public List m_threadsData; - - public static string m_filter = ""; - - private BackgroundWorker m_loadingWorker; - - private void Form1_Load(object sender, EventArgs e) - { - //DoubleBuffered = true; - - dataGridView_Prof.Dock = DockStyle.Fill; - - dataGridView_Prof.AutoGenerateColumns = false; - dataGridView_Prof.ColumnCount = 2; - //AdjustDataGridViewSizing(); - dataGridView_Prof.Columns[0].Name = "Thread"; - dataGridView_Prof.Columns[1].Name = "Blocks"; - - dataGridView_Prof.Columns[0].Frozen = true; - - dataGridView_Prof.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells; - dataGridView_Prof.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - //dataGridView_Prof.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.None; - //dataGridView_Prof.Columns[1].Width = 500; - - dataGridView_Prof.Columns[0].SortMode = DataGridViewColumnSortMode.NotSortable; - dataGridView_Prof.Columns[1].SortMode = DataGridViewColumnSortMode.NotSortable; - - dataGridView_Prof.ShowCellToolTips = false; - - dataGridView_Prof.MouseWheel += new MouseEventHandler(dataGridView_Prof_MouseWheel); - dataGridView_Prof.MouseClick += new MouseEventHandler(dataGridView_Prof_MouseClick); - - //dataGridView_Prof.AllowUserToResizeRows = true; - - - m_barFont = (Font)dataGridView_Prof.DefaultCellStyle.Font.Clone(); - - - m_tooltip = new ToolTip(); - m_tooltip.ShowAlways = false; - m_tooltip.UseAnimation = false; - m_tooltip.UseFading = false; - m_tooltip.AutomaticDelay = 0; - m_tooltip.AutoPopDelay = 0; - - m_BarsBrushes = new List(); - for(int i = 0; i < Form1.s_clrBars.Length; ++i) - { - m_BarsBrushes.Add(new SolidBrush(s_clrBars[i])); - } - - m_loadingWorker = new BackgroundWorker(); - m_loadingWorker.WorkerReportsProgress = true; - m_loadingWorker.ProgressChanged += (object progressSender, ProgressChangedEventArgs progressArgs) => - { - DataGridViewRow row = progressArgs.UserState as DataGridViewRow; - if (row != null) - dataGridView_Prof.Rows.Add(row); - }; - - m_loadingWorker.RunWorkerCompleted += (object progressSender, RunWorkerCompletedEventArgs progressArgs) => - { - progressBar1.Visible = false; - progressBar1.Enabled = false; - menuStrip1.Enabled = true; - this.Text = m_sessionName; - }; - - m_loadingWorker.DoWork += (object progressSender, DoWorkEventArgs doWorkArgs) => - { - Graphics g = this.CreateGraphics(); - try - { - m_hoveredData = null; - if (m_threadsData != null) - m_threadsData.Clear(); - - string filename = doWorkArgs.Argument as string; - - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.Load(filename); - - m_sessionName = filename; - - m_threadsData = new List(); - XmlNode rootNode = xmlDoc.SelectSingleNode("root"); - int threadIndex = 0; - int num_childs = rootNode.ChildNodes.Count; - foreach (XmlNode threadNode in rootNode) - { - string threadName = threadNode.Attributes.GetNamedItem("name").Value; - float threadTimeMS = Single.Parse(threadNode.Attributes.GetNamedItem("totalTimeMS").Value, System.Globalization.CultureInfo.InvariantCulture); - long threadStart = Convert.ToInt64(threadNode.Attributes.GetNamedItem("startTime").Value); - long threadEnd = Convert.ToInt64(threadNode.Attributes.GetNamedItem("stopTime").Value); - long threadTime = threadEnd - threadStart; - - m_threadsData.Add(new CThreadTag()); - - CThreadTag threadData = m_threadsData[threadIndex]; - threadData.m_Times = new CBlockData(threadName, threadTimeMS, threadStart, threadEnd, 0, ""); - - DataGridViewRow row = new DataGridViewRow(); - DataGridViewCell cell0 = new DataGridViewTextBoxCell(); - cell0.Value = threadName; - row.Cells.Add(cell0); - row.Tag = threadData; - m_loadingWorker.ReportProgress(0, row); - - getBlocksFromXML(threadNode, 0, threadIndex); - threadIndex++; - - // create rows - for (int i = 0; i < threadData.m_StackEnties.Count; ++i) - { - CBlockTag rowInfo = threadData.m_StackEnties[i]; - - // used for DrawFrectangles() - for (int j = 0; j < rowInfo.blocks.Count; ++j) - { - CBlockData data = rowInfo.blocks[j]; - //rowInfo.blocksByColor[data.colorIdx].Add(data); - data.m_labelSize = g.MeasureString(data.name, m_barFont); - } - - DataGridViewRow stackedRow = new DataGridViewRow(); - DataGridViewCell stackedCell = new DataGridViewTextBoxCell(); - stackedCell.Value = i; - stackedRow.Cells.Add(stackedCell); - stackedRow.Tag = rowInfo; - m_loadingWorker.ReportProgress(0, stackedRow); - } - }// foreach (XmlNode threadNode in rootNode) - } - catch (System.Exception ex) - { - m_sessionName = string.Empty; - MessageBox.Show(ex.Message); - } - g.Dispose(); - }; - } - - private void OpenSession(string filename) - { - if (m_loadingWorker.IsBusy) - return; - - // 0 seed for same colors - m_random = new Random(0); - - dataGridView_Prof.Rows.Clear(); - - - DataGridViewRow timeRow = new DataGridViewRow(); - DataGridViewCell textCell = new DataGridViewTextBoxCell(); - textCell.Value = "Time"; - timeRow.Cells.Add(textCell); - timeRow.Height = 40; - timeRow.Tag = new CTimeTag(); - timeRow.Frozen = true; - dataGridView_Prof.Rows.Add(timeRow); - - progressBar1.Value = 0; - progressBar1.Visible = true; - progressBar1.Enabled = true; - menuStrip1.Enabled = false; - - m_loadingWorker.RunWorkerAsync(filename); - } - private void getBlocksFromXML(XmlNode node, int depth, int threadIndex) - { - //if (depth == 3) - // return; - - if (node.SelectSingleNode("block")!=null) - { - CThreadTag threadData = m_threadsData[threadIndex]; - if (depth >= threadData.m_StackEnties.Count) - { - threadData.m_StackEnties.Add(new CBlockTag()); //new stack level - threadData.m_StackEnties[depth].threadIndex = threadIndex; - } - - int prevClrIndex = 0; - foreach (XmlNode blockNode in node) - { - string name = blockNode.Attributes.GetNamedItem("name").Value; - float totalTimeMS = Single.Parse(blockNode.Attributes.GetNamedItem("totalTimeMS").Value, System.Globalization.CultureInfo.InvariantCulture); - long startTime = Convert.ToInt64(blockNode.Attributes.GetNamedItem("startTime").Value); - long stopTime = Convert.ToInt64(blockNode.Attributes.GetNamedItem("stopTime").Value); - XmlNode argsNode = blockNode.Attributes.GetNamedItem("args"); - string args = ""; - if(argsNode != null) - args = argsNode.Value; - - int clrIndex = m_random.Next(0, s_clrBars.Length); - if (clrIndex == prevClrIndex) - { - clrIndex++; - if (clrIndex == s_clrBars.Length) - clrIndex = 0; - } - - threadData.m_StackEnties[depth].blocks.Add(new CBlockData(name, totalTimeMS, startTime, stopTime, clrIndex, args)); - prevClrIndex = clrIndex; - - getBlocksFromXML(blockNode, depth+1, threadIndex); - } - } - } - - private void dataGridView_Prof_MouseWheel(object sender, MouseEventArgs e) - { - if (ModifierKeys == Keys.Control) - { - if (!dataGridView_Prof.IsOffsetSet()) - { - return; - } - - int oldOffset = dataGridView_Prof.HorizontalScrollingOffset; - - dataGridView_Prof.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.None; - double zoomFactor = Math.Pow(2, (double)e.Delta * 0.001); - int newWidth = (int)(dataGridView_Prof.Columns[1].Width * zoomFactor); - - bool clampWidth = newWidth < 0 || newWidth >= 65535; - newWidth = newWidth < 65535 ? newWidth : 65535; - newWidth = newWidth >= 0 ? newWidth : 0; - - dataGridView_Prof.Columns[1].Width = newWidth; - - int visibleColumn1Width = dataGridView_Prof.Width - dataGridView_Prof.Columns[0].Width; - int mouseColumn1Offset = e.X - dataGridView_Prof.Columns[0].Width; - double mousePrecentage = (double)mouseColumn1Offset / (double)visibleColumn1Width; - - int newOffset = clampWidth ? oldOffset : ((int)((double)oldOffset * zoomFactor) + (int)(visibleColumn1Width * mousePrecentage * (double)e.Delta * 0.001)); - newOffset = newOffset >= 0 ? newOffset : 0; - dataGridView_Prof.SetOffset(newOffset); - } - } - - private void dataGridView_Prof_MouseClick(object sender, MouseEventArgs e) - { - if (ModifierKeys == Keys.Control) - { - dataGridView_Prof.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } - - if (e.Button == MouseButtons.Right) - { - if (m_hoveredData != null) - { - ContextMenu m = new ContextMenu(); - MenuItem copyName = new MenuItem("Copy name"); - copyName.Click += new System.EventHandler( - delegate(object o, EventArgs click_args) - { - Clipboard.SetText(m_hoveredData.name); - } - ); - m.MenuItems.Add(copyName); - MenuItem copyArgs = new MenuItem("Copy arguments"); - copyArgs.Click += new System.EventHandler( - delegate(object o, EventArgs click_args) - { - Clipboard.SetText(m_hoveredData.args); - } - ); - m.MenuItems.Add(copyArgs); - m.Show(dataGridView_Prof, e.Location); - } - } - } - - private void dataGridView_Prof_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) - { - if (e.RowIndex < 0 || e.ColumnIndex < 0) - return; - - if (e.ColumnIndex != 1) - return; - - - object tag = dataGridView_Prof.Rows[e.RowIndex].Tag; - if (tag != null) - { - IRowTag rowTag = tag as IRowTag; - if (rowTag != null) - rowTag.Draw(ref e, this); - } - else - { - //DRAW timeline - } - } - - private int binarySearch(List list, int value) - { - int min = 0; - int max = list.Count - 1; - - while(min <= max) - { - int mid = min + (max - min)/2; - - if (value >= list[mid].drawXStart) - { - if (value <= list[mid].drawXEnd) - return mid; - else - min = mid + 1; - } - else - max = mid - 1; - } - return -1; - } - - private Point m_PrevMousePos; - private CBlockData m_hoveredData; - private void dataGridView_Prof_MouseMove(object sender, MouseEventArgs e) - { - if (m_loadingWorker.IsBusy) - return; - if (m_PrevMousePos != e.Location) - { - m_PrevMousePos = e.Location; - - DataGridView.HitTestInfo hittest = dataGridView_Prof.HitTest(e.Location.X, e.Location.Y); - - m_tooltip.RemoveAll(); - if (hittest.ColumnIndex == 1 && hittest.RowIndex >= 0 && hittest.RowIndex < dataGridView_Prof.RowCount) - { - object tag = dataGridView_Prof.Rows[hittest.RowIndex].Tag; - if (tag != null) - { - CBlockTag info = tag as CBlockTag; - if (info != null) - { - List filteredBlocks = info.blocks.Where(x => x.visible).ToList(); - int idx = binarySearch(filteredBlocks, e.Location.X); - if (idx != -1) - { - m_hoveredData = filteredBlocks[idx]; - m_tooltip.Hide(dataGridView_Prof); - - Rectangle columnRect = info.cellBounds; - - float threadMS = m_threadsData[0].m_Times.timeMS; - float mouseRel = ((e.X - columnRect.X) * 100.0f) / columnRect.Width; - float mouseRelMS = (mouseRel / 100.0f) * threadMS; - - string text; - - m_tooltip.ToolTipTitle = filteredBlocks[idx].name; - if (filteredBlocks[idx].args.Length > 0) - { - text = string.Format("totalTime = {0} ms\ncursorAbsolute = {1} ms ({2:##.##} %)\nargs = {3}", - filteredBlocks[idx].timeMS, mouseRelMS, mouseRel, filteredBlocks[idx].args); - } - else - { - text = string.Format("totalTime = {0} ms\ncursorAbsolute = {1} ms ({2:##.##} %)", - filteredBlocks[idx].timeMS, mouseRelMS, mouseRel); - } - - m_tooltip.Show(text, dataGridView_Prof, e.X + 20, e.Y + 20); - - } - else - { - m_hoveredData = null; - m_tooltip.Hide(dataGridView_Prof); - } - } - CThreadTag td = tag as CThreadTag; - if (td != null) - { - - m_tooltip.Hide(dataGridView_Prof); - m_tooltip.Show(string.Format("time = {0} ms", td.m_Times.timeMS), dataGridView_Prof, e.X + 20, e.Y + 20); - m_tooltip.ToolTipTitle = td.m_Times.name; - } - } - else - { - m_hoveredData = null; - m_tooltip.Hide(dataGridView_Prof); - } - } - else - { - m_hoveredData = null; - m_tooltip.Hide(dataGridView_Prof); - } - } - - // base.OnMouseMove(e); - } - - private void Form1_DragDrop(object sender, DragEventArgs e) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - - - if (files.Length == 1) - { - OpenSession(files[0]); - } - } - } - - private void Form1_DragEnter(object sender, DragEventArgs e) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - e.Effect = DragDropEffects.Move; - } - } - - private void openToolStripMenuItem_Click(object sender, EventArgs e) - { - OpenFileDialog myDialog = new OpenFileDialog(); - - myDialog.Filter = "All files (*.xml)|*.xml"; - myDialog.CheckFileExists = true; - myDialog.Multiselect = false; - - if (myDialog.ShowDialog() == DialogResult.OK) - { - OpenSession(myDialog.FileName); - } - } - - private void reloadToolStripMenuItem_Click(object sender, EventArgs e) - { - if (m_sessionName != null) - OpenSession(m_sessionName); - } - - private void searchTextBox_KeyUp(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Enter) - { - m_filter = searchTextBox.Text; - - for (int i = 0; i < m_threadsData.Count; ++i) - { - m_threadsData[i].UpdateFilter(); - } - - dataGridView_Prof.Refresh(); - } - } - } - - public class DGW : DataGridView - { - private bool reapplyOffset = false; - private int deferredOffset = 0; - - public DGW() - { - this.DoubleBuffered = true; - } - - protected override void OnPaintBackground(PaintEventArgs pevent) - { - if (reapplyOffset) - { - HorizontalScrollingOffset = deferredOffset; - reapplyOffset = false; - } - } - - protected override void OnPaint(PaintEventArgs e) - { - if (reapplyOffset) - { - HorizontalScrollingOffset = deferredOffset; - reapplyOffset = false; - Invalidate(true); - } - - base.OnPaint(e); - } - - public bool IsOffsetSet() - { - return !reapplyOffset; - } - - public void SetOffset(int offset) - { - if (reapplyOffset) - { - deferredOffset += offset; - return; - } - - reapplyOffset = true; - deferredOffset = offset; - } - } - - public class CBlockData - { - public string name; - public float timeMS; - public long timeStart; - public long timeEnd; - public long time; - - public string args; - - public int drawXStart; - public int drawXEnd; - public int colorIdx; - - public bool visible; - - public SizeF m_labelSize; - public CBlockData(string n, float t, long start, long end, int clrIdx, string a) - { - name = n; - timeMS = t; - timeStart = start; - timeEnd = end; - time = end - start; - - args = a; - - colorIdx = clrIdx; - - visible = true; - } - } - - public abstract class IRowTag - { - public abstract void Draw(ref DataGridViewCellPaintingEventArgs e, Form1 form); - } - - public class CBlockTag : IRowTag - { - public int threadIndex; - public List blocks; - public Rectangle cellBounds; - public CBlockTag() - { - blocks = new List(); - } - - public void UpdateFilter() - { - for (int i = 0; i < blocks.Count; i++) - { - CBlockData blockData = blocks[i]; - blockData.visible = Form1.m_filter == "" - || (blockData.name.ToLower().Contains(Form1.m_filter.ToLower()) - || blockData.args.ToLower().Contains(Form1.m_filter.ToLower())); - } - } - - public override void Draw(ref DataGridViewCellPaintingEventArgs e, Form1 form) - { - e.Handled = true; - Graphics g = e.Graphics; - cellBounds = e.CellBounds; - - const int offset = 2; - Rectangle cellBound = new Rectangle(e.CellBounds.X, e.CellBounds.Y + offset, - e.CellBounds.Width, e.CellBounds.Height - offset - 1); - - using (Brush backBrush = new SolidBrush(Form1.s_clrBack[e.RowIndex % 2])) - { - using (Pen borderPen = new Pen(Color.Black, 1)) - { - g.FillRectangle(backBrush, e.CellBounds); - g.DrawRectangle(borderPen, e.CellBounds); - - borderPen.Dispose(); - } - } - - CThreadTag threadData = form.m_threadsData[threadIndex]; - CBlockData threadTime = threadData.m_Times; - long ttime = threadTime.time; // 100% - - bool smallBlock = false; - int smallBlockPos = 0; - - for (int i = 0; i < blocks.Count; i++) - { - CBlockData blockData = blocks[i]; - if (!blockData.visible) - { - continue; - } - - long blockWidth = e.CellBounds.Width * blockData.time / ttime; - cellBound.Width = (int)blockWidth; - - long blockStart = (blockData.timeStart - threadTime.timeStart) * e.CellBounds.Width / ttime; - cellBound.X = e.CellBounds.X + (int)blockStart; - - blockData.drawXStart = cellBound.X; - blockData.drawXEnd = cellBound.X + cellBound.Width; - - if (smallBlock && smallBlockPos != cellBound.X) - { - Rectangle rec = new Rectangle(smallBlockPos, e.CellBounds.Y + offset, - 1, e.CellBounds.Height - offset - 1); - - g.FillRectangle(form.m_BarsBrushes[blocks[i - 1].colorIdx], rec); - - smallBlock = false; - } - - if (cellBound.Width < 1) - { - //cellBound.Width = 1; - - smallBlockPos = cellBound.X; - smallBlock = true; - continue; - } - - if ((cellBound.X < e.ClipBounds.X + e.ClipBounds.Width) && - (cellBound.X + cellBound.Width > e.ClipBounds.X)) - { - g.FillRectangle(form.m_BarsBrushes[blockData.colorIdx], cellBound); - - SizeF textSize = blockData.m_labelSize; - if (textSize.Width < cellBound.Width - 3) - { - StringFormat formatter = new StringFormat(); - formatter.LineAlignment = StringAlignment.Center; - formatter.Alignment = StringAlignment.Center; - float tx = cellBound.X + cellBound.Width / 2; - float ty = cellBound.Y + cellBound.Height / 2; - g.DrawString(blockData.name, form.m_barFont, Brushes.White, tx, ty, formatter); - } - } - } //for (int i = 0; i < info.blocks.Count; i++) - - if (smallBlock) - { - Rectangle rec = new Rectangle(smallBlockPos, e.CellBounds.Y + offset, - 1, e.CellBounds.Height - offset - 1); - - g.FillRectangle(form.m_BarsBrushes[blocks[blocks.Count - 1].colorIdx], rec); - } - } - - } - - public class CThreadTag : IRowTag - { - public CBlockData m_Times; - public List m_StackEnties; //each stack level have a list of blocks - public CThreadTag() - { - m_StackEnties = new List(); - } - - public void UpdateFilter() - { - for (int i = 0; i < m_StackEnties.Count; i++) - { - CBlockTag tag = m_StackEnties[i]; - tag.UpdateFilter(); - } - } - - public override void Draw(ref DataGridViewCellPaintingEventArgs e, Form1 form) - { - e.Handled = true; - Graphics g = e.Graphics; - - const int offset = 2; - Rectangle cellBound = new Rectangle(e.CellBounds.X, e.CellBounds.Y + offset, - e.CellBounds.Width, e.CellBounds.Height - offset - 1); - - string threadText = "Thread: " + m_Times.name; - g.FillRectangle(Brushes.DimGray, e.CellBounds); - Font font = new Font(e.CellStyle.Font, FontStyle.Bold); - - SizeF textSize = g.MeasureString(threadText, font); - if (textSize.Width < cellBound.Width - 3) - { - StringFormat formatter = new StringFormat(); - formatter.LineAlignment = StringAlignment.Center; - formatter.Alignment = StringAlignment.Center; - float tx = cellBound.X + cellBound.Width / 2; - float ty = cellBound.Y + cellBound.Height / 2; - g.DrawString(threadText, font, Brushes.White, tx, ty, formatter); - } - } - } - - public class CTimeTag : IRowTag - { - private void DrawLinesBetween(ref DataGridViewCellPaintingEventArgs e, Pen pen, Font font, int pos1, int pos2, float pos2MS, float blockMS, int markerHeight) - { - int blockThreshold = 200; // in pixels - //int blockDivCount = 5; - - int diff = pos2 - pos1; - - if (diff != 0 && diff > blockThreshold && markerHeight > 1) - { - - Graphics g = e.Graphics; - - int X = e.CellBounds.X; - int Y = e.CellBounds.Y + e.CellBounds.Height - 1; - - int linePos = pos1 + (pos2 - pos1)/2; - int DrawPos = X + linePos; - - - float pos1MS = pos2MS - blockMS; - float lineMS = pos1MS + (pos2MS - pos1MS) / 2.0f; - - - //if (DrawPos > e.ClipBounds.X && DrawPos < e.ClipBounds.X + e.ClipBounds.Width) //artifacts ;( - { - g.DrawLine(pen, DrawPos, Y - markerHeight, DrawPos, Y); - - - string s = string.Format("{0:##.##}", (lineMS)); - - StringFormat formatter = new StringFormat(); - formatter.LineAlignment = StringAlignment.Center; - formatter.Alignment = StringAlignment.Center; - g.DrawString(s, font, Brushes.Black, DrawPos, Y - markerHeight - 5, formatter); - - blockMS = pos2MS - lineMS; - DrawLinesBetween(ref e, pen, font, pos1, linePos, lineMS, blockMS, markerHeight - 2); - DrawLinesBetween(ref e, pen, font, linePos, pos2, pos2MS, blockMS, markerHeight - 2); - } - } - } - - public override void Draw(ref DataGridViewCellPaintingEventArgs e, Form1 form) - { - e.Handled = true; - Graphics g = e.Graphics; - - g.FillRectangle(Brushes.White, e.CellBounds); - - if (form.m_threadsData != null && form.m_threadsData.Count > 0) - { - Int32 cellWidth = e.CellBounds.Width; - Int32 lineYpos = e.CellBounds.Y + e.CellBounds.Height - 1; - - using (Pen btPen = new Pen(Color.Black, 2)) - { - // bottom line - g.DrawLine(btPen, - e.CellBounds.X, lineYpos, - e.CellBounds.X + cellWidth, lineYpos); - - btPen.Dispose(); - } - - - //form.dataGridView_Prof.PointToScreen() - g.DrawString("Milliseconds", form.m_barFont, Brushes.Black, e.CellBounds.X + 1 , e.CellBounds.Y + 1); - Pen pen = new Pen(Color.Black, 1); - - CThreadTag threadData = form.m_threadsData[0]; - CBlockData threadTime = threadData.m_Times; - float totalTimeMS = threadTime.timeMS; - //long totalTime = threadTime.time; - - int marketHeight = 16; - - int[] blocks = {10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1}; - - float timeMSperBlock = 0.0f; - int blockInx = 0; - while (timeMSperBlock < 10.0f || blockInx > blocks.Count()) - { - timeMSperBlock = totalTimeMS / blocks[blockInx++]; - } - if (blockInx != 0 ) - --blockInx; - - float blockMS = blocks[blockInx]; - - - - int linePx = 0; - int linePrevPx = 0; - int i = 0; - while (linePx < cellWidth) - { - float lineMS = i *blockMS; - ++i; - - linePrevPx = linePx; - linePx = Convert.ToInt32(Math.Round((float)(lineMS * cellWidth) / totalTimeMS)); - - DrawLinesBetween(ref e, pen, form.m_barFont, linePrevPx, linePx, lineMS, blockMS, marketHeight); - - int Xpos = e.CellBounds.X + linePx; - g.DrawLine(pen, Xpos, lineYpos - marketHeight, Xpos, lineYpos); - - string s = string.Format("{0}", Convert.ToInt32(lineMS)); - - StringFormat formatter = new StringFormat(); - formatter.LineAlignment = StringAlignment.Center; - formatter.Alignment = StringAlignment.Center; - float tx = Xpos; - float ty = lineYpos - marketHeight - 5; - - g.DrawString(s, form.m_barFont, Brushes.Black, tx, ty, formatter); - } - - pen.Dispose(); - } - } - } -} diff --git a/Code/Tools/ProfVis/ProfVis/Form1.resx b/Code/Tools/ProfVis/ProfVis/Form1.resx deleted file mode 100644 index d5494e3059..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Form1.resx +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/ProfVis.csproj b/Code/Tools/ProfVis/ProfVis/ProfVis.csproj deleted file mode 100644 index 802d28ceec..0000000000 --- a/Code/Tools/ProfVis/ProfVis/ProfVis.csproj +++ /dev/null @@ -1,129 +0,0 @@ - - - - - Debug - AnyCPU - {3AF4C1C6-4DF2-4F3E-9997-B2844D461DF8} - WinExe - Properties - ProfVis - ProfVis - v4.5 - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - Form - - - Form1.cs - - - - - Form1.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Program.cs b/Code/Tools/ProfVis/ProfVis/Program.cs deleted file mode 100644 index d96891f6d8..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Program.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace ProfVis -{ - static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main(string[] args) - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new Form1(args)); - } - } -} diff --git a/Code/Tools/ProfVis/ProfVis/Properties/AssemblyInfo.cs b/Code/Tools/ProfVis/ProfVis/Properties/AssemblyInfo.cs deleted file mode 100644 index 75bbb5c23d..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* -* 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. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ProfVis")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ProfVis")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c15ff8ac-4f15-4960-96a2-1cc11631169d")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/Form1.datasource b/Code/Tools/ProfVis/ProfVis/Properties/DataSources/Form1.datasource deleted file mode 100644 index 918f8373ac..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/Form1.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - ProfVis.Form1, ProfVis, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Resources.datasource b/Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Resources.datasource deleted file mode 100644 index 85f7e26e4e..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Resources.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - ProfVis.Properties.Resources, ProfVis, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Settings.datasource b/Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Settings.datasource deleted file mode 100644 index 57cc8f19cd..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/ProfVis.Properties.Settings.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - ProfVis.Properties.Settings, ProfVis, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/Program.datasource b/Code/Tools/ProfVis/ProfVis/Properties/DataSources/Program.datasource deleted file mode 100644 index 414f4fb85f..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/DataSources/Program.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - ProfVis.Program, ProfVis, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Properties/Resources.Designer.cs b/Code/Tools/ProfVis/ProfVis/Properties/Resources.Designer.cs deleted file mode 100644 index ccf37a2b9c..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/Resources.Designer.cs +++ /dev/null @@ -1,72 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.17929 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -// Modifications copyright Amazon.com, Inc. or its affiliates - -namespace ProfVis.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ProfVis.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Code/Tools/ProfVis/ProfVis/Properties/Resources.resx b/Code/Tools/ProfVis/ProfVis/Properties/Resources.resx deleted file mode 100644 index af7dbebbac..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Code/Tools/ProfVis/ProfVis/Properties/Settings.Designer.cs b/Code/Tools/ProfVis/ProfVis/Properties/Settings.Designer.cs deleted file mode 100644 index ba491e877b..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/Settings.Designer.cs +++ /dev/null @@ -1,31 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.17929 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -// Modifications copyright Amazon.com, Inc. or its affiliates - -namespace ProfVis.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Code/Tools/ProfVis/ProfVis/Properties/Settings.settings b/Code/Tools/ProfVis/ProfVis/Properties/Settings.settings deleted file mode 100644 index 39645652af..0000000000 --- a/Code/Tools/ProfVis/ProfVis/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Code/Tools/PythonBindingsExample/source/ApplicationParameters.cpp b/Code/Tools/PythonBindingsExample/source/ApplicationParameters.cpp index d104606f8d..eb82e8dd4b 100644 --- a/Code/Tools/PythonBindingsExample/source/ApplicationParameters.cpp +++ b/Code/Tools/PythonBindingsExample/source/ApplicationParameters.cpp @@ -18,7 +18,7 @@ namespace PythonBindingsExample void ApplicationParameters::ShowHelp() { constexpr const char* helpText = -R"(PythonBindingsExample - An example of how to bind the Behavior Context in a simple Tools Application + R"(PythonBindingsExample - An example of how to bind the Behavior Context in a simple Tools Application PythonBindingsExample.exe --file path/to/file.py --arg one --arg two --help Prints the help text @@ -32,43 +32,42 @@ PythonBindingsExample.exe --file path/to/file.py --arg one --arg two bool ApplicationParameters::Parse(const AzFramework::CommandLine* commandLine) { - if (commandLine->GetSwitchList().empty()) + if (commandLine->empty()) { ShowHelp(); return false; } - auto&& switchList = commandLine->GetSwitchList(); - for (auto&& switchItem : switchList) + for (auto&& switchItem : *commandLine) { - if (switchItem.first == "help") + if (switchItem.m_option == "help") { ShowHelp(); return false; } - else if (switchItem.first.starts_with('v')) + else if (switchItem.m_option.starts_with('v')) { m_verbose = true; } - else if (switchItem.first.starts_with('f')) + else if (switchItem.m_option.starts_with('f')) { - m_pythonFilename = switchItem.second[0]; + m_pythonFilename = switchItem.m_value; } - else if (switchItem.first.starts_with('a')) + else if (switchItem.m_option.starts_with('a')) { - m_pythonArgs.push_back(switchItem.second[0]); + m_pythonArgs.push_back(switchItem.m_value); } - else if (switchItem.first.starts_with('s')) + else if (switchItem.m_option.starts_with('s')) { - m_pythonStatement = switchItem.second[0]; + m_pythonStatement = switchItem.m_value; } - else if (switchItem.first.starts_with('i')) + else if (switchItem.m_option.starts_with('i')) { m_interactiveMode = true; } else { - AZ_Warning("python_app", false, "Unknown switch %s \n", switchItem.first.c_str()); + AZ_Warning("python_app", false, "Unknown switch %s \n", switchItem.m_option.c_str()); } } return true; diff --git a/Code/Tools/RC/ResourceCompiler/ResourceCompiler.cpp b/Code/Tools/RC/ResourceCompiler/ResourceCompiler.cpp index ba67ae2fbb..66c026d5c8 100644 --- a/Code/Tools/RC/ResourceCompiler/ResourceCompiler.cpp +++ b/Code/Tools/RC/ResourceCompiler/ResourceCompiler.cpp @@ -3330,7 +3330,6 @@ void ResourceCompiler::RegisterDefaultKeys() RegisterKey("unattended", "Prevents RC from opening any dialogs or message boxes"); RegisterKey("createjobs", "Instructs RC to read the specified input file (a CreateJobsRequest) and output a CreateJobsResponse"); RegisterKey("port", "Specifies the port that should be used to connect to the asset processor. If not set, the default from the bootstrap cfg will be used instead"); - RegisterKey("approot", "Specifies a custom directory for the engine root path. This path should contain bootstrap.cfg."); RegisterKey("branchtoken", "Specifies a branchtoken that should be used by the RC to negotiate with the asset processor. if not set it will be set from the bootstrap file."); RegisterKey("recompress", "Recompress a pack file during a copy job using the multi-variant process which picks the fastest decompressor"); RegisterKey("use_fastest", "Checks every compressor and uses the one that decompresses the data fastest when adding files to a PAK"); diff --git a/Code/Tools/RC/ResourceCompiler/main.cpp b/Code/Tools/RC/ResourceCompiler/main.cpp index 788eec3603..a33668f6cf 100644 --- a/Code/Tools/RC/ResourceCompiler/main.cpp +++ b/Code/Tools/RC/ResourceCompiler/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -558,25 +557,28 @@ int rcmain(int argc, char** argv, [[maybe_unused]] char** envp) RCLog("Initializing System"); - - string appRootInput = config.GetAsString("approot", "", ""); - if (!appRootInput.empty()) - { - rc.SetAppRootPath(appRootInput); - } - else { // Create a local SettingsRegistry to read the bootstrap.cfg settings if the appRoot hasn't been overriden // on the command line AZ::SettingsRegistryImpl settingsRegistry; AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(settingsRegistry); + + string projectPath = config.GetAsString("gameroot", "", ""); + if (!projectPath.empty()) + { + const auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString::format( + "%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); + settingsRegistry.Set(projectPathKey, projectPath.c_str()); + } + string gameName = config.GetAsString("gamesubdirectory", "", ""); if (!gameName.empty()) { - const auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - settingsRegistry.Set(gameFolderKey, gameName); + const auto projectNameKey = AZ::SettingsRegistryInterface::FixedValueString::format( + "%s/project_name", AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey); + settingsRegistry.Set(projectNameKey, gameName.c_str()); } + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(settingsRegistry); // and because we're a tool, add the tool folders: if (AZ::SettingsRegistryInterface::FixedValueString appRoot; settingsRegistry.Get(appRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) diff --git a/Code/Tools/RC/ResourceCompilerPC/StatCGFCompiler.cpp b/Code/Tools/RC/ResourceCompilerPC/StatCGFCompiler.cpp index bfcf481f79..87a3493ba2 100644 --- a/Code/Tools/RC/ResourceCompilerPC/StatCGFCompiler.cpp +++ b/Code/Tools/RC/ResourceCompilerPC/StatCGFCompiler.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -815,22 +816,18 @@ bool CStatCGFCompiler::CompileCGF(AssetBuilderSDK::ProcessJobResponse& response, #endif // If no game project was specified, then query it from the Settings Registry - if (gameFolder.length() == 0) + if (gameFolder.empty()) { - auto settingsRegistry = AZ::SettingsRegistry::Get(); - auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName); - if (settingsRegistry) - { - settingsRegistry->Get(gameFolder, gameFolderKey); - } + gameFolder = AZ::Utils::GetProjectName(); } // If no asset root was specified, then query it from the application - if (assetRoot.length() == 0) + if (assetRoot.empty()) { - EBUS_EVENT_RESULT(assetRoot, AzFramework::ApplicationRequests::Bus, GetAssetRoot); - assetRoot += gameFolder; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(assetRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } } const string sourceFile = m_CC.GetSourcePath(); diff --git a/Code/Tools/RC/ResourceCompilerPC/Tests/test_Main.cpp b/Code/Tools/RC/ResourceCompilerPC/Tests/test_Main.cpp index 835730c474..2944dde60d 100644 --- a/Code/Tools/RC/ResourceCompilerPC/Tests/test_Main.cpp +++ b/Code/Tools/RC/ResourceCompilerPC/Tests/test_Main.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include "../CryEngine/Cry3DEngine/CGF/CGFLoader.h" @@ -121,7 +122,7 @@ protected: const AZStd::string engroot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str()); - AZ::IO::Path assetRoot(engroot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); diff --git a/Code/Tools/RC/ResourceCompilerScene/SceneCompiler.cpp b/Code/Tools/RC/ResourceCompilerScene/SceneCompiler.cpp index c7b95ff5bc..f5a819ee51 100644 --- a/Code/Tools/RC/ResourceCompilerScene/SceneCompiler.cpp +++ b/Code/Tools/RC/ResourceCompilerScene/SceneCompiler.cpp @@ -144,25 +144,35 @@ namespace AZ AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( registry, AZ::RC::GetAssetBuilderTargetName()); - //the project name can be overridden, check it - AZStd::string overrideProjectName; - overrideProjectName = m_context.m_config->GetAsString("gamesubdirectory", "", ""); + AZ::CommandLine* commandLine = application.GetAzCommandLine(); + + AZStd::string overrideProjectPath = m_context.m_config->GetAsString("gameroot", "", "").c_str(); + if (!overrideProjectPath.empty()) + { + auto overrideArgs = AZStd::string::format( + "--regset=%s/project_path=%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, overrideProjectPath.c_str()); + + AZ::CommandLine::ParamContainer commandLineArgs; + commandLine->Dump(commandLineArgs); + commandLineArgs.emplace_back(overrideArgs.c_str(), overrideArgs.size()); + commandLine->Parse(commandLineArgs); + } + + AZStd::string overrideProjectName = m_context.m_config->GetAsString("gamesubdirectory", "", "").c_str(); if (!overrideProjectName.empty()) { - // Copy the gamesubdirectory argument into --regset command line parameter for the sys_game_folder - auto gameNameOverride = AZStd::string::format("--regset=%s/sys_game_folder=%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, + auto gameNameOverride = AZStd::string::format("--regset=%s/project_name=%s", AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey, overrideProjectName.c_str()); - AZ::CommandLine* commandLine = application.GetAzCommandLine(); - auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::CommandLine::ParamContainer commandLineArgs; commandLine->Dump(commandLineArgs); commandLineArgs.emplace_back(gameNameOverride.c_str(), gameNameOverride.size()); commandLine->Parse(commandLineArgs); - - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, *commandLine, false); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry); } + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, false); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); + bool connectedToAP; if (!PrepareForExporting(application, m_appRoot, connectedToAP)) { @@ -233,7 +243,7 @@ namespace AZ return &m_context; } - bool SceneCompiler::PrepareForExporting(RCToolApplication& application, const AZStd::string& appRoot, bool& connectedToAssetProcessor) + bool SceneCompiler::PrepareForExporting(RCToolApplication& application, [[maybe_unused]] const AZStd::string& appRoot, bool& connectedToAssetProcessor) { // Not all Gems shutdown properly and leak memory, but this shouldn't // prevent this builder from completing. @@ -245,7 +255,6 @@ namespace AZ descriptor.m_enableScriptReflection = false; AZ::ComponentApplication::StartupParameters startupParam; - startupParam.m_appRootOverride = appRoot.c_str(); startupParam.m_loadDynamicModules = false; application.Start(descriptor, startupParam); diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp index 4ef14284b2..f72d7ccd6d 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp @@ -63,63 +63,59 @@ namespace AZ { auto mesh = scene->mMeshes[currentNode->mMeshes[m]]; + // Don't create this until a bone with weights is encountered + Containers::SceneGraph::NodeIndex weightsIndexForMesh; + AZStd::string skinWeightName; + AZStd::shared_ptr skinWeightData; + for(unsigned b = 0; b < mesh->mNumBones; ++b) { - auto bone = mesh->mBones[b]; + const aiBone* bone = mesh->mBones[b]; if(bone->mNumWeights <= 0) { continue; } - AZStd::string skinWeightName = s_skinWeightName; - skinWeightName += AZStd::to_string(b); - RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition); - - AZStd::shared_ptr skinDeformer = BuildSkinWeightData(bone, mesh->mNumVertices); - - Containers::SceneGraph::NodeIndex newIndex = - context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, skinWeightName.c_str()); - - AZ_Error("SkinWeightsImporter", newIndex.IsValid(), "Failed to create SceneGraph node for attribute."); - if (!newIndex.IsValid()) + if (!weightsIndexForMesh.IsValid()) { - combinedSkinWeightsResult += Events::ProcessingResult::Failure; - continue; + skinWeightName = s_skinWeightName; + skinWeightName += AZStd::to_string(m); + RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition); + + weightsIndexForMesh = + context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, skinWeightName.c_str()); + + AZ_Error("SkinWeightsImporter", weightsIndexForMesh.IsValid(), "Failed to create SceneGraph node for attribute."); + if (!weightsIndexForMesh.IsValid()) + { + combinedSkinWeightsResult += Events::ProcessingResult::Failure; + continue; + } + skinWeightData = AZStd::make_shared(); } + Pending pending; + pending.m_bone = bone; + pending.m_numVertices = mesh->mNumVertices; + pending.m_skinWeightData = skinWeightData; + m_pendingSkinWeights.push_back(pending); + } - Events::ProcessingResult skinWeightsResult; - AssImpSceneAttributeDataPopulatedContext dataPopulated(context, skinDeformer, newIndex, skinWeightName); - skinWeightsResult = Events::Process(dataPopulated); + Events::ProcessingResult skinWeightsResult; + AssImpSceneAttributeDataPopulatedContext dataPopulated(context, skinWeightData, weightsIndexForMesh, skinWeightName); + skinWeightsResult = Events::Process(dataPopulated); - if (skinWeightsResult != Events::ProcessingResult::Failure) - { - skinWeightsResult = AddAttributeDataNodeWithContexts(dataPopulated); - } - - combinedSkinWeightsResult += skinWeightsResult; + if (skinWeightsResult != Events::ProcessingResult::Failure) + { + skinWeightsResult = AddAttributeDataNodeWithContexts(dataPopulated); } + + combinedSkinWeightsResult += skinWeightsResult; } return combinedSkinWeightsResult.GetResult(); } - AZStd::shared_ptr AssImpSkinWeightsImporter::BuildSkinWeightData(aiBone* bone, unsigned numVertices) - { - AZStd::shared_ptr skinWeightData = - AZStd::make_shared(); - - // Cache the new object and the link info for now so it can be resolved at a later point when all - // names have been updated. - Pending pending; - pending.m_bone = bone; - pending.m_numVertices = numVertices; - pending.m_skinWeightData = skinWeightData; - m_pendingSkinWeights.push_back(pending); - - return skinWeightData; - } - Events::ProcessingResult AssImpSkinWeightsImporter::SetupNamedBoneLinks(AssImpFinalizeSceneContext& /*context*/) { AZ_TraceContext("Importer", "Skin Weights"); @@ -137,7 +133,7 @@ namespace AZ link.boneId = boneId; link.weight = it.m_bone->mWeights[weight].mWeight; - it.m_skinWeightData->AppendLink(it.m_bone->mWeights[weight].mVertexId, link); + it.m_skinWeightData->AddAndSortLink(it.m_bone->mWeights[weight].mVertexId, link); } } const auto result = m_pendingSkinWeights.empty() ? Events::ProcessingResult::Ignored : Events::ProcessingResult::Success; diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h index ac751c688b..f048fe0af2 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h @@ -59,11 +59,10 @@ namespace AZ protected: struct Pending { - aiBone* m_bone = nullptr; + const aiBone* m_bone = nullptr; unsigned m_numVertices = 0; AZStd::shared_ptr m_skinWeightData; }; - AZStd::shared_ptr BuildSkinWeightData(aiBone* bone, unsigned numVertices); //! List of skin weights that still need to be filled in. Setting the data for skin weights is //! delayed until after the tree has been fully constructed as bones are linked by name, but until diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.cpp b/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.cpp index b5f23338fc..61b911d922 100644 --- a/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.cpp +++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.cpp @@ -100,103 +100,99 @@ namespace AZ return shininess; } - bool AssImpMaterialWrapper::GetUseColorMap() const + AZStd::optional AssImpMaterialWrapper::GetUseColorMap() const { // AssImp stores values as floats, so load as float and convert to bool. float useMap = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_USE_COLOR_MAP, useMap) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_USE_COLOR_MAP, useMap) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useColorMap from the material. Using default."); + return useMap != 0.0f; } - return useMap != 0.0f; + return AZStd::nullopt; } - AZ::Vector3 AssImpMaterialWrapper::GetBaseColor() const + AZStd::optional AssImpMaterialWrapper::GetBaseColor() const { aiColor3D color(1.f, 1.f, 1.f); - if (m_assImpMaterial->Get(AI_MATKEY_BASE_COLOR, color) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_BASE_COLOR, color) != aiReturn::aiReturn_FAILURE) { - // If a base color is not set, fall back to the diffuse color. - // Before PBR support was added, the base color was set to the diffuse color, so - // this will match that behavior. - return GetDiffuseColor(); + return AZ::Vector3(color.r, color.g, color.b); } - return AZ::Vector3(color.r, color.g, color.b); + return AZStd::nullopt; } - bool AssImpMaterialWrapper::GetUseMetallicMap() const + AZStd::optional AssImpMaterialWrapper::GetUseMetallicMap() const { // AssImp stores values as floats, so load as float and convert to bool. float useMap = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_USE_METALLIC_MAP, useMap) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_USE_METALLIC_MAP, useMap) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useMetallicMap from the material. Using default."); + return useMap != 0.0f; } - return useMap != 0.0f; + return AZStd::nullopt; } - float AssImpMaterialWrapper::GetMetallicFactor() const + AZStd::optional AssImpMaterialWrapper::GetMetallicFactor() const { float metallic = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_METALLIC_FACTOR, metallic) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_METALLIC_FACTOR, metallic) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get metallic from the material. Using default."); + return metallic; } - return metallic; + return AZStd::nullopt; } - bool AssImpMaterialWrapper::GetUseRoughnessMap() const + AZStd::optional AssImpMaterialWrapper::GetUseRoughnessMap() const { // AssImp stores values as floats, so load as float and convert to bool. float useMap = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_USE_ROUGHNESS_MAP, useMap) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_USE_ROUGHNESS_MAP, useMap) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useRoughnessMap from the material. Using default."); + return useMap != 0.0f; } - return useMap != 0.0f; + return AZStd::nullopt; } - float AssImpMaterialWrapper::GetRoughnessFactor() const + AZStd::optional AssImpMaterialWrapper::GetRoughnessFactor() const { float roughness = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_ROUGHNESS_FACTOR, roughness) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_ROUGHNESS_FACTOR, roughness) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get roughness from the material. Using default."); + return roughness; } - return roughness; + return AZStd::nullopt; } - bool AssImpMaterialWrapper::GetUseEmissiveMap() const + AZStd::optional AssImpMaterialWrapper::GetUseEmissiveMap() const { // AssImp stores values as floats, so load as float and convert to bool. float useMap = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_USE_EMISSIVE_MAP, useMap) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_USE_EMISSIVE_MAP, useMap) != aiReturn::aiReturn_FAILURE) { - AZ_Warning( - AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useEmissiveMap from the material. Using default."); + return useMap != 0.0f; } - return useMap != 0.0f; + return AZStd::nullopt; } - float AssImpMaterialWrapper::GetEmissiveIntensity() const + AZStd::optional AssImpMaterialWrapper::GetEmissiveIntensity() const { float emissiveIntensity = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_EMISSIVE_INTENSITY, emissiveIntensity) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_EMISSIVE_INTENSITY, emissiveIntensity) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get emissive intensity from the material. Using default."); + return emissiveIntensity; } - return emissiveIntensity; + return AZStd::nullopt; } - bool AssImpMaterialWrapper::GetUseAOMap() const + AZStd::optional AssImpMaterialWrapper::GetUseAOMap() const { // AssImp stores values as floats, so load as float and convert to bool. float useMap = 0.0f; - if (m_assImpMaterial->Get(AI_MATKEY_USE_AO_MAP, useMap) == aiReturn::aiReturn_FAILURE) + if (m_assImpMaterial->Get(AI_MATKEY_USE_AO_MAP, useMap) != aiReturn::aiReturn_FAILURE) { - AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useAOMap from the material. Using default."); + return useMap != 0.0f; } - return useMap != 0.0f; + return AZStd::nullopt; } AZStd::string AssImpMaterialWrapper::GetTextureFileName(MaterialMapType textureType) const diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.h b/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.h index b9fac074b9..96f786c932 100644 --- a/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.h +++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpMaterialWrapper.h @@ -33,15 +33,15 @@ namespace AZ float GetShininess() const override; AZStd::string GetTextureFileName(MaterialMapType textureType) const override; - bool GetUseColorMap() const; - AZ::Vector3 GetBaseColor() const; - bool GetUseMetallicMap() const; - float GetMetallicFactor() const; - bool GetUseRoughnessMap() const; - float GetRoughnessFactor() const; - bool GetUseEmissiveMap() const; - float GetEmissiveIntensity() const; - bool GetUseAOMap() const; + AZStd::optional GetUseColorMap() const; + AZStd::optional GetBaseColor() const; + AZStd::optional GetUseMetallicMap() const; + AZStd::optional GetMetallicFactor() const; + AZStd::optional GetUseRoughnessMap() const; + AZStd::optional GetRoughnessFactor() const; + AZStd::optional GetUseEmissiveMap() const; + AZStd::optional GetEmissiveIntensity() const; + AZStd::optional GetUseAOMap() const; }; } // namespace AssImpSDKWrapper }// namespace AZ diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp index 161dc5438e..a2eac862bc 100644 --- a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp +++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp @@ -43,6 +43,8 @@ namespace AZ m_assImpScene = m_importer.ReadFile(fileName, aiProcess_Triangulate //Triangulates all faces of all meshes | aiProcess_JoinIdenticalVertices //Identifies and joins identical vertex data sets for the imported meshes + | aiProcess_LimitBoneWeights //Limits the number of bones that can affect a vertex to a maximum value + //dropping the least important and re-normalizing | aiProcess_GenNormals); //Generate normals for meshes if (!m_assImpScene) { diff --git a/Code/Tools/SceneAPI/SceneCore/DataTypes/GraphData/IMaterialData.h b/Code/Tools/SceneAPI/SceneCore/DataTypes/GraphData/IMaterialData.h index 7e065562b3..0ed946e0c4 100644 --- a/Code/Tools/SceneAPI/SceneCore/DataTypes/GraphData/IMaterialData.h +++ b/Code/Tools/SceneAPI/SceneCore/DataTypes/GraphData/IMaterialData.h @@ -87,15 +87,15 @@ namespace AZ virtual float GetOpacity() const = 0; virtual float GetShininess() const = 0; - virtual bool GetUseColorMap() const = 0; - virtual const AZ::Vector3& GetBaseColor() const = 0; - virtual bool GetUseMetallicMap() const = 0; - virtual float GetMetallicFactor() const = 0; - virtual bool GetUseRoughnessMap() const = 0; - virtual float GetRoughnessFactor() const = 0; - virtual bool GetUseEmissiveMap() const = 0; - virtual float GetEmissiveIntensity() const = 0; - virtual bool GetUseAOMap() const = 0; + virtual AZStd::optional GetUseColorMap() const = 0; + virtual AZStd::optional GetBaseColor() const = 0; + virtual AZStd::optional GetUseMetallicMap() const = 0; + virtual AZStd::optional GetMetallicFactor() const = 0; + virtual AZStd::optional GetUseRoughnessMap() const = 0; + virtual AZStd::optional GetRoughnessFactor() const = 0; + virtual AZStd::optional GetUseEmissiveMap() const = 0; + virtual AZStd::optional GetEmissiveIntensity() const = 0; + virtual AZStd::optional GetUseAOMap() const = 0; virtual uint64_t GetUniqueId() const = 0; }; diff --git a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp index 455dab754e..ef4ae3d51a 100644 --- a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp @@ -367,7 +367,8 @@ namespace AZ MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char* ()); + MOCK_CONST_METHOD0(GetAppRoot, const char*()); + MOCK_CONST_METHOD0(GetEngineRoot, const char*()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ()); MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&)); diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp index 61d520e15e..e99788d570 100644 --- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp @@ -72,6 +72,41 @@ namespace AZ::SceneAPI::Utilities m_output += AZStd::string::format("\t%s: <% f, % f, % f>\n", name, data.GetX(), data.GetY(), data.GetZ()); } + void DebugOutput::Write(const char* name, AZStd::optional data) + { + if (data.has_value()) + { + Write(name, data.value()); + } + else + { + Write(name, "Not set"); + } + } + void DebugOutput::Write(const char* name, AZStd::optional data) + { + if (data.has_value()) + { + Write(name, data.value()); + } + else + { + Write(name, "Not set"); + } + } + + void DebugOutput::Write(const char* name, AZStd::optional data) + { + if (data.has_value()) + { + Write(name, data.value()); + } + else + { + Write(name, "Not set"); + } + } + const AZStd::string& DebugOutput::GetOutput() const { return m_output; diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h index 6652a25d95..a598c996c9 100644 --- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h +++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h @@ -36,6 +36,9 @@ namespace AZ::SceneAPI::Utilities SCENE_CORE_API void Write(const char* name, const DataTypes::MatrixType& data); SCENE_CORE_API void Write(const char* name, bool data); SCENE_CORE_API void Write(const char* name, Vector3 data); + SCENE_CORE_API void Write(const char* name, AZStd::optional data); + SCENE_CORE_API void Write(const char* name, AZStd::optional data); + SCENE_CORE_API void Write(const char* name, AZStd::optional data); SCENE_CORE_API const AZStd::string& GetOutput() const; diff --git a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp index 85ad55982c..8a74d9e5c2 100644 --- a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp +++ b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp @@ -156,7 +156,7 @@ namespace AZ // get project folder auto settingsRegistry = AZ::SettingsRegistry::Get(); AZ::IO::FixedMaxPath projectPath; - if (!settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder)) + if (!settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) { return Events::ProcessingResult::Ignored; } diff --git a/Code/Tools/SceneAPI/SceneData/CMakeLists.txt b/Code/Tools/SceneAPI/SceneData/CMakeLists.txt index 44c2d08d86..8b2b351391 100644 --- a/Code/Tools/SceneAPI/SceneData/CMakeLists.txt +++ b/Code/Tools/SceneAPI/SceneData/CMakeLists.txt @@ -47,6 +47,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzTest + AZ::AzFramework + AZ::SceneCore AZ::SceneData ) ly_add_googletest( diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp index a5a40b3258..400a2d39a3 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp @@ -144,92 +144,92 @@ namespace AZ return m_shininess; } - void MaterialData::SetUseColorMap(bool useColorMap) + void MaterialData::SetUseColorMap(AZStd::optional useColorMap) { m_useColorMap = useColorMap; } - bool MaterialData::GetUseColorMap() const + AZStd::optional MaterialData::GetUseColorMap() const { return m_useColorMap; } - void MaterialData::SetBaseColor(const AZ::Vector3& baseColor) + void MaterialData::SetBaseColor(const AZStd::optional& baseColor) { m_baseColor = baseColor; } - const AZ::Vector3& MaterialData::GetBaseColor() const + AZStd::optional MaterialData::GetBaseColor() const { return m_baseColor; } - void MaterialData::SetUseMetallicMap(bool useMetallicMap) + void MaterialData::SetUseMetallicMap(AZStd::optional useMetallicMap) { m_useMetallicMap = useMetallicMap; } - bool MaterialData::GetUseMetallicMap() const + AZStd::optional MaterialData::GetUseMetallicMap() const { return m_useMetallicMap; } - void MaterialData::SetMetallicFactor(float metallicFactor) + void MaterialData::SetMetallicFactor(AZStd::optional metallicFactor) { m_metallicFactor = metallicFactor; } - float MaterialData::GetMetallicFactor() const + AZStd::optional MaterialData::GetMetallicFactor() const { return m_metallicFactor; } - void MaterialData::SetUseRoughnessMap(bool useRoughnessMap) + void MaterialData::SetUseRoughnessMap(AZStd::optional useRoughnessMap) { m_useRoughnessMap = useRoughnessMap; } - bool MaterialData::GetUseRoughnessMap() const + AZStd::optional MaterialData::GetUseRoughnessMap() const { return m_useRoughnessMap; } - void MaterialData::SetRoughnessFactor(float roughnessFactor) + void MaterialData::SetRoughnessFactor(AZStd::optional roughnessFactor) { m_roughnessFactor = roughnessFactor; } - float MaterialData::GetRoughnessFactor() const + AZStd::optional MaterialData::GetRoughnessFactor() const { return m_roughnessFactor; } - void MaterialData::SetUseEmissiveMap(bool useEmissiveMap) + void MaterialData::SetUseEmissiveMap(AZStd::optional useEmissiveMap) { m_useEmissiveMap = useEmissiveMap; } - bool MaterialData::GetUseEmissiveMap() const + AZStd::optional MaterialData::GetUseEmissiveMap() const { return m_useEmissiveMap; } - void MaterialData::SetEmissiveIntensity(float emissiveIntensity) + void MaterialData::SetEmissiveIntensity(AZStd::optional emissiveIntensity) { m_emissiveIntensity = emissiveIntensity; } - float MaterialData::GetEmissiveIntensity() const + AZStd::optional MaterialData::GetEmissiveIntensity() const { return m_emissiveIntensity; } - void MaterialData::SetUseAOMap(bool useAOMap) + void MaterialData::SetUseAOMap(AZStd::optional useAOMap) { m_useAOMap = useAOMap; } - bool MaterialData::GetUseAOMap() const + AZStd::optional MaterialData::GetUseAOMap() const { return m_useAOMap; } diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.h b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.h index e24790864a..75c64793d5 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.h +++ b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.h @@ -47,15 +47,15 @@ namespace AZ SCENE_DATA_API virtual void SetOpacity(float opacity); SCENE_DATA_API virtual void SetShininess(float shininess); SCENE_DATA_API virtual void SetUniqueId(uint64_t uid); - SCENE_DATA_API virtual void SetUseColorMap(bool useColorMap); - SCENE_DATA_API virtual void SetBaseColor(const AZ::Vector3& baseColor); - SCENE_DATA_API virtual void SetUseMetallicMap(bool useMetallicMap); - SCENE_DATA_API virtual void SetMetallicFactor(float metallicFactor); - SCENE_DATA_API virtual void SetUseRoughnessMap(bool useRoughnessMap); - SCENE_DATA_API virtual void SetRoughnessFactor(float roughnessFactor); - SCENE_DATA_API virtual void SetUseEmissiveMap(bool useEmissiveMap); - SCENE_DATA_API virtual void SetEmissiveIntensity(float emissiveIntensity); - SCENE_DATA_API virtual void SetUseAOMap(bool useAOMap); + SCENE_DATA_API virtual void SetUseColorMap(AZStd::optional useColorMap); + SCENE_DATA_API virtual void SetBaseColor(const AZStd::optional& baseColor); + SCENE_DATA_API virtual void SetUseMetallicMap(AZStd::optional useMetallicMap); + SCENE_DATA_API virtual void SetMetallicFactor(AZStd::optional metallicFactor); + SCENE_DATA_API virtual void SetUseRoughnessMap(AZStd::optional useRoughnessMap); + SCENE_DATA_API virtual void SetRoughnessFactor(AZStd::optional roughnessFactor); + SCENE_DATA_API virtual void SetUseEmissiveMap(AZStd::optional useEmissiveMap); + SCENE_DATA_API virtual void SetEmissiveIntensity(AZStd::optional emissiveIntensity); + SCENE_DATA_API virtual void SetUseAOMap(AZStd::optional useAOMap); SCENE_DATA_API const AZStd::string& GetTexture(TextureMapType mapType) const override; @@ -67,15 +67,15 @@ namespace AZ SCENE_DATA_API float GetOpacity() const override; SCENE_DATA_API float GetShininess() const override; SCENE_DATA_API uint64_t GetUniqueId() const override; - SCENE_DATA_API bool GetUseColorMap() const override; - SCENE_DATA_API const AZ::Vector3& GetBaseColor() const override; - SCENE_DATA_API bool GetUseMetallicMap() const override; - SCENE_DATA_API float GetMetallicFactor() const override; - SCENE_DATA_API bool GetUseRoughnessMap() const override; - SCENE_DATA_API float GetRoughnessFactor() const override; - SCENE_DATA_API bool GetUseEmissiveMap() const override; - SCENE_DATA_API float GetEmissiveIntensity() const override; - SCENE_DATA_API bool GetUseAOMap() const override; + SCENE_DATA_API AZStd::optional GetUseColorMap() const override; + SCENE_DATA_API AZStd::optional GetBaseColor() const override; + SCENE_DATA_API AZStd::optional GetUseMetallicMap() const override; + SCENE_DATA_API AZStd::optional GetMetallicFactor() const override; + SCENE_DATA_API AZStd::optional GetUseRoughnessMap() const override; + SCENE_DATA_API AZStd::optional GetRoughnessFactor() const override; + SCENE_DATA_API AZStd::optional GetUseEmissiveMap() const override; + SCENE_DATA_API AZStd::optional GetEmissiveIntensity() const override; + SCENE_DATA_API AZStd::optional GetUseAOMap() const override; static void Reflect(ReflectContext* context); @@ -85,18 +85,18 @@ namespace AZ AZ::Vector3 m_diffuseColor; AZ::Vector3 m_specularColor; AZ::Vector3 m_emissiveColor; - AZ::Vector3 m_baseColor; + AZStd::optional m_baseColor; float m_opacity; float m_shininess; - float m_metallicFactor = 0.0f; - float m_roughnessFactor = 0.0f; - float m_emissiveIntensity = 0.0f; - - bool m_useColorMap = false; - bool m_useMetallicMap = false; - bool m_useRoughnessMap = false; - bool m_useEmissiveMap = false; - bool m_useAOMap = false; + AZStd::optional m_metallicFactor = AZStd::nullopt; + AZStd::optional m_roughnessFactor = AZStd::nullopt; + AZStd::optional m_emissiveIntensity = AZStd::nullopt; + + AZStd::optional m_useColorMap = AZStd::nullopt; + AZStd::optional m_useMetallicMap = AZStd::nullopt; + AZStd::optional m_useRoughnessMap = AZStd::nullopt; + AZStd::optional m_useEmissiveMap = AZStd::nullopt; + AZStd::optional m_useAOMap = AZStd::nullopt; bool m_isNoDraw; diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.cpp index 025301b4f2..0d7255960c 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.cpp @@ -66,6 +66,19 @@ namespace AZ m_vertexLinks[vertexIndex].push_back(link); } + bool CompareLinks(const SceneAPI::DataTypes::ISkinWeightData::Link& left, const SceneAPI::DataTypes::ISkinWeightData::Link& right) + { + // sort highest to lowest + return left.weight >= right.weight; + } + + void SkinWeightData::AddAndSortLink(size_t vertexIndex, const SceneAPI::DataTypes::ISkinWeightData::Link& link) + { + AZ_Assert(vertexIndex < m_vertexLinks.size(), "Invalid vertex index %i for skin weight data links.", vertexIndex); + m_vertexLinks[vertexIndex].insert( + AZStd::lower_bound(m_vertexLinks[vertexIndex].begin(), m_vertexLinks[vertexIndex].end(), link, CompareLinks), link); + } + int SkinWeightData::GetBoneId(const AZStd::string& boneName) { if (m_boneNameIdMap.find(boneName) == m_boneNameIdMap.end()) diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.h b/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.h index e14b9495f8..2a5380adb3 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.h +++ b/Code/Tools/SceneAPI/SceneData/GraphData/SkinWeightData.h @@ -41,6 +41,7 @@ namespace AZ SCENE_DATA_API void ResizeContainerSpace(size_t size); SCENE_DATA_API void AppendLink(size_t vertexIndex, const SceneAPI::DataTypes::ISkinWeightData::Link& link); + SCENE_DATA_API void AddAndSortLink(size_t vertexIndex, const SceneAPI::DataTypes::ISkinWeightData::Link& link); SCENE_DATA_API int GetBoneId(const AZStd::string& boneName); diff --git a/Code/Tools/SceneAPI/SceneData/SceneData_testing_files.cmake b/Code/Tools/SceneAPI/SceneData/SceneData_testing_files.cmake index 6009f4bc50..b5bd0df270 100644 --- a/Code/Tools/SceneAPI/SceneData/SceneData_testing_files.cmake +++ b/Code/Tools/SceneAPI/SceneData/SceneData_testing_files.cmake @@ -14,4 +14,5 @@ set(FILES Tests/GraphData/MeshDataTests.cpp Tests/GraphData/MeshDataPrimitiveUtilsTests.cpp Tests/GraphData/GraphDataBehaviorTests.cpp + Tests/SceneManifest/SceneManifestRuleTests.cpp ) diff --git a/Code/Tools/SceneAPI/SceneData/Tests/SceneManifest/SceneManifestRuleTests.cpp b/Code/Tools/SceneAPI/SceneData/Tests/SceneManifest/SceneManifestRuleTests.cpp new file mode 100644 index 0000000000..782dc0f6a0 --- /dev/null +++ b/Code/Tools/SceneAPI/SceneData/Tests/SceneManifest/SceneManifestRuleTests.cpp @@ -0,0 +1,178 @@ +/* +* 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. +* +*/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace SceneAPI + { + class MockRotationRule final + : public DataTypes::IManifestObject + { + public: + AZ_RTTI(MockRotationRule, "{90AECE4A-58D4-411C-9CDE-59B54C59354F}", DataTypes::IManifestObject); + AZ_CLASS_ALLOCATOR(MockRotationRule, AZ::SystemAllocator, 0); + + static void Reflect(ReflectContext* context) + { + AZ::SerializeContext* serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Version(1) + ->Field("rotation", &MockRotationRule::m_rotation); + } + } + + AZ::Quaternion m_rotation = AZ::Quaternion::CreateIdentity(); + }; + + namespace Containers + { + class SceneManifestContainer + { + public: + static AZ::Outcome SaveToJsonDocumentHelper( + SceneAPI::Containers::SceneManifest& manifest, + SerializeContext* context, + JsonRegistrationContext* registrationContext) + { + return manifest.SaveToJsonDocument(context, registrationContext); + } + }; + } + } + + namespace SceneData + { + class SceneManifest_JSON + : public UnitTest::AllocatorsFixture + { + public: + AZStd::unique_ptr m_serializeContext; + AZStd::unique_ptr m_jsonRegistrationContext; + AZStd::unique_ptr m_jsonSystemComponent; + + void SetUp() override + { + UnitTest::AllocatorsFixture::SetUp(); + AZ::NameDictionary::Create(); + + m_serializeContext = AZStd::make_unique(); + AZ::SceneAPI::RegisterDataTypeReflection(m_serializeContext.get()); + AZ::SceneAPI::Containers::SceneManifest::Reflect(m_serializeContext.get()); + AZ::SceneAPI::DataTypes::IManifestObject::Reflect(m_serializeContext.get()); + AZ::SceneAPI::MockRotationRule::Reflect(m_serializeContext.get()); + + m_jsonRegistrationContext = AZStd::make_unique(); + + m_jsonSystemComponent = AZStd::make_unique(); + m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get()); + } + + void TearDown() override + { + m_jsonRegistrationContext->EnableRemoveReflection(); + m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get()); + m_jsonRegistrationContext->DisableRemoveReflection(); + + m_serializeContext.reset(); + m_jsonRegistrationContext.reset(); + m_jsonSystemComponent.reset(); + + AZ::NameDictionary::Destroy(); + UnitTest::AllocatorsFixture::TearDown(); + } + }; + + TEST_F(SceneManifest_JSON, LoadFromString_BlankManifest_HasDefaultParts) + { + SceneAPI::Containers::SceneManifest sceneManifest; + sceneManifest.LoadFromString("{}", m_serializeContext.get(), m_jsonRegistrationContext.get(), false); + } + + TEST_F(SceneManifest_JSON, LoadFromString_LoadRotationRuleWithQuaternion_ReturnsTrue) + { + using namespace SceneAPI::Containers; + SceneManifest sceneManifest; + + auto anglesInDegrees = AZ::Vector3(45.0f, 90.0f, 45.0f); + auto originRule = AZStd::make_shared(); + originRule->m_rotation = Quaternion::CreateFromEulerAnglesDegrees(anglesInDegrees); + sceneManifest.AddEntry(originRule); + + auto writeToJsonResult = SceneManifestContainer::SaveToJsonDocumentHelper(sceneManifest, m_serializeContext.get(), m_jsonRegistrationContext.get()); + ASSERT_TRUE(writeToJsonResult.IsSuccess()); + + AZStd::string jsonText; + auto writeToStringResult = AzFramework::FileFunc::WriteJsonToString(writeToJsonResult.GetValue(), jsonText); + ASSERT_TRUE(writeToStringResult.IsSuccess()); + EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("$type": "MockRotationRule")")); + EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("rotation": [)")); + + SceneManifest loaded; + auto loadFromStringResult = loaded.LoadFromString(jsonText, m_serializeContext.get(), m_jsonRegistrationContext.get()); + EXPECT_TRUE(loadFromStringResult.IsSuccess()); + EXPECT_FALSE(loaded.IsEmpty()); + + ASSERT_EQ(loaded.GetEntryCount(), sceneManifest.GetEntryCount()); + } + + TEST_F(SceneManifest_JSON, LoadFromString_LoadRotationRuleWithAnglesInDegrees_ReturnsTrue) + { + using namespace SceneAPI::Containers; + + constexpr const char* jsonWithAngles = { R"JSON( + { + "values": [ + { + "$type": "MockRotationRule", + "rotation": { "yaw" : 45.0, "pitch" : 90.0, "roll" : 0.0 } + } + ] + })JSON"}; + + SceneManifest loaded; + auto loadFromStringResult = loaded.LoadFromString(jsonWithAngles, m_serializeContext.get(), m_jsonRegistrationContext.get()); + EXPECT_TRUE(loadFromStringResult.IsSuccess()); + EXPECT_FALSE(loaded.IsEmpty()); + + auto writeToJsonResult = + SceneManifestContainer::SaveToJsonDocumentHelper(loaded, m_serializeContext.get(), m_jsonRegistrationContext.get()); + ASSERT_TRUE(writeToJsonResult.IsSuccess()); + + AZStd::string jsonText; + auto writeToStringResult = AzFramework::FileFunc::WriteJsonToString(writeToJsonResult.GetValue(), jsonText); + ASSERT_TRUE(writeToStringResult.IsSuccess()); + EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("$type": "MockRotationRule")")); + EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("rotation": [)")); + EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(0.27)")); + EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(0.65)")); + } + } +} diff --git a/Code/Tools/SerializeContextTools/Application.cpp b/Code/Tools/SerializeContextTools/Application.cpp index b4c34d9744..2ab9847aa6 100644 --- a/Code/Tools/SerializeContextTools/Application.cpp +++ b/Code/Tools/SerializeContextTools/Application.cpp @@ -13,73 +13,57 @@ #include #include #include -#include +#include +#include namespace AZ { namespace SerializeContextTools { - Application::Application(int* argc, char*** argv) - : AzToolsFramework::ToolsApplication(argc, argv) + Application::Application(int argc, char** argv) + : AZ::ComponentApplication(argc, argv) { - AZ::IO::FixedMaxPath sourceGameFolder; - if (!m_settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder)) + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + if (projectPath.empty()) { - AZ_Error("Serialize Context Tools", false, "Unable to determine the game root automatically. " - "Make sure a default project has been set or provide a default option on the command line. (See -help for more info.)"); + AZ_Error("Serialize Context Tools", false, "Unable to determine the project path . " + "Make sure project has been set or provide via the -project-path option on the command line. (See -help for more info.)"); return; } - AZStd::string configFilePath = "Config/Editor.xml"; - if (m_commandLine.HasSwitch("config")) + size_t configSwitchCount = m_commandLine.GetNumSwitchValues("config"); + if (configSwitchCount > 0) { - configFilePath = m_commandLine.GetSwitchValue("config", 0); - } - - AZ::IO::FixedMaxPath absConfigFilePath = sourceGameFolder / configFilePath; - if (AZ::IO::SystemFile::Exists(absConfigFilePath.c_str())) - { - m_configFilePath = AZStd::move(absConfigFilePath); - } - else - { - AZ_Error("Serialize Context Tools", false, "Unable to resolve path to config file."); + AZ::IO::FixedMaxPath absConfigFilePath = projectPath / m_commandLine.GetSwitchValue("config", configSwitchCount - 1); + if (AZ::IO::SystemFile::Exists(absConfigFilePath.c_str())) + { + m_configFilePath = AZStd::move(absConfigFilePath); + } } // Merge the build system generated setting registry file by using either "Editor" or // and "${ProjectName}_GameLauncher" as a specialization - bool projectNameFound{}; - AZ::SettingsRegistryInterface::FixedValueString projectName; - AZ::SettingsRegistryInterface& registry = *AZ::SettingsRegistry::Get(); - constexpr auto sysGameFolderKey = AZ::SettingsRegistryInterface::FixedValueString( - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/sys_game_folder"; - if (projectNameFound = registry.Get(projectName, sysGameFolderKey); !projectNameFound) + auto projectName = AZ::Utils::GetProjectName(); + if (projectName.empty()) { - AZ_Error("Serialize Context Tools", false, "Unable to query the %s key from the SettingsRegistry", - sysGameFolderKey.c_str()); + AZ_Error("Serialize Context Tools", false, "Unable to query the project name from settings registry"); } else { - AZ::IO::PathView configFilenameStem = m_configFilePath.Stem(); AZ::SettingsRegistryInterface::Specializations projectSpecializations{ projectName }; - size_t configFilenameStemSize = configFilenameStem.Native().size(); - if (configFilenameStemSize > 0 && azstrnicmp(configFilenameStem.Native().data(), "Editor", configFilenameStemSize) == 0) + AZ::IO::PathView configFilenameStem = m_configFilePath.Stem(); + if (AZ::StringFunc::Equal(configFilenameStem.Native(), "Editor")) { projectSpecializations.Append("editor"); } - else if (configFilenameStemSize > 0 && azstrnicmp(configFilenameStem.Native().data(), "Game", configFilenameStemSize) == 0) + else if (AZ::StringFunc::Equal(configFilenameStem.Native(), "Game")) { projectSpecializations.Append(projectName + "_GameLauncher"); } - else - { - AZ_TracePrintf("Serialize Context Tools", "No Editor.xml or Game.xml supplied." - R"( Build dependency specialization will not use a specialization of "%s" nor "editor" for locating *.setreg files)", - (projectName + "_GameLauncher").c_str()); - } // Used the project specializations to merge the build dependencies *.setreg files - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, + auto registry = AZ::SettingsRegistry::Get(); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(*registry, AZ_TRAIT_OS_PLATFORM_CODENAME, projectSpecializations); } } @@ -91,7 +75,7 @@ namespace AZ void Application::SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations) { - AzToolsFramework::ToolsApplication::SetSettingsRegistrySpecializations(specializations); + AZ::ComponentApplication::SetSettingsRegistrySpecializations(specializations); specializations.Append("serializecontexttools"); } } // namespace SerializeContextTools diff --git a/Code/Tools/SerializeContextTools/Application.h b/Code/Tools/SerializeContextTools/Application.h index e5115cbc97..63bc1892ed 100644 --- a/Code/Tools/SerializeContextTools/Application.h +++ b/Code/Tools/SerializeContextTools/Application.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace AZ @@ -20,10 +20,10 @@ namespace AZ namespace SerializeContextTools { class Application final - : public AzToolsFramework::ToolsApplication + : public AZ::ComponentApplication { public: - Application(int* argc, char*** argv); + Application(int argc, char** argv); ~Application() override = default; const char* GetConfigFilePath() const; diff --git a/Code/Tools/SerializeContextTools/CMakeLists.txt b/Code/Tools/SerializeContextTools/CMakeLists.txt index e73fd014ab..1a993de53c 100644 --- a/Code/Tools/SerializeContextTools/CMakeLists.txt +++ b/Code/Tools/SerializeContextTools/CMakeLists.txt @@ -29,6 +29,4 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE AZ::AzCore - AZ::AzFramework - AZ::AzToolsFramework ) diff --git a/Code/Tools/SerializeContextTools/Converter.cpp b/Code/Tools/SerializeContextTools/Converter.cpp index 33aa5e569e..b15bb4fa8e 100644 --- a/Code/Tools/SerializeContextTools/Converter.cpp +++ b/Code/Tools/SerializeContextTools/Converter.cpp @@ -14,13 +14,14 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include #include #include #include @@ -33,7 +34,7 @@ namespace AZ { using namespace AZ::JsonSerializationResult; - const AzFramework::CommandLine* commandLine = application.GetCommandLine(); + const AZ::CommandLine* commandLine = application.GetAzCommandLine(); if (!commandLine) { AZ_Error("SerializeContextTools", false, "Command line not available."); @@ -123,7 +124,7 @@ namespace AZ } // If there's only one file, then use the original name instead of the extended name - AzFramework::StringFunc::Path::ReplaceExtension(filePath, extension.c_str()); + AZ::StringFunc::Path::ReplaceExtension(filePath, extension.c_str()); if (documents.size() == 1) { AZ_Printf("Convert", " Exporting to '%s'\n", filePath.c_str()); @@ -142,7 +143,7 @@ namespace AZ else { AZStd::string fileName; - AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName); + AZ::StringFunc::Path::GetFileName(filePath.c_str(), fileName); for (PathDocumentPair& document : documents) { AZStd::string fileNameExtended = fileName; @@ -150,7 +151,7 @@ namespace AZ fileNameExtended += document.first; Utilities::SanitizeFilePath(fileNameExtended); AZStd::string finalFilePath = filePath; - AzFramework::StringFunc::Path::ReplaceFullName(finalFilePath, fileNameExtended.c_str(), extension.c_str()); + AZ::StringFunc::Path::ReplaceFullName(finalFilePath, fileNameExtended.c_str(), extension.c_str()); AZ_Printf("Convert", " Exporting to '%s'\n", finalFilePath.c_str()); if (!isDryRun) @@ -172,7 +173,7 @@ namespace AZ bool Converter::ConvertApplicationDescriptor(Application& application) { - const AzFramework::CommandLine* commandLine = application.GetCommandLine(); + const AZ::CommandLine* commandLine = application.GetAzCommandLine(); if (!commandLine) { AZ_Error("SerializeContextTools", false, "Command line not available."); @@ -212,7 +213,7 @@ namespace AZ const AZStd::string& filePath = application.GetConfigFilePath(); AZ_Printf("Convert", "Reading '%s' for conversion.\n", filePath.c_str()); AZStd::string configurationName; - if (!AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), configurationName) || + if (!AZ::StringFunc::Path::GetFileName(filePath.c_str(), configurationName) || configurationName.empty()) { AZ_Error("Convert", false, "Unable to extract configuration from '%s'.", filePath.c_str()); @@ -225,7 +226,7 @@ namespace AZ AZ::IO::FixedMaxPath sourceGameFolder; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); !settingsRegistry - || !settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder)) + || !settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) { AZ_Error("Serialize Context Tools", false, "Unable to determine the game root automatically. " "Make sure a default project has been set or provide a default option on the command line. (See -help for more info.)"); @@ -314,7 +315,7 @@ namespace AZ bool Converter::ConvertConfigFile(Application& application) { bool result = true; - const AzFramework::CommandLine* commandLine = application.GetCommandLine(); + const AZ::CommandLine* commandLine = application.GetAzCommandLine(); if (!commandLine) { AZ_Error("SerializeContextTools", false, "Command line not available."); @@ -334,13 +335,6 @@ namespace AZ const bool isDryRun = commandLine->HasSwitch("dryrun"); - // Use the Engine Root Folder from the Global Settings Registry - AZ::IO::FixedMaxPath engineRootPath; - if (auto globalSettingsRegistry = AZ::SettingsRegistry::Get(); globalSettingsRegistry != nullptr) - { - globalSettingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - // The AZ CommandLine internally splits switches on and semicolon AZStd::vector fileList; size_t filesToConvert = commandLine->GetNumSwitchValues("files"); @@ -353,10 +347,9 @@ namespace AZ PathDocumentContainer documents; for (AZStd::string_view configFileView : fileList) { - // Appends the paths in "files" argument to the EngineRootPath - // If the "files" argument is absolute AZ::IO::Path follows the python os.join logic - // and replaces the paths before it with the absolute path - AZ::IO::FixedMaxPath configFilePath = engineRootPath / configFileView; + // Convert the supplied file list to an absolute path + AZStd::optional absFilePath = AZ::Utils::ConvertToAbsolutePath(configFileView); + AZ::IO::FixedMaxPath configFilePath = absFilePath ? *absFilePath : configFileView; auto callback = [&documents, &outputExtension, &configFilePath](AZ::IO::PathView configFileView, bool isFile) -> bool { if (configFileView == "." || configFileView == "..") @@ -866,7 +859,7 @@ namespace AZ } void Converter::SetupLogging(AZStd::string& scratchBuffer, JsonSerializationResult::JsonIssueCallback& callback, - const AzFramework::CommandLine& commandLine) + const AZ::CommandLine& commandLine) { if (commandLine.HasSwitch("verbose")) { diff --git a/Code/Tools/SerializeContextTools/Converter.h b/Code/Tools/SerializeContextTools/Converter.h index dcb06d13c2..18f30cc562 100644 --- a/Code/Tools/SerializeContextTools/Converter.h +++ b/Code/Tools/SerializeContextTools/Converter.h @@ -61,7 +61,7 @@ namespace AZ rapidjson::StringBuffer& scratchBuffer); static void SetupLogging(AZStd::string& scratchBuffer, JsonSerializationResult::JsonIssueCallback& callback, - const AzFramework::CommandLine& commandLine); + const AZ::CommandLine& commandLine); static JsonSerializationResult::ResultCode VerboseLogging(AZStd::string& scratchBuffer, AZStd::string_view message, JsonSerializationResult::ResultCode result, AZStd::string_view target); static AZ::JsonSerializationResult::ResultCode SimpleLogging(AZStd::string& scratchBuffer, AZStd::string_view message, diff --git a/Code/Tools/SerializeContextTools/Dumper.cpp b/Code/Tools/SerializeContextTools/Dumper.cpp index f8f44687ae..55c9581602 100644 --- a/Code/Tools/SerializeContextTools/Dumper.cpp +++ b/Code/Tools/SerializeContextTools/Dumper.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace AZ::SerializeContextTools AZ::IO::Path sourceGameFolder; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder); + settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } bool result = true; diff --git a/Code/Tools/SerializeContextTools/Utilities.cpp b/Code/Tools/SerializeContextTools/Utilities.cpp index 517071af5e..127f833f6b 100644 --- a/Code/Tools/SerializeContextTools/Utilities.cpp +++ b/Code/Tools/SerializeContextTools/Utilities.cpp @@ -36,13 +36,13 @@ namespace AZ::SerializeContextTools AZ::IO::Path sourceGameFolder; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder); + settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } AZ::IO::Path outputPath; - if (application.GetCommandLine()->HasSwitch("output")) + if (application.GetAzCommandLine()->HasSwitch("output")) { - outputPath.Native() = application.GetCommandLine()->GetSwitchValue("output", 0); + outputPath.Native() = application.GetAzCommandLine()->GetSwitchValue("output", 0); if (outputPath.IsRelative()) { outputPath = sourceGameFolder / outputPath; @@ -59,7 +59,7 @@ namespace AZ::SerializeContextTools { AZStd::vector result; - const AZ::CommandLine* commandLine = application.GetCommandLine(); + const AZ::CommandLine* commandLine = application.GetAzCommandLine(); if (!commandLine) { AZ_Error("SerializeContextTools", false, "Command line not available."); @@ -76,7 +76,7 @@ namespace AZ::SerializeContextTools AZ::IO::Path sourceGameFolder; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_SourceGameFolder); + settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } AZStd::vector fileList; diff --git a/Code/Tools/SerializeContextTools/main.cpp b/Code/Tools/SerializeContextTools/main.cpp index 9108790e7b..ee505c9cc0 100644 --- a/Code/Tools/SerializeContextTools/main.cpp +++ b/Code/Tools/SerializeContextTools/main.cpp @@ -11,8 +11,8 @@ */ #include -#include -#include +#include +#include #include #include #include @@ -58,8 +58,8 @@ void PrintHelp() AZ_Printf("Help", " [opt] -verbose: Report additional details during the conversion process.\n"); AZ_Printf("Help", " [opt] -regset =: Set setreg_value at key setreg_key within the settings registry.\n"); AZ_Printf("Help", " This can be used for example to override the Active Game Project in the settings registry.\n"); - AZ_Printf("Help", " instead of using the sys_game_folder value from the bootstrap.cfg.\n"); - AZ_Printf("Help", R"( Ex. -regset "/Amazon/AzCore/Bootstrap/sys_game_folder=AutomatedTesting"\n)"); + AZ_Printf("Help", " instead of using the project_path value from the bootstrap.cfg.\n"); + AZ_Printf("Help", R"( Ex. -regset "/Amazon/AzCore/Bootstrap/project_path=AutomatedTesting"\n)"); AZ_Printf("Help", " This sets the active game project as AutomatedTesting, overrideing the value in the bootstrap.cfg\n"); AZ_Printf("Help", " example: 'convertad -config=config/game.xml -dryrun\n"); AZ_Printf("Help", R"( 'convert-ini': Converts windows-style INI file to a json format file.)" "\n"); @@ -71,7 +71,7 @@ void PrintHelp() AZ_Printf("Help", R"( [opt] -json-prefix=: JSON pointer path prefix to anchor the JSON output underneath.)" "\n"); AZ_Printf("Help", R"( On Windows the should be in quotes, as \"/\" is treated as command option prefix)" "\n"); AZ_Printf("Help", R"( [opt] -verbose: Report additional details during the conversion process.)" "\n"); - AZ_Printf("Help", R"( example: 'convertconfig --files=AssetProcessorPlatformConfigIni;bootstrap.cfg --ext=setreg)" "\n"); + AZ_Printf("Help", R"( example: 'convert-ini --files=AssetProcessorPlatformConfig.ini;bootstrap.cfg --ext=setreg)" "\n"); } int main(int argc, char** argv) @@ -79,15 +79,15 @@ int main(int argc, char** argv) using namespace AZ::SerializeContextTools; bool result = false; - Application application(&argc, &argv); + Application application(argc, argv); AZ::ComponentApplication::StartupParameters startupParameters; startupParameters.m_loadDynamicModules = false; - application.Start({}, startupParameters); + application.Create({}, startupParameters); // Load the DynamicModules after the Application starts to prevent Gem System Components // from activating application.LoadDynamicModules(); - const AZ::CommandLine* commandLine = application.GetCommandLine(); + const AZ::CommandLine* commandLine = application.GetAzCommandLine(); if (commandLine->GetNumMiscValues() < 1) { PrintHelp(); @@ -96,23 +96,23 @@ int main(int argc, char** argv) else { const AZStd::string& action = commandLine->GetMiscValue(0); - if (AzFramework::StringFunc::Equal("dumpfiles", action.c_str())) + if (AZ::StringFunc::Equal("dumpfiles", action.c_str())) { result = Dumper::DumpFiles(application); } - else if (AzFramework::StringFunc::Equal("dumpsc", action.c_str())) + else if (AZ::StringFunc::Equal("dumpsc", action.c_str())) { result = Dumper::DumpSerializeContext(application); } - else if (AzFramework::StringFunc::Equal("convert", action.c_str())) + else if (AZ::StringFunc::Equal("convert", action.c_str())) { result = Converter::ConvertObjectStreamFiles(application); } - else if (AzFramework::StringFunc::Equal("convertad", action.c_str())) + else if (AZ::StringFunc::Equal("convertad", action.c_str())) { result = Converter::ConvertApplicationDescriptor(application); } - else if (AzFramework::StringFunc::Equal("convert-ini", action.c_str())) + else if (AZ::StringFunc::Equal("convert-ini", action.c_str())) { result = Converter::ConvertConfigFile(application); } @@ -128,7 +128,7 @@ int main(int argc, char** argv) AZ_Printf("SerializeContextTools", "Processing didn't complete fully as problems were encountered.\n"); } - application.Stop(); + application.Destroy(); return result ? 0 : -1; } diff --git a/Code/Tools/ShaderCacheGen/ShaderCacheGen/ShaderCacheGen.cpp b/Code/Tools/ShaderCacheGen/ShaderCacheGen/ShaderCacheGen.cpp index c44acf9142..b4660d7630 100644 --- a/Code/Tools/ShaderCacheGen/ShaderCacheGen/ShaderCacheGen.cpp +++ b/Code/Tools/ShaderCacheGen/ShaderCacheGen/ShaderCacheGen.cpp @@ -24,8 +24,6 @@ #include -#include - #include #include #include @@ -249,7 +247,6 @@ int main_wrapped(int argc, char* argv[]) COutputPrintSink printSink; SSystemInitParams sip; - CEngineConfig cfg; using PlatformMap = AZStd::unordered_map>; using PlatformMapElement = PlatformMap::value_type; @@ -340,10 +337,6 @@ int main_wrapped(int argc, char* argv[]) return errorCode; } - // Overwrite assets platform so it matches the platform for which we are generating the shaders. - cfg.m_assetPlatform = foundPlatform->first.c_str(); - cfg.CopyToStartupParams(sip); - sip.bShaderCacheGen = true; sip.bDedicatedServer = false; sip.bPreview = false; diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp b/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp index 6cbf949804..a08e6f4d7f 100644 --- a/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp +++ b/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -80,8 +82,11 @@ namespace LUAEditor , m_settingsDialog(nullptr) { initSharedResources(); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::IO::FixedMaxPath engineRootPath; + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); AzQtComponents::StyleManager* m_styleSheet = new AzQtComponents::StyleManager(this); - m_styleSheet->initialize(qApp); + m_styleSheet->initialize(qApp, engineRootPath); LUAViewMessages::Bus::Handler::BusConnect(); diff --git a/Engine/Registry/bootstrap.setreg b/Engine/Registry/bootstrap.setreg new file mode 100644 index 0000000000..b0c954a127 --- /dev/null +++ b/Engine/Registry/bootstrap.setreg @@ -0,0 +1,39 @@ +{ + "Amazon": { + "AzCore": { + "Bootstrap": { + "remote_filesystem": 0, + "provo_remote_filesystem": 0, + "android_remote_filesystem": 0, + "ios_remote_filesystem": 0, + "mac_remote_filesystem": 0, + "assets": "pc", + "android_assets": "es3", + "ios_assets": "ios", + "mac_assets": "osx_gl", + "allowed_list": "", + "remote_ip": "127.0.0.1", + "remote_port": 45643, + "connect_to_remote": 0, + "windows_connect_to_remote": 1, + "provo_connect_to_remote": 1, + "salem_connect_to_remote": 0, + "jasper_connect_to_remote": 0, + "android_connect_to_remote": 0, + "ios_connect_to_remote": 0, + "mac_connect_to_remote": 0, + "wait_for_connect": 0, + "provo_wait_for_connect": 0, + "salem_wait_for_connect": 0, + "jasper_wait_for_connect": 0, + "windows_wait_for_connect": 1, + "android_wait_for_connect": 0, + "ios_wait_for_connect": 0, + "mac_wait_for_connect": 0, + "connect_ap_timeout" : 3, + "launch_ap_timeout": 15, + "wait_ap_ready_timeout": 1200 + } + } + } +} \ No newline at end of file diff --git a/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthResourceMappingConstants.h b/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthResourceMappingConstants.h new file mode 100644 index 0000000000..315e4bdb27 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthResourceMappingConstants.h @@ -0,0 +1,16 @@ +/* +* 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 + +constexpr char CognitoUserPoolIdResourceMappingKey[] = "AWSClientAuth.CognitoUserPoolId"; +constexpr char CognitoAppClientIdResourceMappingKey[] = "AWSClientAuth.CognitoUserPoolAppClientId"; +constexpr char CognitoIdentityPoolIdResourceMappingKey[] = "AWSClientAuth.CognitoIdentityPoolId"; diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AWSCognitoAuthenticationProvider.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AWSCognitoAuthenticationProvider.h index 22722d6f20..09d89f0791 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AWSCognitoAuthenticationProvider.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AWSCognitoAuthenticationProvider.h @@ -23,8 +23,8 @@ namespace AWSClientAuth : public AuthenticationProviderInterface { public: - AWSCognitoAuthenticationProvider(); - virtual ~AWSCognitoAuthenticationProvider(); + AWSCognitoAuthenticationProvider() = default; + virtual ~AWSCognitoAuthenticationProvider() = default; // AuthenticationProviderInterface overrides bool Initialize(AZStd::weak_ptr settingsRegistry) override; @@ -41,8 +41,8 @@ namespace AWSClientAuth void UpdateTokens(const Aws::CognitoIdentityProvider::Model::AuthenticationResultType& authenticationResult); protected: - AZStd::unique_ptr m_settings; AZStd::string m_session; + AZStd::string m_cognitoAppClientId; }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h index a299db1364..1e10e66307 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h @@ -68,35 +68,4 @@ namespace AWSClientAuth ->Field("OAuthTokensURL", &GoogleProviderSetting::m_oAuthTokensURL); } }; - - //! Holds AWS Cognito provider serialized Settings. - class AWSCognitoProviderSetting - { - public: - AWSCognitoProviderSetting() = default; - ~AWSCognitoProviderSetting() = default; - - AZ_TYPE_INFO(AWSCognitoProviderSetting, "{46EF239C-D3CF-4B17-BA68-FD6B3B249305}"); - - AZStd::string m_appClientId; - - static void Reflect(AZ::SerializeContext& context) - { - context.Class() - ->Field("AppClientId", &AWSCognitoProviderSetting::m_appClientId) - ; - - AZ::EditContext* editContext = context.GetEditContext(); - - if (editContext) - { - editContext->Class("AWSCognitoProviderSetting", "AWSCognitoProviderSetting Settings") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Category, "AWSClientAuth") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) - ->DataElement(AZ::Edit::UIHandlers::Default, &AWSCognitoProviderSetting::m_appClientId, "ClientId", "Cognito User Pool App Client Id"); - } - } - }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/OAuthConstants.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/OAuthConstants.h index 8ce1b4d9f8..3b9e1c2c63 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/OAuthConstants.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/OAuthConstants.h @@ -14,27 +14,25 @@ namespace AWSClientAuth { - constexpr char OAUTH_CLIENT_ID_BODY_KEY[] = "client_id"; - constexpr char OAUTH_CLIENT_SECRET_BODY_KEY[] = "client_secret"; - constexpr char OAUTH_DEVICE_CODE_BODY_KEY[] = "device_code"; - constexpr char OAUTH_SCOPE_BODY_KEY[] = "scope"; - constexpr char OAUTH_SCOPE_BODY_VALUE[] = "profile"; - constexpr char OAUTH_GRANT_TYPE_BODY_KEY[] = "grant_type"; - constexpr char OAUTH_REFRESH_TOKEN_BODY_KEY[] = "refresh_token"; - constexpr char OAUTH_REFRESH_TOKEN_BODY_VALUE[] = "refresh_token"; - constexpr char OAUTH_RESPONSE_TYPE_BODY_KEY[] = "response_type"; - - constexpr char OAUTH_CONTENT_TYPE_HEADER_KEY[] = "Content-Type"; - constexpr char OAUTH_CONTENT_TYPE_HEADER_VALUE[] = "application/x-www-form-urlencoded"; - constexpr char OAUTH_CONTENT_LENGTH_HEADER_KEY[] = "Content-Length"; - - constexpr char OAUTH_USER_CODE_RESPONSE_KEY[] = "user_code"; - constexpr char OAUTH_ID_TOKEN_RESPONSE_KEY[] = "id_token"; - constexpr char OAUTH_ACCESS_TOKEN_RESPONSE_KEY[] = "access_token"; - constexpr char OAUTH_REFRESH_TOKEN_RESPONSE_KEY[] = "refresh_token"; - constexpr char OAUTH_EXPIRES_IN_RESPONSE_KEY[] = "expires_in"; - constexpr char OAUTH_ERROR_RESPONSE_KEY[] = "error"; + constexpr char OAuthClientIdBodyKey[] = "client_id"; + constexpr char OAuthClientSecretBodyKey[] = "client_secret"; + constexpr char OAuthDeviceCodeBodyKey[] = "device_code"; + constexpr char OAuthScopeBodyKey[] = "scope"; + constexpr char OAuthScopeBodyValue[] = "profile"; + constexpr char OAuthGrantTypeBodyKey[] = "grant_type"; + constexpr char OAuthRefreshTokenBodyKey[] = "refresh_token"; + constexpr char OAuthRefreshTokenBodyValue[] = "refresh_token"; + constexpr char OAuthResponseTypeBodyKey[] = "response_type"; + constexpr char OAuthContentTypeHeaderKey[] = "Content-Type"; + constexpr char OAuthContentTypeHeaderValue[] = "application/x-www-form-urlencoded"; + constexpr char OAuthContentLengthHeaderKey[] = "Content-Length"; + constexpr char OAuthUserCodeResponseKey[] = "user_code"; + constexpr char OAuthIdTokenResponseKey[] = "id_token"; + constexpr char OAuthAccessTokenResponseKey[] = "access_token"; + constexpr char OAuthRefreshTokenResponseKey[] = "refresh_token"; + constexpr char OAuthExpiresInResponseKey[] = "expires_in"; + constexpr char OAuthErrorResponseKey[] = "error"; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h index 3092fb7298..5100f38c06 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h @@ -12,7 +12,6 @@ #pragma once -#include #include namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h index 37762bf8c7..47982faf9f 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h @@ -13,7 +13,6 @@ #pragma once #include -#include #include #include #include @@ -34,7 +33,7 @@ namespace AWSClientAuth virtual ~AWSCognitoAuthorizationController(); // AWSCognitoAuthorizationRequestsBus interface methods - bool Initialize(const AZStd::string& settingsRegistryPath) override; + bool Initialize() override; void Reset() override; AZStd::string GetIdentityId() override; bool HasPersistedLogins() override; @@ -54,12 +53,15 @@ namespace AWSClientAuth int GetCredentialHandlerOrder() const override; std::shared_ptr GetCredentialsProvider() override; - AZStd::unique_ptr m_settings; std::shared_ptr m_persistentCognitoIdentityProvider; std::shared_ptr m_persistentAnonymousCognitoIdentityProvider; std::shared_ptr m_cognitoCachingCredentialsProvider; std::shared_ptr m_cognitoCachingAnonymousCredentialsProvider; + AZStd::string m_cognitoIdentityPoolId; + AZStd::string m_formattedCognitoUserPoolId; + AZStd::string m_awsAccountId; + private: void PersistLoginsAndRefreshAWSCredentials(const AuthenticationTokens& authenticationTokens); diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationTypes.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationTypes.h deleted file mode 100644 index a053eb1e02..0000000000 --- a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationTypes.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -* 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 - -#include - -namespace AWSClientAuth -{ - //! Holds Cognito Authorization Identity pool settings. - class CognitoAuthorizationSettings - { - public: - - AZ_TYPE_INFO(CognitoAuthorizationSettings, "{2F2080CD-E575-42BD-9717-E42E43C13956}"); - - static void Reflect(AZ::SerializeContext& context) - { - context.Class() - ->Field("CognitoUserPoolId", &CognitoAuthorizationSettings::m_cognitoUserPoolId) - ->Field("LoginWithAmazonId", &CognitoAuthorizationSettings::m_loginWithAmazonId) - ->Field("GoogleId", &CognitoAuthorizationSettings::m_googleId) - ->Field("AWSAccountId", &CognitoAuthorizationSettings::m_awsAccountId) - ->Field("IdentityPoolId", &CognitoAuthorizationSettings::m_cognitoIdentityPoolId); - - AZ::EditContext* editContext = context.GetEditContext(); - - if (editContext) - { - editContext->Class("CognitoAuthorizationSettings", "CognitoAuthorizationSettings") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Category, "AWSClientAuth") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) - ->DataElement(AZ::Edit::UIHandlers::Default, &CognitoAuthorizationSettings::m_cognitoUserPoolId, "CognitoUserPoolId", "Cognito User pool Id") - ->DataElement(AZ::Edit::UIHandlers::Default, &CognitoAuthorizationSettings::m_loginWithAmazonId, "LoginWithAmazonId", "Login with Amazon id. default: www.amazon.com") - ->DataElement(AZ::Edit::UIHandlers::Default, &CognitoAuthorizationSettings::m_googleId, "Google Endpoint", "Google endpoint. default: accounts.google.com") - ->DataElement(AZ::Edit::UIHandlers::Default, &CognitoAuthorizationSettings::m_cognitoUserPoolId, "AWSAccountId", "AWS account Cognito for Cognito identity pool") - ->DataElement(AZ::Edit::UIHandlers::Default, &CognitoAuthorizationSettings::m_cognitoUserPoolId, "IdentityPoolId", "Cognito Identity pool Id") - ; - } - - } - - AZStd::string m_cognitoUserPoolId; - AZStd::string m_loginWithAmazonId = "www.amazon.com"; - AZStd::string m_googleId = "accounts.google.com"; - AZStd::string m_awsAccountId; - AZStd::string m_cognitoIdentityPoolId; - }; -} // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementController.h b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementController.h index 03975ad42e..3dde661bd9 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementController.h +++ b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementController.h @@ -13,7 +13,6 @@ #pragma once #include -#include namespace AWSClientAuth { @@ -27,7 +26,7 @@ namespace AWSClientAuth virtual ~AWSCognitoUserManagementController(); // AWSCognitoUserManagementRequestsBus interface methods - bool Initialize(const AZStd::string& settingsRegistryPath); + bool Initialize() override; void EmailSignUpAsync(const AZStd::string& username, const AZStd::string& password, const AZStd::string& email) override; void PhoneSignUpAsync(const AZStd::string& username, const AZStd::string& password, const AZStd::string& phoneNumber) override; void ConfirmSignUpAsync(const AZStd::string& username, const AZStd::string& confirmationCode) override; @@ -35,8 +34,13 @@ namespace AWSClientAuth void ConfirmForgotPasswordAsync(const AZStd::string& userName, const AZStd::string& confirmationCode, const AZStd::string& newPassword) override; void EnableMFAAsync(const AZStd::string& accessToken) override; - protected: - AZStd::unique_ptr m_settings; + inline const AZStd::string& GetCognitoAppClientId() const + { + return m_cognitoAppClientId; + } + + private: + AZStd::string m_cognitoAppClientId; }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementTypes.h b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementTypes.h deleted file mode 100644 index ad5a59f271..0000000000 --- a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/AWSCognitoUserManagementTypes.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* 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 - -#include - -namespace AWSClientAuth -{ - - //! Holds AWS Cognito user management serialized Settings. - class AWSCognitoUserManagementSetting - { - public: - AWSCognitoUserManagementSetting() = default; - ~AWSCognitoUserManagementSetting() = default; - - AZ_TYPE_INFO(AWSCognitoUserManagementSetting, "{58FC34F1-B84B-4677-B986-45A226F0328D}"); - - AZStd::string m_appClientId; - - static void Reflect(AZ::SerializeContext& context) - { - context.Class() - ->Field("AppClientId", &AWSCognitoUserManagementSetting::m_appClientId) - ; - - AZ::EditContext* editContext = context.GetEditContext(); - - if (editContext) - { - editContext->Class("AWSCognitoUserManagementSetting", "AWSCognitoUserManagementSetting Settings") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Category, "AWSClientAuth") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) - ->DataElement(AZ::Edit::UIHandlers::Default, &AWSCognitoUserManagementSetting::m_appClientId, "ClientId", "Cognito User Pool App Client Id") - ; - } - } - }; -} // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authorization/AWSCognitoAuthorizationBus.h b/Gems/AWSClientAuth/Code/Include/Public/Authorization/AWSCognitoAuthorizationBus.h index bd40a840bd..7cc31c01c6 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authorization/AWSCognitoAuthorizationBus.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authorization/AWSCognitoAuthorizationBus.h @@ -27,7 +27,7 @@ namespace AWSClientAuth //! Initializes settings for Cognito identity pool from settings registry. //! @param settingsRegistryPath Path for the settings registry file to use. - virtual bool Initialize(const AZStd::string& settingsRegistryPath) = 0; + virtual bool Initialize() = 0; //! Once credentials provider are set they cannot be reset. So recreates new Cognito credentials provider on reset. //! Service clients need to be created with the new AWSCredentialsProvider after reset. diff --git a/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h b/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h index 16bbcf5513..89ddf0a999 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h +++ b/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h @@ -24,7 +24,7 @@ namespace AWSClientAuth //! Initialize Cognito User pool. //! @param settingsRegistryPath settingsRegistryPath Path for the settings registry file to use. - virtual bool Initialize(const AZStd::string& settingsRegistryPath) = 0; + virtual bool Initialize() = 0; // Requests interface //! Cognito user pool email sign up start. diff --git a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp index 6727d4a709..885027ef0f 100644 --- a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp +++ b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -25,7 +24,7 @@ namespace AWSClientAuth { - constexpr char SERIALIZE_COMPONENT_NAME[] = "AWSClientAuth"; + constexpr char SerializeComponentName[] = "AWSClientAuth"; void AWSClientAuthSystemComponent::Reflect(AZ::ReflectContext* context) { @@ -41,17 +40,14 @@ namespace AWSClientAuth ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true); } - AWSClientAuth::AWSCognitoProviderSetting::Reflect(*serialize); AWSClientAuth::LWAProviderSetting::Reflect(*serialize); AWSClientAuth::GoogleProviderSetting::Reflect(*serialize); - AWSClientAuth::CognitoAuthorizationSettings::Reflect(*serialize); - AWSClientAuth::AWSCognitoUserManagementSetting::Reflect(*serialize); } if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { behaviorContext->EBus("AuthenticationProviderRequestBus") - ->Attribute(AZ::Script::Attributes::Category, SERIALIZE_COMPONENT_NAME) + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Event("Initialize", &AuthenticationProviderRequestBus::Events::Initialize) ->Event("IsSignedIn", &AuthenticationProviderRequestBus::Events::IsSignedIn) ->Event("GetAuthenticationTokens", &AuthenticationProviderRequestBus::Events::GetAuthenticationTokens) @@ -64,7 +60,7 @@ namespace AWSClientAuth ->Event("SignOut", &AuthenticationProviderRequestBus::Events::SignOut); behaviorContext->EBus("AWSCognitoAuthorizationRequestBus") - ->Attribute(AZ::Script::Attributes::Category, SERIALIZE_COMPONENT_NAME) + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Event("Initialize", &AWSCognitoAuthorizationRequestBus::Events::Initialize) ->Event("Reset", &AWSCognitoAuthorizationRequestBus::Events::Reset) ->Event("GetIdentityId", &AWSCognitoAuthorizationRequestBus::Events::GetIdentityId) @@ -72,7 +68,7 @@ namespace AWSClientAuth ->Event("RequestAWSCredentialsAsync", &AWSCognitoAuthorizationRequestBus::Events::RequestAWSCredentialsAsync); behaviorContext->EBus("AWSCognitoUserManagementRequestBus") - ->Attribute(AZ::Script::Attributes::Category, SERIALIZE_COMPONENT_NAME) + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Event("Initialize", &AWSCognitoUserManagementRequestBus::Events::Initialize) ->Event("EmailSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::EmailSignUpAsync) ->Event("PhoneSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::PhoneSignUpAsync) diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp index 6bcd3b9a7f..eca5ba22c2 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -28,31 +30,18 @@ namespace AWSClientAuth { - - constexpr char COGNITO_IDP_SETTINGS_PATH[] = "/AWS/CognitoIDP"; - constexpr char COGNITO_USERNAME_KEY[] = "USERNAME"; - constexpr char COGNITO_PASSWORD_KEY[] = "PASSWORD"; - constexpr char COGNITO_REFRESH_TOKEN_AUTHPARAM_KEY[] = "REFRESH_TOKEN"; - constexpr char COGNITO_SMS_MFA_CODE_KEY[] = "SMS_MFA_CODE"; - - AWSCognitoAuthenticationProvider::AWSCognitoAuthenticationProvider() - { - m_settings = AZStd::make_unique(); - } - - AWSCognitoAuthenticationProvider::~AWSCognitoAuthenticationProvider() - { - m_settings.reset(); - } + constexpr char CognitoUsernameKey[] = "USERNAME"; + constexpr char CognitoPasswordKey[] = "PASSWORD"; + constexpr char CognitoRefreshTokenAuthParamKey[] = "REFRESH_TOKEN"; + constexpr char CognitoSmsMfaCodeKey[] = "SMS_MFA_CODE"; bool AWSCognitoAuthenticationProvider::Initialize(AZStd::weak_ptr settingsRegistry) { - if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), COGNITO_IDP_SETTINGS_PATH)) - { - AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get settings object for path %s", COGNITO_IDP_SETTINGS_PATH); - return false; - } - return true; + AZ_UNUSED(settingsRegistry); + AWSCore::AWSResourceMappingRequestBus::BroadcastResult( + m_cognitoAppClientId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoAppClientIdResourceMappingKey); + AZ_Warning("AWSCognitoAuthenticationProvider", m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); + return !m_cognitoAppClientId.empty(); } @@ -128,9 +117,9 @@ namespace AWSClientAuth // Set Request parameters for SMS Multi factor authentication. // Note: Email MFA is no longer supported by Cognito, use SMS as MFA Aws::CognitoIdentityProvider::Model::RespondToAuthChallengeRequest respondToAuthChallengeRequest; - respondToAuthChallengeRequest.SetClientId(m_settings->m_appClientId.c_str()); - respondToAuthChallengeRequest.AddChallengeResponses(COGNITO_SMS_MFA_CODE_KEY, confirmationCode.c_str()); - respondToAuthChallengeRequest.AddChallengeResponses(COGNITO_USERNAME_KEY, username.c_str()); + respondToAuthChallengeRequest.SetClientId(m_cognitoAppClientId.c_str()); + respondToAuthChallengeRequest.AddChallengeResponses(CognitoSmsMfaCodeKey, confirmationCode.c_str()); + respondToAuthChallengeRequest.AddChallengeResponses(CognitoUsernameKey, username.c_str()); respondToAuthChallengeRequest.SetChallengeName(Aws::CognitoIdentityProvider::Model::ChallengeNameType::SMS_MFA); respondToAuthChallengeRequest.SetSession(m_session.c_str()); @@ -177,13 +166,13 @@ namespace AWSClientAuth { // Set Request parameters. Aws::CognitoIdentityProvider::Model::InitiateAuthRequest initiateAuthRequest; - initiateAuthRequest.SetClientId(m_settings->m_appClientId.c_str()); + initiateAuthRequest.SetClientId(m_cognitoAppClientId.c_str()); initiateAuthRequest.SetAuthFlow(Aws::CognitoIdentityProvider::Model::AuthFlowType::REFRESH_TOKEN_AUTH); // Set username and password for Password grant/ Initiate Auth flow. Aws::Map authParameters { - {COGNITO_REFRESH_TOKEN_AUTHPARAM_KEY, GetAuthenticationTokens().GetRefreshToken().c_str()} + {CognitoRefreshTokenAuthParamKey, GetAuthenticationTokens().GetRefreshToken().c_str()} }; initiateAuthRequest.SetAuthParameters(authParameters); @@ -228,14 +217,14 @@ namespace AWSClientAuth { // Set Request parameters. Aws::CognitoIdentityProvider::Model::InitiateAuthRequest initiateAuthRequest; - initiateAuthRequest.SetClientId(m_settings->m_appClientId.c_str()); + initiateAuthRequest.SetClientId(m_cognitoAppClientId.c_str()); initiateAuthRequest.SetAuthFlow(Aws::CognitoIdentityProvider::Model::AuthFlowType::USER_PASSWORD_AUTH); // Set username and password for Password grant/ Initiate Auth flow. Aws::Map authParameters { - {COGNITO_USERNAME_KEY, username.c_str()}, - {COGNITO_PASSWORD_KEY, password.c_str()} + {CognitoUsernameKey, username.c_str()}, + {CognitoPasswordKey, password.c_str()} }; initiateAuthRequest.SetAuthParameters(authParameters); diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp index 74926d6f83..7762b3919b 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp @@ -22,8 +22,8 @@ namespace AWSClientAuth { - constexpr char GOOGLE_SETTINGS_PATH[] = "/AWS/Google"; - constexpr char GOOGLE_VERIFICATION_URL_RESPONSE_KEY[] = "verification_url"; + constexpr char GoogleSettingsPath[] = "/AWS/Google"; + constexpr char GoogleVerificationUrlResponseKey[] = "verification_url"; GoogleAuthenticationProvider::GoogleAuthenticationProvider() { @@ -37,9 +37,9 @@ namespace AWSClientAuth bool GoogleAuthenticationProvider::Initialize(AZStd::weak_ptr settingsRegistry) { - if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), GOOGLE_SETTINGS_PATH)) + if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), GoogleSettingsPath)) { - AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get Google settings object for path %s", GOOGLE_SETTINGS_PATH); + AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get Google settings object for path %s", GoogleSettingsPath); return false; } return true; @@ -70,13 +70,13 @@ namespace AWSClientAuth // Refer https://developers.google.com/identity/protocols/oauth2/limited-input-device#step-1:-request-device-and-user-codes. void GoogleAuthenticationProvider::DeviceCodeGrantSignInAsync() { - AZStd::string body = AZStd::string::format("%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str() - , OAUTH_SCOPE_BODY_KEY, OAUTH_SCOPE_BODY_VALUE); + AZStd::string body = AZStd::string::format("%s=%s&%s=%s", OAuthClientIdBodyKey, m_settings->m_appClientId.c_str() + , OAuthScopeBodyKey, OAuthScopeBodyValue); // Set headers and body for device sign in http requests. AZStd::map headers; - headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE; - headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length()); + headers[OAuthContentTypeHeaderKey] = OAuthContentTypeHeaderValue; + headers[OAuthContentLengthHeaderKey] = AZStd::to_string(body.length()); HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthCodeURL , Aws::Http::HttpMethod::HTTP_POST, headers, body @@ -84,15 +84,15 @@ namespace AWSClientAuth { if (responseCode == Aws::Http::HttpResponseCode::OK) { - m_cachedDeviceCode = jsonView.GetString(OAUTH_DEVICE_CODE_BODY_KEY).c_str(); + m_cachedDeviceCode = jsonView.GetString(OAuthDeviceCodeBodyKey).c_str(); AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInSuccess - , jsonView.GetString(OAUTH_USER_CODE_RESPONSE_KEY).c_str(), jsonView.GetString(GOOGLE_VERIFICATION_URL_RESPONSE_KEY).c_str() - , jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY)); + , jsonView.GetString(OAuthUserCodeResponseKey).c_str(), jsonView.GetString(GoogleVerificationUrlResponseKey).c_str() + , jsonView.GetInteger(OAuthExpiresInResponseKey)); } else { AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInFail - , jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str()); + , jsonView.GetString(OAuthErrorResponseKey).c_str()); } } ); @@ -105,12 +105,12 @@ namespace AWSClientAuth { // Set headers and body for device confirm sign in http requests. AZStd::map headers; - AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str() - , OAUTH_CLIENT_SECRET_BODY_KEY, m_settings->m_clientSecret.c_str(), OAUTH_DEVICE_CODE_BODY_KEY, m_cachedDeviceCode.c_str() - , OAUTH_GRANT_TYPE_BODY_KEY, m_settings->m_grantType.c_str()); + AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s&%s=%s", OAuthClientIdBodyKey, m_settings->m_appClientId.c_str() + , OAuthClientSecretBodyKey, m_settings->m_clientSecret.c_str(), OAuthDeviceCodeBodyKey, m_cachedDeviceCode.c_str() + , OAuthGrantTypeBodyKey, m_settings->m_grantType.c_str()); - headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE; - headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length()); + headers[OAuthContentTypeHeaderKey] = OAuthContentTypeHeaderValue; + headers[OAuthContentLengthHeaderKey] = AZStd::to_string(body.length()); HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL , Aws::Http::HttpMethod::HTTP_POST, headers, body @@ -125,7 +125,7 @@ namespace AWSClientAuth else { AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantConfirmSignInFail - , jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str()); + , jsonView.GetString(OAuthErrorResponseKey).c_str()); } } ); @@ -136,12 +136,12 @@ namespace AWSClientAuth void GoogleAuthenticationProvider::RefreshTokensAsync() { AZStd::map headers; - AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str() - , OAUTH_CLIENT_SECRET_BODY_KEY, m_settings->m_clientSecret.c_str() - , OAUTH_GRANT_TYPE_BODY_KEY, OAUTH_REFRESH_TOKEN_BODY_VALUE, OAUTH_REFRESH_TOKEN_BODY_KEY, m_authenticationTokens.GetRefreshToken().c_str()); + AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s&%s=%s", OAuthClientIdBodyKey, m_settings->m_appClientId.c_str() + , OAuthClientSecretBodyKey, m_settings->m_clientSecret.c_str() + , OAuthGrantTypeBodyKey, OAuthRefreshTokenBodyValue, OAuthRefreshTokenBodyKey, m_authenticationTokens.GetRefreshToken().c_str()); - headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE; - headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length()); + headers[OAuthContentTypeHeaderKey] = OAuthContentTypeHeaderValue; + headers[OAuthContentLengthHeaderKey] = AZStd::to_string(body.length()); HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL , Aws::Http::HttpMethod::HTTP_POST, headers, body @@ -156,7 +156,7 @@ namespace AWSClientAuth else { AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail - , jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str()); + , jsonView.GetString(OAuthErrorResponseKey).c_str()); } } ); @@ -164,9 +164,9 @@ namespace AWSClientAuth void GoogleAuthenticationProvider::UpdateTokens(const Aws::Utils::Json::JsonView& jsonView) { - m_authenticationTokens = AuthenticationTokens(jsonView.GetString(OAUTH_ACCESS_TOKEN_RESPONSE_KEY).c_str(), - jsonView.GetString(OAUTH_REFRESH_TOKEN_RESPONSE_KEY).c_str() ,jsonView.GetString(OAUTH_ID_TOKEN_RESPONSE_KEY).c_str(), ProviderNameEnum::Google - , jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY)); + m_authenticationTokens = AuthenticationTokens(jsonView.GetString(OAuthAccessTokenResponseKey).c_str(), + jsonView.GetString(OAuthRefreshTokenResponseKey).c_str() ,jsonView.GetString(OAuthIdTokenResponseKey).c_str(), ProviderNameEnum::Google + , jsonView.GetInteger(OAuthExpiresInResponseKey)); } } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp index 3e3ff3f348..a86e01a58e 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp @@ -21,8 +21,8 @@ namespace AWSClientAuth { - constexpr char LWA_SETTINGS_PATH[] = "/AWS/LoginWithAmazon"; - constexpr char LWA_VERIFICATION_URL_RESPONSE_KEY[] = "verification_uri"; + constexpr char LwaSettingsPath[] = "/AWS/LoginWithAmazon"; + constexpr char LwaVerificationUrlResponseKey[] = "verification_uri"; LWAAuthenticationProvider::LWAAuthenticationProvider() { @@ -36,9 +36,9 @@ namespace AWSClientAuth bool LWAAuthenticationProvider::Initialize(AZStd::weak_ptr settingsRegistry) { - if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), LWA_SETTINGS_PATH)) + if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), LwaSettingsPath)) { - AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get login with Amazon settings object for path %s", LWA_SETTINGS_PATH); + AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get login with Amazon settings object for path %s", LwaSettingsPath); return false; } return true; @@ -70,12 +70,12 @@ namespace AWSClientAuth void LWAAuthenticationProvider::DeviceCodeGrantSignInAsync() { // Set headers and body for device sign in http requests. - AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAUTH_RESPONSE_TYPE_BODY_KEY, m_settings->m_responseType.c_str() - , OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str(), OAUTH_SCOPE_BODY_KEY, OAUTH_SCOPE_BODY_VALUE); + AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAuthResponseTypeBodyKey, m_settings->m_responseType.c_str() + , OAuthClientIdBodyKey, m_settings->m_appClientId.c_str(), OAuthScopeBodyKey, OAuthScopeBodyValue); AZStd::map headers; - headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE; - headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length()); + headers[OAuthContentTypeHeaderKey] = OAuthContentTypeHeaderValue; + headers[OAuthContentLengthHeaderKey] = AZStd::to_string(body.length()); HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthCodeURL , Aws::Http::HttpMethod::HTTP_POST, headers, body @@ -83,17 +83,17 @@ namespace AWSClientAuth { if (responseCode == Aws::Http::HttpResponseCode::OK) { - m_cachedUserCode = jsonView.GetString(OAUTH_USER_CODE_RESPONSE_KEY).c_str(); - m_cachedDeviceCode = jsonView.GetString(OAUTH_DEVICE_CODE_BODY_KEY).c_str(); + m_cachedUserCode = jsonView.GetString(OAuthUserCodeResponseKey).c_str(); + m_cachedDeviceCode = jsonView.GetString(OAuthDeviceCodeBodyKey).c_str(); AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInSuccess - , jsonView.GetString(OAUTH_USER_CODE_RESPONSE_KEY).c_str() - , jsonView.GetString(LWA_VERIFICATION_URL_RESPONSE_KEY).c_str() - , jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY)); + , jsonView.GetString(OAuthUserCodeResponseKey).c_str() + , jsonView.GetString(LwaVerificationUrlResponseKey).c_str() + , jsonView.GetInteger(OAuthExpiresInResponseKey)); } else { AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInFail - , jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str()); + , jsonView.GetString(OAuthErrorResponseKey).c_str()); } } ); @@ -104,12 +104,12 @@ namespace AWSClientAuth void LWAAuthenticationProvider::DeviceCodeGrantConfirmSignInAsync() { // Set headers and body for device confirm sign in http requests. - AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAUTH_USER_CODE_RESPONSE_KEY, m_cachedUserCode.c_str() - , OAUTH_GRANT_TYPE_BODY_KEY, m_settings->m_grantType.c_str(), OAUTH_DEVICE_CODE_BODY_KEY, m_cachedDeviceCode.c_str()); + AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAuthUserCodeResponseKey, m_cachedUserCode.c_str() + , OAuthGrantTypeBodyKey, m_settings->m_grantType.c_str(), OAuthDeviceCodeBodyKey, m_cachedDeviceCode.c_str()); AZStd::map headers; - headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE; - headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length()); + headers[OAuthContentTypeHeaderKey] = OAuthContentTypeHeaderValue; + headers[OAuthContentLengthHeaderKey] = AZStd::to_string(body.length()); HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL , Aws::Http::HttpMethod::HTTP_POST, headers, body @@ -136,12 +136,12 @@ namespace AWSClientAuth void LWAAuthenticationProvider::RefreshTokensAsync() { // Set headers and body for device confirm sign in http requests. - AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str(), OAUTH_GRANT_TYPE_BODY_KEY, - OAUTH_REFRESH_TOKEN_BODY_VALUE, OAUTH_REFRESH_TOKEN_BODY_KEY, m_authenticationTokens.GetRefreshToken().c_str()); + AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAuthClientIdBodyKey, m_settings->m_appClientId.c_str(), OAuthGrantTypeBodyKey, + OAuthRefreshTokenBodyValue, OAuthRefreshTokenBodyKey, m_authenticationTokens.GetRefreshToken().c_str()); AZStd::map headers; - headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE; - headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length()); + headers[OAuthContentTypeHeaderKey] = OAuthContentTypeHeaderValue; + headers[OAuthContentLengthHeaderKey] = AZStd::to_string(body.length()); HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL , Aws::Http::HttpMethod::HTTP_POST, headers, body @@ -165,9 +165,9 @@ namespace AWSClientAuth void LWAAuthenticationProvider::UpdateTokens(const Aws::Utils::Json::JsonView& jsonView) { // For Login with Amazon openId and access tokens are the same. - m_authenticationTokens = AuthenticationTokens(jsonView.GetString(OAUTH_ACCESS_TOKEN_RESPONSE_KEY).c_str(), jsonView.GetString(OAUTH_REFRESH_TOKEN_RESPONSE_KEY).c_str(), - jsonView.GetString(OAUTH_ACCESS_TOKEN_RESPONSE_KEY).c_str(), ProviderNameEnum::LoginWithAmazon - , jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY)); + m_authenticationTokens = AuthenticationTokens(jsonView.GetString(OAuthAccessTokenResponseKey).c_str(), jsonView.GetString(OAuthRefreshTokenResponseKey).c_str(), + jsonView.GetString(OAuthAccessTokenResponseKey).c_str(), ProviderNameEnum::LoginWithAmazon + , jsonView.GetInteger(OAuthExpiresInResponseKey)); } } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp index 95d4725ef1..4c10d968fc 100644 --- a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp @@ -13,6 +13,9 @@ #include #include #include +#include +#include + #include #include #include @@ -22,7 +25,9 @@ namespace AWSClientAuth { - constexpr char COGNITO_AUTHORIZATION_SETTINGS_PATH[] = "/AWS/CognitoIdentityPool"; + constexpr char CognitoAmazonLoginsId[] = "www.amazon.com"; + constexpr char CognitoGoogleLoginsId[] = "accounts.google.com"; + constexpr char CognitoUserPoolIdFormat[] = "cognito-idp.%s.amazonaws.com/%s"; AWSCognitoAuthorizationController::AWSCognitoAuthorizationController() { @@ -31,8 +36,6 @@ namespace AWSClientAuth AuthenticationProviderNotificationBus::Handler::BusConnect(); AWSCore::AWSCredentialRequestBus::Handler::BusConnect(); - m_settings = AZStd::make_unique(); - m_persistentCognitoIdentityProvider = std::make_shared(); m_persistentAnonymousCognitoIdentityProvider = std::make_shared(); @@ -52,32 +55,39 @@ namespace AWSClientAuth m_persistentCognitoIdentityProvider.reset(); m_persistentAnonymousCognitoIdentityProvider.reset(); - m_settings.reset(); - AWSCore::AWSCredentialRequestBus::Handler::BusDisconnect(); AuthenticationProviderNotificationBus::Handler::BusDisconnect(); AWSCognitoAuthorizationRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); } - bool AWSCognitoAuthorizationController::Initialize(const AZStd::string& settingsRegistryPath) + bool AWSCognitoAuthorizationController::Initialize() { - AZStd::unique_ptr settingsRegistry = AZStd::make_unique(); + AWSCore::AWSResourceMappingRequestBus::BroadcastResult( + m_awsAccountId, &AWSCore::AWSResourceMappingRequests::GetDefaultAccountId); - if (!settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch)) - { - AZ_Error("AWSCognitoAuthorizationController", true, "Failed to merge settings file for path %s", settingsRegistryPath.c_str()); - return false; - } + AWSCore::AWSResourceMappingRequestBus::BroadcastResult( + m_cognitoIdentityPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoIdentityPoolIdResourceMappingKey); - if (!settingsRegistry->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), COGNITO_AUTHORIZATION_SETTINGS_PATH)) + if (m_awsAccountId.empty() || m_cognitoIdentityPoolId.empty()) { - AZ_Error("AWSCognitoAuthorizationController", true, "Failed to get settings object for path %s", COGNITO_AUTHORIZATION_SETTINGS_PATH); + AZ_Warning("AWSCognitoUserManagementController", m_awsAccountId.empty(), "Missing AWS account id in resource mappings."); + AZ_Warning("AWSCognitoUserManagementController", m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings."); return false; } - m_persistentCognitoIdentityProvider->Initialize(m_settings->m_awsAccountId.c_str(), m_settings->m_cognitoIdentityPoolId.c_str()); - m_persistentAnonymousCognitoIdentityProvider->Initialize(m_settings->m_awsAccountId.c_str(), m_settings->m_cognitoIdentityPoolId.c_str()); + AZStd::string userPoolId; + AWSCore::AWSResourceMappingRequestBus::BroadcastResult( + userPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoUserPoolIdResourceMappingKey); + AZ_Warning("AWSCognitoUserManagementController", userPoolId.empty(), "Missing Cognito USer pool id in resource mappings. Cognito IDP authenticated identities will no work."); + + AZStd::string defaultRegion; + AWSCore::AWSResourceMappingRequestBus::BroadcastResult( + defaultRegion, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion); + m_formattedCognitoUserPoolId = AZStd::string::format(CognitoUserPoolIdFormat, defaultRegion.c_str(), userPoolId.c_str()); + + m_persistentCognitoIdentityProvider->Initialize(m_awsAccountId.c_str(), m_cognitoIdentityPoolId.c_str()); + m_persistentAnonymousCognitoIdentityProvider->Initialize(m_awsAccountId.c_str(), m_cognitoIdentityPoolId.c_str()); return true; } @@ -182,15 +192,15 @@ namespace AWSClientAuth { case ProviderNameEnum::AWSCognitoIDP: { - return m_settings->m_cognitoUserPoolId; + return m_formattedCognitoUserPoolId; } case ProviderNameEnum::LoginWithAmazon: { - return m_settings->m_loginWithAmazonId; + return CognitoAmazonLoginsId; } case ProviderNameEnum::Google: { - return m_settings->m_googleId; + return CognitoGoogleLoginsId; } default: { diff --git a/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp b/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp index 3cc251d2de..19d5d47d33 100644 --- a/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp +++ b/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp @@ -14,7 +14,9 @@ #include #include +#include #include +#include #include #include @@ -35,41 +37,25 @@ namespace AWSClientAuth { - constexpr char COGNITO_USER_POOL[] = "/AWS/CognitoUserPool"; - AWSCognitoUserManagementController::AWSCognitoUserManagementController() { AZ::Interface::Register(this); AWSCognitoUserManagementRequestBus::Handler::BusConnect(); - - m_settings = AZStd::make_unique(); } AWSCognitoUserManagementController::~AWSCognitoUserManagementController() { - m_settings.reset(); - AWSCognitoUserManagementRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); } - bool AWSCognitoUserManagementController::Initialize(const AZStd::string& settingsRegistryPath) + bool AWSCognitoUserManagementController::Initialize() { - AZStd::unique_ptr settingsRegistry = AZStd::make_unique(); - - if (!settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch)) - { - AZ_Error("AWSCognitoUserManagementController", true, "Failed to merge settings file for path %s", settingsRegistryPath.c_str()); - return false; - } - - if (!settingsRegistry->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), COGNITO_USER_POOL)) - { - AZ_Error("AWSCognitoUserManagementController", true, "Failed to get settings object for path %s", COGNITO_USER_POOL); - return false; - } - - return true; + AWSCore::AWSResourceMappingRequestBus::BroadcastResult( + m_cognitoAppClientId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoAppClientIdResourceMappingKey); + AZ_Warning( + "AWSCognitoUserManagementController", m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); + return !m_cognitoAppClientId.empty(); } // Call Cognito user pool sign up using email. Confirmation code sent to the email set. @@ -85,7 +71,7 @@ namespace AWSClientAuth AZ::Job* emailSignUpJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, password, email]() { Aws::CognitoIdentityProvider::Model::SignUpRequest signUpRequest; - signUpRequest.SetClientId(m_settings->m_appClientId.c_str()); + signUpRequest.SetClientId(m_cognitoAppClientId.c_str()); signUpRequest.SetUsername(username.c_str()); signUpRequest.SetPassword(password.c_str()); @@ -123,7 +109,7 @@ namespace AWSClientAuth AZ::Job* phoneSignUpJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, password, phoneNumber]() { Aws::CognitoIdentityProvider::Model::SignUpRequest signUpRequest; - signUpRequest.SetClientId(m_settings->m_appClientId.c_str()); + signUpRequest.SetClientId(m_cognitoAppClientId.c_str()); signUpRequest.SetUsername(username.c_str()); signUpRequest.SetPassword(password.c_str()); @@ -163,7 +149,7 @@ namespace AWSClientAuth AZ::Job* confirmSignUpJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, confirmationCode]() { Aws::CognitoIdentityProvider::Model::ConfirmSignUpRequest confirmSignupRequest; - confirmSignupRequest.SetClientId(m_settings->m_appClientId.c_str()); + confirmSignupRequest.SetClientId(m_cognitoAppClientId.c_str()); confirmSignupRequest.SetUsername(username.c_str()); confirmSignupRequest.SetConfirmationCode(confirmationCode.c_str()); @@ -192,7 +178,7 @@ namespace AWSClientAuth AZ::Job* forgotPasswordJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username]() { Aws::CognitoIdentityProvider::Model::ForgotPasswordRequest forgotPasswordRequest; - forgotPasswordRequest.SetClientId(m_settings->m_appClientId.c_str()); + forgotPasswordRequest.SetClientId(m_cognitoAppClientId.c_str()); forgotPasswordRequest.SetUsername(username.c_str()); Aws::CognitoIdentityProvider::Model::ForgotPasswordOutcome forgotPasswordOutcome{ cognitoIdentityProviderClient->ForgotPassword(forgotPasswordRequest) }; @@ -220,7 +206,7 @@ namespace AWSClientAuth AZ::Job* confirmForgotPasswordJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, confirmationCode, newPassword]() { Aws::CognitoIdentityProvider::Model::ConfirmForgotPasswordRequest confirmForgotPasswordRequest; - confirmForgotPasswordRequest.SetClientId(m_settings->m_appClientId.c_str()); + confirmForgotPasswordRequest.SetClientId(m_cognitoAppClientId.c_str()); confirmForgotPasswordRequest.SetUsername(username.c_str()); confirmForgotPasswordRequest.SetConfirmationCode(confirmationCode.c_str()); confirmForgotPasswordRequest.SetPassword(newPassword.c_str()); diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h index 698070bd68..70b32443cc 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -68,13 +69,14 @@ namespace AWSClientAuthUnitTest constexpr char TEST_PASSWORD[] = "TestPassword"; constexpr char TEST_NEW_PASSWORD[] = "TestNewPassword"; constexpr char TEST_CODE[] = "TestCode"; + constexpr char TEST_REGION[] = "us-east-1"; constexpr char TEST_EMAIL[] = "test@test.com"; constexpr char TEST_PHONE[] = "+11234567890"; constexpr char TEST_COGNITO_CLIENTID[] = "TestCognitoClientId"; constexpr char TEST_EXCEPTION[] = "TestException"; constexpr char TEST_SESSION[] = "TestSession"; constexpr char TEST_TOKEN[] = "TestToken"; - constexpr char TEST_ACCOUNT_ID[] = "1234567890"; + constexpr char TEST_ACCOUNT_ID[] = "TestAccountId"; constexpr char TEST_IDENTITY_POOL_ID[] = "TestIdenitityPoolId"; constexpr char TEST_IDENTITY_ID[] = "TestIdenitityId"; constexpr char TEST_ACCESS_TOKEN[] = "TestAccessToken"; @@ -82,6 +84,39 @@ namespace AWSClientAuthUnitTest constexpr char TEST_ID_TOKEN[] = "TestIdToken"; constexpr char TEST_ACCESS_KEY_ID[] = "TestAccessKeyId"; constexpr char TEST_SECRET_KEY_ID[] = "TestSecretKeyId"; + constexpr char TEST_RESOURCE_NAME_ID[] = "TestResourceNameId"; + + class AWSResourceMappingRequestBusMock + : public AWSCore::AWSResourceMappingRequestBus::Handler + { + public: + AWSResourceMappingRequestBusMock() + { + AWSCore::AWSResourceMappingRequestBus::Handler::BusConnect(); + + ON_CALL(*this, GetResourceRegion).WillByDefault(testing::Return(TEST_REGION)); + ON_CALL(*this, GetDefaultAccountId).WillByDefault(testing::Return(TEST_ACCOUNT_ID)); + ON_CALL(*this, GetResourceAccountId).WillByDefault(testing::Return(TEST_ACCOUNT_ID)); + ON_CALL(*this, GetResourceNameId).WillByDefault(testing::Return(TEST_RESOURCE_NAME_ID)); + ON_CALL(*this, GetDefaultRegion).WillByDefault(testing::Return(TEST_REGION)); + } + ~AWSResourceMappingRequestBusMock() + { + AWSCore::AWSResourceMappingRequestBus::Handler::BusDisconnect(); + } + + MOCK_CONST_METHOD0(GetDefaultAccountId, AZStd::string()); + MOCK_CONST_METHOD0(GetDefaultRegion, AZStd::string()); + MOCK_CONST_METHOD1(GetResourceAccountId, AZStd::string(const AZStd::string& resourceKeyName)); + MOCK_CONST_METHOD1(GetResourceNameId, AZStd::string(const AZStd::string& resourceKeyName)); + MOCK_CONST_METHOD1(GetResourceRegion, AZStd::string(const AZStd::string& resourceKeyName)); + MOCK_CONST_METHOD1(GetResourceType, AZStd::string(const AZStd::string& resourceKeyName)); + MOCK_CONST_METHOD1(GetServiceUrlByServiceName, AZStd::string(const AZStd::string& serviceName)); + MOCK_CONST_METHOD2( + GetServiceUrlByRESTApiIdAndStage, + AZStd::string(const AZStd::string& restApiIdKeyName, const AZStd::string& restApiStageKeyName)); + MOCK_METHOD1(ReloadConfigFile, void(bool isReloadingConfigFileName)); + }; class HttpRequestorRequestBusMock : public HttpRequestor::HttpRequestorRequestBus::Handler @@ -545,6 +580,7 @@ namespace AWSClientAuthUnitTest AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthSystemComponentTest.cpp b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthSystemComponentTest.cpp index 47ffe7e01e..923d11539a 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthSystemComponentTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthSystemComponentTest.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -119,33 +118,6 @@ namespace AWSClientAuthUnitTest }; } -class AWSResourceMappingRequestBusMock - : public AWSCore::AWSResourceMappingRequestBus::Handler -{ -public: - AWSResourceMappingRequestBusMock() - { - AWSCore::AWSResourceMappingRequestBus::Handler::BusConnect(); - - ON_CALL(*this, GetResourceRegion).WillByDefault(testing::Return("us-east-1")); - } - ~AWSResourceMappingRequestBusMock() - { - AWSCore::AWSResourceMappingRequestBus::Handler::BusDisconnect(); - } - - MOCK_CONST_METHOD0(GetDefaultAccountId, AZStd::string()); - MOCK_CONST_METHOD0(GetDefaultRegion, AZStd::string()); - MOCK_CONST_METHOD1(GetResourceAccountId, AZStd::string(const AZStd::string& resourceKeyName)); - MOCK_CONST_METHOD1(GetResourceNameId, AZStd::string(const AZStd::string& resourceKeyName)); - MOCK_CONST_METHOD1(GetResourceRegion, AZStd::string(const AZStd::string& resourceKeyName)); - MOCK_CONST_METHOD1(GetResourceType, AZStd::string(const AZStd::string& resourceKeyName)); - MOCK_CONST_METHOD1(GetServiceUrlByServiceName, AZStd::string(const AZStd::string& serviceName)); - MOCK_CONST_METHOD2( - GetServiceUrlByRESTApiIdAndStage, AZStd::string(const AZStd::string& restApiIdKeyName, const AZStd::string& restApiStageKeyName)); - MOCK_METHOD1(ReloadConfigFile, void(bool isReloadingConfigFileName)); -}; - class AWSClientAuthSystemComponentTest : public AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture { @@ -193,7 +165,7 @@ protected: public: testing::NiceMock *m_awsClientAuthSystemsComponent; testing::NiceMock *m_awsCoreSystemsComponent; - testing::NiceMock m_awsResourceMappingRequestBusMock; + testing::NiceMock m_awsResourceMappingRequestBusMock; AZ::Entity* m_entity = nullptr; }; diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AWSCognitoAuthenticationProviderTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AWSCognitoAuthenticationProviderTest.cpp index dbff5127f6..25686561ed 100644 --- a/Gems/AWSClientAuth/Code/Tests/Authentication/AWSCognitoAuthenticationProviderTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AWSCognitoAuthenticationProviderTest.cpp @@ -24,7 +24,7 @@ namespace AWSClientAuthUnitTest : public AWSClientAuth::AWSCognitoAuthenticationProvider { public: - using AWSClientAuth::AWSCognitoAuthenticationProvider::m_settings; + using AWSClientAuth::AWSCognitoAuthenticationProvider::m_cognitoAppClientId; }; } @@ -36,22 +36,6 @@ class AWSCognitoAuthenticationProviderTest { AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::SetUp(); - AWSClientAuth::AWSCognitoProviderSetting::Reflect(*m_serializeContext); - - AZStd::string path = AZStd::string::format("%s/%s/authenticationProvider.setreg", - m_testFolder->c_str(), AZ::SettingsRegistryInterface::RegistryFolder); - CreateTestFile("authenticationProvider.setreg" - , R"({ - "AWS": - { - "CognitoIDP": - { - "AppClientId": "TestCognitoClientId" - } - } - })"); - m_settingsRegistry->MergeSettingsFile(path, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}); - m_cognitoAuthenticationProviderMock.Initialize(m_settingsRegistry); AWSCore::AWSCoreRequestBus::Handler::BusConnect(); @@ -78,6 +62,7 @@ class AWSCognitoAuthenticationProviderTest public: AWSClientAuthUnitTest::AWSCognitoAuthenticationProviderrLocalMock m_cognitoAuthenticationProviderMock; + testing::NiceMock m_awsResourceMappingRequestBusMock; void AssertAuthenticationTokensPopulated() { @@ -116,9 +101,10 @@ public: TEST_F(AWSCognitoAuthenticationProviderTest, Initialize_Success) { + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1); AWSClientAuthUnitTest::AWSCognitoAuthenticationProviderrLocalMock mock; ASSERT_TRUE(mock.Initialize(m_settingsRegistry)); - ASSERT_EQ(mock.m_settings->m_appClientId, AWSClientAuthUnitTest::TEST_COGNITO_CLIENTID); + ASSERT_EQ(mock.m_cognitoAppClientId, AWSClientAuthUnitTest::TEST_RESOURCE_NAME_ID); } TEST_F(AWSCognitoAuthenticationProviderTest, PasswordGrantSingleFactorSignInAsync_Success) @@ -275,15 +261,9 @@ TEST_F(AWSCognitoAuthenticationProviderTest, SignOut_Success) AssertAuthenticationTokensEmpty(); } -TEST_F(AWSCognitoAuthenticationProviderTest, Initialize_Fail_EmptyRegistry) +TEST_F(AWSCognitoAuthenticationProviderTest, Initialize_Fail_EmptyResourceName) { AWSClientAuthUnitTest::AWSCognitoAuthenticationProviderrLocalMock mock; - AZStd::shared_ptr registry = AZStd::make_shared(); - registry->SetContext(m_serializeContext.get()); - ASSERT_FALSE(mock.Initialize(registry)); - ASSERT_EQ(mock.m_settings->m_appClientId, ""); - registry.reset(); - - // Restore - mock.Initialize(m_settingsRegistry); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1).WillOnce(testing::Return("")); + ASSERT_FALSE(mock.Initialize(m_settingsRegistry)); } diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp index a01d870ebb..2f58019774 100644 --- a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp @@ -66,7 +66,6 @@ protected: { AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::SetUp(); - AWSClientAuth::AWSCognitoProviderSetting::Reflect(*m_serializeContext); AWSClientAuth::LWAProviderSetting::Reflect(*m_serializeContext); AWSClientAuth::GoogleProviderSetting::Reflect(*m_serializeContext); @@ -93,10 +92,6 @@ protected: "Scope": "profile", "OAuthCodeURL": "https://oauth2.googleapis.com/device/code", "OAuthTokensURL": "https://oauth2.googleapis.com/token" - }, - "CognitoIDP": - { - "AppClientId": "TestCognitoClientId" } } })"); diff --git a/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp index 2bd8f0f1ae..cfaa057735 100644 --- a/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp @@ -24,11 +24,13 @@ namespace AWSClientAuthUnitTest { public: - using AWSClientAuth::AWSCognitoAuthorizationController::m_settings; using AWSClientAuth::AWSCognitoAuthorizationController::m_persistentCognitoIdentityProvider; using AWSClientAuth::AWSCognitoAuthorizationController::m_persistentAnonymousCognitoIdentityProvider; using AWSClientAuth::AWSCognitoAuthorizationController::m_cognitoCachingCredentialsProvider; using AWSClientAuth::AWSCognitoAuthorizationController::m_cognitoCachingAnonymousCredentialsProvider; + using AWSClientAuth::AWSCognitoAuthorizationController::m_cognitoIdentityPoolId; + using AWSClientAuth::AWSCognitoAuthorizationController::m_formattedCognitoUserPoolId; + using AWSClientAuth::AWSCognitoAuthorizationController::m_awsAccountId; }; } @@ -39,9 +41,6 @@ protected: void SetUp() override { AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::SetUp(); - - AWSClientAuth::CognitoAuthorizationSettings::Reflect(*m_serializeContext); - m_mockController = AZStd::make_unique(); } @@ -53,26 +52,18 @@ protected: public: AZStd::unique_ptr m_mockController; + testing::NiceMock m_awsResourceMappingRequestBusMock; }; TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Success) { - AZStd::string path = AZStd::string::format("%s/%s/awsCognitoAuthorization.setreg", - m_testFolder->c_str(), AZ::SettingsRegistryInterface::RegistryFolder); - CreateTestFile("awsCognitoAuthorization.setreg" - , R"({ - "AWS": { - "CognitoIdentityPool": { - "CognitoUserPoolId": "TestUserPoolId", - "LoginWithAmazonId": "www.amazon.com", - "AWSAccountId": "1234567890", - "IdentityPoolId": "TestIdentityPoolId" - } - } - })"); - - ASSERT_TRUE(m_mockController->Initialize(path)); - ASSERT_TRUE(m_mockController->m_settings->m_cognitoUserPoolId == "TestUserPoolId"); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(2); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultRegion()).Times(1); + ASSERT_TRUE(m_mockController->Initialize()); + ASSERT_TRUE(m_mockController->m_formattedCognitoUserPoolId.find(AWSClientAuthUnitTest::TEST_RESOURCE_NAME_ID) != AZStd::string::npos); + ASSERT_TRUE(m_mockController->m_awsAccountId == AWSClientAuthUnitTest::TEST_ACCOUNT_ID); + ASSERT_TRUE(m_mockController->m_cognitoIdentityPoolId == AWSClientAuthUnitTest::TEST_RESOURCE_NAME_ID); } TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_WithLogins_Success) @@ -438,9 +429,17 @@ TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialHandlerOrder_Call_Alw EXPECT_EQ(order, AWSCore::CredentialHandlerOrder::COGNITO_IDENITY_POOL_CREDENTIAL_HANDLER); } -TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_InvalidPath) +TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_GetResourceNameEmpty) +{ + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1).WillOnce(testing::Return("")); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1); + ASSERT_FALSE(m_mockController->Initialize()); +} + +TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_GetAWSAccountEmpty) { - AZ_TEST_START_TRACE_SUPPRESSION; - ASSERT_FALSE(m_mockController->Initialize("")); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1).WillOnce(testing::Return("")); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultRegion()).Times(0); + ASSERT_FALSE(m_mockController->Initialize()); } diff --git a/Gems/AWSClientAuth/Code/Tests/UserManagement/AWSCognitoUserManagementControllerTest.cpp b/Gems/AWSClientAuth/Code/Tests/UserManagement/AWSCognitoUserManagementControllerTest.cpp index 9d5aef6bf8..9d657ff593 100644 --- a/Gems/AWSClientAuth/Code/Tests/UserManagement/AWSCognitoUserManagementControllerTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/UserManagement/AWSCognitoUserManagementControllerTest.cpp @@ -16,17 +16,6 @@ #include #include -namespace AWSClientAuthUnitTest -{ - class AWSCognitoUserManagementControllerLocalMock - : public AWSClientAuth::AWSCognitoUserManagementController - { - public: - using AWSClientAuth::AWSCognitoUserManagementController::m_settings; - }; -} - - class AWSCognitoUserManagementControllerTest : public AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture , public AWSCore::AWSCoreRequestBus::Handler @@ -35,8 +24,7 @@ protected: void SetUp() override { AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::SetUp(); - AWSClientAuth::AWSCognitoUserManagementSetting::Reflect(*m_serializeContext); - m_mockController = AZStd::make_unique(); + m_mockController = AZStd::make_unique(); AWSCore::AWSCoreRequestBus::Handler::BusConnect(); } @@ -61,26 +49,15 @@ protected: } public: - AZStd::unique_ptr m_mockController; + AZStd::unique_ptr m_mockController; + testing::NiceMock m_awsResourceMappingRequestBusMock; }; TEST_F(AWSCognitoUserManagementControllerTest, Initialize_Success) { - AZStd::string path = AZStd::string::format("%s/%s/awsCognitoUserManagement.setreg", - m_testFolder->c_str(), AZ::SettingsRegistryInterface::RegistryFolder); - CreateTestFile("awsCognitoUserManagement.setreg" - , R"({"AWS": - { - "CognitoUserPool": - { - "AppClientId": "TestClientId", - "SignUpConfirmationType": "email" - } - } - })"); - - ASSERT_TRUE(m_mockController->Initialize(path)); - ASSERT_EQ(m_mockController->m_settings->m_appClientId, "TestClientId"); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1); + ASSERT_TRUE(m_mockController->Initialize()); + ASSERT_EQ(m_mockController->GetCognitoAppClientId(), AWSClientAuthUnitTest::TEST_RESOURCE_NAME_ID); } TEST_F(AWSCognitoUserManagementControllerTest, EmailSignUp_Success) @@ -203,9 +180,8 @@ TEST_F(AWSCognitoUserManagementControllerTest, ConfirmForgotPassword_Fail_Confir m_mockController->ConfirmForgotPasswordAsync(AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_CODE, AWSClientAuthUnitTest::TEST_NEW_PASSWORD); } -TEST_F(AWSCognitoUserManagementControllerTest, Initialize_Fail_InvalidPath) +TEST_F(AWSCognitoUserManagementControllerTest, Initialize_Fail_GetResourceNameEmpty) { - AZ_TEST_START_TRACE_SUPPRESSION; - ASSERT_FALSE(m_mockController->Initialize("")); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1).WillOnce(testing::Return("")); + ASSERT_FALSE(m_mockController->Initialize()); } diff --git a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake index a300ac7f50..79da00076c 100644 --- a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake +++ b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake @@ -18,16 +18,15 @@ set(FILES Include/Private/AWSClientAuthSystemComponent.h Include/Private/AWSClientAuthBus.h + Include/Private/AWSClientAuthResourceMappingConstants.h Include/Private/Authentication/AuthenticationProviderTypes.h Include/Private/Authentication/AuthenticationProviderManager.h Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h - Include/Private/Authorization/AWSCognitoAuthorizationTypes.h Include/Private/Authorization/AWSCognitoAuthorizationController.h Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h - Include/Private/UserManagement/AWSCognitoUserManagementTypes.h Include/Private/UserManagement/AWSCognitoUserManagementController.h Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h diff --git a/Gems/AWSClientAuth/cdk/requirements.txt b/Gems/AWSClientAuth/cdk/requirements.txt index 2fe7823943..e0f46f4add 100644 --- a/Gems/AWSClientAuth/cdk/requirements.txt +++ b/Gems/AWSClientAuth/cdk/requirements.txt @@ -1,3 +1,3 @@ -aws-cdk.core -aws-cdk.aws_cognito -aws-cdk.aws_iam \ No newline at end of file +aws-cdk.core>=1.91.0 +aws-cdk.aws_iam>=1.91.0 +aws-cdk.aws_cognito>=1.91.0 \ No newline at end of file diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index 1221f83d50..6ec0f72180 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( ly_add_target( NAME AWSCore ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AWSCore.c3710872891c4401b0cbdabfca066cb5.0.1.0 FILES_CMAKE awscore_shared_files.cmake INCLUDE_DIRECTORIES @@ -71,7 +70,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME AWSCore.Editor MODULE NAMESPACE Gem - OUTPUT_NAME Gem.AWSCore.Editor.45818501e4b24cb3b09848740ace9fac.0.1.0 FILES_CMAKE awscore_editor_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AWSMetrics/Code/Include/Private/MetricsManager.h b/Gems/AWSMetrics/Code/Include/Private/MetricsManager.h index 1caf4318b5..394d6ac333 100644 --- a/Gems/AWSMetrics/Code/Include/Private/MetricsManager.h +++ b/Gems/AWSMetrics/Code/Include/Private/MetricsManager.h @@ -93,6 +93,11 @@ namespace AWSMetrics //! @return Path to the local metrics file. const char* GetMetricsFilePath() const; + //! Get the total number of requests for sending metrics events. + //! This value could be different to the number of submitted metrics events since metrics events could be sent in batch. + //! @return Total number of requests for sending metrics events. + int GetNumTotalRequests() const; + private: //! Job management void SetupJobContext(); diff --git a/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp b/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp index 06446c0b81..1a7b9e2231 100644 --- a/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp +++ b/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp @@ -145,11 +145,11 @@ namespace AWSMetrics const GlobalStatistics& stats = m_metricsManager->GetGlobalStatistics(); - AZ_Printf("AWSMetrics", " - Total number of metrics events sent to the backend: %u", stats.m_numEvents.load()); - AZ_Printf("AWSMetrics", " - Total number of metrics events sent to the backend successfully: %u", stats.m_numSuccesses.load()); - AZ_Printf("AWSMetrics", " - Total size of metrics events sent to the backend successfully: %u bytes", stats.m_sendSizeInBytes.load()); - AZ_Printf("AWSMetrics", " - Total number of metrics events failed to be processed by the backend: %u", stats.m_numErrors.load()); - AZ_Printf("AWSMetrics", " - Total number of metrics events which failed the JSON schema validation or reached the maximum number of retries : %u", stats.m_numDropped.load()); + AZ_Printf("AWSMetrics", "Total number of metrics events sent to the backend: %u", stats.m_numEvents.load()); + AZ_Printf("AWSMetrics", "Total number of metrics events sent to the backend successfully: %u", stats.m_numSuccesses.load()); + AZ_Printf("AWSMetrics", "Total size of metrics events sent to the backend successfully: %u bytes", stats.m_sendSizeInBytes.load()); + AZ_Printf("AWSMetrics", "Total number of metrics events failed to be processed by the backend: %u", stats.m_numErrors.load()); + AZ_Printf("AWSMetrics", "Total number of metrics events which failed the JSON schema validation or reached the maximum number of retries : %u", stats.m_numDropped.load()); } void AWSMetricsSystemComponent::EnableOfflineRecording(const AZ::ConsoleCommandContainer& arguments) diff --git a/Gems/AWSMetrics/Code/Source/MetricsManager.cpp b/Gems/AWSMetrics/Code/Source/MetricsManager.cpp index b0dfed40be..04e8f03f94 100644 --- a/Gems/AWSMetrics/Code/Source/MetricsManager.cpp +++ b/Gems/AWSMetrics/Code/Source/MetricsManager.cpp @@ -60,6 +60,8 @@ namespace AWSMetrics } m_consumerTerminated = false; + + AZStd::lock_guard lock(m_metricsMutex); m_lastSendMetricsTime = AZStd::chrono::system_clock::now(); // Start a separate thread to monitor and consume the metrics queue. @@ -138,8 +140,6 @@ namespace AWSMetrics void MetricsManager::SendMetricsAsync(AZStd::shared_ptr metricsQueue) { - m_lastSendMetricsTime = AZStd::chrono::system_clock::now(); - if (m_clientConfiguration->OfflineRecordingEnabled()) { SendMetricsToLocalFileAsync(metricsQueue); @@ -186,13 +186,20 @@ namespace AWSMetrics OnResponseReceived(*metricsQueue, responseRecords); - AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsSuccess, requestId); + AZ::TickBus::QueueFunction([requestId]() + { + AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsSuccess, requestId); + }); } else { OnResponseReceived(*metricsQueue); - AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsFailure, requestId, outcome.GetError()); + AZStd::string errorMessage = outcome.GetError(); + AZ::TickBus::QueueFunction([requestId, errorMessage]() + { + AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsFailure, requestId, errorMessage); + }); } }, true, m_jobContext.get()); @@ -209,13 +216,20 @@ namespace AWSMetrics { OnResponseReceived(successJob->parameters.data, successJob->result.events); - AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsSuccess, requestId); + AZ::TickBus::QueueFunction([requestId]() + { + AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsSuccess, requestId); + }); }, [this, requestId](ServiceAPI::PostProducerEventsRequestJob* failedJob) { OnResponseReceived(failedJob->parameters.data); - AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsFailure, requestId, failedJob->error.message); + AZStd::string errorMessage = failedJob->error.message; + AZ::TickBus::QueueFunction([requestId, errorMessage]() + { + AWSMetricsNotificationBus::Broadcast(&AWSMetricsNotifications::OnSendMetricsFailure, requestId, errorMessage); + }); }); requestJob->parameters.data = AZStd::move(metricsQueue); @@ -332,6 +346,10 @@ namespace AWSMetrics void MetricsManager::FlushMetricsAsync() { + AZStd::lock_guard lock(m_metricsMutex); + + m_lastSendMetricsTime = AZStd::chrono::system_clock::now(); + if (m_metricsQueue.GetNumMetrics() == 0) { return; @@ -452,4 +470,9 @@ namespace AWSMetrics { return m_clientConfiguration->GetMetricsFileFullPath(); } + + int MetricsManager::GetNumTotalRequests() const + { + return m_sendMetricsId.load(); + } } diff --git a/Gems/AWSMetrics/Code/Tests/MetricsManagerTest.cpp b/Gems/AWSMetrics/Code/Tests/MetricsManagerTest.cpp index 24acf7b0fd..86c4e3fcd5 100644 --- a/Gems/AWSMetrics/Code/Tests/MetricsManagerTest.cpp +++ b/Gems/AWSMetrics/Code/Tests/MetricsManagerTest.cpp @@ -212,17 +212,29 @@ namespace AWSMetrics int currentNumProcessedEvents = originalStats.m_numEvents; int processingTime = 0; - while (processingTime < TIMEOUT_FOR_PROCESSING_IN_MS && currentNumProcessedEvents < expectedNumProcessedEvents) + int numTotalRequests = 0; + while (processingTime < TIMEOUT_FOR_PROCESSING_IN_MS) { AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(SLEEP_TIME_FOR_PROCESSING_IN_MS)); processingTime += SLEEP_TIME_FOR_PROCESSING_IN_MS; const GlobalStatistics& currentStats = m_metricsManager->GetGlobalStatistics(); currentNumProcessedEvents = currentStats.m_numEvents; - } + numTotalRequests = m_metricsManager->GetNumTotalRequests(); + + if (currentNumProcessedEvents == expectedNumProcessedEvents) + { + // All the expectd metrics events has been sent. Flush the tick bus queue until we get all the notifications. + AZ::TickBus::ExecuteQueuedEvents(); + if (numTotalRequests == + m_notifications.m_numSuccessNotification + m_notifications.m_numFailureNotification) + { + break; + } + } + } } - testing::NiceMock m_awsMetricsNotificationBusMock; AZStd::unique_ptr m_metricsManager; AWSMetricsNotificationBusMock m_notifications; @@ -356,7 +368,7 @@ namespace AWSMetrics AWSMetricsRequestBus::Broadcast(&AWSMetricsRequests::FlushMetrics); - WaitForProcessing(1); + WaitForProcessing(MAX_NUM_METRICS_EVENTS); ASSERT_EQ(m_notifications.m_numSuccessNotification, 1); ASSERT_EQ(m_notifications.m_numFailureNotification, 0); ASSERT_EQ(m_metricsManager->GetNumBufferedMetrics(), 0); diff --git a/Gems/AWSMetrics/cdk/README.md b/Gems/AWSMetrics/cdk/README.md index 8c406c9d92..3f0544a9ce 100644 --- a/Gems/AWSMetrics/cdk/README.md +++ b/Gems/AWSMetrics/cdk/README.md @@ -52,7 +52,7 @@ to use for environment variables. ## Bootstrap the environment An environment needs to be bootstrapped since this CDK application uses assets like a local directory that contains the handler code for the AWS Lambda functions. -Use the following cdk bootstrap command to bootstrap one or more AWS environments. +Use the following CDK bootstrap command to bootstrap one or more AWS environments. ``` cdk bootstrap aws://ACCOUNT-NUMBER-1/REGION-1 aws://ACCOUNT-NUMBER-2/REGION-2 ... @@ -68,9 +68,33 @@ $ cdk synth ``` To add additional dependencies, for example other CDK libraries, just add -them to your `setup.py` file and rerun the `pip install -r requirements.txt` +them to your `requirements.txt` file and rerun the `pip install -r requirements.txt` command. +## Deploy the project +To deploy the CDK application, use the following CLI command: + +``` +$ cdk deploy +``` + +## Enable the optional batch processing feature +You can optionally enable the batch processing feature by specifying the context variable like below: + +``` +$ cdk synth -c batch_processing=true +$ cdk deploy -c batch_processing=true +``` + +This will deploy the AWS resources required by the batch processing feature and bring additional cost. + +To disable the feature and remove related AWS resources, you need to empty the deployed S3 bucket manually and run the normal CDK CLI commands for updating the CDK application: + +``` +$ cdk synth +$ cdk deploy +``` + ## Useful commands * `cdk ls` list all stacks in the app diff --git a/Gems/AWSMetrics/cdk/aws_metrics/auth.py b/Gems/AWSMetrics/cdk/aws_metrics/auth.py index 90e0856d48..882a13f903 100644 --- a/Gems/AWSMetrics/cdk/aws_metrics/auth.py +++ b/Gems/AWSMetrics/cdk/aws_metrics/auth.py @@ -68,6 +68,6 @@ class AuthPolicy: policy_output = core.CfnOutput( self._stack, id=f'{policy_id}Output', - description='User policy arn to call service', + description=f'{role_name} policy arn to call service', export_name=f"{self._application_name}:{policy_id}", value=policy.managed_policy_arn) diff --git a/Gems/AWSMetrics/cdk/aws_metrics/aws_metrics_constants.py b/Gems/AWSMetrics/cdk/aws_metrics/aws_metrics_constants.py index 7d1ef3ca34..4a132d8315 100644 --- a/Gems/AWSMetrics/cdk/aws_metrics/aws_metrics_constants.py +++ b/Gems/AWSMetrics/cdk/aws_metrics/aws_metrics_constants.py @@ -121,7 +121,7 @@ DASHBOARD_GLOBAL_DESCRIPTION = "# Metrics Dashboard \n"\ "This dashboard contains near-real-time metrics sent from your client"\ " or dedicated server. \n You can edit the widgets using the AWS console"\ " or modify your CDK application code. Please note that redeploying"\ - " the CDK application will not overwrite any changes you made directly"\ + " the CDK application will overwrite any changes you made directly"\ " via the AWS console. \n For more information about using the AWS Metrics Gem"\ " and CDK application, please check the AWSMetrics gem document." # The description for the operational health shown on the CloudWatch dashboard diff --git a/Gems/Achievements/Code/CMakeLists.txt b/Gems/Achievements/Code/CMakeLists.txt index bb72a4ed2f..b49409bd5e 100644 --- a/Gems/Achievements/Code/CMakeLists.txt +++ b/Gems/Achievements/Code/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( ly_add_target( NAME Achievements ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Achievements.6f8d953dd4fc4bb6ad34c9118a7b789f.v0.1.0 FILES_CMAKE achievements_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt b/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt index f575742221..7cca815017 100644 --- a/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt +++ b/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt @@ -30,7 +30,6 @@ ly_add_target( ly_add_target( NAME AssetMemoryAnalyzer ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AssetMemoryAnalyzer.35414634480a4d4c8412c60fe62f4c81.v0.1.0 FILES_CMAKE assetmemoryanalyzer_shared_files.cmake INCLUDE_DIRECTORIES @@ -41,6 +40,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::AssetMemoryAnalyzer.Static + RUNTIME_DEPENDENCIES + Gem::ImGui ) ################################################################################ diff --git a/Gems/AssetValidation/Code/CMakeLists.txt b/Gems/AssetValidation/Code/CMakeLists.txt index eb89eb79d3..983ddd9e9d 100644 --- a/Gems/AssetValidation/Code/CMakeLists.txt +++ b/Gems/AssetValidation/Code/CMakeLists.txt @@ -23,14 +23,12 @@ ly_add_target( PUBLIC AZ::AzCore AZ::AzFramework - AZ::GemRegistry Legacy::CryCommon ) ly_add_target( NAME AssetValidation ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AssetValidation.5a5c3c10b91d4b4ea8baef474c5b5d49.v0.1.0 FILES_CMAKE assetvalidation_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AssetValidation/Code/Source/AssetSeedUtil.cpp b/Gems/AssetValidation/Code/Source/AssetSeedUtil.cpp index bc05e68ae3..ce8c318562 100644 --- a/Gems/AssetValidation/Code/Source/AssetSeedUtil.cpp +++ b/Gems/AssetValidation/Code/Source/AssetSeedUtil.cpp @@ -11,20 +11,11 @@ */ #include "AssetSeedUtil.h" +#include #include namespace AssetValidation::AssetSeed { - GemInfo::GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath, AZStd::string identifier, bool isGameGem, bool assetOnlyGem) - : m_gemName(AZStd::move(name)) - , m_relativeFilePath(AZStd::move(relativeFilePath)) - , m_absoluteFilePath(AZStd::move(absoluteFilePath)) - , m_identifier(AZStd::move(identifier)) - , m_isGameGem(isGameGem) - , m_assetOnly(assetOnlyGem) - { - } - void AddPlatformSeeds(const AZStd::string& rootFolder, AZStd::vector& defaultSeedLists, AzFramework::PlatformFlags platformFlags) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); @@ -69,193 +60,82 @@ namespace AssetValidation::AssetSeed fileIO->FindFiles(platformsDirectory.c_str(), AZStd::string::format("*.%s", SeedFileExtension).c_str(), [&](const char* fileName) - { - AZStd::string normalizedFilePath = fileName; - AZ::StringFunc::Path::Normalize(normalizedFilePath); - defaultSeedLists.emplace_back(normalizedFilePath); - return true; - }); + { + AZStd::string normalizedFilePath = fileName; + AZ::StringFunc::Path::Normalize(normalizedFilePath); + defaultSeedLists.emplace_back(normalizedFilePath); + return true; + }); } AddPlatformSeeds(platformsDirectory, defaultSeedLists, platformFlags); } - bool GetGemsInfo(const char* root, const char* assetRoot, const char* gameName, AZStd::vector& gemInfoList) + AZStd::vector GetGemSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags) { - Gems::IGemRegistry* registry = nullptr; - Gems::IProjectSettings* projectSettings = nullptr; - AZ::ModuleManagerRequests::LoadModuleOutcome result = AZ::Failure(AZStd::string("Failed to connect to ModuleManagerRequestBus.\n")); - AZ::ModuleManagerRequestBus::BroadcastResult(result, &AZ::ModuleManagerRequestBus::Events::LoadDynamicModule, "GemRegistry", AZ::ModuleInitializationSteps::Load, false); - if (!result.IsSuccess()) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Could not load the GemRegistry module - %s.\n", result.GetError().c_str()); - return false; - } - - // Use shared_ptr aliasing ctor to use the refcount/deleter from the moduledata pointer, but we only need to store the dynamic module handle. - auto registryModule = AZStd::shared_ptr(result.GetValue(), result.GetValue()->GetDynamicModuleHandle()); - auto CreateGemRegistry = registryModule->GetFunction(GEMS_REGISTRY_CREATOR_FUNCTION_NAME); - Gems::RegistryDestroyerFunction registryDestroyerFunc = registryModule->GetFunction(GEMS_REGISTRY_DESTROYER_FUNCTION_NAME); - if (!CreateGemRegistry || !registryDestroyerFunc) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to load GemRegistry functions.\n"); - return false; - } - - registry = CreateGemRegistry(); - if (!registry) - { - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to create Gems::GemRegistry.\n"); - return false; - } - - registry->AddSearchPath({ root, GemsDirectoryName }, false); - - - registry->AddSearchPath({ assetRoot, GemsDirectoryName }, false); - - const char* engineRootPath = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRootPath, &AzFramework::ApplicationRequests::GetEngineRoot); - - if (engineRootPath && azstricmp(engineRootPath, root)) - { - registry->AddSearchPath({ engineRootPath, GemsDirectoryName }, false); - } - projectSettings = registry->CreateProjectSettings(); - if (!projectSettings) - { - registryDestroyerFunc(registry); - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to create Gems::ProjectSettings.\n"); - return false; - } - - if (!projectSettings->Initialize(assetRoot, gameName)) - { - registry->DestroyProjectSettings(projectSettings); - registryDestroyerFunc(registry); - - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to initialize Gems::ProjectSettings.\n"); - return false; - } - - auto loadProjectOutcome = registry->LoadProject(*projectSettings, true); - if (!loadProjectOutcome.IsSuccess()) - { - registry->DestroyProjectSettings(projectSettings); - registryDestroyerFunc(registry); - - AZ_Error("AzToolsFramework::AssetUtils", false, "Failed to load Gems project: %s.\n", loadProjectOutcome.GetError().c_str()); - return false; - } - - // Populating the gem info list - for (const auto& pair : projectSettings->GetGems()) + AZStd::vector gemSeedListFiles; + for (const AzFramework::GemInfo& gemInfo : gemInfoList) { - Gems::IGemDescriptionConstPtr desc = registry->GetGemDescription(pair.second); - - if (!desc) + for (AZ::IO::Path absoluteGemAssetPath : gemInfo.m_absoluteSourcePaths) { - Gems::ProjectGemSpecifier gemSpecifier = pair.second; - AZStd::string errorStr = AZStd::string::format("Failed to load Gem with ID %s and Version %s (from path %s).\n", - gemSpecifier.m_id.ToString().c_str(), gemSpecifier.m_version.ToString().c_str(), gemSpecifier.m_path.c_str()); - - if (Gems::IGemDescriptionConstPtr latestVersion = registry->GetLatestGem(pair.first)) - { - errorStr += AZStd::string::format(" Found version %s, you may want to use that instead.\n", latestVersion->GetVersion().ToString().c_str()); - } - - AZ_Error("AzToolsFramework::AssetUtils", false, errorStr.c_str()); - return false; - } + absoluteGemAssetPath /= AzFramework::GemInfo::GetGemAssetFolder(); - // Note: the two 'false' parameters in the ToString call below ToString(false, false) - // eliminates brackets and dashes in the formatting of the UUID. - // this keeps it compatible with legacy formatting which also omitted the curly braces and the dashes in the UUID. - AZStd::string gemId = desc->GetID().ToString(false, false).c_str(); - AZStd::to_lower(gemId.begin(), gemId.end()); + AZ::IO::Path absoluteGemSeedFilePath = absoluteGemAssetPath / GemsSeedFileName; + absoluteGemSeedFilePath.ReplaceExtension(SeedFileExtension); - bool assetOnlyGem = true; - - Gems::ModuleDefinitionVector moduleList = desc->GetModules(); - - for (Gems::ModuleDefinitionConstPtr moduleDef : moduleList) - { - if (moduleDef->m_linkType != Gems::LinkType::NoCode) + if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteGemSeedFilePath.c_str())) { - assetOnlyGem = false; - break; + gemSeedListFiles.emplace_back(absoluteGemSeedFilePath); } - } - - gemInfoList.emplace_back(GemInfo(desc->GetName(), desc->GetPath(), desc->GetAbsolutePath(), gemId, desc->IsGameGem(), assetOnlyGem)); - } - - registry->DestroyProjectSettings(projectSettings); - registryDestroyerFunc(registry); - return true; - } - - AZStd::vector GetGemSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags) - { - AZStd::vector gemSeedListFiles; - for (const GemInfo& gemInfo : gemInfoList) - { - AZStd::string absoluteGemSeedFilePath; - AZ::StringFunc::Path::ConstructFull(gemInfo.m_absoluteFilePath.c_str(), GemsSeedFileName, SeedFileExtension, absoluteGemSeedFilePath, true); - - if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteGemSeedFilePath.c_str())) - { - gemSeedListFiles.emplace_back(absoluteGemSeedFilePath); + AddPlatformsDirectorySeeds(absoluteGemAssetPath.Native(), gemSeedListFiles, platformFlags); } - - AddPlatformsDirectorySeeds(gemInfo.m_absoluteFilePath, gemSeedListFiles, platformFlags); } return gemSeedListFiles; } - AZStd::vector GetDefaultSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlag) + AZStd::vector GetDefaultSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlag) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "AZ::IO::FileIOBase must be ready for use.\n"); - const char* root = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(root, &AzFramework::ApplicationRequests::GetEngineRoot); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ_Assert(settingsRegistry, "Global Settings registry must be available to retrieve default seed list"); + + AZ::IO::Path engineRoot; + settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); // Add all seed list files of enabled gems for the given project AZStd::vector defaultSeedLists = GetGemSeedListFiles(gemInfoList, platformFlag); // Add the engine seed list file - AZStd::string engineDirectory; - AZ::StringFunc::Path::Join(root, EngineDirectoryName, engineDirectory); - AZStd::string absoluteEngineSeedFilePath; - AZ::StringFunc::Path::ConstructFull(engineDirectory.c_str(), EngineSeedFileName, SeedFileExtension, absoluteEngineSeedFilePath, true); + AZ::IO::Path engineSourceAssetsDirectory = engineRoot / EngineDirectoryName; + AZ::IO::Path absoluteEngineSeedFilePath = engineSourceAssetsDirectory; + absoluteEngineSeedFilePath /= EngineSeedFileName; + absoluteEngineSeedFilePath.ReplaceExtension(SeedFileExtension); if (fileIO->Exists(absoluteEngineSeedFilePath.c_str())) { - defaultSeedLists.emplace_back(absoluteEngineSeedFilePath); + defaultSeedLists.emplace_back(AZStd::move(absoluteEngineSeedFilePath.LexicallyNormal().Native())); } - AddPlatformsDirectorySeeds(engineDirectory, defaultSeedLists, platformFlag); + AddPlatformsDirectorySeeds(engineSourceAssetsDirectory.Native(), defaultSeedLists, platformFlag); // Add the current project default seed list file AZStd::string projectName; bool checkPlatform = false; - auto settingsRegistry = AZ::SettingsRegistry::Get(); - if (settingsRegistry) + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) { - AZ::SettingsRegistryInterface::FixedValueString bootstrapProjectName; - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - settingsRegistry->Get(bootstrapProjectName, projectKey); - if (!bootstrapProjectName.empty()) + AZ::IO::FixedMaxPath absoluteProjectDefaultSeedFilePath{ engineRoot }; + absoluteProjectDefaultSeedFilePath /= projectPath; + absoluteProjectDefaultSeedFilePath /= EngineSeedFileName; + absoluteProjectDefaultSeedFilePath.ReplaceExtension(SeedFileExtension); + + if (fileIO->Exists(absoluteProjectDefaultSeedFilePath.c_str())) { - AZStd::string absoluteProjectDefaultSeedFilePath; - AZ::StringFunc::Path::ConstructFull(root, bootstrapProjectName.c_str(), EngineSeedFileName, SeedFileExtension, absoluteProjectDefaultSeedFilePath, true); - if (fileIO->Exists(absoluteProjectDefaultSeedFilePath.c_str())) - { - defaultSeedLists.emplace_back(move(absoluteProjectDefaultSeedFilePath)); - } + defaultSeedLists.emplace_back(absoluteProjectDefaultSeedFilePath.LexicallyNormal().String()); } } return defaultSeedLists; diff --git a/Gems/AssetValidation/Code/Source/AssetSeedUtil.h b/Gems/AssetValidation/Code/Source/AssetSeedUtil.h index 45832ed7b1..4a6ff1f1d8 100644 --- a/Gems/AssetValidation/Code/Source/AssetSeedUtil.h +++ b/Gems/AssetValidation/Code/Source/AssetSeedUtil.h @@ -17,11 +17,11 @@ #include #include #include +#include #include #include +#include #include -#include -#include namespace AssetValidation::AssetSeed { @@ -32,31 +32,12 @@ namespace AssetValidation::AssetSeed constexpr char EngineSeedFileName[] = "SeedAssetList"; constexpr char EngineDirectoryName[] = "Engine"; - //! This struct stores gem related information - struct GemInfo - { - AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0); - GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath, AZStd::string identifier, bool isGameGem, bool assetOnlyGem); - GemInfo() = default; - AZStd::string m_gemName; ///< A friendly display name, not to be used for any pathing stuff. - AZStd::string m_relativeFilePath; ///< Where the gem's folder is (relative to the gems search path(s)) - AZStd::string m_absoluteFilePath; ///< Where the gem's folder is (as an absolute path) - AZStd::string m_identifier; ///< The UUID of the gem. - - bool m_isGameGem = false; //< True if its a 'game project' gem. Only one such gem can exist for any game project. - bool m_assetOnly = false; ///< True if it is an asset only gems. - - static constexpr AZStd::string_view GetGemAssetFolder() { return AZStd::string_view("Assets"); } - - }; - void AddPlatformSeeds(const AZStd::string& rootFolder, AZStd::vector& defaultSeedLists, AzFramework::PlatformFlags platformFlags); void AddPlatformsDirectorySeeds(const AZStd::string& rootFolder, AZStd::vector& defaultSeedLists, AzFramework::PlatformFlags platformFlags); - bool GetGemsInfo(const char* root, const char* assetRoot, const char* gameName, AZStd::vector& gemInfoList); - AZStd::vector GetGemSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); + AZStd::vector GetGemSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlags); - AZStd::vector GetDefaultSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlag); + AZStd::vector GetDefaultSeedListFiles(const AZStd::vector& gemInfoList, AzFramework::PlatformFlags platformFlag); } diff --git a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp index 1cd9bd0a32..d26ad0eea2 100644 --- a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp +++ b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp @@ -452,7 +452,7 @@ namespace AssetValidation auto settingsRegistry = AZ::SettingsRegistry::Get(); AZ::SettingsRegistryInterface::FixedValueString gameFolder; - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); + auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); settingsRegistry->Get(gameFolder, projectKey); if (gameFolder.empty()) @@ -461,9 +461,9 @@ namespace AssetValidation return false; } - AZStd::vector gemInfoList; + AZStd::vector gemInfoList; - if (!AssetSeed::GetGemsInfo(engineRoot, appRoot, gameFolder.c_str(), gemInfoList)) + if (!AzFramework::GetGemsInfo(gemInfoList, *settingsRegistry)) { AZ_Warning("AssetValidation", false, "Unable to get gem information."); return false; diff --git a/Gems/AssetValidation/Code/Tests/AssetValidationTest.cpp b/Gems/AssetValidation/Code/Tests/AssetValidationTest.cpp index 375928c057..a5ff671fc3 100644 --- a/Gems/AssetValidation/Code/Tests/AssetValidationTest.cpp +++ b/Gems/AssetValidation/Code/Tests/AssetValidationTest.cpp @@ -15,6 +15,7 @@ #include "AssetValidationTestShared.h" #include #include +#include // Needs SPEC-2324 #if !AZ_TRAIT_USE_POSIX_TEMP_FOLDER @@ -29,25 +30,22 @@ bool AssetValidationTest::CreateDummyFile(const char* path, const char* seedFile TEST_F(AssetValidationTest, DefaultSeedList_ReturnsExpectedSeedLists) { - AZStd::vector gemInfo; + AZStd::vector gemInfo; AZStd::string gemSeedList, engineSeedList, projectSeedList; - ASSERT_TRUE(CreateDummyFile("mockGem", "seedList", "Mock Gem Seed List", gemSeedList)); + ASSERT_TRUE(CreateDummyFile((AZ::IO::Path("mockGem") / AzFramework::GemInfo::GetGemAssetFolder()).c_str(), "seedList", "Mock Gem Seed List", gemSeedList)); ASSERT_TRUE(CreateDummyFile("Engine", "SeedAssetList", "Engine Seed List", engineSeedList)); - auto settingsRegistry = AZ::SettingsRegistry::Get(); - ASSERT_NE(settingsRegistry, nullptr); - AZ::SettingsRegistryInterface::FixedValueString bootstrapProjectName; - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - settingsRegistry->Get(bootstrapProjectName, projectKey); - ASSERT_FALSE(bootstrapProjectName.empty()); - ASSERT_TRUE(CreateDummyFile(bootstrapProjectName.c_str(), "SeedAssetList", "Project Seed List", projectSeedList)); + AZ::SettingsRegistryInterface::FixedValueString projectName = AZ::Utils::GetProjectName(); + ASSERT_FALSE(projectName.empty()); + ASSERT_TRUE(CreateDummyFile(projectName.c_str(), "SeedAssetList", "Project Seed List", projectSeedList)); - AssetValidation::AssetSeed::GemInfo mockGem("MockGem", "mockGem", (m_tempDir / "mockGem").string().c_str(), "mockGem", true, false); + AzFramework::GemInfo mockGem("MockGem"); + mockGem.m_absoluteSourcePaths.push_back((m_tempDir / "mockGem").string().c_str()); gemInfo.push_back(mockGem); - AZStd::vector defaultSeedLists = GetDefaultSeedListFiles(gemInfo, AzFramework::PlatformFlags::Platform_PC); + AZStd::vector defaultSeedLists = AssetValidation::AssetSeed::GetDefaultSeedListFiles(gemInfo, AzFramework::PlatformFlags::Platform_PC); ASSERT_THAT(defaultSeedLists, ::testing::UnorderedElementsAre(gemSeedList, engineSeedList, projectSeedList)); } diff --git a/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h b/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h index 72e8840171..ab9e65b896 100644 --- a/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h +++ b/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h @@ -150,8 +150,15 @@ struct AssetValidationTest { if (!AZ::SettingsRegistry::Get()) { - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(m_registry); AZ::SettingsRegistry::Register(&m_registry); + + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(m_registry); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); + // Set the engine root to the temporary directory and re-update the runtime file paths + auto enginePathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + + "/engine_path"; + m_registry.Set(enginePathKey, GetEngineRoot()); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); } } @@ -165,7 +172,7 @@ struct AssetValidationTest AZ_Assert(false, "Not implemented"); } - void CalculateBranchTokenForAppRoot([[maybe_unused]] AZStd::string& token) const override + void CalculateBranchTokenForEngineRoot([[maybe_unused]] AZStd::string& token) const override { AZ_Assert(false, "Not implemented"); } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.ini b/Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.ini deleted file mode 100644 index 28edbdd706..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,15 +0,0 @@ -; ---- add any metadata file type here that needs to be monitored by the AssetProcessor. -; Modifying these meta file will cause the source asset to re-compile again. -; They are specified in the following format -; metadata extension=original extension to replace -; if the metadata extension does not replace the original, then the original can be blank -; so for example if your normal file is blah.tif and your metafile for that file is blah.tif.exportsettings -; then your declaration would be exportsettings= ; ie, it would be blank -; however if your metafile REPLACES the extension (for example, if you have the file blah.i_caf and its metafile is blah.exportsettings) -; then you specify the original extension here to narrow the scope. -; If a relative path to a specific file is provided instead of an extension, a change to the file will change all files -; with the associated extension (e.g. Animations/SkeletonList.xml=i_caf will cause all i_caf files to recompile when -; Animations/SkeletonList.xml within the current game project changes) - -[MetaDataTypes] -assetinfo= \ No newline at end of file diff --git a/Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.setreg b/Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..17d9887fe8 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/AssetProcessorGemConfig.setreg @@ -0,0 +1,7 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": {} + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt index 8e3e78090d..7068f7235a 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt @@ -93,9 +93,9 @@ ly_add_source_properties( ) ly_add_target( - NAME ImageProcessingAtom.Editor MODULE + NAME ImageProcessingAtom.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.ImageProcessingAtom.Editor.9d10b00be96045caa64c705e5772cb64.v0.1.0 FILES_CMAKE imageprocessingatom_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp index aa479b3971..4de024c088 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -85,10 +86,13 @@ namespace ImageProcessingAtom m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler()); m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler()); + + ImageProcessingRequestBus::Handler::BusConnect(); } void BuilderPluginComponent::Deactivate() { + ImageProcessingRequestBus::Handler::BusDisconnect(); m_imageBuilder.BusDisconnect(); BuilderSettingManager::DestroyInstance(); CPixelFormats::DestroyInstance(); @@ -125,6 +129,23 @@ namespace ImageProcessingAtom incompatible.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e)); } + IImageObjectPtr BuilderPluginComponent::LoadImage(const AZStd::string& filePath) + { + return IImageObjectPtr(LoadImageFromFile(filePath)); + } + + IImageObjectPtr BuilderPluginComponent::LoadImagePreview(const AZStd::string& filePath) + { + IImageObjectPtr image(LoadImageFromFile(filePath)); + if (image) + { + ImageToProcess imageToProcess(image); + imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); + return imageToProcess.Get(); + } + return image; + } + void ImageBuilderWorker::ShutDown() { // it is important to note that this will be called on a different thread than your process job thread diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h index 9f9fb2d9ee..fd099eb08a 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace ImageProcessingAtom { @@ -45,6 +46,7 @@ namespace ImageProcessingAtom //! BuilderPluginComponent is to handle the lifecycle of ImageBuilder module. class BuilderPluginComponent : public AZ::Component + , protected ImageProcessingRequestBus::Handler { public: AZ_COMPONENT(BuilderPluginComponent, "{A227F803-D2E4-406E-93EC-121EF45A64A1}") @@ -63,6 +65,12 @@ namespace ImageProcessingAtom static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); ////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + // AtomImageProcessingRequestBus interface implementation + IImageObjectPtr LoadImage(const AZStd::string& filePath) override; + IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override; + //////////////////////////////////////////////////////////////////////// + private: BuilderPluginComponent(const BuilderPluginComponent&) = delete; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessingSystemComponent.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessingSystemComponent.h index 228d100ab0..7ddaafb0c4 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessingSystemComponent.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessingSystemComponent.h @@ -53,7 +53,6 @@ namespace ImageProcessingAtom IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override; //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation void Init() override; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index 635d4a6897..706d60dee7 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -110,8 +110,9 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_context.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return m_jsonRegistrationContext.get(); } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} @@ -159,7 +160,7 @@ namespace UnitTest m_jsonSystemComponent = AZStd::make_unique(); m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get()); BuilderPluginComponent::Reflect(m_jsonRegistrationContext.get()); - + // Startup default local FileIO (hits OSAllocator) if not already setup. if (AZ::IO::FileIOBase::GetInstance() == nullptr) { @@ -171,7 +172,7 @@ namespace UnitTest m_gemFolder = AZ::Test::GetEngineRootPath() + "/Gems/Atom/Asset/ImageProcessingAtom/"; s_gemFolder = m_gemFolder.c_str(); - + m_defaultSettingFolder = m_gemFolder + AZStd::string("Config/"); m_testFileFolder = m_gemFolder + AZStd::string("Code/Tests/TestAssets/"); @@ -192,7 +193,7 @@ namespace UnitTest delete AZ::IO::FileIOBase::GetInstance(); AZ::IO::FileIOBase::SetInstance(nullptr); - + m_jsonRegistrationContext->EnableRemoveReflection(); m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get()); BuilderPluginComponent::Reflect(m_jsonRegistrationContext.get()); @@ -916,7 +917,7 @@ namespace UnitTest imageToProcess.LinearToGamma(); SaveImageToFile(imageToProcess.Get(), "LinearToGamma_DeGamma", 1); } - + TEST_F(ImageProcessingTest, VerifyRestrictedPlatform) { auto outcome = BuilderSettingManager::Instance()->LoadConfigFromFolder(m_defaultSettingFolder); @@ -1005,7 +1006,7 @@ namespace UnitTest TEST_F(ImageProcessingTest, DISABLED_TestLoadDdsImage) { IImageObjectPtr originImage, alphaImage; - AZStd::string inputFolder = "../Cache/SamplesProject/pc/samplesproject/engineassets/texturemsg/"; + AZStd::string inputFolder = "../SamplesProject/Cache/pc/engineassets/texturemsg/"; AZStd::string inputFile; inputFile = "E:/Javelin_NWLYDev/dev/Cache/Assets/pc/assets/textures/blend_maps/moss/jav_moss_ddn.dds"; @@ -1074,7 +1075,7 @@ namespace UnitTest } f.close(); } - + TEST_F(ImageProcessingTest, TextureSettingReflect_SerializingModernDataInAndOut_WritesAndParsesFileAccurately) { AZStd::string filepath = "test.xml"; diff --git a/Gems/Atom/Asset/Shader/Code/CMakeLists.txt b/Gems/Atom/Asset/Shader/Code/CMakeLists.txt index 6e04e65135..cbe80ffa83 100644 --- a/Gems/Atom/Asset/Shader/Code/CMakeLists.txt +++ b/Gems/Atom/Asset/Shader/Code/CMakeLists.txt @@ -22,9 +22,9 @@ if(NOT PAL_TRAIT_BUILD_ATOM_ASSET_SHADER_SUPPORTED) # Create a stub ly_add_target( - NAME Atom_Asset_Shader.Builders MODULE + NAME Atom_Asset_Shader.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Asset_Shader.Builders.d32452026dae4b7dba2ad89dbde9c48f.v0.1.0 FILES_CMAKE atom_asset_shader_builders_stub_files.cmake INCLUDE_DIRECTORIES @@ -83,9 +83,9 @@ foreach(enabled_platform ${LY_PAL_TOOLS_ENABLED}) endforeach() ly_add_target( - NAME Atom_Asset_Shader.Builders MODULE + NAME Atom_Asset_Shader.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Asset_Shader.Builders.d32452026dae4b7dba2ad89dbde9c48f.v0.1.0 FILES_CMAKE atom_asset_shader_builders_shared_files.cmake PLATFORM_INCLUDE_FILES diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslBuilder.cpp index f5d5eac251..062c19e7e3 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslBuilder.cpp @@ -167,7 +167,12 @@ namespace AZ // execute azsl prepending here, before preprocess, in order to support macros in AzslcHeader.azsli AZStd::string prependedAzslSourceCode; - RHI::PrependArguments args{ fullPath.c_str(), shaderPlatformInterface->GetAzslHeader(info), shaderPlatformInterface->GetAPIName().GetCStr(), nullptr, &prependedAzslSourceCode }; + RHI::PrependArguments args; + args.m_sourceFile = fullPath.c_str(); + args.m_prependFile = shaderPlatformInterface->GetAzslHeader(info); + args.m_addSuffixToFileName = shaderPlatformInterface->GetAPIName().GetCStr(); + args.m_destinationStringOpt = &prependedAzslSourceCode; + if (RHI::PrependFile(args) == fullPath) // error case. it returns the combined-file's name on success, or original path on failure, but here we use the "direct to string" mode so we don't need to store the returned name. { response.m_result = AssetBuilderSDK::CreateJobsResultCode::Failed; @@ -345,14 +350,11 @@ namespace AZ return; } - // pass it to the shader platform interface: - platformInterface->SetExternalArguments(buildOptions.m_compilerArguments); - // compiler setup ShaderBuilder::AzslCompiler azslc(preprocessedPath); - AZStd::string compilerParameters = platformInterface->GetAzslCompilerParameters(); + AZStd::string compilerParameters = platformInterface->GetAzslCompilerParameters(buildOptions.m_compilerArguments); compilerParameters += " "; - compilerParameters += platformInterface->GetAzslCompilerWarningParameters(); + compilerParameters += platformInterface->GetAzslCompilerWarningParameters(buildOptions.m_compilerArguments); AtomShaderConfig::AddParametersFromConfigFile(compilerParameters, request.m_platformInfo); if (isSrgi || isAzsli) { diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.cpp index 6663c520ba..d7382cee6f 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslCompiler.cpp @@ -28,8 +28,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp index 9d01be7c7f..961af6e8fe 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp @@ -86,7 +86,7 @@ namespace AZ // Register AZSL's compilation products Builder AssetBuilderSDK::AssetBuilderDesc azslBuilderDescriptor; azslBuilderDescriptor.m_name = "AZSL Builder"; - azslBuilderDescriptor.m_version = 5; // ATOM-13204 + azslBuilderDescriptor.m_version = 7; // LKG Merge // register all extensions thay may carry azsl code. header. main shader. or SRG azslBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); azslBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.azsl", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); @@ -102,7 +102,7 @@ namespace AZ // Register Shader Resource Group Layout Builder AssetBuilderSDK::AssetBuilderDesc srgLayoutBuilderDescriptor; srgLayoutBuilderDescriptor.m_name = "Shader Resource Group Layout Builder"; - srgLayoutBuilderDescriptor.m_version = 48; // ATOM-14428 + srgLayoutBuilderDescriptor.m_version = 50; // ATOM-14918 (probably don't need to bump this one but just playing it safe) srgLayoutBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.azsl", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); srgLayoutBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.azsli", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); srgLayoutBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", SrgLayoutBuilder::MergedPartialSrgsExtension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); @@ -117,7 +117,7 @@ namespace AZ // Register Shader Asset Builder AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor; shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder"; - shaderAssetBuilderDescriptor.m_version = 93; // ATOM-13204 + shaderAssetBuilderDescriptor.m_version = 95; // LKG Merge // .shader file changes trigger rebuilds shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderAssetBuilderDescriptor.m_busId = azrtti_typeid(); @@ -132,7 +132,7 @@ namespace AZ shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; // Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update // ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder". - shaderVariantAssetBuilderDescriptor.m_version = 14; // ATOM-13204 + shaderVariantAssetBuilderDescriptor.m_version = 16; // LKG Merge shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid(); shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); @@ -144,7 +144,7 @@ namespace AZ // Register Precompiled Shader Builder AssetBuilderSDK::AssetBuilderDesc precompiledShaderBuilderDescriptor; precompiledShaderBuilderDescriptor.m_name = "Precompiled Shader Builder"; - precompiledShaderBuilderDescriptor.m_version = 4; // ATOM-14428 + precompiledShaderBuilderDescriptor.m_version = 6; // ATOM-14918 precompiledShaderBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", AZ::PrecompiledShaderBuilder::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); precompiledShaderBuilderDescriptor.m_busId = azrtti_typeid(); precompiledShaderBuilderDescriptor.m_createJobFunction = AZStd::bind(&PrecompiledShaderBuilder::CreateJobs, &m_precompiledShaderBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.cpp index 197cc64c3d..c9d23aecd1 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/GlobalBuildOptions.cpp @@ -65,12 +65,6 @@ namespace AZ GlobalBuildOptions ReadBuildOptions(const char* builderName) { GlobalBuildOptions output; - // get the application root: - AZStd::string devFolder; - AzFramework::ApplicationRequests::Bus::BroadcastResult(devFolder, &AzFramework::ApplicationRequests::GetAppRoot); - AzFramework::StringFunc::Path::Normalize(devFolder); - - // additionally, // try to parse some config file for eventual additional options AZStd::string globalBuildOption = "Config/shader_global_build_options.json"; bool found = MutateToAbsolutePathIfFound(globalBuildOption); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp index 9212ed4095..ead0674d25 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/CommonFiles/Preprocessor.cpp @@ -309,22 +309,22 @@ namespace AZ } } // the folders constructed this fashion constitute the base of automatic include search paths - // get the application root: - AZStd::string devFolder; - AzFramework::ApplicationRequests::Bus::BroadcastResult(devFolder, &AzFramework::ApplicationRequests::GetAppRoot); - AzFramework::StringFunc::Path::Normalize(devFolder); + // get the engine root: + AZStd::string engineRoot; + AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AzFramework::StringFunc::Path::Normalize(engineRoot); // add optional additional options for (AZStd::string& path : options.m_projectIncludePaths) { - AzFramework::StringFunc::Path::Join(devFolder.c_str(), path.c_str(), path); + AzFramework::StringFunc::Path::Join(engineRoot.c_str(), path.c_str(), path); DeleteFromSet(path, scanFoldersSet); // no need to add a path two times. } // back-insert the default paths (after the config-read paths we just read) TransferContent(/*to:*/options.m_projectIncludePaths, /*from:*/scanFoldersSet); - // finally the dev/Gems fallback + // finally the /Gems fallback AZStd::string gemsFolder; - AzFramework::StringFunc::Path::Join(devFolder.c_str(), "Gems", gemsFolder); + AzFramework::StringFunc::Path::Join(engineRoot.c_str(), "Gems", gemsFolder); options.m_projectIncludePaths.push_back(gemsFolder); } diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index c570843041..98a07f1c61 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -128,7 +128,12 @@ namespace AZ {// *** block (remove all this when [ATOM-4225] addressed) // this is the same code as in AzslBuilder.cpp's CreateJobs. This is not supposed to be repeated here (temporary hack), so not factorized. refer to AzslBuilder.cpp for code comments AZStd::string prependedAzslSourceCode; - RHI::PrependArguments args{ fullPath.c_str(), shaderPlatformInterface->GetAzslHeader(platformInfo), shaderPlatformInterface->GetAPIName().GetCStr(), nullptr, &prependedAzslSourceCode }; + RHI::PrependArguments args; + args.m_sourceFile = fullPath.c_str(); + args.m_prependFile = shaderPlatformInterface->GetAzslHeader(platformInfo); + args.m_addSuffixToFileName = shaderPlatformInterface->GetAPIName().GetCStr(); + args.m_destinationStringOpt = &prependedAzslSourceCode; + if (RHI::PrependFile(args) == fullPath) { response.m_result = AssetBuilderSDK::CreateJobsResultCode::Failed; @@ -179,6 +184,7 @@ namespace AZ RHI::ShaderPlatformInterface* shaderPlatformInterface, AssetBuilderSDK::ProcessJobResponse& response, AzslData& azslData, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, RPI::Ptr shaderOptionGroupLayout, const RPI::ShaderSourceData& shaderSourceDataDescriptor, AZStd::sys_time_t shaderAssetBuildTimestamp, @@ -217,7 +223,7 @@ namespace AZ // Signal the begin of shader data for an RHI API. shaderAssetCreator.BeginAPI(shaderPlatformInterface->GetAPIType()); RHI::Ptr pipelineLayoutDescriptor = ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi( - ShaderAssetBuilderName, shaderPlatformInterface, bindingDependencies, srgAssets, shaderEntryPoints, &rootConstantData); + ShaderAssetBuilderName, shaderPlatformInterface, bindingDependencies, srgAssets, shaderEntryPoints, shaderCompilerArguments, &rootConstantData); if (!pipelineLayoutDescriptor) { AZ_Error(ShaderAssetBuilderName, false, "Failed to build pipeline layout descriptor for api=[%s]", @@ -257,6 +263,7 @@ namespace AZ variantCreationContext, *shaderPlatformInterface, azslData, + shaderCompilerArguments, pathOfProductFiles[ShaderBuilderUtility::AzslSubProducts::om], pathOfProductFiles[ShaderBuilderUtility::AzslSubProducts::ia]); if (!outcomeForShaderVariantAsset.IsSuccess()) @@ -483,8 +490,6 @@ namespace AZ // We define a merge behavior that is: ".shader wins if set" RHI::ShaderCompilerArguments mergedArguments = buildOptions.m_compilerArguments; mergedArguments.Merge(shaderAssetSource.m_compiler); - // pass it to the shader platform interface: - shaderPlatformInterface->SetExternalArguments(mergedArguments); AssetBuilderSDK::ProcessJobResultCode compileResult = CompileForAPI( @@ -493,6 +498,7 @@ namespace AZ shaderPlatformInterface, response, azslData, + mergedArguments, shaderOptionGroupLayout, shaderAssetSource, shaderAssetBuildTimestamp, diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp index 67af2e281f..c9933dc98a 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.cpp @@ -23,6 +23,7 @@ #include #include +#include #include @@ -316,6 +317,7 @@ namespace AZ BindingDependencies& bindingDependencies /*inout*/, const ShaderResourceGroupAssets& srgAssets, const MapOfStringToStageType& shaderEntryPoints, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, const RootConstantData* rootConstantData /*= nullptr*/) { PruneNonEntryFunctions(bindingDependencies, shaderEntryPoints); @@ -415,7 +417,7 @@ namespace AZ rootConstantInfo.m_totalSizeInBytes = rootConstantsLayout->GetDataSize(); // Build platform-specific PipelineLayoutDescriptor data, and finalize - if (!shaderPlatformInterface->BuildPipelineLayoutDescriptor(pipelineLayoutDescriptor, srgInfos, rootConstantInfo)) + if (!shaderPlatformInterface->BuildPipelineLayoutDescriptor(pipelineLayoutDescriptor, srgInfos, rootConstantInfo, shaderCompilerArguments)) { AZ_Error(BuilderName, false, "Failed to build pipeline layout descriptor"); return nullptr; diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h index 02e5315e6f..42cad593a6 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderBuilderUtility.h @@ -87,6 +87,7 @@ namespace AZ BindingDependencies& bindingDependencies /*inout*/, const ShaderResourceGroupAssets& srgAssets, const MapOfStringToStageType& shaderEntryPoints, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, const RootConstantData* rootConstantData = nullptr ); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 22a2e2fb00..738163a844 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -68,7 +68,7 @@ namespace AZ static constexpr char ShaderVariantAssetBuilderName[] = "ShaderVariantAssetBuilder"; static constexpr uint32_t ShaderVariantLoadErrorParam = 0; - static constexpr uint32_t ShaderPathJobParam = 2; + static constexpr uint32_t ShaderSourceFilePathJobParam = 2; static constexpr uint32_t ShaderVariantJobVariantParam = 3; static constexpr uint32_t ShouldExitEarlyFromProcessJobParam = 4; @@ -234,7 +234,7 @@ namespace AZ AZStd::string m_deferredMessage; // Only used when m_code == DeferredError }; - static LoadResult LoadShaderVariantList(const AZStd::string& variantListFullPath, RPI::ShaderVariantListSourceData& shaderVariantList, AZStd::string& shaderFullPath, + static LoadResult LoadShaderVariantList(const AZStd::string& variantListFullPath, RPI::ShaderVariantListSourceData& shaderVariantList, AZStd::string& shaderSourceFileFullPath, bool& shouldExitEarlyFromProcessJob) { // Need to get the name of the shader file from the template so that we can preprocess the shader data and setup @@ -251,9 +251,9 @@ namespace AZ return LoadResult{LoadResult::Code::DeferredError, AZStd::string::format("The shader path [%s] was not found.", resolvedShaderPath.c_str())}; } - shaderFullPath = resolvedShaderPath; + shaderSourceFileFullPath = resolvedShaderPath; - if (!ValidateShaderVariantListLocation(variantListFullPath, shaderFullPath, shouldExitEarlyFromProcessJob)) + if (!ValidateShaderVariantListLocation(variantListFullPath, shaderSourceFileFullPath, shouldExitEarlyFromProcessJob)) { return LoadResult{LoadResult::Code::Error}; } @@ -270,13 +270,13 @@ namespace AZ return LoadResult{LoadResult::Code::Error}; } - if (!IO::FileIOBase::GetInstance()->Exists(shaderFullPath.c_str())) + if (!IO::FileIOBase::GetInstance()->Exists(shaderSourceFileFullPath.c_str())) { - return LoadResult{LoadResult::Code::DeferredError, AZStd::string::format("ShaderSourceData file does not exist: %s.", shaderFullPath.c_str())}; + return LoadResult{LoadResult::Code::DeferredError, AZStd::string::format("ShaderSourceData file does not exist: %s.", shaderSourceFileFullPath.c_str())}; } // Let's open the shader source, because We need the source code of its AZSL file - auto outcomeShaderData = ShaderBuilderUtility::LoadShaderDataJson(shaderFullPath); + auto outcomeShaderData = ShaderBuilderUtility::LoadShaderDataJson(shaderSourceFileFullPath); if (!outcomeShaderData.IsSuccess()) { return LoadResult{LoadResult::Code::DeferredError, AZStd::string::format("Failed to parse Shader Descriptor JSON: %s", outcomeShaderData.GetError().c_str())}; @@ -292,9 +292,9 @@ namespace AZ AZ_TracePrintf(ShaderVariantAssetBuilderName, "CreateJobs for Shader Variant List \"%s\"\n", variantListFullPath.data()); RPI::ShaderVariantListSourceData shaderVariantList; - AZStd::string shaderFullPath; + AZStd::string shaderSourceFileFullPath; bool shouldExitEarlyFromProcessJob = false; - const LoadResult loadResult = LoadShaderVariantList(variantListFullPath, shaderVariantList, shaderFullPath, shouldExitEarlyFromProcessJob); + const LoadResult loadResult = LoadShaderVariantList(variantListFullPath, shaderVariantList, shaderSourceFileFullPath, shouldExitEarlyFromProcessJob); if (loadResult.m_code == LoadResult::Code::Error) { @@ -318,7 +318,7 @@ namespace AZ AZStd::vector platformInterfaces = ShaderBuilderUtility::DiscoverValidShaderPlatformInterfaces(info); for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces) { - AddAzslBuilderJobDependency(jobDescriptor, info.m_identifier, shaderPlatformInterface->GetAPIName().GetCStr(), shaderFullPath); + AddAzslBuilderJobDependency(jobDescriptor, info.m_identifier, shaderPlatformInterface->GetAPIName().GetCStr(), shaderSourceFileFullPath); } if (loadResult.m_code == LoadResult::Code::DeferredError) @@ -357,7 +357,7 @@ namespace AZ AddShaderAssetJobDependency(jobDescriptor, info, variantListFullPath, shaderVariantList.m_shaderFilePath); - jobDescriptor.m_jobParameters.emplace(ShaderPathJobParam, shaderFullPath); + jobDescriptor.m_jobParameters.emplace(ShaderSourceFilePathJobParam, shaderSourceFileFullPath); response.m_createJobOutputs.push_back(jobDescriptor); } @@ -392,7 +392,7 @@ namespace AZ jobDescriptor.m_jobDependencyList.emplace_back(variantTreeJobDependency); jobDescriptor.m_jobParameters.emplace(ShaderVariantJobVariantParam, variantInfoAsJsonString); - jobDescriptor.m_jobParameters.emplace(ShaderPathJobParam, shaderFullPath); + jobDescriptor.m_jobParameters.emplace(ShaderSourceFilePathJobParam, shaderSourceFileFullPath); response.m_createJobOutputs.push_back(jobDescriptor); } @@ -449,14 +449,14 @@ namespace AZ return; } - const AZStd::string& shaderFullPath = request.m_jobDescription.m_jobParameters.at(ShaderPathJobParam); + const AZStd::string& shaderSourceFileFullPath = request.m_jobDescription.m_jobParameters.at(ShaderSourceFilePathJobParam); //For debugging purposes will create a dummy azshadervarianttree file. AZStd::string shaderName; - AzFramework::StringFunc::Path::Split(shaderFullPath.c_str(), nullptr /*drive*/, nullptr /*path*/, & shaderName, nullptr /*extension*/); + AzFramework::StringFunc::Path::Split(shaderSourceFileFullPath.c_str(), nullptr /*drive*/, nullptr /*path*/, & shaderName, nullptr /*extension*/); RPI::ShaderSourceData shaderSourceDescriptor; - AZStd::shared_ptr azslSources = ShaderBuilderUtility::PrepareSourceInput(ShaderVariantAssetBuilderName, shaderFullPath, shaderSourceDescriptor); + AZStd::shared_ptr azslSources = ShaderBuilderUtility::PrepareSourceInput(ShaderVariantAssetBuilderName, shaderSourceFileFullPath, shaderSourceDescriptor); if (!azslSources) { response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; @@ -474,7 +474,7 @@ namespace AZ // Gracefully do nothing and continue with the next shaderPlatformInterface. AZ_TracePrintf( ShaderVariantAssetBuilderName, "Skipping shader variant tree compilation of [%s] for API [%s]\n", - shaderFullPath.c_str(), + shaderSourceFileFullPath.c_str(), shaderPlatformInterface->GetAPIName().GetCStr()); continue; } @@ -551,6 +551,7 @@ namespace AZ Data::Asset& shaderVariantAsset, RHI::ShaderPlatformInterface* shaderPlatformInterface, AzslData& azslData, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, const RPI::ShaderOptionGroupLayout& shaderOptionGroupLayout, const RPI::ShaderSourceData& shaderSourceDataDescriptor, AZStd::sys_time_t shaderAssetBuildTimestamp, @@ -583,7 +584,7 @@ namespace AZ } if (!ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi( - ShaderVariantAssetBuilderName, shaderPlatformInterface, bindingDependencies, srgAssets, shaderEntryPoints, &rootConstantData)) + ShaderVariantAssetBuilderName, shaderPlatformInterface, bindingDependencies, srgAssets, shaderEntryPoints, shaderCompilerArguments, &rootConstantData)) { AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to build pipeline layout descriptor for api=[%s]", shaderPlatformInterface->GetAPIName().GetCStr()); @@ -597,6 +598,7 @@ namespace AZ variantCreationContext, *shaderPlatformInterface, azslData, + shaderCompilerArguments, pathToOmJson, pathToIaJson); if (!outcomeForShaderVariantAsset.IsSuccess()) @@ -621,23 +623,23 @@ namespace AZ AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, true); const auto& jobParameters = request.m_jobDescription.m_jobParameters; - const AZStd::string& shaderFullPath = jobParameters.at(ShaderPathJobParam); + const AZStd::string& shaderSourceFileFullPath = jobParameters.at(ShaderSourceFilePathJobParam); const AZStd::string& variantJsonString = jobParameters.at(ShaderVariantJobVariantParam); RPI::ShaderVariantListSourceData::VariantInfo variantInfo; const bool toJsonStringSuccess = AZ::RPI::JsonUtils::LoadObjectFromJsonString(variantJsonString, variantInfo); AZ_Assert(toJsonStringSuccess, "Failed to convert json string to VariantInfo"); - auto shaderAssetOutcome = RPI::AssetUtils::LoadAsset(shaderFullPath); + auto shaderAssetOutcome = RPI::AssetUtils::LoadAsset(shaderSourceFileFullPath); if (!shaderAssetOutcome.IsSuccess()) { - AZ_Error(ShaderVariantAssetBuilderName, false, "The shader path [%s] could not be loaded.", shaderFullPath.c_str()); + AZ_Error(ShaderVariantAssetBuilderName, false, "The shader path [%s] could not be loaded.", shaderSourceFileFullPath.c_str()); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; return; } Data::Asset shaderAsset = shaderAssetOutcome.TakeValue(); RPI::ShaderSourceData shaderSourceDescriptor; - AZStd::shared_ptr sources = ShaderBuilderUtility::PrepareSourceInput(ShaderVariantAssetBuilderName, shaderFullPath, shaderSourceDescriptor); + AZStd::shared_ptr sources = ShaderBuilderUtility::PrepareSourceInput(ShaderVariantAssetBuilderName, shaderSourceFileFullPath, shaderSourceDescriptor); // Request the list of valid shader platform interfaces for the target platform. AZStd::vector platformInterfaces; @@ -652,13 +654,13 @@ namespace AZ // Gracefully do nothing and continue with the next shaderPlatformInterface. AZ_TracePrintf( ShaderVariantAssetBuilderName, "Skipping shader variant compilation of [%s] with StableId [%u] for API [%s]\n", - shaderFullPath.c_str(), variantInfo.m_stableId, shaderPlatformInterface->GetAPIName().GetCStr()); + shaderSourceFileFullPath.c_str(), variantInfo.m_stableId, shaderPlatformInterface->GetAPIName().GetCStr()); continue; } if (!shaderPlatformInterface) { - AZ_Error(ShaderVariantAssetBuilderName, false, "ShaderPlatformInterface for [%s] is not registered, can't compile [%s]", request.m_platformInfo.m_identifier.c_str(), shaderFullPath.c_str()); + AZ_Error(ShaderVariantAssetBuilderName, false, "ShaderPlatformInterface for [%s] is not registered, can't compile [%s]", request.m_platformInfo.m_identifier.c_str(), shaderSourceFileFullPath.c_str()); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; return; } @@ -714,11 +716,27 @@ namespace AZ return; } + GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderVariantAssetBuilderName); + + auto shaderSourceLoadResult = ShaderBuilderUtility::LoadShaderDataJson(shaderSourceFileFullPath); + if (!shaderSourceLoadResult.IsSuccess()) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to load/parse Shader Descriptor JSON: %s", shaderSourceLoadResult.GetError().c_str()); + return; + } + + // The idea of this merge is that we have compiler options coming from 2 source: + // global options (from project Config/), and .shader options. + // We define a merge behavior that is: ".shader wins if set" + RHI::ShaderCompilerArguments mergedArguments = buildOptions.m_compilerArguments; + mergedArguments.Merge(shaderSourceLoadResult.GetValue().m_compiler); + Data::Asset shaderVariantAsset; auto [success, byproducts] = CompileShaderVariantForAPI( shaderVariantAsset, shaderPlatformInterface, azslData, + mergedArguments, *shaderOptionGroupLayout, shaderSourceDescriptor, shaderAsset->GetShaderAssetBuildTimestamp(), @@ -740,7 +758,7 @@ namespace AZ // Time to save the asset in the cache tmp folder. const uint32_t productSubID = RPI::ShaderVariantAsset::GetAssetSubId(shaderPlatformInterface->GetAPIUniqueIndex(), shaderVariantAsset->GetStableId()); AssetBuilderSDK::JobProduct assetProduct; - if (!SerializeOutShaderVariantAsset(shaderVariantAsset, shaderFullPath, request.m_tempDirPath, *shaderPlatformInterface, productSubID, assetProduct)) + if (!SerializeOutShaderVariantAsset(shaderVariantAsset, shaderSourceFileFullPath, request.m_tempDirPath, *shaderPlatformInterface, productSubID, assetProduct)) { response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; return; @@ -811,6 +829,7 @@ namespace AZ static bool CreateShaderVariant( ShaderVariantCreationContext& variantCreationContext, const AzslData& azslData, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, RHI::ShaderPlatformInterface& shaderPlatformInterface, const size_t colorAttachmentCount, const RPI::ShaderVariantStableId variantStableId, @@ -834,7 +853,6 @@ namespace AZ auto assetBuilderShaderType = ShaderBuilderUtility::ToAssetBuilderShaderType(shaderStageType); AZStd::string variantShaderSourcePath; - auto crc = AZ::Crc32(azslData.m_shaderCodePrefix.data(), azslData.m_shaderCodePrefix.size()); // Check if we need to prepend any code prefix if (!azslData.m_shaderCodePrefix.empty()) @@ -868,7 +886,8 @@ namespace AZ shaderEntryName, assetBuilderShaderType, variantCreationContext.m_tempDirPath, - descriptor); + descriptor, + shaderCompilerArguments); if (!shaderWasCompiled) { @@ -1147,6 +1166,7 @@ namespace AZ ShaderVariantCreationContext& variantCreationContext, RHI::ShaderPlatformInterface& shaderPlatformInterface, AzslData& azslData, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, const AZStd::string& pathToOmJson, const AZStd::string& pathToIaJson) { @@ -1191,14 +1211,6 @@ namespace AZ optionList.push_back(OptionCache{ optionName, optionValue, optionIndex, value }); } - // The user might supply the option values in any order. Sort them now: - AZStd::sort(optionList.begin(), optionList.end(), [](const OptionCache& left, const OptionCache& right) - { - // m_optionIndex is the cached index in the m_options vector (stored in the ShaderOptionGroupLayout) - // m_options has already been sorted so the index *is* the option priority: - return left.m_optionIndex < right.m_optionIndex; - }); - // Create one instance of the shader variant RPI::ShaderOptionGroup optionGroup(&shaderOptionGroupLayout); @@ -1236,6 +1248,7 @@ namespace AZ if (!CreateShaderVariant( variantCreationContext, azslData, + shaderCompilerArguments, shaderPlatformInterface, colorAttachmentCount, shaderVariantStableId, @@ -1268,11 +1281,11 @@ namespace AZ } } - bool ShaderVariantAssetBuilder::SerializeOutShaderVariantAsset(const Data::Asset shaderVariantAsset, const AZStd::string& shaderFullPath, const AZStd::string& tempDirPath, + bool ShaderVariantAssetBuilder::SerializeOutShaderVariantAsset(const Data::Asset shaderVariantAsset, const AZStd::string& shaderSourceFileFullPath, const AZStd::string& tempDirPath, const RHI::ShaderPlatformInterface& shaderPlatformInterface, const uint32_t productSubID, AssetBuilderSDK::JobProduct& assetProduct) { AZStd::string shaderName; - AzFramework::StringFunc::Path::Split(shaderFullPath.c_str(), nullptr /*drive*/, nullptr /*path*/, &shaderName, nullptr /*extension*/); + AzFramework::StringFunc::Path::Split(shaderSourceFileFullPath.c_str(), nullptr /*drive*/, nullptr /*path*/, &shaderName, nullptr /*extension*/); AZStd::string filename = AZStd::string::format("%s_%s_%u.%s", shaderName.c_str(), shaderPlatformInterface.GetAPIName().GetCStr(), shaderVariantAsset->GetStableId().GetIndex(), RPI::ShaderVariantAsset::Extension); AZStd::string assetPath; diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h index 6c9129c5fe..7dd76f7ef1 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h @@ -66,6 +66,7 @@ namespace AZ ShaderVariantCreationContext& context, RHI::ShaderPlatformInterface& shaderPlatformInterface, AzslData& azslData, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, const AZStd::string& pathToOmJson, const AZStd::string& pathToIaJson); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp index 34a580f4d4..b4ebf9c28a 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp @@ -352,9 +352,9 @@ namespace AZ // The register number only makes sense if the platform uses "spaces", // since the register Id of the resource will not change even if the pipeline layout changes. - AZStd::string compilerParameters = shaderPlatformInterface->GetAzslCompilerParameters(); - bool useRegisterId = (AzFramework::StringFunc::Find(compilerParameters, "--use-spaces") != AZStd::string::npos); - AtomShaderConfig::AddParametersFromConfigFile(compilerParameters, request.m_platformInfo); + // We can pass in a default ShaderCompilerArguments because all we care about is whether the shaderPlatformInterface appends the "--use-spaces" flag. + AZStd::string azslCompilerParameters = shaderPlatformInterface->GetAzslCompilerParameters(RHI::ShaderCompilerArguments{}); + bool useRegisterId = (AzFramework::StringFunc::Find(azslCompilerParameters, "--use-spaces") != AZStd::string::npos); // Samplers for (const SamplerSrgData& samplerData : srgData.m_samplers) diff --git a/Gems/Atom/Bootstrap/Code/CMakeLists.txt b/Gems/Atom/Bootstrap/Code/CMakeLists.txt index fb80aa2bdd..5e5a8c96d9 100644 --- a/Gems/Atom/Bootstrap/Code/CMakeLists.txt +++ b/Gems/Atom/Bootstrap/Code/CMakeLists.txt @@ -22,7 +22,6 @@ ly_add_target( ly_add_target( NAME Atom_Bootstrap ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Bootstrap.c7ff89ad6e8b4b45b2fadef2bcf12d6e.v0.1.0 FILES_CMAKE bootstrap_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/Component/DebugCamera/Code/CMakeLists.txt b/Gems/Atom/Component/DebugCamera/Code/CMakeLists.txt index 998c8c74f3..acdf9189fd 100644 --- a/Gems/Atom/Component/DebugCamera/Code/CMakeLists.txt +++ b/Gems/Atom/Component/DebugCamera/Code/CMakeLists.txt @@ -30,7 +30,6 @@ ly_add_target( ly_add_target( NAME Atom_Component_DebugCamera ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Component_DebugCamera.013d1b42ad314c929b292c143bcbf045.v0.1.0 FILES_CMAKE atom_component_debugcamera_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader index 8ddf49655b..49725bedc9 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader @@ -14,6 +14,13 @@ "ReadMask" : "0x00", "WriteMask" : "0xFF", "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : { "Func" : "Always", "DepthFailOp" : "Keep", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass_EDS.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass_EDS.shader index 2b8cfd3202..6adbba952d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass_EDS.shader +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass_EDS.shader @@ -14,6 +14,13 @@ "ReadMask" : "0x00", "WriteMask" : "0xFF", "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : { "Func" : "Always", "DepthFailOp" : "Keep", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Shadowmap_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Shadowmap_WithPS.azsl index 984d9b43de..665f9a106d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Shadowmap_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Shadowmap_WithPS.azsl @@ -70,7 +70,7 @@ VertexOutput MainVS(VertexInput IN) struct PSDepthOutput { - float m_depth : SV_DepthLessEqual; + float m_depth : SV_DepthGreaterEqual; }; PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.shader index 46d3d60910..1af03e49da 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.shader +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.shader @@ -14,6 +14,13 @@ "ReadMask" : "0x00", "WriteMask" : "0xFF", "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : { "Func" : "Always", "DepthFailOp" : "Keep", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass_EDS.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass_EDS.shader index 87cbf4068a..ad2a06c208 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass_EDS.shader +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass_EDS.shader @@ -14,6 +14,13 @@ "ReadMask" : "0x00", "WriteMask" : "0xFF", "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : { "Func" : "Always", "DepthFailOp" : "Keep", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader index d5a53493c7..00f22643d7 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader @@ -14,6 +14,13 @@ "ReadMask" : "0x00", "WriteMask" : "0xFF", "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : { "Func" : "Always", "DepthFailOp" : "Keep", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass_EDS.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass_EDS.shader index 8609dc273e..4e7221d91c 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass_EDS.shader +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass_EDS.shader @@ -14,6 +14,13 @@ "ReadMask" : "0x00", "WriteMask" : "0xFF", "FrontFace" : + { + "Func" : "Always", + "DepthFailOp" : "Keep", + "FailOp" : "Keep", + "PassOp" : "Replace" + }, + "BackFace" : { "Func" : "Always", "DepthFailOp" : "Keep", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Shadowmap_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Shadowmap_WithPS.azsl index da93fc50b2..da6486619d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Shadowmap_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Shadowmap_WithPS.azsl @@ -70,7 +70,7 @@ VertexOutput MainVS(VertexInput IN) struct PSDepthOutput { - float m_depth : SV_DepthLessEqual; + float m_depth : SV_DepthGreaterEqual; }; PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace) diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt index 886707674a..cd1bf4f31a 100644 --- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt @@ -73,7 +73,6 @@ ly_add_target( ly_add_target( NAME Atom_Feature_Common ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Feature_Common.b58e5eed0901428ca78544b04dbd61bd.v0.1.0 FILES_CMAKE atom_feature_common_shared_files.cmake ../Assets/atom_feature_common_asset_files.cmake @@ -95,9 +94,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Atom_Feature_Common.Editor MODULE + NAME Atom_Feature_Common.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Feature_Common.Editor.b58e5eed0901428ca78544b04dbd61bd.v0.1.0 FILES_CMAKE atom_feature_common_editor_files.cmake INCLUDE_DIRECTORIES @@ -126,9 +125,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Atom_Feature_Common.Builders MODULE + NAME Atom_Feature_Common.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_Feature_Common.Builders.b58e5eed0901428ca78544b04dbd61bd.v0.1.0 FILES_CMAKE atom_feature_common_builders_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h index 1cd2cb89a8..06617ed20f 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h @@ -76,6 +76,18 @@ namespace AZ }; using FrameCaptureNotificationBus = EBus; + //! Stores the result of a frame capture request. + //! Includes the result type along with an optional error message if the request did not complete successfully. + struct FrameCaptureOutputResult + { + FrameCaptureResult m_result; //!< Outcome after attempting to capture a frame. + AZStd::optional m_errorMessage; //!< If the capture did not succeed, an optional diagnostic message is set. + }; + + //! Writes out content of ReadbackResult in the Dds image format. + FrameCaptureOutputResult DdsFrameCaptureOutput( + const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult); + } // namespace Render AZ_TYPE_INFO_SPECIALIZE(Render::FrameCaptureResult, "{F0B013CE-DFAE-4743-B123-EB1EE1705E03}"); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h index 9d186fc48e..1c220e0d8d 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h @@ -80,9 +80,10 @@ namespace AZ bool m_autoSelect = false; AZStd::string m_displayName; - AZ::Data::Asset m_skyboxImageAsset; - AZ::Data::Asset m_iblSpecularImageAsset; AZ::Data::Asset m_iblDiffuseImageAsset; + AZ::Data::Asset m_iblSpecularImageAsset; + AZ::Data::Asset m_skyboxImageAsset; + AZ::Data::Asset m_alternateSkyboxImageAsset; float m_iblExposure = 0.0f; float m_skyboxExposure = 0.0f; ExposureControlConfig m_exposure; @@ -99,7 +100,8 @@ namespace AZ const Camera::Configuration& cameraConfig, AZStd::vector& lightHandles, Data::Instance shadowCatcherMaterial = nullptr, - RPI::MaterialPropertyIndex shadowCatcherOpacityPropertyIndex = RPI::MaterialPropertyIndex()) const; + RPI::MaterialPropertyIndex shadowCatcherOpacityPropertyIndex = RPI::MaterialPropertyIndex(), + bool enableAlternateSkybox = false) const; }; using LightingPresetPtr = AZStd::shared_ptr; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h index 80dd803618..896d6fb78f 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace AZ { @@ -34,6 +35,7 @@ namespace AZ bool m_autoSelect = false; AZStd::string m_displayName; AZ::Data::Asset m_modelAsset; + AZ::Data::Asset m_previewImageAsset; }; using ModelPresetPtr = AZStd::shared_ptr; diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index c2cf999bcc..f85598bb79 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -38,6 +38,18 @@ namespace AZ { AZ_ENUM_DEFINE_REFLECT_UTILITIES(FrameCaptureResult); + FrameCaptureOutputResult DdsFrameCaptureOutput( + const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) + { + // write the read back result of the image attachment to a dds file + const auto outcome = AZ::DdsFile::WriteFile( + outputFilePath, + {readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, readbackResult.m_dataBuffer.get()}); + + return outcome.IsSuccess() ? FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt} + : FrameCaptureOutputResult{FrameCaptureResult::InternalError, outcome.GetError().m_message}; + } + class FrameCaptureNotificationBusHandler final : public FrameCaptureNotificationBus::Handler , public AZ::BehaviorEBusHandler @@ -392,18 +404,9 @@ namespace AZ } else if (extension == "dds") { - // write the read back result of the image attachment to a dds file - auto outcome = AZ::DdsFile::WriteFile(m_outputFilePath, { readbackResult.m_imageDescriptor.m_size, - readbackResult.m_imageDescriptor.m_format, readbackResult.m_dataBuffer.get() }); - if (outcome.IsSuccess()) - { - m_result = FrameCaptureResult::Success; - } - else - { - m_latestCaptureInfo = outcome.GetError().m_message; - m_result = FrameCaptureResult::InternalError; - } + const auto ddsFrameCapture = DdsFrameCaptureOutput(m_outputFilePath, readbackResult); + m_result = ddsFrameCapture.m_result; + m_latestCaptureInfo = ddsFrameCapture.m_errorMessage.value_or(""); } else { diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctor.h b/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctor.h index 44f27ffeed..f201b90e4b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctor.h @@ -42,10 +42,10 @@ namespace AZ uint32_t m_ev100Index; uint32_t m_nitIndex; - float m_ev100Min; - float m_ev100Max; - float m_nitMin; - float m_nitMax; + float m_ev100Min = 0.0f; + float m_ev100Max = 0.0f; + float m_nitMin = 0.0f; + float m_nitMax = 0.0f; }; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp index 64f599e1c3..dbbf666967 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp @@ -27,7 +27,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(2) + ->Version(3) ->Attribute(Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })); } } @@ -42,15 +42,16 @@ namespace AZ RPI::MaterialConverterBus::Handler::BusDisconnect(); } - bool MaterialConverterSystemComponent::ConvertMaterial(const AZ::SceneAPI::DataTypes::IMaterialData& materialData, RPI::MaterialSourceData& sourceData) + bool MaterialConverterSystemComponent::ConvertMaterial( + const AZ::SceneAPI::DataTypes::IMaterialData& materialData, RPI::MaterialSourceData& sourceData) { using namespace AZ::RPI; // The source data for generating material asset sourceData.m_materialType = GetMaterialTypePath(); - auto handleTexture = [&materialData, &sourceData](const char* propertyTextureGroup, SceneAPI::DataTypes::IMaterialData::TextureMapType textureType) - { + auto handleTexture = [&materialData, &sourceData]( + const char* propertyTextureGroup, SceneAPI::DataTypes::IMaterialData::TextureMapType textureType) { MaterialSourceData::PropertyMap& properties = sourceData.m_properties[propertyTextureGroup]; const AZStd::string& texturePath = materialData.GetTexture(textureType); @@ -61,14 +62,16 @@ namespace AZ using namespace AzToolsFramework; AZ::Data::AssetInfo sourceInfo; AZStd::string watchFolder; - AssetSystemRequestBus::BroadcastResult(assetFound, &AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, texturePath.c_str(), sourceInfo, watchFolder); + AssetSystemRequestBus::BroadcastResult( + assetFound, &AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, texturePath.c_str(), sourceInfo, + watchFolder); } if (assetFound) { properties["textureMap"].m_value = texturePath; } - else if(!texturePath.empty()) + else if (!texturePath.empty()) { AZ_Warning("AtomFeatureCommon", false, "Could not find asset '%s' for '%s'", texturePath.c_str(), propertyTextureGroup); } @@ -76,29 +79,54 @@ namespace AZ handleTexture("specularF0", SceneAPI::DataTypes::IMaterialData::TextureMapType::Specular); handleTexture("normal", SceneAPI::DataTypes::IMaterialData::TextureMapType::Normal); - handleTexture("baseColor", SceneAPI::DataTypes::IMaterialData::TextureMapType::BaseColor); - + AZStd::optional useColorMap = materialData.GetUseColorMap(); + // If the useColorMap property exists, this is a PBR material and the color should be set to baseColor. + if (useColorMap.has_value()) + { + handleTexture("baseColor", SceneAPI::DataTypes::IMaterialData::TextureMapType::BaseColor); + } + else + { + // If it doesn't have the useColorMap property, then it's a non-PBR material and the baseColor + // texture needs to be set to the diffuse texture. + handleTexture("baseColor", SceneAPI::DataTypes::IMaterialData::TextureMapType::Diffuse); + } auto toColor = [](const AZ::Vector3& v) { return AZ::Color::CreateFromVector3AndFloat(v, 1.0f); }; - sourceData.m_properties["baseColor"]["color"].m_value = toColor(materialData.GetBaseColor()); + + AZStd::optional baseColor = materialData.GetBaseColor(); + if (baseColor.has_value()) + { + sourceData.m_properties["baseColor"]["color"].m_value = toColor(baseColor.value()); + } sourceData.m_properties["opacity"]["factor"].m_value = materialData.GetOpacity(); + auto applyOptionalPropertiesFunc = [&sourceData](const auto& propertyGroup, const auto& propertyName, const auto& propertyOptional) + { + // Only set PBR settings if they were specifically set in the scene's data. + // Otherwise, leave them unset so the data driven default properties are used. + if (propertyOptional.has_value()) + { + sourceData.m_properties[propertyGroup][propertyName].m_value = propertyOptional.value(); + } + }; + handleTexture("metallic", SceneAPI::DataTypes::IMaterialData::TextureMapType::Metallic); - sourceData.m_properties["metallic"]["factor"].m_value = materialData.GetMetallicFactor(); - sourceData.m_properties["metallic"]["useTexture"].m_value = materialData.GetUseMetallicMap(); + applyOptionalPropertiesFunc("metallic", "factor", materialData.GetMetallicFactor()); + applyOptionalPropertiesFunc("metallic", "useTexture", materialData.GetUseMetallicMap()); handleTexture("roughness", SceneAPI::DataTypes::IMaterialData::TextureMapType::Roughness); - sourceData.m_properties["roughness"]["factor"].m_value = materialData.GetRoughnessFactor(); - sourceData.m_properties["roughness"]["useTexture"].m_value = materialData.GetUseRoughnessMap(); + applyOptionalPropertiesFunc("roughness", "factor", materialData.GetRoughnessFactor()); + applyOptionalPropertiesFunc("roughness", "useTexture", materialData.GetUseRoughnessMap()); handleTexture("emissive", SceneAPI::DataTypes::IMaterialData::TextureMapType::Emissive); - sourceData.m_properties["emissive"]["intensity"].m_value = materialData.GetEmissiveIntensity(); sourceData.m_properties["emissive"]["color"].m_value = toColor(materialData.GetEmissiveColor()); - sourceData.m_properties["emissive"]["useTexture"].m_value = materialData.GetUseEmissiveMap(); + applyOptionalPropertiesFunc("emissive", "intensity", materialData.GetEmissiveIntensity()); + applyOptionalPropertiesFunc("emissive", "useTexture", materialData.GetUseEmissiveMap()); handleTexture("ambientOcclusion", SceneAPI::DataTypes::IMaterialData::TextureMapType::AmbientOcclusion); - sourceData.m_properties["ambientOcclusion"]["useTexture"].m_value = materialData.GetUseAOMap(); + applyOptionalPropertiesFunc("ambientOcclusion", "useTexture", materialData.GetUseAOMap()); return true; } diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp index 6efd9bc326..e7f9c8b09f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp @@ -113,9 +113,10 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_displayName, "Display Name", "Identifier used for display and selection") ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_autoSelect, "Auto Select", "When true, the configuration is automatically selected when loaded") - ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_skyboxImageAsset, "Skybox Image Asset", "Skybox image asset reference") ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_iblDiffuseImageAsset, "IBL Diffuse Image Asset", "IBL diffuse image asset reference") ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_iblSpecularImageAsset, "IBL Specular Image Asset", "IBL specular image asset reference") + ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_skyboxImageAsset, "Skybox Image Asset", "Skybox image asset reference") + ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_alternateSkyboxImageAsset, "Skybox Image Asset (Alt)", "Alternate skybox image asset reference") ->DataElement(AZ::Edit::UIHandlers::Slider, &LightingPreset::m_skyboxExposure, "Skybox Exposure", "Skybox exposure") ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp index 3797acc08d..b8b0b610f3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp @@ -34,6 +34,7 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_displayName, "Display Name", "Identifier used for display and selection") ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_autoSelect, "Auto Select", "When true, the configuration is automatically selected when loaded") ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_modelAsset, "Model Asset", "Model asset reference") + ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_previewImageAsset, "Preview Image Asset", "Preview image asset reference") ; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp index 58100185c0..c2653964e3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp @@ -107,12 +107,13 @@ namespace AZ serializeContext->RegisterGenericType>(); serializeContext->Class() - ->Version(3) + ->Version(4) ->Field("autoSelect", &LightingPreset::m_autoSelect) ->Field("displayName", &LightingPreset::m_displayName) - ->Field("skyboxImageAsset", &LightingPreset::m_skyboxImageAsset) - ->Field("iblSpecularImageAsset", &LightingPreset::m_iblSpecularImageAsset) ->Field("iblDiffuseImageAsset", &LightingPreset::m_iblDiffuseImageAsset) + ->Field("iblSpecularImageAsset", &LightingPreset::m_iblSpecularImageAsset) + ->Field("skyboxImageAsset", &LightingPreset::m_skyboxImageAsset) + ->Field("alternateSkyboxImageAsset", &LightingPreset::m_alternateSkyboxImageAsset) ->Field("iblExposure", &LightingPreset::m_iblExposure) ->Field("skyboxExposure", &LightingPreset::m_skyboxExposure) ->Field("shadowCatcherOpacity", &LightingPreset::m_shadowCatcherOpacity) @@ -132,6 +133,7 @@ namespace AZ ->Constructor() ->Property("autoSelect", BehaviorValueProperty(&LightingPreset::m_autoSelect)) ->Property("displayName", BehaviorValueProperty(&LightingPreset::m_displayName)) + ->Property("alternateSkyboxImageAsset", BehaviorValueProperty(&LightingPreset::m_alternateSkyboxImageAsset)) ->Property("skyboxImageAsset", BehaviorValueProperty(&LightingPreset::m_skyboxImageAsset)) ->Property("iblSpecularImageAsset", BehaviorValueProperty(&LightingPreset::m_iblSpecularImageAsset)) ->Property("iblDiffuseImageAsset", BehaviorValueProperty(&LightingPreset::m_iblDiffuseImageAsset)) @@ -152,7 +154,8 @@ namespace AZ const Camera::Configuration& cameraConfig, AZStd::vector& lightHandles, Data::Instance shadowCatcherMaterial, - RPI::MaterialPropertyIndex shadowCatcherOpacityPropertyIndex) const + RPI::MaterialPropertyIndex shadowCatcherOpacityPropertyIndex, + bool enableAlternateSkybox) const { if (iblFeatureProcessor) { @@ -163,7 +166,8 @@ namespace AZ if (skyboxFeatureProcessor) { - skyboxFeatureProcessor->SetCubemap(RPI::StreamingImage::FindOrCreate(m_skyboxImageAsset)); + auto skyboxAsset = (enableAlternateSkybox && m_alternateSkyboxImageAsset.GetId().IsValid()) ? m_alternateSkyboxImageAsset : m_skyboxImageAsset; + skyboxFeatureProcessor->SetCubemap(RPI::StreamingImage::FindOrCreate(skyboxAsset)); skyboxFeatureProcessor->SetCubemapExposure(m_skyboxExposure); } diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp index b9eb411152..d9f4775a26 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp @@ -25,10 +25,11 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("autoSelect", &ModelPreset::m_autoSelect) ->Field("displayName", &ModelPreset::m_displayName) ->Field("modelAsset", &ModelPreset::m_modelAsset) + ->Field("previewImageAsset", &ModelPreset::m_previewImageAsset) ; } @@ -44,6 +45,7 @@ namespace AZ ->Property("autoSelect", BehaviorValueProperty(&ModelPreset::m_autoSelect)) ->Property("displayName", BehaviorValueProperty(&ModelPreset::m_displayName)) ->Property("modelAsset", BehaviorValueProperty(&ModelPreset::m_modelAsset)) + ->Property("previewImageAsset", BehaviorValueProperty(&ModelPreset::m_previewImageAsset)) ; } } diff --git a/Gems/Atom/RHI/Code/CMakeLists.txt b/Gems/Atom/RHI/Code/CMakeLists.txt index a4815cc653..00c53f1ac6 100644 --- a/Gems/Atom/RHI/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Code/CMakeLists.txt @@ -68,7 +68,6 @@ ly_add_target( ly_add_target( NAME Atom_RHI.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI.Private.fb7f322c8bdb42228d9e155c954f98bd.v0.1.0 FILES_CMAKE atom_rhi_private_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h index dcb56c4253..ebae451770 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h @@ -51,6 +51,9 @@ namespace AZ //! This class provides a platform agnostic interface for the creation //! and manipulation of platform shader objects. + //! WARNING: The ShaderPlatformInterface objects are singletons and will be used to process multiple shader compilation jobs. + //! Do not store per-job configuration data in any ShaderPlatformInterface classes, as it may get stomped. Instead, pass + //! any per-job configuration on the call stack. class ShaderPlatformInterface { public: @@ -123,16 +126,17 @@ namespace AZ const AZStd::string& functionName, ShaderHardwareStage shaderStage, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const = 0; + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const = 0; //! Get the parameters (except warning related) from that platform interface, and the configuration files. - virtual AZStd::string GetAzslCompilerParameters() const = 0; + virtual AZStd::string GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const = 0; //! Get only the warning-related parameters from that platform interface. - virtual AZStd::string GetAzslCompilerWarningParameters() const = 0; + virtual AZStd::string GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const = 0; //! Query whether the shaders are set to build with debug information - virtual bool BuildHasDebugInfo() const = 0; + virtual bool BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const = 0; //! Get the filename of include file to prefix shader programs with virtual const char* GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const = 0; @@ -142,23 +146,20 @@ namespace AZ virtual bool BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptor, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) = 0; + const RootConstantsInfo& rootConstantsInfo, + const ShaderCompilerArguments& shaderCompilerArguments) = 0; //! See AZ::RHI::Factory::GetAPIUniqueIndex() for details. //! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax. uint32_t GetAPIUniqueIndex() const { return m_apiUniqueIndex; } - //! To set when you can read from a config file: additional arguments or compiler settings - void SetExternalArguments(const ShaderCompilerArguments& arguments) - { - m_settings = arguments; - } - - protected: - ShaderCompilerArguments m_settings; - private: ShaderPlatformInterface() = delete; + + //! WARNING: The ShaderPlatformInterface objects are singletons and will be used to process multiple shader compilation jobs. + //! Do not store per-job configuration data in any ShaderPlatformInterface classes, as it may get stomped. Instead, pass + //! any per-job configuration on the call stack. + const uint32_t m_apiUniqueIndex; }; } diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h index 84eea204cd..3e593794af 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/Utils.h @@ -52,7 +52,7 @@ namespace AZ { const char* m_sourceFile; const char* m_prependFile; - const char* m_addSuffixToFileName; + const char* m_addSuffixToFileName = nullptr; //!< optional const char* m_destinationFolder = nullptr; //!< optional. if not set, will just use sourceFile's folder AZStd::string* m_destinationStringOpt = nullptr; //!< when not null, PrependFile() will dump the result in that string rather than on disk. ArrayOfCharForMd5* m_digest = nullptr; //! optionally run a hash diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Format.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Format.h index 15f3485460..5e70972e9a 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Format.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Format.h @@ -133,6 +133,7 @@ namespace AZ P8, A8P8, B4G4R4A4_UNORM, + R4G4B4A4_UNORM, R10G10B10_7E3_A2_FLOAT, R10G10B10_6E4_A2_FLOAT, D16_UNORM_S8_UINT, diff --git a/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp b/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp index 6576a5dd99..00b5dada69 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Edit/Utils.cpp @@ -14,8 +14,8 @@ #include -#include -#include +#include +#include #include #include @@ -176,7 +176,16 @@ namespace AZ AZStd::string combinedFile; if (arguments.m_destinationFolder) { - combinedFile = arguments.m_destinationFolder; + AZStd::string filename; + if(AzFramework::StringFunc::Path::GetFullFileName(sourceFileAbsolutePath->c_str(), filename)) + { + combinedFile = AZStd::string::format("%s/%s", arguments.m_destinationFolder, filename.c_str()); + } + else + { + AZ_Error(ShaderPlatformInterfaceName, false, "GetFullFileName('%s') failed", sourceFileAbsolutePath->c_str()); + return *sourceFileAbsolutePath; + } } else { @@ -248,10 +257,10 @@ namespace AZ return false; } - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" %s", executableAbsolutePath.c_str(), parameters.c_str()); processLaunchInfo.m_showWindow = true; - processLaunchInfo.m_processPriority = AzToolsFramework::PROCESSPRIORITY_NORMAL; + processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; { AZStd::string contextKey = toolNameForLog + AZStd::string(" Input File"); @@ -263,14 +272,14 @@ namespace AZ } AZ_TracePrintf(ShaderPlatformInterfaceName, "Executing '%s' ...", processLaunchInfo.m_commandlineParameters.c_str()); - AzToolsFramework::ProcessWatcher* watcher = AzToolsFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzToolsFramework::COMMUNICATOR_TYPE_STDINOUT); + AzFramework::ProcessWatcher* watcher = AzFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzFramework::COMMUNICATOR_TYPE_STDINOUT); if (!watcher) { AZ_Error(ShaderPlatformInterfaceName, false, "Shader compiler could not be launched"); return false; } - AZStd::unique_ptr watcherPtr = AZStd::unique_ptr(watcher); + AZStd::unique_ptr watcherPtr = AZStd::unique_ptr(watcher); AZStd::string errorMessages; auto pumpOuputStreams = [&watcherPtr, &errorMessages]() diff --git a/Gems/Atom/RHI/DX12/Code/CMakeLists.txt b/Gems/Atom/RHI/DX12/Code/CMakeLists.txt index fb7f8e4c95..f12469d1b7 100644 --- a/Gems/Atom/RHI/DX12/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/DX12/Code/CMakeLists.txt @@ -46,7 +46,6 @@ if(NOT PAL_TRAIT_ATOM_RHI_DX12_SUPPORTED) ly_add_target( NAME Atom_RHI_DX12.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_DX12.Private.e011969cf32442fdaac2443a960ab5ff.v0.1.0 FILES_CMAKE atom_rhi_dx12_stub_module.cmake BUILD_DEPENDENCIES @@ -56,9 +55,9 @@ if(NOT PAL_TRAIT_ATOM_RHI_DX12_SUPPORTED) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Atom_RHI_DX12.Builders MODULE + NAME Atom_RHI_DX12.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_DX12.Builders.e011969cf32442fdaac2443a960ab5ff.v0.1.0 FILES_CMAKE Source/Platform/${PAL_PLATFORM_NAME}/platform_builders_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake atom_rhi_dx12_reflect_common_files.cmake @@ -136,7 +135,6 @@ ly_add_target( ly_add_target( NAME Atom_RHI_DX12.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_DX12.Private.e011969cf32442fdaac2443a960ab5ff.v0.1.0 FILES_CMAKE atom_rhi_dx12_private_common_shared_files.cmake INCLUDE_DIRECTORIES @@ -182,9 +180,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Atom_RHI_DX12.Builders MODULE + NAME Atom_RHI_DX12.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_DX12.Builders.e011969cf32442fdaac2443a960ab5ff.v0.1.0 FILES_CMAKE atom_rhi_dx12_builders_common_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/NsightAftermathGpuCrashTracker_Windows.cpp b/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/NsightAftermathGpuCrashTracker_Windows.cpp index 04c58d540f..a69aa0ce02 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/NsightAftermathGpuCrashTracker_Windows.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/NsightAftermathGpuCrashTracker_Windows.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -91,16 +92,8 @@ void GpuCrashTracker::OnDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescripti // Add some basic description about the crash. This is called after the GPU crash happens, but before // the actual GPU crash dump callback. The provided data is included in the crash dump and can be // retrieved using GFSDK_Aftermath_GpuCrashDump_GetDescription(). - AZ::SettingsRegistryInterface::FixedValueString projectName; - auto settingsRegistry = AZ::Interface::Get(); - - auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); - settingsRegistry->Get(projectName, projectKey); - - static const char* executableFolder = nullptr; - AZStd::string fileAbsolutePath; AZ::ComponentApplicationBus::BroadcastResult(executableFolder, &AZ::ComponentApplicationBus::Events::GetExecutableFolder); - AzFramework::StringFunc::Path::Join(executableFolder, projectName.c_str(), fileAbsolutePath); + fileAbsolutePath /= AZ::Utils::GetProjectName(); addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, fileAbsolutePath.c_str()); addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationVersion, "v1.0"); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp index 203441d897..119c1a42db 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp @@ -88,7 +88,8 @@ namespace AZ bool ShaderPlatformInterface::BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptorBase, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) + const RootConstantsInfo& rootConstantsInfo, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) { PipelineLayoutDescriptor* pipelineLayoutDescriptor = azrtti_cast(pipelineLayoutDescriptorBase.get()); AZ_Assert(pipelineLayoutDescriptor, "PipelineLayoutDescriptor should have been created by now"); @@ -116,7 +117,7 @@ namespace AZ } } - if (m_settings.m_dxcDisableOptimizations) + if (shaderCompilerArguments.m_dxcDisableOptimizations) { // When optimizations are disabled (-Od), all resources declared in the source file are available to all stages // (when enabled only the resources which are referenced in a stage are bound to the stage) @@ -148,7 +149,8 @@ namespace AZ const AZStd::string& functionName, RHI::ShaderHardwareStage shaderStage, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { AZStd::vector shaderByteCode; @@ -158,6 +160,7 @@ namespace AZ tempFolderPath, // AP job temp folder functionName, // name of function that is the entry point shaderStage, // shader stage (vertex shader, pixel shader, ...) + shaderCompilerArguments, shaderByteCode, // compiled shader output outputDescriptor.m_byProducts); // dynamic branch count output & byproduct files @@ -182,20 +185,20 @@ namespace AZ return true; } - AZStd::string ShaderPlatformInterface::GetAzslCompilerParameters() const + AZStd::string ShaderPlatformInterface::GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.MakeAdditionalAzslcCommandLineString() + + return shaderCompilerArguments.MakeAdditionalAzslcCommandLineString() + " --use-spaces --namespace=dx --root-const=128"; } - AZStd::string ShaderPlatformInterface::GetAzslCompilerWarningParameters() const + AZStd::string ShaderPlatformInterface::GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.MakeAdditionalAzslcWarningCommandLineString(); + return shaderCompilerArguments.MakeAdditionalAzslcWarningCommandLineString(); } - bool ShaderPlatformInterface::BuildHasDebugInfo() const + bool ShaderPlatformInterface::BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.m_dxcGenerateDebugInfo; + return shaderCompilerArguments.m_dxcGenerateDebugInfo; } const char* ShaderPlatformInterface::GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const @@ -209,6 +212,7 @@ namespace AZ const AZStd::string& tempFolder, const AZStd::string& entryPoint, const RHI::ShaderHardwareStage shaderStageType, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, AZStd::vector& compiledShader, ByProducts& byProducts) const { @@ -253,7 +257,7 @@ namespace AZ } // Compilation parameters - AZStd::string params = m_settings.MakeAdditionalDxcCommandLineString(); + AZStd::string params = shaderCompilerArguments.MakeAdditionalDxcCommandLineString(); // Enable half precision types when shader model >= 6.2 int shaderModelMajor = 0; @@ -267,13 +271,18 @@ namespace AZ AZ::StringFunc::TrimWhiteSpace(params, true, false); // we don't need the extra leading spaces that tend to build up unsigned char md5[RHI::Md5NumBytes]; - RHI::PrependArguments args{ shaderSourceFile.c_str(), PlatformShaderHeader, "", tempFolder.c_str(), nullptr, &md5 }; + RHI::PrependArguments args; + args.m_sourceFile = shaderSourceFile.c_str(); + args.m_prependFile = PlatformShaderHeader; + args.m_destinationFolder = tempFolder.c_str(); + args.m_digest = &md5; + const auto dxcInputFile = RHI::PrependFile(args); // Prepend PAL header & obtain hash // -Fd "Write debug information to the given file, or automatically named file in directory when ending in '\\'" // If we use the auto-name (hash), there is no way we can retrieve that name apart from listing the directory. // Instead, let's just generate that hash ourselves. AZStd::string symbolDatabaseFileCliArgument{" "}; // when not debug: still insert a space between 5.dxil and 7.hlsl-in - if (BuildHasDebugInfo()) + if (BuildHasDebugInfo(shaderCompilerArguments)) { // prepare .ldd filename: AZStd::string md5hex = RHI::ByteToHexString(md5); @@ -343,7 +352,7 @@ namespace AZ byProducts.m_dynamicBranchCount = ByProducts::UnknownDynamicBranchCount; } - if (BuildHasDebugInfo()) + if (BuildHasDebugInfo(shaderCompilerArguments)) { byProducts.m_intermediatePaths.emplace(AZStd::move(objectCodeOutputFile)); } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.h b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.h index fa6e45a249..88b6923785 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.h @@ -38,7 +38,8 @@ namespace AZ bool BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptor, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) override; + const RootConstantsInfo& rootConstantsInfo, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) override; bool CompilePlatformInternal( const AssetBuilderSDK::PlatformInfo& platform, @@ -46,13 +47,14 @@ namespace AZ const AZStd::string& functionName, RHI::ShaderHardwareStage shaderStage, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const override; + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; - AZStd::string GetAzslCompilerParameters() const override; + AZStd::string GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; - AZStd::string GetAzslCompilerWarningParameters() const override; + AZStd::string GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; - bool BuildHasDebugInfo() const override; + bool BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; const char* GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const override; @@ -64,6 +66,7 @@ namespace AZ const AZStd::string& tempFolder, const AZStd::string& entryPoint, const RHI::ShaderHardwareStage shaderStageType, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, AZStd::vector& m_byteCode, ByProducts& products) const; diff --git a/Gems/Atom/RHI/Metal/Code/CMakeLists.txt b/Gems/Atom/RHI/Metal/Code/CMakeLists.txt index bf027ad431..e658a66257 100644 --- a/Gems/Atom/RHI/Metal/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Metal/Code/CMakeLists.txt @@ -17,7 +17,6 @@ include(${pal_source_dir}/PAL2_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) if(NOT PAL_TRAIT_ATOM_RHI_METAL_SUPPORTED) ly_add_target( NAME Atom_RHI_Metal.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} - OUTPUT_NAME Gem.Atom_RHI_Metal.Private.5f27cdc951e64fe0be9d823dc7acbc28.v0.1.0 NAMESPACE Gem FILES_CMAKE atom_rhi_metal_stub_module.cmake @@ -35,8 +34,8 @@ if(NOT PAL_TRAIT_ATOM_RHI_METAL_SUPPORTED) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Atom_RHI_Metal.Builders MODULE - OUTPUT_NAME Gem.Atom_RHI_Metal.Builders.5f27cdc951e64fe0be9d823dc7acbc28.v0.1.0 + NAME Atom_RHI_Metal.Builders GEM_MODULE + NAMESPACE Gem FILES_CMAKE Source/Platform/${PAL_PLATFORM_NAME}/platform_builders_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake @@ -101,7 +100,6 @@ ly_add_target( ly_add_target( NAME Atom_RHI_Metal.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_Metal.Private.5f27cdc951e64fe0be9d823dc7acbc28.v0.1.0 FILES_CMAKE atom_rhi_metal_private_common_shared_files.cmake PLATFORM_INCLUDE_FILES @@ -146,9 +144,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Atom_RHI_Metal.Builders MODULE + NAME Atom_RHI_Metal.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_Metal.Builders.5f27cdc951e64fe0be9d823dc7acbc28.v0.1.0 FILES_CMAKE atom_rhi_metal_builders_shared_files.cmake PLATFORM_INCLUDE_FILES diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp index 67faabf4e1..9b8e0e2d58 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp @@ -60,7 +60,8 @@ namespace AZ bool ShaderPlatformInterface::BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptor, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) + const RootConstantsInfo& rootConstantsInfo, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) { AZ::Metal::PipelineLayoutDescriptor* metalDescriptor = azrtti_cast(pipelineLayoutDescriptor.get()); AZ_Assert(metalDescriptor, "PipelineLayoutDescriptor should have been created by now"); @@ -154,22 +155,22 @@ namespace AZ return (shaderStageType == RHI::ShaderHardwareStage::RayTracing); } - AZStd::string ShaderPlatformInterface::GetAzslCompilerParameters() const + AZStd::string ShaderPlatformInterface::GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { // Note: all platforms use DirectX packing rules. We enable vk namespace as well to allow // for vk syntax to carry through from dxc to spirv-cross. - return m_settings.MakeAdditionalAzslcCommandLineString() + + return shaderCompilerArguments.MakeAdditionalAzslcCommandLineString() + " --use-spaces --unique-idx --namespace=mt,vk --root-const=128"; } - AZStd::string ShaderPlatformInterface::GetAzslCompilerWarningParameters() const + AZStd::string ShaderPlatformInterface::GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.MakeAdditionalAzslcWarningCommandLineString(); + return shaderCompilerArguments.MakeAdditionalAzslcWarningCommandLineString(); } - bool ShaderPlatformInterface::BuildHasDebugInfo() const + bool ShaderPlatformInterface::BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.m_dxcGenerateDebugInfo; + return shaderCompilerArguments.m_dxcGenerateDebugInfo; } const char* ShaderPlatformInterface::GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const @@ -190,7 +191,8 @@ namespace AZ const AZStd::string& functionName, RHI::ShaderHardwareStage shaderStage, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { for (auto srgLayout : m_srgLayouts) { @@ -206,6 +208,7 @@ namespace AZ tempFolderPath, // AP temp folder for the job functionName, // name of function that is the entry point shaderStage, // shader stage (vertex shader, pixel shader, ...) + shaderCompilerArguments, shaderSourceCode, // cross-compiled shader output shaderByteCode, // compiled byte code platform, // target platform @@ -241,6 +244,7 @@ namespace AZ const AZStd::string& tempFolder, const AZStd::string& entryPoint, const RHI::ShaderHardwareStage shaderType, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, AZStd::vector& sourceMetalShader, AZStd::vector& compiledByteCode, const AssetBuilderSDK::PlatformInfo& platform, @@ -275,7 +279,7 @@ namespace AZ AZStd::string shaderSpirvOutputFile = RHI::BuildFileNameWithExtension(shaderSourceFile, tempFolder, "spirv"); // Compilation parameters - AZStd::string params = m_settings.MakeAdditionalDxcCommandLineString(); + AZStd::string params = shaderCompilerArguments.MakeAdditionalDxcCommandLineString(); params += " -spirv"; // Generate SPIRV shader // Enable half precision types when shader model >= 6.2 @@ -299,7 +303,10 @@ namespace AZ prependFile = MacPlatformShaderHeader; } - RHI::PrependArguments args{ shaderSourceFile.c_str(), prependFile.c_str(), "", tempFolder.c_str() }; + RHI::PrependArguments args; + args.m_sourceFile = shaderSourceFile.c_str(); + args.m_prependFile = prependFile.c_str(); + args.m_destinationFolder = tempFolder.c_str(); const auto dxcInputFile = RHI::PrependFile(args); if (BuildHasDebugInfo()) diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h index e8ead2c15e..ef99968900 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h @@ -42,7 +42,8 @@ namespace AZ bool BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptor, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) override; + const RootConstantsInfo& rootConstantsInfo, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) override; bool CompilePlatformInternal( const AssetBuilderSDK::PlatformInfo& platform, @@ -50,11 +51,12 @@ namespace AZ const AZStd::string& functionName, RHI::ShaderHardwareStage shaderStage, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const override; + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; - AZStd::string GetAzslCompilerParameters() const; - AZStd::string GetAzslCompilerWarningParameters() const; - bool BuildHasDebugInfo() const override; + AZStd::string GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const; + AZStd::string GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const; + bool BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; const char* GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const override; @@ -66,6 +68,7 @@ namespace AZ const AZStd::string& tempFolder, const AZStd::string& entryPoint, const RHI::ShaderHardwareStage shaderAssetType, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, AZStd::vector& compiledShader, AZStd::vector& compiledByteCode, const AssetBuilderSDK::PlatformInfo& platform, diff --git a/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt b/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt index 78305d89b9..f433c24fd3 100644 --- a/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Vulkan/Code/CMakeLists.txt @@ -20,7 +20,6 @@ if(NOT PAL_TRAIT_ATOM_RHI_VULKAN_SUPPORTED) ly_add_target( NAME Atom_RHI_Vulkan.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_Vulkan.Private.150d40d376124d98a388dfe890551c03.v0.1.0 FILES_CMAKE atom_rhi_vulkan_stub_module.cmake INCLUDE_DIRECTORIES @@ -36,9 +35,9 @@ if(NOT PAL_TRAIT_ATOM_RHI_VULKAN_SUPPORTED) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Atom_RHI_Vulkan.Builders MODULE + NAME Atom_RHI_Vulkan.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_Vulkan.Builders.150d40d376124d98a388dfe890551c03.v0.1.0 FILES_CMAKE ${pal_source_dir}/platform_builders_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake atom_rhi_vulkan_reflect_common_files.cmake @@ -117,7 +116,6 @@ ly_add_target( ly_add_target( NAME Atom_RHI_Vulkan.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_Vulkan.Private.150d40d376124d98a388dfe890551c03.v0.1.0 FILES_CMAKE atom_rhi_vulkan_private_common_shared_files.cmake INCLUDE_DIRECTORIES @@ -176,9 +174,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Atom_RHI_Vulkan.Builders MODULE + NAME Atom_RHI_Vulkan.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RHI_Vulkan.Builders.150d40d376124d98a388dfe890551c03.v0.1.0 FILES_CMAKE ${pal_source_dir}/platform_builders_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp index c703f3dab5..6d2addfabe 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp @@ -87,30 +87,32 @@ namespace AZ bool ShaderPlatformInterface::BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptor, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) + const RootConstantsInfo& rootConstantsInfo, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) { AZ_UNUSED(srgInfoList); AZ_UNUSED(rootConstantsInfo); + AZ_UNUSED(shaderCompilerArguments); // Nothing to do, so we just finalize the layout descriptor. return pipelineLayoutDescriptor->Finalize() == RHI::ResultCode::Success; } - AZStd::string ShaderPlatformInterface::GetAzslCompilerParameters() const + AZStd::string ShaderPlatformInterface::GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { // Note: all platforms use DirectX packing rules. - return m_settings.MakeAdditionalAzslcCommandLineString() + + return shaderCompilerArguments.MakeAdditionalAzslcCommandLineString() + " --use-spaces --unique-idx --namespace=vk --root-const=128"; } - AZStd::string ShaderPlatformInterface::GetAzslCompilerWarningParameters() const + AZStd::string ShaderPlatformInterface::GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.MakeAdditionalAzslcWarningCommandLineString(); + return shaderCompilerArguments.MakeAdditionalAzslcWarningCommandLineString(); } - bool ShaderPlatformInterface::BuildHasDebugInfo() const + bool ShaderPlatformInterface::BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { - return m_settings.m_dxcGenerateDebugInfo; + return shaderCompilerArguments.m_dxcGenerateDebugInfo; } const char* ShaderPlatformInterface::GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const @@ -133,7 +135,8 @@ namespace AZ const AZStd::string& functionName, RHI::ShaderHardwareStage shaderAssetType, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const { AZStd::vector shaderByteCode; @@ -143,6 +146,7 @@ namespace AZ tempFolderPath, // AP temp folder for the job functionName, // name of function that is the entry point shaderAssetType, // shader stage (vertex shader, pixel shader, ...) + shaderCompilerArguments, shaderByteCode, // compiled shader output platform, // target platform outputDescriptor.m_byProducts); // dynamic branch count output & debug dumps @@ -174,6 +178,7 @@ namespace AZ const AZStd::string& tempFolder, const AZStd::string& entryPoint, const RHI::ShaderHardwareStage shaderStageType, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, AZStd::vector& compiledShader, const AssetBuilderSDK::PlatformInfo& platform, ByProducts& byProducts) const @@ -215,7 +220,7 @@ namespace AZ } // Compilation parameters - AZStd::string params = m_settings.MakeAdditionalDxcCommandLineString(); + AZStd::string params = shaderCompilerArguments.MakeAdditionalDxcCommandLineString(); params += " -spirv"; // Generate SPIRV shader switch (shaderStageType) @@ -273,10 +278,13 @@ namespace AZ prependFile = WindowsPlatformShaderHeader; } - RHI::PrependArguments args{ shaderSourceFile.c_str(), prependFile.c_str(), "", tempFolder.c_str() }; + RHI::PrependArguments args; + args.m_sourceFile = shaderSourceFile.c_str(); + args.m_prependFile = prependFile.c_str(); + args.m_destinationFolder = tempFolder.c_str(); const auto dxcInputFile = RHI::PrependFile(args); // Prepend header - if (BuildHasDebugInfo()) + if (BuildHasDebugInfo(shaderCompilerArguments)) { // dump intermediate "true final HLSL" file (shadername.vulkan.shadersource.prepend) byProducts.m_intermediatePaths.insert(dxcInputFile); @@ -329,7 +337,7 @@ namespace AZ byProducts.m_dynamicBranchCount = ByProducts::UnknownDynamicBranchCount; } - if (BuildHasDebugInfo()) + if (BuildHasDebugInfo(shaderCompilerArguments)) { byProducts.m_intermediatePaths.emplace(AZStd::move(objectCodeOutputFile)); } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.h index 33b9e05eb1..c6e1f988d5 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI.Builders/ShaderPlatformInterface.h @@ -42,7 +42,8 @@ namespace AZ bool BuildPipelineLayoutDescriptor( RHI::Ptr pipelineLayoutDescriptor, const ShaderResourceGroupInfoList& srgInfoList, - const RootConstantsInfo& rootConstantsInfo) override; + const RootConstantsInfo& rootConstantsInfo, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) override; bool CompilePlatformInternal( const AssetBuilderSDK::PlatformInfo& platform, @@ -50,11 +51,12 @@ namespace AZ const AZStd::string& functionName, RHI::ShaderHardwareStage shaderStage, const AZStd::string& tempFolderPath, - StageDescriptor& outputDescriptor) const override; + StageDescriptor& outputDescriptor, + const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; - AZStd::string GetAzslCompilerParameters() const override; - AZStd::string GetAzslCompilerWarningParameters() const override; - bool BuildHasDebugInfo() const override; + AZStd::string GetAzslCompilerParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; + AZStd::string GetAzslCompilerWarningParameters(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; + bool BuildHasDebugInfo(const RHI::ShaderCompilerArguments& shaderCompilerArguments) const override; const char* GetAzslHeader(const AssetBuilderSDK::PlatformInfo& platform) const override; @@ -66,6 +68,7 @@ namespace AZ const AZStd::string& tempFolder, const AZStd::string& entryPoint, const RHI::ShaderHardwareStage shaderAssetType, + const RHI::ShaderCompilerArguments& shaderCompilerArguments, AZStd::vector& compiledShader, const AssetBuilderSDK::PlatformInfo& platform, ByProducts& byProducts) const; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Formats.inl b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Formats.inl index 6ab4efdb7e..ec508c8d9b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Formats.inl +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Formats.inl @@ -91,6 +91,7 @@ _Func(P010, VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, 1, 0, 0) \ _Func(P016, VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, 1, 0, 0) \ _Func(B4G4R4A4_UNORM, VK_FORMAT_B4G4R4A4_UNORM_PACK16, 1, 0, 0) \ + _Func(R4G4B4A4_UNORM, VK_FORMAT_R4G4B4A4_UNORM_PACK16, 1, 0, 0) \ _Func(D16_UNORM_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, 0, 1, 1) \ _Func(EAC_R11_UNORM, VK_FORMAT_EAC_R11_UNORM_BLOCK, 1, 0, 0) \ _Func(EAC_R11_SNORM, VK_FORMAT_EAC_R11_SNORM_BLOCK, 1, 0, 0) \ diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index c866e75bdf..f92213d9d7 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -36,7 +36,6 @@ ly_add_target( ly_add_target( NAME Atom_RPI.Private ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RPI.Private.a218db9eb2114477b46600fea4441a6c.v0.1.0 FILES_CMAKE atom_rpi_private_files.cmake INCLUDE_DIRECTORIES @@ -96,9 +95,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Atom_RPI.Editor MODULE + NAME Atom_RPI.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RPI.Editor.a218db9eb2114477b46600fea4441a6c.v0.1.0 FILES_CMAKE atom_rpi_editor_files.cmake INCLUDE_DIRECTORIES @@ -165,9 +164,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) # Create a stub ly_add_target( - NAME Atom_RPI.Builders MODULE + NAME Atom_RPI.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RPI.Builders.a218db9eb2114477b46600fea4441a6c.v0.1.0 FILES_CMAKE atom_rpi_builders_stub_files.cmake INCLUDE_DIRECTORIES @@ -209,9 +208,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Atom_RPI.Builders MODULE + NAME Atom_RPI.Builders GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Atom_RPI.Builders.a218db9eb2114477b46600fea4441a6c.v0.1.0 FILES_CMAKE atom_rpi_builders_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp index 35fd849b0d..d31b6b3802 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp @@ -50,7 +50,7 @@ namespace AZ { AssetBuilderSDK::AssetBuilderDesc materialBuilderDescriptor; materialBuilderDescriptor.m_name = JobKey; - materialBuilderDescriptor.m_version = 105; // ATOM-6239 + materialBuilderDescriptor.m_version = 107; // ATOM-14918 materialBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.material", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); materialBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.materialtype", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); materialBuilderDescriptor.m_busId = azrtti_typeid(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp index 16421a26b7..69e4aff0ba 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp @@ -91,7 +91,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(13); // [ATOM-13410] + ->Version(14); // [ATOM-13410] } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index c47d0b732a..d5b082f4fe 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -837,7 +837,7 @@ namespace AZ const AZ::u32 controlPointIndex = sourceMeshData->GetControlPointIndex(vertexIndex); const size_t numSkinInfluences = skinData->GetLinkCount(controlPointIndex); - const size_t numInfluencesToAdd = AZStd::min(numInfluencesAdded + numSkinInfluences, maxNumInfluences); + const size_t numInfluencesToAdd = AZStd::min(numSkinInfluences, maxNumInfluences - numInfluencesAdded); for (size_t influenceIndex = 0; influenceIndex < numInfluencesToAdd; ++influenceIndex) { const AZ::SceneAPI::DataTypes::ISkinWeightData::Link& link = skinData->GetLink(controlPointIndex, influenceIndex); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp index 0d92590aa5..4356a56622 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp @@ -11,12 +11,12 @@ */ #include +#include #include #include #include - namespace AZ { namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp index 3e3612723a..83ae615856 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp @@ -43,7 +43,7 @@ namespace AZ childRequest.m_inputConnections.emplace_back(childInputConnection); m_childPass = passSystem->CreatePassFromRequest(&childRequest); - AZ_Assert(m_childPass, "SwapChain child pass is invalid: check your passs pipeline, run configuration and your AssetProcessor set project (sys_game_folder)"); + AZ_Assert(m_childPass, "SwapChain child pass is invalid: check your passs pipeline, run configuration and your AssetProcessor set project (project_path)"); CreateChildPasses(); diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h index 49eb09a611..1044aa56c6 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h @@ -44,8 +44,9 @@ namespace UnitTest bool DeleteEntity(const AZ::EntityId&) override { return false; } AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h index cd00e6093c..995663b3bf 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h @@ -42,8 +42,9 @@ namespace UnitTest AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} AZ::SerializeContext* GetSerializeContext() override diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp index a00f02de14..2828d7eb39 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -69,7 +70,7 @@ namespace UnitTest m_localFileIO.reset(aznew AZ::IO::LocalFileIO()); AZ::IO::FileIOBase::SetInstance(m_localFileIO.get()); - AZ::IO::Path assetPath = AZ::Test::GetEngineRootPath(); + AZ::IO::Path assetPath = AZStd::string_view{ AZ::Utils::GetProjectPath() }; assetPath /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetPath.c_str()); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index 420b780687..fb4750ce93 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -42,11 +42,11 @@ ly_add_target( ) ly_add_target( - NAME AtomToolsFramework.Editor MODULE + NAME AtomToolsFramework.Editor GEM_MODULE + NAMESPACE Gem AUTOMOC AUTORCC - OUTPUT_NAME Gem.AtomToolsFramework.Editor.3e0ee0c27f204f5188146baac822d020.v0.1.0 FILES_CMAKE atomtoolsframework_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h index 6641efc8d6..5f16894a0c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h @@ -14,6 +14,8 @@ #include #include +class QWidget; + namespace AtomToolsFramework { class InspectorGroupWidget; @@ -40,7 +42,7 @@ namespace AtomToolsFramework const AZStd::string& groupNameId, const AZStd::string& groupDisplayName, const AZStd::string& groupDescription, - InspectorGroupWidget* groupWidget) = 0; + QWidget* groupWidget) = 0; //! Calls Refresh for a specific InspectorGroupWidget, allowing for non-destructive UI changes virtual void RefreshGroup(const AZStd::string& groupNameId) = 0; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h index 8bcbe9e8fe..9f8df2da71 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h @@ -58,7 +58,7 @@ namespace AtomToolsFramework const AZStd::string& groupNameId, const AZStd::string& groupDisplayName, const AZStd::string& groupDescription, - InspectorGroupWidget* groupWidget) override; + QWidget* groupWidget) override; void RefreshGroup(const AZStd::string& groupNameId) override; void RebuildGroup(const AZStd::string& groupNameId) override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp index a28e35f577..b1a46ff0e9 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp @@ -63,7 +63,7 @@ namespace AtomToolsFramework const AZStd::string& groupNameId, const AZStd::string& groupDisplayName, const AZStd::string& groupDescription, - InspectorGroupWidget* groupWidget) + QWidget* groupWidget) { InspectorGroupHeaderWidget* groupHeader = new InspectorGroupHeaderWidget(m_ui->m_propertyContent); groupHeader->setText(groupDisplayName.c_str()); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt index 704cfbe811..40d6a8f30a 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt @@ -63,6 +63,7 @@ ly_add_target( Gem::AtomToolsFramework.Editor Gem::Atom_RPI.Public Gem::Atom_Feature_Common.Public + Gem::ImageProcessingAtom.Headers ) ly_add_target( @@ -132,6 +133,12 @@ ly_add_target_dependencies( Source/Platform/${PAL_PLATFORM_NAME}/tool_dependencies_${PAL_PLATFORM_NAME_LOWERCASE}.cmake ) +# Inject the project path into the MaterialEditor VS debugger command arguments if the build system being invoked +# in a project centric view +if(NOT PROJECT_NAME STREQUAL "O3DE") + set_property(TARGET MaterialEditor APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${CMAKE_SOURCE_DIR}\"") +endif() + # Adds the MaterialEditor target as a C preprocessor define so that it can be used as a Settings Registry # specialization in order to look up the generated .setreg which contains the dependencies # specified for the target. diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportNotificationBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportNotificationBus.h index 878e96f614..84406d8402 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportNotificationBus.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportNotificationBus.h @@ -60,6 +60,12 @@ namespace MaterialEditor //! Notify when enabled state for grid changes virtual void OnGridEnabledChanged([[maybe_unused]] bool enable) {} + + //! Notify when enabled state for alternate skybox changes + virtual void OnAlternateSkyboxEnabledChanged([[maybe_unused]] bool enable) {} + + //! Notify when field of view changes + virtual void OnFieldOfViewChanged([[maybe_unused]] float fieldOfView) {} }; using MaterialViewportNotificationBus = AZ::EBus; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportRequestBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportRequestBus.h index a6fb2107c6..ea6be4f21a 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportRequestBus.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/MaterialViewportRequestBus.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace MaterialEditor { @@ -42,7 +43,7 @@ namespace MaterialEditor //! Save lighting preset //! @returns true if preset was saved, otherwise false - virtual bool SaveLightingPresetSelection(const AZStd::string& path) const = 0; + virtual bool SaveLightingPreset(AZ::Render::LightingPresetPtr preset, const AZStd::string& path) const = 0; //! Get lighting preset by name //! @param name preset name to search for @@ -54,7 +55,7 @@ namespace MaterialEditor virtual AZ::Render::LightingPresetPtr GetLightingPresetSelection() const = 0; //! Select lighting preset - //! @param name preset to select + //! @param preset to select virtual void SelectLightingPreset(AZ::Render::LightingPresetPtr preset) = 0; //! Select lighting preset by name @@ -64,6 +65,19 @@ namespace MaterialEditor //! Get set of lighting preset names virtual MaterialViewportPresetNameSet GetLightingPresetNames() const = 0; + //! Set lighting preset preview image + //! @param preset used to set preview image + //! @param preview image + virtual void SetLightingPresetPreview(AZ::Render::LightingPresetPtr preset, const QImage& image) = 0; + + //! Get lighting preset preview image + //! @param preset used to find preview image + virtual QImage GetLightingPresetPreview(AZ::Render::LightingPresetPtr preset) const = 0; + + //! Get model preset last save path + //! @param preset to lookup last save path + virtual AZStd::string GetLightingPresetLastSavePath(AZ::Render::LightingPresetPtr preset) const = 0; + //! Add model preset //! @param preset model preset to add for selection //! @returns pointer to new, managed preset @@ -75,7 +89,7 @@ namespace MaterialEditor //! Save Model preset //! @returns true if preset was saved, otherwise false - virtual bool SaveModelPresetSelection(const AZStd::string& path) const = 0; + virtual bool SaveModelPreset(AZ::Render::ModelPresetPtr preset, const AZStd::string& path) const = 0; //! Get model preset by name //! @param name preset name to search for @@ -97,6 +111,19 @@ namespace MaterialEditor //! Get set of model preset names virtual MaterialViewportPresetNameSet GetModelPresetNames() const = 0; + //! Set model preset preview image + //! @param preset used to set preview image + //! @param preview image + virtual void SetModelPresetPreview(AZ::Render::ModelPresetPtr preset, const QImage& image) = 0; + + //! Get model preset preview image + //! @param preset used to find preview image + virtual QImage GetModelPresetPreview(AZ::Render::ModelPresetPtr preset) const = 0; + + //! Get model preset last save path + //! @param preset to lookup last save path + virtual AZStd::string GetModelPresetLastSavePath(AZ::Render::ModelPresetPtr preset) const = 0; + //! Set enabled state for shadow catcher virtual void SetShadowCatcherEnabled(bool enable) = 0; @@ -108,6 +135,18 @@ namespace MaterialEditor //! Get enabled state for grid virtual bool GetGridEnabled() const = 0; + + //! Set enabled state for alternate skybox + virtual void SetAlternateSkyboxEnabled(bool enable) = 0; + + //! Get enabled state for alternate skybox + virtual bool GetAlternateSkyboxEnabled() const = 0; + + //! Set field of view + virtual void SetFieldOfView(float fieldOfView) = 0; + + //! Get field of view + virtual float GetFieldOfView() const = 0; }; using MaterialViewportRequestBus = AZ::EBus; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp index 1bf9a10956..79f328bbc3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp @@ -457,10 +457,8 @@ namespace MaterialEditor { AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); AZ::IO::FixedMaxPath assetDatabaseSqlitePath; - if (settingsRegistry && settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) + if (settingsRegistry && settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) { - // Grab the Parent of the Asset RootPath to remove the platform from the end of the path - assetDatabaseSqlitePath = assetDatabaseSqlitePath.ParentPath(); assetDatabaseSqlitePath /= "assetdb.sqlite"; result = AZStd::string_view(assetDatabaseSqlitePath.Native()); return true; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp index 9f308ed651..b2ebc9a9a4 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,9 @@ #include #include +#include +#include + #include #include @@ -33,6 +37,33 @@ namespace MaterialEditor { + using LoadImageAsyncCallback = AZStd::function; + void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback) + { + AZ::Job* job = AZ::CreateJobFunction([path, callback]() { + ImageProcessingAtom::IImageObjectPtr imageObject; + ImageProcessingAtom::ImageProcessingRequestBus::BroadcastResult(imageObject, &ImageProcessingAtom::ImageProcessingRequests::LoadImagePreview, path); + + if (imageObject) + { + AZ::u8* imageBuf = nullptr; + AZ::u32 pitch = 0; + AZ::u32 mip = 0; + imageObject->GetImagePointer(mip, imageBuf, pitch); + const AZ::u32 width = imageObject->GetWidth(mip); + const AZ::u32 height = imageObject->GetHeight(mip); + + QImage image(imageBuf, width, height, pitch, QImage::Format_RGBA8888); + + if (callback) + { + callback(image); + } + } + }, true); + job->Start(); + } + MaterialViewportComponent::MaterialViewportComponent() { } @@ -62,25 +93,31 @@ namespace MaterialEditor ->Attribute(AZ::Script::Attributes::Module, "materialeditor") ->Event("ReloadContent", &MaterialViewportRequestBus::Events::ReloadContent) ->Event("AddLightingPreset", &MaterialViewportRequestBus::Events::AddLightingPreset) - ->Event("SaveLightingPresetSelection", &MaterialViewportRequestBus::Events::SaveLightingPresetSelection) + ->Event("SaveLightingPreset", &MaterialViewportRequestBus::Events::SaveLightingPreset) ->Event("GetLightingPresets", &MaterialViewportRequestBus::Events::GetLightingPresets) ->Event("GetLightingPresetByName", &MaterialViewportRequestBus::Events::GetLightingPresetByName) ->Event("GetLightingPresetSelection", &MaterialViewportRequestBus::Events::GetLightingPresetSelection) ->Event("SelectLightingPreset", &MaterialViewportRequestBus::Events::SelectLightingPreset) ->Event("SelectLightingPresetByName", &MaterialViewportRequestBus::Events::SelectLightingPresetByName) ->Event("GetLightingPresetNames", &MaterialViewportRequestBus::Events::GetLightingPresetNames) + ->Event("GetLightingPresetLastSavePath", &MaterialViewportRequestBus::Events::GetLightingPresetLastSavePath) ->Event("AddModelPreset", &MaterialViewportRequestBus::Events::AddModelPreset) - ->Event("SaveModelPresetSelection", &MaterialViewportRequestBus::Events::SaveModelPresetSelection) + ->Event("SaveModelPreset", &MaterialViewportRequestBus::Events::SaveModelPreset) ->Event("GetModelPresets", &MaterialViewportRequestBus::Events::GetModelPresets) ->Event("GetModelPresetByName", &MaterialViewportRequestBus::Events::GetModelPresetByName) ->Event("GetModelPresetSelection", &MaterialViewportRequestBus::Events::GetModelPresetSelection) ->Event("SelectModelPreset", &MaterialViewportRequestBus::Events::SelectModelPreset) ->Event("SelectModelPresetByName", &MaterialViewportRequestBus::Events::SelectModelPresetByName) ->Event("GetModelPresetNames", &MaterialViewportRequestBus::Events::GetModelPresetNames) + ->Event("GetModelPresetLastSavePath", &MaterialViewportRequestBus::Events::GetModelPresetLastSavePath) ->Event("SetShadowCatcherEnabled", &MaterialViewportRequestBus::Events::SetShadowCatcherEnabled) ->Event("GetShadowCatcherEnabled", &MaterialViewportRequestBus::Events::GetShadowCatcherEnabled) ->Event("SetGridEnabled", &MaterialViewportRequestBus::Events::SetGridEnabled) ->Event("GetGridEnabled", &MaterialViewportRequestBus::Events::GetGridEnabled) + ->Event("SetAlternateSkyboxEnabled", &MaterialViewportRequestBus::Events::SetAlternateSkyboxEnabled) + ->Event("GetAlternateSkyboxEnabled", &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled) + ->Event("SetFieldOfView", &MaterialViewportRequestBus::Events::SetFieldOfView) + ->Event("GetFieldOfView", &MaterialViewportRequestBus::Events::GetFieldOfView) ; behaviorContext->EBus("MaterialViewportNotificationBus") @@ -95,6 +132,8 @@ namespace MaterialEditor ->Event("OnModelPresetChanged", &MaterialViewportNotificationBus::Events::OnModelPresetChanged) ->Event("OnShadowCatcherEnabledChanged", &MaterialViewportNotificationBus::Events::OnShadowCatcherEnabledChanged) ->Event("OnGridEnabledChanged", &MaterialViewportNotificationBus::Events::OnGridEnabledChanged) + ->Event("OnAlternateSkyboxEnabledChanged", &MaterialViewportNotificationBus::Events::OnAlternateSkyboxEnabledChanged) + ->Event("OnFieldOfViewChanged", &MaterialViewportNotificationBus::Events::OnFieldOfViewChanged) ; } } @@ -102,6 +141,7 @@ namespace MaterialEditor void MaterialViewportComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("PerformanceMonitorService", 0x6a44241a)); + required.push_back(AZ_CRC("AtomImageBuilderService", 0x76ded592)); } void MaterialViewportComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) @@ -120,6 +160,12 @@ namespace MaterialEditor void MaterialViewportComponent::Activate() { + m_lightingPresetPreviewImageDefault = QImage(180, 90, QImage::Format::Format_RGBA8888); + m_lightingPresetPreviewImageDefault.fill(Qt::GlobalColor::black); + + m_modelPresetPreviewImageDefault = QImage(90, 90, QImage::Format::Format_RGBA8888); + m_modelPresetPreviewImageDefault.fill(Qt::GlobalColor::black); + MaterialViewportRequestBus::Handler::BusConnect(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); } @@ -129,10 +175,14 @@ namespace MaterialEditor AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); MaterialViewportRequestBus::Handler::BusDisconnect(); + m_lightingPresetPreviewImages.clear(); m_lightingPresetVector.clear(); + m_lightingPresetLastSavePathMap.clear(); m_lightingPresetSelection.reset(); + m_modelPresetPreviewImages.clear(); m_modelPresetVector.clear(); + m_modelPresetLastSavePathMap.clear(); m_modelPresetSelection.reset(); } @@ -146,9 +196,11 @@ namespace MaterialEditor const AZStd::string prevModelPresetSelectionName = m_modelPresetSelection ? m_modelPresetSelection->m_displayName : ""; m_lightingPresetVector.clear(); + m_lightingPresetLastSavePathMap.clear(); m_lightingPresetSelection.reset(); m_modelPresetVector.clear(); + m_modelPresetLastSavePathMap.clear(); m_modelPresetSelection.reset(); AZStd::vector lightingAssetInfoVector; @@ -182,7 +234,8 @@ namespace MaterialEditor const AZ::Render::LightingPreset* preset = asset->GetDataAs(); if (preset) { - AddLightingPreset(*preset); + auto presetPtr = AddLightingPreset(*preset); + m_lightingPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); AZ_TracePrintf("Material Editor", "Loaded viewport configurtion: %s.\n", info.m_relativePath.c_str()); } } @@ -193,14 +246,15 @@ namespace MaterialEditor { if (info.m_assetId.IsValid()) { - AZ::Data::Asset asset = AZ::RPI::AssetUtils::LoadAssetById( - info.m_assetId, AZ::RPI::AssetUtils::TraceLevel::Warning); + AZ::Data::Asset asset = + AZ::RPI::AssetUtils::LoadAssetById(info.m_assetId, AZ::RPI::AssetUtils::TraceLevel::Warning); if (asset) { const AZ::Render::ModelPreset* preset = asset->GetDataAs(); if (preset) { - AddModelPreset(*preset); + auto presetPtr = AddModelPreset(*preset); + m_modelPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); AZ_TracePrintf("Material Editor", "Loaded viewport configurtion: %s.\n", info.m_relativePath.c_str()); } } @@ -220,15 +274,24 @@ namespace MaterialEditor AZ::Render::LightingPresetPtr MaterialViewportComponent::AddLightingPreset(const AZ::Render::LightingPreset& preset) { m_lightingPresetVector.push_back(AZStd::make_shared(preset)); - MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetAdded, - m_lightingPresetVector.back()); + auto presetPtr = m_lightingPresetVector.back(); + + MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetAdded, presetPtr); if (preset.m_autoSelect || m_lightingPresetVector.size() == 1) { - SelectLightingPreset(m_lightingPresetVector.back()); + SelectLightingPreset(presetPtr); } - return m_lightingPresetVector.back(); + const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(presetPtr->m_skyboxImageAsset.GetId()); + LoadImageAsync(imagePath, [presetPtr](const QImage& image) { + QImage imageScaled = image.scaled(180, 90, Qt::AspectRatioMode::KeepAspectRatio); + AZ::TickBus::QueueFunction([presetPtr, imageScaled]() { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetLightingPresetPreview, presetPtr, imageScaled); + }); + }); + + return presetPtr; } AZ::Render::LightingPresetPtr MaterialViewportComponent::GetLightingPresetByName(const AZStd::string& name) const @@ -243,12 +306,12 @@ namespace MaterialEditor return m_lightingPresetVector; } - bool MaterialViewportComponent::SaveLightingPresetSelection(const AZStd::string& path) const + bool MaterialViewportComponent::SaveLightingPreset(AZ::Render::LightingPresetPtr preset, const AZStd::string& path) const { - if (m_lightingPresetSelection) + if (preset && AZ::JsonSerializationUtils::SaveObjectToFile(preset.get(), path).IsSuccess()) { - return AZ::JsonSerializationUtils::SaveObjectToFile( - m_lightingPresetSelection.get(), path).IsSuccess(); + m_lightingPresetLastSavePathMap[preset] = path; + return true; } return false; @@ -286,18 +349,44 @@ namespace MaterialEditor return names; } + void MaterialViewportComponent::SetLightingPresetPreview(AZ::Render::LightingPresetPtr preset, const QImage& image) + { + m_lightingPresetPreviewImages[preset] = image; + } + + QImage MaterialViewportComponent::GetLightingPresetPreview(AZ::Render::LightingPresetPtr preset) const + { + auto imageItr = m_lightingPresetPreviewImages.find(preset); + return imageItr != m_lightingPresetPreviewImages.end() ? imageItr->second : m_lightingPresetPreviewImageDefault; + } + + AZStd::string MaterialViewportComponent::GetLightingPresetLastSavePath(AZ::Render::LightingPresetPtr preset) const + { + auto pathItr = m_lightingPresetLastSavePathMap.find(preset); + return pathItr != m_lightingPresetLastSavePathMap.end() ? pathItr->second : AZStd::string(); + } + AZ::Render::ModelPresetPtr MaterialViewportComponent::AddModelPreset(const AZ::Render::ModelPreset& preset) { m_modelPresetVector.push_back(AZStd::make_shared(preset)); - MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetAdded, - m_modelPresetVector.back()); + auto presetPtr = m_modelPresetVector.back(); + + MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetAdded, presetPtr); if (preset.m_autoSelect || m_modelPresetVector.size() == 1) { - SelectModelPreset(m_modelPresetVector.back()); + SelectModelPreset(presetPtr); } - return m_modelPresetVector.back(); + const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(presetPtr->m_previewImageAsset.GetId()); + LoadImageAsync(imagePath, [presetPtr](const QImage& image) { + QImage imageScaled = image.scaled(90, 90, Qt::AspectRatioMode::KeepAspectRatio); + AZ::TickBus::QueueFunction([presetPtr, imageScaled]() { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetModelPresetPreview, presetPtr, imageScaled); + }); + }); + + return presetPtr; } AZ::Render::ModelPresetPtr MaterialViewportComponent::GetModelPresetByName(const AZStd::string& name) const @@ -312,12 +401,12 @@ namespace MaterialEditor return m_modelPresetVector; } - bool MaterialViewportComponent::SaveModelPresetSelection(const AZStd::string& path) const + bool MaterialViewportComponent::SaveModelPreset(AZ::Render::ModelPresetPtr preset, const AZStd::string& path) const { - if (m_modelPresetSelection) + if (preset && AZ::JsonSerializationUtils::SaveObjectToFile(preset.get(), path).IsSuccess()) { - return AZ::JsonSerializationUtils::SaveObjectToFile( - m_modelPresetSelection.get(), path).IsSuccess(); + m_modelPresetLastSavePathMap[preset] = path; + return true; } return false; @@ -355,6 +444,23 @@ namespace MaterialEditor return names; } + void MaterialViewportComponent::SetModelPresetPreview(AZ::Render::ModelPresetPtr preset, const QImage& image) + { + m_modelPresetPreviewImages[preset] = image; + } + + QImage MaterialViewportComponent::GetModelPresetPreview(AZ::Render::ModelPresetPtr preset) const + { + auto imageItr = m_modelPresetPreviewImages.find(preset); + return imageItr != m_modelPresetPreviewImages.end() ? imageItr->second : m_modelPresetPreviewImageDefault; + } + + AZStd::string MaterialViewportComponent::GetModelPresetLastSavePath(AZ::Render::ModelPresetPtr preset) const + { + auto pathItr = m_modelPresetLastSavePathMap.find(preset); + return pathItr != m_modelPresetLastSavePathMap.end() ? pathItr->second : AZStd::string(); + } + void MaterialViewportComponent::SetShadowCatcherEnabled(bool enable) { m_shadowCatcherEnabled = enable; @@ -378,6 +484,30 @@ namespace MaterialEditor return m_gridEnabled; } + void MaterialViewportComponent::SetAlternateSkyboxEnabled(bool enable) + { + m_alternateSkyboxEnabled = enable; + MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnAlternateSkyboxEnabledChanged, enable); + } + + + bool MaterialViewportComponent::GetAlternateSkyboxEnabled() const + { + return m_alternateSkyboxEnabled; + } + + void MaterialViewportComponent::SetFieldOfView(float fieldOfView) + { + m_fieldOfView = fieldOfView; + MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnFieldOfViewChanged, fieldOfView); + } + + + float MaterialViewportComponent::GetFieldOfView() const + { + return m_fieldOfView; + } + void MaterialViewportComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) { AZ::TickBus::QueueFunction([this]() { ReloadContent(); }); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h index 054facc7e3..036974e123 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h @@ -55,26 +55,36 @@ namespace MaterialEditor AZ::Render::LightingPresetPtr AddLightingPreset(const AZ::Render::LightingPreset& preset) override; AZ::Render::LightingPresetPtrVector GetLightingPresets() const override; - bool SaveLightingPresetSelection(const AZStd::string& path) const override; + bool SaveLightingPreset(AZ::Render::LightingPresetPtr preset, const AZStd::string& path) const override; AZ::Render::LightingPresetPtr GetLightingPresetByName(const AZStd::string& name) const override; AZ::Render::LightingPresetPtr GetLightingPresetSelection() const override; void SelectLightingPreset(AZ::Render::LightingPresetPtr preset) override; void SelectLightingPresetByName(const AZStd::string& name) override; MaterialViewportPresetNameSet GetLightingPresetNames() const override; + void SetLightingPresetPreview(AZ::Render::LightingPresetPtr preset, const QImage& image) override; + QImage GetLightingPresetPreview(AZ::Render::LightingPresetPtr preset) const override; + AZStd::string GetLightingPresetLastSavePath(AZ::Render::LightingPresetPtr preset) const override; AZ::Render::ModelPresetPtr AddModelPreset(const AZ::Render::ModelPreset& preset) override; AZ::Render::ModelPresetPtrVector GetModelPresets() const override; - bool SaveModelPresetSelection(const AZStd::string& path) const override; + bool SaveModelPreset(AZ::Render::ModelPresetPtr preset, const AZStd::string& path) const override; AZ::Render::ModelPresetPtr GetModelPresetByName(const AZStd::string& name) const override; AZ::Render::ModelPresetPtr GetModelPresetSelection() const override; void SelectModelPreset(AZ::Render::ModelPresetPtr preset) override; void SelectModelPresetByName(const AZStd::string& name) override; MaterialViewportPresetNameSet GetModelPresetNames() const override; + void SetModelPresetPreview(AZ::Render::ModelPresetPtr preset, const QImage& image) override; + QImage GetModelPresetPreview(AZ::Render::ModelPresetPtr preset) const override; + AZStd::string GetModelPresetLastSavePath(AZ::Render::ModelPresetPtr preset) const override; void SetShadowCatcherEnabled(bool enable) override; bool GetShadowCatcherEnabled() const override; void SetGridEnabled(bool enable) override; bool GetGridEnabled() const override; + void SetAlternateSkyboxEnabled(bool enable) override; + bool GetAlternateSkyboxEnabled() const override; + void SetFieldOfView(float fieldOfView) override; + float GetFieldOfView() const override; //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// @@ -88,7 +98,18 @@ namespace MaterialEditor AZ::Render::ModelPresetPtrVector m_modelPresetVector; AZ::Render::ModelPresetPtr m_modelPresetSelection; + AZStd::map m_lightingPresetPreviewImages; + AZStd::map m_modelPresetPreviewImages; + + QImage m_lightingPresetPreviewImageDefault; + QImage m_modelPresetPreviewImageDefault; + + mutable AZStd::map m_lightingPresetLastSavePathMap; + mutable AZStd::map m_modelPresetLastSavePathMap; + bool m_shadowCatcherEnabled = true; bool m_gridEnabled = true; + bool m_alternateSkyboxEnabled = false; + float m_fieldOfView = 90.0f; }; } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 7ba9792270..ece05f04c1 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -318,6 +318,9 @@ namespace MaterialEditor Camera::Configuration cameraConfig; Camera::CameraRequestBus::EventResult(cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); + bool enableAlternateSkybox = false; + MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); + preset->ApplyLightingPreset( iblFeatureProcessor, m_skyboxFeatureProcessor, @@ -326,7 +329,8 @@ namespace MaterialEditor cameraConfig, m_lightHandles, m_shadowCatcherMaterial, - m_shadowCatcherOpacityPropertyIndex); + m_shadowCatcherOpacityPropertyIndex, + enableAlternateSkybox); } void MaterialViewportRenderer::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) @@ -392,12 +396,24 @@ namespace MaterialEditor } } + void MaterialViewportRenderer::OnAlternateSkyboxEnabledChanged(bool enable) + { + AZ_UNUSED(enable); + AZ::Render::LightingPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + OnLightingPresetSelected(selectedPreset); + } + + void MaterialViewportRenderer::OnFieldOfViewChanged(float fieldOfView) + { + MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView); + } + void MaterialViewportRenderer::OnAssetReady(AZ::Data::Asset asset) { if (m_modelAssetId == asset.GetId()) { - MaterialEditorViewportInputControllerRequestBus::Broadcast( - &MaterialEditorViewportInputControllerRequestBus::Handler::Reset); + MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset); AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId()); } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h index c6c02ef668..e014d9eada 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h @@ -69,6 +69,8 @@ namespace MaterialEditor void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override; void OnShadowCatcherEnabledChanged(bool enable) override; void OnGridEnabledChanged(bool enable) override; + void OnAlternateSkyboxEnabledChanged(bool enable) override; + void OnFieldOfViewChanged(float fieldOfView) override; // AZ::Data::AssetBus::Handler interface overrides... void OnAssetReady(AZ::Data::Asset asset) override; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index 6119352ac9..1e116b4a22 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include @@ -420,50 +419,6 @@ namespace MaterialEditor m_menuFile->addSeparator(); - auto presetMenu = m_menuFile->addMenu("Presets"); - - presetMenu->addAction("New Model Preset", [this]() { - AZ::Render::ModelPresetPtr preset; - MaterialViewportRequestBus::BroadcastResult(preset, &MaterialViewportRequestBus::Events::AddModelPreset, AZ::Render::ModelPreset()); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, preset); - }); - - presetMenu->addAction("Save Model Preset", [this]() { - const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + - AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + - AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled.modelpreset.azasset").absoluteFilePath(); - - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveModelPresetSelection, - AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData()); - }); - - presetMenu->addSeparator(); - - presetMenu->addAction("New Lighting Preset", [this]() { - AZ::Render::LightingPresetPtr preset; - MaterialViewportRequestBus::BroadcastResult(preset, &MaterialViewportRequestBus::Events::AddLightingPreset, AZ::Render::LightingPreset()); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, preset); - }); - - presetMenu->addAction("Save Lighting Preset", [this]() { - const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + - AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + - AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled.lightingpreset.azasset").absoluteFilePath(); - - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveLightingPresetSelection, - AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData()); - }); - - presetMenu->addSeparator(); - - presetMenu->addAction("Reload Presets", [this]() { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::ReloadContent); - }, QKeySequence::Refresh); - - m_menuFile->addSeparator(); - m_menuFile->addAction("Run &Python...", [this]() { const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); if (!script.isEmpty()) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowComponent.cpp index dd4e01d661..6f03510301 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowComponent.cpp @@ -22,11 +22,14 @@ #include #include #include +#include namespace MaterialEditor { void MaterialEditorWindowComponent::Reflect(AZ::ReflectContext* context) { + GeneralViewportSettings::Reflect(context); + if (AZ::SerializeContext* serialize = azrtti_cast(context)) { serialize->Class() diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp new file mode 100644 index 0000000000..5f50a4e518 --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp @@ -0,0 +1,73 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include + +namespace MaterialEditor +{ + LightingPresetBrowserDialog::LightingPresetBrowserDialog(QWidget* parent) + : PresetBrowserDialog(parent) + { + QSignalBlocker signalBlocker(this); + + setWindowTitle("Lighting Preset Browser"); + + MaterialViewportRequestBus::BroadcastResult(m_initialPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + + AZ::Render::LightingPresetPtrVector presets; + MaterialViewportRequestBus::BroadcastResult(presets, &MaterialViewportRequestBus::Events::GetLightingPresets); + AZStd::sort(presets.begin(), presets.end(), [](const auto& a, const auto& b) { return a->m_displayName < b->m_displayName; }); + + QListWidgetItem* selectedItem = nullptr; + for (const auto& preset : presets) + { + QImage image; + MaterialViewportRequestBus::BroadcastResult(image, &MaterialViewportRequestBus::Events::GetLightingPresetPreview, preset); + + QListWidgetItem* item = CreateListItem(preset->m_displayName.c_str(), image); + + m_listItemToPresetMap[item] = preset; + + if (m_initialPreset == preset) + { + selectedItem = item; + } + } + + if (selectedItem) + { + m_ui->m_presetList->setCurrentItem(selectedItem); + m_ui->m_presetList->scrollToItem(selectedItem); + } + } + + void LightingPresetBrowserDialog::SelectCurrentPreset() + { + auto presetItr = m_listItemToPresetMap.find(m_ui->m_presetList->currentItem()); + if (presetItr != m_listItemToPresetMap.end()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, presetItr->second); + } + } + + void LightingPresetBrowserDialog::SelectInitialPreset() + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, m_initialPreset); + } + +} // namespace MaterialEditor + +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h new file mode 100644 index 0000000000..3c29971391 --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h @@ -0,0 +1,40 @@ +/* + * 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 + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#endif + +#include + +namespace MaterialEditor +{ + //! Widget for managing and selecting from a library of preset assets + class LightingPresetBrowserDialog : public PresetBrowserDialog + { + Q_OBJECT + public: + LightingPresetBrowserDialog(QWidget* parent = nullptr); + ~LightingPresetBrowserDialog() = default; + + private: + void SelectCurrentPreset() override; + void SelectInitialPreset() override; + + AZ::Render::LightingPresetPtr m_initialPreset; + AZStd::unordered_map m_listItemToPresetMap; + }; +} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp new file mode 100644 index 0000000000..a943ae3628 --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp @@ -0,0 +1,73 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include + +namespace MaterialEditor +{ + ModelPresetBrowserDialog::ModelPresetBrowserDialog(QWidget* parent) + : PresetBrowserDialog(parent) + { + QSignalBlocker signalBlocker(this); + + setWindowTitle("Model Preset Browser"); + + MaterialViewportRequestBus::BroadcastResult(m_initialPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + + AZ::Render::ModelPresetPtrVector presets; + MaterialViewportRequestBus::BroadcastResult(presets, &MaterialViewportRequestBus::Events::GetModelPresets); + AZStd::sort(presets.begin(), presets.end(), [](const auto& a, const auto& b) { return a->m_displayName < b->m_displayName; }); + + QListWidgetItem* selectedItem = nullptr; + for (const auto& preset : presets) + { + QImage image; + MaterialViewportRequestBus::BroadcastResult(image, &MaterialViewportRequestBus::Events::GetModelPresetPreview, preset); + + QListWidgetItem* item = CreateListItem(preset->m_displayName.c_str(), image); + + m_listItemToPresetMap[item] = preset; + + if (m_initialPreset == preset) + { + selectedItem = item; + } + } + + if (selectedItem) + { + m_ui->m_presetList->setCurrentItem(selectedItem); + m_ui->m_presetList->scrollToItem(selectedItem); + } + } + + void ModelPresetBrowserDialog::SelectCurrentPreset() + { + auto presetItr = m_listItemToPresetMap.find(m_ui->m_presetList->currentItem()); + if (presetItr != m_listItemToPresetMap.end()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, presetItr->second); + } + } + + void ModelPresetBrowserDialog::SelectInitialPreset() + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, m_initialPreset); + } + +} // namespace MaterialEditor + +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h new file mode 100644 index 0000000000..b95ba7816c --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h @@ -0,0 +1,40 @@ +/* + * 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 + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#endif + +#include + +namespace MaterialEditor +{ + //! Widget for managing and selecting from a library of preset assets + class ModelPresetBrowserDialog : public PresetBrowserDialog + { + Q_OBJECT + public: + ModelPresetBrowserDialog(QWidget* parent = nullptr); + ~ModelPresetBrowserDialog() = default; + + private: + void SelectCurrentPreset() override; + void SelectInitialPreset() override; + + AZ::Render::ModelPresetPtr m_initialPreset; + AZStd::unordered_map m_listItemToPresetMap; + }; +} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp new file mode 100644 index 0000000000..a00490c0b9 --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp @@ -0,0 +1,115 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace MaterialEditor +{ + PresetBrowserDialog::PresetBrowserDialog(QWidget* parent) + : QDialog(parent) + , m_ui(new Ui::PresetBrowserDialog) + { + m_ui->setupUi(this); + + QSignalBlocker signalBlocker(this); + + SetupPresetList(); + SetupSearchWidget(); + SetupDialogButtons(); + } + + void PresetBrowserDialog::SetupPresetList() + { + m_ui->m_presetList->setFlow(QListView::LeftToRight); + m_ui->m_presetList->setResizeMode(QListView::Adjust); + m_ui->m_presetList->setGridSize(QSize(0, 0)); + m_ui->m_presetList->setWrapping(true); + + QObject::connect(m_ui->m_presetList, &QListWidget::currentItemChanged, [this]() { SelectCurrentPreset(); }); + } + + QListWidgetItem* PresetBrowserDialog::CreateListItem(const QString& title, const QImage& image) + { + const QSize gridSize = m_ui->m_presetList->gridSize(); + m_ui->m_presetList->setGridSize( + QSize(AZStd::max(gridSize.width(), image.width() + 10), AZStd::max(gridSize.height(), image.height() + 10))); + + QListWidgetItem* item = new QListWidgetItem(m_ui->m_presetList); + item->setData(Qt::UserRole, title); + item->setSizeHint(image.size() + QSize(4, 4)); + m_ui->m_presetList->addItem(item); + + QLabel* previewImage = new QLabel(m_ui->m_presetList); + previewImage->setFixedSize(image.size()); + previewImage->setMargin(0); + previewImage->setPixmap(QPixmap::fromImage(image)); + previewImage->updateGeometry(); + + AzQtComponents::ElidingLabel* previewLabel = new AzQtComponents::ElidingLabel(previewImage); + previewLabel->setText(title); + previewLabel->setFixedSize(QSize(image.width(), 15)); + previewLabel->setMargin(0); + previewLabel->setStyleSheet("background-color: rgb(35, 35, 35)"); + AzQtComponents::Text::addPrimaryStyle(previewLabel); + AzQtComponents::Text::addLabelStyle(previewLabel); + + m_ui->m_presetList->setItemWidget(item, previewImage); + + return item; + } + + void PresetBrowserDialog::SetupSearchWidget() + { + m_ui->m_searchWidget->setReadOnly(false); + m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu); + AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget); + connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this]() { ApplySearchFilter(); }); + connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos) { ShowSearchMenu(pos); }); + } + + void PresetBrowserDialog::SetupDialogButtons() + { + connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(this, &QDialog::rejected, this, [this]() { SelectInitialPreset(); }); + } + + void PresetBrowserDialog::ApplySearchFilter() + { + for (int index = 0; index < m_ui->m_presetList->count(); ++index) + { + QListWidgetItem* item = m_ui->m_presetList->item(index); + const QString& title = item->data(Qt::UserRole).toString(); + const QString filter = m_ui->m_searchWidget->text(); + item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive)); + } + } + + void PresetBrowserDialog::ShowSearchMenu(const QPoint& pos) + { + QScopedPointer menu(m_ui->m_searchWidget->createStandardContextMenu()); + menu->setStyleSheet("background-color: #333333"); + menu->exec(m_ui->m_searchWidget->mapToGlobal(pos)); + } +} // namespace MaterialEditor + +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h new file mode 100644 index 0000000000..3dd1147ce0 --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h @@ -0,0 +1,50 @@ +/* + * 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 + +#if !defined(Q_MOC_RUN) +#include + +#include +#endif + +#include + +class QImage; +class QListWidgetItem; +class QString; + +namespace MaterialEditor +{ + //! Widget for managing and selecting from a library of preset assets + class PresetBrowserDialog : public QDialog + { + Q_OBJECT + public: + PresetBrowserDialog(QWidget* parent = nullptr); + ~PresetBrowserDialog() = default; + +protected: + void SetupPresetList(); + QListWidgetItem* CreateListItem(const QString& title, const QImage& image); + + void SetupSearchWidget(); + void SetupDialogButtons(); + void ApplySearchFilter(); + void ShowSearchMenu(const QPoint& pos); + virtual void SelectCurrentPreset() = 0; + virtual void SelectInitialPreset() = 0; + + QScopedPointer m_ui; + }; +} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui new file mode 100644 index 0000000000..172feb214c --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui @@ -0,0 +1,44 @@ + + + PresetBrowserDialog + + + + 0 + 0 + 400 + 300 + + + + + 100 + 100 + + + + Preset Browser + + + + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.cpp deleted file mode 100644 index 5c15c9a613..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -* 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. -* -*/ - -#include -#include -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -AZ_POP_DISABLE_WARNING - -namespace MaterialEditor -{ - FovSliderWidget::FovSliderWidget(QWidget* parent) - : QWidget(parent) - { - QHBoxLayout* layout = new QHBoxLayout(); - m_label = new QLabel("Field of View"); - layout->addWidget(m_label); - AzQtComponents::SliderInt* slider = new AzQtComponents::SliderInt(Qt::Orientation::Horizontal); - slider->setRange(60, 120); - connect(slider, &AzQtComponents::SliderInt::valueChanged, this, &FovSliderWidget::SliderValueChanged); - slider->setValue(90); - layout->addWidget(slider); - setLayout(layout); - } - - void FovSliderWidget::SliderValueChanged(int value) const - { - m_label->setText(QString("Field of View (%1)").arg(value)); - MaterialEditorViewportInputControllerRequestBus::Broadcast( - &MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, - aznumeric_cast(value)); - } -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.h deleted file mode 100644 index 6ff4b4a775..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/FovSliderWidget.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* 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 - -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -AZ_POP_DISABLE_WARNING - -namespace MaterialEditor -{ - //! Widget for adjusting Field of View in viewport - class FovSliderWidget - : public QWidget - { - Q_OBJECT - public: - FovSliderWidget(QWidget* parent = 0); - ~FovSliderWidget() = default; - - private: - QLabel* m_label; - - private Q_SLOTS: - void SliderValueChanged(int value) const; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp index d0a8a094de..0b3c5e1cfc 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp @@ -13,12 +13,15 @@ #include #include #include -#include #include #include +#include +#include + AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include +#include #include #include #include @@ -36,7 +39,7 @@ namespace MaterialEditor toggleGrid->setCheckable(true); connect(toggleGrid, &QAction::triggered, [this, toggleGrid]() { MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetGridEnabled, toggleGrid->isChecked()); - }); + }); bool enableGrid = false; MaterialViewportRequestBus::BroadcastResult(enableGrid, &MaterialViewportRequestBus::Events::GetGridEnabled); toggleGrid->setChecked(enableGrid); @@ -46,7 +49,7 @@ namespace MaterialEditor toggleShadowCatcher->setCheckable(true); connect(toggleShadowCatcher, &QAction::triggered, [this, toggleShadowCatcher]() { MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetShadowCatcherEnabled, toggleShadowCatcher->isChecked()); - }); + }); bool enableShadowCatcher = false; MaterialViewportRequestBus::BroadcastResult(enableShadowCatcher, &MaterialViewportRequestBus::Events::GetShadowCatcherEnabled); toggleShadowCatcher->setChecked(enableShadowCatcher); @@ -57,13 +60,13 @@ namespace MaterialEditor QMenu* toneMappingMenu = new QMenu(toneMappingButton); toneMappingMenu->addAction("None", [this]() { MaterialEditorSettingsRequestBus::Broadcast(&MaterialEditorSettingsRequests::SetStringProperty, "toneMapping", "None"); - }); + }); toneMappingMenu->addAction("Gamma2.2", [this]() { MaterialEditorSettingsRequestBus::Broadcast(&MaterialEditorSettingsRequests::SetStringProperty, "toneMapping", "Gamma2.2"); - }); + }); toneMappingMenu->addAction("ACES", [this]() { MaterialEditorSettingsRequestBus::Broadcast(&MaterialEditorSettingsRequests::SetStringProperty, "toneMapping", "ACES"); - }); + }); toneMappingButton->setMenu(toneMappingMenu); toneMappingButton->setText("Tone Mapping"); toneMappingButton->setIcon(QIcon(":/Icons/toneMapping.svg")); @@ -82,10 +85,6 @@ namespace MaterialEditor auto lightingPresetComboBox = new LightingPresetComboBox(this); lightingPresetComboBox->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); addWidget(lightingPresetComboBox); - - FovSliderWidget* fovSlider = new FovSliderWidget(this); - fovSlider->setFixedWidth(250); - addWidget(fovSlider); } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp index 1b31a0261d..8b6704ea54 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -12,11 +12,65 @@ #include #include - #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include namespace MaterialEditor { + void GeneralViewportSettings::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("enableGrid", &GeneralViewportSettings::m_enableGrid) + ->Field("enableShadowCatcher", &GeneralViewportSettings::m_enableShadowCatcher) + ->Field("enableAlternateSkybox", &GeneralViewportSettings::m_enableAlternateSkybox) + ->Field("fieldOfView", &GeneralViewportSettings::m_fieldOfView) + ; + + if (auto editContext = serializeContext->GetEditContext()) + { + editContext->Class( + "GeneralViewportSettings", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &GeneralViewportSettings::m_enableGrid, "Enable Grid", "") + ->DataElement(AZ::Edit::UIHandlers::Default, &GeneralViewportSettings::m_enableShadowCatcher, "Enable Shadow Catcher", "") + ->DataElement(AZ::Edit::UIHandlers::Default, &GeneralViewportSettings::m_enableAlternateSkybox, "Enable Alternate Skybox", "") + ->DataElement(AZ::Edit::UIHandlers::Slider, &GeneralViewportSettings::m_fieldOfView, "Field Of View", "") + ->Attribute(AZ::Edit::Attributes::Min, 60.0f) + ->Attribute(AZ::Edit::Attributes::Max, 120.0f) + ; + } + } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("GeneralViewportSettings") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Editor") + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Constructor() + ->Constructor() + ->Property("enableGrid", BehaviorValueProperty(&GeneralViewportSettings::m_enableGrid)) + ->Property("enableShadowCatcher", BehaviorValueProperty(&GeneralViewportSettings::m_enableShadowCatcher)) + ->Property("enableAlternateSkybox", BehaviorValueProperty(&GeneralViewportSettings::m_enableAlternateSkybox)) + ->Property("fieldOfView", BehaviorValueProperty(&GeneralViewportSettings::m_fieldOfView)) + ; + } + } + ViewportSettingsInspector::ViewportSettingsInspector(QWidget* parent) : AtomToolsFramework::InspectorWidget(parent) { @@ -34,40 +88,218 @@ namespace MaterialEditor void ViewportSettingsInspector::Popuate() { AddGroupsBegin(); + AddGeneralGroup(); + AddModelGroup(); + AddLightingGroup(); + AddGroupsEnd(); + } - m_modelPreset.reset(); - MaterialViewportRequestBus::BroadcastResult(m_modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + void ViewportSettingsInspector::AddGeneralGroup() + { + const AZStd::string groupNameId = "general"; + const AZStd::string groupDisplayName = "General"; + const AZStd::string groupDescription = "General"; + + AddGroup( + groupNameId, groupDisplayName, groupDescription, + new AtomToolsFramework::InspectorPropertyGroupWidget(&m_generalSettings, nullptr, m_generalSettings.TYPEINFO_Uuid(), this)); + } + + void ViewportSettingsInspector::AddModelGroup() + { + const AZStd::string groupNameId = "model"; + const AZStd::string groupDisplayName = "Model"; + const AZStd::string groupDescription = "Model"; + + auto groupWidget = new QWidget(this); + auto buttonGroupWidget = new QWidget(groupWidget); + auto addButtonWidget = new QPushButton("Add", buttonGroupWidget); + auto selectButtonWidget = new QPushButton("Select", buttonGroupWidget); + auto saveButtonWidget = new QPushButton("Save", buttonGroupWidget); + auto refreshButtonWidget = new QPushButton("Refresh", buttonGroupWidget); + + buttonGroupWidget->setLayout(new QHBoxLayout(buttonGroupWidget)); + buttonGroupWidget->layout()->addWidget(addButtonWidget); + buttonGroupWidget->layout()->addWidget(selectButtonWidget); + buttonGroupWidget->layout()->addWidget(saveButtonWidget); + buttonGroupWidget->layout()->addWidget(refreshButtonWidget); + + groupWidget->setLayout(new QVBoxLayout(groupWidget)); + groupWidget->layout()->addWidget(buttonGroupWidget); + + QObject::connect(addButtonWidget, &QPushButton::clicked, this, [this]() { AddModelPreset(); }); + QObject::connect(selectButtonWidget, &QPushButton::clicked, this, [this]() { SelectModelPreset(); }); + QObject::connect(saveButtonWidget, &QPushButton::clicked, this, [this]() { SaveModelPreset(); }); + QObject::connect(refreshButtonWidget, &QPushButton::clicked, this, [this]() { RefreshPresets(); }); if (m_modelPreset) { - const AZStd::string groupNameId = "model"; - const AZStd::string groupDisplayName = "Model"; - const AZStd::string groupDescription = "Model"; + auto inspectorWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( + m_modelPreset.get(), nullptr, m_modelPreset.get()->TYPEINFO_Uuid(), nullptr, groupWidget); - AddGroup(groupNameId, groupDisplayName, groupDescription, - new AtomToolsFramework::InspectorPropertyGroupWidget(m_modelPreset.get(), nullptr, m_modelPreset.get()->TYPEINFO_Uuid(), this)); + groupWidget->layout()->addWidget(inspectorWidget); } - m_lightingPreset.reset(); - MaterialViewportRequestBus::BroadcastResult(m_lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + AddGroup(groupNameId, groupDisplayName, groupDescription, groupWidget); + } + + void ViewportSettingsInspector::AddModelPreset() + { + const AZStd::string defaultPath = GetDefaultUniqueSaveFilePath("untitled.modelpreset.azasset"); + const AZStd::string savePath = AtomToolsFramework::GetSaveFileInfo(defaultPath.c_str()).absoluteFilePath().toUtf8().constData(); + + if (!savePath.empty()) + { + AZ::Render::ModelPresetPtr preset; + MaterialViewportRequestBus::BroadcastResult( + preset, &MaterialViewportRequestBus::Events::AddModelPreset, AZ::Render::ModelPreset()); + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveModelPreset, preset, savePath); + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, preset); + } + } + + void ViewportSettingsInspector::SelectModelPreset() + { + ModelPresetBrowserDialog dialog(QApplication::activeWindow()); + + dialog.setFixedSize(800, 400); + dialog.show(); + + // Removing fixed size to allow drag resizing + dialog.setMinimumSize(0, 0); + dialog.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + dialog.exec(); + } + + void ViewportSettingsInspector::SaveModelPreset() + { + AZ::Render::ModelPresetPtr preset; + MaterialViewportRequestBus::BroadcastResult(preset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + + AZStd::string defaultPath; + MaterialViewportRequestBus::BroadcastResult(defaultPath, &MaterialViewportRequestBus::Events::GetModelPresetLastSavePath, preset); + + if (defaultPath.empty()) + { + defaultPath = GetDefaultUniqueSaveFilePath("untitled.modelpreset.azasset"); + } + + const AZStd::string savePath = AtomToolsFramework::GetSaveFileInfo(defaultPath.c_str()).absoluteFilePath().toUtf8().constData(); + + if (!savePath.empty()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveModelPreset, preset, savePath); + } + } + + void ViewportSettingsInspector::AddLightingGroup() + { + const AZStd::string groupNameId = "lighting"; + const AZStd::string groupDisplayName = "Lighting"; + const AZStd::string groupDescription = "Lighting"; + + auto groupWidget = new QWidget(this); + auto buttonGroupWidget = new QWidget(groupWidget); + auto addButtonWidget = new QPushButton("Add", buttonGroupWidget); + auto selectButtonWidget = new QPushButton("Select", buttonGroupWidget); + auto saveButtonWidget = new QPushButton("Save", buttonGroupWidget); + auto refreshButtonWidget = new QPushButton("Refresh", buttonGroupWidget); + + buttonGroupWidget->setLayout(new QHBoxLayout(buttonGroupWidget)); + buttonGroupWidget->layout()->addWidget(addButtonWidget); + buttonGroupWidget->layout()->addWidget(selectButtonWidget); + buttonGroupWidget->layout()->addWidget(saveButtonWidget); + buttonGroupWidget->layout()->addWidget(refreshButtonWidget); + + groupWidget->setLayout(new QVBoxLayout(groupWidget)); + groupWidget->layout()->addWidget(buttonGroupWidget); + + QObject::connect(addButtonWidget, &QPushButton::clicked, this, [this]() { AddLightingPreset(); }); + QObject::connect(selectButtonWidget, &QPushButton::clicked, this, [this]() { SelectLightingPreset(); }); + QObject::connect(saveButtonWidget, &QPushButton::clicked, this, [this]() { SaveLightingPreset(); }); + QObject::connect(refreshButtonWidget, &QPushButton::clicked, this, [this]() { RefreshPresets(); }); if (m_lightingPreset) { - const AZStd::string groupNameId = "lighting"; - const AZStd::string groupDisplayName = "Lighting"; - const AZStd::string groupDescription = "Lighting"; + auto inspectorWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( + m_lightingPreset.get(), nullptr, m_lightingPreset.get()->TYPEINFO_Uuid(), nullptr, groupWidget); - AddGroup(groupNameId, groupDisplayName, groupDescription, - new AtomToolsFramework::InspectorPropertyGroupWidget(m_lightingPreset.get(), nullptr, m_lightingPreset.get()->TYPEINFO_Uuid(), this)); + groupWidget->layout()->addWidget(inspectorWidget); } - AddGroupsEnd(); + AddGroup(groupNameId, groupDisplayName, groupDescription, groupWidget); + } + + void ViewportSettingsInspector::AddLightingPreset() + { + const AZStd::string defaultPath = GetDefaultUniqueSaveFilePath("untitled.lightingpreset.azasset"); + const AZStd::string savePath = AtomToolsFramework::GetSaveFileInfo(defaultPath.c_str()).absoluteFilePath().toUtf8().constData(); + + if (!savePath.empty()) + { + AZ::Render::LightingPresetPtr preset; + MaterialViewportRequestBus::BroadcastResult( + preset, &MaterialViewportRequestBus::Events::AddLightingPreset, AZ::Render::LightingPreset()); + MaterialViewportRequestBus::Broadcast( + &MaterialViewportRequestBus::Events::SaveLightingPreset, preset, savePath); + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, preset); + } + } + + void ViewportSettingsInspector::SelectLightingPreset() + { + LightingPresetBrowserDialog dialog(QApplication::activeWindow()); + + dialog.setFixedSize(800, 400); + dialog.show(); + + // Removing fixed size to allow drag resizing + dialog.setMinimumSize(0, 0); + dialog.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + dialog.exec(); + } + + void ViewportSettingsInspector::SaveLightingPreset() + { + AZ::Render::LightingPresetPtr preset; + MaterialViewportRequestBus::BroadcastResult(preset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + + AZStd::string defaultPath; + MaterialViewportRequestBus::BroadcastResult(defaultPath, &MaterialViewportRequestBus::Events::GetLightingPresetLastSavePath, preset); + + if (defaultPath.empty()) + { + defaultPath = GetDefaultUniqueSaveFilePath("untitled.lightingpreset.azasset"); + } + + const AZStd::string savePath = AtomToolsFramework::GetSaveFileInfo(defaultPath.c_str()).absoluteFilePath().toUtf8().constData(); + + if (!savePath.empty()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveLightingPreset, preset, savePath); + } + } + + void ViewportSettingsInspector::RefreshPresets() + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::ReloadContent); } void ViewportSettingsInspector::Reset() { - m_lightingPreset.reset(); m_modelPreset.reset(); + MaterialViewportRequestBus::BroadcastResult(m_modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + + m_lightingPreset.reset(); + MaterialViewportRequestBus::BroadcastResult(m_lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + + MaterialViewportRequestBus::BroadcastResult(m_generalSettings.m_enableGrid, &MaterialViewportRequestBus::Events::GetGridEnabled); + MaterialViewportRequestBus::BroadcastResult( + m_generalSettings.m_enableShadowCatcher, &MaterialViewportRequestBus::Events::GetShadowCatcherEnabled); + MaterialViewportRequestBus::BroadcastResult( + m_generalSettings.m_enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); + MaterialViewportRequestBus::BroadcastResult(m_generalSettings.m_fieldOfView, &MaterialViewportRequestBus::Handler::GetFieldOfView); + AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); } @@ -88,6 +320,30 @@ namespace MaterialEditor } } + void ViewportSettingsInspector::OnShadowCatcherEnabledChanged(bool enable) + { + m_generalSettings.m_enableShadowCatcher = enable; + RefreshGroup("general"); + } + + void ViewportSettingsInspector::OnGridEnabledChanged(bool enable) + { + m_generalSettings.m_enableGrid = enable; + RefreshGroup("general"); + } + + void ViewportSettingsInspector::OnAlternateSkyboxEnabledChanged(bool enable) + { + m_generalSettings.m_enableAlternateSkybox = enable; + RefreshGroup("general"); + } + + void ViewportSettingsInspector::OnFieldOfViewChanged(float fieldOfView) + { + m_generalSettings.m_fieldOfView = fieldOfView; + RefreshGroup("general"); + } + void ViewportSettingsInspector::BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) { AZ_UNUSED(pNode); @@ -96,17 +352,37 @@ namespace MaterialEditor void ViewportSettingsInspector::AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) { AZ_UNUSED(pNode); - MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetChanged, m_lightingPreset); - MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetChanged, m_modelPreset); + ApplyChanges(); } void ViewportSettingsInspector::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode) { AZ_UNUSED(pNode); + ApplyChanges(); + } + + void ViewportSettingsInspector::ApplyChanges() + { MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetChanged, m_lightingPreset); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetChanged, m_modelPreset); + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetGridEnabled, m_generalSettings.m_enableGrid); + MaterialViewportRequestBus::Broadcast( + &MaterialViewportRequestBus::Events::SetShadowCatcherEnabled, m_generalSettings.m_enableShadowCatcher); + MaterialViewportRequestBus::Broadcast( + &MaterialViewportRequestBus::Events::SetAlternateSkyboxEnabled, m_generalSettings.m_enableAlternateSkybox); + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Handler::SetFieldOfView, m_generalSettings.m_fieldOfView); } + AZStd::string ViewportSettingsInspector::GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const + { + AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR; + savePath += "Materials"; + savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR; + savePath += baseName; + savePath = AtomToolsFramework::GetUniqueFileInfo(savePath.c_str()).absoluteFilePath().toUtf8().constData(); + return savePath; + } } // namespace MaterialEditor #include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h index 7b96e96748..08e22a380c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h @@ -22,6 +22,18 @@ namespace MaterialEditor { + struct GeneralViewportSettings + { + AZ_TYPE_INFO(GeneralViewportSettings, "{16150503-A314-4765-82A3-172670C9EA90}"); + AZ_CLASS_ALLOCATOR(GeneralViewportSettings, AZ::SystemAllocator, 0); + static void Reflect(AZ::ReflectContext* context); + + bool m_enableGrid = true; + bool m_enableShadowCatcher = true; + bool m_enableAlternateSkybox = false; + float m_fieldOfView = 90.0f; + }; + //! Provides controls for viewing and editing a material document settings. //! The settings can be divided into cards, with each one showing a subset of properties. class ViewportSettingsInspector @@ -38,6 +50,19 @@ namespace MaterialEditor private: void Popuate(); + void AddGeneralGroup(); + + void AddModelGroup(); + void AddModelPreset(); + void SelectModelPreset(); + void SaveModelPreset(); + + void AddLightingGroup(); + void AddLightingPreset(); + void SelectLightingPreset(); + void SaveLightingPreset(); + + void RefreshPresets(); // AtomToolsFramework::InspectorRequestBus::Handler overrides... void Reset() override; @@ -45,16 +70,24 @@ namespace MaterialEditor // MaterialViewportNotificationBus::Handler overrides... void OnLightingPresetSelected([[maybe_unused]] AZ::Render::LightingPresetPtr preset) override; void OnModelPresetSelected([[maybe_unused]] AZ::Render::ModelPresetPtr preset) override; + void OnShadowCatcherEnabledChanged(bool enable) override; + void OnGridEnabledChanged(bool enable) override; + void OnAlternateSkyboxEnabledChanged(bool enable) override; + void OnFieldOfViewChanged(float fieldOfView) override; // AzToolsFramework::IPropertyEditorNotify overrides... void BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) override; void AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) override; void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {} void SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode) override; + void ApplyChanges(); void SealUndoStack() override {} void RequestPropertyContextMenu(AzToolsFramework::InstanceDataNode*, const QPoint&) override {} void PropertySelectionChanged(AzToolsFramework::InstanceDataNode*, bool) override {} + AZStd::string GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const; + + GeneralViewportSettings m_generalSettings; AZ::Render::ModelPresetPtr m_modelPreset; AZ::Render::LightingPresetPtr m_lightingPreset; }; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp index 7b7015aa68..eb80638a4d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp @@ -10,6 +10,8 @@ * */ +#include +#include #include #include #include @@ -43,12 +45,17 @@ int main(int argc, char** argv) AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware); MaterialEditor::MaterialEditorApplication app(&argc, &argv); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } auto globalEventFilter = new AzQtComponents::GlobalEventFilter(&app); app.installEventFilter(globalEventFilter); AzQtComponents::StyleManager styleManager(&app); - styleManager.Initialize(&app); + styleManager.initialize(&app, engineRootPath); app.Start(AZ::ComponentApplication::Descriptor{}); app.exec(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditorwindow_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditorwindow_files.cmake index 712e44a62b..fef3aeefb7 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditorwindow_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditorwindow_files.cmake @@ -29,11 +29,16 @@ set(FILES Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp Source/Window/CreateMaterialDialog/CreateMaterialDialog.h Source/Window/CreateMaterialDialog/CreateMaterialDialog.ui + Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp + Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h + Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui + Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp + Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h + Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp + Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui - Source/Window/ToolBar/FovSliderWidget.h - Source/Window/ToolBar/FovSliderWidget.cpp Source/Window/ToolBar/MaterialEditorToolBar.h Source/Window/ToolBar/MaterialEditorToolBar.cpp Source/Window/ToolBar/ModelPresetComboBox.h diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt b/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt index 0b3ffdcf5e..2222cd46cf 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt @@ -102,6 +102,12 @@ ly_add_target_dependencies( Source/Platform/${PAL_PLATFORM_NAME}/tool_dependencies_${PAL_PLATFORM_NAME_LOWERCASE}.cmake ) +# Inject the project path into the ShaderManagementConsole VS debugger command arguments if the build system being invoked +# in a project centric view +if(NOT PROJECT_NAME STREQUAL "O3DE") + set_property(TARGET ShaderManagementConsole APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${CMAKE_SOURCE_DIR}\"") +endif() + # Adds the ShaderManagementConsole target as a C preprocessor define so that it can be used as a Settings Registry # specialization in order to look up the generated .setreg which contains the dependencies # specified for the target. diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index 0c34f1d7ba..cca963fee7 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -379,10 +379,8 @@ namespace ShaderManagementConsole { AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); AZ::IO::FixedMaxPath assetDatabaseSqlitePath; - if (settingsRegistry && settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) + if (settingsRegistry && settingsRegistry->Get(assetDatabaseSqlitePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) { - // Grab the Parent of the Asset RootPath to remove the platform from the end of the path - assetDatabaseSqlitePath = assetDatabaseSqlitePath.ParentPath(); assetDatabaseSqlitePath /= "assetdb.sqlite"; result = AZStd::string_view(assetDatabaseSqlitePath.Native()); return true; diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp index 59c6ef632e..5692522e58 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp @@ -10,6 +10,8 @@ * */ +#include +#include #include #include #include @@ -43,12 +45,17 @@ int main(int argc, char** argv) AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::PerScreenDpiAware); ShaderManagementConsole::ShaderManagementConsoleApplication app(&argc, &argv); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } auto globalEventFilter = new AzQtComponents::GlobalEventFilter(&app); app.installEventFilter(globalEventFilter); AzQtComponents::StyleManager styleManager(&app); - styleManager.Initialize(&app); + styleManager.initialize(&app, engineRootPath); app.Start({}); app.exec(); diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt index bf764a7bda..0eb6898b07 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt @@ -34,7 +34,6 @@ ly_add_target( ly_add_target( NAME Atom_AtomBridge ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_AtomBridge.b55b2738aa4a46c8b034fe98e6e5158b.v0.1.0 FILES_CMAKE atombridge_shared_files.cmake INCLUDE_DIRECTORIES @@ -54,7 +53,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME Atom_AtomBridge.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_AtomBridge.Editor.b55b2738aa4a46c8b034fe98e6e5158b.v0.1.0 FILES_CMAKE atombridge_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/FlyCameraInputComponent.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/FlyCameraInputComponent.h index 0beee73321..03fb3c421e 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/FlyCameraInputComponent.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/FlyCameraInputComponent.h @@ -32,7 +32,7 @@ namespace AZ static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void Reflect(AZ::ReflectContext* reflection); - AZ_COMPONENT(FlyCameraInputComponent, "{EB588B1E-AC2E-44AA-A1E6-E5960942E950}"); + AZ_COMPONENT(FlyCameraInputComponent, "{7AE0D6AD-691C-41B6-9DD5-F23F78B1A02E}"); virtual ~FlyCameraInputComponent(); // AZ::Component diff --git a/Gems/AtomLyIntegration/AtomImGuiTools/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomImGuiTools/Code/CMakeLists.txt index 02072fa665..d653d54f6b 100644 --- a/Gems/AtomLyIntegration/AtomImGuiTools/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomImGuiTools/Code/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( ly_add_target( NAME AtomImGuiTools ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AtomImGuiTools.1a9d10de1b8a45fab2fe04517f613962.v0.1.0 FILES_CMAKE atomimguitools_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.ini b/Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.ini deleted file mode 100644 index e123b9ba90..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,4 +0,0 @@ -[RC PostFxLayerCategories] -glob=*.postfxlayercategories -params=copy -productAssetType={A18B1B11-4C1E-4C1B-9643-178E8ED27019} \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.setreg b/Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..e43b0dea2d --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/AssetProcessorGemConfig.setreg @@ -0,0 +1,13 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "RC PostFxLayerCategories": { + "glob": "*.postfxlayercategories", + "params": "copy", + "productAssetType": "{A18B1B11-4C1E-4C1B-9643-178E8ED27019}" + } + } + } + } +} \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt index 0343559d05..16897742cf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt @@ -50,7 +50,6 @@ ly_add_target( ly_add_target( NAME AtomLyIntegration_CommonFeatures ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AtomLyIntegration_CommonFeatures.4e981f3b17394f5d84d674fff0f54f4f.v0.1.0 FILES_CMAKE atomlyintegration_commonfeatures_shared_files.cmake INCLUDE_DIRECTORIES @@ -65,9 +64,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME AtomLyIntegration_CommonFeatures.Editor MODULE + NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.AtomLyIntegration_CommonFeatures.Editor.4e981f3b17394f5d84d674fff0f54f4f.v0.1.0 AUTOUIC AUTOMOC AUTORCC diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 3d21cb49b5..ecb0527a47 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -255,6 +255,10 @@ namespace AZ void MaterialComponentController::SetMaterialOverrides(const MaterialAssignmentMap& materials) { + // this function is called twice once material asset is changed, a temp variable is + // needed to prevent material asset going out of scope during second call + // before LoadMaterials() is called [LYN-2249] + auto temp = m_configuration.m_materials; m_configuration.m_materials = materials; LoadMaterials(); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt index 94852b5eb7..d2a1e5abf0 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt @@ -35,7 +35,6 @@ ly_add_target( ly_add_target( NAME EMotionFX_Atom ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.EMotionFX_Atom.4f8a4d073ba34b43be45705f18705f1e.v0.1.0 FILES_CMAKE emotionfxatom_shared_files.cmake INCLUDE_DIRECTORIES @@ -51,9 +50,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME EMotionFX_Atom.Editor MODULE + NAME EMotionFX_Atom.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.EMotionFX_Atom.Editor.4f8a4d073ba34b43be45705f18705f1e.v0.1.0 FILES_CMAKE emotionfx_atom_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/ImguiAtom/Code/CMakeLists.txt index 2f15dc8f6d..14a64f1133 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/CMakeLists.txt @@ -30,7 +30,6 @@ ly_add_target( ly_add_target( NAME ImguiAtom ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ImguiAtom.9986e22e14184f2fb6bb1e7dd185b2f9.v0.1.0 FILES_CMAKE imguiatom_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt index 79fcdde6c8..75b776fe17 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME DccScriptingInterface.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Atom_DccScriptingInterface.Editor.7bf5a77dacd8438bb4966a66b5a678d8.v0.1.0 FILES_CMAKE dccscriptinginterface_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/__init__.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/__init__.py index b01a2d9d0f..d03e4c6906 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/__init__.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/__init__.py @@ -85,7 +85,7 @@ from pathlib import Path # get/set the project name _LY_DEV = os.getenv(constants.ENVAR_LY_DEV, config_utils.get_stub_check_path(in_path=os.getcwd(), - check_stub='engineroot.txt')) + check_stub='engine.json')) # get/set the project name _LY_PROJECT_TAG = os.getenv(constants.ENVAR_LY_PROJECT, @@ -94,8 +94,8 @@ _LY_PROJECT_TAG = os.getenv(constants.ENVAR_LY_PROJECT, # project cache log dir path _DCCSI_LOG_PATH = Path(os.getenv(constants.ENVAR_DCCSI_LOG_PATH, Path(_LY_DEV, + _LY_PROJECT_TAG, 'Cache', - _LY_PROJECT_TAG, 'pc', 'user', 'log', 'logs'))) diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py index b20f1e1b36..f7bbe0bf5b 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py @@ -30,7 +30,7 @@ _LOGGER = _logging.getLogger(_PACKAGENAME) _LOGGER.debug('Initializing: {0}.'.format({_PACKAGENAME})) __all__ = ['get_os', 'return_stub', 'get_stub_check_path', - 'get_dccsi_config', 'get_current_project'] + 'get_dccsi_config'] # note: this module should reamin py2.7 compatible (Maya) so no f'strings # ------------------------------------------------------------------------- @@ -135,23 +135,6 @@ def get_dccsi_config(dccsi_dirpath=return_stub_dir()): return None # ------------------------------------------------------------------------- - -# ------------------------------------------------------------------------- -def get_current_project(dev_folder=get_stub_check_path()): - """Uses regex in lumberyard Dev\\bootstrap.cfg to retreive project tag str""" - boostrap_filepath = Path(dev_folder, "bootstrap.cfg") - if boostrap_filepath.exists(): - bootstrap = open(str(boostrap_filepath), "r") - game_project_regex = re.compile(r"^sys_game_folder\s*=\s*(.*)") - for line in bootstrap: - game_folder_match = game_project_regex.match(line) - if game_folder_match: - _LOGGER.debug('Project is: {}'.format(game_folder_match.group(1))) - return game_folder_match.group(1) - return None -# ------------------------------------------------------------------------- - - # ------------------------------------------------------------------------- def bootstrap_dccsi_py_libs(dccsi_dirpath=return_stub_dir()): """Builds and adds local site dir libs based on py version""" @@ -192,9 +175,6 @@ if __name__ == '__main__': _LOGGER.info('DCCSI_CONFIG_PATH: {}'.format(_config)) _LOGGER.info('LY_DEV: {}'.format(get_stub_check_path('engineroot.txt'))) - - _LOGGER.info('LY_PROJECT: {}'.format(get_current_project(get_stub_check_path('engineroot.txt')))) - _LOGGER.info('DCCSI_PYTHON_LIB_PATH: {}'.format(bootstrap_dccsi_py_libs(return_stub_dir('dccsi_stub')))) diff --git a/Gems/AudioEngineWwise/AssetProcessorGemConfig.ini b/Gems/AudioEngineWwise/AssetProcessorGemConfig.ini deleted file mode 100644 index 5a5e8fc5ab..0000000000 --- a/Gems/AudioEngineWwise/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,12 +0,0 @@ - -[Exclude AudioProject] -pattern=.*\\/Sounds\\/.+_project.* - -[Exclude AudioTemp] -pattern=.*\\/Sounds\\/.+\\.(txt|xml|dat) - -[RC audio] -pattern=.*\\.(wav|pcm) -params=copy -productAssetType={2FC41C35-244B-41D3-A312-B1E222CAE762} -server=skip diff --git a/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg b/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..9b4d86791c --- /dev/null +++ b/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg @@ -0,0 +1,20 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "Exclude AudioProject": { + "pattern": ".*\\\\/Sounds\\\\/.+_project.*" + }, + "Exclude AudioTemp": { + "pattern": ".*\\\\/Sounds\\\\/.+\\\\.(txt|xml|dat)" + }, + "RC audio": { + "pattern": ".*\\\\.(wav|pcm)", + "params": "copy", + "productAssetType": "{2FC41C35-244B-41D3-A312-B1E222CAE762}", + "server": "skip" + } + } + } + } +} diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 5351d5bdba..73cfe8d90b 100644 --- a/Gems/AudioEngineWwise/Code/CMakeLists.txt +++ b/Gems/AudioEngineWwise/Code/CMakeLists.txt @@ -26,7 +26,7 @@ if (PAL_TRAIT_BUILD_SERVER_SUPPORTED OR PAL_TRAIT_AUDIO_ENGINE_WWISE_USE_STUB) ly_add_target( NAME AudioEngineWwise.Stub ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AudioEngineWwise.Stub + OUTPUT_NAME AudioEngineWwise.Stub FILES_CMAKE audioenginewwise_stub_files.cmake BUILD_DEPENDENCIES @@ -68,7 +68,6 @@ ly_add_target( ly_add_target( NAME AudioEngineWwise ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AudioEngineWwise.67a80e2ac865406c990f2715feb55f7f.v0.1.0 FILES_CMAKE audioenginewwise_shared_files.cmake INCLUDE_DIRECTORIES @@ -201,9 +200,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME AudioEngineWwise.Editor MODULE + NAME AudioEngineWwise.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.AudioEngineWwise.Editor.67a80e2ac865406c990f2715feb55f7f.v0.1.0 FILES_CMAKE audioenginewwise_editor_shared_files.cmake COMPILE_DEFINITIONS @@ -219,6 +218,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::AudioEngineWwise.Editor.Static + RUNTIME_DEPENDENCIES + Gem::AudioSystem.Editor ) if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) diff --git a/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.cpp b/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.cpp index 49524742d2..faaf4d5c75 100644 --- a/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.cpp +++ b/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.cpp @@ -17,8 +17,9 @@ #include #include #include +#include +#include -#include #include #include #include @@ -111,7 +112,7 @@ namespace AudioEngineWwiseGem #endif // AUDIO_ENGINE_WWISE_EDITOR } - bool AudioEngineWwiseGemSystemComponent::Initialize(const SSystemInitParams* initParams) + bool AudioEngineWwiseGemSystemComponent::Initialize() { bool success = false; @@ -143,7 +144,14 @@ namespace AudioEngineWwiseGem AZ::AllocatorInstance::Create(allocDesc); } - m_engineWwise = AZStd::make_unique(initParams->assetsPlatform); + AZ::SettingsRegistryInterface::FixedValueString assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform( + AZ_TRAIT_OS_PLATFORM_CODENAME); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, assetPlatform, + AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "assets"); + } + m_engineWwise = AZStd::make_unique(assetPlatform.c_str()); if (m_engineWwise) { #if AZ_TRAIT_AUDIOENGINEWWISE_PROVIDE_IMPL_SECONDARY_POOL diff --git a/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.h b/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.h index fa2dc8678b..131f9a025c 100644 --- a/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.h +++ b/Gems/AudioEngineWwise/Code/Source/AudioEngineWwiseGemSystemComponent.h @@ -47,7 +47,7 @@ namespace AudioEngineWwiseGem protected: //////////////////////////////////////////////////////////////////////// // Audio::Gem::AudioEngineGemRequestBus interface implementation - bool Initialize(const SSystemInitParams* initParams) override; + bool Initialize() override; void Release() override; //////////////////////////////////////////////////////////////////////// diff --git a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp index a68057ce6a..e6e1c0db7f 100644 --- a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp +++ b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,7 @@ protected: const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - AZ::IO::Path assetRoot(engineRoot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); diff --git a/Gems/AudioSystem/Code/CMakeLists.txt b/Gems/AudioSystem/Code/CMakeLists.txt index e1e1f492cf..83167ff92b 100644 --- a/Gems/AudioSystem/Code/CMakeLists.txt +++ b/Gems/AudioSystem/Code/CMakeLists.txt @@ -43,7 +43,6 @@ ly_add_target( ly_add_target( NAME AudioSystem ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.AudioSystem.6f63f2b6d07f4b89b4b7c86ebee7feb8.v0.1.0 FILES_CMAKE audiosystem_shared_files.cmake INCLUDE_DIRECTORIES @@ -69,9 +68,9 @@ ly_add_target( if (PAL_TRAIT_BUILD_SERVER_SUPPORTED) # Stub gem for server. Audio system is client only ly_add_target( - NAME AudioSystem.Server MODULE + NAME AudioSystem.Server GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.AudioSystem.Server.6f63f2b6d07f4b89b4b7c86ebee7feb8.v0.1.0 FILES_CMAKE audiosystem_stub_files.cmake BUILD_DEPENDENCIES @@ -215,9 +214,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AudioSystem.Static ) ly_add_target( - NAME AudioSystem.Editor MODULE + NAME AudioSystem.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.AudioSystem.Editor.6f63f2b6d07f4b89b4b7c86ebee7feb8.v0.1.0 FILES_CMAKE audiosystem_editor_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp b/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp index f407ab9cba..a09da7a1bc 100644 --- a/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp +++ b/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp @@ -156,7 +156,7 @@ namespace AudioSystemGem // Initialize the implementation module... bool initImplSuccess = false; - Audio::Gem::AudioEngineGemRequestBus::BroadcastResult(initImplSuccess, &Audio::Gem::AudioEngineGemRequestBus::Events::Initialize, initParams); + Audio::Gem::AudioEngineGemRequestBus::BroadcastResult(initImplSuccess, &Audio::Gem::AudioEngineGemRequestBus::Events::Initialize); if (initImplSuccess) { diff --git a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt index 03705bc1e9..551f76da02 100644 --- a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt +++ b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt @@ -39,4 +39,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::AutomatedLauncherTesting.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) diff --git a/Gems/Blast/AssetProcessorGemConfig.ini b/Gems/Blast/AssetProcessorGemConfig.ini deleted file mode 100644 index 346ddbfb90..0000000000 --- a/Gems/Blast/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,13 +0,0 @@ -[RC Blast Asset] -glob=*.blast -params=copy -productAssetType={5BBFE65A-B2F7-4752-A12A-8B44A07D88EB} - -[RC blastmaterial] -glob=*.blastmaterial -params=copy -productAssetType={55F38C86-0767-4E7F-830A-A4BF624BE4DA} - -[RC blastconfiguration] -glob=*.blastconfiguration -params=copy \ No newline at end of file diff --git a/Gems/Blast/AssetProcessorGemConfig.setreg b/Gems/Blast/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..49d85f1a90 --- /dev/null +++ b/Gems/Blast/AssetProcessorGemConfig.setreg @@ -0,0 +1,22 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "RC Blast Asset": { + "glob": "*.blast", + "params": "copy", + "productAssetType": "{5BBFE65A-B2F7-4752-A12A-8B44A07D88EB}" + }, + "RC blastmaterial": { + "glob": "*.blastmaterial", + "params": "copy", + "productAssetType": "{55F38C86-0767-4E7F-830A-A4BF624BE4DA}" + }, + "RC blastconfiguration": { + "glob": "*.blastconfiguration", + "params": "copy" + } + } + } + } +} diff --git a/Gems/Blast/Code/CMakeLists.txt b/Gems/Blast/Code/CMakeLists.txt index f6e02cd799..d06ac4a687 100644 --- a/Gems/Blast/Code/CMakeLists.txt +++ b/Gems/Blast/Code/CMakeLists.txt @@ -43,7 +43,6 @@ ly_add_target( ly_add_target( NAME Blast ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Blast.414bd211c99d4f74aef3a266b9ca208c.v0.1.0 FILES_CMAKE blast_shared_files.cmake INCLUDE_DIRECTORIES @@ -55,6 +54,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::Blast.Static + RUNTIME_DEPENDENCIES + Gem::PhysX ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -87,10 +88,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Blast.Editor MODULE + NAME Blast.Editor GEM_MODULE + NAMESPACE Gem AUTOMOC - OUTPUT_NAME Gem.Blast.Editor.414bd211c99d4f74aef3a266b9ca208c.v0.1.0 FILES_CMAKE blast_editor_shared_files.cmake INCLUDE_DIRECTORIES @@ -104,7 +105,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Blast.Editor.Static Gem::PythonAssetBuilder.Editor RUNTIME_DEPENDENCIES - 3rdParty::assimplib + 3rdParty::assimplib + Gem::PhysX.Editor ) endif() diff --git a/Gems/Blast/Code/blast_unsupported.cmake b/Gems/Blast/Code/blast_unsupported.cmake index a94e47c23c..25cf984717 100644 --- a/Gems/Blast/Code/blast_unsupported.cmake +++ b/Gems/Blast/Code/blast_unsupported.cmake @@ -25,7 +25,8 @@ add_library(Gem::Blast ALIAS Blast.Stub) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Blast.Editor.Stub MODULE + NAME Blast.Editor.Stub GEM_MODULE + NAMESPACE Gem FILES_CMAKE blast_stub_files.cmake diff --git a/Gems/Camera/Code/CMakeLists.txt b/Gems/Camera/Code/CMakeLists.txt index 27edefe36d..950ff451ff 100644 --- a/Gems/Camera/Code/CMakeLists.txt +++ b/Gems/Camera/Code/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( ly_add_target( NAME Camera ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Camera.f910686b6725452fbfc4671f95f733c6.v0.1.0 FILES_CMAKE camera_shared_files.cmake INCLUDE_DIRECTORIES @@ -43,9 +42,9 @@ ly_add_target( if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Camera.Editor MODULE + NAME Camera.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Camera.Editor.f910686b6725452fbfc4671f95f733c6.v0.1.0 FILES_CMAKE camera_editor_files.cmake COMPILE_DEFINITIONS diff --git a/Gems/CameraFramework/Code/CMakeLists.txt b/Gems/CameraFramework/Code/CMakeLists.txt index dc7dd1abdb..1ec9dc0ad9 100644 --- a/Gems/CameraFramework/Code/CMakeLists.txt +++ b/Gems/CameraFramework/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME CameraFramework ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.CameraFramework.54f2763fe191432fa681ce4a354eedf5.v0.1.0 FILES_CMAKE cameraframework_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/CertificateManager/Code/CMakeLists.txt b/Gems/CertificateManager/Code/CMakeLists.txt index 884b9fedad..93e78bb86a 100644 --- a/Gems/CertificateManager/Code/CMakeLists.txt +++ b/Gems/CertificateManager/Code/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( ly_add_target( NAME CertificateManager ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.CertificateManager.659cffff33b14a10835bafc6ea623f98.v0.0.1 FILES_CMAKE certificatemanager_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/CrashReporting/Code/CMakeLists.txt b/Gems/CrashReporting/Code/CMakeLists.txt index 112c7f67fb..0195aa82e4 100644 --- a/Gems/CrashReporting/Code/CMakeLists.txt +++ b/Gems/CrashReporting/Code/CMakeLists.txt @@ -16,7 +16,6 @@ endif() ly_add_target( NAME CrashReporting ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.CrashReporting.089562a2cbbd41749b359f85fa04f1c9.v0.1.0 FILES_CMAKE crashreporting_static_files.cmake Platform/${PAL_PLATFORM_NAME}/crashreporting_static_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake diff --git a/Gems/CustomAssetExample/Code/CMakeLists.txt b/Gems/CustomAssetExample/Code/CMakeLists.txt index ecf86e2117..7bad2611ca 100644 --- a/Gems/CustomAssetExample/Code/CMakeLists.txt +++ b/Gems/CustomAssetExample/Code/CMakeLists.txt @@ -12,7 +12,6 @@ ly_add_target( NAME CustomAssetExample ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.CustomAssetExample.ad082dd50c6545849729e9afeaaeaa1d.v0.1.0 FILES_CMAKE customassetexample_shared_files.cmake INCLUDE_DIRECTORIES @@ -27,9 +26,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME CustomAssetExample.Editor MODULE + NAME CustomAssetExample.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.CustomAssetExample.Editor.ad082dd50c6545849729e9afeaaeaa1d.v0.1.0 FILES_CMAKE customassetexample_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/DebugDraw/Code/CMakeLists.txt b/Gems/DebugDraw/Code/CMakeLists.txt index b000e18977..5759cdaff2 100644 --- a/Gems/DebugDraw/Code/CMakeLists.txt +++ b/Gems/DebugDraw/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME DebugDraw ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.DebugDraw.66239f50bf754354b514c850c8b841fb.v0.1.0 FILES_CMAKE debugdraw_shared_files.cmake INCLUDE_DIRECTORIES @@ -42,9 +41,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME DebugDraw.Editor MODULE + NAME DebugDraw.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.DebugDraw.Editor.66239f50bf754354b514c850c8b841fb.v0.1.0 FILES_CMAKE debugdraw_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index 4665f723db..b68db062f2 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -9,8 +9,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -set(GemUUID 044a63ea67d04479aa5daf62ded9d9ca) - ly_get_list_relative_pal_filename(core_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) ly_get_list_relative_pal_filename(editor_pal_dir ${CMAKE_CURRENT_LIST_DIR}/Editor/Platform/${PAL_PLATFORM_NAME}) @@ -60,12 +58,13 @@ ly_add_target( ly_add_target( NAME EMotionFX ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.EMotionFX.${GemUUID}.v0.1.0 FILES_CMAKE Source/Integration/System/emotionfx_module_files.cmake BUILD_DEPENDENCIES PRIVATE Gem::EMotionFX.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if (PAL_TRAIT_BUILD_HOST_TOOLS) @@ -121,9 +120,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME EMotionFX.Editor MODULE + NAME EMotionFX.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.EMotionFX.Editor.${GemUUID}.v0.1.0 FILES_CMAKE Source/Integration/System/emotionfx_module_files.cmake INCLUDE_DIRECTORIES @@ -133,6 +132,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::EMotionFX.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MotionCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MotionCommands.cpp index bf267a6874..df4c462a37 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MotionCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MotionCommands.cpp @@ -221,7 +221,7 @@ namespace CommandSystem // Resolve the filename if it starts with a path alias if (auto fileIoBase{ AZ::IO::FileIOBase::GetInstance() }; fileIoBase && filename.starts_with('@')) { - char resolvedPath[AZ::StringFunc::Path::MaxPathLength]; + char resolvedPath[AZ::IO::MaxPathLength]; if (fileIoBase->ResolvePath(filename.c_str(), resolvedPath, AZ_ARRAY_SIZE(resolvedPath))) { filename = resolvedPath; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp index 962fa7e94d..eb8be44b28 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp @@ -11,6 +11,7 @@ */ #include +#include #include "EMotionFXConfig.h" #include "Mesh.h" #include "SubMesh.h" @@ -29,8 +30,6 @@ namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(Mesh, MeshAllocator, 0) - - // default constructor Mesh::Mesh() : BaseObject() { @@ -48,7 +47,6 @@ namespace EMotionFX mSharedVertexAttributes.SetMemoryCategory(EMFX_MEMCATEGORY_GEOMETRY_MESHES); } - // allocation constructor Mesh::Mesh(uint32 numVerts, uint32 numIndices, uint32 numPolygons, uint32 numOrgVerts, bool isCollisionMesh) { @@ -69,44 +67,137 @@ namespace EMotionFX Allocate(numVerts, numIndices, numPolygons, numOrgVerts); } - - // destructor Mesh::~Mesh() { ReleaseData(); } - - // creation Mesh* Mesh::Create() { return aznew Mesh(); } - - // extended creation Mesh* Mesh::Create(uint32 numVerts, uint32 numIndices, uint32 numPolygons, uint32 numOrgVerts, bool isCollisionMesh) { return aznew Mesh(numVerts, numIndices, numPolygons, numOrgVerts, isCollisionMesh); } + namespace AtomMeshHelpers + { + // Local 2D and 4D packed vector structs as we don't have packed representations in AzCore and don't plan to add these. + struct Vector2 + { + float x; + float y; + }; + + struct Vector4 + { + float x; + float y; + float z; + float w; + }; + + // Needed for converting the packed vectors from the Atom buffers that normally load directly into GPU into AzCore versions used by EMFX. + AZ::Vector2 ConvertVector(const Vector2& input) + { + return AZ::Vector2(input.x, input.y); + } + + AZ::Vector3 ConvertVector(const AZ::PackedVector3f& input) + { + return AZ::Vector3(input.GetX(), input.GetY(), input.GetZ()); + } + + AZ::Vector4 ConvertVector(const Vector4& input) + { + return AZ::Vector4(input.x, input.y, input.z, input.w); + } + + // Convert Atom buffer storing elements of type SourceType to an EMFX vertex attribute layer storing elements of type TargetType. + // The vertex attribute layer is created within and added to the given target mesh. + // Atom meshes might have different vertex features like some might contain tangents or multiple UV sets while other meshes do not have + // tangents or don't contain any UV set at all. The corresponding EMFX sub-meshes do not support that, so we need to pad the vertex buffers. + // @param[in] sourceModelLod Source model LOD asset to read the vertex buffers from. + // @param[in] modelVertexCount Accumulated vertex count for all Atom meshes calculated and cached by the caller. + // @param[in] sourceBufferName The name of the buffer to translate into a vertex attribute layer. + // @param[in] inputBufferData Pointer to the source buffer from the Atom model LOD asset. This contains the data to be translated and copied over. + // @param[in] targetMesh The EMFX mesh where the newly created vertex attribute layer should be added to. + // @param[in] vertexAttributeLayerTypeId The type ID of the attribute layer used to identify type of vertex data (positions, normals, etc.) + // @param[in] keepOriginals True in case the vertex elements change when deforming the mesh, false if not. + // @param[in] defaultPaddingValue The value used for the sub-meshes in the EMFX that do not contain a given vertex feature in Atom for the given mesh. + template + void CreateAndAddVertexAttributeLayer(const AZ::Data::Asset& sourceModelLod, AZ::u32 modelVertexCount, + const AZ::Name& sourceBufferName, const void* inputBufferData, + Mesh* targetMesh, AZ::u32 vertexAttributeLayerTypeId, bool keepOriginals, + const TargetType& defaultPaddingValue) + { + VertexAttributeLayerAbstractData* targetVertexAttributeLayer = VertexAttributeLayerAbstractData::Create(modelVertexCount, vertexAttributeLayerTypeId, sizeof(TargetType), keepOriginals); + TargetType* targetBuffer = static_cast(targetVertexAttributeLayer->GetData()); + + // Fill the vertex attribute layer by iterating through the Atom meshes and copying over the vertex data for each. + size_t addedElements = 0; + for (const AZ::RPI::ModelLodAsset::Mesh& atomMesh : sourceModelLod->GetMeshes()) + { + const uint32_t atomMeshVertexCount = atomMesh.GetVertexCount(); + const AZ::RPI::BufferAssetView* bufferAssetView = atomMesh.GetSemanticBufferAssetView(sourceBufferName); + if (bufferAssetView) + { + const AZ::RHI::BufferViewDescriptor& bufferAssetViewDescriptor = bufferAssetView->GetBufferViewDescriptor(); + const SourceType* atomMeshBuffer = reinterpret_cast(inputBufferData) + bufferAssetViewDescriptor.m_elementOffset; + + for (size_t vertexIndex = 0; vertexIndex < atomMeshVertexCount; ++vertexIndex) + { + targetBuffer[vertexIndex] = ConvertVector(atomMeshBuffer[vertexIndex]); + } + } + else + { + AZ_Warning("EMotionFX", false, "Padding %s buffer for mesh %s. Mesh has %d vertices while buffer is empty.", + sourceBufferName.GetCStr(), atomMesh.GetName().GetCStr(), atomMeshVertexCount); + + for (size_t vertexIndex = 0; vertexIndex < atomMeshVertexCount; ++vertexIndex) + { + targetBuffer[vertexIndex] = defaultPaddingValue; + } + } + + targetBuffer += atomMeshVertexCount; + addedElements += atomMeshVertexCount; + } + + AZ_Assert(addedElements == modelVertexCount, "The model has %d vertices while we only added %d elements to the %s buffer.", + modelVertexCount, addedElements, sourceBufferName.GetCStr()); + + // In case we want to keep the original values, the target buffer will have double the size and we copy the same thing twice. + // The original values won't be touched when morphing or skinning but are needed as a base for the mesh deformations. + if (keepOriginals) + { + memcpy(targetBuffer, targetVertexAttributeLayer->GetData(), sizeof(TargetType) * modelVertexCount); + } + + targetMesh->AddVertexAttributeLayer(targetVertexAttributeLayer); + } + }; Mesh* Mesh::CreateFromModelLod(const AZ::Data::Asset& sourceModelLod, const AZStd::unordered_map& skinToSkeletonIndexMap) { - AZ::u32 numVertex = 0; - AZ::u32 numIndices = 0; + AZ::u32 modelVertexCount = 0; + AZ::u32 modelIndexCount = 0; for (const AZ::RPI::ModelLodAsset::Mesh& mesh : sourceModelLod->GetMeshes()) { - numVertex += mesh.GetVertexCount(); - numIndices += mesh.GetIndexCount(); + modelVertexCount += mesh.GetVertexCount(); + modelIndexCount += mesh.GetIndexCount(); } + // IndicesPerFace defined in atom is 3. - const AZ::u32 numPolygons = numIndices / 3; - Mesh* mesh = Create(numVertex, numIndices, numPolygons, numVertex, false); + const AZ::u32 numPolygons = modelIndexCount / 3; + Mesh* mesh = Create(modelVertexCount, modelIndexCount, numPolygons, modelVertexCount, false); // The lod has shared buffers that combine the data from each submesh. // These buffers can be accessed through the first submesh in their entirety - // by using the BufferViewDescriptor from the Buffer instead of the one from the submesh's BufferAssetView + // by using the BufferViewDescriptor from the Buffer instead of the one from the sub-mesh's BufferAssetView const AZ::RPI::ModelLodAsset::Mesh& sourceMesh = sourceModelLod->GetMeshes()[0]; // Copy the index buffer for the entire lod @@ -129,84 +220,59 @@ namespace EMotionFX for (const AZ::RPI::ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo : sourceMesh.GetStreamBufferInfoList()) { const AZ::RHI::BufferViewDescriptor& bufferAssetViewDescriptor = streamBufferInfo.m_bufferAssetView.GetBufferAsset()->GetBufferViewDescriptor(); - const AZ::u32 elementSize = bufferAssetViewDescriptor.m_elementSize; const size_t elementCountInBytes = bufferAssetViewDescriptor.m_elementSize * bufferAssetViewDescriptor.m_elementCount; - const size_t elementOffsetInBytes = bufferAssetViewDescriptor.m_elementSize * bufferAssetViewDescriptor.m_elementOffset; const void* bufferData = streamBufferInfo.m_bufferAssetView.GetBufferAsset()->GetBuffer().data(); const AZ::Name& name = streamBufferInfo.m_semantic.m_name; if (name == AZ::Name("POSITION")) { - VertexAttributeLayerAbstractData* targetDataLayer = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_POSITIONS, sizeof(AZ::Vector3), true); - AZ::Vector3* targetData = static_cast(targetDataLayer->GetData()); - const AZ::PackedVector3f* sourceData = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset; - for (size_t vertexIndex = 0; vertexIndex < numVertex; ++vertexIndex) - { - AZ::PackedVector3f sourceVector = sourceData[vertexIndex]; - targetData[vertexIndex] = AZ::Vector3(sourceVector.GetX(), sourceVector.GetY(), sourceVector.GetZ()); - } - memcpy(targetData + numVertex, targetData, numVertex * sizeof(AZ::Vector3)); - mesh->AddVertexAttributeLayer(targetDataLayer); + AtomMeshHelpers::CreateAndAddVertexAttributeLayer(sourceModelLod, modelVertexCount, + name, bufferData, + mesh, Mesh::ATTRIB_POSITIONS, /*keepOriginals=*/true, + AZ::Vector3(0.0f, 0.0f, 0.0f)); } else if (name == AZ::Name("NORMAL")) { - VertexAttributeLayerAbstractData* targetDataLayer = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_NORMALS, sizeof(AZ::Vector3), true); - AZ::Vector3* targetData = static_cast(targetDataLayer->GetData()); - const AZ::PackedVector3f* sourceData = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset; - for (size_t vertexIndex = 0; vertexIndex < numVertex; ++vertexIndex) - { - const AZ::PackedVector3f& sourceVector = sourceData[vertexIndex]; - targetData[vertexIndex] = AZStd::move(AZ::Vector3(sourceVector.GetX(), sourceVector.GetY(), sourceVector.GetZ())); - } - memcpy(targetData + numVertex, targetData, numVertex * sizeof(AZ::Vector3)); - mesh->AddVertexAttributeLayer(targetDataLayer); + AtomMeshHelpers::CreateAndAddVertexAttributeLayer(sourceModelLod, modelVertexCount, + name, bufferData, + mesh, Mesh::ATTRIB_NORMALS, /*keepOriginals=*/true, + AZ::Vector3(1.0f, 0.0f, 0.0f)); } else if (name == AZ::Name("UV")) { - VertexAttributeLayerAbstractData* uvData = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_UVCOORDS, sizeof(AZ::Vector2), false); - const float* sourceData = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset * 2; - AZ::Vector2* targetData = static_cast(uvData->GetData()); - for (size_t vertexIndex = 0; vertexIndex < numVertex; ++vertexIndex) - { - targetData[vertexIndex] = AZStd::move(AZ::Vector2(sourceData[2 * vertexIndex], sourceData[2 * vertexIndex + 1])); - } - mesh->AddVertexAttributeLayer(uvData); + AtomMeshHelpers::CreateAndAddVertexAttributeLayer(sourceModelLod, modelVertexCount, + name, bufferData, + mesh, Mesh::ATTRIB_UVCOORDS, /*keepOriginals=*/false, + AZ::Vector2(0.0f, 0.0f)); } else if (name == AZ::Name("TANGENT")) { - VertexAttributeLayerAbstractData* tangentData = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_TANGENTS, sizeof(AZ::Vector4), true); - const AZ::Vector4* sourceData = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset; - memcpy(tangentData->GetData(), sourceData, elementCountInBytes); - memcpy((uint8*)tangentData->GetData() + elementCountInBytes, bufferData, elementCountInBytes); - mesh->AddVertexAttributeLayer(tangentData); + AtomMeshHelpers::CreateAndAddVertexAttributeLayer(sourceModelLod, modelVertexCount, + name, bufferData, + mesh, Mesh::ATTRIB_TANGENTS, /*keepOriginals=*/true, + AZ::Vector4(1.0f, 0.0f, 0.0f, 0.0f)); } else if (name == AZ::Name("BITANGENT")) { - VertexAttributeLayerAbstractData* targetDataLayer = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_BITANGENTS, sizeof(AZ::Vector3), true); - AZ::Vector3* targetData = static_cast(targetDataLayer->GetData()); - const AZ::PackedVector3f* sourceData = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset; - for (size_t vertexIndex = 0; vertexIndex < numVertex; ++vertexIndex) - { - const AZ::PackedVector3f& sourceVector = sourceData[vertexIndex]; - targetData[vertexIndex] = AZStd::move(AZ::Vector3(sourceVector.GetX(), sourceVector.GetY(), sourceVector.GetZ())); - } - memcpy(targetData + numVertex, targetData, numVertex * sizeof(AZ::Vector3)); - mesh->AddVertexAttributeLayer(targetDataLayer); + AtomMeshHelpers::CreateAndAddVertexAttributeLayer(sourceModelLod, modelVertexCount, + name, bufferData, + mesh, Mesh::ATTRIB_BITANGENTS, /*keepOriginals=*/true, + AZ::Vector3(1.0f, 0.0f, 0.0f)); } else if (name == AZ::Name("COLOR")) { - VertexAttributeLayerAbstractData* colorData = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_COLORS128, sizeof(AZ::Vector4), false); - const AZ::Vector4* sourceData = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset; - memcpy(colorData->GetData(), sourceData, elementCountInBytes); - mesh->AddVertexAttributeLayer(colorData); + AtomMeshHelpers::CreateAndAddVertexAttributeLayer(sourceModelLod, modelVertexCount, + name, bufferData, + mesh, Mesh::ATTRIB_COLORS128, /*keepOriginals=*/false, + AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f)); } else if (name == AZ::Name("SKIN_JOINTINDICES")) { // Atom stores the skin indices as uint16, but the buffer itself is a buffer of uint32 with two id's per element size_t influenceCount = elementCountInBytes / sizeof(AZ::u16); - maxSkinInfluences = influenceCount / numVertex; + maxSkinInfluences = influenceCount / modelVertexCount; AZ_Assert(maxSkinInfluences > 0 && maxSkinInfluences < 100, "Expect max skin influences in a reasonable value range."); - AZ_Assert(influenceCount % numVertex == 0, "Expect an equal number of influences for each vertex."); + AZ_Assert(influenceCount % modelVertexCount == 0, "Expect an equal number of influences for each vertex."); AZ_Assert(bufferAssetViewDescriptor.m_elementSize == 4, "Expect skin joint indices to be stored in a raw 32-bit per element buffer"); // Multiply element offset by 2 here since m_elementOffset is referring to 32-bit elements @@ -217,7 +283,7 @@ namespace EMotionFX { // Atom stores joint weights as float (range 0 - 1) size_t influenceCount = elementCountInBytes / sizeof(float); - maxSkinInfluences = influenceCount / numVertex; + maxSkinInfluences = influenceCount / modelVertexCount; AZ_Assert(maxSkinInfluences > 0 && maxSkinInfluences < 100, "Expect max skin influences in a reasonable value range."); skinWeights = static_cast(bufferData) + bufferAssetViewDescriptor.m_elementOffset; } @@ -234,9 +300,9 @@ namespace EMotionFX } // Add the original vertex layer - VertexAttributeLayerAbstractData* originalVertexData = VertexAttributeLayerAbstractData::Create(numVertex, Mesh::ATTRIB_ORGVTXNUMBERS, sizeof(AZ::u32), false); + VertexAttributeLayerAbstractData* originalVertexData = VertexAttributeLayerAbstractData::Create(modelVertexCount, Mesh::ATTRIB_ORGVTXNUMBERS, sizeof(AZ::u32), false); AZ::u32* originalVertexDataRaw = static_cast(originalVertexData->GetData()); - for (AZ::u32 i = 0; i < numVertex; ++i) + for (size_t i = 0; i < modelVertexCount; ++i) { originalVertexDataRaw[i] = i; } @@ -246,14 +312,14 @@ namespace EMotionFX if (skinJointIndices && skinWeights) { // Create the skinning layer - SkinningInfoVertexAttributeLayer* skinningLayer = SkinningInfoVertexAttributeLayer::Create(numVertex, /*allocData=*/false); + SkinningInfoVertexAttributeLayer* skinningLayer = SkinningInfoVertexAttributeLayer::Create(modelVertexCount, /*allocData=*/false); mesh->AddSharedVertexAttributeLayer(skinningLayer); MCore::Array2D& skin2dArray = skinningLayer->GetArray2D(); skin2dArray.SetNumPreCachedElements(maxSkinInfluences); - skin2dArray.Resize(numVertex); + skin2dArray.Resize(modelVertexCount); // Fill in skinning data from atom buffer - for (uint32 v = 0; v < numVertex; ++v) + for (uint32 v = 0; v < modelVertexCount; ++v) { for (uint32 i = 0; i < maxSkinInfluences; ++i) { @@ -293,9 +359,9 @@ namespace EMotionFX subMeshVertexCount, subMeshIndexCount, subMeshPolygonCount, - /*materialIndex*/ 0, - /*numJoints*/ 0); - + /*materialIndex*/0, + /*numJoints*/0); + mesh->InsertSubMesh(subMeshIndex, subMesh); vertexOffset += subMeshVertexCount; @@ -1064,78 +1130,78 @@ namespace EMotionFX // remove indexed null triangles (triangles that use 2 or 3 of the same vertices, so which are invisible) uint32 Mesh::RemoveIndexedNullTriangles(bool removeEmptySubMeshes) { - uint32 numRemoved = 0; - uint32 i; + uint32 numRemoved = 0; + uint32 i; - // for all triangles - uint32 numIndices = mNumIndices; - uint32 offset = 0; - for (i=0; i 0) - MCore::MemMove(((uint8*)mIndices + (offset * sizeof(uint32))), ((uint8*)mIndices + (offset+3)*sizeof(uint32)), numBytesToMove); + // if we need to remove this triangle + if (indexA == indexB || indexA == indexC || indexB == indexC) + { + // re-arrange the array in memory + uint32 numBytesToMove = (mNumIndices - (offset+3)) * sizeof(uint32); + if (numBytesToMove > 0) + MCore::MemMove(((uint8*)mIndices + (offset * sizeof(uint32))), ((uint8*)mIndices + (offset+3)*sizeof(uint32)), numBytesToMove); - numRemoved++; - numIndices -= 3; + numRemoved++; + numIndices -= 3; - // adjust all submesh start index offsets changed - //const uint32 numSubMeshes = mSubMeshes.GetLength(); - for (uint32 s=0; sGetStartIndex() <= offset && mSubMeshes[s+1]->GetStartIndex() > offset) - subMesh->SetNumIndices( subMesh->GetNumIndices() - 3 ); - } - else - { - if (subMesh->GetStartIndex() <= offset) - subMesh->SetNumIndices( subMesh->GetNumIndices() - 3 ); - } + // if this isn't the last submesh + if (s < mSubMeshes.GetLength() - 1) + { + // if we remove a triangle from this submesh + if (subMesh->GetStartIndex() <= offset && mSubMeshes[s+1]->GetStartIndex() > offset) + subMesh->SetNumIndices( subMesh->GetNumIndices() - 3 ); + } + else + { + if (subMesh->GetStartIndex() <= offset) + subMesh->SetNumIndices( subMesh->GetNumIndices() - 3 ); + } - // now find out if we need to adjust the index offset of the submesh - if (subMesh->GetStartIndex() >= offset) - { - if (subMesh->GetStartIndex() != offset) - subMesh->SetStartIndex( subMesh->GetStartIndex() - 3 ); - } + // now find out if we need to adjust the index offset of the submesh + if (subMesh->GetStartIndex() >= offset) + { + if (subMesh->GetStartIndex() != offset) + subMesh->SetStartIndex( subMesh->GetStartIndex() - 3 ); + } - // remove the submesh if it's empty - if (subMesh->GetNumIndices() == 0 && removeEmptySubMeshes) - mSubMeshes.Remove(s); - else - s++; + // remove the submesh if it's empty + if (subMesh->GetNumIndices() == 0 && removeEmptySubMeshes) + mSubMeshes.Remove(s); + else + s++; - } - } // if we gotta remove - else - offset += 3; - } + } + } // if we gotta remove + else + offset += 3; + } - // reallocate the array, if we removed anything - if (numIndices != mNumIndices) - mIndices = (uint32*)MCore::AlignedRealloc(mIndices, sizeof(uint32) * numIndices, mNumIndices*sizeof(uint32), 32, EMFX_MEMCATEGORY_GEOMETRY_MESHES, Mesh::MEMORYBLOCK_ID); + // reallocate the array, if we removed anything + if (numIndices != mNumIndices) + mIndices = (uint32*)MCore::AlignedRealloc(mIndices, sizeof(uint32) * numIndices, mNumIndices*sizeof(uint32), 32, EMFX_MEMCATEGORY_GEOMETRY_MESHES, Mesh::MEMORYBLOCK_ID); - // update the number of indices - MCORE_ASSERT(numRemoved == (mNumIndices - numIndices) / 3); - mNumIndices = numIndices; + // update the number of indices + MCORE_ASSERT(numRemoved == (mNumIndices - numIndices) / 3); + mNumIndices = numIndices; - // return the number of removed triangles - return numRemoved; + // return the number of removed triangles + return numRemoved; } */ @@ -1159,7 +1225,7 @@ namespace EMotionFX //------------------------------------ const uint32 numVertsToRemove = (endVertexNr - startVertexNr) + 1; // +1 because we remove the end vertex as well - // remove the num verices counter + // remove the num verices counter mNumVertices -= numVertsToRemove; // remove the attributes from the vertex attribute layers @@ -1508,17 +1574,17 @@ namespace EMotionFX MCore::LogDebug(" + Is Triangle Mesh = %d", CheckIfIsTriangleMesh()); MCore::LogDebug(" + Is Quad Mesh = %d", CheckIfIsQuadMesh()); /* - // iterate through and log all org vertex numbers - const uint32 numOrgVertices = GetNumOrgVertices(); - LogDebug(" - Org Vertices (%d)", numOrgVertices); - for (i=0; iGetMaterial()); /* // output all triangle indices that point inside the data we output above - LogDebug(" - Triangle Indices:"); - const uint32 startVertex = subMesh->GetStartVertex(); - const uint32 startIndex = subMesh->GetStartIndex(); - const uint32 endIndex = subMesh->GetStartIndex() + subMesh->GetNumIndices(); - for (i=startIndex; iGetStartVertex(); + const uint32 startIndex = subMesh->GetStartIndex(); + const uint32 endIndex = subMesh->GetStartIndex() + subMesh->GetNumIndices(); + for (i=startIndex; i #include +#include +#include #include #include @@ -57,19 +59,24 @@ namespace EMStudio } AZStd::string commandString; - AZStd::string resultFileName = filename; + AZ::IO::Path resultFileName = filename; // If the filename is in the asset source folder, we relocated it to the cache folder first. - if (GetMainWindow()->GetFileManager()->IsFileInAssetSource(resultFileName)) + if (!GetMainWindow()->GetFileManager()->IsFileInAssetCache(resultFileName.Native()) && + GetMainWindow()->GetFileManager()->IsFileInAssetSource(resultFileName.Native())) { - GetMainWindow()->GetFileManager()->RelocateToAssetCacheFolder(resultFileName); + GetMainWindow()->GetFileManager()->RelocateToAssetCacheFolder(resultFileName.Native()); } - if (GetMainWindow()->GetFileManager()->IsFileInAssetCache(resultFileName)) + if (GetMainWindow()->GetFileManager()->IsFileInAssetCache(resultFileName.Native())) { // Retrieve relative filename for file in cache folder. - EMotionFX::GetEMotionFX().GetFilenameRelativeTo(&resultFileName, EMotionFX::GetEMotionFX().GetAssetCacheFolder().c_str()); - resultFileName = "@assets@/" + resultFileName; + if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) + { + AZ::IO::FixedMaxPath convertedPath; + fileIoBase->ConvertToAlias(convertedPath, resultFileName); + resultFileName = convertedPath; + } } else { @@ -80,9 +87,19 @@ namespace EMStudio AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, filename.c_str(), assetInfo, watchFolder); if (success) { - // In this case, the file likely exists in the other folder detectived by AP (e.g Gems/something/Assets) + // In this case, the file likely exists in the other folder not scanned by AP (e.g Gems/something/Assets) // AP will process this file and move the processed file in cache folder. - resultFileName = "@assets@/" + assetInfo.m_relativePath; + AZ::IO::Path assetCachePath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(assetCachePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } + if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) + { + AZ::IO::FixedMaxPath convertedPath; + fileIoBase->ConvertToAlias(convertedPath, assetCachePath / assetInfo.m_relativePath); + resultFileName = convertedPath; + } } else { diff --git a/Gems/EMotionFX/Code/Tests/SystemComponentFixture.h b/Gems/EMotionFX/Code/Tests/SystemComponentFixture.h index d0b359d545..04a1ca4f81 100644 --- a/Gems/EMotionFX/Code/Tests/SystemComponentFixture.h +++ b/Gems/EMotionFX/Code/Tests/SystemComponentFixture.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -165,7 +166,12 @@ namespace EMotionFX virtual AZStd::string GetAssetFolder() const { - return m_app.GetAssetRoot(); + AZStd::string assetCachePath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(assetCachePath, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } + return assetCachePath; } // Runs after allocators are set up but before application startup diff --git a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp index 467586c99c..781355f80c 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp @@ -75,8 +75,9 @@ namespace EMotionFX QString GetAssetSaveFolder() const { - QString dataDir = GetEMotionFX().GetAssetCacheFolder().c_str(); - dataDir += "/TmpTestAssets"; + auto testAssetsPath = AZ::IO::Path(GetEMotionFX().GetAssetCacheFolder()) / "TmpTestAssets"; + QString dataDir = QString::fromUtf8(testAssetsPath.c_str(), aznumeric_cast(testAssetsPath.Native().size())); + dataDir += "TmpTestAssets"; if (!QDir(dataDir).exists()) { diff --git a/Gems/EMotionFX/Code/Tests/UI/UIFixture.cpp b/Gems/EMotionFX/Code/Tests/UI/UIFixture.cpp index fb3c9c1486..991c92edb0 100644 --- a/Gems/EMotionFX/Code/Tests/UI/UIFixture.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/UIFixture.cpp @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include #include @@ -51,7 +53,12 @@ namespace EMotionFX AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::NotifyRegisterViews); - (new AzQtComponents::StyleManager(m_uiApp))->initialize(m_uiApp); + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get()) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + (new AzQtComponents::StyleManager(m_uiApp))->initialize(m_uiApp, engineRootPath); } MakeQtApplicationBase::~MakeQtApplicationBase() diff --git a/Gems/EditorPythonBindings/Code/CMakeLists.txt b/Gems/EditorPythonBindings/Code/CMakeLists.txt index e42a6c0753..3a34a8491d 100644 --- a/Gems/EditorPythonBindings/Code/CMakeLists.txt +++ b/Gems/EditorPythonBindings/Code/CMakeLists.txt @@ -48,9 +48,9 @@ ly_add_target( ) ly_add_target( - NAME EditorPythonBindings.Editor MODULE + NAME EditorPythonBindings.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.EditorPythonBindings.Editor.b658359393884c4381c2fe2952b1472a.v0.1.0 FILES_CMAKE editorpythonbindings_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp index d012f3baab..11ac32cede 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -348,73 +349,111 @@ namespace EditorPythonBindings { // the order of the Python paths is the order the Python bootstrap scripts will execute - AZStd::string gameFolder; auto settingsRegistry = AZ::SettingsRegistry::Get(); - settingsRegistry->Get(gameFolder, AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName)); + if (!settingsRegistry) + { + return; + } - if (gameFolder.empty()) + AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); + if (projectPath.empty()) { return; } auto resolveScriptPath = [&pythonPathStack](AZStd::string_view path) { - AZStd::string editorScriptsPath; - AzFramework::StringFunc::Path::Join(path.data(), "Editor/Scripts", editorScriptsPath); + AZ::IO::Path editorScriptsPath(path); + editorScriptsPath /= "Editor/Scripts"; if (AZ::IO::SystemFile::Exists(editorScriptsPath.c_str())) { - pythonPathStack.emplace_back(editorScriptsPath); + pythonPathStack.emplace_back(AZStd::move(editorScriptsPath.LexicallyNormal().Native())); } }; // The discovery order will be: - // - engine - // - gems - // - project - // - user(dev) + // 1 - engine + // 2 - gems + // 3 - project + // 4 - user(dev) - // engine - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - resolveScriptPath(engineRoot); + // 1 - engine + AZ::IO::FixedMaxPath engineRoot; + if (settingsRegistry->Get(engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); !engineRoot.empty()) + { + resolveScriptPath(engineRoot.Native()); + } - // gems - auto moduleCallback = [this, &pythonPathStack, resolveScriptPath, engineRoot](const AZ::ModuleData& moduleData) -> bool + // 2 - gems + struct GetGemSourcePathsVisitor + : AZ::SettingsRegistryInterface::Visitor { - if (moduleData.GetDynamicModuleHandle()) + GetGemSourcePathsVisitor(AZ::SettingsRegistryInterface& settingsRegistry) + : m_settingsRegistry(settingsRegistry) + {} + void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type, + AZStd::string_view value) override { - const AZ::OSString& modulePath = moduleData.GetDynamicModuleHandle()->GetFilename(); - AZStd::string fileName; - AzFramework::StringFunc::Path::GetFileName(modulePath.c_str(), fileName); - - AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(fileName.c_str(), tokens, '.'); - if (tokens.size() > 2 && tokens[0] == "Gem") + AZStd::string_view jsonSourcePathPointer{ path }; + // Remove the array index from the path and check if the JSON path ends with "/SourcePaths" + AZ::StringFunc::TokenizeLast(jsonSourcePathPointer, "/"); + if (jsonSourcePathPointer.ends_with("/SourcePaths")) { - resolveScriptPath(AZStd::string::format("%s/Gems/%s", engineRoot, tokens[1].c_str())); + AZ::IO::Path newSourcePath = jsonSourcePathPointer; + // Resolve any file aliases first - Do not use ResolvePath() as that assumes + // any relative path is underneath the @assets@ alias + if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) + { + AZ::IO::FixedMaxPath replacedAliasPath; + if (fileIoBase->ReplaceAlias(replacedAliasPath, value)) + { + newSourcePath = AZ::IO::PathView(replacedAliasPath); + } + } + + // The current assumption is that the gem source path is the relative to the engine root + AZ::IO::Path engineRootPath; + m_settingsRegistry.Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + newSourcePath = (engineRootPath / newSourcePath).LexicallyNormal(); + + if (auto gemSourcePathIter = AZStd::find(m_gemSourcePaths.begin(), m_gemSourcePaths.end(), newSourcePath); + gemSourcePathIter == m_gemSourcePaths.end()) + { + m_gemSourcePaths.emplace_back(AZStd::move(newSourcePath)); + } } } - return true; + + AZStd::vector m_gemSourcePaths; + private: + AZ::SettingsRegistryInterface& m_settingsRegistry; }; - AZ::ModuleManagerRequestBus::Broadcast(&AZ::ModuleManagerRequestBus::Events::EnumerateModules, moduleCallback); - // project - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - resolveScriptPath(AZStd::string::format("%s/%s", appRoot, gameFolder.c_str())); + GetGemSourcePathsVisitor visitor{ *settingsRegistry }; + constexpr auto gemListKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::OrganizationRootKey) + + "/Gems"; + settingsRegistry->Visit(visitor, gemListKey); + for (const AZ::IO::Path& gemSourcePath : visitor.m_gemSourcePaths) + { + resolveScriptPath(gemSourcePath.Native()); + } + + // 3 - project + resolveScriptPath(AZStd::string_view{ projectPath }); - // user + // 4 - user AZStd::string assetsType; AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, assetsType, AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::Assets); if (!assetsType.empty()) { - // the pattern to user path is /Cache///user e.g. c:/myroot/dev/Cache/MyProject/pc/user - AZStd::string userRelativePath = AZStd::string::format("Cache/%s/%s/user", gameFolder.c_str(), assetsType.c_str()); - AZStd::string userCachePath; - AzFramework::StringFunc::Path::Join(appRoot, userRelativePath.c_str(), userCachePath); - resolveScriptPath(userCachePath); + AZ::IO::FixedMaxPath userCachePath; + if (settingsRegistry->Get(userCachePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + !userCachePath.empty()) + { + userCachePath /= "user"; + resolveScriptPath(userCachePath.Native()); + } } } @@ -493,15 +532,17 @@ namespace EditorPythonBindings bool PythonSystemComponent::ExtendSysPath(const AZStd::unordered_set& extendPaths) { - AZStd::string oldPath{ Py_EncodeLocale(Py_GetPath(), nullptr) }; - AZStd::vector pathParts; - AZ::StringFunc::Tokenize(oldPath, pathParts, DELIM, false, false); - AZStd::unordered_set oldPathSet{ pathParts.begin(), pathParts.end() }; + AZStd::unordered_set oldPathSet; + auto SplitPath = [&oldPathSet](AZStd::string_view pathPart) + { + oldPathSet.emplace(pathPart); + }; + AZ::StringFunc::TokenizeVisitor(Py_EncodeLocale(Py_GetPath(), nullptr), SplitPath, DELIM); bool appended{ false }; AZStd::string pathAppend{ "import sys\n" }; for (const auto& thisStr : extendPaths) { - if (oldPathSet.find(thisStr) == oldPathSet.end()) + if (!oldPathSet.contains(thisStr)) { pathAppend.append(AZStd::string::format("sys.path.append('%s')\n", thisStr.c_str())); appended = true; diff --git a/Gems/EditorPythonBindings/Code/Tests/EditorPythonBindingsTest.cpp b/Gems/EditorPythonBindings/Code/Tests/EditorPythonBindingsTest.cpp index 0a3bc75ab6..86628d08a1 100644 --- a/Gems/EditorPythonBindings/Code/Tests/EditorPythonBindingsTest.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/EditorPythonBindingsTest.cpp @@ -221,8 +221,7 @@ sys.version return static_cast(LogTypes::Skip); }; - AZStd::string filename; - AzFramework::StringFunc::Path::ConstructFull(m_engineRoot, "Gems/EditorPythonBindings/Code/Tests", "EditorPythonBindingsTest", "py", filename); + AZ::IO::Path filename = AZ::IO::PathView(m_engineRoot / "Gems" / "EditorPythonBindings" / "Code" / "Tests" / "EditorPythonBindingsTest.py"); AZ::Entity e; e.CreateComponent(); @@ -284,8 +283,7 @@ sys.version return static_cast(LogTypes::Skip); }; - AZStd::string filename; - AzFramework::StringFunc::Path::ConstructFull(m_engineRoot, "Gems/EditorPythonBindings/Code/Tests", "EditorPythonBindingsTestWithArgs", "py", filename); + AZ::IO::Path filename = AZ::IO::PathView(m_engineRoot / "Gems" / "EditorPythonBindings" / "Code" / "Tests" / "EditorPythonBindingsTestWithArgs.py"); AZ::Entity e; e.CreateComponent(); diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h index f60d8584bb..e9fa4dbda6 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h +++ b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h @@ -12,12 +12,12 @@ #pragma once #include +#include #include #include #include #include -#include #include #include @@ -79,16 +79,14 @@ namespace UnitTest void SetUp() override { // fetch the Engine Root folder + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - int argc = 0; - char** argv = nullptr; - QCoreApplication qtApp(argc, argv); - azsnprintf(m_engineRoot, sizeof(m_engineRoot), AzQtComponents::FindEngineRootDir(nullptr).toLocal8Bit().data()); + settingsRegistry->Get(m_engineRoot.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } m_fileIOHelper = AZStd::make_unique(); - m_fileIOHelper->m_fileIO.SetAlias("@devroot@", m_engineRoot); - m_fileIOHelper->m_fileIO.SetAlias("@engroot@", m_engineRoot); + m_fileIOHelper->m_fileIO.SetAlias("@devroot@", m_engineRoot.c_str()); + m_fileIOHelper->m_fileIO.SetAlias("@engroot@", m_engineRoot.c_str()); AzFramework::Application::Descriptor appDesc; appDesc.m_enableDrilling = false; @@ -141,15 +139,15 @@ namespace UnitTest // required pure virtual overrides void NormalizePath(AZStd::string& ) override {} void NormalizePathKeepCase(AZStd::string& ) override {} - void CalculateBranchTokenForAppRoot(AZStd::string& ) const override {} + void CalculateBranchTokenForEngineRoot(AZStd::string& ) const override {} // Gets the engine root path for testing - const char* GetEngineRoot() const override { return m_engineRoot; } + const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } // Retrieves the app root path for testing - const char* GetAppRoot() const override { return m_engineRoot; } + const char* GetAppRoot() const override { return m_engineRoot.c_str(); } AZ::ComponentApplication m_app; AZStd::unique_ptr m_fileIOHelper; AZStd::unique_ptr m_commandRegistrationBusSupression; - char m_engineRoot[1024]; + AZ::IO::FixedMaxPath m_engineRoot; }; } diff --git a/Gems/ExpressionEvaluation/Code/CMakeLists.txt b/Gems/ExpressionEvaluation/Code/CMakeLists.txt index bacb4feeb3..563e3f3341 100644 --- a/Gems/ExpressionEvaluation/Code/CMakeLists.txt +++ b/Gems/ExpressionEvaluation/Code/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( ly_add_target( NAME ExpressionEvaluation ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ExpressionEvaluation.4c6f9df57ca2468f93c8d860ee6a1167.v0.1.0 FILES_CMAKE expressionevaluation_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/FastNoise/Code/CMakeLists.txt b/Gems/FastNoise/Code/CMakeLists.txt index a4408d8d7f..a49126303a 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( ly_add_target( NAME FastNoise ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.FastNoise.c5f23032407f49ca8d8de1733423565c.v0.1.0 FILES_CMAKE fastnoise_shared_files.cmake INCLUDE_DIRECTORIES @@ -38,6 +37,9 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::FastNoise.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral + Gem::GradientSignal ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -62,9 +64,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME FastNoise.Editor MODULE + NAME FastNoise.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.FastNoise.Editor.c5f23032407f49ca8d8de1733423565c.v0.1.0 FILES_CMAKE fastnoise_editor_shared_files.cmake INCLUDE_DIRECTORIES @@ -75,6 +77,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE FastNoise.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor + Gem::SurfaceData.Editor ) endif() diff --git a/Gems/GameEffectSystem/Code/CMakeLists.txt b/Gems/GameEffectSystem/Code/CMakeLists.txt index 0cf2854928..f5735b5107 100644 --- a/Gems/GameEffectSystem/Code/CMakeLists.txt +++ b/Gems/GameEffectSystem/Code/CMakeLists.txt @@ -26,7 +26,6 @@ ly_add_target( ly_add_target( NAME GameEffectSystem ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.GameEffectSystem.d378b5a7b47747d0a7aa741945df58f3.v1.0.0 FILES_CMAKE gameeffectsystem_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/GameLift/Code/CMakeLists.txt b/Gems/GameLift/Code/CMakeLists.txt index fa09c3304c..f78bc953bd 100644 --- a/Gems/GameLift/Code/CMakeLists.txt +++ b/Gems/GameLift/Code/CMakeLists.txt @@ -41,7 +41,6 @@ ly_add_target( ly_add_target( NAME GameLift ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.GameLift.76de765796504906b73be7365a9bff06.v2.0.0 FILES_CMAKE GameLift_files.cmake ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake @@ -97,9 +96,9 @@ if (PAL_TRAIT_BUILD_SERVER_SUPPORTED) ) ly_add_target( - NAME GameLift.Server MODULE + NAME GameLift.Server GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.GameLift.Server.76de765796504906b73be7365a9bff06.v2.0.0 FILES_CMAKE GameLift_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/GameState/Code/CMakeLists.txt b/Gems/GameState/Code/CMakeLists.txt index 65b2390004..34db30fdb5 100644 --- a/Gems/GameState/Code/CMakeLists.txt +++ b/Gems/GameState/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME GameState ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.GameState.1a557ac19dc34f5697fe03f30be5b6e4.v0.1.0 FILES_CMAKE gamestate_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/GameStateSamples/Code/CMakeLists.txt b/Gems/GameStateSamples/Code/CMakeLists.txt index 9c0c09d983..e3ebc25016 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -32,7 +32,6 @@ ly_add_target( ly_add_target( NAME GameStateSamples ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.GameStateSamples.76db0b1bcff84224a92cbceb373f4a85.v0.1.0 FILES_CMAKE gamestatesamples_shared_files.cmake ${include_pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake diff --git a/Gems/Gestures/Code/CMakeLists.txt b/Gems/Gestures/Code/CMakeLists.txt index 709f1174bb..fe0fd9d98b 100644 --- a/Gems/Gestures/Code/CMakeLists.txt +++ b/Gems/Gestures/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME Gestures ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Gestures.6056556b6088413984309c4a413593ad.v1.0.0 FILES_CMAKE gestures_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index 6490585453..362ef61185 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -31,7 +31,6 @@ ly_add_target( ly_add_target( NAME GradientSignal ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.GradientSignal.8825563d9d964ec3be3bab681f3bd9f2.v0.1.0 FILES_CMAKE gradientsignal_shared_files.cmake INCLUDE_DIRECTORIES @@ -45,6 +44,9 @@ ly_add_target( PUBLIC Gem::ImageProcessing.Headers # ImageProcessing/PixelFormats.h is part of a header in Includes Gem::ImageProcessingAtom.Headers # Atom/ImageProcessing/PixelFormats.h is part of a header in Includes + RUNTIME_DEPENDENCIES + Gem::LmbrCentral + Gem::SurfaceData ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -74,9 +76,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME GradientSignal.Editor MODULE + NAME GradientSignal.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.GradientSignal.Editor.8825563d9d964ec3be3bab681f3bd9f2.v0.1.0 FILES_CMAKE gradientsignal_editor_shared_files.cmake INCLUDE_DIRECTORIES @@ -87,6 +89,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::GradientSignal.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor + Gem::SurfaceData.Editor ) endif() diff --git a/Gems/GraphCanvas/Code/CMakeLists.txt b/Gems/GraphCanvas/Code/CMakeLists.txt index 94c4509b5a..c21c3ac806 100644 --- a/Gems/GraphCanvas/Code/CMakeLists.txt +++ b/Gems/GraphCanvas/Code/CMakeLists.txt @@ -12,7 +12,6 @@ ly_add_target( NAME GraphCanvas ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.GraphCanvas.875b6fcbdeea44deaae7984ad9bb6cdc.v0.1.0 FILES_CMAKE GraphCanvas_game_files.cmake INCLUDE_DIRECTORIES @@ -51,9 +50,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME GraphCanvas.Editor MODULE + NAME GraphCanvas.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.GraphCanvas.Editor.875b6fcbdeea44deaae7984ad9bb6cdc.v0.1.0 AUTOMOC AUTORCC FILES_CMAKE diff --git a/Gems/GraphModel/Code/CMakeLists.txt b/Gems/GraphModel/Code/CMakeLists.txt index 583c2d6a7a..2c4fc57252 100644 --- a/Gems/GraphModel/Code/CMakeLists.txt +++ b/Gems/GraphModel/Code/CMakeLists.txt @@ -31,9 +31,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::GraphCanvasWidgets ) ly_add_target( - NAME GraphModel.Editor MODULE + NAME GraphModel.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.GraphModel.Editor.0844f64a3acf4f5abf3a535dc9b63bc9.v0.1.0 FILES_CMAKE graphmodel_editor_files.cmake COMPILE_DEFINITIONS @@ -49,6 +49,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework Gem::GraphCanvasWidgets Gem::GraphModel.Editor.Static + RUNTIME_DEPENDENCIES + Gem::GraphCanvas.Editor ) endif() diff --git a/Gems/HttpRequestor/Code/CMakeLists.txt b/Gems/HttpRequestor/Code/CMakeLists.txt index e871d3496d..71181f9ff4 100644 --- a/Gems/HttpRequestor/Code/CMakeLists.txt +++ b/Gems/HttpRequestor/Code/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( ly_add_target( NAME HttpRequestor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.HttpRequestor.28479e255bde466e91fc34eec808d9c7.v1.0.0 FILES_CMAKE httprequestor_shared_files.cmake PLATFORM_INCLUDE_FILES diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index a34ec5bad4..0a828c0b2b 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -77,7 +77,6 @@ ly_add_target( ly_add_target( NAME ImGui ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ImGui.bab8807a1bc646b3909f3cc200ffeedf.v0.1.0 FILES_CMAKE imgui_shared_files.cmake INCLUDE_DIRECTORIES @@ -88,13 +87,15 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::ImGui.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME ImGui.Editor MODULE + NAME ImGui.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.ImGui.Editor.bab8807a1bc646b3909f3cc200ffeedf.v0.1.0 AUTOMOC AUTOUIC FILES_CMAKE @@ -115,5 +116,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) 3rdParty::Qt::Widgets AZ::AzToolsFramework Legacy::Editor.Headers + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/ImageProcessing/AssetProcessorGemConfig.ini b/Gems/ImageProcessing/AssetProcessorGemConfig.ini deleted file mode 100644 index b37cbe2bb8..0000000000 --- a/Gems/ImageProcessing/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,15 +0,0 @@ -; ---- add any metadata file type here that needs to be monitored by the AssetProcessor. -; Modifying these meta file will cause the source asset to re-compile again. -; They are specified in the following format -; metadata extension=original extension to replace -; if the metadata extension does not replace the original, then the original can be blank -; so for example if your normal file is blah.tif and your metafile for that file is blah.tif.exportsettings -; then your declaration would be exportsettings= ; ie, it would be blank -; however if your metafile REPLACES the extension (for example, if you have the file blah.i_caf and its metafile is blah.exportsettings) -; then you specify the original extension here to narrow the scope. -; If a relative path to a specific file is provided instead of an extension, a change to the file will change all files -; with the associated extension (e.g. Animations/SkeletonList.xml=i_caf will cause all i_caf files to recompile when -; Animations/SkeletonList.xml within the current game project changes) - -[MetaDataTypes] -imagesettings= \ No newline at end of file diff --git a/Gems/ImageProcessing/AssetProcessorGemConfig.setreg b/Gems/ImageProcessing/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..17d9887fe8 --- /dev/null +++ b/Gems/ImageProcessing/AssetProcessorGemConfig.setreg @@ -0,0 +1,7 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": {} + } + } +} diff --git a/Gems/ImageProcessing/Code/CMakeLists.txt b/Gems/ImageProcessing/Code/CMakeLists.txt index 71e4988dce..356ec3d8a1 100644 --- a/Gems/ImageProcessing/Code/CMakeLists.txt +++ b/Gems/ImageProcessing/Code/CMakeLists.txt @@ -79,9 +79,9 @@ ly_add_source_properties( ) ly_add_target( - NAME ImageProcessing.Editor MODULE + NAME ImageProcessing.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.ImageProcessing.Editor.eeffbd9211cf4ce0b5cc73696b427cbe.v0.1.0 AUTOMOC AUTORCC FILES_CMAKE @@ -108,6 +108,7 @@ ly_add_target( Gem::TextureAtlas RUNTIME_DEPENDENCIES 3rdParty::ASTCEncoder + Gem::TextureAtlas ) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) diff --git a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp index 81e98251cc..64ceabe962 100644 --- a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp +++ b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -67,61 +68,18 @@ namespace TextureAtlasBuilder return (pathLength > 0 && (path.at(pathLength - 1) == '/' || path.at(pathLength - 1) == '\\')); } - bool GetCanonicalPathFromFullPath(const AZStd::string& fullPath, AZStd::string& canonicalPathOut) - { - AZStd::string curPath = fullPath; - - // We avoid using LocalFileIO::ConvertToAbsolutePath for this because it does not behave consistently across platforms. - // On non-Windows platforms, LocalFileIO::ConvertToAbsolutePath requires that the path exist, otherwise the path - // remains unchanged. This won't work for paths that include wildcards. - // Also, on non-Windows platforms, if the path is already a full path, it will remain unchanged even if it contains - // "./" or "../" somewhere other than the beginning of the path - - // Normalize path - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, curPath); - - const AZStd::string slash("/"); - - // Replace "/./" occurrances with "/" - const AZStd::string slashDotSlash("/./"); - bool replaced = false; - do - { - // Replace first occurrance - replaced = AzFramework::StringFunc::Replace(curPath, slashDotSlash.c_str(), slash.c_str(), false, true, false); - } while (replaced); - - // Replace "/xxx/../" with "/" - const AZStd::regex slashDotDotSlash("\\/[^/.]*\\/\\.\\.\\/"); - AZStd::string prevPath; - while (prevPath != curPath) - { - prevPath = curPath; - curPath = AZStd::regex_replace(prevPath, slashDotDotSlash, slash, AZStd::regex_constants::match_flag_type::format_first_only); - } - - if ((curPath.find("..") != AZStd::string::npos) || (curPath.find("./") != AZStd::string::npos) || (curPath.find("/.") != AZStd::string::npos)) - { - return false; - } - - canonicalPathOut = curPath; - return true; - } - bool ResolveRelativePath(const AZStd::string& relativePath, const AZStd::string& watchDirectory, AZStd::string& resolvedFullPathOut) { bool resolved = false; // Get full path by appending the relative path to the watch directory - AZStd::string fullPath = watchDirectory; - fullPath.append("/"); - fullPath.append(relativePath); + AZ::IO::FixedMaxPath resolvedPath; + AZ::IO::FileIOBase::GetInstance()->ReplaceAlias(resolvedPath, AZ::IO::PathView{relativePath}); - // Resolve to canonical path (remove "./" and "../") - resolved = GetCanonicalPathFromFullPath(fullPath, resolvedFullPathOut); + resolvedPath = (AZ::IO::FixedMaxPath{watchDirectory} / resolvedPath).LexicallyNormal(); + resolvedFullPathOut = resolvedPath.String(); - return resolved; + return true; } bool GetAbsoluteSourcePathFromRelativePath(const AZStd::string& relativeSourcePath, AZStd::string& absoluteSourcePathOut) @@ -434,33 +392,38 @@ namespace TextureAtlasBuilder void AtlasBuilderInput::AddFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& insert) { - const AZStd::string& fullPath = insert; + AZ::IO::PathView fullPathView(insert); - AZStd::vector candidates; - AZStd::string fixedPath = fullPath.substr(0, fullPath.find('*')); - fixedPath = fixedPath.substr(0, fixedPath.find_last_of('/')); - candidates.push_back(fixedPath); + // Find first path element with a wild card in it + AZ::IO::Path staticPath; + auto wildCardPathElementIter = fullPathView.begin(); + for (; wildCardPathElementIter != fullPathView.end(); ++wildCardPathElementIter) + { + if (wildCardPathElementIter->Native().contains('*')) + { + break; + } + staticPath /= *wildCardPathElementIter; + } - AZStd::vector wildPath; - AzFramework::StringFunc::Tokenize(fullPath.substr(fixedPath.length()).c_str(), wildPath, "/"); + // The remaining path segments are part of the wild card path - for (size_t i = 0; i < wildPath.size() && candidates.size() > 0; ++i) + AZStd::vector candidates{ AZStd::move(staticPath) }; + for(; wildCardPathElementIter != fullPathView.end() && !candidates.empty(); ++wildCardPathElementIter) { - AZStd::vector nextCandidates; - for (size_t j = 0; j < candidates.size(); ++j) + AZStd::vector nextCandidates; + for (const AZ::IO::Path& candidate : candidates) { - AZStd::string compare = AZStd::string::format("%s/%s", candidates[j].c_str(), wildPath[i].c_str()); - QDir inputFolder(candidates[j].c_str()); - if (inputFolder.exists()) + if (QDir inputFolder(QString::fromUtf8(candidate.c_str(), aznumeric_cast(candidate.Native().size()))); + inputFolder.exists()) { QFileInfoList entries = inputFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files); for (const QFileInfo& entry : entries) { - AZStd::string child = (entry.filePath().toStdString()).c_str(); - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, child); - if (DoesPathnameMatchWildCard(compare, child)) + AZ::IO::Path filenameEntry(entry.fileName().toUtf8().data()); + if (filenameEntry.Match(wildCardPathElementIter->Native())) { - nextCandidates.push_back(child); + nextCandidates.push_back(entry.filePath().toUtf8().data()); } } } @@ -468,138 +431,70 @@ namespace TextureAtlasBuilder candidates = nextCandidates; } - for (size_t i = 0; i < candidates.size(); ++i) + for (const AZ::IO::Path& candidate : candidates) { - if (!IsFolderPath(candidates[i]) && !HasTrailingSlash(fullPath)) + QFileInfo fileInfo(QString::fromUtf8(candidate.c_str(), aznumeric_cast(candidate.Native().size()))); + if (fileInfo.isFile()) { - AZStd::string ext; - AzFramework::StringFunc::Path::GetExtension(candidates[i].c_str(), ext, false); + AZStd::string ext = fileInfo.suffix().toUtf8().data(); if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds") { - bool duplicate = false; - for (size_t j = 0; j < paths.size() && !duplicate; ++j) + auto FindExistingPath = [&candidate](const AZStd::string& path) { - duplicate = paths[j] == candidates[i]; - } - if (!duplicate) + return candidate == AZ::IO::PathView(path); + }; + if (auto foundIt = AZStd::find_if(paths.begin(), paths.end(), FindExistingPath); + foundIt == paths.end()) { - paths.push_back(candidates[i]); + AZStd::string normalizedPath = AZ::IO::Path(candidate.Native(), AZ::IO::PosixPathSeparator).LexicallyNormal().Native(); + paths.push_back(AZStd::move(normalizedPath)); } } } - else if (IsFolderPath(candidates[i]) && HasTrailingSlash(fullPath)) + else if (fileInfo.isDir()) { bool waste = true; - AddFolderContents(paths, candidates[i], waste); + AddFolderContents(paths, candidate.Native(), waste); } } } void AtlasBuilderInput::RemoveFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& remove) { - bool isDir = (remove.at(remove.length() - 1) == '/'); - for (size_t i = 0; i < paths.size(); ++i) + auto RemoveWildCardPath = [&remove](const AZStd::string& subPath) { - if (isDir ? DoesWildCardDirectoryIncludePathname(remove, paths[i]) : DoesPathnameMatchWildCard(remove, paths[i])) - { - paths.erase(paths.begin() + i); - --i; - } - } - } - - // Tells us if the child follows the rule - bool AtlasBuilderInput::DoesPathnameMatchWildCard(const AZStd::string& rule, const AZStd::string& child) - { - AZStd::vector rulePathTokens; - AzFramework::StringFunc::Tokenize(rule.c_str(), rulePathTokens, "/"); - AZStd::vector pathTokens; - AzFramework::StringFunc::Tokenize(child.c_str(), pathTokens, "/"); - if (rulePathTokens.size() != pathTokens.size()) - { - return false; - } - for (size_t i = 0; i < rulePathTokens.size(); ++i) - { - if (!TokenMatchesWildcard(rulePathTokens[i], pathTokens[i])) - { - return false; - } - } - return true; - } - - bool AtlasBuilderInput::DoesWildCardDirectoryIncludePathname(const AZStd::string& rule, const AZStd::string& child) - { - AZStd::vector rulePathTokens; - AzFramework::StringFunc::Tokenize(rule.c_str(), rulePathTokens, "/"); - AZStd::vector pathTokens; - AzFramework::StringFunc::Tokenize(child.c_str(), pathTokens, "/"); - if (rulePathTokens.size() >= pathTokens.size()) - { - return false; - } - for (size_t i = 0; i < rulePathTokens.size(); ++i) - { - if (!TokenMatchesWildcard(rulePathTokens[i], pathTokens[i])) - { - return false; - } - } - return true; - } - - bool AtlasBuilderInput::TokenMatchesWildcard(const AZStd::string& rule, const AZStd::string& child) - { - AZStd::vector ruleTokens; - AzFramework::StringFunc::Tokenize(rule.c_str(), ruleTokens, "*"); - size_t pos = 0; - int token = 0; - if (rule.at(0) != '*' && child.find(ruleTokens[0]) != 0) - { - return false; - } - - while (pos != AZStd::string::npos && token < ruleTokens.size()) - { - pos = child.find(ruleTokens[token], pos); - if (pos != AZStd::string::npos) - { - pos += ruleTokens[token].size(); - } - ++token; - } - return pos == child.size() || (pos != AZStd::string::npos && rule.at(rule.length() - 1) == '*'); + return AZ::IO::PathView(subPath).Match(remove); + }; + AZStd::erase_if(paths, RemoveWildCardPath); } // Replaces all folder paths with the files they contain void AtlasBuilderInput::AddFolderContents(AZStd::vector& paths, const AZStd::string& insert, bool& valid) { - QDir inputFolder(insert.c_str()); - - if (inputFolder.exists()) + if (QDir inputFolder(insert.c_str()); inputFolder.exists()) { QFileInfoList entries = inputFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files); for (const QFileInfo& entry : entries) { - AZStd::string child = (entry.filePath().toStdString()).c_str(); - AZStd::string ext; - bool isDir = !AzFramework::StringFunc::Path::GetExtension(child.c_str(), ext, false); + AZ::IO::Path child = entry.filePath().toUtf8().data(); + AZStd::string ext = entry.suffix().toUtf8().data(); + const bool isDir = entry.isDir(); if (isDir) { - AddFolderContents(paths, child, valid); + AddFolderContents(paths, child.Native(), valid); } else if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds") { - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, child); - bool duplicate = false; - for (size_t i = 0; i < paths.size() && !duplicate; ++i) + auto FindExistingPath = [&child](const AZStd::string& path) { - duplicate = paths[i] == child; - } - if (!duplicate) + return child == AZ::IO::PathView(path); + }; + if (auto foundIter = AZStd::find_if(paths.begin(), paths.end(), FindExistingPath); + foundIter == paths.end()) { - paths.push_back(child); + // Normalize the path to have posix slashes + AZStd::string normalizedPath = AZ::IO::Path(child.Native(), AZ::IO::PosixPathSeparator).LexicallyNormal().Native(); + paths.push_back(AZStd::move(normalizedPath)); } } } @@ -614,17 +509,11 @@ namespace TextureAtlasBuilder // Removes all of the contents of a folder void AtlasBuilderInput::RemoveFolderContents(AZStd::vector& paths, const AZStd::string& remove) { - AZStd::string folder = remove; - AzFramework::StringFunc::Strip(folder, "/", false, false, true); - folder.append("/"); - for (size_t i = 0; i < paths.size(); ++i) + auto RemoveSubPath = [folder = AZ::IO::PathView(remove)](const AZStd::string& subPath) { - if (paths[i].find(folder) == 0) - { - paths.erase(paths.begin() + i); - --i; - } - } + return AZ::IO::PathView(subPath).IsRelativeTo(folder); + }; + AZStd::erase_if(paths, RemoveSubPath); } // Note - Shutdown will be called on a different thread than your process job thread diff --git a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h index 94e2b5b226..f28535998e 100644 --- a/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h +++ b/Gems/ImageProcessing/Code/Source/AtlasBuilder/AtlasBuilderWorker.h @@ -62,15 +62,6 @@ namespace TextureAtlasBuilder //! Removes anything that matches the wildcard static void RemoveFilesUsingWildCard(AZStd::vector& paths, const AZStd::string& remove); - //! Compare considering wildcards - static bool DoesPathnameMatchWildCard(const AZStd::string& rule, const AZStd::string& path); - - //! As FollowsRule but allows extra items after the last '/' - static bool DoesWildCardDirectoryIncludePathname(const AZStd::string& rule, const AZStd::string& path); - - //! Helper function for DoesPathnameMatchWildCard - static bool TokenMatchesWildcard(const AZStd::string& rule, const AZStd::string& token); - //! Resolves any folder paths into image file paths static void AddFolderContents(AZStd::vector& paths, const AZStd::string& insert, bool& valid); diff --git a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp b/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp index 02b85b7eed..8c0dc0ff56 100644 --- a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.cpp @@ -28,6 +28,8 @@ #include #include +#include +#include namespace ImageProcessing { @@ -71,11 +73,13 @@ namespace ImageProcessing builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); m_imageBuilder.BusConnect(builderDescriptor.m_busId); + ImageProcessingRequestBus::Handler::BusConnect(); AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor); } void BuilderPluginComponent::Deactivate() { + ImageProcessingRequestBus::Handler::BusDisconnect(); m_imageBuilder.BusDisconnect(); BuilderSettingManager::DestroyInstance(); CPixelFormats::DestroyInstance(); @@ -111,6 +115,23 @@ namespace ImageProcessing incompatible.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e)); } + IImageObjectPtr BuilderPluginComponent::LoadImage(const AZStd::string& filePath) + { + return IImageObjectPtr(LoadImageFromFile(filePath)); + } + + IImageObjectPtr BuilderPluginComponent::LoadImagePreview(const AZStd::string& filePath) + { + IImageObjectPtr image(LoadImageFromFile(filePath)); + if (image) + { + ImageToProcess imageToProcess(image); + imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8); + return imageToProcess.Get(); + } + return image; + } + void ImageBuilderWorker::ShutDown() { // it is important to note that this will be called on a different thread than your process job thread diff --git a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h b/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h index 881ff4bdba..212081ec92 100644 --- a/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h +++ b/Gems/ImageProcessing/Code/Source/ImageBuilderComponent.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace ImageProcessing { @@ -48,6 +49,7 @@ namespace ImageProcessing //! BuilderPluginComponent is to handle the lifecycle of ImageBuilder module. class BuilderPluginComponent : public AZ::Component + , protected ImageProcessingRequestBus::Handler { public: AZ_COMPONENT(BuilderPluginComponent, "{2F12E1BE-D8F6-47A4-AC3E-6C5527C55840}") @@ -66,6 +68,12 @@ namespace ImageProcessing static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); ////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + // ImageProcessingRequestBus interface implementation + IImageObjectPtr LoadImage(const AZStd::string& filePath) override; + IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override; + //////////////////////////////////////////////////////////////////////// + private: ImageBuilderWorker m_imageBuilder; }; diff --git a/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp b/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp index d49cfe77e3..8fafa9fd93 100644 --- a/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/ImageProcessing/Code/Tests/ImageProcessing_Test.cpp @@ -127,8 +127,9 @@ protected: AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/InAppPurchases/Code/CMakeLists.txt b/Gems/InAppPurchases/Code/CMakeLists.txt index 5c26249dfb..61f9839841 100644 --- a/Gems/InAppPurchases/Code/CMakeLists.txt +++ b/Gems/InAppPurchases/Code/CMakeLists.txt @@ -32,7 +32,6 @@ ly_add_target( ly_add_target( NAME InAppPurchases ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.InAppPurchases.92fe57eae7d3402a90761973678c079a.v0.1.0 FILES_CMAKE inapppurchases_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/LandscapeCanvas/Code/CMakeLists.txt b/Gems/LandscapeCanvas/Code/CMakeLists.txt index 45f2ed7f7b..e8e2fce689 100644 --- a/Gems/LandscapeCanvas/Code/CMakeLists.txt +++ b/Gems/LandscapeCanvas/Code/CMakeLists.txt @@ -43,9 +43,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Vegetation.Editor ) ly_add_target( - NAME LandscapeCanvas.Editor MODULE + NAME LandscapeCanvas.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.LandscapeCanvas.Editor.19c2b2d5018940108baf252934b8e6bf.v0.1.0 FILES_CMAKE landscapecanvas_editor_files.cmake COMPILE_DEFINITIONS @@ -64,6 +64,13 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::GraphCanvasWidgets Gem::GraphModel.Editor.Static Gem::LandscapeCanvas.Editor.Static + RUNTIME_DEPENDENCIES + Gem::GraphCanvas.Editor + Gem::LmbrCentral.Editor + Gem::GraphModel.Editor + Gem::GradientSignal.Editor + Gem::SurfaceData.Editor + Gem::Vegetation.Editor ) endif() diff --git a/Gems/LmbrCentral/Code/CMakeLists.txt b/Gems/LmbrCentral/Code/CMakeLists.txt index 7e68f414d7..c1fbd744e6 100644 --- a/Gems/LmbrCentral/Code/CMakeLists.txt +++ b/Gems/LmbrCentral/Code/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( ly_add_target( NAME LmbrCentral ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0 FILES_CMAKE lmbrcentral_shared_files.cmake INCLUDE_DIRECTORIES @@ -76,9 +75,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME LmbrCentral.Editor MODULE + NAME LmbrCentral.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.LmbrCentral.Editor.ff06785f7145416b9d46fde39098cb0c.v0.1.0 FILES_CMAKE lmbrcentral_editor_shared_files.cmake INCLUDE_DIRECTORIES @@ -96,12 +95,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ${additional_dependencies} ) - unset(QT_LRELEASE_EXECUTABLE CACHE) - find_program(QT_LRELEASE_EXECUTABLE lrelease HINTS "${QT_PATH}/bin") - mark_as_advanced(QT_LRELEASE_EXECUTABLE) # Hiding from GUI - if(NOT QT_LRELEASE_EXECUTABLE) - message(FATAL_ERROR "Qt's lrelease executbale not found") - endif() include(${pal_dir}/lrelease_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) ly_add_target_files( diff --git a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp index be61ba1bb1..1da0759275 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/XmlBuilderWorker/XmlBuilderWorker.cpp @@ -570,7 +570,9 @@ namespace CopyDependencyBuilder { AZ_Error("XmlBuilderWorker", false, rootNodeOutcome.TakeError().c_str()); // The XML file couldn't be loaded. - return SchemaMatchResult::Error; + // We can't know whether this is intentionally an empty file any more than if it were an empty xml with a root node that that were incorrect + // So we leave it as "nothing will match this" and emit the above error + return SchemaMatchResult::NoMatchFound; } AZ::rapidxml::xml_node* xmlFileRootNode = rootNodeOutcome.GetValue(); diff --git a/Gems/LmbrCentral/Code/Source/Builders/TranslationBuilder/TranslationBuilderComponent.cpp b/Gems/LmbrCentral/Code/Source/Builders/TranslationBuilder/TranslationBuilderComponent.cpp index f0db13f41b..0fa01d737d 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/TranslationBuilder/TranslationBuilderComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/TranslationBuilder/TranslationBuilderComponent.cpp @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include namespace TranslationBuilder { @@ -124,7 +124,7 @@ namespace TranslationBuilder } else { - AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; AZStd::string command( AZStd::string::format("\"%s\" \"%s\" -qm \"%s\"", lRelease.c_str(), request.m_fullPath.c_str(), destPath.c_str()) ); AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Issuing command:%s", command.c_str()); @@ -132,9 +132,9 @@ namespace TranslationBuilder processLaunchInfo.m_commandlineParameters = command; processLaunchInfo.m_showWindow = false; processLaunchInfo.m_workingDirectory = request.m_tempDirPath; - processLaunchInfo.m_processPriority = AzToolsFramework::PROCESSPRIORITY_IDLE; + processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_IDLE; - AzToolsFramework::ProcessWatcher* watcher = AzToolsFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzToolsFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT); + AzFramework::ProcessWatcher* watcher = AzFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT); if (!watcher) { @@ -147,10 +147,10 @@ namespace TranslationBuilder if (result) { // grab output and append to logs, will help with any debugging down the road. - AzToolsFramework::ProcessCommunicator* processCommunicator = watcher->GetCommunicator(); + AzFramework::ProcessCommunicator* processCommunicator = watcher->GetCommunicator(); if ( processCommunicator && processCommunicator->IsValid() ) { - AzToolsFramework::ProcessOutput rawOutput; + AzFramework::ProcessOutput rawOutput; processCommunicator->ReadIntoProcessOutput(rawOutput); // note that the rawOutput may contain a formating code, such as "%s" within the text, diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index a02935f1a8..80e87e081f 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -580,26 +580,6 @@ namespace LmbrCentral REGISTER_INT(s_meshAssetHandler_AsyncCvar, 1, 0, "Enables asynchronous loading of legacy mesh formats"); - // Update the application's asset root. - // Requires @assets@ alias which is set during CrySystem initialization. - AZStd::string assetRoot; - EBUS_EVENT_RESULT(assetRoot, AzFramework::ApplicationRequests::Bus, GetAssetRoot); - - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO) - { - const char* aliasPath = fileIO->GetAlias("@assets@"); - if (aliasPath && aliasPath[0] != '\0') - { - assetRoot = aliasPath; - } - } - - if (!assetRoot.empty()) - { - EBUS_EVENT(AzFramework::ApplicationRequests::Bus, SetAssetRoot, assetRoot.c_str()); - } - // Enable catalog now that application's asset root is set. if (system.GetGlobalEnvironment()->IsEditor()) { diff --git a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp index 4c2bbec95a..f082ef74f9 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -69,7 +70,7 @@ protected: const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - AZ::IO::Path assetRoot(engineRoot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); @@ -513,8 +514,11 @@ TEST_F(CopyDependencyBuilderTest, TestXmlAsset_InvalidSourceFilePath_NoProductDe AZStd::string fileName = "Xmls/InvalidFilePathExample.xml"; XmlBuilderWorker builderWorker; builderWorker.AddSchemaFileDirectory(GetFullPath("Xmls/Schema/WithoutVersionConstraints/FullFeatured")); + + AZStd::vector expectedPaths; + AZStd::vector expectedProductDependencies; AZ_TEST_START_TRACE_SUPPRESSION; - TestFailureCase(&builderWorker, fileName); + TestSuccessCase(&builderWorker, fileName, expectedPaths, expectedProductDependencies); // One error occurs: Cannot open the source file AZ_TEST_STOP_TRACE_SUPPRESSION(1 * SuppressedErrorMultiplier); } diff --git a/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp index 29f26c5acc..a0ce24d34f 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp @@ -14,14 +14,15 @@ #include #include #include +#include +#include #include #include +#include #include #include #include #include -#include "AzCore/Slice/SliceAssetHandler.h" -#include using namespace LevelBuilder; using namespace AZ; @@ -107,7 +108,7 @@ protected: const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - AZ::IO::Path assetRoot(engineRoot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); diff --git a/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp index b8c98e4c87..05d292c9e6 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ namespace UnitTest const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - AZ::IO::Path assetRoot(engineRoot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); diff --git a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp index 4080f56c89..8aae0c4790 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace MaterialBuilder; using namespace AZ; @@ -45,7 +46,7 @@ protected: const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - AZ::IO::Path assetRoot(engineRoot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetRoot.c_str()); diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 22c843ccb2..6fc2ff8eeb 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -309,8 +309,9 @@ public: SerializeContext* GetSerializeContext() override { return m_serializeContext; } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/LocalUser/Code/CMakeLists.txt b/Gems/LocalUser/Code/CMakeLists.txt index 712acff510..6198d88e15 100644 --- a/Gems/LocalUser/Code/CMakeLists.txt +++ b/Gems/LocalUser/Code/CMakeLists.txt @@ -31,7 +31,6 @@ ly_add_target( ly_add_target( NAME LocalUser ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.LocalUser.93ccb44a96b142f7942a3fb6b9ca36e1.v0.1.0 FILES_CMAKE localuser_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index ff189a25d8..81abb0c08f 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -34,7 +34,6 @@ ly_add_target( ly_add_target( NAME LyShine ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.LyShine.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0 FILES_CMAKE lyshine_common_module_files.cmake INCLUDE_DIRECTORIES @@ -48,6 +47,9 @@ ly_add_target( Legacy::CryCommon Gem::LmbrCentral Gem::TextureAtlas + RUNTIME_DEPENDENCIES + Gem::LmbrCentral + Gem::TextureAtlas ) if (PAL_TRAIT_BUILD_HOST_TOOLS) @@ -85,9 +87,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME LyShine.Editor MODULE + NAME LyShine.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.LyShine.Editor.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0 FILES_CMAKE lyshine_common_module_files.cmake COMPILE_DEFINITIONS @@ -107,6 +109,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::LyShine.Editor.Static Gem::LmbrCentral Gem::TextureAtlas + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor + Gem::TextureAtlas ) endif() diff --git a/Gems/LyShine/Code/Editor/FileHelpers.cpp b/Gems/LyShine/Code/Editor/FileHelpers.cpp index 36b988ba0f..0e06050d5a 100644 --- a/Gems/LyShine/Code/Editor/FileHelpers.cpp +++ b/Gems/LyShine/Code/Editor/FileHelpers.cpp @@ -11,6 +11,9 @@ */ #include "UiCanvasEditor_precompiled.h" +#include +#include + #include "EditorCommon.h" #include @@ -18,35 +21,6 @@ #include #include -namespace -{ - QString GetEngineRootDir() - { - static bool hasBeenInit = false; - static QString fullDir; - if (!hasBeenInit) - { - hasBeenInit = true; - - QDir appPath(qApp->applicationDirPath()); - while (!appPath.isRoot()) - { - if (QFile::exists(appPath.filePath("engineroot.txt"))) - { - fullDir = appPath.absolutePath(); - break; - } - - if (!appPath.cdUp()) - { - break; - } - } - } - return fullDir; - } -} // anonymous namespace. - namespace FileHelpers { QString GetAbsoluteDir(const char* subDir) @@ -65,14 +39,13 @@ namespace FileHelpers QString GetRelativePathFromEngineRoot(const QString& fullPath) { - QString rootPath = GetEngineRootDir() + "/"; - - QString result = fullPath; - if (result.startsWith(rootPath, Qt::CaseInsensitive)) + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - result = result.remove(0, rootPath.length()); + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - return result; + + return AZ::IO::PathView(fullPath.toUtf8().constData()).LexicallyProximate(engineRootPath).c_str(); } void AppendExtensionIfNotPresent(QString& filename, diff --git a/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp b/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp index bfb4a7945a..9e57ac26fd 100644 --- a/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp +++ b/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp @@ -15,8 +15,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -97,7 +98,7 @@ protected: AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - AZ::IO::Path assetRoot(engineRoot); + AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index 4076b6c19d..ccf49ba467 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( ly_add_target( NAME LyShineExamples ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.LyShineExamples.c7935ecf5e8047fe8ca947b34b11cadb.v0.1.0 FILES_CMAKE lyshineexamples_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Maestro/Code/CMakeLists.txt b/Gems/Maestro/Code/CMakeLists.txt index f9558cc5d5..afe01e822e 100644 --- a/Gems/Maestro/Code/CMakeLists.txt +++ b/Gems/Maestro/Code/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( ly_add_target( NAME Maestro ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Maestro.3b9a978ed6f742a1acb99f74379a342c.v0.1.0 FILES_CMAKE maestro_files.cmake INCLUDE_DIRECTORIES @@ -42,13 +41,15 @@ ly_add_target( Legacy::CryCommon Gem::Maestro.Static Gem::LmbrCentral + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Maestro.Editor MODULE + NAME Maestro.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Maestro.Editor.3b9a978ed6f742a1acb99f74379a342c.v0.1.0 FILES_CMAKE maestro_files.cmake maestro_editor_files.cmake @@ -70,6 +71,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AssetBuilderSDK Gem::Maestro.Static Gem::LmbrCentral + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/MessagePopup/Code/CMakeLists.txt b/Gems/MessagePopup/Code/CMakeLists.txt index b797299029..2d0ad1ebcc 100644 --- a/Gems/MessagePopup/Code/CMakeLists.txt +++ b/Gems/MessagePopup/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME MessagePopup ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.MessagePopup.89225422672547deaca9e7a22b883973.v0.1.0 FILES_CMAKE messagepopup_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Metastream/Code/CMakeLists.txt b/Gems/Metastream/Code/CMakeLists.txt index 6d91cf62ed..6d2983c91d 100644 --- a/Gems/Metastream/Code/CMakeLists.txt +++ b/Gems/Metastream/Code/CMakeLists.txt @@ -32,7 +32,6 @@ ly_add_target( ly_add_target( NAME Metastream ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Metastream.c02d7efe05134983b5699d9ee7594c3a.v1.0.0 FILES_CMAKE metastream_shared_files.cmake ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake diff --git a/Gems/Microphone/Code/CMakeLists.txt b/Gems/Microphone/Code/CMakeLists.txt index 50419b82b1..942899735c 100644 --- a/Gems/Microphone/Code/CMakeLists.txt +++ b/Gems/Microphone/Code/CMakeLists.txt @@ -38,10 +38,11 @@ ly_add_target( ly_add_target( NAME Microphone ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Microphone.e70dd59f02f14ea49e6b38434e86ebf1.v0.1.0 FILES_CMAKE microphone_shared_files.cmake BUILD_DEPENDENCIES PRIVATE Gem::Microphone.Static + RUNTIME_DEPENDENCIES + Gem::AudioSystem ) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index ec88bd77b9..af9aef2591 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -41,7 +41,6 @@ ly_add_target( ly_add_target( NAME Multiplayer ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Multiplayer.9524EBD3E64D4D13A9764A18DB9A564F.v1.0.0 FILES_CMAKE multiplayer_shared_files.cmake INCLUDE_DIRECTORIES @@ -53,6 +52,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::Multiplayer.Static + RUNTIME_DEPENDENCIES + Gem::CertificateManager ) ################################################################################ diff --git a/Gems/MultiplayerCompression/Code/CMakeLists.txt b/Gems/MultiplayerCompression/Code/CMakeLists.txt index 21f3744c8a..96761c3b1e 100644 --- a/Gems/MultiplayerCompression/Code/CMakeLists.txt +++ b/Gems/MultiplayerCompression/Code/CMakeLists.txt @@ -31,7 +31,6 @@ ly_add_target( ly_add_target( NAME MultiplayerCompression ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.MultiplayerCompression.1d353c8ca3c74ed193fd6c6783ae41cc.v0.1.0 FILES_CMAKE multiplayercompression_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/NvCloth/Code/CMakeLists.txt b/Gems/NvCloth/Code/CMakeLists.txt index 4ffedeef47..98cbebee68 100644 --- a/Gems/NvCloth/Code/CMakeLists.txt +++ b/Gems/NvCloth/Code/CMakeLists.txt @@ -39,7 +39,6 @@ ly_add_target( ly_add_target( NAME NvCloth ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.NvCloth.6ab53783d9f54c9e97a15ad729e7c182.v0.1.0 FILES_CMAKE nvcloth_shared_files.cmake INCLUDE_DIRECTORIES @@ -53,6 +52,8 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::NvCloth.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -80,9 +81,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME NvCloth.Editor MODULE + NAME NvCloth.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.NvCloth.Editor.6ab53783d9f54c9e97a15ad729e7c182.v0.1.0 FILES_CMAKE nvcloth_editor_shared_files.cmake INCLUDE_DIRECTORIES @@ -96,6 +97,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PRIVATE Legacy::CryCommon Gem::NvCloth.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/NvCloth/Code/Tests/NvClothEditorTestEnvironment.cpp b/Gems/NvCloth/Code/Tests/NvClothEditorTestEnvironment.cpp index 52a8106c32..0a875ee7dd 100644 --- a/Gems/NvCloth/Code/Tests/NvClothEditorTestEnvironment.cpp +++ b/Gems/NvCloth/Code/Tests/NvClothEditorTestEnvironment.cpp @@ -51,8 +51,8 @@ namespace UnitTest void NvClothEditorTestEnvironment::AddGemsAndComponents() { AddDynamicModulePaths({ - "Gem.LmbrCentral.Editor.ff06785f7145416b9d46fde39098cb0c.v0.1.0", - "Gem.EMotionFX.Editor.044a63ea67d04479aa5daf62ded9d9ca.v0.1.0" + "LmbrCentral.Editor", + "EMotionFX.Editor" }); AddComponentDescriptors({ diff --git a/Gems/NvCloth/Code/Tests/NvClothTestEnvironment.cpp b/Gems/NvCloth/Code/Tests/NvClothTestEnvironment.cpp index 616e8c2da0..375d7760cb 100644 --- a/Gems/NvCloth/Code/Tests/NvClothTestEnvironment.cpp +++ b/Gems/NvCloth/Code/Tests/NvClothTestEnvironment.cpp @@ -45,8 +45,8 @@ namespace UnitTest void NvClothTestEnvironment::AddGemsAndComponents() { AddDynamicModulePaths({ - "Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0", - "Gem.EMotionFX.044a63ea67d04479aa5daf62ded9d9ca.v0.1.0" + "LmbrCentral", + "EMotionFX" }); AddComponentDescriptors({ diff --git a/Gems/NvCloth/Code/nvcloth_stub.cmake b/Gems/NvCloth/Code/nvcloth_stub.cmake index 19ea0ed924..70925afe4f 100644 --- a/Gems/NvCloth/Code/nvcloth_stub.cmake +++ b/Gems/NvCloth/Code/nvcloth_stub.cmake @@ -25,7 +25,8 @@ add_library(Gem::NvCloth ALIAS NvCloth.Stub) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME NvCloth.Editor.Stub MODULE + NAME NvCloth.Editor.Stub GEM_MODULE + NAMESPACE Gem FILES_CMAKE nvcloth_stub_files.cmake diff --git a/Gems/PhysX/AssetProcessorGemConfig.ini b/Gems/PhysX/AssetProcessorGemConfig.ini deleted file mode 100644 index 3383c14fda..0000000000 --- a/Gems/PhysX/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,9 +0,0 @@ -[RC physxconfiguration] -pattern=(.*\.physicsconfiguration|.*\.physxconfiguration) -params=copy - -; Copy over cooked PhysX heightfield -[RC PhysX HeightField] -glob=*.pxheightfield -params=copy -productAssetType={B61189FE-B2D7-4AF1-8951-CB5C0F7834FC} diff --git a/Gems/PhysX/AssetProcessorGemConfig.setreg b/Gems/PhysX/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..993a99616b --- /dev/null +++ b/Gems/PhysX/AssetProcessorGemConfig.setreg @@ -0,0 +1,17 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "RC physxconfiguration": { + "pattern": "(.*\\.physicsconfiguration|.*\\.physxconfiguration)", + "params": "copy" + }, + "RC PhysX HeightField": { + "glob": "*.pxheightfield", + "params": "copy", + "productAssetType": "{B61189FE-B2D7-4AF1-8951-CB5C0F7834FC}" + } + } + } + } +} diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index 8083778a57..2befecf7da 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -52,7 +52,6 @@ ly_add_target( ly_add_target( NAME PhysX ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.PhysX.4e08125824434932a0fe3717259caa47.v0.1.0 FILES_CMAKE ${physx_shared_files} COMPILE_DEFINITIONS @@ -66,6 +65,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::PhysX.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -116,10 +117,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME PhysX.Editor MODULE + NAME PhysX.Editor GEM_MODULE + NAMESPACE Gem AUTOMOC - OUTPUT_NAME Gem.PhysX.Editor.4e08125824434932a0fe3717259caa47.v0.1.0 FILES_CMAKE physx_editor_shared_files.cmake INCLUDE_DIRECTORIES @@ -132,6 +133,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::PhysX.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/PhysX/Code/Tests/PhysXEditorTest.cpp b/Gems/PhysX/Code/Tests/PhysXEditorTest.cpp index f577a9fb13..8467de798e 100644 --- a/Gems/PhysX/Code/Tests/PhysXEditorTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXEditorTest.cpp @@ -35,7 +35,7 @@ namespace Physics /// Allows derived environments to override to set up which gems, components etc the environment should load. void AddGemsAndComponents() override { - AddDynamicModulePaths({ "Gem.LmbrCentral.Editor.ff06785f7145416b9d46fde39098cb0c.v0.1.0" }); + AddDynamicModulePaths({ "LmbrCentral.Editor" }); const auto& physxDescriptors = PhysX::GetDescriptors(); const auto& physxEditorDescriptors = PhysX::GetEditorDescriptors(); diff --git a/Gems/PhysX/Code/Tests/PhysXTestEnvironment.cpp b/Gems/PhysX/Code/Tests/PhysXTestEnvironment.cpp index 283ed42be4..bb7fac4fd0 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestEnvironment.cpp +++ b/Gems/PhysX/Code/Tests/PhysXTestEnvironment.cpp @@ -101,7 +101,7 @@ namespace PhysX // Set up gems other than PhysX for loading AZ::DynamicModuleDescriptor dynamicModuleDescriptor; - dynamicModuleDescriptor.m_dynamicLibraryPath = "Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0"; + dynamicModuleDescriptor.m_dynamicLibraryPath = "LmbrCentral"; appDesc.m_modules.push_back(dynamicModuleDescriptor); // Create system entity diff --git a/Gems/PhysXDebug/Code/CMakeLists.txt b/Gems/PhysXDebug/Code/CMakeLists.txt index 6880157ceb..a3730e5bcf 100644 --- a/Gems/PhysXDebug/Code/CMakeLists.txt +++ b/Gems/PhysXDebug/Code/CMakeLists.txt @@ -25,7 +25,6 @@ endif() ly_add_target( NAME PhysXDebug ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.PhysXDebug.516145e2d9904b13813f1b54605e26a6.v0.1.0 FILES_CMAKE ${physx_files} INCLUDE_DIRECTORIES @@ -40,13 +39,16 @@ ly_add_target( Gem::PhysX Gem::ImGui.imguilib Gem::ImGui + RUNTIME_DEPENDENCIES + Gem::PhysX + Gem::ImGui ) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME PhysXDebug.Editor MODULE + NAME PhysXDebug.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.PhysXDebug.Editor.516145e2d9904b13813f1b54605e26a6.v0.1.0 FILES_CMAKE ${physx_editor_files} COMPILE_DEFINITIONS @@ -66,5 +68,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::PhysX Gem::ImGui.imguilib Gem::ImGui + RUNTIME_DEPENDENCIES + Gem::PhysX.Editor + Gem::ImGui.Editor ) endif() diff --git a/Gems/Prefab/PrefabBuilder/CMakeLists.txt b/Gems/Prefab/PrefabBuilder/CMakeLists.txt index 2b7ce76ca3..d2304612ef 100644 --- a/Gems/Prefab/PrefabBuilder/CMakeLists.txt +++ b/Gems/Prefab/PrefabBuilder/CMakeLists.txt @@ -16,7 +16,6 @@ endif() ly_add_target( NAME Prefab.PrefabBuilder MODULE NAMESPACE Gem - OUTPUT_NAME Gem.Prefab.PrefabBuilder FILES_CMAKE prefabbuilder_files.cmake BUILD_DEPENDENCIES @@ -31,6 +30,6 @@ ly_add_target_dependencies( AssetBuilder AssetProcessor AssetProcessorBatch - DEPENDENCIES_FILES - prefabbuilder_dependencies.cmake + DEPENDENT_TARGETS + Gem::Prefab.PrefabBuilder ) diff --git a/Gems/Prefab/PrefabBuilder/prefabbuilder_dependencies.cmake b/Gems/Prefab/PrefabBuilder/prefabbuilder_dependencies.cmake deleted file mode 100644 index 292e02b6cf..0000000000 --- a/Gems/Prefab/PrefabBuilder/prefabbuilder_dependencies.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -# 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. -# - -set(GEM_DEPENDENCIES Gem::Prefab.PrefabBuilder) diff --git a/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake b/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake index 114708769d..84200cd2e6 100644 --- a/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake +++ b/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake @@ -10,6 +10,5 @@ # set(FILES - prefabbuilder_dependencies.cmake PrefabBuilderModule.cpp ) diff --git a/Gems/Presence/Code/CMakeLists.txt b/Gems/Presence/Code/CMakeLists.txt index 2484663253..07780fc8eb 100644 --- a/Gems/Presence/Code/CMakeLists.txt +++ b/Gems/Presence/Code/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( ly_add_target( NAME Presence ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Presence.903ce283760647049efaef70d9368eeb.v0.1.0 PLATFORM_INCLUDE_FILES ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake FILES_CMAKE diff --git a/Gems/PythonAssetBuilder/Code/CMakeLists.txt b/Gems/PythonAssetBuilder/Code/CMakeLists.txt index 95cc58d8a1..60af675bc6 100644 --- a/Gems/PythonAssetBuilder/Code/CMakeLists.txt +++ b/Gems/PythonAssetBuilder/Code/CMakeLists.txt @@ -48,9 +48,9 @@ ly_add_target( ) ly_add_target( - NAME PythonAssetBuilder.Editor MODULE + NAME PythonAssetBuilder.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.PythonAssetBuilder.Editor.0a5fda05323649009444bb7c3ee2b9c4.v0.1.0 FILES_CMAKE ${editor_files} ${shared_files} @@ -65,6 +65,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE ${editor_dependencies} + RUNTIME_DEPENDENCIES + Gem::EditorPythonBindings.Editor ) ################################################################################ diff --git a/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderSystemComponent.cpp b/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderSystemComponent.cpp index 945729386e..b1e02077d0 100644 --- a/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderSystemComponent.cpp +++ b/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderSystemComponent.cpp @@ -14,9 +14,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -198,16 +200,15 @@ namespace PythonAssetBuilder } // transaction->Commit() requires the "@user@" alias - if (AZ::IO::FileIOBase::GetInstance()->GetAlias("@user@") == nullptr) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + auto ioBase = AZ::IO::FileIOBase::GetInstance(); + if (ioBase->GetAlias("@user@") == nullptr) { - AZStd::string assetRoot; - AzFramework::ApplicationRequests::Bus::BroadcastResult( - assetRoot, - &AzFramework::ApplicationRequests::Bus::Events::GetAssetRoot); - - AZStd::string userPath; - AZ::StringFunc::Path::Join(assetRoot.c_str(), "AssetProcessorTemp", userPath); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@user@", userPath.c_str()); + if (AZ::IO::Path userPath; settingsRegistry->Get(userPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) + { + userPath /= "AssetProcessorTemp"; + ioBase->SetAlias("@user@", userPath.c_str()); + } } // transaction->Commit() expects the file to exist and write-able diff --git a/Gems/QtForPython/Code/CMakeLists.txt b/Gems/QtForPython/Code/CMakeLists.txt index cb3f866bda..413e542c9f 100644 --- a/Gems/QtForPython/Code/CMakeLists.txt +++ b/Gems/QtForPython/Code/CMakeLists.txt @@ -45,10 +45,11 @@ ly_add_target( ly_add_target( NAME QtForPython.Editor MODULE NAMESPACE Gem - OUTPUT_NAME Gem.QtForPython.Editor.cd50c7a1e31f4c9495dcffdacc3bde92.v0.1.0 FILES_CMAKE qtforpython_shared_files.cmake BUILD_DEPENDENCIES PRIVATE Gem::QtForPython.Editor.Static + RUNTIME_DEPENDENCIES + Gem::EditorPythonBindings.Editor ) diff --git a/Gems/RADTelemetry/Code/CMakeLists.txt b/Gems/RADTelemetry/Code/CMakeLists.txt index a493fa9aab..78a5561b7c 100644 --- a/Gems/RADTelemetry/Code/CMakeLists.txt +++ b/Gems/RADTelemetry/Code/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( ly_add_target( NAME RADTelemetry ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.RADTelemetry.bdaf32823406492686e35200afc555b3.v0.1.0 FILES_CMAKE radtelemetry_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/RenderToTexture/Code/CMakeLists.txt b/Gems/RenderToTexture/Code/CMakeLists.txt index 4ac2f4b537..0c662f1bb6 100644 --- a/Gems/RenderToTexture/Code/CMakeLists.txt +++ b/Gems/RenderToTexture/Code/CMakeLists.txt @@ -41,7 +41,6 @@ ly_add_target( ly_add_target( NAME RenderToTexture ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.RenderToTexture.b895c3bc4f894c1ebb9562a3577248f9.v0.1.0 FILES_CMAKE rendertotexture_shared_files.cmake PLATFORM_INCLUDE_FILES @@ -54,6 +53,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::RenderToTexture.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -83,9 +84,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME RenderToTexture.Editor MODULE + NAME RenderToTexture.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.RenderToTexture.Editor.b895c3bc4f894c1ebb9562a3577248f9.v0.1.0 FILES_CMAKE rendertotexture_shared_files.cmake PLATFORM_INCLUDE_FILES @@ -98,6 +99,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::RenderToTexture.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/RenderToTexture/Code/Source/EditorRenderToTextureComponent.cpp b/Gems/RenderToTexture/Code/Source/EditorRenderToTextureComponent.cpp index 9e4e335103..5e921c4d84 100644 --- a/Gems/RenderToTexture/Code/Source/EditorRenderToTextureComponent.cpp +++ b/Gems/RenderToTexture/Code/Source/EditorRenderToTextureComponent.cpp @@ -230,7 +230,7 @@ namespace RenderToTexture return AZ::TICK_LAST; } - void EditorRenderToTextureComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time) + void EditorRenderToTextureComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { // we can do this in the editor because it is single threaded Render(m_renderTargetHandle, m_config, GetEntityId()); diff --git a/Gems/RenderToTexture/Code/Source/RenderToTextureComponent.cpp b/Gems/RenderToTexture/Code/Source/RenderToTextureComponent.cpp index e246df8da9..d4ffd7ee49 100644 --- a/Gems/RenderToTexture/Code/Source/RenderToTextureComponent.cpp +++ b/Gems/RenderToTexture/Code/Source/RenderToTextureComponent.cpp @@ -190,7 +190,7 @@ namespace RenderToTexture return AZ::TICK_LAST; } - void RenderToTextureComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time) + void RenderToTextureComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { // push the changes from the component's RenderContextConfig to our RenderContext // do this here before we render so we avoid threading issues. diff --git a/Gems/SVOGI/Code/CMakeLists.txt b/Gems/SVOGI/Code/CMakeLists.txt index 519e5db70d..c4ffb92003 100644 --- a/Gems/SVOGI/Code/CMakeLists.txt +++ b/Gems/SVOGI/Code/CMakeLists.txt @@ -32,7 +32,6 @@ ly_add_target( ly_add_target( NAME SVOGI ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.SVOGI.09a70eb8876e49a8a919cabbb8f33b27.v0.1.0 FILES_CMAKE svogi_shared_files.cmake INCLUDE_DIRECTORIES @@ -44,4 +43,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::SVOGI.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) diff --git a/Gems/SaveData/Code/CMakeLists.txt b/Gems/SaveData/Code/CMakeLists.txt index d5fa94053c..46c6e91f58 100644 --- a/Gems/SaveData/Code/CMakeLists.txt +++ b/Gems/SaveData/Code/CMakeLists.txt @@ -34,7 +34,6 @@ ly_add_target( ly_add_target( NAME SaveData ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.SaveData.d96ab03f53d14c9e83f9b4528c8576d7.v0.1.0 FILES_CMAKE savedata_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/SceneLoggingExample/Code/CMakeLists.txt b/Gems/SceneLoggingExample/Code/CMakeLists.txt index 5b8bde40b8..56e0fdaa6a 100644 --- a/Gems/SceneLoggingExample/Code/CMakeLists.txt +++ b/Gems/SceneLoggingExample/Code/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( ly_add_target( NAME SceneLoggingExample ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.SceneLoggingExample.35d8f6e49ae04c9382c61a42d4355c2f.v0.1.0 FILES_CMAKE sceneloggingexample_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/SceneProcessing/Code/CMakeLists.txt b/Gems/SceneProcessing/Code/CMakeLists.txt index 79342b1fd6..9c514adbe4 100644 --- a/Gems/SceneProcessing/Code/CMakeLists.txt +++ b/Gems/SceneProcessing/Code/CMakeLists.txt @@ -12,7 +12,6 @@ ly_add_target( NAME SceneProcessing ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.SceneProcessing.7c2578f634df4345aca98d671e39b8ab.v0.1.0 FILES_CMAKE sceneprocessing_files.cmake INCLUDE_DIRECTORIES @@ -50,9 +49,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME SceneProcessing.Editor MODULE + NAME SceneProcessing.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.SceneProcessing.Editor.7c2578f634df4345aca98d671e39b8ab.v0.1.0 FILES_CMAKE sceneprocessing_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index 133d2c901d..680d9ffdf0 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -145,26 +145,25 @@ namespace ScriptCanvasBuilder } } - { - AssetBuilderSDK::JobDescriptor copyDescriptor; - copyDescriptor.m_priority = 2; - copyDescriptor.m_critical = true; - copyDescriptor.m_jobKey = s_scriptCanvasCopyJobKey; - copyDescriptor.SetPlatformIdentifier("pc"); - copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()) - .append(AZStd::string::format("|%zu", fingerprint)); - response.m_createJobOutputs.push_back(copyDescriptor); - } - for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) { + if (info.HasTag("tools")) + { + AssetBuilderSDK::JobDescriptor copyDescriptor; + copyDescriptor.m_priority = 2; + copyDescriptor.m_critical = true; + copyDescriptor.m_jobKey = s_scriptCanvasCopyJobKey; + copyDescriptor.SetPlatformIdentifier(info.m_identifier.c_str()); + copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast(fingerprint))); + response.m_createJobOutputs.push_back(copyDescriptor); + } + AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = 2; jobDescriptor.m_critical = true; jobDescriptor.m_jobKey = s_scriptCanvasProcessJobKey; jobDescriptor.SetPlatformIdentifier(info.m_identifier.c_str()); - jobDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()) - .append(AZStd::string::format("|%zu", fingerprint)); + jobDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast(fingerprint))); // Graph process job needs to wait until its dependency asset job finished for (const auto& sourceDependency : sourceFileDependencies) { diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasFunctionBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasFunctionBuilderWorker.cpp index a85bdf99ac..cd9a3384cd 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasFunctionBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasFunctionBuilderWorker.cpp @@ -124,20 +124,19 @@ namespace ScriptCanvasBuilder AZStd::hash_combine(fingerprint, nodeComponent->GenerateFingerprint()); } } - - { - AssetBuilderSDK::JobDescriptor copyDescriptor; - copyDescriptor.m_priority = 2; - copyDescriptor.m_critical = true; - copyDescriptor.m_jobKey = s_scriptCanvasCopyJobKey; - copyDescriptor.SetPlatformIdentifier("pc"); - copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()) - .append(AZStd::string::format("|%zu", fingerprint)); - response.m_createJobOutputs.push_back(copyDescriptor); - } - for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) { + if (info.HasTag("tools")) + { + AssetBuilderSDK::JobDescriptor copyDescriptor; + copyDescriptor.m_priority = 2; + copyDescriptor.m_critical = true; + copyDescriptor.m_jobKey = s_scriptCanvasCopyJobKey; + copyDescriptor.SetPlatformIdentifier(info.m_identifier.c_str()); + copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast(fingerprint))); + response.m_createJobOutputs.push_back(copyDescriptor); + } + AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = 2; jobDescriptor.m_critical = true; diff --git a/Gems/ScriptCanvas/Code/CMakeLists.txt b/Gems/ScriptCanvas/Code/CMakeLists.txt index 68c3a5eb20..6243c04b9d 100644 --- a/Gems/ScriptCanvas/Code/CMakeLists.txt +++ b/Gems/ScriptCanvas/Code/CMakeLists.txt @@ -86,7 +86,6 @@ ly_add_target( ly_add_target( NAME ScriptCanvas ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ScriptCanvasGem.869a0d0ec11a45c299917d45c81555e6.v0.1.0 FILES_CMAKE scriptcanvasgem_game_files.cmake INCLUDE_DIRECTORIES @@ -105,7 +104,9 @@ ly_add_target( AZ::AzCore AZ::AzFramework Gem::ScriptEvents.Static - + RUNTIME_DEPENDENCIES + Gem::ScriptEvents + Gem::ExpressionEvaluation ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -172,9 +173,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME ScriptCanvas.Editor MODULE + NAME ScriptCanvas.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.ScriptCanvasGem.Editor.869a0d0ec11a45c299917d45c81555e6.v0.1.0 FILES_CMAKE scriptcanvasgem_editor_shared_files.cmake COMPILE_DEFINITIONS @@ -199,6 +200,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) 3rdParty::Qt::Widgets Legacy::EditorCore AZ::AzQtComponents + Gem::GraphCanvas.Editor + Gem::ScriptEvents.Editor + Gem::ExpressionEvaluation ) endif() diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 06879640db..0ce74325f2 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -580,7 +580,7 @@ namespace ScriptCanvasEditor AZStd::string tempFilename; AzFramework::StringFunc::Path::GetFullFileName(targetFilename.data(), tempFilename); - AZStd::string tempPath = AZStd::string::format("@cache@/scriptcanvas/%s.temp", tempFilename.data()); + AZStd::string tempPath = AZStd::string::format("@usercache@/scriptcanvas/%s.temp", tempFilename.data()); AZStd::array resolvedPath{}; AZ::IO::FileIOBase::GetInstance()->ResolvePath(tempPath.data(), resolvedPath.data(), resolvedPath.size()); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp index 9729770e75..5c02f7a3b4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationUtilities.cpp @@ -27,8 +27,7 @@ namespace TranslationUtilitiesCPP using namespace ScriptCanvas::Translation; const char* k_namespaceNameNative = "AutoNative"; - const char* k_fileDirectoryPathNative = "@engroot@/Gems/ScriptCanvas/Include/ScriptCanvas/AutoNative"; - const char* k_fileDirectoryPathLua = "@engroot@/DebugScriptCanvas2LuaOutput/"; + const char* k_fileDirectoryPathLua = "@usercache@/DebugScriptCanvas2LuaOutput/"; const char* k_space = " "; const size_t k_maxTabs = 20; @@ -113,18 +112,6 @@ namespace TranslationUtilitiesCPP return AZ::Failure(AZStd::string("FileIOBase unavailable")); } - if (!fileIO->GetAlias("@engroot@")) - { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - - if (engineRoot == nullptr) - { - return AZ::Failure(AZStd::string("no engine root")); - } - - fileIO->SetAlias("@engroot@", engineRoot); - } // \todo get a (debug) file path based on the extension const AZStd::string filePath = TranslationUtilitiesCPP::GetDebugLuaFilePath(source, extension); diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index 2fc8d3b490..0dc03f6651 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -87,8 +87,9 @@ protected: AZ::SerializeContext* GetSerializeContext() override { return m_serializeContext; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetExecutableFolder() const override { return nullptr; } const char* GetAppRoot() const override { return nullptr; } + const char* GetEngineRoot() const override { return nullptr; } + const char* GetExecutableFolder() const override { return nullptr; } AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; } void EnumerateEntities(const AZ::ComponentApplicationRequests::EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt index 840abedd03..d9ce9004d3 100644 --- a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt @@ -37,7 +37,6 @@ ly_add_target( ly_add_target( NAME ScriptCanvasDeveloper ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ScriptCanvasDeveloperGem.f905c05883b94fd6bddc91052c3c5a86.v0.1.0 FILES_CMAKE scriptcanvasdeveloper_gem_game_files.cmake INCLUDE_DIRECTORIES @@ -51,14 +50,15 @@ ly_add_target( PRIVATE AZ::AzCore Gem::ScriptCanvasDeveloper.Static + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas ) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME ScriptCanvasDeveloper.Editor MODULE + NAME ScriptCanvasDeveloper.Editor GEM_MODULE NAMESPACE Gem AUTOMOC - OUTPUT_NAME Gem.ScriptCanvasDeveloperGem.Editor.f905c05883b94fd6bddc91052c3c5a86.v0.1.0 FILES_CMAKE scriptcanvasdeveloper_gem_editor_files.cmake INCLUDE_DIRECTORIES @@ -79,5 +79,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::ScriptCanvasDeveloper.Static Gem::ScriptCanvas.Editor.Static Gem::GraphCanvasWidgets + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas.Editor ) endif() diff --git a/Gems/ScriptCanvasDiagnosticLibrary/Code/CMakeLists.txt b/Gems/ScriptCanvasDiagnosticLibrary/Code/CMakeLists.txt index 851501cee6..9c2ca7282a 100644 --- a/Gems/ScriptCanvasDiagnosticLibrary/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasDiagnosticLibrary/Code/CMakeLists.txt @@ -34,7 +34,6 @@ ly_add_target( ly_add_target( NAME ScriptCanvasDiagnosticLibrary ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ScriptCanvasDiagnosticLibrary.d969b997bb7f4342ba0b3eedc378025d.v0.1.0 FILES_CMAKE scriptcanvasdiagnosticlibrary_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt index 9aca943f80..8d6668b816 100644 --- a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( ly_add_target( NAME ScriptCanvasPhysics ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ScriptCanvasPhysics.1c27519a4dda4ffaaeebf91514e5b1e8.v0.1.0 FILES_CMAKE scriptcanvas_physics_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index c054fd0c26..e8e34031c1 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -49,7 +49,8 @@ ly_add_target( ) ly_add_target( - NAME ScriptCanvasTesting.Editor MODULE + NAME ScriptCanvasTesting.Editor GEM_MODULE + NAMESPACE Gem FILES_CMAKE scriptcanvastestingeditor_shared_files.cmake @@ -69,6 +70,8 @@ ly_add_target( AZ::AzCore AZ::AzFramework AZ::AzToolsFramework + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas.Editor ) ################################################################################ diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h index 5b1e9f283c..a86361e900 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h @@ -74,9 +74,9 @@ namespace ScriptCanvasTests descriptor.m_useExistingAllocator = true; AZ::DynamicModuleDescriptor dynamicModuleDescriptor; - dynamicModuleDescriptor.m_dynamicLibraryPath = "Gem.GraphCanvas.Editor.875b6fcbdeea44deaae7984ad9bb6cdc.v0.1.0"; + dynamicModuleDescriptor.m_dynamicLibraryPath = "GraphCanvas.Editor"; descriptor.m_modules.push_back(dynamicModuleDescriptor); - dynamicModuleDescriptor.m_dynamicLibraryPath = "Gem.ScriptCanvasGem.Editor.869a0d0ec11a45c299917d45c81555e6.v0.1.0"; + dynamicModuleDescriptor.m_dynamicLibraryPath = "ScriptCanvas.Editor"; descriptor.m_modules.push_back(dynamicModuleDescriptor); dynamicModuleDescriptor.m_dynamicLibraryPath = "Gem.ExpressionEvaluation.4c6f9df57ca2468f93c8d860ee6a1167.v0.1.0"; descriptor.m_modules.push_back(dynamicModuleDescriptor); diff --git a/Gems/ScriptEvents/Code/CMakeLists.txt b/Gems/ScriptEvents/Code/CMakeLists.txt index f1c2f78e40..12f8cfd7b6 100644 --- a/Gems/ScriptEvents/Code/CMakeLists.txt +++ b/Gems/ScriptEvents/Code/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( ly_add_target( NAME ScriptEvents ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ScriptEvents.32d8ba21703e4bbbb08487366e48dd69.v0.1.0 FILES_CMAKE scriptevents_files.cmake INCLUDE_DIRECTORIES @@ -43,9 +42,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME ScriptEvents.Editor MODULE + NAME ScriptEvents.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.ScriptEvents.Editor.32d8ba21703e4bbbb08487366e48dd69.v0.1.0 FILES_CMAKE scriptevents_editor_files.cmake scriptevents_editor_builder_files.cmake diff --git a/Gems/ScriptedEntityTweener/Code/CMakeLists.txt b/Gems/ScriptedEntityTweener/Code/CMakeLists.txt index 1cc31ec920..c5062c84b7 100644 --- a/Gems/ScriptedEntityTweener/Code/CMakeLists.txt +++ b/Gems/ScriptedEntityTweener/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME ScriptedEntityTweener ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.ScriptedEntityTweener.0d1f5f05559c4a99aaefd30633a0158e.v0.1.0 FILES_CMAKE scriptedentitytweener_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/SliceFavorites/Code/CMakeLists.txt b/Gems/SliceFavorites/Code/CMakeLists.txt index e3a9f712f4..4ad89ad6c3 100644 --- a/Gems/SliceFavorites/Code/CMakeLists.txt +++ b/Gems/SliceFavorites/Code/CMakeLists.txt @@ -36,9 +36,9 @@ ly_add_target( ) ly_add_target( - NAME SliceFavorites.Editor MODULE + NAME SliceFavorites.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.SliceFavorites.Editor.1bfc7270d4a1490daac8aa8b072c4489.v0.1.0 FILES_CMAKE slicefavorites_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/SliceFavorites/Code/Source/FavoriteDataModel.cpp b/Gems/SliceFavorites/Code/Source/FavoriteDataModel.cpp index dcac6a9431..c02951e332 100644 --- a/Gems/SliceFavorites/Code/Source/FavoriteDataModel.cpp +++ b/Gems/SliceFavorites/Code/Source/FavoriteDataModel.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -762,18 +762,10 @@ namespace SliceFavorites QString FavoriteDataModel::GetProjectName() { - AZStd::string gameFolder; - auto settingsRegistry = AZ::SettingsRegistry::Get(); - auto gameFolderKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s", - AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, AzFramework::AssetSystem::ProjectName); - if (settingsRegistry) + AZ::SettingsRegistryInterface::FixedValueString projectName = AZ::Utils::GetProjectName(); + if (!projectName.empty()) { - settingsRegistry->Get(gameFolder, gameFolderKey); - } - - if (!gameFolder.empty()) - { - return gameFolder.c_str(); + return QString::fromUtf8(projectName.c_str(), aznumeric_cast(projectName.size())); } return "unknown"; diff --git a/Gems/StartingPointCamera/Code/CMakeLists.txt b/Gems/StartingPointCamera/Code/CMakeLists.txt index 8eb2377b9a..d6dd1a7038 100644 --- a/Gems/StartingPointCamera/Code/CMakeLists.txt +++ b/Gems/StartingPointCamera/Code/CMakeLists.txt @@ -30,7 +30,6 @@ ly_add_target( ly_add_target( NAME StartingPointCamera ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.StartingPointCamera.834070b9537d44df83559e2045c3859f.v0.1.0 FILES_CMAKE startingpointcamera_shared_files.cmake INCLUDE_DIRECTORIES @@ -46,4 +45,6 @@ ly_add_target( Gem::CameraFramework.Static Gem::LmbrCentral.Static Legacy::CryCommon + RUNTIME_DEPENDENCIES + Gem::CameraFramework ) diff --git a/Gems/StartingPointInput/Code/CMakeLists.txt b/Gems/StartingPointInput/Code/CMakeLists.txt index 08269a3f46..78a97e218f 100644 --- a/Gems/StartingPointInput/Code/CMakeLists.txt +++ b/Gems/StartingPointInput/Code/CMakeLists.txt @@ -37,7 +37,6 @@ ly_add_target( ly_add_target( NAME StartingPointInput ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.StartingPointInput.09f4bedeee614358bc36788e77f97e51.v0.1.0 FILES_CMAKE startingpointinput_shared_files.cmake INCLUDE_DIRECTORIES @@ -59,9 +58,9 @@ ly_add_source_properties( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME StartingPointInput.Editor MODULE + NAME StartingPointInput.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.StartingPointInput.Editor.09f4bedeee614358bc36788e77f97e51.v0.1.0 FILES_CMAKE startingpointinput_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/StartingPointMovement/Code/CMakeLists.txt b/Gems/StartingPointMovement/Code/CMakeLists.txt index 0a18f19e6f..d6434ccf78 100644 --- a/Gems/StartingPointMovement/Code/CMakeLists.txt +++ b/Gems/StartingPointMovement/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME StartingPointMovement ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.StartingPointMovement.73d8779dc28a4123b7c9ed76217464af.v0.1.0 FILES_CMAKE startingpointmovement_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/SurfaceData/Code/CMakeLists.txt b/Gems/SurfaceData/Code/CMakeLists.txt index 1f85da9d23..7988a9651c 100644 --- a/Gems/SurfaceData/Code/CMakeLists.txt +++ b/Gems/SurfaceData/Code/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( ly_add_target( NAME SurfaceData ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.SurfaceData.5de82d29d6094bfe97c1a4d35fcd5fbe.v0.1.0 FILES_CMAKE surfacedata_shared_files.cmake INCLUDE_DIRECTORIES @@ -41,14 +40,16 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::SurfaceData.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME SurfaceData.Editor MODULE + NAME SurfaceData.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.SurfaceData.Editor.5de82d29d6094bfe97c1a4d35fcd5fbe.v0.1.0 FILES_CMAKE surfacedata_editor_files.cmake COMPILE_DEFINITIONS @@ -64,6 +65,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon AZ::AzToolsFramework Gem::SurfaceData.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) endif() diff --git a/Gems/TestAssetBuilder/Code/CMakeLists.txt b/Gems/TestAssetBuilder/Code/CMakeLists.txt index 9a24cfffdc..1106ebf477 100644 --- a/Gems/TestAssetBuilder/Code/CMakeLists.txt +++ b/Gems/TestAssetBuilder/Code/CMakeLists.txt @@ -30,7 +30,8 @@ ly_add_target( ) ly_add_target( - NAME TestAssetBuilder.Editor MODULE + NAME TestAssetBuilder.Editor GEM_MODULE + NAMESPACE Gem FILES_CMAKE testassetbuilder_shared_files.cmake diff --git a/Gems/TestAssetBuilder/Code/Source/Builder/TestAssetBuilderComponent.cpp b/Gems/TestAssetBuilder/Code/Source/Builder/TestAssetBuilderComponent.cpp index 29c2ec4458..e4d1022352 100644 --- a/Gems/TestAssetBuilder/Code/Source/Builder/TestAssetBuilderComponent.cpp +++ b/Gems/TestAssetBuilder/Code/Source/Builder/TestAssetBuilderComponent.cpp @@ -514,7 +514,8 @@ namespace TestAssetBuilder } if (relativePath != fileName) { - AZ_Error("AssetBuilder", false, "GetRelativeProductPathFromFullSourceOrProductPath - relativePath and fileName didn't match for ( %s ).", sourcePath.c_str()); + AZ_Error("AssetBuilder", false, R"(GetRelativeProductPathFromFullSourceOrProductPath - relativePath "%s" and fileName "%s" didn't match for ( %s ).)", + relativePath.c_str(), fileName.c_str(), sourcePath.c_str()); return; } @@ -565,17 +566,20 @@ namespace TestAssetBuilder } if (sliceSourceInfo.m_assetId.IsValid()) { - AZ_Error("AssetBuilder", false, "AssetSystemRequest::GetAssetInfoById - Response AssetID should not be valid for ( %s )", badAssetId.ToString().c_str()); + AZ_Error("AssetBuilder", false, R"(AssetSystemRequest::GetAssetInfoById - Response AssetID should not be valid for ( %s ). Received Asset ID "%s")", + badAssetId.ToString().c_str(), sliceSourceInfo.m_assetId.ToString().c_str()); return; } if (badAssetId.m_subId == sliceSourceInfo.m_assetId.m_subId) { - AZ_Error("AssetBuilder", false, "AssetSystemRequest::GetAssetInfoById - Response SubID should not match for ( %s ) Received SubID %d.", badAssetId.ToString().c_str()); + AZ_Error("AssetBuilder", false, "AssetSystemRequest::GetAssetInfoById - Response SubID should not match for ( %s ) Received SubID %d.", + badAssetId.ToString().c_str(), sliceSourceInfo.m_assetId.m_subId); return; } if (sliceSourceInfo.m_assetType != AZ::Data::s_invalidAssetType) { - AZ_Error("AssetBuilder", false, "AssetSystemRequest::GetAssetInfoById - Response AssetType should not be valid for ( %s )", badAssetId.ToString().c_str()); + AZ_Error("AssetBuilder", false, R"(AssetSystemRequest::GetAssetInfoById - Response AssetType should not be valid for ( %s ). Received AssetType "%s")", + badAssetId.ToString().c_str(), sliceSourceInfo.m_assetType.ToString().c_str()); return; } diff --git a/Gems/TextureAtlas/Code/CMakeLists.txt b/Gems/TextureAtlas/Code/CMakeLists.txt index 71594ceaad..b7072321dc 100644 --- a/Gems/TextureAtlas/Code/CMakeLists.txt +++ b/Gems/TextureAtlas/Code/CMakeLists.txt @@ -12,7 +12,6 @@ ly_add_target( NAME TextureAtlas ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0 FILES_CMAKE textureatlas_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/TickBusOrderViewer/Code/CMakeLists.txt b/Gems/TickBusOrderViewer/Code/CMakeLists.txt index 6a2056a549..3f56a0d554 100644 --- a/Gems/TickBusOrderViewer/Code/CMakeLists.txt +++ b/Gems/TickBusOrderViewer/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME TickBusOrderViewer ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.TickBusOrderViewer.937fc4d2b2a94291bdeea06261c501b3.v0.1.0 FILES_CMAKE tickbusorderviewer_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Twitch/Code/CMakeLists.txt b/Gems/Twitch/Code/CMakeLists.txt index 36cbc15bb6..14d7a41532 100644 --- a/Gems/Twitch/Code/CMakeLists.txt +++ b/Gems/Twitch/Code/CMakeLists.txt @@ -25,7 +25,6 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES - PRIVATE PUBLIC AZ::AzCore Gem::HttpRequestor @@ -35,7 +34,6 @@ ly_add_target( ly_add_target( NAME Twitch ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Twitch.b63e64141fab40b791211ba257632e84.v1.0.0 FILES_CMAKE twitch_shared_files.cmake INCLUDE_DIRECTORIES @@ -46,4 +44,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::Twitch.Static + RUNTIME_DEPENDENCIES + Gem::HttpRequestor ) diff --git a/Gems/Vegetation/Code/CMakeLists.txt b/Gems/Vegetation/Code/CMakeLists.txt index 19f9a60900..67becf6c5a 100644 --- a/Gems/Vegetation/Code/CMakeLists.txt +++ b/Gems/Vegetation/Code/CMakeLists.txt @@ -34,7 +34,6 @@ ly_add_target( ly_add_target( NAME Vegetation ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Vegetation.f394e7cf54424bba89615381bba9511b.v0.1.0 FILES_CMAKE vegetation_shared_files.cmake INCLUDE_DIRECTORIES @@ -45,13 +44,17 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::Vegetation.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral + Gem::GradientSignal + Gem::SurfaceData ) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Vegetation.Editor MODULE + NAME Vegetation.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Vegetation.Editor.f394e7cf54424bba89615381bba9511b.v0.1.0 FILES_CMAKE vegetation_editor_files.cmake COMPILE_DEFINITIONS @@ -66,6 +69,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PRIVATE Gem::Vegetation.Static AZ::AzToolsFramework + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor + Gem::GradientSignal.Editor + Gem::SurfaceData.Editor ) endif() diff --git a/Gems/VideoPlaybackFramework/Code/CMakeLists.txt b/Gems/VideoPlaybackFramework/Code/CMakeLists.txt index 8ed1de3056..297f4cfaac 100644 --- a/Gems/VideoPlaybackFramework/Code/CMakeLists.txt +++ b/Gems/VideoPlaybackFramework/Code/CMakeLists.txt @@ -30,7 +30,6 @@ ly_add_target( ly_add_target( NAME VideoPlaybackFramework ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.VideoPlaybackFramework.560d69cbaafd40bea8a09bccfe7f77e6.v0.1.0 FILES_CMAKE videoplaybackframework_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/VirtualGamepad/Code/CMakeLists.txt b/Gems/VirtualGamepad/Code/CMakeLists.txt index 3fbe61c581..99a33db70b 100644 --- a/Gems/VirtualGamepad/Code/CMakeLists.txt +++ b/Gems/VirtualGamepad/Code/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( ly_add_target( NAME VirtualGamepad ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.VirtualGamepad.8aa9a66015804d6d9c809ce306e7d913.v0.1.0 FILES_CMAKE virtualgamepad_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/Visibility/Code/CMakeLists.txt b/Gems/Visibility/Code/CMakeLists.txt index ba57cb0913..c8650eea79 100644 --- a/Gems/Visibility/Code/CMakeLists.txt +++ b/Gems/Visibility/Code/CMakeLists.txt @@ -27,7 +27,6 @@ ly_add_target( ly_add_target( NAME Visibility ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.Visibility.3b4ab3f54c2749328934c5b864355a61.v0.1.0 FILES_CMAKE visibility_shared_files.cmake INCLUDE_DIRECTORIES @@ -64,9 +63,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME Visibility.Editor MODULE + NAME Visibility.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.Visibility.Editor.3b4ab3f54c2749328934c5b864355a61.v0.1.0 FILES_CMAKE visibility_editor_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/WhiteBox/AssetProcessorGemConfig.ini b/Gems/WhiteBox/AssetProcessorGemConfig.ini deleted file mode 100644 index be0194c59d..0000000000 --- a/Gems/WhiteBox/AssetProcessorGemConfig.ini +++ /dev/null @@ -1,5 +0,0 @@ -; Copy over WhiteBoxMesh -[RC WhiteBoxMesh] -glob=*.wbm -params=copy -productAssetType={6784304A-4ED6-42FD-A5C9-316265F071F2} diff --git a/Gems/WhiteBox/AssetProcessorGemConfig.setreg b/Gems/WhiteBox/AssetProcessorGemConfig.setreg new file mode 100644 index 0000000000..3724eb29bc --- /dev/null +++ b/Gems/WhiteBox/AssetProcessorGemConfig.setreg @@ -0,0 +1,13 @@ +{ + "Amazon": { + "AssetProcessor": { + "Settings": { + "RC WhiteBoxMesh": { + "glob": "*.wbm", + "params": "copy", + "productAssetType": "{6784304A-4ED6-42FD-A5C9-316265F071F2}" + } + } + } + } +} diff --git a/Gems/WhiteBox/Code/CMakeLists.txt b/Gems/WhiteBox/Code/CMakeLists.txt index cd3a61159b..a15a4e150c 100644 --- a/Gems/WhiteBox/Code/CMakeLists.txt +++ b/Gems/WhiteBox/Code/CMakeLists.txt @@ -18,7 +18,6 @@ if(NOT PAL_TRAIT_WHITEBOX_SUPPORTED) ly_add_target( NAME WhiteBox ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.WhiteBox.c5833dbda2e045d3a5f16b7414280c27.v0.1.0 FILES_CMAKE whitebox_unsupported_files.cmake INCLUDE_DIRECTORIES @@ -32,9 +31,9 @@ if(NOT PAL_TRAIT_WHITEBOX_SUPPORTED) ) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME WhiteBox.Editor MODULE + NAME WhiteBox.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.WhiteBox.Editor.c5833dbda2e045d3a5f16b7414280c27.v0.1.0 FILES_CMAKE whitebox_unsupported_files.cmake INCLUDE_DIRECTORIES @@ -75,7 +74,6 @@ ly_add_target( ly_add_target( NAME WhiteBox ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.WhiteBox.c5833dbda2e045d3a5f16b7414280c27.v0.1.0 FILES_CMAKE whitebox_shared_files.cmake INCLUDE_DIRECTORIES @@ -117,9 +115,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ) ly_add_target( - NAME WhiteBox.Editor MODULE + NAME WhiteBox.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.WhiteBox.Editor.c5833dbda2e045d3a5f16b7414280c27.v0.1.0 FILES_CMAKE whitebox_editor_shared_files.cmake INCLUDE_DIRECTORIES diff --git a/Gems/WhiteBox/Code/Tests/WhiteBoxPhysicsTest.cpp b/Gems/WhiteBox/Code/Tests/WhiteBoxPhysicsTest.cpp index 3287498e70..e2aa9ba2f2 100644 --- a/Gems/WhiteBox/Code/Tests/WhiteBoxPhysicsTest.cpp +++ b/Gems/WhiteBox/Code/Tests/WhiteBoxPhysicsTest.cpp @@ -53,7 +53,7 @@ namespace UnitTest void EditorWhiteBoxPhysicsTestEnvironment::AddGemsAndComponents() { - AddDynamicModulePaths({"Gem.PhysX.Editor.4e08125824434932a0fe3717259caa47.v0.1.0"}); + AddDynamicModulePaths({"PhysX.Editor"}); AddComponentDescriptors( {AzToolsFramework::EditorEntityContextComponent::CreateDescriptor(), WhiteBox::EditorWhiteBoxComponent::CreateDescriptor(), WhiteBox::WhiteBoxComponent::CreateDescriptor(), diff --git a/Templates/DefaultProject/Template/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index 04157333fe..24b229d05b 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -11,6 +11,18 @@ # # {END_LICENSE} +#! Adds the --project-path argument to the VS IDE debugger command arguments +function(add_vs_debugger_arguments) + # Inject the project root into the --project-path argument into the Visual Studio Debugger arguments by defaults + list(APPEND app_targets ${Name}.GameLauncher ${Name}.ServerLauncher) + list(APPEND app_targets AssetBuilder AssetProcessor AssetProcessorBatch Editor) + foreach(app_target IN LISTS app_targets) + if (TARGET ${app_target}) + set_property(TARGET ${app_target} APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${CMAKE_CURRENT_LIST_DIR}\"") + endif() + endforeach() +endfunction() + if(NOT PROJECT_NAME) cmake_minimum_required(VERSION 3.19) project(${Name} @@ -20,7 +32,18 @@ if(NOT PROJECT_NAME) include(EngineFinder.cmake OPTIONAL) find_package(o3de REQUIRED) o3de_initialize() + add_vs_debugger_arguments() else() + # Add the project_name to global LY_PROJECTS_TARGET_NAME property + file(READ "${CMAKE_CURRENT_LIST_DIR}/project.json" project_json) + + string(JSON project_target_name ERROR_VARIABLE json_error GET ${project_json} "project_name") + if(${json_error}) + message(FATAL_ERROR "Unable to read key 'project_name' from 'project.json'") + endif() + + set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) + # Currently we are in the ${Name} folder: ${CMAKE_CURRENT_LIST_DIR} # Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} # Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform diff --git a/Templates/DefaultProject/Template/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake index 42e37d0999..d1b83b6b6c 100644 --- a/Templates/DefaultProject/Template/EngineFinder.cmake +++ b/Templates/DefaultProject/Template/EngineFinder.cmake @@ -23,12 +23,17 @@ if(json_error) endif() # Read the list of paths from ~.o3de/o3de_manifest.json -if($ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) - set(manifest_path $ENV{USERPROFILE}/.o3de/o3de_manifest.json) # Windows -else() - set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix +file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows +if((NOT home_directory) OR (NOT EXISTS ${home_directory})) + file(TO_CMAKE_PATH "$ENV{HOME}" home_directory)# Unix endif() +if (NOT home_directory) + message(FATAL_ERROR "Cannot find user home directory, the o3de manifest cannot be found") +endif() +# Set manifest path to path in the user home directory +set(manifest_path ${home_directory}/.o3de/o3de_manifest.json) + if(EXISTS ${manifest_path}) file(READ ${manifest_path} manifest_json) string(JSON engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines) diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py index f4067d3c05..806f634f1b 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py @@ -150,9 +150,9 @@ class AbstractResourceLocator(object): def cache(self): """ Return path to the cache dir. - :return: path to engine_root/dev/Cache/ + :return: path to project_root/Cache/ """ - return self._cache_override or os.path.join(self.dev(), "Cache") + return self._cache_override or os.path.join(self.project(), "Cache") def asset_db(self): """ @@ -171,9 +171,9 @@ class AbstractResourceLocator(object): def asset_cache(self, platform): """ Return path to the cache for the current platform and project inside the game project folder - :return: path to cache/// + :return: path to /Cache/ """ - return os.path.join(self.platform_cache_path(platform), self._project) + return os.path.join(self.platform_cache_path(platform)) def asset_catalog(self, platform): """ @@ -194,14 +194,14 @@ class AbstractResourceLocator(object): Return path to AssetProcessorBatch's log directory using the project bin dir :return: path where the "logs" folder will be found """ - return self._ap_log_root or self.build_directory() + return self._ap_log_root or self.project_log() def ap_log_dir(self): """ Return path to AssetProcessorBatch's log directory using the project bin dir :return: path to 'logs' dir in folder """ - return os.path.join(self.ap_log_root(), 'logs') + return self.ap_log_root() def ap_job_logs(self): """ @@ -210,6 +210,7 @@ class AbstractResourceLocator(object): """ return os.path.join(self.ap_log_dir(), 'JobLogs') + def ap_batch_log(self): """ Return path to AssetProcessorBatch's log file using the project bin dir @@ -227,9 +228,9 @@ class AbstractResourceLocator(object): def project_cache(self): """ Return path to the current project cache folder - :return: path to engine_root/dev/Cache/ + :return: path to /Cache """ - return os.path.join(self.cache(), self._project) + return self.cache() def get_shader_compiler_path(self): """ @@ -243,7 +244,7 @@ class AbstractResourceLocator(object): return os.path.join(self.dev(), 'bootstrap.cfg') def asset_processor_config_file(self): - return os.path.join(self.dev(), 'AssetProcessorPlatformConfig.ini') + return os.path.join(self.dev(), 'AssetProcessorPlatformConfig.setreg') def autoexec_file(self): return os.path.join( diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py index d4ffd4f56f..482e0daefc 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py @@ -50,14 +50,14 @@ class _MacResourceLocator(AbstractResourceLocator): Return path to the project's log dir for the Mac operating system. :return: path to 'log' dir in the platform cache dir """ - return os.path.join(self.platform_cache(), 'user', 'log') + return os.path.join(self.project(), 'user', 'log') def project_screenshots(self): """ Return path to the project's screenshot dir for the Mac operating system. :return: path to 'screenshot' dir in the platform cache dir """ - return os.path.join(self.platform_cache(), 'user', 'ScreenShots') + return os.path.join(self.project(), 'user', 'ScreenShots') def editor_log(self): """ diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py index e7ff78c63d..b319a62e68 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py @@ -56,14 +56,14 @@ class _WindowsResourceLocator(AbstractResourceLocator): Return path to the project's log dir for the Windows operating system. :return: path to 'log' dir in the platform cache dir """ - return os.path.join(self.platform_cache(), 'user', 'log') + return os.path.join(self.project(), 'user', 'log') def project_screenshots(self): """ Return path to the project's screenshot dir for the Windows operating system. :return: path to 'screenshot' dir in the platform cache dir """ - return os.path.join(self.platform_cache(), 'user', 'ScreenShots') + return os.path.join(self.project(), 'user', 'ScreenShots') def editor_log(self): """ diff --git a/Tools/LyTestTools/ly_test_tools/builtin/helpers.py b/Tools/LyTestTools/ly_test_tools/builtin/helpers.py index 93fdf1c4fc..fc69fcce8e 100644 --- a/Tools/LyTestTools/ly_test_tools/builtin/helpers.py +++ b/Tools/LyTestTools/ly_test_tools/builtin/helpers.py @@ -78,12 +78,12 @@ def setup_bootstrap_project(workspace, project): found_gamefolder = False for i, line in enumerate(lines): - if line.lstrip().startswith("sys_game_folder"): - lines[i] = f"sys_game_folder={project}\n" + if line.lstrip().startswith("project_path"): + lines[i] = f"project_path={project}\n" found_gamefolder = True break - assert found_gamefolder, "'sys_game_folder' not found in bootstrap.cfg" + assert found_gamefolder, "'project_path' not found in bootstrap.cfg" with open(bootstrap_cfg, "w") as f: f.writelines(lines) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py index 90b142e100..08cae651b4 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py @@ -20,6 +20,7 @@ Assumptions for running automation: import json import logging import os +from pathlib import PurePath, Path from subprocess import CalledProcessError import six @@ -120,6 +121,7 @@ class AndroidLauncher(Launcher): self._adb_prefix_command = ['adb'] self._device_id = None self.launch_proc = None + self.android_vfs_setreg_path = None self.package_name = get_package_name(os.path.join(self.workspace.paths.dev(), self.workspace.project)) self._device_id = self.get_device_config(config_file=self.workspace.paths.devices_file(), @@ -181,6 +183,9 @@ class AndroidLauncher(Launcher): def teardown(self): ly_test_tools.mobile.android.undo_tcp_port_changes(self._device_id) self.restore_settings() + # Remove temporary vfs file if created + if self.android_vfs_setreg_path and os.path.isfile(self.android_vfs_setreg_path): + os.remove(self.android_vfs_setreg_path) self.workspace.shader_compiler.stop() super(AndroidLauncher, self).teardown() @@ -190,12 +195,22 @@ class AndroidLauncher(Launcher): :return: None """ - self.workspace.settings.modify_bootstrap_setting('sys_game_folder', self.workspace.project) - self.workspace.settings.modify_bootstrap_setting('connect_to_remote', 1) - self.workspace.settings.modify_bootstrap_setting('android_connect_to_remote', 1) - self.workspace.settings.modify_bootstrap_setting('wait_for_connect', 1) - self.workspace.settings.modify_bootstrap_setting('remote_ip', '127.0.0.1') - self.workspace.settings.modify_bootstrap_setting('remote_port', '45643') + + # Write the Android vfs settings to a settings registry file within the user's registry folder + user_registry_path = Path(self.workspace.project) / 'user' / 'Registry' + user_registry_path.mkdir(parents=True, exist_ok=True) + + # Create a python dictionary that can serialize to a json file with JSON pointer of + # /Amazon/AzCore/Bootstrap/ + vfs_settings = { 'Amazon' : { 'AzCore' : { 'Bootstrap' : {} }}} + vfs_settings['Amazon']['AzCore']['Bootstrap']['connect_to_remote'] = 1 + vfs_settings['Amazon']['AzCore']['Bootstrap']['android_connect_to_remote'] = 1 + vfs_settings['Amazon']['AzCore']['Bootstrap']['wait_for_connect'] = 1 + vfs_settings['Amazon']['AzCore']['Bootstrap']['remote_ip'] = '127.0.0.1' + vfs_settings['Amazon']['AzCore']['Bootstrap']['remote_port'] = 45643 + self.android_vfs_setreg_path = user_registry_path / 'test_android_vfs_settings.android.setreg' + with self.android_vfs_setreg_path.open('w') as android_vfs_setreg: + json.dump(vfs_settings, android_vfs_setreg, indent=4) self.workspace.settings.modify_platform_setting('r_AssetProcessorShaderCompiler', 1) self.workspace.settings.modify_platform_setting('r_ShadersAsyncCompiling', 0) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py index d855f8f9ec..6b53c1f8f3 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py @@ -140,7 +140,6 @@ class Launcher(object): Perform settings configuration, must be called after a backup of settings has been created with backup_settings(). Preferred ways to modify settings are: - self.workspace.settings.modify_bootstrap_setting() self.workspace.settings.modify_platform_setting() :return: None @@ -156,7 +155,6 @@ class Launcher(object): """ backup_path = self.workspace.settings.get_temp_path() log.debug(f"Restoring backup of bootstrap, platform and user settings in path {backup_path}") - self.workspace.settings.restore_bootstrap_settings(backup_path) self.workspace.settings.restore_platform_settings(backup_path) self.workspace.settings.restore_shader_compiler_settings(backup_path) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py index 7d69611f79..a509cd6366 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py @@ -163,13 +163,12 @@ class WinLauncher(Launcher): :return: None """ - # Update settings + # Update settings via the settings registry to avoid modifying the bootstrap.cfg host_ip = '127.0.0.1' - - self.workspace.settings.modify_bootstrap_setting("sys_game_folder", self.workspace.project) - self.workspace.settings.modify_bootstrap_setting("remote_ip", host_ip) - self.workspace.settings.modify_bootstrap_setting("wait_for_connect", 1) - self.workspace.settings.modify_bootstrap_setting("white_list", host_ip) + self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/project_path={self.workspace.project}"') + self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/remote_ip={host_ip}"') + self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"') + self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"') self.workspace.settings.modify_platform_setting("r_AssetProcessorShaderCompiler", 1) self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip) @@ -194,7 +193,7 @@ class WinEditor(WinLauncher): def __init__(self, build, args): super(WinEditor, self).__init__(build, args) - self.args.append("--regset=\"/Amazon/Settings/EnableSourceControl=false\"") + self.args.append('--regset="/Amazon/Settings/EnableSourceControl=false"') def binary_path(self): """ diff --git a/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor.py b/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor.py index 1aea4de75f..523c28bcf8 100644 --- a/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor.py @@ -49,6 +49,7 @@ ASSET_PROCESSOR_PLATFORM_MAP = { 'windows': 'pc', } +ASSET_PROCESSOR_SETTINGS_ROOT_KEY='/Amazon/AssetProcessor/Settings' class AssetProcessorError(Exception): """ Indicates that the AssetProcessor raised an error """ @@ -69,6 +70,7 @@ class AssetProcessor(object): self._ap_proc = None self._temp_asset_directory = None self._temp_asset_root = None + self._project_path = self._workspace.project self._override_scan_folders = [] self._test_assets_source_folder = None self._cache_folder = None @@ -76,6 +78,8 @@ class AssetProcessor(object): self._control_connection = None self._function_name = None self._failed_log_root = None + self._disable_all_platforms = False + self._enabled_platform_overrides = dict() # Starts AP but does not by default run until idle. def start(self, connection_timeout=30, quitonidle=False, add_gem_scan_folders=None, add_config_scan_folders=None, @@ -445,7 +449,10 @@ class AssetProcessor(object): extra_gui_params.append(ap_platform) if extra_params: - extra_gui_params.append(extra_params) + if isinstance(extra_params, list): + extra_gui_params.extend(extra_params) + else: + extra_gui_params.append(extra_params) command = self.build_ap_command(ap_path=ap_path, fastscan=fastscan, platforms=platforms, extra_params=extra_gui_params, add_gem_scan_folders=add_gem_scan_folders, @@ -508,9 +515,8 @@ class AssetProcessor(object): if fastscan: command.append("--zeroAnalysisMode") - if self._workspace.project: - command.append("--gamefolder") - command.append(self._workspace.project) + if self._project_path: + command.append(f'--regset="/Amazon/AzCore/Bootstrap/project_path={self._project_path}"') # When using a scratch workspace we will set several options. The asset root controls where our # cache lives, gives us a unique directory to place our logs in, and indicates we wish to randomize our @@ -520,6 +526,7 @@ class AssetProcessor(object): command.append(f"{self._temp_asset_root}") command.append("--logDir") command.append(f"{self._temp_asset_root}") + command.append(f'--regset="/Amazon/AzCore/Bootstrap/project_cache_path={self.temp_project_cache_path()}"') command.append("--randomListeningPort") if self._override_scan_folders: command.append("--scanfolders") @@ -537,10 +544,16 @@ class AssetProcessor(object): if not isinstance(scan_folder_pattern, list): scan_folder_pattern = [scan_folder_pattern] command.append(f"{','.join(scan_folder_pattern)}") + + if self._disable_all_platforms: + command.append(f'--regremove="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms"') if platforms: if isinstance(platforms, list): platforms = ','.join(platforms) - command.append(f'/platforms={platforms}') + command.append(f'--platforms={platforms}') + for key, value in self._enabled_platform_overrides: + command.append(f'--regset="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms/{key}={value}"') + if extra_params: if isinstance(extra_params, list): command.extend(extra_params) @@ -602,84 +615,21 @@ class AssetProcessor(object): def disable_all_asset_processor_platforms(self): """ - Modify the AssetProcessorPlatformConfig file to enable asset procesing for the target platform. - This is done by commenting the line containing the platform name. + Disables all platforms via the SettingsRegistry --regremove option :return: None """ - if not os.path.isfile(self._workspace.paths.asset_processor_config_file()): - raise IOError("Unable to find a file at {}".format(self._workspace.paths.asset_processor_config_file())) - else: - # AssetProcessorPlatformConfig.ini is generally in read only mode on fresh checkouts - file_system.unlock_file(self._workspace.paths.asset_processor_config_file()) - with open(self._workspace.paths.asset_processor_config_file(), 'r+') as config_file: - data = config_file.readlines() - - section_end = None - section_begin = None - - # configParser is useless here because it strips commented lines. - for lineNmber, configRow in enumerate(data): - if "[Platforms]" in configRow: - section_begin = lineNmber - # First instance of an open bracket after the platform's section will be the start of a section - elif "[" in configRow and section_begin is not None: - section_end = lineNmber - if section_begin is not None and section_end is not None: - break - - offsetFromPlatformsHeader = 0 - for line in itertools.islice(data, section_begin + 1, section_end): - offsetFromPlatformsHeader += 1 - data[section_begin + offsetFromPlatformsHeader] = f";{line}" - - config_file.seek(0) - config_file.truncate() - config_file.writelines(data) + self._disable_all_platforms = True def enable_asset_processor_platform(self, platform): # type: (str) -> None """ - Modify the AssetProcessorPlatformConfig file to enable asset processing for the target platform. - This is done by uncommenting the line containing the platform name. + Add the platform to the dict of platforms to enable via the SettingsRegistry --regset option :param platform: The platform to enable :return: None """ - config_file_path = self._workspace.paths.asset_processor_config_file() - if self._temp_asset_root: - config_file_path = os.path.join(self._temp_asset_root, "AssetProcessorPlatformConfig.ini") - if not os.path.isfile(config_file_path): - raise IOError(f"Unable to find a file at {config_file_path}") - else: - # AssetProcessorPlatformConfig.ini is generally in read only mode on fresh checkouts - file_system.unlock_file(config_file_path) - with open(config_file_path, 'r+') as config_file: - data = config_file.readlines() - - section_end = None - section_begin = None - - # configParser is useless here because it strips commented lines. - for lineNmber, configRow in enumerate(data): - if "[Platforms]" in configRow: - section_begin = lineNmber - # First instance of an open bracket after the platform's section will be the start of a section - elif "[" in configRow and section_begin is not None: - section_end = lineNmber - if section_begin is not None and section_end is not None: - break - - offsetFromPlatformsHeader = 0 - for line in itertools.islice(data, section_begin + 1, section_end): - offsetFromPlatformsHeader += 1 - if platform in line: - data[section_begin + offsetFromPlatformsHeader] = line.replace(';', '') - break - - config_file.seek(0) - config_file.truncate() - config_file.writelines(data) + self._enabled_platform_overrides[platform] = 'enabled' def temp_asset_root(self): """ @@ -697,13 +647,11 @@ class AssetProcessor(object): :return: None """ - for copy_dir in [os.path.join(self._workspace.project, 'Config'), 'Engine']: + for copy_dir in [self._workspace.project, 'Engine']: make_dir = os.path.join(self._temp_asset_root, copy_dir) if not os.path.isdir(make_dir): os.makedirs(make_dir) - for copyfile_name in ['bootstrap.cfg', 'AssetProcessorPlatformConfig.ini', 'engine.json', - os.path.join(self._workspace.project, 'Config', 'Editor.xml'), - os.path.join(self._workspace.project, "gems.json"), + for copyfile_name in ['bootstrap.cfg', 'AssetProcessorPlatformConfig.setreg', os.path.join(self._workspace.project, "project.json"), os.path.join('Engine', 'exclude.filetag')]: shutil.copyfile(os.path.join(self._workspace.paths.dev(), copyfile_name), @@ -752,9 +700,9 @@ class AssetProcessor(object): self._temp_asset_root = self._temp_asset_directory.name self._copy_asset_root_files() self._workspace.paths.set_ap_log_root(self._temp_asset_root) + self._project_path = os.path.join(self._temp_asset_root, self._workspace.project) if project_scan_folder: - project_dir = os.path.join(self._temp_asset_root, self._workspace.project) - self.add_scan_folder(project_dir) + self.add_scan_folder(self._project_path) def add_scan_folder(self, folder_name) -> str: """ @@ -834,9 +782,8 @@ class AssetProcessor(object): self._function_name = function_name self._assets_source_folder = utils.prepare_test_assets(assets_path, function_name, test_folder) self._test_assets_source_folder = test_folder - self._cache_folder = os.path.join(self._temp_asset_root, 'Cache', self._workspace.project, cache_platform or + self._cache_folder = os.path.join(self._temp_asset_root, 'Cache', cache_platform or ASSET_PROCESSOR_PLATFORM_MAP[self._workspace.asset_processor_platform], - self._workspace.project.lower(), function_name.lower() if existing_function_name is None else existing_function_name) @@ -938,10 +885,20 @@ class AssetProcessor(object): :param asset_platform: Asset platform to use. Workspace's asset platform if not supplied :return: path to project cache """ - project_name = project_name or self._workspace.project asset_platform = asset_platform or ASSET_PROCESSOR_PLATFORM_MAP[self._workspace.asset_processor_platform] - return os.path.join(self._temp_asset_root, 'Cache', project_name, - asset_platform.lower(), project_name.lower()) + return os.path.join(self._temp_asset_root, 'Cache', + asset_platform.lower()) + + def temp_project_cache_path(self, project_name=None): + """ + Get the project cache root folder from a test run using prepare_test_environment + The project cache root folder does not include the asset platform + + :param project_name: Project name to use, defaults to workspace's project name + + :return: path to project cache root folder + """ + return os.path.join(self._temp_asset_root, 'Cache') def clear_readonly(self, relative_dest): """ @@ -991,13 +948,19 @@ class AssetProcessor(object): def _build_ap_batch_call_params(ap_path, project, platforms, extra_params=None): - project_str = f"/gamefolder={project}" + project_str = f"--regset=/Amazon/AzCore/Bootstrap/project_path={project}" project_str.rstrip(' ') param_list = [ap_path, project_str] + + if self._disable_all_platforms: + command.append(f'--regremove="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms"') if platforms: if isinstance(platforms, list): platforms = ','.join(platforms) - param_list.append(f'/platforms={platforms}') + param_list.append(f'--platforms={platforms}') + for key, value in self._enabled_platform_overrides: + param_list.append(f'--regset="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms/{key}={value}"') + if extra_params: if isinstance(extra_params, list): param_list.extend(extra_params) diff --git a/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor_config_util.py b/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor_config_util.py index 3ed0e87cc9..1678ddc6d8 100644 --- a/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor_config_util.py +++ b/Tools/LyTestTools/ly_test_tools/lumberyard/asset_processor_config_util.py @@ -9,22 +9,47 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Library of functions to support reading, modifying and writing to -AssetProcessorPlatformConfig.ini +AssetProcessorPlatformConfig.setreg """ +import json import logging -from ly_test_tools.lumberyard import ini_configuration_util as ini import os.path as path logger = logging.getLogger(__name__) -AssetProcessorConfig = "AssetProcessorPlatformConfig.ini" +AssetProcessorConfig = "AssetProcessorPlatformConfig.setreg" -def platform_exists(config_ini_path, platform): +def load_asset_processor_platform_config(file_location): + """ + Loads the AssetProcessorPlatformConfig.setreg file removing any comments + + :param file_location: The file path of AssetProcessorPlatformConfig.setreg + """ + json_dict = {} + with open(file_location, 'r') as json_file: + cleaned_lines = [] + for line in json_file.readlines(): + lineIndex = line.lstrip().startswith('//') + cleaned_lines.append(line if lineIndex == -1 else line[:lineIndex]) + json_dict = json.loads(''.join(cleaned_lines)) + return json_dict + +def save_asset_processor_platform_config(file_location, json_dict): + """ + Saves the json_dict to the AssetProcessorPlatformConfig.setreg file + + :param file_location: The file path of AssetProcessorPlatformConfig.setreg + """ + with open(file_location, 'w') as json_file: + json.dump(json_dict, json_file, indent=4) + return json_dict + +def platform_exists(config_setreg_path, platform): """ Checks to see if a specific Platform Key is in Platforms Section - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :param platform: Name of the Platform Key that you're checking exists :return: The boolean value of the existance of the platform """ @@ -32,19 +57,22 @@ def platform_exists(config_ini_path, platform): logger.debug("Checking for Platform '{0}' in Platforms Section of '{1}" .format(platform, AssetProcessorConfig)) - file_location = path.join(config_ini_path, AssetProcessorConfig) - - assert ini.check_section_exists(file_location, 'Platforms'), \ - 'Platforms section does not exist in {0}'.format(file_location) + file_location = path.join(config_setreg_path, AssetProcessorConfig) + json_dict = load_asset_processor_platform_config(file_location) + try: + platformExist = platform in json_dict['Amazon']['AssetProcessor']['Settings']['Platforms'] + return platformExist + except KeyError as err: + logger.error(f'KeyError when attempting to query platform existance of {platform} in file {file_location}: {err}') - return ini.check_key_exists(path.join(config_ini_path, AssetProcessorConfig), 'Platforms', platform) + return False -def is_platform_enabled(config_ini_path, platform): +def is_platform_enabled(config_setreg_path, platform): """ Checks to see if a specific Platform Key is enabled in Platforms Section - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :param platform: Name of the Platform that you're checking is enabled. See asset_processor.SUPPORTED_PLATFORMS for listed of supported platforms :return: The boolean value of the enabled state of the platform @@ -53,21 +81,23 @@ def is_platform_enabled(config_ini_path, platform): logger.debug("Checking if Platform '{0}' is enabled in Platform Section of '{1}" .format(platform, AssetProcessorConfig)) - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) + # load AssetProcessorPlatformConfig.setreg removing any comments + json_dict = load_asset_processor_platform_config(file_location) + try: + enabled = json_dict['Amazon']['AssetProcessor']['Settings']['Platforms'][platform] == 'enabled' + return enabled + except KeyError as err: + logger.error(f'KeyError when attempting to check if platform {platform} is enabled in file {file_location}: {err}') - assert ini.check_section_exists(file_location, 'Platforms'), \ - 'Platforms section does not exist in {0}'.format(file_location) + return False - enabled = str(ini.get_string_value(file_location, 'Platforms', platform)) == 'enabled' - return enabled - - -def enable_platform(config_ini_path, platform): +def enable_platform(config_setreg_path, platform): """ Enables a specific Platform Key is in Platforms Section - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :param platform: Name of the Platform Key that you're checking exists See asset_processor.SUPPORTED_PLATFORMS for listed of supported platforms :assert: Assert if the platform is not enabled @@ -76,35 +106,35 @@ def enable_platform(config_ini_path, platform): logger.debug("Enabling platform '{0}' in '{1}'".format(platform, AssetProcessorConfig)) - file_location = path.join(config_ini_path, AssetProcessorConfig) - - ini.add_key(file_location, 'Platforms', platform, 'enabled') + file_location = path.join(config_setreg_path, AssetProcessorConfig) + json_dict = load_asset_processor_platform_config(file_location) + # Enable platform in settings registry + json_dict.setdefault('Amazon', {}).setdefault('AssetProcessor', {}).setdefault('Settings',{}) \ + .setdefault('Platforms',{})[platform] = 'enabled' + save_asset_processor_platform_config(file_location) - assert is_platform_enabled(config_ini_path, platform), "Platform '{0}' failed to enable in '{1}'"\ - .format(platform, AssetProcessorConfig) - -def enable_all_platforms(config_ini_path): +def enable_all_platforms(config_setreg_path): """ Enable all supported platforms in the Platforms Section - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ logger.debug("Enabling all supported platforms in '{0}'.".format(AssetProcessorConfig)) for platform in SUPPORTED_PLATFORMS: - enable_platform(config_ini_path, platform) + enable_platform(config_setreg_path, platform) logger.debug("All supported platforms have been enabled in '{0}'.".format(AssetProcessorConfig)) -def disable_platform(config_ini_path, platform): +def disable_platform(config_setreg_path, platform): """ Disables a specific Platform Key is in Platforms Section - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :param platform: Name of the Platform Key that you're checking exists. See asset_processor_config_util.SUPPORTED_PLATFORMS for listed of supported platforms :assert: Assert if the platform is not disabled @@ -113,170 +143,196 @@ def disable_platform(config_ini_path, platform): logger.debug("Disabling platform '{0}' in '{1}'".format(platform, AssetProcessorConfig)) - file_location = path.join(config_ini_path, AssetProcessorConfig) - - ini.add_key(file_location, 'Platforms', platform, 'disabled') - - assert not is_platform_enabled(config_ini_path, platform), "Platform '{0}' failed to disable in '{1}'"\ - .format(platform, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) + # Disable platform in settings registry + json_dict = load_asset_processor_platform_config(file_location) + json_dict.setdefault('Amazon', {}).setdefault('AssetProcessor', {}).setdefault('Settings',{}) \ + .setdefault('Platforms',{})[platform] = 'disabled' + save_asset_processor_platform_config(file_location) -def disable_all_platforms(config_ini_path): +def disable_all_platforms(config_setreg_path): """ Disable all supported platforms in the Platforms Section - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ logger.debug("Disabling all platforms in '{0}'".format(AssetProcessorConfig)) for platform in SUPPORTED_PLATFORMS: - disable_platform(config_ini_path, platform) + disable_platform(config_setreg_path, platform) logger.debug("All supported platforms have been disabled in '{0}'.".format(AssetProcessorConfig)) -def enable_scanfolder_engine(config_ini_path): +def enable_scanfolder_engine(config_setreg_path): """ Enable Asset Processor scanning on the Engine folder - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) section = 'ScanFolder Engine' logger.debug("Enabling Asset Processor scanning of the Engine folder") - if not ini.check_section_exists(file_location, section): - ini.add_section(file_location, section) - ini.add_key(file_location, section, 'watch', r'@ENGINEROOT@/Engine') - ini.add_key(file_location, section, 'recursive', '1') - ini.add_key(file_location, section, 'order', '20000') + json_dict = load_asset_processor_platform_config(file_location) + json_dict.setdefault('Amazon', {}).setdefault('AssetProcessor', {}).setdefault('Settings',{}) \ + .setdefault(section,{})['watch'] = '@ENGINEROOT@/Engine' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['recursive'] = '1' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['order'] = '20000' + save_asset_processor_platform_config(file_location) -def disable_scanfolder_engine(config_ini_path): +def disable_scanfolder_engine(config_setreg_path): """ Disable Asset Processor scanning on the Engine folder - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) section = 'ScanFolder Engine' logger.debug("Disabling Asset Processor scanning of the Engine folder") - ini.delete_section(file_location, section) + json_dict = load_asset_processor_platform_config(file_location) + try: + del json_dict['Amazon']['AssetProcessor']['Settings'][section] + save_asset_processor_platform_config(file_location) + except KeyError as err: + logger.debug(f'No-op: f{section} key does not exist in file {file_location}') -def enable_scanfolder_editor(config_ini_path): +def enable_scanfolder_editor(config_setreg_path): """ Enable Asset Processor scanning on the editor folder - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) section = 'ScanFolder Editor' logger.debug("Enabling Asset Processor scanning of the Editor folder") - if not ini.check_section_exists(file_location, section): - ini.add_section(file_location, section) - ini.add_key(file_location, section, 'watch', r'@ENGINEROOT@/Editor') - ini.add_key(file_location, section, 'output', 'editor') - ini.add_key(file_location, section, 'recursive', '1') - ini.add_key(file_location, section, 'order', '30000') - ini.add_key(file_location, section, 'include', 'tools,renderer') + json_dict = load_asset_processor_platform_config(file_location) + json_dict.setdefault('Amazon', {}).setdefault('AssetProcessor', {}).setdefault('Settings',{}) \ + .setdefault(section,{})['watch'] = '@ENGINEROOT@/Editor' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['output'] = 'editor' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['recursive'] = '1' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['order'] = '30000' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['include'] = 'tools,renderer' + save_asset_processor_platform_config(file_location) -def disable_scanfolder_editor(config_ini_path): +def disable_scanfolder_editor(config_setreg_path): """ Disable Asset Processor scanning on the Engine folder - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) section = 'ScanFolder Editor' logger.debug("Disabling Asset Processor scanning of the Editor folder") - ini.delete_section(file_location, section) + try: + del json_dict['Amazon']['AssetProcessor']['Settings'][section] + save_asset_processor_platform_config(file_location) + except KeyError as err: + logger.debug(f'No-op: f{section} key does not exist in file {file_location}') -def enable_scanfolder_root(config_ini_path): +def enable_scanfolder_root(config_setreg_path): """ Enable Asset Processor scanning on the Root folder - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) section = 'ScanFolder Root' logger.debug("Enabling Asset Processor scanning of the Root folder") - if not ini.check_section_exists(file_location, section): - ini.add_section(file_location, section) - ini.add_key(file_location, section, 'watch', r'@ROOT@') - ini.add_key(file_location, section, 'recursive', '0') - ini.add_key(file_location, section, 'order', '10000') + json_dict = load_asset_processor_platform_config(file_location) + json_dict.setdefault('Amazon', {}).setdefault('AssetProcessor', {}).setdefault('Settings',{}) \ + .setdefault(section,{})['watch'] = '@ROOT@' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['recursive'] = '0' + json_dict['Amazon']['AssetProcessor']['Settings'][section]['order'] = '10000' + save_asset_processor_platform_config(file_location) -def disable_scanfolder_root(config_ini_path): +def disable_scanfolder_root(config_setreg_path): """ Disable Asset Processor scanning on the Root folder - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) section = 'ScanFolder Root' logger.debug("Disabling Asset Processor scanning of the Root folder") - ini.delete_section(file_location, section) + try: + del json_dict['Amazon']['AssetProcessor']['Settings'][section] + save_asset_processor_platform_config(file_location) + except KeyError as err: + logger.debug(f'No-op: f{section} key does not exist in file {file_location}') -def update_pattern(config_ini_path, pattern, key, value): +def update_pattern(config_setreg_path, pattern, key, value): """ Update a RC pattern's behavior options with the provided key and value. - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :param pattern: The RC pattern to update :param key: The key to update :param value: The value to set the key to :return: None """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) rc_pattern = 'RC ' + pattern logger.debug("Modifying pattern for '{0}'.".format(rc_pattern)) - ini.add_key(file_location, rc_pattern, key, value) + json_dict = load_asset_processor_platform_config(file_location) + json_dict.setdefault('Amazon', {}).setdefault('AssetProcessor', {}).setdefault('Settings',{}) \ + .setdefault(rc_pattern,{})[key] = value + save_asset_processor_platform_config(file_location) -def get_pattern_key(config_ini_path, pattern, key): +def get_pattern_key(config_setreg_path, pattern, key): """ Get the value of a RC pattern's behavior options key value - :param config_ini_path: The file path to the location of AssetProcessorPlatformConfig.ini + :param config_setreg_path: The file path to the location of AssetProcessorPlatformConfig.setreg :param pattern: The RC pattern to retrieve a key from :param key: The key to retrieve :return: value of RC pattern key value """ - file_location = path.join(config_ini_path, AssetProcessorConfig) + file_location = path.join(config_setreg_path, AssetProcessorConfig) rc_pattern = 'RC ' + pattern logger.debug("Retrieving the key '{0}' from pattern '{1}'.".format(key, rc_pattern)) - return ini.get_string_value(file_location, rc_pattern, key) + json_dict = load_asset_processor_platform_config(file_location) + try: + value = json_dict['Amazon']['AssetProcessor']['Settings'][rc_pattern][key] + return value + except KeyError as err: + logger.error(f'KeyError attempting to query value for key "/Amazon/AssetProcessor/Settings/{rc_pattern}/{key}" in file {file_location}: {err}') + + return None diff --git a/Tools/LyTestTools/ly_test_tools/lumberyard/settings.py b/Tools/LyTestTools/ly_test_tools/lumberyard/settings.py index 3e09909b7a..783aeaa5d0 100644 --- a/Tools/LyTestTools/ly_test_tools/lumberyard/settings.py +++ b/Tools/LyTestTools/ly_test_tools/lumberyard/settings.py @@ -41,10 +41,6 @@ class LySettings(object): logger.info(f'Updating setting {setting} to {value}') _edit_text_settings_file(self._resource_locator.platform_config_file(), setting, value) - def modify_bootstrap_setting(self, setting, value, bootstrap_path=None): - logger.info(f'Updating setting {setting} to {value}') - _edit_text_settings_file(bootstrap_path or self._resource_locator.bootstrap_config_file(), setting, value) - def modify_shader_compiler_setting(self, setting, value): logger.info(f'Updating setting {setting} to {value}') _edit_text_settings_file(self._resource_locator.shader_compiler_config_file(), setting, value) diff --git a/Tools/LyTestTools/tests/CMakeLists.txt b/Tools/LyTestTools/tests/CMakeLists.txt index ca51061ff9..924fbf334c 100644 --- a/Tools/LyTestTools/tests/CMakeLists.txt +++ b/Tools/LyTestTools/tests/CMakeLists.txt @@ -19,7 +19,8 @@ ly_add_pytest( COMPONENT TestTools ) -if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_NAME) +get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME) +if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_TARGET_NAME) # Integration tests. ly_add_pytest( NAME LyTestTools_IntegTests_Sanity_smoke_no_gpu @@ -43,19 +44,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT COMPONENT TestTools ) - ly_add_pytest( - NAME LyTestTools_IntegTests_Settings_smoke_no_gpu - PATH ${CMAKE_CURRENT_LIST_DIR}/integ/test_settings.py - TEST_SERIAL - TEST_SUITE smoke - RUNTIME_DEPENDENCIES - AssetProcessor - AutomatedTesting.GameLauncher - AutomatedTesting.Assets - Legacy::CryRenderNULL - COMPONENT TestTools - ) - # Regression tests. ly_add_pytest( NAME LyTestTools_IntegTests_RegressionTests_periodic_no_gpu diff --git a/Tools/LyTestTools/tests/integ/test_settings.py b/Tools/LyTestTools/tests/integ/test_settings.py deleted file mode 100644 index 95e41511c0..0000000000 --- a/Tools/LyTestTools/tests/integ/test_settings.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -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. -""" - -import filecmp -import os -import pytest - - -pytestmark = pytest.mark.SUITE_smoke - - -class TestLySettings(object): - - @pytest.mark.parametrize("project", ["AutomatedTesting"]) - @pytest.mark.parametrize("wait_for_connect", [1234, 4567]) - def test_BootstrapSettings_BackupModifyRestore_SettingsMatch(self, workspace, wait_for_connect): - backup_path = workspace.tmp_path - - # create backup - workspace.settings.backup_bootstrap_settings(backup_path) - - # verify files match - bootstrap_settings = workspace.paths.bootstrap_config_file() - bootstrap_settings_backup = os.path.join(backup_path, '{}.bak'.format(os.path.basename(bootstrap_settings))) - assert os.path.exists(bootstrap_settings), "Bootstrap settings file does not exist" - assert os.path.exists(bootstrap_settings_backup), "Bootstrap settings backup does not exist" - assert filecmp.cmp(bootstrap_settings, bootstrap_settings_backup), "Bootstrap settings and backup do not match" - - # modify settings - workspace.settings.modify_bootstrap_setting('remote_filesystem', 0) - workspace.settings.modify_bootstrap_setting('wait_for_connect', wait_for_connect) - workspace.settings.modify_bootstrap_setting('remote_ip', '0.36.27.18') - workspace.settings.modify_bootstrap_setting('additional_setting', 'value1') - - # verify files are different - assert not filecmp.cmp(bootstrap_settings, bootstrap_settings_backup), "Modified bootstrap settings and backup" \ - " are equal, they should be different" - - # restore backup - workspace.settings.restore_bootstrap_settings(backup_path) - - # verify files match - assert filecmp.cmp(bootstrap_settings, bootstrap_settings_backup), "Restored bootstrap settings and backup " \ - "are different, they should be equal" diff --git a/Tools/LyTestTools/tests/unit/test_abstract_resource_locator.py b/Tools/LyTestTools/tests/unit/test_abstract_resource_locator.py index b746099981..4baa7ee742 100644 --- a/Tools/LyTestTools/tests/unit/test_abstract_resource_locator.py +++ b/Tools/LyTestTools/tests/unit/test_abstract_resource_locator.py @@ -134,7 +134,7 @@ class TestAbstractResourceLocator(object): def test_Cache_IsCalled_ReturnsCachePath(self): mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator( mock_build_directory, mock_project) - expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'Cache') + expected_path = os.path.join(mock_abstract_resource_locator.cache()) assert mock_abstract_resource_locator.cache() == expected_path @@ -178,7 +178,7 @@ class TestAbstractResourceLocator(object): def test_AssetProcessorConfigFile_IsCalled_ReturnsAssetProcessorConfigFilePath(self): mock_abstract_resource_locator = abstract_resource_locator.AbstractResourceLocator( mock_build_directory, mock_project) - expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'AssetProcessorPlatformConfig.ini') + expected_path = os.path.join(mock_abstract_resource_locator.dev(), 'AssetProcessorPlatformConfig.setreg') assert mock_abstract_resource_locator.asset_processor_config_file() == expected_path diff --git a/Tools/LyTestTools/tests/unit/test_asset_processor.py b/Tools/LyTestTools/tests/unit/test_asset_processor.py index dadb21931d..d59b0412ab 100644 --- a/Tools/LyTestTools/tests/unit/test_asset_processor.py +++ b/Tools/LyTestTools/tests/unit/test_asset_processor.py @@ -60,7 +60,7 @@ class TestAssetProcessor(object): under_test.start(connect_to_ap=True) assert under_test._ap_proc is not None - mock_popen.assert_called_once_with([mock_ap_path, '--zeroAnalysisMode', '--gamefolder', 'AutomatedTesting', + mock_popen.assert_called_once_with([mock_ap_path, '--zeroAnalysisMode', '--regset="/Amazon/AzCore/Bootstrap/project_path=AutomatedTesting"', '--acceptInput', '--platforms', 'bar'], cwd=os.path.dirname(mock_ap_path)) mock_connect.assert_called() @@ -105,8 +105,8 @@ class TestAssetProcessor(object): @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') @mock.patch('subprocess.run') def test_BatchProcess_NoFastscanBatchCompletes_Success(self, mock_run, mock_workspace): - under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) mock_workspace.project = None + under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) apb_path = mock_workspace.paths.asset_processor_batch() mock_run.return_value.returncode = 0 result, _ = under_test.batch_process(1, False) @@ -118,23 +118,23 @@ class TestAssetProcessor(object): @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') @mock.patch('subprocess.run') def test_BatchProcess_FastscanBatchCompletes_Success(self, mock_run, mock_workspace): - under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) mock_workspace.project = 'AutomatedTesting' + under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) apb_path = mock_workspace.paths.asset_processor_batch() mock_run.return_value.returncode = 0 result = under_test.batch_process(1, True) assert result - mock_run.assert_called_once_with([apb_path, '--zeroAnalysisMode', '--gamefolder', 'AutomatedTesting'], + mock_run.assert_called_once_with([apb_path, '--zeroAnalysisMode', '--regset="/Amazon/AzCore/Bootstrap/project_path=AutomatedTesting"'], close_fds=True, capture_output=False, timeout=1) @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') @mock.patch('subprocess.run') def test_BatchProcess_ReturnCodeFail_Failure(self, mock_run, mock_workspace): - under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) mock_workspace.project = None + under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) apb_path = mock_workspace.paths.asset_processor_batch() mock_run.return_value.returncode = 1 @@ -145,42 +145,11 @@ class TestAssetProcessor(object): @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') - @mock.patch('os.path.isfile') - @mock.patch('ly_test_tools.lumberyard.asset_processor.file_system.unlock_file') - def test_EnableAssetProcessorPlatform_PlatformInConfig_ConfigUpdated(self, mock_unlock, mock_isfile, - mock_workspace): - mock_isfile.return_value = True + def test_EnableAssetProcessorPlatform_AssetProcessorObject_Updated(self, mock_workspace): under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) - apconfig_path = mock_workspace.paths.asset_processor_config_file() - - mock_config_content = '[Platforms]\n;foo\n;bar\n[Other]\nsomething\n' - - mock_open_config = mock.mock_open(read_data=mock_config_content) - - patcher = mock.patch('builtins.open', mock_open_config) - patcher.start() under_test.enable_asset_processor_platform('foo') - - mock_unlock.assert_called_once_with(apconfig_path) - mock_open_config.assert_called_once_with(apconfig_path, 'r+') - file_handle = mock_open_config() - file_handle.writelines.assert_called_once_with(['[Platforms]\n', 'foo\n', ';bar\n', '[Other]\n', 'something\n']) - patcher.stop() - - @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') - @mock.patch('os.path.isfile') - @mock.patch('ly_test_tools.lumberyard.asset_processor.file_system.unlock_file') - def test_EnableAssetProcessorPlatform_FileDoesNotExist_ErrorRaised(self, mock_unlock, mock_isfile, mock_workspace): - mock_isfile.return_value = False - under_test = ly_test_tools.lumberyard.asset_processor.AssetProcessor(mock_workspace) - apconfig_path = mock_workspace.paths.asset_processor_config_file() - - with pytest.raises(IOError): - under_test.enable_asset_processor_platform('foo') - - mock_isfile.assert_called_once_with(apconfig_path) - mock_unlock.assert_not_called() + assert "foo" in under_test._enabled_platform_overrides @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') def test_BackupAPSettings_Called_CallsBackupAPSettings(self, mock_workspace): diff --git a/Tools/LyTestTools/tests/unit/test_launcher_android.py b/Tools/LyTestTools/tests/unit/test_launcher_android.py index ab566558e9..55684822fe 100644 --- a/Tools/LyTestTools/tests/unit/test_launcher_android.py +++ b/Tools/LyTestTools/tests/unit/test_launcher_android.py @@ -234,7 +234,6 @@ class TestAndroidLauncher: mock_workspace.shader_compiler.stop.assert_called_once() @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict') - @mock.patch('ly_test_tools.lumberyard.settings.LySettings.modify_bootstrap_setting', mock.MagicMock) @mock.patch('ly_test_tools.lumberyard.settings.LySettings.modify_platform_setting', mock.MagicMock) def test_ConfigureSettings_DefaultValues_SetsValues(self, mock_config): mock_config.return_value = VALID_ANDROID_CONFIG @@ -243,7 +242,6 @@ class TestAndroidLauncher: launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"]) launcher.configure_settings() - assert mock_workspace.settings.modify_bootstrap_setting.call_count == 6 assert mock_workspace.settings.modify_platform_setting.call_count == 8 @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict') diff --git a/Tools/LyTestTools/tests/unit/test_manager_platforms_mac.py b/Tools/LyTestTools/tests/unit/test_manager_platforms_mac.py index 4a4e4a75cf..0b5bbd6117 100644 --- a/Tools/LyTestTools/tests/unit/test_manager_platforms_mac.py +++ b/Tools/LyTestTools/tests/unit/test_manager_platforms_mac.py @@ -59,7 +59,7 @@ class TestMacResourceLocator(object): def test_ProjectLog_HasPath_ReturnsPath(self): expected = os.path.join( - mac_resource_locator.platform_cache(), + mac_resource_locator.project(), 'user', 'log') @@ -67,7 +67,7 @@ class TestMacResourceLocator(object): def test_ProjectScreenshots_HasPath_ReturnsPath(self): expected = os.path.join( - mac_resource_locator.platform_cache(), + mac_resource_locator.project(), 'user', 'ScreenShots') diff --git a/Tools/LyTestTools/tests/unit/test_manager_platforms_windows.py b/Tools/LyTestTools/tests/unit/test_manager_platforms_windows.py index c58a439404..ddfb8df907 100644 --- a/Tools/LyTestTools/tests/unit/test_manager_platforms_windows.py +++ b/Tools/LyTestTools/tests/unit/test_manager_platforms_windows.py @@ -64,7 +64,7 @@ class TestWindowsResourceLocator(object): def test_ProjectLog_HasPath_ReturnsPath(self): expected = os.path.join( - windows_resource_locator.platform_cache(), + windows_resource_locator.project(), 'user', 'log') @@ -72,7 +72,7 @@ class TestWindowsResourceLocator(object): def test_ProjectScreenshots_HasPath_ReturnsPath(self): expected = os.path.join( - windows_resource_locator.platform_cache(), + windows_resource_locator.project(), 'user', 'ScreenShots') diff --git a/Tools/RemoteConsole/ly_remote_console/tests/CMakeLists.txt b/Tools/RemoteConsole/ly_remote_console/tests/CMakeLists.txt index 806e18b739..c7352da3a0 100644 --- a/Tools/RemoteConsole/ly_remote_console/tests/CMakeLists.txt +++ b/Tools/RemoteConsole/ly_remote_console/tests/CMakeLists.txt @@ -17,7 +17,8 @@ ly_add_pytest( PATH ${CMAKE_CURRENT_LIST_DIR}/unit/ ) -if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_NAME) +get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME) +if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_TARGET_NAME) # Integration tests. # ly_add_pytest( # NAME RemoteConsole_IntegTests_periodic_no_gpu diff --git a/Tools/build/JenkinsScripts/build/Platform/Android/build_config.json b/Tools/build/JenkinsScripts/build/Platform/Android/build_config.json index 5c0c91537b..e4f86aea17 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Android/build_config.json +++ b/Tools/build/JenkinsScripts/build/Platform/Android/build_config.json @@ -1,4 +1,13 @@ { + "profile_pipe": { + "TAGS": [ + "default" + ], + "steps": [ + "profile", + "gradle" + ] + }, "metrics": { "TAGS":[ "weekly" @@ -11,7 +20,7 @@ }, "debug": { "TAGS":[ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND":"../Windows/build_ninja_windows.cmd", @@ -26,7 +35,6 @@ }, "profile": { "TAGS":[ - "default", "weekly-build-metrics", "daily-pipeline-metrics" ], @@ -42,7 +50,7 @@ }, "profile_nounity": { "TAGS":[ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND":"../Windows/build_ninja_windows.cmd", @@ -95,6 +103,7 @@ }, "release": { "TAGS":[ + "nightly", "weekly-build-metrics" ], "COMMAND":"../Windows/build_ninja_windows.cmd", @@ -109,7 +118,7 @@ }, "monolithic_release": { "TAGS":[ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND":"../Windows/build_ninja_windows.cmd", @@ -124,7 +133,6 @@ }, "gradle": { "TAGS":[ - "default", "weekly-build-metrics" ], "COMMAND":"gradle_windows.cmd", diff --git a/Tools/build/JenkinsScripts/build/Platform/Android/gradle_windows.cmd b/Tools/build/JenkinsScripts/build/Platform/Android/gradle_windows.cmd index 5ba42f7a61..4faff41bb2 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Android/gradle_windows.cmd +++ b/Tools/build/JenkinsScripts/build/Platform/Android/gradle_windows.cmd @@ -76,8 +76,8 @@ IF NOT EXIST %TMP% ( mkdir temp ) SET PYTHON=python\python.cmd -ECHO [ci_build] %PYTHON% cmake\Tools\Platform\Android\generate_android_project.py --dev-root=. --build-dir=%OUTPUT_DIRECTORY% -g %GAME_PROJECT% --gradle-install-path=%GRADLE_HOME% --cmake-install-path=%CMAKE_HOME% --ninja-install-path=%LY_NINJA_PATH% --third-party-path=%LY_3RDPARTY_PATH% --android-ndk-path=%LY_ANDROID_NDK% --android-sdk-path=%LY_ANDROID_SDK% --android-ndk-version=%ANDROID_NDK_PLATFORM% --android-sdk-version=%ANDROID_SDK_PLATFORM% -CALL %PYTHON% cmake\Tools\Platform\Android\generate_android_project.py --dev-root=. --build-dir=%OUTPUT_DIRECTORY% -g %GAME_PROJECT% --gradle-install-path=%GRADLE_HOME% --cmake-install-path=%CMAKE_HOME% --ninja-install-path=%LY_NINJA_PATH% --third-party-path=%LY_3RDPARTY_PATH% --android-ndk-path=%LY_ANDROID_NDK% --android-sdk-path=%LY_ANDROID_SDK% --android-ndk-version=%ANDROID_NDK_PLATFORM% --android-sdk-version=%ANDROID_SDK_PLATFORM% +ECHO [ci_build] %PYTHON% cmake\Tools\Platform\Android\generate_android_project.py --project-path=%GAME_PROJECT% --engine-root=. --build-dir=%OUTPUT_DIRECTORY% --gradle-install-path=%GRADLE_HOME% --cmake-install-path=%CMAKE_HOME% --ninja-install-path=%LY_NINJA_PATH% --third-party-path=%LY_3RDPARTY_PATH% --android-ndk-path=%LY_ANDROID_NDK% --android-sdk-path=%LY_ANDROID_SDK% --android-ndk-version=%ANDROID_NDK_PLATFORM% --android-sdk-version=%ANDROID_SDK_PLATFORM% +CALL %PYTHON% cmake\Tools\Platform\Android\generate_android_project.py --project-path="%GAME_PROJECT%" --engine-root=. --build-dir="%OUTPUT_DIRECTORY%" --gradle-install-path="%GRADLE_HOME%" --cmake-install-path="%CMAKE_HOME%" --ninja-install-path="%LY_NINJA_PATH%" --third-party-path="%LY_3RDPARTY_PATH%" --android-ndk-path="%LY_ANDROID_NDK%" --android-sdk-path="%LY_ANDROID_SDK%" --android-ndk-version=%ANDROID_NDK_PLATFORM% --android-sdk-version=%ANDROID_SDK_PLATFORM% IF NOT %ERRORLEVEL%==0 GOTO :error PUSHD %OUTPUT_DIRECTORY% diff --git a/Tools/build/JenkinsScripts/build/Platform/Linux/asset_linux.sh b/Tools/build/JenkinsScripts/build/Platform/Linux/asset_linux.sh index ac8b9e46d9..325e09f57a 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Linux/asset_linux.sh +++ b/Tools/build/JenkinsScripts/build/Platform/Linux/asset_linux.sh @@ -34,8 +34,8 @@ fi for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g") do - echo [ci_build] ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --gamefolder=$project --platforms=$ASSET_PROCESSOR_PLATFORMS - ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --gamefolder=$project --platforms=$ASSET_PROCESSOR_PLATFORMS + echo [ci_build] ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --project-path=$project --platforms=$ASSET_PROCESSOR_PLATFORMS + ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --project-path=$project --platforms=$ASSET_PROCESSOR_PLATFORMS done popd diff --git a/Tools/build/JenkinsScripts/build/Platform/Linux/build_config.json b/Tools/build/JenkinsScripts/build/Platform/Linux/build_config.json index f781acaeaf..285249056b 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Linux/build_config.json +++ b/Tools/build/JenkinsScripts/build/Platform/Linux/build_config.json @@ -1,12 +1,11 @@ { "profile_pipe": { "TAGS": [ - "default", - "weekly-build-metrics", - "daily-pipeline-metrics" + "default" ], "steps": [ "profile", + "asset_profile", "test_profile" ] }, @@ -22,7 +21,7 @@ }, "debug": { "TAGS": [ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND": "build_linux.sh", @@ -35,7 +34,10 @@ } }, "profile": { - "TAGS": [], + "TAGS": [ + "daily-pipeline-metrics", + "weekly-build-metrics" + ], "COMMAND": "build_linux.sh", "PARAMETERS": { "CONFIGURATION": "profile", @@ -47,7 +49,7 @@ }, "profile_nounity": { "TAGS": [ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND": "build_linux.sh", @@ -60,7 +62,10 @@ } }, "test_profile": { - "TAGS": [], + "TAGS": [ + "daily-pipeline-metrics", + "weekly-build-metrics" + ], "COMMAND": "build_test_linux.sh", "PARAMETERS": { "CONFIGURATION": "profile", @@ -73,7 +78,6 @@ }, "asset_profile": { "TAGS": [ - "default", "weekly-build-metrics" ], "COMMAND": "build_asset_linux.sh", @@ -139,6 +143,7 @@ }, "release": { "TAGS": [ + "nightly", "weekly-build-metrics" ], "COMMAND": "build_linux.sh", @@ -152,7 +157,7 @@ }, "monolithic_release": { "TAGS": [ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND": "build_linux.sh", diff --git a/Tools/build/JenkinsScripts/build/Platform/Mac/asset_mac.sh b/Tools/build/JenkinsScripts/build/Platform/Mac/asset_mac.sh index 2ecdda9c53..1750521b02 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Mac/asset_mac.sh +++ b/Tools/build/JenkinsScripts/build/Platform/Mac/asset_mac.sh @@ -34,8 +34,8 @@ fi for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g") do - echo [ci_build] ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --gamefolder=$project --platforms=$ASSET_PROCESSOR_PLATFORMS - ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --gamefolder=$project --platforms=$ASSET_PROCESSOR_PLATFORMS + echo [ci_build] ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --project-path=$project --platforms=$ASSET_PROCESSOR_PLATFORMS + ${ASSET_PROCESSOR_BINARY} $ASSET_PROCESSOR_OPTIONS --project-path=$project --platforms=$ASSET_PROCESSOR_PLATFORMS done popd \ No newline at end of file diff --git a/Tools/build/JenkinsScripts/build/Platform/Mac/build_config.json b/Tools/build/JenkinsScripts/build/Platform/Mac/build_config.json index 8f6faa7d61..c72d8bc526 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Mac/build_config.json +++ b/Tools/build/JenkinsScripts/build/Platform/Mac/build_config.json @@ -1,8 +1,7 @@ { "profile_pipe": { "TAGS": [ - "nightly", - "weekly-build-metrics" + "nightly" ], "steps": [ "profile", @@ -35,7 +34,8 @@ }, "profile": { "TAGS": [ - "daily-pipeline-metrics" + "daily-pipeline-metrics", + "weekly-build-metrics" ], "COMMAND": "build_mac.sh", "PARAMETERS": { @@ -61,7 +61,9 @@ } }, "asset_profile": { - "TAGS": [], + "TAGS": [ + "weekly-build-metrics" + ], "COMMAND": "build_asset_mac.sh", "PARAMETERS": { "CONFIGURATION": "profile", @@ -125,6 +127,7 @@ }, "release": { "TAGS": [ + "nightly", "weekly-build-metrics" ], "COMMAND": "build_mac.sh", diff --git a/Tools/build/JenkinsScripts/build/Platform/Windows/asset_windows.cmd b/Tools/build/JenkinsScripts/build/Platform/Windows/asset_windows.cmd index 4768d71e16..4a5b5cff1d 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Windows/asset_windows.cmd +++ b/Tools/build/JenkinsScripts/build/Platform/Windows/asset_windows.cmd @@ -33,8 +33,8 @@ IF NOT EXIST %ASSET_PROCESSOR_BINARY% ( ) FOR %%P in (%CMAKE_LY_PROJECTS%) do ( - ECHO [ci_build] %ASSET_PROCESSOR_BINARY% %ASSET_PROCESSOR_OPTIONS% --gamefolder=%%P --platforms=%ASSET_PROCESSOR_PLATFORMS% - %ASSET_PROCESSOR_BINARY% %ASSET_PROCESSOR_OPTIONS% --gamefolder=%%P --platforms=%ASSET_PROCESSOR_PLATFORMS% + ECHO [ci_build] %ASSET_PROCESSOR_BINARY% %ASSET_PROCESSOR_OPTIONS% --project-path=%%P --platforms=%ASSET_PROCESSOR_PLATFORMS% + %ASSET_PROCESSOR_BINARY% %ASSET_PROCESSOR_OPTIONS% --project-path=%%P --platforms=%ASSET_PROCESSOR_PLATFORMS% IF NOT !ERRORLEVEL!==0 GOTO :popd_error ) diff --git a/Tools/build/JenkinsScripts/build/Platform/Windows/build_config.json b/Tools/build/JenkinsScripts/build/Platform/Windows/build_config.json index c85d5f3901..9ec9fa5ad2 100644 --- a/Tools/build/JenkinsScripts/build/Platform/Windows/build_config.json +++ b/Tools/build/JenkinsScripts/build/Platform/Windows/build_config.json @@ -10,8 +10,7 @@ }, "debug_vs2019_pipe": { "TAGS": [ - "default", - "weekly-build-metrics" + "nightly" ], "steps": [ "debug_vs2019", @@ -20,9 +19,7 @@ }, "profile_vs2019_pipe": { "TAGS": [ - "default", - "daily-pipeline-metrics", - "weekly-build-metrics" + "default" ], "steps": [ "profile_vs2019", @@ -31,7 +28,9 @@ ] }, "scrubbing": { - "TAGS": [], + "TAGS": [ + "weekly-build-metrics" + ], "COMMAND": "python_windows.cmd", "PARAMETERS": { "SCRIPT_PATH": "Tools/build/JenkinsScripts/build/scrubbing_job.py" @@ -39,7 +38,7 @@ }, "validation": { "TAGS": [ - "" + "weekly-build-metrics" ], "COMMAND": "python_windows.cmd", "PARAMETERS": { @@ -77,7 +76,9 @@ } }, "debug_vs2019": { - "TAGS": [], + "TAGS": [ + "weekly-build-metrics" + ], "COMMAND": "build_windows.cmd", "PARAMETERS": { "CONFIGURATION": "debug", @@ -89,7 +90,9 @@ } }, "test_debug_vs2019": { - "TAGS": [], + "TAGS": [ + "weekly-build-metrics" + ], "COMMAND": "build_test_windows.cmd", "PARAMETERS": { "CONFIGURATION": "debug", @@ -98,12 +101,14 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", - "CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\"" + "CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -T Test" } }, "profile_vs2019": { "TAGS": [ - "project" + "project", + "daily-pipeline-metrics", + "weekly-build-metrics" ], "COMMAND": "build_windows.cmd", "PARAMETERS": { @@ -117,7 +122,7 @@ }, "profile_vs2019_nounity": { "TAGS": [ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND": "build_windows.cmd", @@ -131,7 +136,10 @@ } }, "test_cpu_profile_vs2019": { - "TAGS": [], + "TAGS": [ + "daily-pipeline-metrics", + "weekly-build-metrics" + ], "COMMAND": "build_test_windows.cmd", "PARAMETERS": { "CONFIGURATION": "profile", @@ -140,7 +148,7 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", - "CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\"" + "CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test" } }, "test_gpu_profile_vs2019": { @@ -156,11 +164,13 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", - "CTEST_OPTIONS": "-L \"(SUITE_smoke_REQUIRES_gpu|SUITE_main_REQUIRES_gpu)\"" + "CTEST_OPTIONS": "-L \"(SUITE_smoke_REQUIRES_gpu|SUITE_main_REQUIRES_gpu)\" -T Test" } }, "asset_profile_vs2019": { - "TAGS": [], + "TAGS": [ + "weekly-build-metrics" + ], "COMMAND": "build_asset_windows.cmd", "PARAMETERS": { "CONFIGURATION": "profile", @@ -207,7 +217,7 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", - "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"" + "CTEST_OPTIONS": "-L \"(SUITE_periodic)\" -T Test" } }, "sandbox_test_profile_vs2019": { @@ -226,7 +236,7 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_sandbox", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", - "CTEST_OPTIONS": "-L \"(SUITE_sandbox)\"" + "CTEST_OPTIONS": "-L \"(SUITE_sandbox)\" -T Test" } }, "benchmark_test_profile_vs2019": { @@ -242,7 +252,7 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", - "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"" + "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\" -T Test" } }, "release_vs2019": { @@ -262,7 +272,7 @@ }, "monolithic_release_vs2019": { "TAGS": [ - "default", + "nightly", "weekly-build-metrics" ], "COMMAND": "build_windows.cmd", diff --git a/Tools/build/JenkinsScripts/build/Platform/iOS/build_config.json b/Tools/build/JenkinsScripts/build/Platform/iOS/build_config.json index 68ac479c26..4961ee6e10 100644 --- a/Tools/build/JenkinsScripts/build/Platform/iOS/build_config.json +++ b/Tools/build/JenkinsScripts/build/Platform/iOS/build_config.json @@ -1,14 +1,4 @@ { - "profile_pipe": { - "TAGS": [ - "nightly", - "weekly-build-metrics" - ], - "steps": [ - "profile", - "asset_profile" - ] - }, "metrics": { "TAGS": [ "weekly" @@ -36,7 +26,9 @@ }, "profile": { "TAGS": [ - "daily-pipeline-metrics" + "nightly", + "daily-pipeline-metrics", + "weekly-build-metrics" ], "COMMAND": "../Mac/build_mac.sh", "PARAMETERS": { @@ -64,7 +56,10 @@ } }, "asset_profile": { - "TAGS": [], + "TAGS": [ + "nightly", + "weekly-build-metrics" + ], "COMMAND": "../Mac/build_asset_mac.sh", "PARAMETERS": { "CONFIGURATION": "profile", diff --git a/Tools/build/JenkinsScripts/build/cmake_package.py b/Tools/build/JenkinsScripts/build/cmake_package.py index 2b2030aee7..5f9664d2b1 100644 --- a/Tools/build/JenkinsScripts/build/cmake_package.py +++ b/Tools/build/JenkinsScripts/build/cmake_package.py @@ -67,7 +67,7 @@ def override_bootstrap_cfg(package_env): print('Override values in bootstrap.cfg') engine_root = package_env.get('ENGINE_ROOT') bootstrap_path = os.path.join(engine_root, 'bootstrap.cfg') - replace_values = {'sys_game_folder':'{}'.format(package_env.get('BOOTSTRAP_CFG_GAME_FOLDER'))} + replace_values = {'project_path':'{}'.format(package_env.get('BOOTSTRAP_CFG_GAME_FOLDER'))} try: with open(bootstrap_path, 'r') as bootstrap_cfg: content = bootstrap_cfg.read() diff --git a/bootstrap.cfg b/bootstrap.cfg index 6775ae73a6..6443a4b207 100644 --- a/bootstrap.cfg +++ b/bootstrap.cfg @@ -82,4 +82,3 @@ mac_wait_for_connect=0 -- This time is dependent on Machine load as well as how long it takes for the new AP instance to initialize -- A debug AP takes longer to start up than a profile AP -- launch_ap_timeout=15 - diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index da8fd6f981..197d48eee6 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -296,13 +296,3 @@ list(APPEND CMAKE_MODULE_PATH ${pal_dir}) ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake) ly_get_absolute_pal_filename(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}) ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) - - -# we must include this here to bring the package system up before we actually start calling -# find_package. Otherwise the find_package may not actually find the packages it needs -include(cmake/3rdPartyPackages.cmake) - -if(PAL_TRAIT_BUILD_HOST_TOOLS) - # Importing this globally to handle AUTOMOC, AUTOUIC, AUTORCC - find_package(Qt REQUIRED MODULE) -endif() diff --git a/cmake/3rdParty/FindAWSNativeSDK.cmake b/cmake/3rdParty/FindAWSNativeSDK.cmake deleted file mode 100644 index d0d5abb50f..0000000000 --- a/cmake/3rdParty/FindAWSNativeSDK.cmake +++ /dev/null @@ -1,118 +0,0 @@ -# -# 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. -# - -set(AWSNATIVESDK_PACKAGE_NAME AWSNativeSDK) -set(AWSNATIVESDK_3RDPARTY_DIRECTORY AWS/AWSNativeSDK) -set(AWSNATIVESDK_PACKAGE_VERSION 1.7.167-az.2) -set(AWSNATIVESDK_COMPILEDEFINITIONS AWS_CUSTOM_MEMORY_MANAGEMENT PLATFORM_SUPPORTS_AWS_NATIVE_SDK) - -set(AWSNATIVESDK_MODULES - Common - Core - EventStream - Checksums - AcessManagement - CognitoIdentity - CognitoIdp - DeviceFarm - DynamoDB - GameLift - IdentityManagement - Kinesis - Lambda - MobileAnalytics - Queues - S3 - SNS - SQS - STS - Transfer -) -foreach(awsmodule ${AWSNATIVESDK_MODULES}) - ly_add_external_target( - NAME ${awsmodule} - PACKAGE ${AWSNATIVESDK_PACKAGE_NAME} - VERSION ${AWSNATIVESDK_PACKAGE_VERSION} - 3RDPARTY_DIRECTORY ${AWSNATIVESDK_3RDPARTY_DIRECTORY} - INCLUDE_DIRECTORIES include - COMPILE_DEFINITIONS ${AWSNATIVESDK_COMPILEDEFINITIONS} - ) -endforeach() - -# Then we have some groupings by functionality. We define a function here to make this easier to define -include(CMakeParseArguments) -function(ly_aws_addgroup) - cmake_parse_arguments(ly_aws_add "" "NAME" "BUILD_DEPENDENCIES" ${ARGN}) - ly_add_external_target( - NAME ${ly_aws_add_NAME} - PACKAGE ${AWSNATIVESDK_PACKAGE_NAME} - VERSION ${AWSNATIVESDK_PACKAGE_VERSION} - 3RDPARTY_DIRECTORY ${AWSNATIVESDK_3RDPARTY_DIRECTORY} - INCLUDE_DIRECTORIES include - COMPILE_DEFINITIONS ${AWSNATIVESDK_COMPILEDEFINITIONS} - BUILD_DEPENDENCIES ${ly_aws_add_BUILD_DEPENDENCIES} - ) -endfunction() - -# And here we define the groupings -ly_aws_addgroup(NAME Dependencies - BUILD_DEPENDENCIES - 3rdParty::AWSNativeSDK::Checksums - 3rdParty::AWSNativeSDK::Common - 3rdParty::AWSNativeSDK::EventStream -) - -ly_aws_addgroup(NAME IdentityMetrics - BUILD_DEPENDENCIES - 3rdParty::AWSNativeSDK::Dependencies - 3rdParty::AWSNativeSDK::CognitoIdentity - 3rdParty::AWSNativeSDK::CognitoIdp - 3rdParty::AWSNativeSDK::Core - 3rdParty::AWSNativeSDK::IdentityManagement - 3rdParty::AWSNativeSDK::STS - 3rdParty::AWSNativeSDK::MobileAnalytics -) - -ly_aws_addgroup(NAME IdentityLambda - BUILD_DEPENDENCIES - 3rdParty::AWSNativeSDK::Dependencies - 3rdParty::AWSNativeSDK::CognitoIdentity - 3rdParty::AWSNativeSDK::CognitoIdp - 3rdParty::AWSNativeSDK::Core - 3rdParty::AWSNativeSDK::IdentityManagement - 3rdParty::AWSNativeSDK::Lambda - 3rdParty::AWSNativeSDK::STS -) - -ly_aws_addgroup(NAME GameLiftClient - BUILD_DEPENDENCIES - 3rdParty::AWSNativeSDK::Core - 3rdParty::AWSNativeSDK::GameLift - 3rdParty::AWSNativeSDK::Dependencies -) - -ly_aws_addgroup(NAME AWSClientAuth - BUILD_DEPENDENCIES - 3rdParty::AWSNativeSDK::Dependencies - 3rdParty::AWSNativeSDK::CognitoIdentity - 3rdParty::AWSNativeSDK::CognitoIdp - 3rdParty::AWSNativeSDK::STS - 3rdParty::AWSNativeSDK::IdentityManagement -) - -ly_aws_addgroup(NAME AWSCore - BUILD_DEPENDENCIES - 3rdParty::AWSNativeSDK::Dependencies - 3rdParty::AWSNativeSDK::Core - 3rdParty::AWSNativeSDK::DynamoDB - 3rdParty::AWSNativeSDK::Lambda - 3rdParty::AWSNativeSDK::S3 -) \ No newline at end of file diff --git a/cmake/3rdParty/FindQt.cmake b/cmake/3rdParty/FindQt.cmake deleted file mode 100644 index e8de7cd64f..0000000000 --- a/cmake/3rdParty/FindQt.cmake +++ /dev/null @@ -1,173 +0,0 @@ -# -# 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. -# - -if(TARGET 3rdParty::Qt::Core) # Check we are not called multiple times - return() -endif() - -set(QT_PACKAGE_NAME Qt) -set(QT_PACKAGE_VERSION 5.15.1.2-az) - -set(BASE_PATH "${LY_3RDPARTY_PATH}/${QT_PACKAGE_NAME}/${QT_PACKAGE_VERSION}") -if(NOT EXISTS ${BASE_PATH}) - message(FATAL_ERROR "Cannot find 3rdParty library ${QT_PACKAGE_NAME} on path ${BASE_PATH}") -endif() - -set(QT5_COMPONENTS - Core - Concurrent - Gui - LinguistTools - Network - OpenGL - Svg - Test - WebEngineWidgets - Widgets - Xml -) - -include(${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/Qt_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) - -list(APPEND CMAKE_PREFIX_PATH ${QT_LIB_PATH}/cmake/Qt5) - -# Clear the cache for found DIRs -unset(Qt5_DIR CACHE) -foreach(component ${QT5_COMPONENTS}) - unset(Qt5${component}_DIR CACHE) -endforeach() -unset(Qt5Positioning_DIR CACHE) -unset(Qt5PrintSupport_DIR CACHE) -unset(Qt5WebChannel_DIR CACHE) -unset(Qt5WebEngineCore_DIR CACHE) - -# Populate the Qt5 configurations -find_package(Qt5 - COMPONENTS ${QT5_COMPONENTS} - REQUIRED - NO_CMAKE_PACKAGE_REGISTRY -) -mark_as_advanced(Qt5_DIR) # Hiding from GUI -mark_as_advanced(Qt5LinguistTools_DIR) # Hiding from GUI, this variable comes from the LinguistTools module - -# Now create libraries that wrap the dependency so we can refer to them in our format -foreach(component ${QT5_COMPONENTS}) - if(TARGET Qt5::${component}) - - get_target_property(system_includes Qt5::${component} INTERFACE_INCLUDE_DIRECTORIES) - set_target_properties(Qt5::${component} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "") # Clear it in case someone refers to it - - ly_target_include_system_directories(TARGET Qt5::${component} - INTERFACE "${system_includes}" - ) - - add_library(3rdParty::Qt::${component} INTERFACE IMPORTED) - set_target_properties(3rdParty::Qt::${component} PROPERTIES - INTERFACE_LINK_LIBRARIES Qt5::${component} - INTERFACE_COMPILE_DEFINITIONS QT_NO_EXCEPTIONS - ) - mark_as_advanced(Qt5${component}_DIR) # Hiding from GUI - - endif() -endforeach() - -# Some extra DIR variables we want to hide from GUI -mark_as_advanced(Qt5Positioning_DIR) -mark_as_advanced(Qt5PrintSupport_DIR) -mark_as_advanced(Qt5WebChannel_DIR) -mark_as_advanced(Qt5WebEngineCore_DIR) - -# Special case for Qt::Gui, we are using the private headers... -ly_target_include_system_directories(TARGET 3rdParty::Qt::Gui - INTERFACE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}" -) - -# Another special case: Qt:Widgets, we are also using private headers -ly_target_include_system_directories(TARGET 3rdParty::Qt::Widgets - INTERFACE "${Qt5Widgets_PRIVATE_INCLUDE_DIRS}" -) - -# UIC executable -unset(QT_UIC_EXECUTABLE CACHE) -find_program(QT_UIC_EXECUTABLE uic HINTS "${QT_PATH}/bin") -mark_as_advanced(QT_UIC_EXECUTABLE) # Hiding from GUI - -#! ly_qt_uic_target: handles qt's ui files by injecting uic generation -# -# AUTOUIC has issues to detect changes in UIC files and trigger regeneration: -# https://gitlab.kitware.com/cmake/cmake/-/issues/18741 -# So instead, we are going to manually wrap the files. We dont use qt5_wrap_ui because -# it outputs to ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h and we want to follow the -# same folder structure that AUTOUIC uses -# -function(ly_qt_uic_target TARGET) - - get_target_property(all_ui_sources ${TARGET} SOURCES) - list(FILTER all_ui_sources INCLUDE REGEX "^.*\\.ui$") - if(NOT all_ui_sources) - message(FATAL_ERROR "Target ${TARGET} contains AUTOUIC but doesnt have any .ui file") - endif() - - if(AUTOGEN_BUILD_DIR) - set(gen_dir ${AUTOGEN_BUILD_DIR}) - else() - set(gen_dir ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_autogen/include) - endif() - - foreach(ui_source ${all_ui_sources}) - - get_filename_component(filename ${ui_source} NAME_WE) - get_filename_component(dir ${ui_source} DIRECTORY) - if(IS_ABSOLUTE ${dir}) - file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir}) - endif() - - set(outfolder ${gen_dir}/${dir}) - set(outfile ${outfolder}/ui_${filename}.h) - get_filename_component(infile ${ui_source} ABSOLUTE) - - file(MAKE_DIRECTORY ${outfolder}) - add_custom_command(OUTPUT ${outfile} - COMMAND ${QT_UIC_EXECUTABLE} -o ${outfile} ${infile} - MAIN_DEPENDENCY ${infile} VERBATIM - COMMENT "UIC ${infile}" - ) - - set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC TRUE) - set_source_files_properties(${outfile} PROPERTIES - SKIP_AUTOMOC TRUE - SKIP_AUTOUIC TRUE - GENERATED TRUE - ) - list(APPEND all_ui_wrapped_sources ${outfile}) - - endforeach() - - # Add files to the target - target_sources(${TARGET} PRIVATE ${all_ui_wrapped_sources}) - source_group("Generated Files" FILES ${all_ui_wrapped_sources}) - - # Add include directories relative to the generated folder - # query for the property first to avoid the "NOTFOUND" in a list - get_property(has_includes TARGET ${TARGET} PROPERTY INCLUDE_DIRECTORIES SET) - if(has_includes) - get_property(all_include_directories TARGET ${TARGET} PROPERTY INCLUDE_DIRECTORIES) - foreach(dir ${all_include_directories}) - if(IS_ABSOLUTE ${dir}) - file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir}) - endif() - list(APPEND new_includes ${gen_dir}/${dir}) - endforeach() - endif() - list(APPEND new_includes ${gen_dir}) - target_include_directories(${TARGET} PRIVATE ${new_includes}) - -endfunction() diff --git a/cmake/3rdParty/Platform/Android/AWSNativeSDK_android.cmake b/cmake/3rdParty/Platform/Android/AWSNativeSDK_android.cmake deleted file mode 100644 index a516cade66..0000000000 --- a/cmake/3rdParty/Platform/Android/AWSNativeSDK_android.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# -# 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. -# - -if(LY_MONOLITHIC_GAME) - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/lib/android/arm64-v8a/$,Debug,Release>) - set(AWSNATIVE_SDK_LIB_EXTENSION a) - set(AWSNATIVESDK_BUILD_DEPENDENCIES - ${AWSNATIVE_SDK_LIB_PATH}/dependencies/libcurl.a - ${AWSNATIVE_SDK_LIB_PATH}/dependencies/libssl.a - ${AWSNATIVE_SDK_LIB_PATH}/dependencies/libcrypto.a - ${AWSNATIVE_SDK_LIB_PATH}/dependencies/libz.a - ) -else() - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/bin/android/arm64-v8a/$,Debug,Release>) - set(AWSNATIVE_SDK_LIB_EXTENSION so) -endif() - -set(AWSNATIVESDK_CORE_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-core.${AWSNATIVE_SDK_LIB_EXTENSION}) -if(NOT LY_MONOLITHIC_GAME) - list(APPEND AWSNATIVESDK_CORE_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libcurl$,-d,>.${AWSNATIVE_SDK_LIB_EXTENSION}) -endif() - -set(AWSNATIVESDK_COMMON_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-common.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_EVENTSTREAM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-event-stream.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_CHECKSUMS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-checksums.${AWSNATIVE_SDK_LIB_EXTENSION}) - -set(AWSNATIVESDK_ACESSMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-access-management.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_COGNITOIDENTITY_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-identity.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_COGNITOIDP_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-idp.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_DYNAMODB_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-dynamodb.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_GAMELIFT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-gamelift.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-identity-management.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_KINESIS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-kinesis.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_LAMBDA_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-lambda.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_MOBILEANALYTICS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-mobileanalytics.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_QUEUES_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-queues.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_S3_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-s3.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_SNS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sns.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_SQS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sqs.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_STS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sts.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_TRANSFER_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-transfer.${AWSNATIVE_SDK_LIB_EXTENSION}) - -if(NOT LY_MONOLITHIC_GAME) - - list(JOIN AWSNATIVESDK_CORE_LIBS ";" AWSNATIVESDK_CORE_RUNTIME_DEPENDENCIES) - - set(AWSNATIVESDK_COMMON_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_COMMON_LIBS}) - set(AWSNATIVESDK_EVENTSTREAM_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_EVENTSTREAM_LIBS}) - set(AWSNATIVESDK_CHECKSUMS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_CHECKSUMS_LIBS}) - set(AWSNATIVESDK_ACCESSMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_ACESSMANAGEMENT_LIBS}) - set(AWSNATIVESDK_COGNITOIDENTITY_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_COGNITOIDENTITY_LIBS}) - set(AWSNATIVESDK_COGNITOIDP_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_COGNITOIDP_LIBS}) - set(AWSNATIVESDK_DYNAMODB_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_DYNAMODB_LIBS}) - set(AWSNATIVESDK_GAMELIFT_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_GAMELIFT_LIBS}) - set(AWSNATIVESDK_IDENTITYMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS}) - set(AWSNATIVESDK_KINESIS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_KINESIS_LIBS}) - set(AWSNATIVESDK_LAMBDA_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_LAMBDA_LIBS}) - set(AWSNATIVESDK_MOBILEANALYTICS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_MOBILEANALYTICS_LIBS}) - set(AWSNATIVESDK_QUEUES_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_QUEUES_LIBS}) - -endif() \ No newline at end of file diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index a40b652d66..47258b9a7f 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -20,6 +20,7 @@ ly_associate_package(PACKAGE_NAME lz4-r128-multiplatform TARGETS lz4 ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) # platform-specific: +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev1-android TARGETS AWSNativeSDK PACKAGE_HASH 3612d8397700cb3a585405440aec2a393843baa506ef8821d0a9b29162fb1854) ly_associate_package(PACKAGE_NAME PhysX-4.1.0.25992954-rev1-android TARGETS PhysX PACKAGE_HASH 9c494576c2d4ff04dee5a9e092fcd9d5af4b2845f15ffdfcaabb0dbc5b88a7a9) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-android TARGETS googletest PACKAGE_HASH 95671be75287a61c9533452835c3647e9c1b30f81b34b43bcb0ec1997cc23894) diff --git a/cmake/3rdParty/Platform/Android/cmake_android_files.cmake b/cmake/3rdParty/Platform/Android/cmake_android_files.cmake index 2a99a7a4a6..427ac93a18 100644 --- a/cmake/3rdParty/Platform/Android/cmake_android_files.cmake +++ b/cmake/3rdParty/Platform/Android/cmake_android_files.cmake @@ -10,7 +10,6 @@ # set(FILES - AWSNativeSDK_android.cmake BuiltInPackages_android.cmake civetweb_android.cmake expat_android.cmake diff --git a/cmake/3rdParty/Platform/Linux/AWSNativeSDK_linux.cmake b/cmake/3rdParty/Platform/Linux/AWSNativeSDK_linux.cmake deleted file mode 100644 index 7504e6c095..0000000000 --- a/cmake/3rdParty/Platform/Linux/AWSNativeSDK_linux.cmake +++ /dev/null @@ -1,73 +0,0 @@ -# -# 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. -# - -if(LY_MONOLITHIC_GAME) - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/lib/linux/$,Debug,Release>) - set(AWSNATIVE_SDK_LIB_EXTENSION a) -else() - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/bin/linux/$,Debug,Release>) - set(AWSNATIVE_SDK_LIB_EXTENSION so) - set(AWSNATIVESDK_COMMON_UNSTABLE_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-common.so.0unstable) - set(AWSNATIVESDK_EVENTSTREAM_UNSTABLE_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-event-stream.so.0unstable) -endif() - -set(AWSNATIVESDK_LIBS - curl # The one bundled with the aws sdk in 3rdParty doesn't use the right openssl -) - -set(AWSNATIVESDK_CORE_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-core.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_COMMON_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-common.${AWSNATIVE_SDK_LIB_EXTENSION} ${AWSNATIVESDK_COMMON_UNSTABLE_LIBS}) -set(AWSNATIVESDK_EVENTSTREAM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-event-stream.${AWSNATIVE_SDK_LIB_EXTENSION} ${AWSNATIVESDK_EVENTSTREAM_UNSTABLE_LIBS}) -set(AWSNATIVESDK_CHECKSUMS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-checksums.${AWSNATIVE_SDK_LIB_EXTENSION}) - -set(AWSNATIVESDK_ACESSMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-access-management.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_COGNITOIDENTITY_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-identity.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_COGNITOIDP_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-idp.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_DEVICEFARM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-devicefarm.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_DYNAMODB_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-dynamodb.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_GAMELIFT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-gamelift.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-identity-management.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_KINESIS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-kinesis.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_LAMBDA_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-lambda.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_MOBILEANALYTICS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-mobileanalytics.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_QUEUES_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-queues.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_S3_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-s3.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_SNS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sns.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_SQS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sqs.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_STS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sts.${AWSNATIVE_SDK_LIB_EXTENSION}) -set(AWSNATIVESDK_TRANSFER_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-transfer.${AWSNATIVE_SDK_LIB_EXTENSION}) - -if(NOT LY_MONOLITHIC_GAME) - - list(JOIN AWSNATIVESDK_CORE_LIBS ";" AWSNATIVESDK_CORE_RUNTIME_DEPENDENCIES) - - set(AWSNATIVESDK_COMMON_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_COMMON_LIBS}) - set(AWSNATIVESDK_EVENTSTREAM_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_EVENTSTREAM_LIBS}) - set(AWSNATIVESDK_CHECKSUMS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_CHECKSUMS_LIBS}) - set(AWSNATIVESDK_ACCESSMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_ACESSMANAGEMENT_LIBS}) - set(AWSNATIVESDK_COGNITOIDENTITY_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_COGNITOIDENTITY_LIBS}) - set(AWSNATIVESDK_COGNITOIDP_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_COGNITOIDP_LIBS}) - set(AWSNATIVESDK_DEVICEFARM_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_DEVICEFARM_LIBS}) - set(AWSNATIVESDK_DYNAMODB_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_DYNAMODB_LIBS}) - set(AWSNATIVESDK_GAMELIFT_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_GAMELIFT_LIBS}) - set(AWSNATIVESDK_IDENTITYMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS}) - set(AWSNATIVESDK_KINESIS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_KINESIS_LIBS}) - set(AWSNATIVESDK_LAMBDA_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_LAMBDA_LIBS}) - set(AWSNATIVESDK_MOBILEANALYTICS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_MOBILEANALYTICS_LIBS}) - set(AWSNATIVESDK_QUEUES_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_QUEUES_LIBS}) - - set(AWSNATIVESDK_S3_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_S3_LIBS}) - set(AWSNATIVESDK_SNS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_SNS_LIBS}) - set(AWSNATIVESDK_SQS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_SQS_LIBS}) - set(AWSNATIVESDK_STS_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_STS_LIBS}) - set(AWSNATIVESDK_TRANSFER_RUNTIME_DEPENDENCIES ${AWSNATIVESDK_TRANSFER_LIBS}) - -endif() diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 4de615d97f..28ed49e1d1 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -28,11 +28,13 @@ ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARG ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev3-multiplatform TARGETS PVRTexTool PACKAGE_HASH d9c7e21e03b03cb560da4793a91a0d384ea621757cf87a1a82c83bfca6b23f97) +ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev1-linux TARGETS AWSNativeSDK PACKAGE_HASH 3876457b5e3233b951ccd9bcf53df4b946041a7de2955eba647020d7ae46163d) ly_associate_package(PACKAGE_NAME PhysX-4.1.0.25992954-rev1-linux TARGETS PhysX PACKAGE_HASH e3ca36106a8dbf1524709f8bb82d520920ebd3ff3a92672d382efff406c75ee3) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-linux TARGETS mikkelsen PACKAGE_HASH 5973b1e71a64633588eecdb5b5c06ca0081f7be97230f6ef64365cbda315b9c8) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux TARGETS googletest PACKAGE_HASH 7b7ad330f369450c316a4c4592d17fbb4c14c731c95bd8f37757203e8c2bbc1b) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev1-linux TARGETS GoogleBenchmark PACKAGE_HASH e794530c60bd1ecb5f224a346091f23c8fdeb4cfd7ba70b5195d6d2e276447e3) ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux TARGETS unwind PACKAGE_HASH 3453265fb056e25432f611a61546a25f60388e315515ad39007b5925dd054a77) +ly_associate_package(PACKAGE_NAME qt-5.15.2-linux TARGETS Qt PACKAGE_HASH 3857fbb2fc5581cdb71d80a7f9298c83ef06073d4e1ccd86a32b4f88782b6f14) diff --git a/cmake/3rdParty/Platform/Linux/Qt_linux.cmake b/cmake/3rdParty/Platform/Linux/Qt_linux.cmake deleted file mode 100644 index cde2bda5cd..0000000000 --- a/cmake/3rdParty/Platform/Linux/Qt_linux.cmake +++ /dev/null @@ -1,80 +0,0 @@ -# -# 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. -# - -set(QT_PATH ${BASE_PATH}/gcc_64) # "gcc" means "linux" in this case -set(QT_LIB_PATH ${QT_PATH}/lib) - -include(CMakeParseArguments) - -unset(WINDEPLOYQT_EXECUTABLE CACHE) -find_program(WINDEPLOYQT_EXECUTABLE windeployqt - HINTS - "${QT_PATH}/bin" -) -mark_as_advanced(WINDEPLOYQT_EXECUTABLE) # Hiding from GUI - -function(ly_qt_deploy) - - set(options) - set(oneValueArgs TARGET) - set(multiValueArgs) - - cmake_parse_arguments(ly_qt_deploy "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Validate input arguments - if(NOT ly_qt_deploy_TARGET) - message(FATAL_ERROR "You must provide a target to detect qt dependencies") - endif() - - # When winqtdeploy is used on a unix platform it copies over the hardcoded platform abstraction plugin - # of qxcb plugin. The qxcb plugin requires an X server to be running on linux and order to load properly - # To avoid the issue of requiring an X server to be running in a headless setup, the qminimal - # platform plugin is also copied over to the target file output directory. - set(plugin_path "${QT_PATH}/plugins") - set(platform_plugins ${plugin_path}/platforms/libqminimal.so) - set(xcbglintegrations_plugins ${plugin_path}/xcbglintegrations/libqxcb-glx-integration.so) - - add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD - COMMAND "${CMAKE_COMMAND}" - -DLY_TIMESTAMP_REFERENCE=$ - -DLY_LOCK_FILE=$/qtdeploy.lock - -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake - EXEC_COMMAND "${CMAKE_COMMAND}" -E - env PATH=${CMAKE_BINARY_DIR}:${QT_PATH}/bin:$ENV{PATH} - "${CMAKE_COMMAND}" -P "${LY_ROOT_FOLDER}/cmake/Platform/Linux/windeployqt_wrapper.cmake" - "$" - "${WINDEPLOYQT_EXECUTABLE}" - --verbose 2 - --no-compiler-runtime - --dir "$" - "$" - EXEC_COMMAND ${CMAKE_COMMAND} -E make_directory - "$/platforms" - EXEC_COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${platform_plugins} - "$/platforms" - EXEC_COMMAND ${CMAKE_COMMAND} -E make_directory - "$/xcbglintegrations" - EXEC_COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${xcbglintegrations_plugins} - "$/xcbglintegrations" - DEPENDS $ - COMMENT "Deploying qt..." - VERBATIM - ) - -endfunction() - -# windeployqt uses qmake -query to introspect a given Qt installation. However, -# qmake is not relocatable, so the paths reported are those from the build -# machine, and not from wherever the user has their 3rdParty libraries. So we -# create a fake qmake executable to report the right paths to windeployqt. -configure_file(${CMAKE_CURRENT_LIST_DIR}/Qt_qmake_${PAL_PLATFORM_NAME_LOWERCASE}.cmake.in ${CMAKE_BINARY_DIR}/qmake) diff --git a/cmake/3rdParty/Platform/Linux/Qt_qmake_linux.cmake.in b/cmake/3rdParty/Platform/Linux/Qt_qmake_linux.cmake.in deleted file mode 100644 index a02b1aa397..0000000000 --- a/cmake/3rdParty/Platform/Linux/Qt_qmake_linux.cmake.in +++ /dev/null @@ -1,38 +0,0 @@ -#!${CMAKE_COMMAND} -P - -# -# 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. -# - - -execute_process(COMMAND ${CMAKE_COMMAND} -E echo "QT_SYSROOT: -QT_INSTALL_PREFIX:${QT_PATH} -QT_INSTALL_ARCHDATA:${QT_PATH} -QT_INSTALL_DATA:${QT_PATH} -QT_INSTALL_DOCS:${QT_PATH}/doc -QT_INSTALL_HEADERS:${QT_PATH}/include -QT_INSTALL_LIBS:${QT_PATH}/lib -QT_INSTALL_LIBEXECS:${QT_PATH}/libexec -QT_INSTALL_BINS:${QT_PATH}/bin -QT_INSTALL_TESTS:${QT_PATH}/tests -QT_INSTALL_PLUGINS:${QT_PATH}/plugins -QT_INSTALL_IMPORTS:${QT_PATH}/imports -QT_INSTALL_TRANSLATIONS:${QT_PATH}/translations -QT_INSTALL_CONFIGURATION:${QT_PATH}/etc/xdg -QT_INSTALL_EXAMPLES:${QT_PATH}/examples -QT_INSTALL_DEMOS:${QT_PATH}/examples -QT_HOST_PREFIX:${QT_PATH} -QT_HOST_DATA:${QT_PATH} -QT_HOST_BINS:${QT_PATH}/bin -QT_HOST_LIBS:${QT_PATH}/lib -QMAKE_SPEC:linux-g++ -QMAKE_XSPEC:linux-g++ -QMAKE_VERSION:3.1 -QT_VERSION:${QT_PACKAGE_VERSION}") diff --git a/cmake/3rdParty/Platform/Linux/cmake_linux_files.cmake b/cmake/3rdParty/Platform/Linux/cmake_linux_files.cmake index f4b013ddd2..400b99827d 100644 --- a/cmake/3rdParty/Platform/Linux/cmake_linux_files.cmake +++ b/cmake/3rdParty/Platform/Linux/cmake_linux_files.cmake @@ -11,7 +11,6 @@ set(FILES AWSGameLiftServerSDK_linux.cmake - AWSNativeSDK_linux.cmake BuiltInPackages_linux.cmake civetweb_linux.cmake Clang_linux.cmake @@ -21,7 +20,6 @@ set(FILES FbxSdk_linux.cmake FreeType2_linux.cmake OpenSSL_linux.cmake - Qt_linux.cmake tiff_linux.cmake Wwise_linux.cmake ) diff --git a/cmake/3rdParty/Platform/Mac/AWSNativeSDK_mac.cmake b/cmake/3rdParty/Platform/Mac/AWSNativeSDK_mac.cmake deleted file mode 100644 index 31b36d00a7..0000000000 --- a/cmake/3rdParty/Platform/Mac/AWSNativeSDK_mac.cmake +++ /dev/null @@ -1,95 +0,0 @@ -# -# 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. -# - -if (LY_MONOLITHIC_GAME) - #Static libs - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/lib/mac/$,Debug,Release>) - - set(AWSNATIVESDK_CORE_LIBS - ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-core.a - curl # The one bundled with the aws sdk in 3rdParty doesn't use the right openssl - ) - set(AWSNATIVESDK_COMMON_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-common.a) - set(AWSNATIVESDK_EVENTSTREAM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-event-stream.a) - set(AWSNATIVESDK_CHECKSUMS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-checksums.a) - set(AWSNATIVESDK_COGNITOIDENTITY_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-identity.a) - set(AWSNATIVESDK_COGNITOIDP_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-idp.a) - set(AWSNATIVESDK_DEVICEFARM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-devicefarm.a) - set(AWSNATIVESDK_DYNAMODB_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-dynamodb.a) - set(AWSNATIVESDK_GAMELIFT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-gamelift.a) - set(AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-identity-management.a) - set(AWSNATIVESDK_KINESIS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-kinesis.a) - set(AWSNATIVESDK_LAMBDA_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-lambda.a) - set(AWSNATIVESDK_MOBILEANALYTICS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-mobileanalytics.a) - set(AWSNATIVESDK_QUEUES_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-queues.a) - set(AWSNATIVESDK_S3_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-s3.a) - set(AWSNATIVESDK_SNS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sns.a) - set(AWSNATIVESDK_SQS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sqs.a) - set(AWSNATIVESDK_STS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sts.a) -else() - # Shared Libs - set(AWSNATIVE_SDK_SHARED_LIB_PATH ${BASE_PATH}/bin/mac/$,Debug,Release>) - - set(AWSNATIVESDK_CORE_LIBS - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-core.dylib - curl # The one bundled with the aws sdk in 3rdParty doesn't use the right openssl - ) - set(AWSNATIVESDK_COMMON_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-common.dylib) - set(AWSNATIVESDK_EVENTSTREAM_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-event-stream.dylib) - set(AWSNATIVESDK_CHECKSUMS_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-checksums.dylib) - set(AWSNATIVESDK_COGNITOIDENTITY_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-cognito-identity.dylib) - set(AWSNATIVESDK_COGNITOIDP_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-cognito-idp.dylib) - set(AWSNATIVESDK_DEVICEFARM_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-devicefarm.dylib) - set(AWSNATIVESDK_DYNAMODB_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-dynamodb.dylib) - set(AWSNATIVESDK_GAMELIFT_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-gamelift.dylib) - set(AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-identity-management.dylib) - set(AWSNATIVESDK_KINESIS_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-kinesis.dylib) - set(AWSNATIVESDK_LAMBDA_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-lambda.dylib) - set(AWSNATIVESDK_MOBILEANALYTICS_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-mobileanalytics.dylib) - set(AWSNATIVESDK_QUEUES_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-queues.dylib) - set(AWSNATIVESDK_S3_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-s3.dylib) - set(AWSNATIVESDK_SNS_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-sns.dylib) - set(AWSNATIVESDK_SQS_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-sqs.dylib) - set(AWSNATIVESDK_STS_LIBS ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-sts.dylib) - - set(AWSNATIVESDK_CORE_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-core.dylib) - - set(AWSNATIVESDK_COMMON_RUNTIME_DEPENDENCIES - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-common.dylib - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-common.0unstable.dylib - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-common.1.0.0.dylib - ) - - set(AWSNATIVESDK_EVENTSTREAM_RUNTIME_DEPENDENCIES - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-event-stream.dylib - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-event-stream.0unstable.dylib - ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-c-event-stream.1.0.0.dylib - ) - - set(AWSNATIVESDK_CHECKSUMS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-checksums.dylib) - set(AWSNATIVESDK_ACCESSMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-access-management.dylib) - set(AWSNATIVESDK_COGNITOIDENTITY_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-cognito-identity.dylib) - set(AWSNATIVESDK_COGNITOIDP_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-cognito-idp.dylib) - set(AWSNATIVESDK_DEVICEFARM_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-devicefarm.dylib) - set(AWSNATIVESDK_DYNAMODB_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-dynamodb.dylib) - set(AWSNATIVESDK_GAMELIFT_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-gamelift.dylib) - set(AWSNATIVESDK_IDENTITYMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-identity-management.dylib) - set(AWSNATIVESDK_KINESIS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-kinesis.dylib) - set(AWSNATIVESDK_LAMBDA_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-lambda.dylib) - set(AWSNATIVESDK_MOBILEANALYTICS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-mobileanalytics.dylib) - set(AWSNATIVESDK_QUEUES_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-queues.dylib) - set(AWSNATIVESDK_S3_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-s3.dylib) - set(AWSNATIVESDK_SNS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-sns.dylib) - set(AWSNATIVESDK_SQS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-sqs.dylib) - set(AWSNATIVESDK_STS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-sts.dylib) - set(AWSNATIVESDK_TRANSFER_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_SHARED_LIB_PATH}/libaws-cpp-sdk-transfer.dylib) -endif() - diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 5ddd28c243..28e7f8a5f8 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -33,10 +33,12 @@ ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxcAz-5.0.0_az-rev1-multi ly_associate_package(PACKAGE_NAME azslc-1.7.19-rev1-multiplatform TARGETS azslc PACKAGE_HASH e7649ba4a9190a82512f9aaad1b4318fbdf09384c533d2e3cc15c8440e65bd4a) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev3-multiplatform TARGETS PVRTexTool PACKAGE_HASH d9c7e21e03b03cb560da4793a91a0d384ea621757cf87a1a82c83bfca6b23f97) +ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev1-mac TARGETS AWSNativeSDK PACKAGE_HASH 9d0562de258edfd8f14c4cc85ac665cf64b6bf13928d53725e7f90e4ad4672a3) ly_associate_package(PACKAGE_NAME PhysX-4.1.0.25992954-rev1-mac TARGETS PhysX PACKAGE_HASH 149f5e9b44bd27291b1c4772f5e89a1e0efa88eef73c7e0b188935ed4d0c4a70) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-mac TARGETS mikkelsen PACKAGE_HASH 83af99ca8bee123684ad254263add556f0cf49486c0b3e32e6d303535714e505) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac TARGETS googletest PACKAGE_HASH cbf020d5ef976c5db8b6e894c6c63151ade85ed98e7c502729dd20172acae5a8) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev1-mac TARGETS GoogleBenchmark PACKAGE_HASH d81817701931508c8aa4efc61852d3d9c5672e43d2f68df645ab56251da43119) +ly_associate_package(PACKAGE_NAME qt-5.15.2-mac TARGETS Qt PACKAGE_HASH ac248833d65838e4bcef50f30c9ff02ba9464ff64b9ada52de2ad6045d38baec) diff --git a/cmake/3rdParty/Platform/Mac/Qt_mac.cmake b/cmake/3rdParty/Platform/Mac/Qt_mac.cmake deleted file mode 100644 index 041ac43c80..0000000000 --- a/cmake/3rdParty/Platform/Mac/Qt_mac.cmake +++ /dev/null @@ -1,78 +0,0 @@ -# -# 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. -# - -set(QT_PATH ${BASE_PATH}/clang_64) -set(QT_LIB_PATH ${QT_PATH}/lib) - -list(APPEND QT5_COMPONENTS MacExtras) - - -include(CMakeParseArguments) - -# Clear the cache for found executable -unset(MACDEPLOYQT_EXECUTABLE CACHE) -find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${QT_PATH}/bin") -mark_as_advanced(MACDEPLOYQT_EXECUTABLE) # Hiding from GUI - -function(ly_qt_deploy) - - set(options) - set(oneValueArgs TARGET) - set(multiValueArgs) - - cmake_parse_arguments(ly_qt_deploy "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Validate input arguments - if(NOT ly_qt_deploy_TARGET) - message(FATAL_ERROR "You must provide a target to detect qt dependencies") - endif() - - get_target_property(is_bundle ${ly_qt_deploy_TARGET} MACOSX_BUNDLE) - if (is_bundle) - add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD - COMMAND "${CMAKE_COMMAND}" - -DLY_TIMESTAMP_REFERENCE=$ - -DLY_LOCK_FILE=$/qtdeploy.lock - -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake - EXEC_COMMAND "${CMAKE_COMMAND}" -E time - ${MACDEPLOYQT_EXECUTABLE} - $ - -always-overwrite - -no-strip - -verbose=0 - -fs=APFS - DEPENDS $ - COMMENT "Deploying qt to the ${ly_qt_deploy_TARGET} bundle ..." - VERBATIM - ) - else() - set(qt_conf_config "[Paths]\nPlugins=@plugin_path@") - set(plugin_path "${QT_PATH}/plugins") - string(CONFIGURE "${qt_conf_config}" qt_conf_output @ONLY) - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" "${qt_conf_output}") - - # output the qt_conf file using "echo" and file redirection - add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD - COMMAND "${CMAKE_COMMAND}" - -DLY_TIMESTAMP_REFERENCE=$ - -DLY_LOCK_FILE=$/qtdeploy.lock - -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake - EXEC_COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_CURRENT_BINARY_DIR}/qt.conf - $/qt.conf - COMMENT "copying over qt.conf..." - VERBATIM - ) - endif() - -endfunction() - - diff --git a/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake b/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake index 57f7eea210..c531066871 100644 --- a/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake +++ b/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake @@ -10,7 +10,6 @@ # set(FILES - AWSNativeSDK_mac.cmake BuiltInPackages_mac.cmake civetweb_mac.cmake Clang_mac.cmake @@ -20,6 +19,5 @@ set(FILES FbxSdk_mac.cmake FreeType2_mac.cmake OpenSSL_mac.cmake - Qt_mac.cmake Wwise_mac.cmake ) \ No newline at end of file diff --git a/cmake/3rdParty/Platform/Windows/AWSNativeSDK_windows.cmake b/cmake/3rdParty/Platform/Windows/AWSNativeSDK_windows.cmake deleted file mode 100644 index 02c53a8e51..0000000000 --- a/cmake/3rdParty/Platform/Windows/AWSNativeSDK_windows.cmake +++ /dev/null @@ -1,74 +0,0 @@ -# -# 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. -# - - -if (LY_MONOLITHIC_GAME) - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/lib/windows/$,Debug,Release>) -else() - set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/bin/windows/$,Debug,Release>) -endif() - -set(AWSNATIVESDK_CORE_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-core.lib - Bcrypt.lib - Userenv.lib - Version.lib - Wininet.lib - Winhttp.lib - Ws2_32.lib -) -set(AWSNATIVESDK_COMMON_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-c-common.lib) -set(AWSNATIVESDK_EVENTSTREAM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-c-event-stream.lib) -set(AWSNATIVESDK_CHECKSUMS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-checksums.lib) -set(AWSNATIVESDK_ACCESSMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-access-management.lib) -set(AWSNATIVESDK_COGNITOIDENTITY_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-cognito-identity.lib) -set(AWSNATIVESDK_COGNITOIDP_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-cognito-idp.lib) -set(AWSNATIVESDK_DEVICEFARM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-devicefarm.lib) -set(AWSNATIVESDK_DYNAMODB_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-dynamodb.lib) -set(AWSNATIVESDK_GAMELIFT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-gamelift.lib) -set(AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-identity-management.lib) -set(AWSNATIVESDK_KINESIS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-kinesis.lib) -set(AWSNATIVESDK_LAMBDA_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-lambda.lib) -set(AWSNATIVESDK_MOBILEANALYTICS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-mobileanalytics.lib) -set(AWSNATIVESDK_QUEUES_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-queues.lib) -set(AWSNATIVESDK_S3_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-s3.lib) -set(AWSNATIVESDK_SNS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-sns.lib) -set(AWSNATIVESDK_SQS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-sqs.lib) -set(AWSNATIVESDK_STS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-sts.lib) -set(AWSNATIVESDK_TRANSFER_LIBS ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-transfer.lib) - -if (NOT LY_MONOLITHIC_GAME) - - # Add 'USE_IMPORT_EXPORT' for external linkage - set(AWSNATIVESDK_COMPILE_DEFINITIONS USE_IMPORT_EXPORT) - - #Shared libs - set(AWSNATIVESDK_CORE_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-core.dll) - set(AWSNATIVESDK_COMMON_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-c-common.dll) - set(AWSNATIVESDK_EVENTSTREAM_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-c-event-stream.dll) - set(AWSNATIVESDK_CHECKSUMS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-checksums.dll) - set(AWSNATIVESDK_ACCESSMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-access-management.dll) - set(AWSNATIVESDK_COGNITOIDENTITY_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-cognito-identity.dll) - set(AWSNATIVESDK_COGNITOIDP_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-cognito-idp.dll) - set(AWSNATIVESDK_DEVICEFARM_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-devicefarm.dll) - set(AWSNATIVESDK_DYNAMODB_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-dynamodb.dll) - set(AWSNATIVESDK_GAMELIFT_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-gamelift.dll) - set(AWSNATIVESDK_IDENTITYMANAGEMENT_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-identity-management.dll) - set(AWSNATIVESDK_KINESIS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-kinesis.dll) - set(AWSNATIVESDK_LAMBDA_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-lambda.dll) - set(AWSNATIVESDK_MOBILEANALYTICS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-mobileanalytics.dll) - set(AWSNATIVESDK_QUEUES_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-queues.dll) - set(AWSNATIVESDK_S3_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-s3.dll) - set(AWSNATIVESDK_SNS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-sns.dll) - set(AWSNATIVESDK_SQS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-sqs.dll) - set(AWSNATIVESDK_STS_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-sts.dll) - set(AWSNATIVESDK_TRANSFER_RUNTIME_DEPENDENCIES ${AWSNATIVE_SDK_LIB_PATH}/aws-cpp-sdk-transfer.dll) - -endif() \ No newline at end of file diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index ef150f579f..983b6d9b38 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -34,8 +34,9 @@ ly_associate_package(PACKAGE_NAME azslc-1.7.19-rev1-multiplatform ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) ly_associate_package(PACKAGE_NAME Blast-1.1.7-rev1-multiplatform TARGETS Blast PACKAGE_HASH 36b8f393bcd25d0f85cfc7a831ebbdac881e6054c4f0735649966aa6aa86e6f0) -ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev3-multiplatform TARGETS PVRTexTool PACKAGE_HASH d9c7e21e03b03cb560da4793a91a0d384ea621757cf87a1a82c83bfca6b23f97) +ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev1-windows TARGETS AWSNativeSDK PACKAGE_HASH 58e199f253a28964b96056ed4a6db06216fcde14a96d6d94b0d6ad3437516bdc) ly_associate_package(PACKAGE_NAME PhysX-4.1.0.25992954-rev1-windows TARGETS PhysX PACKAGE_HASH 198bed89d1aae7caaf5dadba24cee56235fe41725d004b64040d4e50d0f3aa1a) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-windows TARGETS mikkelsen PACKAGE_HASH 872c4d245a1c86139aa929f2b465b63ea4ea55b04ced50309135dd4597457a4e) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-windows TARGETS googletest PACKAGE_HASH 7e8f03ae8a01563124e3daa06386f25a2b311c10bb95bff05cae6c41eff83837) @@ -43,3 +44,4 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev1-windows TARGETS Goo ly_associate_package(PACKAGE_NAME d3dx12-headers-rev1-windows TARGETS d3dx12 PACKAGE_HASH 088c637159fba4a3e4c0cf08fb4921906fd4cca498939bd239db7c54b5b2f804) ly_associate_package(PACKAGE_NAME pyside2-qt-5.15.1-rev2-windows TARGETS pyside2 PACKAGE_HASH c90f3efcc7c10e79b22a33467855ad861f9dbd2e909df27a5cba9db9fa3edd0f) ly_associate_package(PACKAGE_NAME openimageio-2.1.16.0-rev1-windows TARGETS openimageio PACKAGE_HASH b9f6d6df180ad240b9f17a68c1862c7d8f38234de0e692e83116254b0ee467e5) +ly_associate_package(PACKAGE_NAME qt-5.15.2-windows TARGETS Qt PACKAGE_HASH edaf954c647c99727bfd313dab2959803d2df0873914bb96368c3d8286eed6d9) diff --git a/cmake/3rdParty/Platform/Windows/Qt_windows.cmake b/cmake/3rdParty/Platform/Windows/Qt_windows.cmake deleted file mode 100644 index bca04dab17..0000000000 --- a/cmake/3rdParty/Platform/Windows/Qt_windows.cmake +++ /dev/null @@ -1,55 +0,0 @@ -# -# 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. -# - -set(QT_PATH ${BASE_PATH}/msvc2019_64) -set(QT_LIB_PATH ${QT_PATH}/lib) - -include(CMakeParseArguments) - -# Clear the cache for found executable -unset(WINDEPLOYQT_EXECUTABLE CACHE) -find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_PATH}/bin") -mark_as_advanced(WINDEPLOYQT_EXECUTABLE) # Hiding from GUI - -function(ly_qt_deploy) - - set(options) - set(oneValueArgs TARGET) - set(multiValueArgs) - - cmake_parse_arguments(ly_qt_deploy "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Validate input arguments - if(NOT ly_qt_deploy_TARGET) - message(FATAL_ERROR "You must provide a target to detect qt dependencies") - endif() - - # CMake has an issue with POST_BUILD commands in msbuild when it is executed from outside VS: - # https://gitlab.kitware.com/cmake/cmake/issues/18530 - - add_custom_command(TARGET ${ly_qt_deploy_TARGET} POST_BUILD - COMMAND "${CMAKE_COMMAND}" - -DLY_TIMESTAMP_REFERENCE=$ - -DLY_LOCK_FILE=$/qtdeploy.lock - -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake - EXEC_COMMAND "${CMAKE_COMMAND}" -E - env PATH="${QT_PATH}/bin" - ${WINDEPLOYQT_EXECUTABLE} - $<$:--pdb> - --verbose 0 - --no-compiler-runtime - $ - DEPENDS $ $ - COMMENT "Deploying qt..." - VERBATIM - ) - -endfunction() \ No newline at end of file diff --git a/cmake/3rdParty/Platform/Windows/cmake_windows_files.cmake b/cmake/3rdParty/Platform/Windows/cmake_windows_files.cmake index 5ad3998cac..49b7b68c61 100644 --- a/cmake/3rdParty/Platform/Windows/cmake_windows_files.cmake +++ b/cmake/3rdParty/Platform/Windows/cmake_windows_files.cmake @@ -10,7 +10,6 @@ # set(FILES - AWSNativeSDK_windows.cmake AWSGameLiftServerSDK_windows.cmake BuiltInPackages_windows.cmake Clang_windows.cmake @@ -23,7 +22,6 @@ set(FILES FreeType2_windows.cmake libav_windows.cmake OpenSSL_windows.cmake - Qt_windows.cmake tiff_windows.cmake Wwise_windows.cmake ) diff --git a/cmake/3rdParty/Platform/iOS/AWSNativeSDK_ios.cmake b/cmake/3rdParty/Platform/iOS/AWSNativeSDK_ios.cmake deleted file mode 100644 index 0e4710dfce..0000000000 --- a/cmake/3rdParty/Platform/iOS/AWSNativeSDK_ios.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# -# 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. -# - -set(AWSNATIVE_SDK_LIB_PATH ${BASE_PATH}/lib/ios/$,Debug,Release>) - -set(AWSNATIVESDK_CORE_LIBS - ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-core.a - ${AWSNATIVE_SDK_LIB_PATH}/libcurl.a -) -set(AWSNATIVESDK_COMMON_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-common.a) -set(AWSNATIVESDK_EVENTSTREAM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-c-event-stream.a) -set(AWSNATIVESDK_CHECKSUMS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-checksums.a) -set(AWSNATIVESDK_COGNITOIDENTITY_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-identity.a) -set(AWSNATIVESDK_COGNITOIDP_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-cognito-idp.a) -set(AWSNATIVESDK_DEVICEFARM_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-devicefarm.a) -set(AWSNATIVESDK_DYNAMODB_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-dynamodb.a) -set(AWSNATIVESDK_GAMELIFT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-gamelift.a) -set(AWSNATIVESDK_IDENTITYMANAGEMENT_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-identity-management.a) -set(AWSNATIVESDK_KINESIS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-kinesis.a) -set(AWSNATIVESDK_LAMBDA_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-lambda.a) -set(AWSNATIVESDK_MOBILEANALYTICS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-mobileanalytics.a) -set(AWSNATIVESDK_QUEUES_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-queues.a) -set(AWSNATIVESDK_S3_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-s3.a) -set(AWSNATIVESDK_SNS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sns.a) -set(AWSNATIVESDK_SQS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sqs.a) -set(AWSNATIVESDK_STS_LIBS ${AWSNATIVE_SDK_LIB_PATH}/libaws-cpp-sdk-sts.a) - -find_library(SECURITY_FRAMEWORK Security) -set(AWSNATIVESDK_BUILD_DEPENDENCIES ${SECURITY_FRAMEWORK}) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index 80303f3575..63c8b6bb17 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -21,6 +21,7 @@ ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zst ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) # platform-specific: +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev1-ios TARGETS AWSNativeSDK PACKAGE_HASH 9e1956b5bb10762cdb84a981dcd356419078f4296ffbc8c55717bc3f53b09d69) ly_associate_package(PACKAGE_NAME PhysX-4.1.0.25992954-rev1-ios TARGETS PhysX PACKAGE_HASH a2a48a09128337c72b9c2c1b8f43187c6c914e8509c9c6cd91810108748d7e09) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-ios TARGETS mikkelsen PACKAGE_HASH 976aaa3ccd8582346132a10af253822ccc5d5bcc9ea5ba44d27848f65ee88a8a) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-ios TARGETS googletest PACKAGE_HASH 2f121ad9784c0ab73dfaa58e1fee05440a82a07cc556bec162eeb407688111a7) diff --git a/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake b/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake index d7e4d13530..b0188ac808 100644 --- a/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake +++ b/cmake/3rdParty/Platform/iOS/cmake_ios_files.cmake @@ -10,7 +10,6 @@ # set(FILES - AWSNativeSDK_ios.cmake BuiltInPackages_ios.cmake expat_ios.cmake FreeType2_ios.cmake diff --git a/cmake/3rdParty/cmake_files.cmake b/cmake/3rdParty/cmake_files.cmake index da14d25410..c98110ae2b 100644 --- a/cmake/3rdParty/cmake_files.cmake +++ b/cmake/3rdParty/cmake_files.cmake @@ -11,7 +11,6 @@ set(FILES BuiltInPackages.cmake - FindAWSNativeSDK.cmake FindAWSGameLiftServerSDK.cmake Findcivetweb.cmake FindClang.cmake @@ -23,7 +22,6 @@ set(FILES FindFreeType2.cmake Findlibav.cmake FindOpenSSL.cmake - FindQt.cmake FindRadTelemetry.cmake Findtiff.cmake FindVkValidation.cmake diff --git a/cmake/3rdPartyPackages.cmake b/cmake/3rdPartyPackages.cmake index 7f6e7a2958..2219ded0aa 100644 --- a/cmake/3rdPartyPackages.cmake +++ b/cmake/3rdPartyPackages.cmake @@ -699,3 +699,9 @@ if (NOT CMAKE_SCRIPT_MODE_FILE) # a good starting point. include(cmake/3rdParty/BuiltInPackages.cmake) endif() + +if(PAL_TRAIT_BUILD_HOST_TOOLS) + include(cmake/LYWrappers.cmake) + # Importing this globally to handle AUTOMOC, AUTOUIC, AUTORCC + ly_parse_third_party_dependencies(3rdParty::Qt) +endif() diff --git a/cmake/EngineFinder.cmake b/cmake/EngineFinder.cmake index 2481b0c60c..1fdcef2b56 100644 --- a/cmake/EngineFinder.cmake +++ b/cmake/EngineFinder.cmake @@ -21,12 +21,17 @@ if(json_error) endif() # Read the list of paths from ~.o3de/o3de_manifest.json -if($ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) - set(manifest_path $ENV{USERPROFILE}/.o3de/o3de_manifest.json) # Windows -else() - set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix +file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows +if((NOT home_directory) OR (NOT EXISTS ${home_directory})) + file(TO_CMAKE_PATH "$ENV{HOME}" home_directory)# Unix endif() +if (NOT home_directory) + message(FATAL_ERROR "Cannot find user home directory, the o3de manifest cannot be found") +endif() +# Set manifest path to path in the user home directory +set(manifest_path ${home_directory}/.o3de/o3de_manifest.json) + if(EXISTS ${manifest_path}) file(READ ${manifest_path} manifest_json) string(JSON engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines) diff --git a/cmake/FileUtil.cmake b/cmake/FileUtil.cmake index 84164b0c1f..96923537ed 100644 --- a/cmake/FileUtil.cmake +++ b/cmake/FileUtil.cmake @@ -100,6 +100,7 @@ endfunction() # the cmake project generation. This will provide a bridge to non-cmake tools to read the platform-specific cmake # project generation settings. # +get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME) function(ly_update_platform_settings) # Update the .last file to keep track of the recent build_dir set(ly_platform_last_path "${CMAKE_BINARY_DIR}/platform.settings") @@ -109,7 +110,7 @@ function(ly_update_platform_settings) [settings] platform=${PAL_PLATFORM_NAME} -game_projects=${LY_PROJECTS_NAME} +game_projects=${LY_PROJECTS_TARGET_NAME} asset_deploy_mode=${LY_ASSET_DEPLOY_MODE} asset_deploy_type=${LY_ASSET_DEPLOY_ASSET_TYPE} override_pak_root=${LY_OVERRIDE_PAK_FOLDER_ROOT} diff --git a/cmake/Initialize.cmake b/cmake/Initialize.cmake index dbc1628730..474ea39dd6 100644 --- a/cmake/Initialize.cmake +++ b/cmake/Initialize.cmake @@ -23,4 +23,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build dir set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build directory for executables") set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "Installation prefix") +set(LY_EXTERNAL_SUBDIRS "" CACHE STRING "Additional list of subdirectory to recurse into via the cmake `add_subdirectory()` command. \ + The subdirectories are included after the restricted platform folders have been visited by a call to `add_subdirectory(restricted/\${restricted_platform})`") + ly_set(LY_ROOT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}) \ No newline at end of file diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 3677974c3d..1cfc9c473a 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -23,6 +23,16 @@ if(LY_UNITY_BUILD AND NOT PAL_TRAIT_BUILD_UNITY_SUPPORTED) message(ERROR "LY_UNITY_BUILD is specified, but not supported for the current target platform") endif() +define_property(TARGET PROPERTY GEM_MODULE + BRIEF_DOCS "Defines a MODULE library as a Gem" + FULL_DOCS [[ + Property which is set on targets that should be seen as gems + This is used to determine whether this target should load as + when used as a runtime dependency should load at the same time + as its dependee + ]] +) + #! ly_add_target: adds a target and provides parameters for the common configurations. # @@ -39,6 +49,7 @@ endif() # \arg:STATIC (bool) defines this target to be a static library # \arg:SHARED (bool) defines this target to be a dynamic library # \arg:MODULE (bool) defines this target to be a module library +# \arg:GEM_MODULE (bool) defines this target to be a module library while also marking the target as a "Gem" via the GEM_MODULE property # \arg:HEADERONLY (bool) defines this target to be a header only library. A ${NAME}_HEADERS project will be created for the IDE # \arg:EXECUTABLE (bool) defines this target to be an executable # \arg:APPLICATION (bool) defines this target to be an application (executable that is not a console) @@ -64,7 +75,7 @@ endif() # \arg:AUTOGEN_RULES a set of AutoGeneration rules to be passed to the AzAutoGen expansion system function(ly_add_target) - set(options STATIC SHARED MODULE HEADERONLY EXECUTABLE APPLICATION AUTOMOC AUTOUIC AUTORCC NO_UNITY) + set(options STATIC SHARED MODULE GEM_MODULE HEADERONLY EXECUTABLE APPLICATION AUTOMOC AUTOUIC AUTORCC NO_UNITY) set(oneValueArgs NAME NAMESPACE OUTPUT_SUBDIRECTORY OUTPUT_NAME) set(multiValueArgs FILES_CMAKE GENERATED_FILES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES PLATFORM_INCLUDE_FILES TARGET_PROPERTIES AUTOGEN_RULES) @@ -78,6 +89,11 @@ function(ly_add_target) message(FATAL_ERROR "You must provide a list of _files.cmake files for the target") endif() + # If the GEM_MODULE tag is passed set the normal MODULE argument + if(ly_add_target_GEM_MODULE) + set(ly_add_target_MODULE ${ly_add_target_GEM_MODULE}) + endif() + foreach(file_cmake ${ly_add_target_FILES_CMAKE}) ly_include_cmake_file_list(${file_cmake}) endforeach() @@ -176,6 +192,10 @@ function(ly_add_target) endif() + if(ly_add_target_GEM_MODULE) + set_target_properties(${ly_add_target_NAME} PROPERTIES GEM_MODULE TRUE) + endif() + if (ly_add_target_INCLUDE_DIRECTORIES) target_include_directories(${ly_add_target_NAME} ${ly_add_target_INCLUDE_DIRECTORIES} @@ -225,7 +245,15 @@ function(ly_add_target) ly_source_groups_from_folders("${ALLFILES}") source_group("Generated Files" REGULAR_EXPRESSION "(${CMAKE_BINARY_DIR})") # Any file coming from the output folder file(RELATIVE_PATH project_path ${LY_ROOT_FOLDER} ${CMAKE_CURRENT_SOURCE_DIR}) - set_property(TARGET ${project_NAME} PROPERTY FOLDER ${project_path}) + # Visual Studio cannot load a project with a FOLDER that starts with a "../" relative path + # Strip away any leading ../ and then add a prefix of ExternalTargets/ as that in this scenario + # A relative directory with ../ would be outside of the Lumberyard Engine Root therefore it is external + set(ide_path ${project_path}) + if (${project_path} MATCHES [[^(\.\./)+(.*)]]) + set(ide_path "${CMAKE_MATCH_2}") + endif() + set_property(TARGET ${project_NAME} PROPERTY FOLDER ${ide_path}) + if(ly_add_target_RUNTIME_DEPENDENCIES) ly_parse_third_party_dependencies("${ly_add_target_RUNTIME_DEPENDENCIES}") @@ -561,66 +589,6 @@ function(ly_add_target_files) endfunction() -#! ly_add_translations: adds translations (ts) to a target. -# -# This wrapper will generate a qrc file with those translations and add the files under "prefix" and add them to -# the indicated targets. These files will be added under the "Generated Files" filter -# -# \arg:TARGETS name of the targets that the translations will be added to -# \arg:PREFIX prefix where the translation will be located within the qrc file -# \arg:FILES translation files to add -# -function(ly_add_translations) - - set(options) - set(oneValueArgs PREFIX) - set(multiValueArgs TARGETS FILES) - - cmake_parse_arguments(ly_add_translations "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Validate input arguments - if(NOT ly_add_translations_TARGETS) - message(FATAL_ERROR "You must provide at least one target") - endif() - if(NOT ly_add_translations_FILES) - message(FATAL_ERROR "You must provide at least a translation file") - endif() - - qt5_add_translation(TRANSLATED_FILES ${ly_add_translations_FILES}) - - set(qrc_file_contents -" - -") - foreach(file ${TRANSLATED_FILES}) - get_filename_component(filename ${file} NAME) - string(APPEND qrc_file_contents " ${filename} -") - endforeach() - string(APPEND qrc_file_contents " - -") - set(qrc_file_path ${CMAKE_CURRENT_BINARY_DIR}/i18n_${ly_add_translations_PREFIX}.qrc) - file(WRITE - ${qrc_file_path} - ${qrc_file_contents} - ) - set_source_files_properties( - ${TRANSLATED_FILES} - ${qrc_file_path} - PROPERTIES - GENERATED TRUE - SKIP_AUTORCC TRUE - ) - qt5_add_resources(RESOURCE_FILE ${qrc_file_path}) - - foreach(target ${ly_add_translations_TARGETS}) - target_sources(${target} PRIVATE "${TRANSLATED_FILES};${qrc_file_path};${RESOURCE_FILE}") - endforeach() - -endfunction() - - #! ly_add_source_properties: adds/appends properties to a source file. # # This wraps set_source_files_properties to be able to pass a property with multiple values diff --git a/cmake/Monolithic.cmake b/cmake/Monolithic.cmake index 93bb92944f..db45c182fd 100644 --- a/cmake/Monolithic.cmake +++ b/cmake/Monolithic.cmake @@ -22,5 +22,5 @@ if(LY_MONOLITHIC_GAME) ly_set(PAL_TRAIT_BUILD_SERVER_SUPPORTED FALSE) else() ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE SHARED) - ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE MODULE) + ly_set(PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE GEM_MODULE) endif() \ No newline at end of file diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index e6597acca7..734baad8a3 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -62,11 +62,11 @@ function(ly_get_absolute_pal_filename out_name in_name) set(full_name ${in_name}) if (NOT EXISTS ${full_name}) - string(REGEX MATCH "${repo_dir}/(.*)/Platform/([^/]*)(.*)?" match ${full_name}) + string(REGEX MATCH "${repo_dir}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) if(${CMAKE_MATCH_2} IN_LIST PAL_RESTRICTED_PLATFORMS) set(full_name ${repo_dir}/restricted/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) if(NOT "${CMAKE_MATCH_3}" STREQUAL "") - string(APPEND full_name ${CMAKE_MATCH_3}) + string(APPEND full_name "/" ${CMAKE_MATCH_3}) endif() endif() endif() @@ -74,11 +74,7 @@ function(ly_get_absolute_pal_filename out_name in_name) endfunction() function(ly_get_list_relative_pal_filename out_name in_name) - if(${ARGC} GREATER 2) - ly_get_absolute_pal_filename(abs_name ${in_name} ${ARGV2}) - else() - ly_get_absolute_pal_filename(abs_name ${in_name}) - endif() + ly_get_absolute_pal_filename(abs_name ${in_name} ${ARGN}) file(RELATIVE_PATH relative_name ${CMAKE_CURRENT_LIST_DIR} ${abs_name}) set(${out_name} ${relative_name} PARENT_SCOPE) endfunction() diff --git a/cmake/Platform/iOS/SDK_ios.cmake b/cmake/Platform/iOS/SDK_ios.cmake index 8c6027f15a..a7c36b1b9d 100644 --- a/cmake/Platform/iOS/SDK_ios.cmake +++ b/cmake/Platform/iOS/SDK_ios.cmake @@ -9,7 +9,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # - # Detect the ios SDK Path and set the SYSROOT find_program(XCRUN_PROG "xcrun") execute_process(COMMAND ${XCRUN_PROG} --sdk iphoneos --show-sdk-path @@ -20,11 +19,10 @@ if (NOT GET_IOS_SDK_RESULT EQUAL 0) endif() string(STRIP ${LY_IOS_SDK_PATH} LY_IOS_SDK_PATH) -ly_set(CMAKE_SYSROOT ${LY_IOS_SDK_PATH}) - -ly_set(SDKROOT "iphoneos") +set(CMAKE_SYSROOT ${LY_IOS_SDK_PATH}) -ly_set(DEVROOT "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer") +set(SDKROOT "iphoneos") -ly_set(CMAKE_OSX_SYSROOT "${SDKROOT}") +set(DEVROOT "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer") +set(CMAKE_OSX_SYSROOT "${SDKROOT}") diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 61b9377353..0113edc1be 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -26,12 +26,13 @@ set(LY_PROJECTS "" CACHE STRING "List of projects to enable, this can be a relat # found in the DEPENDENCIES_FILES. The PREFIX and each dependent target will be joined using the symbol # \arg:TARGETS names of the targets to associate the dependencies to # \arg:DEPENDENCIES_FILES file(s) that contains the load-time dependencies the TARGETS will be associated to +# \arg:DEPENDENT_TARGETS additional list of targets should be added as load-time dependencies for the TARGETS list # function(ly_add_target_dependencies) set(options) set(oneValueArgs PREFIX) - set(multiValueArgs TARGETS DEPENDENCIES_FILES) + set(multiValueArgs TARGETS DEPENDENCIES_FILES DEPENDENT_TARGETS) cmake_parse_arguments(ly_add_gem_dependencies "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -40,8 +41,8 @@ function(ly_add_target_dependencies) message(FATAL_ERROR "You must provide at least one target to associate the dependencies with") endif() - if(NOT ly_add_gem_dependencies_DEPENDENCIES_FILES) - message(FATAL_ERROR "DEPENDENCIES_FILES parameter missing") + if(NOT ly_add_gem_dependencies_DEPENDENCIES_FILES AND NOT ly_add_gem_dependencies_DEPENDENT_TARGETS) + message(FATAL_ERROR "DEPENDENCIES_FILES parameter missing. It must be supplied unless the DEPENDENT_TARGETS parameter is set") endif() unset(ALL_GEM_DEPENDENCIES) @@ -52,6 +53,9 @@ function(ly_add_target_dependencies) list(APPEND ALL_GEM_DEPENDENCIES ${GEM_DEPENDENCIES}) endforeach() + # Append the DEPENDENT_TARGETS to the list of ALL_GEM_DEPENDENCIES + list(APPEND ALL_GEM_DEPENDENCIES ${ly_add_gem_dependencies_DEPENDENT_TARGETS}) + # for each target, add the dependencies and generate gems json foreach(target ${ly_add_gem_dependencies_TARGETS}) ly_add_dependencies(${target} ${ALL_GEM_DEPENDENCIES}) @@ -100,15 +104,16 @@ function(ly_add_project_dependencies) endfunction() # Add the projects here so the above function is found -unset(LY_PROJECTS_NAME) foreach(project ${LY_PROJECTS}) - if(IS_ABSOLUTE ${project}) - get_filename_component(project_name ${project} NAME) - add_subdirectory(${project} ${project_name}) - list(APPEND LY_PROJECTS_NAME ${project_name}) - else() - add_subdirectory(${project}) - list(APPEND LY_PROJECTS_NAME ${project}) - endif() + get_filename_component(full_directory_path ${project} REALPATH ${CMAKE_SOURCE_DIR}) + string(SHA256 full_directory_hash ${full_directory_path}) + + # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit + # when the external subdirectory contains relative paths of significant length + string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) + + get_filename_component(project_folder_name ${project} NAME) + list(APPEND LY_PROJECTS_FOLDER_NAME ${project_folder_name}) + add_subdirectory(${project} "${project_folder_name}-${full_directory_hash}") endforeach() -ly_set(LY_PROJECTS_NAME ${LY_PROJECTS_NAME}) \ No newline at end of file +ly_set(LY_PROJECTS_FOLDER_NAME ${LY_PROJECTS_FOLDER_NAME}) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index efa96f724c..fda8428cbb 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -30,11 +30,61 @@ set(gems_json_template [[ set(gem_module_template [[ "@stripped_gem_target@": { - "Module":"$", + "Modules":["$"], "SourcePaths":["@gem_relative_source_dir@"] }]] ) +#!ly_get_gem_load_dependencies: Retrieves the list of "load" dependencies for a target +# Visits through only MANUALLY_ADDED_DEPENDENCIES of targets with a GEM_MODULE property +# to determine which gems a target needs to load +# ly_get_runtime_dependencies cannot be used as it will recurse through non-manually added dependencies +# to add manually added added which results in false load dependencies. +# \arg:ly_GEM_LOAD_DEPENDENCIES(name) - Output variable to be populated gem load dependencies +# \arg:ly_TARGET(TARGET) - CMake target to examine for dependencies +function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) + if(NOT TARGET ${ly_TARGET}) + return() # Nothing to do + endif() + + # Optimize the search by caching gem load dependencies + get_property(are_dependencies_cached GLOBAL PROPERTY LY_GEM_LOAD_DEPENDENCIES_${ly_TARGET} SET) + if(are_dependencies_cached) + # We already walked through this target + get_property(cached_dependencies GLOBAL PROPERTY LY_GEM_LOAD_DEPENDENCIES_${ly_TARGET}) + set(${ly_GEM_LOAD_DEPENDENCIES} ${cached_dependencies} PARENT_SCOPE) + return() + endif() + + unset(all_gem_load_dependencies) + + # For load dependencies, we want to copy over the dependency and traverse them + # Only if the dependency has a GEM_MODULE property + unset(load_dependencies) + get_target_property(load_dependencies ${ly_TARGET} MANUALLY_ADDED_DEPENDENCIES) + if(load_dependencies) + foreach(load_dependency ${load_dependencies}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${load_dependency} MATCHES "^::@") + get_property(dependency_type TARGET ${load_dependency} PROPERTY TYPE) + get_property(is_gem_target TARGET ${load_dependency} PROPERTY GEM_MODULE SET) + # If the dependency is a "gem module" then add it as a load dependencies + # and recurse into its manually added dependencies + if (is_gem_target) + unset(dependencies) + ly_get_gem_load_dependencies(dependencies ${load_dependency}) + list(APPEND all_gem_load_dependencies ${load_dependency}) + list(APPEND all_gem_load_dependencies ${dependencies}) + endif() + endif() + endforeach() + endif() + + list(REMOVE_DUPLICATES all_gem_load_dependencies) + set_property(GLOBAL PROPERTY LY_GEM_LOAD_DEPENDENCIES_${ly_TARGET} "${all_gem_load_dependencies}") + set(${ly_GEM_LOAD_DEPENDENCIES} ${all_gem_load_dependencies} PARENT_SCOPE) +endfunction() + #! ly_delayed_generate_settings_registry: Generates a .setreg file for each target with dependencies # added to it via ly_add_target_dependencies # The generated file contains the file to the each dependent targets @@ -58,9 +108,16 @@ function(ly_delayed_generate_settings_registry) # Get the gem dependencies for the given project and target combination get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_LOAD_"${prefix_target}") list(REMOVE_DUPLICATES gem_dependencies) # Strip out any duplicate gem targets + set(all_gem_dependencies ${gem_dependencies}) - unset(target_gem_dependencies_names) foreach(gem_target ${gem_dependencies}) + ly_get_gem_load_dependencies(gem_load_gem_dependencies ${gem_target}) + list(APPEND all_gem_dependencies ${gem_load_gem_dependencies}) + endforeach() + list(REMOVE_DUPLICATES all_gem_dependencies) + + unset(target_gem_dependencies_names) + foreach(gem_target ${all_gem_dependencies}) unset(gem_relative_source_dir) # Create path from the LY_ROOT_FOLDER to the the Gem directory if (NOT TARGET ${gem_target}) @@ -68,7 +125,7 @@ function(ly_delayed_generate_settings_registry) endif() get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) if(gem_relative_source_dir) - # Most gems CMakeLists.txt files reside in the Code/ so remove "Code/" from the path + # Most gems CMakeLists.txt files reside in the /Code/ so remove "Code/" from the path if(gem_relative_source_dir MATCHES ".*/Code$") get_filename_component(gem_relative_source_dir ${gem_relative_source_dir} DIRECTORY) endif() diff --git a/cmake/Tools/Platform/Android/android_deployment.py b/cmake/Tools/Platform/Android/android_deployment.py index f12a3a567f..957bb8833e 100644 --- a/cmake/Tools/Platform/Android/android_deployment.py +++ b/cmake/Tools/Platform/Android/android_deployment.py @@ -96,7 +96,7 @@ class AndroidDeployment(object): if asset_mode == 'PAK': self.local_asset_path = self.dev_root / 'Pak' / f'{game_name.lower()}_{asset_type}_paks' else: - self.local_asset_path = self.dev_root / 'Cache' / game_name / asset_type + self.local_asset_path = self.dev_root / game_name / 'Cache' / asset_type assert game_name is not None, f"'game_name' is required" self.game_name = game_name diff --git a/cmake/Tools/Platform/Android/android_support.py b/cmake/Tools/Platform/Android/android_support.py index c6f67b380d..a262d6f0c9 100644 --- a/cmake/Tools/Platform/Android/android_support.py +++ b/cmake/Tools/Platform/Android/android_support.py @@ -84,7 +84,7 @@ APP_SPLASH_NAME = 'app_splash.png' PYTHON_SCRIPT = 'python.cmd' if platform.system() == 'Windows' else 'python.sh' -ANDROID_LAUNCHER_NAME_PATTERN = "{game_name}.GameLauncher" +ANDROID_LAUNCHER_NAME_PATTERN = "{project_name}.GameLauncher" class AndroidProjectManifestEnvironment(object): """ @@ -92,43 +92,42 @@ class AndroidProjectManifestEnvironment(object): that were passed in or calculated from the command line arguments. """ - def __init__(self, dev_root, game_name, android_sdk_version_number, android_ndk_platform_number): + def __init__(self, engine_root, project_path, android_sdk_version_number, android_ndk_platform_number, is_test:bool): """ Initialize the object with the project specific parameters and values for the game project - :param dev_root: The dev-root path where the game is located - :param game_name: The name of the game + :param engine_root: The path where the engine is located + :param project_path: The path were the project is located :param android_sdk_version_number: The android SDK platform version :param android_ndk_platform_number: The android NDK platform version + :param is_test: Indicates if theAzTestRunner application should be run """ - is_test = game_name.lower() == TEST_RUNNER_PROJECT.lower() - if is_test: - # The AzTestRunner project.json is located under {dev_root}/Code/Tools/AzTestRunner/Platform/Android/android_project.json - game_folder_project_properties_path = dev_root / 'Code' / 'Tools' / 'AzTestRunner' / 'Platform' / 'Android' / 'android_project.json' + # The AzTestRunner project.json is located under {engine_root}/Code/Tools/AzTestRunner/Platform/Android/android_project.json + project_properties_path = engine_root / 'Code' / 'Tools' / 'AzTestRunner' / 'Platform' / 'Android' / 'android_project.json' else: # The project.json file is located under the game name folder - game_folder = dev_root / game_name - game_folder_project_properties_path = game_folder / 'project.json' + project_properties_path = project_path / 'project.json' # Read and parse the project.json file into a dictionary to process the specific attributes needed for the manifest template - game_project_properties_content = game_folder_project_properties_path.resolve(strict=True)\ + project_properties_content = project_properties_path.resolve(strict=True)\ .read_text(encoding=common.DEFAULT_TEXT_READ_ENCODING, errors=common.ENCODING_ERROR_HANDLINGS) - self.game_name = game_name + self.project_path = project_path # Extract the key attributes we need to process and build up our environment table - game_project_json = json.loads(game_project_properties_content) + project_json = json.loads(project_properties_content) - product_name = game_project_json['product_name'] + project_name = project_json['project_name'] + product_name = project_json['product_name'] - game_project_android_settings = game_project_json['android_settings'] + game_project_android_settings = project_json['android_settings'] package_name = game_project_android_settings["package_name"] package_path = package_name.replace('.', '/') - project_activity = f'{TEST_RUNNER_PROJECT}Activity' if is_test else f'{self.game_name}Activity' + project_activity = f'{TEST_RUNNER_PROJECT}Activity' if is_test else f'{project_name}Activity' # Multiview options require special processing multi_window_options = AndroidProjectManifestEnvironment.process_android_multi_window_options(game_project_android_settings) @@ -140,9 +139,9 @@ class AndroidProjectManifestEnvironment(object): "ANDROID_VERSION_NAME": game_project_android_settings["version_name"], "ANDROID_SCREEN_ORIENTATION": game_project_android_settings["orientation"], 'ANDROID_APP_NAME': TEST_RUNNER_PROJECT if is_test else product_name, # external facing name - 'ANDROID_PROJECT_NAME': TEST_RUNNER_PROJECT if is_test else self.game_name, # internal facing name + 'ANDROID_PROJECT_NAME': TEST_RUNNER_PROJECT if is_test else project_name, # internal facing name 'ANDROID_PROJECT_ACTIVITY': project_activity, - 'ANDROID_LAUNCHER_NAME': TEST_RUNNER_PROJECT if is_test else ANDROID_LAUNCHER_NAME_PATTERN.format(game_name=self.game_name), + 'ANDROID_LAUNCHER_NAME': TEST_RUNNER_PROJECT if is_test else ANDROID_LAUNCHER_NAME_PATTERN.format(project_name=project_name), 'ANDROID_CONFIG_CHANGES': multi_window_options['ANDROID_CONFIG_CHANGES'], 'ANDROID_APP_PUBLIC_KEY': game_project_android_settings.get('app_public_key', 'NoKey'), 'ANDROID_APP_OBFUSCATOR_SALT': game_project_android_settings.get('app_obfuscator_salt', ''), @@ -297,7 +296,7 @@ PLATFORM_SETTINGS_FORMAT = """ [settings] platform={platform} -game_projects={game_project} +game_projects={project_path} asset_deploy_mode={asset_mode} asset_deploy_type={asset_type} @@ -336,7 +335,7 @@ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_FORMAT_STR = """ task copyNativeLibs{config}(type: Copy) {{ delete 'outputs/native-lib/{abi}' - from fileTree(dir: 'build/intermediates/cmake/{config_lower}/obj/arm64-v8a/{config_lower}', include: '**/*.so', exclude: 'lib{game_name}.GameLauncher.so' ) + from fileTree(dir: 'build/intermediates/cmake/{config_lower}/obj/arm64-v8a/{config_lower}', include: '**/*.so', exclude: 'lib{project_name}.GameLauncher.so' ) into 'outputs/native-lib/{abi}' }} @@ -363,7 +362,7 @@ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR = """ CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR = """ task syncLYLayoutMode{config}(type:Exec) {{ workingDir '{working_dir}' - commandLine '{python_full_path}', 'layout_tool.py', '--dev-root', '{dev_root}', '-p', 'Android', '-a', '{asset_type}', '-g', '{game_name}', '-m', '{asset_mode}', '--create-layout-root', '-l', '{asset_layout_folder}' + commandLine '{python_full_path}', 'layout_tool.py', '--project-path', '{project_path}', '-p', 'Android', '-a', '{asset_type}', '-m', '{asset_mode}', '--create-layout-root', '-l', '{asset_layout_folder}' }} compile{config}Sources.dependsOn syncLYLayoutMode{config} """ @@ -424,17 +423,19 @@ class AndroidProjectGenerator(object): Class the manages the process to generate an android project folder in order to build with gradle/android studio """ - def __init__(self, dev_root, build_dir, android_ndk_path, android_sdk_path, android_sdk_version, android_ndk_platform, game_name, third_party_path, cmake_version, override_cmake_path, override_gradle_path, override_ninja_path, android_sdk_build_tool_version, include_assets_in_apk, asset_mode, asset_type, signing_config, is_test_project=False): + def __init__(self, engine_root, build_dir, android_ndk_path, android_sdk_path, android_sdk_version, android_ndk_platform, + project_path, third_party_path, cmake_version, override_cmake_path, override_gradle_path, override_ninja_path, + android_sdk_build_tool_version, include_assets_in_apk, asset_mode, asset_type, signing_config, is_test_project=False): """ Initialize the object with all the required parameters needed to create an Android Project. The parameters should be verified before initializing this object - :param dev_root: The dev-root that contains the engine and the game - :param build_dir: The target folder under the ${dev_root} where the android project folder will be created + :param engine_root: The engine root that contains the engine + :param build_dir: The target folder under the where the android project folder will be created :param android_ndk_path: The path to the ANDROID_NDK used for building the native android code :param android_sdk_path: The path to the ANDROID_SDK used for building the android java code :param android_sdk_version: The android platform version number to use for the Android SDK related builds :param android_ndk_platform: The android platform version number to use for the Android NDK related builds - :param game_name: The name of the game under the ${dev_root} to create the project for + :param project_path: The path to the project :param third_party_path: The required path to the lumberyard 3rd party path :param cmake_version: The version number of cmake that will be used by gradle :param override_cmake_path: The override path to cmake if it does not exists in the system path @@ -445,11 +446,11 @@ class AndroidProjectGenerator(object): :param asset_mode: :param asset_type: :param signing_config: Optional signing configuration arguments - :param is_test_project: Flag to indicate if this is a unit test runner project. (If true, game_name, asset_mode, asset_type, and include_assets_in_apk are ignored) + :param is_test_project: Flag to indicate if this is a unit test runner project. (If true, project_path, asset_mode, asset_type, and include_assets_in_apk are ignored) """ self.env = {} - self.dev_root = dev_root + self.engine_root = engine_root self.build_dir = build_dir @@ -457,7 +458,7 @@ class AndroidProjectGenerator(object): self.android_sdk_path = android_sdk_path - self.android_project_builder_path = dev_root / 'Code/Tools/Android/ProjectBuilder' + self.android_project_builder_path = self.engine_root / 'Code/Tools/Android/ProjectBuilder' self.android_sdk_version = android_sdk_version @@ -465,7 +466,7 @@ class AndroidProjectGenerator(object): self.android_ndk_platform = android_ndk_platform - self.game_name = game_name + self.project_path = project_path self.third_party_path = third_party_path @@ -507,7 +508,7 @@ class AndroidProjectGenerator(object): 'SDK_VER': self.android_sdk_version, 'NDK_PLATFORM_VER': self.android_ndk_platform, 'SDK_BUILD_TOOL_VER': self.android_sdk_build_tool_version, - 'LY_DEV_ROOT': common.normalize_path_for_settings(self.dev_root) + 'LY_ENGINE_ROOT': common.normalize_path_for_settings(self.engine_root) } # Generate the gradle build script self.create_file_from_project_template(src_template_file='root.build.gradle.in', @@ -570,7 +571,7 @@ class AndroidProjectGenerator(object): if self.is_test_project: platform_settings_content = PLATFORM_SETTINGS_FORMAT.format(generation_timestamp=str(datetime.datetime.now().strftime("%c")), platform='android', - game_project=TEST_RUNNER_PROJECT, + project_path=TEST_RUNNER_PROJECT, asset_mode='', asset_type='', android_sdk_path=str(self.android_sdk_path), @@ -578,7 +579,7 @@ class AndroidProjectGenerator(object): else: platform_settings_content = PLATFORM_SETTINGS_FORMAT.format(generation_timestamp=str(datetime.datetime.now().strftime("%c")), platform='android', - game_project=self.game_name, + project_path=self.project_path, asset_mode=self.asset_mode, asset_type=self.asset_type, android_sdk_path=str(self.android_sdk_path), @@ -709,22 +710,16 @@ class AndroidProjectGenerator(object): # Prepare the 'PROJECT_DEPENDENCIES' environment variable gradle_project_dependencies = [f" api project(path: ':{project_dependency}')" for project_dependency in project_dependencies] - template_dev_root = common.normalize_path_for_settings(self.dev_root) + template_engine_root = common.normalize_path_for_settings(self.engine_root) template_third_party_path = common.normalize_path_for_settings(self.third_party_path) template_ndk_path = common.normalize_path_for_settings(self.android_ndk_path) gradle_build_env = dict() - # Calculate the relative path of the engine root based on the target build directory, which is - # expected to be at the same folder level as the engine root - relative_engine_root_path = '' - target_app_root_path = self.dev_root / self.build_dir / 'app' - while target_app_root_path != self.dev_root: - target_app_root_path = target_app_root_path.parent - relative_engine_root_path += '../' + engine_root_as_path= pathlib.PurePath(self.engine_root) - relative_cmakelist_path = relative_engine_root_path + 'CMakeLists.txt' - relative_azandroid_path = relative_engine_root_path + 'Code/Framework/AzAndroid/java' + relative_cmakelist_path = (engine_root_as_path / 'CMakeLists.txt').as_posix() + relative_azandroid_path = (engine_root_as_path / 'Code/Framework/AzAndroid/java').as_posix() gradle_build_env['TARGET_TYPE'] = 'application' gradle_build_env['PROJECT_DEPENDENCIES'] = PROJECT_DEPENDENCIES_VALUE_FORMAT.format(dependencies='\n'.join(gradle_project_dependencies)) @@ -744,13 +739,13 @@ class AndroidProjectGenerator(object): # Prepare the cmake argument list based on the collected android settings and each build config cmake_argument_list = [ '"-GNinja"', - f'"-S{template_dev_root}"', + f'"-S{template_engine_root}"', f'"-DCMAKE_BUILD_TYPE={native_config_lower}"', - f'"-DCMAKE_TOOLCHAIN_FILE={template_dev_root}/cmake/Platform/Android/Toolchain_Android.cmake"', + f'"-DCMAKE_TOOLCHAIN_FILE={template_engine_root}/cmake/Platform/Android/Toolchain_Android.cmake"', f'"-DLY_3RDPARTY_PATH={template_third_party_path}"'] if not self.is_test_project: - cmake_argument_list.append(f'"-DLY_PROJECTS={self.game_name}"') + cmake_argument_list.append(f'"-DLY_PROJECTS={pathlib.PurePath(self.project_path).as_posix()}"') else: cmake_argument_list.append('"-DLY_TEST_PROJECT=1"') @@ -766,44 +761,46 @@ class AndroidProjectGenerator(object): if self.override_ninja_path: cmake_argument_list.append(f'"-DCMAKE_MAKE_PROGRAM={common.normalize_path_for_settings(self.override_ninja_path)}"') + # Query the project_path from the project.json file + project_name = common.read_project_name_from_project_json(self.project_path) # Prepare the config-specific section to place the cmake argument list in the build.gradle for the app gradle_build_env[f'NATIVE_CMAKE_SECTION_{native_config_upper}_CONFIG'] = \ - NATIVE_CMAKE_SECTION_BUILD_TYPE_CONFIG_FORMAT_STR.format(targets_section=f'targets "{self.game_name}.GameLauncher"' if not self.is_test_project else "", - arguments=','.join(cmake_argument_list)) - - # Prepare the config-specific section to copy the related .so files that are marked as dependencies for the target - # (launcher) since gradle will not include them automatically for APK import - gradle_build_env[f'CUSTOM_GRADLE_COPY_NATIVE_{native_config_upper}_LIB_TASK'] = \ - CUSTOM_GRADLE_COPY_NATIVE_CONFIG_FORMAT_STR.format(config=native_config, - config_lower=native_config_lower, - game_name=self.game_name, - abi=ANDROID_ARCH, - optional_test_excludes=",'*.Tests.so'" if not self.is_test_project else "") + NATIVE_CMAKE_SECTION_BUILD_TYPE_CONFIG_FORMAT_STR.format(targets_section=f'targets "{project_name}.GameLauncher"' + if project_name and not self.is_test_project else "", arguments=','.join(cmake_argument_list)) + + if project_name: + # Prepare the config-specific section to copy the related .so files that are marked as dependencies for the target + # (launcher) since gradle will not include them automatically for APK import + gradle_build_env[f'CUSTOM_GRADLE_COPY_NATIVE_{native_config_upper}_LIB_TASK'] = \ + CUSTOM_GRADLE_COPY_NATIVE_CONFIG_FORMAT_STR.format(config=native_config, + config_lower=native_config_lower, + project_name=project_name, + abi=ANDROID_ARCH, + optional_test_excludes=",'*.Tests.so'" if not self.is_test_project else "") if self.is_test_project: gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] = \ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR.format(config=native_config, config_lower=native_config_lower, - asset_layout_folder=common.normalize_path_for_settings(self.dev_root / self.build_dir / 'app/src/main/assets'), + asset_layout_folder=(self.project_path / self.build_dir / 'app/src/main/assets').as_posix(), file_includes='Test.Assets/**/*.*') else: # Copy over settings registry files from the Registry folder with build output directory gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] = \ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR.format(config=native_config, config_lower=native_config_lower, - asset_layout_folder=common.normalize_path_for_settings(self.dev_root / self.build_dir / 'app/src/main/assets'), + asset_layout_folder=(self.project_path / self.build_dir / 'app/src/main/assets').as_posix(), file_includes='**/Registry/*.setreg') if self.include_assets_in_apk: if not self.is_test_project: gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ - CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR.format(working_dir=common.normalize_path_for_settings(self.dev_root / 'cmake/Tools'), - python_full_path=common.normalize_path_for_settings(self.dev_root / 'python' / PYTHON_SCRIPT), - dev_root=common.normalize_path_for_settings(self.dev_root), + CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR.format(working_dir=common.normalize_path_for_settings(self.engine_root / 'cmake/Tools'), + python_full_path=common.normalize_path_for_settings(self.engine_root / 'python' / PYTHON_SCRIPT), asset_type=self.asset_type, - game_name=self.game_name, + project_path=self.project_path.as_posix(), asset_mode=self.asset_mode if native_config != 'Release' else 'PAK', - asset_layout_folder=common.normalize_path_for_settings(self.dev_root / self.build_dir / 'app/src/main/assets'), + asset_layout_folder=common.normalize_path_for_settings(self.project_path / self.build_dir / 'app/src/main/assets'), config=native_config) else: gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] = '' @@ -833,10 +830,11 @@ class AndroidProjectGenerator(object): # Generate a AndroidManifest.xml and write to ${az_android_dst_path}/src/main/AndroidManifest.xml dest_src_main_path = az_android_dst_path / 'src/main' dest_src_main_path.mkdir(parents=True) - az_android_package_env = AndroidProjectManifestEnvironment(dev_root=self.dev_root, - game_name=self.game_name, + az_android_package_env = AndroidProjectManifestEnvironment(engine_root=self.engine_root, + project_path=self.project_path, android_sdk_version_number=self.android_sdk_version, - android_ndk_platform_number=self.android_ndk_platform) + android_ndk_platform_number=self.android_ndk_platform, + is_test=self.is_test_project) self.create_file_from_project_template(src_template_file=ANDROID_MANIFEST_FILE, template_env=az_android_package_env, dst_file=dest_src_main_path / ANDROID_MANIFEST_FILE, @@ -972,17 +970,12 @@ class AndroidProjectGenerator(object): # Always return itself if the path is already and absolute path return pathlib.Path(source_path) - game_gem_resources = self.dev_root / self.game_name / 'Gem' / 'Resources' + game_gem_resources = self.project_path / 'Gem' / 'Resources' if game_gem_resources.is_dir(game_gem_resources): # If the source is relative and the game gem's resource is present, construct the path based on that return game_gem_resources / source_path - legacy_game_resources = self.dev_root / 'Code' / self.game_name / 'Resources' - if legacy_game_resources.is_dir(game_gem_resources): - # If the source is relative and the game is using the legacy code folder's resource, construct the path based on that - return legacy_game_resources / source_path - - raise common.LmbrCmdError("Unable to locate resources folder for game '{}'".format(self.game_name)) + raise common.LmbrCmdError(f'Unable to locate resources folder for project at path "{self.project_path}"') def resolve_icon_overrides(self, az_android_dst_path, az_android_package_env): """ @@ -1012,7 +1005,7 @@ class AndroidProjectGenerator(object): shutil.copyfile(src_default_icon_file.resolve(), dst_default_icon_file.resolve()) os.chmod(dst_default_icon_file.resolve(), stat.S_IWRITE | stat.S_IREAD) else: - logging.debug('No default icon override specified for %s', self.game_name) + logging.debug(f'No default icon override specified for project_at path {self.project_path}') # process each of the resolution overrides warnings = [] @@ -1028,11 +1021,11 @@ class AndroidProjectGenerator(object): # if both the resolution and the default are unspecified, warn the user but do nothing if icon_source is None: warnings.append(f'No icon override found for "{resolution}". Either supply one for "{resolution}" or a ' - f'"default" in the android_settings "icon" section of the project.json file for {self.game_name}') + f'"default" in the android_settings "icon" section of the project.json file for {self.project_path}') # if only the resolution is unspecified, remove the resolution specific version from the project else: - logging.debug('Default icon being used for "%s" in %s', resolution, self.game_name) + logging.debug(f'Default icon being used for "{resolution}" in {self.project_path}', resolution) common.remove_dir_path(target_directory) continue @@ -1072,7 +1065,7 @@ class AndroidProjectGenerator(object): unused_override_warning = None if (orientation & orientation_flag) == 0: unused_override_warning = f'Splash screen overrides specified for "{orientation_key}" when desired orientation ' \ - f'is set to "{ORIENTATION_FLAG_TO_KEY_MAP[orientation]}" in project {self.game_name}. ' \ + f'is set to "{ORIENTATION_FLAG_TO_KEY_MAP[orientation]}" in project {self.project_path}. ' \ f'These overrides will be ignored.' # if a default splash image is specified for this orientation, then copy it into the generic drawable- folder @@ -1092,7 +1085,8 @@ class AndroidProjectGenerator(object): shutil.copyfile(src_default_splash_img_file.resolve(), dst_default_splash_img_file.resolve()) os.chmod(dst_default_splash_img_file.resolve(), stat.S_IWRITE | stat.S_IREAD) else: - logging.debug(f'No default splash screen override specified for "%s" orientation in %s', orientation_key, self.game_name) + logging.debug(f'No default splash screen override specified for "%s" orientation in %s', orientation_key, + self.project_path) # process each of the resolution overrides warnings = [] @@ -1113,10 +1107,10 @@ class AndroidProjectGenerator(object): section = f"{orientation_key}-{resolution}" warnings.append(f'No splash screen override found for "{section}". Either supply one for "{resolution}" ' f'or a "default" in the android_settings "splash_screen-{orientation_key}" section of the ' - f'project.json file for {self.game_name}.') + f'project.json file for {self.project_path}.') else: # if only the resolution is unspecified, remove the resolution specific version from the project - logging.debug('Default splash screen being used for "%s-%s" in %s', orientation_key, resolution, self.game_name) + logging.debug(f'Default splash screen being used for "{orientation_key}-{resolution}" in {self.project_path}') common.remove_dir_path(target_directory) continue src_splash_img_file = self.construct_source_resource_path(splash_img_source) @@ -1133,7 +1127,8 @@ class AndroidProjectGenerator(object): for warning_msg in warnings: logging.warning(warning_msg) - def clear_unused_assets(self, az_android_dst_path, az_android_package_env): + @staticmethod + def clear_unused_assets(az_android_dst_path, az_android_package_env): """ micro-optimization to clear assets from the final bundle that won't be used @@ -1208,7 +1203,7 @@ class AndroidProjectGenerator(object): else: project_dependencies = "" - # Prepare an environemt for a basic, no-native (cmake) gradle project (java only) + # Prepare an environment for a basic, no-native (cmake) gradle project (java only) build_gradle_env = { 'PROJECT_DEPENDENCIES': project_dependencies, 'TARGET_TYPE': 'library', @@ -1478,6 +1473,7 @@ def verify_android_ndk(android_ndk_platform, argument_name, override_android_ndk validated_android_platforms.append(dir_item.name) # For NDK revisions 19 and up, there is a mapping file for version numbers that map to other version. + platforms_map_aliases = {} if ndk_revision_number >= LooseVersion('19.0.0'): platforms_map_file = check_android_ndk_path / 'meta/platforms.json' if platforms_map_file.exists(): diff --git a/cmake/Tools/Platform/Android/generate_android_project.py b/cmake/Tools/Platform/Android/generate_android_project.py index b31d094109..f9da1e4a02 100644 --- a/cmake/Tools/Platform/Android/generate_android_project.py +++ b/cmake/Tools/Platform/Android/generate_android_project.py @@ -26,7 +26,6 @@ if ROOT_DEV_PATH not in sys.path: from cmake.Tools import common from cmake.Tools.Platform.Android import android_support - GRADLE_ARGUMENT_NAME = '--gradle-install-path' GRADLE_MIN_VERSION = LooseVersion('4.10.1') GRADLE_MAX_VERSION = LooseVersion('5.6.4') @@ -148,12 +147,13 @@ def main(args): parser = argparse.ArgumentParser(description="Prepare the android studio subfolder") - parser.add_argument('--dev-root', - help='The path to the dev root. Defaults to the current working directory.', + parser.add_argument('--engine-root', + help='The path to the engine root. Defaults to the current working directory.', default=os.getcwd()) parser.add_argument('--build-dir', - help='The build dir subpath from the dev root', + help='The build dir path. It will be concatenated to the project-path using the rules of os.path.join', + type=pathlib.Path, required=True) parser.add_argument('--third-party-path', @@ -196,8 +196,8 @@ def main(args): default=None, required=False) - parser.add_argument('-g', '--game-name', - help='The game project to base off of') + parser.add_argument('-g', '--project-path', + help='The project path to generate an android project') # Asset Options parser.add_argument(INCLUDE_APK_ASSETS_ARGUMENT_NAME, @@ -266,15 +266,15 @@ def main(args): verified_android_ndk_platform, verified_android_ndk_path = android_support.verify_android_ndk(android_ndk_platform=parsed_args.get_argument(ANDROID_NDK_PLATFORM_ARGUMENT_NAME), argument_name=ANDROID_NDK_ARGUMENT_NAME, override_android_ndk_path=parsed_args.get_argument(ANDROID_NDK_ARGUMENT_NAME)) - if parsed_args.unit_test or parsed_args.game_name == android_support.TEST_RUNNER_PROJECT: - verified_game_name = android_support.TEST_RUNNER_PROJECT - _, verified_dev_root = common.verify_game_project_and_dev_root(game_name=None, - dev_root=parsed_args.dev_root) + if parsed_args.unit_test or parsed_args.project_path == android_support.TEST_RUNNER_PROJECT: + verified_project_path = android_support.TEST_RUNNER_PROJECT + _, verified_engine_root = common.verify_project_and_engine_root(project_root=None, + engine_root=parsed_args.dev_root) is_test_project = True else: - # Verify the dev-root and game name - verified_game_name, verified_dev_root = common.verify_game_project_and_dev_root(game_name=parsed_args.game_name, - dev_root=parsed_args.dev_root) + # Verify the engine root path and project path + verified_project_path, verified_engine_root = common.verify_project_and_engine_root(project_root=parsed_args.project_path, + engine_root=parsed_args.engine_root) is_test_project = False # Verify the 3rd Party Root Path @@ -285,26 +285,26 @@ def main(args): common.ERROR_CODE_INVALID_PARAMETER) third_party_path = third_party_path.parent - build_dir = verified_dev_root / parsed_args.build_dir + build_dir = parsed_args.build_dir signing_config = build_optional_signing_profile(store_file=parsed_args.get_argument(SIGNING_PROFILE_STORE_FILE_ARGUMENT_NAME), store_password=parsed_args.get_argument(SIGNING_PROFILE_STORE_PASSWORD_ARGUMENT_NAME), key_alias=parsed_args.get_argument(SIGNING_PROFILE_KEY_ALIAS_ARGUMENT_NAME), key_password=parsed_args.get_argument(SIGNING_PROFILE_KEY_PASSWORD_ARGUMENT_NAME)) - logging.debug("Dev Root : %s", str(verified_dev_root.resolve())) + logging.debug("Engine Root : %s", str(verified_engine_root.resolve())) logging.debug("Build Path : %s", str(build_dir.resolve())) logging.debug("Android NDK Path : %s", str(verified_android_ndk_path.resolve())) logging.debug("Android SDK Path : %s", str(verified_android_sdk_path.resolve())) # Prepare the generator and execute - generator = android_support.AndroidProjectGenerator(dev_root=verified_dev_root, + generator = android_support.AndroidProjectGenerator(engine_root=verified_engine_root, + project_path=verified_project_path, build_dir=build_dir, android_sdk_path=verified_android_sdk_path, android_ndk_path=verified_android_ndk_path, android_sdk_version=verified_android_sdk_platform, android_ndk_platform=verified_android_ndk_platform, - game_name=verified_game_name, third_party_path=third_party_path, cmake_version=cmake_version, override_cmake_path=override_cmake_path, diff --git a/cmake/Tools/Platform/Android/unit_test_android_deployment.py b/cmake/Tools/Platform/Android/unit_test_android_deployment.py index c08678b9e5..011033649a 100644 --- a/cmake/Tools/Platform/Android/unit_test_android_deployment.py +++ b/cmake/Tools/Platform/Android/unit_test_android_deployment.py @@ -90,7 +90,6 @@ def test_adb_call(mock_check_output): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -115,7 +114,6 @@ def test_adb_shell(mock_adb_call): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -141,7 +139,6 @@ def test_adb_ls_success(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -168,7 +165,6 @@ def test_adb_ls_error_no_output(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -195,7 +191,6 @@ def test_adb_ls_error_no_such_file(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -222,7 +217,6 @@ def test_adb_ls_error_permission_denied(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -250,7 +244,6 @@ def test_get_target_android_devices(mock_adb_call): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -277,7 +270,6 @@ def test_check_known_android_paths_success(mock_adb_ls): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -303,7 +295,6 @@ def test_check_known_android_paths_fail(mock_adb_ls): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -330,7 +321,6 @@ def test_detect_device_storage_path_no_external_storage_env(mock_check_known_and patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")),\ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -357,7 +347,6 @@ def test_detect_device_storage_path_invalid_external_storage_env(mock_check_know patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")),\ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -384,7 +373,6 @@ def test_detect_device_storage_path_valid_external_storage_env(mock_adb_ls, mock patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")),\ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -427,7 +415,6 @@ def test_detect_device_storage_path_real_path(): patch.object(android_deployment.AndroidDeployment, 'adb_ls', wraps=_mock_adb_ls), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -469,7 +456,6 @@ def test_detect_device_storage_path_real_path_fail(mock_check_known_android_path patch.object(android_deployment.AndroidDeployment, 'adb_ls', wraps=_mock_adb_ls), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -493,7 +479,6 @@ def test_get_device_file_timestamp_success(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -522,7 +507,6 @@ def test_get_device_file_timestamp_no_file(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -551,7 +535,6 @@ def test_get_device_file_timestamp_bad_timestamp_file(mock_adb_shell): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): - local_asset_path = pathlib.Path("Foo") inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -576,7 +559,7 @@ def test_get_device_file_timestamp_bad_timestamp_file(mock_adb_shell): def test_update_device_file_timestamp(tmpdir): - cache_dir = f'{TEST_DEV_ROOT}/Cache/{TEST_GAME_NAME}/{TEST_ASSET_TYPE}' + cache_dir = f'{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}' tmpdir.ensure(f'{cache_dir}/foo.txt') mock_dev_root = tmpdir.join(TEST_DEV_ROOT).realpath() @@ -585,7 +568,6 @@ def test_update_device_file_timestamp(tmpdir): patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_call', return_value="") as mock_adb_call: - local_asset_path = pathlib.Path(tmpdir.join(cache_dir).realpath()) inst = android_deployment.AndroidDeployment(dev_root=mock_dev_root, build_dir=TEST_BUILD_DIR, configuration='profile', @@ -624,8 +606,8 @@ def test_execute_success(tmpdir, test_config, test_package_name, test_device_sto tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").ensure() expected_apk_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").realpath()) - tmpdir.join(f"{TEST_DEV_ROOT}/Cache/{TEST_GAME_NAME}/{TEST_ASSET_TYPE}/dummy.txt").ensure() - expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/Cache/{TEST_GAME_NAME}/{TEST_ASSET_TYPE}").realpath()) + tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}/dummy.txt").ensure() + expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry/dummy.txt").ensure() expected_registry_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry").realpath()) @@ -696,8 +678,8 @@ def test_execute_clean_deploy_success(tmpdir, test_game_name, test_config, test_ tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").ensure() expected_apk_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").realpath()) - tmpdir.join(f"{TEST_DEV_ROOT}/Cache/{test_game_name}/{test_asset_type}/dummy.txt").ensure() - expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/Cache/{test_game_name}/{test_asset_type}").realpath()) + tmpdir.join(f"{TEST_DEV_ROOT}/{test_game_name}/Cache/{test_asset_type}/dummy.txt").ensure() + expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{test_game_name}/Cache/{test_asset_type}").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry/dummy.txt").ensure() expected_registry_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry").realpath()) @@ -792,8 +774,7 @@ def test_execute_incremental_deploy_success(tmpdir, test_config, test_package_na tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").ensure() expected_apk_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").realpath()) - tmpdir.join(f"{TEST_DEV_ROOT}/Cache/{TEST_GAME_NAME}/{TEST_ASSET_TYPE}/dummy.txt").ensure() - expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/Cache/{TEST_GAME_NAME}/{TEST_ASSET_TYPE}").realpath()) + tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}/dummy.txt").ensure() tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry/dummy.txt").ensure() expected_registry_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry").realpath()) diff --git a/cmake/Tools/Platform/Android/unit_test_generate_android_project.py b/cmake/Tools/Platform/Android/unit_test_generate_android_project.py index a61efc526f..5598942046 100644 --- a/cmake/Tools/Platform/Android/unit_test_generate_android_project.py +++ b/cmake/Tools/Platform/Android/unit_test_generate_android_project.py @@ -27,7 +27,7 @@ from cmake.Tools.Platform.Android import android_support, generate_android_proje @pytest.mark.parametrize( "from_override, version_str, expected_result", [ pytest.param(False, b"Gradle 4.10.1", LooseVersion('4.10.1'), id='equalMinVersion'), - pytest.param(False, b"Gradle 5.6.4", LooseVersion('5.6.4'), id='eualMaxVersion'), + pytest.param(False, b"Gradle 5.6.4", LooseVersion('5.6.4'), id='equalMaxVersion'), pytest.param(False, b"Gradle 1.0", common.LmbrCmdError('error', common.ERROR_CODE_ENVIRONMENT_ERROR), id='lessThanMinVersion'), pytest.param(False, b"Gradle 26.3", common.LmbrCmdError('error', common.ERROR_CODE_ENVIRONMENT_ERROR), id='greaterThanMaxVersion'), pytest.param(True, b"Gradle 4.10.1", LooseVersion('4.10.1')), diff --git a/cmake/Tools/add_remove_gem.py b/cmake/Tools/add_remove_gem.py index df594e9859..01f8a7f12f 100644 --- a/cmake/Tools/add_remove_gem.py +++ b/cmake/Tools/add_remove_gem.py @@ -441,7 +441,7 @@ def add_remove_gem(add: bool, def _run_add_gem(args: argparse) -> int: return add_remove_gem(True, - common.determine_dev_root(), + common.determine_engine_root(), args.gem_path, args.project_path, args.project_restricted_path, @@ -451,7 +451,7 @@ def _run_add_gem(args: argparse) -> int: def _run_remove_gem(args: argparse) -> int: return add_remove_gem(False, - common.determine_dev_root(), + common.determine_engine_root(), args.gem_path, args.project_path, args.project_restricted_path, diff --git a/cmake/Tools/common.py b/cmake/Tools/common.py index 16290188d8..b174983bb1 100644 --- a/cmake/Tools/common.py +++ b/cmake/Tools/common.py @@ -30,9 +30,7 @@ from cmake.Tools import layout_tool DEFAULT_TEXT_READ_ENCODING = 'UTF-8' # The default encoding to use when reading from a text file DEFAULT_TEXT_WRITE_ENCODING = 'ascii' # The encoding to use when writing to a text file ENCODING_ERROR_HANDLINGS = 'ignore' # What to do if we encounter any encoding errors -DEFAULT_PAK_ROOT = 'Pak' # The default Pak root folder under dev where the game paks are built - -ROOT_DEV_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) +DEFAULT_PAK_ROOT = 'Pak' # The default Pak root folder under engine root where the game paks are built if platform.system() == 'Windows': # Re-use microsoft error codes since this script is meant to only run on windows host platforms @@ -53,7 +51,7 @@ else: ERROR_CODE_ENVIRONMENT_ERROR = 1 ERROR_CODE_GENERAL_ERROR = 1 -DEV_ROOT_CHECK_FILE = 'engine.json' +ENGINE_ROOT_CHECK_FILE = 'engine.json' HASH_CHUNK_SIZE = 200000 @@ -75,9 +73,25 @@ class LmbrCmdError(Exception): return str(self.msg) -def determine_dev_root(starting_path=None): +def read_project_name_from_project_json(project_path): + project_name = None + try: + with (pathlib.Path(project_path) / 'project.json').open('r') as project_file: + project_json = json.load(project_file) + project_name = project_json['project_name'] + except OSError as os_error: + logging.warning(f'Unable to open "project.json" file: {os_error}') + except json.JSONDecodeError as json_error: + logging.warning(f'Unable to decode json in {project_file}: {json_error}') + except KeyError as key_error: + logging.warning(f'{project_file} is missing project_name key: {key_error}') + + return project_name + + +def determine_engine_root(starting_path=None): """ - Determine the dev root of the engine. By default, the dev root is the engine path, which is determined by walking + Determine the engine root of the engine. By default, the engine root is the engine path, which is determined by walking up the current working directory until we find the engine.json marker :param starting_path: Optional starting path to look for the engine.json marker file, otherwise use the current working path @@ -86,14 +100,14 @@ def determine_dev_root(starting_path=None): current_path = os.path.normpath(starting_path or os.getcwd()) - check_file = os.path.join(current_path, DEV_ROOT_CHECK_FILE) + check_file = os.path.join(current_path, ENGINE_ROOT_CHECK_FILE) while not os.path.isfile(check_file): next_path = os.path.dirname(current_path) if next_path == current_path: # If going up one level results in the same path, we've hit the root break - check_file = os.path.join(next_path, DEV_ROOT_CHECK_FILE) + check_file = os.path.join(next_path, ENGINE_ROOT_CHECK_FILE) current_path = next_path if not os.path.isfile(check_file): @@ -123,34 +137,34 @@ def get_config_file_values(config_file_path, keys_to_extract): return result_map -def get_bootstrap_values(dev_root, keys_to_extract): +def get_bootstrap_values(engine_root, keys_to_extract): """ Extract requested values from the bootstrap.cfg file in the def root folder - :param dev_root: The dev root folder where bootstrap.cfg exists + :param engine_root: The engine root folder where bootstrap.cfg exists :param keys_to_extract: The keys to extract into a dictionary :return: Dictionary of keys and its values (for matched keys) """ - bootstrap_file = os.path.join(dev_root, 'bootstrap.cfg') + bootstrap_file = os.path.join(engine_root, 'bootstrap.cfg') if not os.path.isfile(bootstrap_file): - raise LmbrCmdError("Missing 'bootstrap.cfg' file from dev root ('{}')".format(dev_root), + raise LmbrCmdError("Missing 'bootstrap.cfg' file from engine root ('{}')".format(engine_root), ERROR_CODE_FILE_NOT_FOUND) result_map = get_config_file_values(bootstrap_file, keys_to_extract) return result_map -def validate_ap_config_asset_type_enabled(dev_root, bootstrap_asset_type): +def validate_ap_config_asset_type_enabled(engine_root, bootstrap_asset_type): """ Validate that the requested bootstrap asset type was enabled in the asset processor configuration file - :param dev_root: The dev root to lookup the AP config file + :param engine_root: The engine root to lookup the AP config file :param bootstrap_asset_type: The asset type to validate :return: True if the asset type was enabled, false if not """ - ap_config_file = os.path.join(dev_root, 'AssetProcessorPlatformConfig.ini') + ap_config_file = os.path.join(engine_root, 'AssetProcessorPlatformConfig.setreg') if not os.path.isfile(ap_config_file): - raise LmbrCmdError("Missing required asset processor configuration file at '{}'".format(dev_root), + raise LmbrCmdError("Missing required asset processor configuration file at '{}'".format(engine_root), ERROR_CODE_FILE_NOT_FOUND) parser = configparser.ConfigParser() @@ -285,48 +299,44 @@ def verify_tool(override_tool_path, tool_name, tool_filename, argument_name, too ERROR_CODE_ERROR_NOT_SUPPORTED) -def verify_game_project_and_dev_root(game_name, dev_root): +def verify_project_and_engine_root(project_root, engine_root): """ - Verify the dev root folder and the game name against that dev root. This will perform basic minimal checks + Verify the engine root folder and the project root folder. This will perform basic minimal checks for validation: - 1. Make sure bootstrap.cfg exists - 2. Make sure ${dev_root}/${game_name}/project.json exists + 1. Make sure ${engine_root}/engine.json + 2. Make sure ${project_root}/project.json exists 3. Make sure that the project.json minimally has a json structure with a 'project_name' attribute - The game name will be verified by returning the value of 'project_name' from the json file to minimize issues - on case-insensitive file systems because we rely on the fact that the game name matches the folder in which it resides + The project name will be verified by returning the value of 'project_name' from the json file to minimize issues + on case-insensitive file systems because we rely on the fact that the project name matches the folder in which it resides - :param game_name: The game name to verify. If None, skip the game name verification - :param dev_root: The dev root directory to verify - :return: A tuple of the actual 'project_name' from the game's project.json and the pathlib.Path of the dev root if verified + :param project_root: The project root to verify. If None, skip the project name verification + :param engine_root: The engine root directory to verify + :return: A tuple of the actual 'project_name' from the game's project.json and the pathlib.Path of the engine root if verified """ - dev_root_path = pathlib.Path(dev_root) - if not dev_root_path.exists(): - raise LmbrCmdError(f"Invalid dev root path ({dev_root})", + engine_root_path = pathlib.Path(engine_root) + if not engine_root_path.exists(): + raise LmbrCmdError(f"Invalid engine root path ({engine_root})", ERROR_CODE_INVALID_PARAMETER) - # Sanity check: bootstrap - bootstrap_path = dev_root_path / 'bootstrap.cfg' - if not bootstrap_path.exists(): - raise LmbrCmdError(f"Invalid dev root path ({dev_root}). Missing bootstrap.cfg", + # Sanity check: engine.json + engine_json_path = engine_root_path / ENGINE_ROOT_CHECK_FILE + if not engine_json_path.exists(): + raise LmbrCmdError(f"Invalid engine root path ({engine_root}). Missing {ENGINE_ROOT_CHECK_FILE}", ERROR_CODE_INVALID_PARAMETER) - if game_name is None: - return None, dev_root_path + if project_root is None: + return None, engine_root_path else: - game_folder = dev_root_path / game_name - game_folder_project_properties = game_folder / 'project.json' - if not game_folder_project_properties.is_file(): - raise LmbrCmdError(f"Invalid game '{game_name}'. Make sure it exists under {dev_root}", + project_path = engine_root_path / project_root + project_path_project_properties = project_path / 'project.json' + if not project_path_project_properties.is_file(): + raise LmbrCmdError(f'Invalid project at path "{project_path}". It is missing the project.json file', ERROR_CODE_INVALID_PARAMETER) - try: - with open(game_folder_project_properties) as project_json_file: - project_json = json.load(project_json_file) - - return project_json['project_name'], dev_root_path - except (json.JSONDecodeError, KeyError) as e: - raise LmbrCmdError(f"Invalid game '{game_name}'. Its project.json is corrupt or invalid: {str(e)}", - ERROR_CODE_INVALID_PARAMETER) - + project_name = read_project_name_from_project_json(project_path) + if not project_name: + raise LmbrCmdError(f'Invalid project at path "{project_path}". Its project.json does not contains a "project_name" key', + ERROR_CODE_INVALID_PARAMETER) + return project_path, engine_root_path def remove_dir_path(path): """ @@ -444,13 +454,13 @@ def validate_build_dir_and_config(build_dir_name, configuration): return build_dir, build_config_dir -def validate_deployment_arguments(build_dir_name, configuration, game_name): +def validate_deployment_arguments(build_dir_name, configuration, project_path): """ Validate the minimal platform deployment arguments @param build_dir_name: The name of the build directory relative to the current working directory @param configuration: The configuration the deployment is based on - @param game_name: The name of the game project to deploy + @param project_path: The path the project to deploy @return: Tuple of (resolved build_dir, game name, asset mode, asset_type, and Pak root folder) """ @@ -458,16 +468,16 @@ def validate_deployment_arguments(build_dir_name, configuration, game_name): platform_settings = PlatformSettings(build_dir) - if not game_name: + if not project_path: if not platform_settings.projects: raise LmbrCmdError("Missing required game project argument. Unable to determine a default one.") - game_name = platform_settings.projects[0] - logging.info(f"Using default game project '{game_name}' as the game project") + internal_project_path = pathlib.PurePath(platform_settings.projects[0]).resolve() + logging.info(f"Using project_path '{internal_project_path}' as the game project") else: - if game_name not in platform_settings.projects: - raise LmbrCmdError(f"Game project {game_name} not valid. Was not configured for build directory {build_dir_name}.") + if project_path not in platform_settings.projects: + raise LmbrCmdError(f"Game project {project_path} not valid. Was not configured for build directory {build_dir_name}.") - return build_dir, game_name, platform_settings.asset_deploy_mode, platform_settings.asset_deploy_type, platform_settings.override_pak_root or DEFAULT_PAK_ROOT + return build_dir, project_path, platform_settings.asset_deploy_mode, platform_settings.asset_deploy_type, platform_settings.override_pak_root or DEFAULT_PAK_ROOT class CommandLineExec(object): @@ -547,20 +557,18 @@ class CommandLineExec(object): raise LmbrCmdError(f"Error trying to call '{self.executable_path}': {str(err)}") -def sync_platform_layout(platform_name, game_project, asset_mode, asset_type, layout_root): +def sync_platform_layout(platform_name, project_path, asset_mode, asset_type, layout_root): """ Perform a layout sync directly on the game project for a platform, game project, asset mode, asset type @param platform_name: The platform (lower) name to sync from - @param game_project: The game project to sync to + @param project_path: The path to project to sync to @param asset_mode: The asset mode to base the sync on @param asset_type: The asset type to base the sync on @param layout_root: The root of the layout to sync to - @param record_elapsed: Option to output the elapsed time """ - layout_tool.ASSET_SYNC_MODE_FUNCTION[asset_mode](dev_root=ROOT_DEV_PATH, - target_platform=platform_name, - game=game_project, + layout_tool.ASSET_SYNC_MODE_FUNCTION[asset_mode](target_platform=platform_name, + project_path=project_path, asset_type=asset_type, warning_on_missing_assets=True, layout_target=layout_root, @@ -603,37 +611,6 @@ def get_cmake_dependency_modules(build_dir_path, target, module_type): return dep_modules -GAME_FOLDER_REGEX = re.compile(r"sys_game_folder\s*=\s*(.*)") -GAME_NAME_REGEX = re.compile(r"sys_game_name\s*=\s*(.*)") - - -def transform_bootstrap_for_game(game_name, src_bootstrap, dst_bootstrap): - """ - Given a source bootstrap.cfg and game, write a copy of one to a different destination and transform it to - override its 'sys_game_folder' or 'sys_game_name' to match the input game_name - - :param game_name: The name of the game to set in the destination bootstrap - :param src_bootstrap: The absolute path of the source bootstrap - :param dst_bootstrap: The absolute path of the destination bootstrap file to write to (or overwrite) - """ - with open(src_bootstrap, "r") as src_bootstrap_file: - bootstrap_lines = src_bootstrap_file.readlines() - with open(dst_bootstrap, "w") as dst_bootstrap_file: - sys_game_detected = False - for bootstrap_line in bootstrap_lines: - if GAME_FOLDER_REGEX.match(bootstrap_line): - dst_bootstrap_file.write(f'sys_game_folder={game_name}\n') - sys_game_detected = True - elif GAME_NAME_REGEX.match(bootstrap_line): - dst_bootstrap_file.write(f'sys_game_name={game_name}\n') - sys_game_detected = True - else: - dst_bootstrap_file.write(bootstrap_line) - if not sys_game_detected: - # If no sys_game* is detected, inject one to prevent an error at least in the target - dst_bootstrap_file.write(f'sys_game_folder={game_name}\n') - - def get_test_module_registry(build_dir_path): """ Read a test module registry file for for all test modules that are enabled for a target build directory diff --git a/cmake/Tools/current_project.py b/cmake/Tools/current_project.py index 4d87f90f10..10d6b73ffa 100644 --- a/cmake/Tools/current_project.py +++ b/cmake/Tools/current_project.py @@ -36,7 +36,7 @@ def set_current_project(dev_root: str, try: with open(os.path.join(dev_root, 'bootstrap.cfg'), 'r') as s: data = s.read() - data = re.sub(r'(.*sys_game_folder\s*?[=:]\s*?)([^\n]+)\n', r'\1 {}\n'.format(project_path), + data = re.sub(r'(.*project_path\s*?[=:]\s*?)([^\n]+)\n', r'\1 {}\n'.format(project_path), data, flags=re.IGNORECASE) if os.path.isfile(os.path.join(dev_root, 'bootstrap.cfg')): os.unlink(os.path.join(dev_root, 'bootstrap.cfg')) @@ -52,29 +52,29 @@ def get_current_project(dev_root: str) -> str: """ get what the current project set is :param dev_root: the dev root of the engine - :return: sys_game_folder or None on failure + :return: project_path or None on failure """ try: with open(os.path.join(dev_root, 'bootstrap.cfg'), 'r') as s: data = s.read() - sys_game_folder = re.search(r'(.*sys_game_folder\s*?[=:]\s*?)(?P[^\n]+)\n', - data, flags=re.IGNORECASE).group('sys_game_folder').strip() + project_path = re.search(r'(.*project_path\s*?[=:]\s*?)(?P[^\n]+)\n', + data, flags=re.IGNORECASE).group('project_path').strip() except Exception as e: logger.error('Failed to get current project. Exception: ' + str(e)) return '' - return sys_game_folder + return project_path def _run_get_current_project(args: argparse) -> int: - sys_game_folder = get_current_project(common.determine_dev_root()) - if sys_game_folder: - print(sys_game_folder) + project_path = get_current_project(common.determine_engine_root()) + if project_path: + print(project_path) return 0 return 1 def _run_set_current_project(args: argparse) -> int: - return set_current_project(common.determine_dev_root(), args.project_path) + return set_current_project(common.determine_engine_root(), args.project_path) def add_args(parser, subparsers) -> None: diff --git a/cmake/Tools/engine_template.py b/cmake/Tools/engine_template.py index 87c1f61977..754546f21e 100644 --- a/cmake/Tools/engine_template.py +++ b/cmake/Tools/engine_template.py @@ -416,17 +416,11 @@ def create_template(dev_root: str, source_restricted_path = source_restricted_path.replace('\\', '/') if not os.path.isabs(source_restricted_path): source_restricted_path = f'{dev_root}/{source_restricted_path}' - if not os.path.isdir(source_restricted_path): - logger.error(f'Src restricted path {source_restricted_path} is not a folder.') - return 1 # template_restricted_path template_restricted_path = template_restricted_path.replace('\\', '/') if not os.path.isabs(template_restricted_path): template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') - return 1 # source restricted relative source_restricted_platform_relative_path = source_restricted_platform_relative_path.replace('\\', '/') @@ -1015,17 +1009,11 @@ def create_from_template(dev_root: str, destination_restricted_path = destination_restricted_path.replace('\\', '/') if not os.path.isabs(destination_restricted_path): destination_restricted_path = f'{dev_root}/{destination_restricted_path}' - if not os.path.isdir(destination_restricted_path): - logger.error(f'Dst restricted path {destination_restricted_path} is not a folder.') - return 1 # template_restricted_path template_restricted_path = template_restricted_path.replace('\\', '/') if not os.path.isabs(template_restricted_path): template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') - return 1 # destination restricted relative destination_restricted_platform_relative_path = destination_restricted_platform_relative_path.replace('\\', '/') @@ -1137,17 +1125,11 @@ def create_project(dev_root: str, project_restricted_path = project_restricted_path.replace('\\', '/') if not os.path.isabs(project_restricted_path): project_restricted_path = f'{dev_root}/{project_restricted_path}' - if not os.path.isdir(project_restricted_path): - logger.error(f'Project restricted path {project_restricted_path} is not a folder.') - return 1 # template_restricted_path template_restricted_path = template_restricted_path.replace('\\', '/') if not os.path.isabs(template_restricted_path): template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') - return 1 # project restricted relative project_restricted_platform_relative_path = project_restricted_platform_relative_path.replace('\\', '/') @@ -1313,17 +1295,11 @@ def create_gem(dev_root: str, gem_restricted_path = gem_restricted_path.replace('\\', '/') if not os.path.isabs(gem_restricted_path): gem_restricted_path = f'{dev_root}/{gem_restricted_path}' - if not os.path.isdir(gem_restricted_path): - logger.error(f'Gem restricted path {gem_restricted_path} is not a folder.') - return 1 # template_restricted_path template_restricted_path = template_restricted_path.replace('\\', '/') if not os.path.isabs(template_restricted_path): template_restricted_path = f'{dev_root}/{template_restricted_path}' - if not os.path.isdir(template_restricted_path): - logger.error(f'Template restricted path {template_restricted_path} is not a folder.') - return 1 # gem restricted relative gem_restricted_platform_relative_path = gem_restricted_platform_relative_path.replace('\\', '/') @@ -1385,7 +1361,7 @@ def create_gem(dev_root: str, def _run_create_template(args: argparse) -> int: - return create_template(common.determine_dev_root(), + return create_template(common.determine_engine_root(), args.source_path, args.template_path, args.source_restricted_path, @@ -1398,7 +1374,7 @@ def _run_create_template(args: argparse) -> int: def _run_create_from_template(args: argparse) -> int: - return create_from_template(common.determine_dev_root(), + return create_from_template(common.determine_engine_root(), args.destination_path, args.template_path, args.destination_restricted_path, @@ -1411,7 +1387,7 @@ def _run_create_from_template(args: argparse) -> int: def _run_create_project(args: argparse) -> int: - return create_project(common.determine_dev_root(), + return create_project(common.determine_engine_root(), args.project_path, args.template_path, args.project_restricted_path, @@ -1427,7 +1403,7 @@ def _run_create_project(args: argparse) -> int: def _run_create_gem(args: argparse) -> int: - return create_gem(common.determine_dev_root(), + return create_gem(common.determine_engine_root(), args.gem_path, args.template_path, args.gem_restricted_path, diff --git a/cmake/Tools/generate_game_paks.py b/cmake/Tools/generate_game_paks.py index a3def75504..6a1ff1e458 100644 --- a/cmake/Tools/generate_game_paks.py +++ b/cmake/Tools/generate_game_paks.py @@ -176,10 +176,10 @@ def main(args): parser.add_argument('-b', '--binfolder', help='The relative location of the binary folder that contains the resource compiler and asset processor') - bootstrap = common.get_bootstrap_values(DEV_ROOT, ['sys_game_folder']) + bootstrap = common.get_bootstrap_values(DEV_ROOT, ['project_path']) parser.add_argument('-g', '--game-name', help='The name of the Game whose asset pak will be generated for', - default=bootstrap.get('sys_game_folder')) + default=bootstrap.get('project_path')) parser.add_argument('-p', '--asset-platform', help='The asset platform type to process') diff --git a/cmake/Tools/layout_tool.py b/cmake/Tools/layout_tool.py index cf3ec5d8c9..f219ab0622 100644 --- a/cmake/Tools/layout_tool.py +++ b/cmake/Tools/layout_tool.py @@ -11,14 +11,13 @@ import argparse -import datetime import hashlib import logging import os import pathlib import platform -import re import shutil +import stat import subprocess import sys import tempfile @@ -26,9 +25,9 @@ import timeit # Resolve the common python module -ROOT_DEV_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) -if ROOT_DEV_PATH not in sys.path: - sys.path.append(ROOT_DEV_PATH) +ROOT_ENGINE_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) +if ROOT_ENGINE_PATH not in sys.path: + sys.path.append(ROOT_ENGINE_PATH) from cmake.Tools import common @@ -51,21 +50,20 @@ PAK_ONLY_BUILD_CONFIGS = ['RELEASE'] PLATFORM_NAME = platform.system() -# List of files to blacklist from copying to the layout folder -COPY_ASSET_FILE_GENERAL_BLACKLIST_FILES = [ +# List of files to deny from copying to the layout folder +COPY_ASSET_FILE_GENERAL_DENYLIST_FILES = [ 'aztest_bootstrap.json', 'editor.cfg', - 'assetprocessorplatformconfig.ini', + 'assetprocessorplatformconfig.setreg', ] - -def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): +def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_type): """ Verify a layout folder (WRT to assets and configs) against the bootstrap and system config files @param layout_dir: The layout path to validate the asset mode against the bootstrap and system configs @param platform_name: The name of the platform the deployment is for - @param game_name: The game (project) name being deployed + @param project_path: The path to the project being deployed @param asset_mode: The desired asset mode (PAK, LOOSE, VFS) @param asset_type: The asset type @return: The number of possible errors in the configuration files based on the asset mode and type @@ -98,8 +96,15 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): warning_count = 0 + # Look up the project_path from the project.json file + project_name = common.read_project_name_from_project_json(project_path) + # If the project-name could not be read from the project.json, then the supplied project path does not + # point to a valid project + if not project_name: + return 1 + platform_name_lower = platform_name.lower() - game_name_lower = game_name.lower() + project_name_lower = project_path.lower() layout_path = pathlib.Path(layout_dir) # Validate bootstrap.cfg exists @@ -108,9 +113,7 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): warning_count += _warn(f"'bootstrap.cfg' is missing from {str(layout_path)}") bootstrap_values = None else: - bootstrap_values = common.get_config_file_values(str(bootstrap_file), ['sys_game_folder', - 'sys_game_name', - f'{platform_name_lower}_remote_filesystem', + bootstrap_values = common.get_config_file_values(str(bootstrap_file), [f'{platform_name_lower}_remote_filesystem', f'{platform_name_lower}_connect_to_remote', f'{platform_name_lower}_wait_for_connect', f'{platform_name_lower}_assets', @@ -120,9 +123,9 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): ]) # Validate the system_{platform}_{asset type}.cfg exists - platform_system_cfg_file = layout_path / f'system_{platform_name}_{asset_type}.cfg' + platform_system_cfg_file = layout_path / f'system_{platform_name_lower}_{asset_type}.cfg' if not platform_system_cfg_file.is_file(): - warning_count += _warn(f"'system_{platform_name}_{asset_type}.cfg' is missing from {str(layout_path)}") + warning_count += _warn(f"'system_{platform_name_lower}_{asset_type}.cfg' is missing from {str(layout_path)}") system_config_values = None else: system_config_values = common.get_config_file_values(str(platform_system_cfg_file), ['r_ShadersRemoteCompiler', @@ -133,14 +136,7 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): if bootstrap_values: remote_ip = bootstrap_values.get(f'{platform_name_lower}_remote_ip') or bootstrap_values.get('remote_ip') or LOCAL_HOST - remote_connect = bootstrap_values.get(f'{platform_name}_connect_to_remote') or '0' - - # Validate that the game name matches in bootstrap.cfg - bootstrap_game = bootstrap_values.get('sys_game_folder') or bootstrap_values.get('sys_game_name') - if not bootstrap_game: - warning_count += _warn("'bootstrap.cfg' is missing the game name set in 'sys_game_folder") - elif bootstrap_game != game_name: - warning_count += _warn(f"The game specified in bootstrap.cfg ({bootstrap_game}) does not match the game name specified for this deployment ({game_name})") + remote_connect = bootstrap_values.get(f'{platform_name_lower}_connect_to_remote') or '0' # Validate that the asset type for the platform matches the one set for the build bootstrap_asset_type = bootstrap_values.get(f'{platform_name_lower}_assets') or bootstrap_values.get('assets') @@ -152,9 +148,9 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): # Validate that if '_connect_to_remote is enabled, that the 'remote_ip' is not set to local host warning_count += _validate_remote_ap(remote_ip, remote_connect, None) - game_asset_path = layout_path / game_name_lower - if not game_asset_path.is_dir(): - warning_count += _warn(f"Asset folder for game {game_name} is missing from the deployment layout.") + project_asset_path = layout_path / project_name_lower + if not project_asset_path.is_dir(): + warning_count += _warn(f"Asset folder for project {project_name} is missing from the deployment layout.") elif system_config_values is not None: @@ -183,9 +179,9 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): # Validate that we have pak files pak_count = 0 has_shader_pak = False - game_paks = game_asset_path.glob("*.pak") - for game_pak in game_paks: - if game_pak.name == 'shadercachestartup.pak': + project_paks = project_asset_path.glob("*.pak") + for project_pak in project_paks: + if project_pak.name == 'shadercachestartup.pak': has_shader_pak = True pak_count += 1 @@ -196,7 +192,7 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): # If the shader paks are set, make sure that the remote shader compiler connection settings are set # or that it is going through AP if shaders_remote_compiler == '1': - warning_count += _warn(f"Shader paks are set for game {game_name} but remote shader compiling " + warning_count += _warn(f"Shader paks are set for project {project_name} but remote shader compiling " f"(r_ShadersRemoteCompiler) is still enabled " f"for it in system_{platform_name_lower}_{asset_type}.cfg.") else: @@ -205,7 +201,7 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): warning_count += _validate_remote_ap(remote_ip, remote_connect, False) if shaders_allow_compilation is not None and shaders_allow_compilation == '1': - warning_count += _warn(f"Shader paks are set for game {game_name} but shader compiling " + warning_count += _warn(f"Shader paks are set for project {project_name} but shader compiling " f"(r_ShadersAllowCompilation) is still enabled " f"for it in system_{platform_name_lower}_{asset_type}.cfg.") @@ -226,26 +222,23 @@ def verify_layout(layout_dir, platform_name, game_name, asset_mode, asset_type): return warning_count - - -def copy_asset_files_to_layout(game_name, game_asset_folder, target_platform, layout_target): +def copy_asset_files_to_layout(project_asset_folder, target_platform, layout_target): """ Perform the specific rules for copying files to the root level of the layout. - :param game_name: The name of the game - :param game_asset_folder: The source game asset folder to copy the files. (Will not traverse deeper than this folder) - :param target_platform: The target platform of the layout - :param layout_target: The target path of the target layout folder. + :param project_asset_folder: The source project asset folder to copy the files. (Will not traverse deeper than this folder) + :param target_platform: The target platform of the layout + :param layout_target: The target path of the target layout folder. """ - src_asset_contents = os.listdir(game_asset_folder) + src_asset_contents = os.listdir(project_asset_folder) allowed_system_config_prefix = 'system_{}'.format(target_platform.lower()) for src_file in src_asset_contents: - # For each source file found in the root of the source game asset folder, apply various rules to determine + # For each source file found in the root of the source project asset folder, apply various rules to determine # if we will copy the file to the layout destination or not - if src_file in COPY_ASSET_FILE_GENERAL_BLACKLIST_FILES: - # The source file is black-listed from being copied + if src_file in COPY_ASSET_FILE_GENERAL_DENYLIST_FILES: + # The source file is denied from being copied continue if src_file.startswith('system_'): @@ -255,7 +248,7 @@ def copy_asset_files_to_layout(game_name, game_asset_folder, target_platform, la continue # Resolve the absolute paths for source and destination to perform more specific checks - abs_src = os.path.join(game_asset_folder, src_file) + abs_src = os.path.join(project_asset_folder, src_file) abs_dst = os.path.join(layout_target, src_file) if os.path.isdir(abs_src): @@ -280,35 +273,33 @@ def copy_asset_files_to_layout(game_name, game_asset_folder, target_platform, la src_file, src_hash) continue - if os.path.basename(abs_src) == 'bootstrap.cfg': - logging.debug("Copying (%s) %s -> %s", game_name, abs_src, abs_dst) - common.transform_bootstrap_for_game(game_name, abs_src, abs_dst) - else: + logging.debug("Copying %s -> %s", abs_src, abs_dst) shutil.copy2(abs_src, abs_dst) -def remove_link(link): +def remove_link(link:pathlib.PurePath): """ Helper function to either remove a symlink, or remove a folder """ + link = pathlib.PurePath(link) if os.path.isdir(link): try: os.unlink(link) - except: - if PLATFORM_NAME == 'Windows': - rmdir_cmd = ['cmd', '/c', 'rmdir', '/J', '/S', link] - else: - rmdir_cmd = ['rm', '-rf', link] + except OSError: + # If unlink fails use shutil.rmtree + def remove_readonly(func, path, _): + "Clear the readonly bit and reattempt the removal" + os.chmod(path, stat.S_IWRITE) + func(path) + try: - logging.debug('Executing call %s', ' '.join(rmdir_cmd)) - subprocess.check_call(rmdir_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError as e: - raise common.LmbrCmdError("Error trying remove directory {}: {}".format(link, e), - e.returncode) + shutil.rmtree(link, onerror=remove_readonly) + except shutil.Error as shutil_error: + raise common.LmbrCmdError(f'Error trying remove directory {link}: {shutil_error}', shutil_error.errno) -def create_link(src, tgt, copy): +def create_link(src:pathlib.Path, tgt:pathlib.Path, copy): """ Helper function to create a directory link or copy a directory. On windows, this will be a directory junction, and on mac/linux this will be a soft link @@ -317,68 +308,74 @@ def create_link(src, tgt, copy): :param tgt: The target of the new link :param copy: Perform a directory copy instead of a link """ + src = pathlib.Path(src) + tgt = pathlib.Path(tgt) if copy: - if os.path.isdir(tgt): - os.rmdir(tgt) - logging.debug("Copying from %s to %s", src, tgt) - shutil.copytree(src, tgt, symlinks=False) - else: - logging.debug('Creating internal junction %s => %s in %s', src, tgt) - if PLATFORM_NAME == 'Windows': - link_type = 'junction' - junction_cmd = ['cmd', '/c', 'mklink', '/J', tgt, src] + # Remove the exist target + if tgt.is_symlink(): + tgt.unlink() else: - link_type = 'soft link' - junction_cmd = ['ln', '-s', src, tgt] + def remove_readonly(func, path, _): + "Clear the readonly bit and reattempt the removal" + os.chmod(path, stat.S_IWRITE) + func(path) + shutil.rmtree(tgt, onerror=remove_readonly) + + logging.debug(f'Copying from {src} to {tgt}') + shutil.copytree(str(src), str(tgt), symlinks=False) + else: + link_type = "symlink" + logging.debug(f'Creating symlink {src} =>{tgt}') try: - logging.debug('Executing call %s', ' '.join(junction_cmd)) - subprocess.check_call(junction_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError as e: - raise common.LmbrCmdError(f"Error trying to create {link_type} {src} => {tgt} : {str(e)}", e.returncode) + if PLATFORM_NAME == "Windows": + link_type = "junction" + import _winapi + _winapi.CreateJunction(str(src), str(tgt)) + else: + src.symlink_to(tgt, target_is_directory=True) + except OSError as e: + raise common.LmbrCmdError(f"Error trying to create {link_type} {src} => {tgt} : {e}", e.errno) -def construct_and_validate_cache_game_asset_folder(dev_root, game_name, asset_type, warn_on_missing_game_cache): +def construct_and_validate_cache_project_asset_folder(project_path, asset_type, warn_on_missing_project_cache): """ - Given the parameters for a game (name, dev root, asset type), construct and validate the absolute path + Given the parameters for a project (project_path, asset type), construct and validate the absolute path of where the built assets are (for LOOSE and VFS modes) - :param dev_root: The dev root to base the Cache folder search - :param game_name: The name of the game - :param asset_type: The type of asset - :param warn_on_missing_game_cache: Option to warn if the path is missing vs raising an exception - :return: The validated constructed cache game asset folder if it exists, None if not + :param project_path: The path to the project + :param asset_type: The type of asset + :param warn_on_missing_project_cache: Option to warn if the path is missing vs raising an exception + :return: The validated constructed cache project asset folder if it exists, None if not """ # Locate the Cache root folder - cache_game_folder_root = os.path.join(dev_root, CACHE_FOLDER_NAME, game_name) - if not os.path.isdir(cache_game_folder_root) and not warn_on_missing_game_cache: + cache_project_folder_root = os.path.join(project_path, CACHE_FOLDER_NAME) + if not os.path.isdir(cache_project_folder_root) and not warn_on_missing_project_cache: raise common.LmbrCmdError( - "Missing Cache folder for the game in the current dev root. Make sure that assets have been built " - "for the game '{}'".format(game_name), + f"Missing Cache folder for the project at path {project_path}. Make sure that assets have been built ", common.ERROR_CODE_ERROR_DIRECTORY) - # Locate based on the game's built asset type - cache_game_asset_folder = os.path.join(cache_game_folder_root, asset_type) - if os.path.isdir(cache_game_asset_folder): + # Locate based on the project's built asset type + cache_project_asset_folder = os.path.join(cache_project_folder_root, asset_type) + if os.path.isdir(cache_project_asset_folder): # TODO: Note, this is only checking the existence of the folder, not for any content validation - return cache_game_asset_folder + return cache_project_asset_folder - # Expected source of the game assets was not found - if not warn_on_missing_game_cache: + # Expected source of the project assets was not found + if not warn_on_missing_project_cache: raise common.LmbrCmdError( - "Missing compiled assets folder for the game. Make sure that assets for '{}' have been built " - "for the game '{}'".format(asset_type, game_name), + f'Missing compiled assets folder for the project at path {project_path}."' + f' Make sure that assets for "{asset_type}" have been built', common.ERROR_CODE_ERROR_DIRECTORY) return None -def sync_layout_vfs(dev_root, target_platform, game, asset_type, warning_on_missing_assets, layout_target, override_pak_folder, copy): +def sync_layout_vfs(target_platform, project_path, asset_type, warning_on_missing_assets, layout_target, override_pak_folder, copy): """ Perform the logic to sync the layout folder with assets in VFS mode - :param dev_root: The configured dev root :param target_platform: The target platform the layout is based on - :param game: The name of the game being synced + :param project_path: The path to the project being synced :param asset_type: The asset type being synced :param warning_on_missing_assets: If the built assets cannot be located (LOOSE or PAKs), then optionally warn vs raising an error :param layout_target: The target layout folder to perform the sync on @@ -386,71 +383,68 @@ def sync_layout_vfs(dev_root, target_platform, game, asset_type, warning_on_miss :param copy: Option to copy instead of attempting to symlink/junction """ - logging.debug("Syncing VFS layout for game '%s' to layout path '%s'", game, layout_target) + logging.debug(f'Syncing VFS layout for project at path "{project_path}" to layout path "{layout_target}"') - game_asset_folder = construct_and_validate_cache_game_asset_folder(dev_root=dev_root, - game_name=game, + project_asset_folder = construct_and_validate_cache_project_asset_folder(project_path=project_path, asset_type=asset_type, - warn_on_missing_game_cache=warning_on_missing_assets) + warn_on_missing_project_cache=warning_on_missing_assets) - game_folder = game.lower() - vfs_asset_source = os.path.join(game_asset_folder, game_folder, 'config') + vfs_asset_source = os.path.join(project_asset_folder, 'config') if not os.path.isdir(vfs_asset_source): - raise common.LmbrCmdError("Cache folder for the game '{}' missing 'config' folder".format(game), + raise common.LmbrCmdError("Cache folder for the project '{}' missing 'config' folder".format(project_path), common.ERROR_CODE_ERROR_DIRECTORY) # create a temporary folder that will serve as a working junction point into the layout hasher = hashlib.md5() - hasher.update(dev_root.encode('UTF-8')) - hasher.update(game_folder.encode('UTF-8')) + hasher.update(project_path.encode('UTF-8')) result = hasher.hexdigest() temp_dir = tempfile.gettempdir() temp_vfs_layout_path = os.path.join(temp_dir, 'ly-layout-{}'.format(result), 'vfs') - temp_vfs_layout_game_path = os.path.join(temp_vfs_layout_path, game_folder) + temp_vfs_layout_project_path = temp_vfs_layout_path - temp_vfs_layout_game_config_path = os.path.join(temp_vfs_layout_game_path, 'config') + temp_vfs_layout_project_config_path = os.path.join(temp_vfs_layout_project_path, 'config') # If the temporary folder was created previously, always reset it - if os.path.isdir(temp_vfs_layout_game_path): - if os.path.isdir(temp_vfs_layout_game_config_path): - os.rmdir(temp_vfs_layout_game_config_path) - shutil.rmtree(temp_vfs_layout_game_path) - os.makedirs(temp_vfs_layout_game_path, exist_ok=True) + if os.path.isdir(temp_vfs_layout_project_path): + if os.path.isdir(temp_vfs_layout_project_config_path): + os.rmdir(temp_vfs_layout_project_config_path) + shutil.rmtree(temp_vfs_layout_project_path) + os.makedirs(temp_vfs_layout_project_path, exist_ok=True) + + # Create the 'project asset platform cache' junction before copying configuration files at the engine root to it + layout_project_folder_target = layout_target + # Remove previous layout folder if it is a directory + if os.path.isdir(layout_project_folder_target): + remove_link(layout_project_folder_target) + if os.path.isdir(temp_vfs_layout_project_path): + create_link(temp_vfs_layout_project_path, layout_project_folder_target, copy) # Create the link - create_link(vfs_asset_source, temp_vfs_layout_game_config_path, copy) + create_link(vfs_asset_source, temp_vfs_layout_project_config_path, copy) # Create the assets to the layout - copy_asset_files_to_layout(game_name=game, - game_asset_folder=game_asset_folder, + copy_asset_files_to_layout(project_asset_folder=project_asset_folder, target_platform=target_platform, layout_target=layout_target) # Reset the 'gems' junction if any in the layout - layout_gems_folder_src = os.path.join(game_asset_folder, 'gems') + layout_gems_folder_src = os.path.join(project_asset_folder, 'gems') layout_gems_folder_target = os.path.join(layout_target, 'gems') if os.path.isdir(layout_gems_folder_target): remove_link(layout_gems_folder_target) if os.path.isdir(layout_gems_folder_src): create_link(layout_gems_folder_src, layout_gems_folder_target, copy) - # Reset the junction - layout_game_folder_target = os.path.join(layout_target, game_folder) - if os.path.isdir(layout_game_folder_target): - remove_link(layout_game_folder_target) - if os.path.isdir(temp_vfs_layout_game_path): - create_link(temp_vfs_layout_game_path, layout_game_folder_target, copy) -def sync_layout_non_vfs(mode, target_platform, dev_root, game, asset_type, warning_on_missing_assets, layout_target, override_pak_folder, copy): +def sync_layout_non_vfs(mode, target_platform, project_path, asset_type, warning_on_missing_assets, layout_target, override_pak_folder, copy): """ Perform the logic to sync the layout folder with assets in non-VFS mode (LOOSE or PAK) :param mode: 'LOOSE' or 'PAK' mode :param target_platform: The target platform the layout is based on - :param dev_root: The configured dev root - :param game: The name of the game being synced + :param project_path: The path to the project being synced :param asset_type: The asset type being synced :param warning_on_missing_assets: If the built assets cannot be located (LOOSE or PAKs), then optionally warn vs raising an error :param layout_target: The target layout folder to perform the sync on @@ -460,66 +454,67 @@ def sync_layout_non_vfs(mode, target_platform, dev_root, game, asset_type, warni assert mode in (ASSET_MODE_PAK, ASSET_MODE_LOOSE) - game_folder = game.lower() + project_name = common.read_project_name_from_project_json(project_path) + if not project_name: + raise common.LmbrCmdError(f'Project at path {project_path} does not have a valid project.json') + project_name_lower = project_name.lower() layout_gems_folder_target = os.path.join(layout_target, 'gems') if os.path.isdir(layout_gems_folder_target): remove_link(layout_gems_folder_target) - layout_game_folder_target = os.path.join(layout_target, game_folder) - if os.path.isdir(layout_game_folder_target): - remove_link(layout_game_folder_target) - if mode == ASSET_MODE_PAK: - target_pak_folder_name = '{}_{}_paks'.format(game_folder, asset_type) - game_asset_folder = os.path.join(dev_root, override_pak_folder or PAK_FOLDER_NAME, target_pak_folder_name) - if not os.path.isdir(game_asset_folder): + target_pak_folder_name = '{}_{}_paks'.format(project_name_lower, asset_type) + project_asset_folder = os.path.join(project_path, override_pak_folder or PAK_FOLDER_NAME, target_pak_folder_name) + if not os.path.isdir(project_asset_folder): if warning_on_missing_assets: - logging.warning("Pak folder for the game '{}' is missing (expected at '{}'). Skipping layout sync".format(game, game_asset_folder)) + logging.warning(f'Pak folder for the project at path "{project_path}" is missing' + f' (expected at "{project_asset_folder}"). Skipping layout sync') return else: - raise common.LmbrCmdError("Pak folder for the game '{}' is missing (expected at '{}')".format(game, game_asset_folder), + raise common.LmbrCmdError(f'Pak folder for the project at path "{project_path}" is missing (expected at' + f' "{project_asset_folder}")', common.ERROR_CODE_ERROR_DIRECTORY) elif mode == ASSET_MODE_LOOSE: - game_asset_folder = construct_and_validate_cache_game_asset_folder(dev_root=dev_root, - game_name=game, + project_asset_folder = construct_and_validate_cache_project_asset_folder(project_path=project_path, asset_type=asset_type, - warn_on_missing_game_cache=warning_on_missing_assets) - if not game_asset_folder: + warn_on_missing_project_cache=warning_on_missing_assets) + if not project_asset_folder: logging.warning( - "Cannot locate built assets for game '{}' (expected at '{}'). Skipping layout sync".format(game, - game_asset_folder)) + f'Cannot locate built assets for project at path "{project_path}" (expected at "{project_asset_folder}").' + f' Skipping layout sync') return else: assert False, "Invalid Mode {}".format(mode) + # Create the 'project asset platform cache' junction before copying additional files to it + layout_project_folder_src = project_asset_folder + # Remove previous layout folder if it is a directory + if os.path.isdir(layout_target): + remove_link(layout_target) + if os.path.isdir(layout_project_folder_src): + create_link(layout_project_folder_src, layout_target, copy) + # Create the assets to the layout - copy_asset_files_to_layout(game_name=game, - game_asset_folder=game_asset_folder, + copy_asset_files_to_layout(project_asset_folder=project_asset_folder, target_platform=target_platform, layout_target=layout_target) # Reset the 'gems' junction if any in the layout (only in loose mode). - layout_gems_folder_src = os.path.join(game_asset_folder, 'gems') + layout_gems_folder_src = os.path.join(project_asset_folder, 'gems') # The gems link only is valid in LOOSE mode. If in PAK, then dont re-link if mode == ASSET_MODE_LOOSE and os.path.isdir(layout_gems_folder_src): if os.path.isdir(layout_gems_folder_src): create_link(layout_gems_folder_src, layout_gems_folder_target, copy) - # Reset the junction - layout_game_folder_src = os.path.join(game_asset_folder, game_folder) - if os.path.isdir(layout_game_folder_src): - create_link(layout_game_folder_src, layout_game_folder_target, copy) - -def sync_layout_pak(dev_root, target_platform, game, asset_type, warning_on_missing_assets, layout_target, +def sync_layout_pak(target_platform, project_path, asset_type, warning_on_missing_assets, layout_target, override_pak_folder, copy): sync_layout_non_vfs(mode=ASSET_MODE_PAK, target_platform=target_platform, - dev_root=dev_root, - game=game, + project_path=project_path, asset_type=asset_type, warning_on_missing_assets=warning_on_missing_assets, layout_target=layout_target, @@ -527,12 +522,11 @@ def sync_layout_pak(dev_root, target_platform, game, asset_type, warning_on_miss copy=copy) -def sync_layout_loose(dev_root, target_platform, game, asset_type, warning_on_missing_assets, layout_target, +def sync_layout_loose(target_platform, project_path, asset_type, warning_on_missing_assets, layout_target, override_pak_folder, copy): sync_layout_non_vfs(mode=ASSET_MODE_LOOSE, target_platform=target_platform, - dev_root=dev_root, - game=game, + project_path=project_path, asset_type=asset_type, warning_on_missing_assets=warning_on_missing_assets, layout_target=layout_target, @@ -548,13 +542,10 @@ ASSET_SYNC_MODE_FUNCTION = { def main(args): - parser = argparse.ArgumentParser(description="Synchronize a game's assets to a layout folder") + parser = argparse.ArgumentParser(description="Synchronize a project's assets to a layout folder") - parser.add_argument('--dev-root', - help='The path to the dev root', - required=True) - parser.add_argument('-g', '--game', - help='Name of the game whose assets we will sync.', + parser.add_argument('--project-path', + help='The project path whose assets we will sync.', required=True) parser.add_argument('-p', '--platform', help='Target platform for the layout.', @@ -567,7 +558,7 @@ def main(args): help='Enable debug logs.') parser.add_argument('--warn-on-missing-assets', action='store_true', - help='If the game does not have any built assets, warn rather than return an error') + help='If the project does not have any built assets, warn rather than return an error') parser.add_argument('-m', '--mode', type=str, choices=ALL_ASSET_MODES, @@ -582,7 +573,7 @@ def main(args): parser.add_argument('--override-pak-folder', default='', help='(optional) If provided, use this path as the path to the pak folder when creating layouts ' - 'in PAK mode. Otherwise, use the dev-root/pak/${game}_${asset_type}_pak as the source pak folder') + 'in PAK mode. Otherwise, use the {project_path}/pak/${project}_${asset_type}_pak as the source pak folder') parser.add_argument('--build-config', default='', help='(optional) If provided, will adjust the asset mode if the provided build-config is "release"') @@ -599,32 +590,9 @@ def main(args): parsed_args = parser.parse_args(args) - # Validate the dev_root exists - if not os.path.exists(parsed_args.dev_root): - raise common.LmbrCmdError("Invalid dev root folder. '{}' does not exist".format(parsed_args.dev_root), - common.ERROR_CODE_INVALID_PARAMETER) - - if not os.path.isdir(parsed_args.layout_root): - # If the layout target doesnt exist, check if we want to create it - if parsed_args.create_layout_root: - try: - os.makedirs(parsed_args.layout_root, exist_ok=True) - except OSError as e: - raise common.LmbrCmdError("Unable to create layout folder '{}': {}".format(e, - parsed_args.layout_root), - common.ERROR_CODE_ERROR_DIRECTORY) - else: - raise common.LmbrCmdError("Invalid layout folder (--layout-root): '{}'".format(parsed_args.layout_root), - common.ERROR_CODE_ERROR_DIRECTORY) - # Prepare the logging logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG if parsed_args.debug else logging.INFO) - # Validate the dev root - for check_file in ('bootstrap.cfg', 'engine.json'): - if not os.path.isfile(os.path.join(parsed_args.dev_root, check_file)): - raise common.LmbrCmdError("Invalid value for --dev-root. Path '{}' missing file '{}'".format(parsed_args.dev_root, check_file), - common.ERROR_CODE_INVALID_PARAMETER) # Validate the asset mode input_asset_mode = parsed_args.mode.upper() if input_asset_mode not in ALL_ASSET_MODES: @@ -636,11 +604,10 @@ def main(args): if build_config in PAK_ONLY_BUILD_CONFIGS: input_asset_mode = ASSET_MODE_PAK - logging.info("Starting (%s) Asset Synchronization in %s mode and game %s", parsed_args.asset_type, input_asset_mode, parsed_args.game) + logging.info("Starting (%s) Asset Synchronization in %s mode and project %s", parsed_args.asset_type, input_asset_mode, parsed_args.project_path) start_time = timeit.default_timer() - ASSET_SYNC_MODE_FUNCTION[input_asset_mode](dev_root=os.path.normpath(parsed_args.dev_root), - target_platform=parsed_args.platform, - game=parsed_args.game, + ASSET_SYNC_MODE_FUNCTION[input_asset_mode](target_platform=parsed_args.platform, + project_path=parsed_args.project_path, asset_type=parsed_args.asset_type, warning_on_missing_assets=parsed_args.warn_on_missing_assets, layout_target=os.path.normpath(parsed_args.layout_root), @@ -649,10 +616,27 @@ def main(args): duration = timeit.default_timer() - start_time logging.info("Asset Synchronization complete {:.2f} seconds".format(duration)) + # Remove broken symlinks/junctions to the layout folder + if os.path.isdir(parsed_args.layout_root) and not os.path.exists(parsed_args.layout_root): + remove_link(parsed_args.layout_root) + + if not os.path.isdir(parsed_args.layout_root): + # If the layout target doesnt exist, check if we want to create it + if parsed_args.create_layout_root: + try: + os.makedirs(parsed_args.layout_root, exist_ok=True) + except OSError as e: + raise common.LmbrCmdError("Unable to create layout folder '{}': {}".format(e, + parsed_args.layout_root), + common.ERROR_CODE_ERROR_DIRECTORY) + else: + raise common.LmbrCmdError("Invalid layout folder (--layout-root): '{}'".format(parsed_args.layout_root), + common.ERROR_CODE_ERROR_DIRECTORY) + if parsed_args.verify: warnings = verify_layout(layout_dir=os.path.normpath(parsed_args.layout_root), platform_name=parsed_args.platform, - game_name=parsed_args.game, + project_path=parsed_args.project_path, asset_mode=input_asset_mode, asset_type=parsed_args.asset_type) if warnings > 0: diff --git a/cmake/Tools/unit_test_common.py b/cmake/Tools/unit_test_common.py index 343c0835eb..58f89876c3 100644 --- a/cmake/Tools/unit_test_common.py +++ b/cmake/Tools/unit_test_common.py @@ -24,7 +24,7 @@ from . import common pytest.param({'fake': 'foo'}, True, id="TestSuccess"), pytest.param(None, False, id="TestFail") ]) -def test_determine_dev_root(tmpdir, engine_json_content, expected_success): +def test_determine_engine_root(tmpdir, engine_json_content, expected_success): test_folder_heirarchy = 'dev/foo1/foo2/foo3/' tmpdir.ensure(test_folder_heirarchy) @@ -40,7 +40,7 @@ def test_determine_dev_root(tmpdir, engine_json_content, expected_success): expected_path = None starting_path = str(tmpdir.join(test_folder_heirarchy).realpath()) - result = common.determine_dev_root(starting_path) + result = common.determine_engine_root(starting_path) if expected_path: assert os.path.normcase(result) == os.path.normcase(expected_path) @@ -49,7 +49,7 @@ def test_determine_dev_root(tmpdir, engine_json_content, expected_success): TEST_BOOTSTRAP_CONTENT_1 = """ -sys_game_folder = Game1 +project_path = Game1 foo = bar key1 = value1 key2 = value2 @@ -58,7 +58,7 @@ assets = pc """ TEST_BOOTSTRAP_CONTENT_2 = """ -sys_game_folder = Game2 +project_path = Game2 foo = bar #------------------------- key1 = value1 @@ -70,12 +70,12 @@ assets = pc @pytest.mark.parametrize( "contents, input_keys, expected_result_map", [ - pytest.param(TEST_BOOTSTRAP_CONTENT_1, ['sys_game_folder', 'foo', 'assets'], {'sys_game_folder': 'Game1', + pytest.param(TEST_BOOTSTRAP_CONTENT_1, ['project_path', 'foo', 'assets'], {'project_path': 'Game1', 'foo': 'bar', 'assets': 'pc'}, id="TestFullMatch"), - pytest.param(TEST_BOOTSTRAP_CONTENT_2, ['sys_game_folder', 'foo', 'barnone'], {'sys_game_folder': 'Game2', + pytest.param(TEST_BOOTSTRAP_CONTENT_2, ['project_path', 'foo', 'barnone'], {'project_path': 'Game2', 'foo': 'bar'}, id="TestPartialMatch"), - pytest.param(TEST_BOOTSTRAP_CONTENT_2, ['sys_game_foldernone', 'foonone', 'barnone'], {}, id="TestNoMatch") + pytest.param(TEST_BOOTSTRAP_CONTENT_2, ['project_pathnone', 'foonone', 'barnone'], {}, id="TestNoMatch") ] ) def test_get_bootstrap_values_success(tmpdir, contents, input_keys, expected_result_map): @@ -223,9 +223,9 @@ subjectB = ${subject_B_value} TEST_GAME_PROJECT_JSON_FORMAT = """ {{ - "project_name": "{game_name}", - "product_name": "{game_name}", - "executable_name": "{game_name}.GameLauncher", + "project_name": "{project_name}", + "product_name": "{project_name}", + "executable_name": "{project_name}.GameLauncher", "modules" : [], "project_id": "{{4F3363D3-4A7C-47A6-B464-B21524771358}}", @@ -244,7 +244,7 @@ def test_verify_game_project_and_dev_root_success(tmpdir): dev_root = 'dev' game_name = 'MyFoo' game_folder = 'myfoo' - game_project_json = TEST_GAME_PROJECT_JSON_FORMAT.format(game_name=game_name) + game_project_json = TEST_GAME_PROJECT_JSON_FORMAT.format(project_name=game_name) tmpdir.ensure(f'{dev_root}/bootstrap.cfg') tmpdir.ensure(f'{dev_root}/{game_folder}/project.json') project_json_path = tmpdir / dev_root / game_folder / 'project.json' @@ -285,7 +285,7 @@ asset_deploy_type={test_asset_deploy_type} assert result.asset_deploy_type == test_asset_deploy_type -def test_transform_bootstrap_sysgamefolder(tmpdir): +def test_transform_bootstrap_project_path(tmpdir): tmpdir.ensure('bootstrap.cfg') @@ -293,7 +293,7 @@ def test_transform_bootstrap_sysgamefolder(tmpdir): -- Blah Blah -- Blah Blah -sys_game_folder=OldProject +project_path=OldProject -- remote_filesystem - enable Virtual File System (VFS) -- This feature allows a remote instance of the game to run off assets @@ -307,53 +307,19 @@ remote_filesystem=0 test_dst_bootstrap = tmpdir / 'bootstrap.transformed.cfg' test_game_name = 'FooBar' - common.transform_bootstrap_for_game(game_name=test_game_name, + common.transform_bootstrap_for_project(game_name=test_game_name, src_bootstrap=str(test_src_bootstrap), dst_bootstrap=str(test_dst_bootstrap)) transformed_text = test_dst_bootstrap.read_text('ascii') - search_gamename = re.search(r"sys_game_folder\s*=\s*(.*)", transformed_text) + search_gamename = re.search(r"project_path\s*=\s*(.*)", transformed_text) assert search_gamename assert search_gamename.group(1) assert search_gamename.group(1) == test_game_name -def test_transform_bootstrap_sysgamename(tmpdir): - - tmpdir.ensure('bootstrap.cfg') - - test_bootstrap_content = """ --- Blah Blah --- Blah Blah - -sys_game_name=OldProject - --- remote_filesystem - enable Virtual File System (VFS) --- This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is off and can be overridden for any platform -remote_filesystem=0 -""" - test_src_bootstrap = tmpdir / 'bootstrap.cfg' - test_src_bootstrap.write_text(test_bootstrap_content, encoding='ascii') - - test_dst_bootstrap = tmpdir / 'bootstrap.transformed.cfg' - test_game_name = 'FooBar' - - common.transform_bootstrap_for_game(game_name=test_game_name, - src_bootstrap=str(test_src_bootstrap), - dst_bootstrap=str(test_dst_bootstrap)) - - transformed_text = test_dst_bootstrap.read_text('ascii') - - search_gamename = re.search(r"sys_game_name\s*=\s*(.*)", transformed_text) - assert search_gamename - assert search_gamename.group(1) - assert search_gamename.group(1) == test_game_name - - -def test_transform_bootstrap_sysgamefolder_missing(tmpdir): +def test_transform_bootstrap_project_path_missing(tmpdir): tmpdir.ensure('bootstrap.cfg') @@ -373,13 +339,13 @@ remote_filesystem=0 test_dst_bootstrap = tmpdir / 'bootstrap.transformed.cfg' test_game_name = 'FooBar' - common.transform_bootstrap_for_game(game_name=test_game_name, + common.transform_bootstrap_for_project(game_name=test_game_name, src_bootstrap=str(test_src_bootstrap), dst_bootstrap=str(test_dst_bootstrap)) transformed_text = test_dst_bootstrap.read_text('ascii') - search_gamename = re.search(r"sys_game_folder\s*=\s*(.*)", transformed_text) + search_gamename = re.search(r"project_path\s*=\s*(.*)", transformed_text) assert search_gamename assert search_gamename.group(1) assert search_gamename.group(1) == test_game_name diff --git a/cmake/Tools/unit_test_current_project.py b/cmake/Tools/unit_test_current_project.py index 1c1150eb8f..7db48b62aa 100644 --- a/cmake/Tools/unit_test_current_project.py +++ b/cmake/Tools/unit_test_current_project.py @@ -15,35 +15,35 @@ import pytest from . import current_project TEST_BOOTSTRAP_CONTENT_1 = """ -sys_game_folder = Game1 +project_path = Game1 foo = bar key1 = value1 key2 = value2 assets = pc """ TEST_BOOTSTRAP_CONTENT_2 = """ -sys_game_folder=Game1 +project_path=Game1 foo = bar key1 = value1 key2 = value2 assets = pc """ TEST_BOOTSTRAP_CONTENT_3 = """ -sys_game_folder= Game1 +project_path= Game1 foo = bar key1 = value1 key2 = value2 assets = pc """ TEST_BOOTSTRAP_CONTENT_4 = """ -sys_game_folder =Game1 +project_path =Game1 foo = bar key1 = value1 key2 = value2 assets = pc """ TEST_BOOTSTRAP_CONTENT_5 = """ -sys_game_folder = Game1 +project_path = Game1 foo = bar key1 = value1 key2 = value2 diff --git a/cmake/Tools/unit_test_layout_tool.py b/cmake/Tools/unit_test_layout_tool.py index 5314a1010a..5be2c23f11 100644 --- a/cmake/Tools/unit_test_layout_tool.py +++ b/cmake/Tools/unit_test_layout_tool.py @@ -37,9 +37,9 @@ def test_copy_asset_files_to_layout_success(): try: # Setup test vectors - # Blacklisted files, should not show up in the result - test_blacklisted_file = [ - 'assetprocessorplatformconfig.ini' + # Denied files, should not show up in the result + test_denylist_file = [ + 'assetprocessorplatformconfig.setreg' ] # System files that are not the same platform, so should skip test_skip_system_files = [ @@ -69,18 +69,14 @@ def test_copy_asset_files_to_layout_success(): 'good_src_2' ] test_expected_copied_files = test_dest_diff_as_src + test_src_not_in_dst - - test_dev_root = 'dev' - test_game = 'game1' - test_asset_type = 'pc' + test_game_asset_folder = 'game_cache' test_layout_target = 'layout_target' test_platform = 'goodplatform' - test_asset_mode = layout_tool.ASSET_MODE_LOOSE def _mock_os_listdir(path): assert path == test_game_asset_folder - mock_files = test_blacklisted_file + \ + mock_files = test_denylist_file + \ test_skip_system_files + \ test_skip_source_folders + \ test_skip_dest_is_folder + \ @@ -130,8 +126,7 @@ def test_copy_asset_files_to_layout_success(): result_copy_files.append(basename) shutil.copy2 = _mock_shutil_copy2 - layout_tool.copy_asset_files_to_layout(game_name=test_game, - game_asset_folder=test_game_asset_folder, + layout_tool.copy_asset_files_to_layout(project_asset_folder=test_game_asset_folder, target_platform=test_platform, layout_target=test_layout_target) @@ -217,17 +212,16 @@ def test_create_link_error(): @pytest.mark.parametrize( - "game_name, asset_type, ensure_path, warn_on_missing, expected_result", [ - pytest.param('Foo', 'pc', 'dev/Cache/Foo/pc/bootstrap.cfg', False, 'dev/Cache/Foo/pc'), + "project_path, asset_type, ensure_path, warn_on_missing, expected_result", [ + pytest.param('Foo', 'pc', 'Foo/Cache/pc/bootstrap.cfg', False, 'Foo/Cache/pc'), pytest.param('Foo', 'pc', 'dev/bootstrap.cfg', True, None), - pytest.param('Foo', 'pc', 'dev/Cache/Foo/es3/bootstrap.cfg', True, None), + pytest.param('Foo', 'pc', 'Foo/Cache/es3/bootstrap.cfg', True, None), pytest.param('Foo', 'pc', 'dev/bootstrap.cfg', False, common.LmbrCmdError), - pytest.param('Foo', 'pc', 'dev/Cache/Foo/es3/bootstrap.cfg', False, common.LmbrCmdError), + pytest.param('Foo', 'pc', 'Foo/Cache/es3/bootstrap.cfg', False, common.LmbrCmdError), ] ) -def test_construct_and_validate_cache_game_asset_folder_success(tmpdir, game_name, asset_type, ensure_path, warn_on_missing, expected_result): +def test_construct_and_validate_cache_game_asset_folder_success(tmpdir, project_path, asset_type, ensure_path, warn_on_missing, expected_result): tmpdir.ensure(ensure_path) - dev_root_realpath = str(tmpdir.join('dev').realpath()) if isinstance(expected_result, str): expected_path_realpath = str(tmpdir.join(expected_result).realpath()) elif expected_result == common.LmbrCmdError: @@ -236,10 +230,9 @@ def test_construct_and_validate_cache_game_asset_folder_success(tmpdir, game_nam expected_path_realpath = None try: - result = layout_tool.construct_and_validate_cache_game_asset_folder(dev_root=dev_root_realpath, - game_name=game_name, + result = layout_tool.construct_and_validate_cache_project_asset_folder(project_path=project_path, asset_type=asset_type, - warn_on_missing_game_cache=warn_on_missing) + warn_on_missing_project_cache=warn_on_missing) assert expected_result != common.LmbrCmdError, "Expecting an error result" if result == None: @@ -273,31 +266,22 @@ def test_sync_layout_vfs_success(tmpdir, existing_temp_vfs_folder, existing_gems try: # Simple Test Parameters - test_dev_root = str(tmpdir.join('dev').realpath()) - test_game = 'Foo' + test_engine_root = str(tmpdir.join('engine-root').realpath()) + test_project_path = str(tmpdir.join('Foo').realpath()) + test_project_name_lower = 'foo' test_target_platform = 'bogus' test_asset_type = 'pc' - game_folder = test_game.lower() # Setup a test dev and game cache folder structure inside the temp folder - path_to_src_cache = 'dev/Cache/{}/pc'.format(test_game) - path_to_src_cache_config = '{}/{}/config'.format(path_to_src_cache, test_game.lower()) - path_to_src_cache_config_file = '{}/game.xml'.format(path_to_src_cache_config) - tmpdir.ensure(path_to_src_cache_config_file) - - # Make a dummy config file - config_file = tmpdir.join(path_to_src_cache_config_file) - config_file.write('') # Capture relevant real paths in the temp folder so we can verify our assertions - cache_game_folder = os.path.join(test_dev_root, 'Cache', test_game) + cache_game_folder = os.path.join(test_project_path, 'Cache') cache_game_folder_gems = os.path.join(cache_game_folder, test_asset_type, 'gems') - - path_to_src_config_realpath = str(tmpdir.join(path_to_src_cache_config).realpath()) + layout_target_root_realpath = str(tmpdir.join('layout').realpath()) layout_target_gems_realpath = os.path.join(layout_target_root_realpath, 'gems') - layout_target_game_realpath = os.path.join(layout_target_root_realpath, test_game) + layout_target_game_realpath = os.path.join(layout_target_root_realpath) # If we are optionally testing existing links in a layout folder, track the expected and actual rmdirs actual_rmdir_paths = set() @@ -331,8 +315,7 @@ def test_sync_layout_vfs_success(tmpdir, existing_temp_vfs_folder, existing_gems # Predict the temp folder name hasher = hashlib.md5() - hasher.update(test_dev_root.encode('UTF-8')) - hasher.update(game_folder.encode('UTF-8')) + hasher.update(test_project_path.encode('UTF-8')) result = hasher.hexdigest() tmp_folder_subfolder = 'ly-layout-{}'.format(result) test_layout_folder = str(tmpdir.join('{}/vfs/foo'.format(tmp_folder_subfolder)).realpath()) @@ -347,7 +330,6 @@ def test_sync_layout_vfs_success(tmpdir, existing_temp_vfs_folder, existing_gems os.rmdir = _mock_os_rmdir mock_layout_tool_create_link_validation = { - os.path.normcase(path_to_src_config_realpath): os.path.normcase(test_layout_config_folder), os.path.normcase(cache_game_folder_gems): os.path.normcase(layout_target_gems_realpath), os.path.normcase(test_layout_folder): os.path.normcase(layout_target_game_realpath) } @@ -360,15 +342,14 @@ def test_sync_layout_vfs_success(tmpdir, existing_temp_vfs_folder, existing_gems layout_tool.create_link = _mock_layout_tool_create_link - def _mock_copy_asset_files_to_layout(game_name, game_asset_folder, target_platform, layout_target): + def _mock_copy_asset_files_to_layout(project_path, project_asset_folder, target_platform, layout_target): # Validate the correct call to copy asset files assert target_platform == target_platform assert os.path.normcase(layout_target) == os.path.normcase(layout_target_root_realpath) layout_tool.copy_asset_files_to_layout = _mock_copy_asset_files_to_layout - layout_tool.sync_layout_vfs(dev_root = test_dev_root, - target_platform = test_target_platform, - game = test_game, + layout_tool.sync_layout_vfs(target_platform = test_target_platform, + project_path = test_project_path, asset_type = test_asset_type, warning_on_missing_assets = False, layout_target = layout_target_root_realpath, @@ -404,19 +385,19 @@ def test_sync_layout_non_vfs_success(tmpdir, mode, existing_game_link, existing_ old_remove_link = layout_tool.remove_link try: # Simple Test Parameters - tmpdir.ensure('dev/bootstrap.cfg') - dev_root_realpath = str(tmpdir.join('dev').realpath()) - test_game = 'Foo' + tmpdir.ensure('engine-root/bootstrap.cfg') + engine_root_realpath = str(tmpdir.join('engine-root').realpath()) + test_project_path = str(tmpdir.join('Foo').realpath()) + test_project_name_lower = 'foo' test_target_platform = 'bogus' test_asset_type = 'pc' - game_folder = test_game.lower() - cache_game_folder_realpath = os.path.join(dev_root_realpath, 'Cache', test_game) + cache_game_folder_realpath = os.path.join(test_project_path, 'Cache') # Make sure a dummy layout folder is created tmpdir.ensure('layout/dummy.txt') test_layout_target_realpath = str(tmpdir.join('layout').realpath()) test_layout_target_gems_realpath = os.path.join(test_layout_target_realpath, 'gems') - test_layout_target_game_realpath = os.path.join(test_layout_target_realpath, game_folder) + test_layout_target_game_realpath = os.path.join(test_layout_target_realpath,) # If we are optionally testing existing links in a layout folder, track the expected and actual rmdirs actual_rmdir_paths = set() @@ -441,11 +422,13 @@ def test_sync_layout_non_vfs_success(tmpdir, mode, existing_game_link, existing_ if mode == 'PAK': # In PAK Mode, the linking rules are slightly different. The 'game folder' link points to inside the pak folder, and there is no 'gems' link if test_override_pak_folder: - test_game_asset_folder = os.path.join(dev_root_realpath, test_override_pak_folder, '{}_{}_paks'.format(game_folder, test_asset_type)) - cache_game_folder_game_realpath = os.path.join(test_game_asset_folder, game_folder) + test_game_asset_folder = os.path.join(engine_root_realpath, test_override_pak_folder, + f'{test_project_name_lower}_{test_asset_type}_paks') + cache_game_folder_game_realpath = os.path.join(test_game_asset_folder) else: - test_game_asset_folder = os.path.join(dev_root_realpath, 'Pak', '{}_{}_paks'.format(game_folder, test_asset_type)) - cache_game_folder_game_realpath = os.path.join(test_game_asset_folder, game_folder) + test_game_asset_folder = os.path.join(engine_root_realpath, 'Pak', + f'{test_project_name_lower}_{test_asset_type}_paks') + cache_game_folder_game_realpath = os.path.join(test_game_asset_folder) mock_layout_tool_create_link_validation[os.path.normcase(cache_game_folder_game_realpath)] = os.path.normcase(test_layout_target_game_realpath) @@ -460,7 +443,7 @@ def test_sync_layout_non_vfs_success(tmpdir, mode, existing_game_link, existing_ test_game_asset_folder = os.path.join(cache_game_folder_realpath, test_asset_type) cache_game_folder_gems_realpath = os.path.join(cache_game_folder_realpath, test_asset_type, 'gems') - cache_game_folder_game_realpath = os.path.join(cache_game_folder_realpath, test_asset_type, game_folder) + cache_game_folder_game_realpath = os.path.join(cache_game_folder_realpath, test_asset_type) mock_layout_tool_create_link_validation[os.path.normcase(cache_game_folder_gems_realpath)] = os.path.normcase(test_layout_target_gems_realpath) mock_layout_tool_create_link_validation[os.path.normcase(cache_game_folder_game_realpath)] = os.path.normcase(test_layout_target_game_realpath) @@ -468,8 +451,8 @@ def test_sync_layout_non_vfs_success(tmpdir, mode, existing_game_link, existing_ assert False, "Invalid Mode {}".format(mode) os.makedirs(test_game_asset_folder, exist_ok=True) - def _mock_copy_asset_files_to_layout(game_name, game_asset_folder, target_platform, layout_target): - assert os.path.normcase(game_asset_folder) == os.path.normcase(test_game_asset_folder) + def _mock_copy_asset_files_to_layout(project_path, project_asset_folder, target_platform, layout_target): + assert os.path.normcase(project_asset_folder) == os.path.normcase(test_game_asset_folder) assert target_platform == test_target_platform assert layout_target == test_layout_target_realpath layout_tool.copy_asset_files_to_layout = _mock_copy_asset_files_to_layout @@ -483,8 +466,7 @@ def test_sync_layout_non_vfs_success(tmpdir, mode, existing_game_link, existing_ layout_tool.sync_layout_non_vfs(mode = mode, target_platform = test_target_platform, - dev_root = dev_root_realpath, - game = test_game, + project_path = test_project_path, asset_type = test_asset_type, warning_on_missing_assets = False, layout_target = test_layout_target_realpath, diff --git a/cmake/UnitTest.cmake b/cmake/UnitTest.cmake index 3e96562d67..096f0f7e7e 100644 --- a/cmake/UnitTest.cmake +++ b/cmake/UnitTest.cmake @@ -70,7 +70,7 @@ set(test_json_template [[ set(test_module_template [[ "@stripped_test_target@": { - "Module":"$" + "Modules":["$"] }]] ) diff --git a/cmake/gemcmake.py b/cmake/gemcmake.py index 7efe2b2c7b..cf849367e1 100644 --- a/cmake/gemcmake.py +++ b/cmake/gemcmake.py @@ -55,7 +55,6 @@ def getGemCMakeListsTemplate(): ly_add_target( NAME {GEM_NAME} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.{GEM_NAME}.{GEM_UUID}.v{GEM_VERSION} FILES_CMAKE {GEM_NAME_LOWERCASE}_shared_files.cmake INCLUDE_DIRECTORIES @@ -70,9 +69,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME {GEM_NAME}.Editor MODULE + NAME {GEM_NAME}.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.{GEM_NAME}.Editor.{GEM_UUID}.v{GEM_VERSION} FILES_CMAKE {GEM_NAME_LOWERCASE}_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/cmake/projectcmake.py b/cmake/projectcmake.py index ac4c6f7630..7b39686475 100644 --- a/cmake/projectcmake.py +++ b/cmake/projectcmake.py @@ -38,7 +38,6 @@ def getProjectGemCMakeListsTemplate(): ly_add_target( NAME {GEM_NAME} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem - OUTPUT_NAME Gem.{GEM_NAME}.{GEM_UUID}.v{GEM_VERSION} FILES_CMAKE {GEM_NAME_LOWERCASE}_shared_files.cmake INCLUDE_DIRECTORIES @@ -53,9 +52,9 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME {GEM_NAME}.Editor MODULE + NAME {GEM_NAME}.Editor GEM_MODULE + NAMESPACE Gem - OUTPUT_NAME Gem.{GEM_NAME}.Editor.{GEM_UUID}.v{GEM_VERSION} FILES_CMAKE {GEM_NAME_LOWERCASE}_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/cmake/run_epbtest.cmake b/cmake/run_epbtest.cmake index 6f9c9de6dd..a0c5eb2b17 100644 --- a/cmake/run_epbtest.cmake +++ b/cmake/run_epbtest.cmake @@ -22,7 +22,7 @@ # EditorPythonBindings need to be enabled for the project we launch execute_process( - COMMAND ${CMD_ARG_EDITOR} -NullRenderer --skipWelcomeScreenDialog --autotest_mode --regset="/Amazon/AzCore/Bootstrap/sys_game_folder=${CMD_ARG_TEST_PROJECT}" --runpython ${CMD_ARG_PYTHON_SCRIPT} + COMMAND ${CMD_ARG_EDITOR} -NullRenderer --skipWelcomeScreenDialog --autotest_mode --regset="/Amazon/AzCore/Bootstrap/project_path=${CMD_ARG_TEST_PROJECT}" --runpython ${CMD_ARG_PYTHON_SCRIPT} TIMEOUT 1800 RESULT_VARIABLE TEST_CMD_RESULT ) diff --git a/ctest_scripts/CMakeLists.txt b/ctest_scripts/CMakeLists.txt index 17594862cb..3ce73dc900 100644 --- a/ctest_scripts/CMakeLists.txt +++ b/ctest_scripts/CMakeLists.txt @@ -22,15 +22,17 @@ endif() ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) - foreach(project ${LY_PROJECTS_NAME}) - add_custom_target(${project}.Assets - COMMENT "Processing ${project} assets..." - COMMAND $ --zeroAnalysisMode --gamefolder=${project} --platforms=${LY_ASSET_DEPLOY_ASSET_TYPE} + get_property(LY_PROJECTS_TARGET_NAME GLOBAL PROPERTY LY_PROJECTS_TARGET_NAME) + foreach(project_target_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJECTS) + file(REAL_PATH ${project_path} project_real_path BASE_DIRECTORY ${LY_ROOT_FOLDER}) + add_custom_target(${project_target_name}.Assets + COMMENT "Processing ${project_target_name} assets..." + COMMAND $ --zeroAnalysisMode --project-path=${project_real_path} --platforms=${LY_ASSET_DEPLOY_ASSET_TYPE} ) - set_target_properties(${project}.Assets + set_target_properties(${project_target_name}.Assets PROPERTIES EXCLUDE_FROM_ALL TRUE - FOLDER ${project} + FOLDER ${project_target_name} ) endforeach() endif() @@ -56,7 +58,7 @@ endforeach() # EPB Sanity test is being registered here to validate that the ly_add_editor_python_test function works. -if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_NAME) +if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS_TARGET_NAME) ly_add_editor_python_test( NAME epb_sanity_smoke_no_gpu TEST_PROJECT AutomatedTesting diff --git a/python/requirements.txt b/python/requirements.txt index 33ca62141b..9648a20ba0 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -223,6 +223,29 @@ python-utils==2.5.6 \ --hash=sha256:18fbc1a1df9a9061e3059a48ebe5c8a66b654d688b0e3ecca8b339a7f168f208 \ --hash=sha256:352d5b1febeebf9b3cdb9f3c87a3b26ef22d3c9e274a8ec1e7048ecd2fac4349 # via requirements.txt +PyYAML==5.4.1 \ + --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ + --hash=sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696 \ + --hash=sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393 \ + --hash=sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77 \ + --hash=sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922 \ + --hash=sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5 \ + --hash=sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8 \ + --hash=sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10 \ + --hash=sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc \ + --hash=sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018 \ + --hash=sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e \ + --hash=sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253 \ + --hash=sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183 \ + --hash=sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb \ + --hash=sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185 \ + --hash=sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db \ + --hash=sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46 \ + --hash=sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b \ + --hash=sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63 \ + --hash=sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df \ + --hash=sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc \ + # via requirements.txt requests==2.23.0 \ --hash=sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee \ --hash=sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6 \ diff --git a/scripts/build/build_node/Platform/Mac/init-setup.sh b/scripts/build/build_node/Platform/Mac/init-setup.sh new file mode 100644 index 0000000000..e5335f120e --- /dev/null +++ b/scripts/build/build_node/Platform/Mac/init-setup.sh @@ -0,0 +1,84 @@ +#!/bin/bash +set -euo pipefail + +# 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. + +BUILD_USER=$(aws ssm get-parameters --names "shared.builderuser" --region $region --with-decryption | ConvertFrom-Json) +BUILD_PASS=$(aws ssm get-parameters --names "shared.builderpass" --region $region --with-decryption | ConvertFrom-Json) + +echo "Setting up ${BUILD_USER} as autologin admin" +sudo sysadminctl -addUser "${BUILD_USER}" -fullName "${BUILD_USER}" -password "${BUILD_PASS}" -admin +sudo echo "${BUILD_USER} ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/${BUILD_USER} +sudo /usr/bin/defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser "${BUILD_USER}" + +echo "Change ownership for brew to ${BUILD_USER}" +sudo chown -R "${BUILD_USER}":admin $(brew --prefix)/* + +echo "Configure SSH" +mkdir /Users/"${BUILD_USER}"/.ssh +echo "PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" > /Users/"${BUILD_USER}"/.ssh/environment +sudo sed -i -e 's/#PermitUserEnvironment no/PermitUserEnvironment yes/g' /etc/ssh/sshd_config +sudo launchctl stop com.openssh.sshd && sudo launchctl start com.openssh.sshd + +echo "Expanding root volume to EBS configurated size" +PDISK=$(diskutil list physical external | head -n1 | cut -d" " -f1) +APFSCONT=$(diskutil list physical external | grep "Apple_APFS" | tr -s " " | cut -d" " -f8) +yes | sudo diskutil repairDisk ${PDISK} +sudo diskutil apfs resizeContainer ${APFSCONT} 0 + +echo "Removing hibernate and sleep image" +sudo pmset hibernatemode 0 +sudo rm -f /var/vm/sleepimage + +echo "Disable screensaver and sleep modes" +macUUID=$(ioreg -rd1 -c IOPlatformExpertDevice | grep -i "UUID" | cut -c27-62) + +rm -rf /Users/"${BUILD_USER}"/Library/Preferences/com.apple.screensaver.${macUUID}.plist +rm -rf /Users/"${BUILD_USER}"/Library/Preferences/ByHost/com.apple.screensaver.${macUUID}.plist +rm -rf /Users/"${BUILD_USER}"/Library/Preferences/com.apple.screensaver.plist +rm -rf /Users/"${BUILD_USER}"/Library/Preferences/ByHost/com.apple.screensaver.plist + +defaults write /Users/"${BUILD_USER}"/Library/Preferences/com.apple.screensaver.${macUUID}.plist idleTime -string 0 +defaults write /Users/"${BUILD_USER}"/Library/Preferences/com.apple.screensaver.${macUUID}.plist CleanExit "YES" +defaults write /Users/"${BUILD_USER}"/Library/Preferences/ByHost/com.apple.screensaver.${macUUID}.plist idleTime -string 0 +defaults write /Users/"${BUILD_USER}"/Library/Preferences/ByHost/com.apple.screensaver.${macUUID}.plist CleanExit "YES" +defaults write /Users/"${BUILD_USER}"/Library/Preferences/com.apple.screensaver.plist idleTime -string 0 +defaults write /Users/"${BUILD_USER}"/Library/Preferences/com.apple.screensaver.plist CleanExit "YES" +defaults write /Users/"${BUILD_USER}"/Library/Preferences/ByHost/com.apple.screensaver.plist idleTime -string 0 +defaults write /Users/"${BUILD_USER}"/Library/Preferences/ByHost/com.apple.screensaver.plist CleanExit "YES" + +chown -R "${BUILD_USER}":staff /Users/"${BUILD_USER}"/Library/Preferences/ByHost/ +chown -R "${BUILD_USER}":staff /Users/"${BUILD_USER}"/Library/Preferences/ + +killall cfprefsd + +# Set values to 0, to prevent sleep at all +pmset -a displaysleep 0 sleep 0 disksleep 0 + +echo "Disable automatic updates" +sudo softwareupdate --schedule off +defaults write com.apple.SoftwareUpdate AutomaticDownload -int 0 +defaults write com.apple.SoftwareUpdate CriticalUpdateInstall -int 0 +defaults write com.apple.commerce AutoUpdate -bool false +defaults write com.apple.SoftwareUpdate AutomaticCheckEnabled -bool false + +echo "Additional NTP servers adding into /etc/ntp.conf file" +cat > /etc/ntp.conf << EOF +server 0.pool.ntp.org +server 1.pool.ntp.org +server 2.pool.ntp.org +server 3.pool.ntp.org +server time.apple.com +server time.windows.com +EOF + +# Set the timezone to UTC. +echo "Setting timezone to UTC" +ln -sf /usr/share/zoneinfo/UTC /etc/localtime \ No newline at end of file diff --git a/Code/Tools/GemRegistry/gemregistry_test_files.cmake b/scripts/build/build_node/Platform/Mac/install-jdk.sh similarity index 51% rename from Code/Tools/GemRegistry/gemregistry_test_files.cmake rename to scripts/build/build_node/Platform/Mac/install-jdk.sh index e19cfe8e74..5b2429cf54 100644 --- a/Code/Tools/GemRegistry/gemregistry_test_files.cmake +++ b/scripts/build/build_node/Platform/Mac/install-jdk.sh @@ -1,4 +1,6 @@ -# +#!/bin/bash +set -euo pipefail + # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # @@ -7,15 +9,14 @@ # 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. -# -set(FILES - tests/main.cpp - tests/VersionTest.cpp - tests/DependencyTest.cpp - tests/DescriptionTest.cpp - tests/ProjectSettingsTest.cpp - tests/RegistryTest.cpp - source/GemRegistry.h - source/GemRegistry.cpp -) +JDK_VERSION="8.282.08.1" + +echo "Installing Corretto JDK ${JDK_VERSION}" +curl -o /tmp/amazon-corretto-${JDK_VERSION}-macosx-x64.pkg https://corretto.aws/downloads/resources/${JDK_VERSION}/amazon-corretto-${JDK_VERSION}-macosx-x64.pkg +if sudo installer -allowUntrusted -pkg /tmp/amazon-corretto-${JDK_VERSION}-macosx-x64.pkg -target / ; then + rm /tmp/amazon-corretto-${JDK_VERSION}-macosx-x64.pkg +else + echo "Installation failed!" + exit 1 +fi \ No newline at end of file diff --git a/Code/Tools/GemRegistry/gemregistry_files.cmake b/scripts/build/build_node/Platform/Mac/install-python.sh similarity index 66% rename from Code/Tools/GemRegistry/gemregistry_files.cmake rename to scripts/build/build_node/Platform/Mac/install-python.sh index c018d1b4cb..1c8b6d3cb0 100644 --- a/Code/Tools/GemRegistry/gemregistry_files.cmake +++ b/scripts/build/build_node/Platform/Mac/install-python.sh @@ -1,4 +1,6 @@ -# +#!/bin/bash +set -euo pipefail + # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # @@ -7,14 +9,9 @@ # 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. -# -set(FILES - include/GemRegistry/Version.h - include/GemRegistry/IGemRegistry.h - include/GemRegistry/Dependency.h - source/ProjectSettings.h - source/ProjectSettings.cpp - source/GemDescription.h - source/GemDescription.cpp -) +PY3_VERSION="3.7.10" + +echo "Installing Python ${PY3_VERSION}" +brew install python@${PY3_VERSION} || echo "Installation failed!"; exit 1 +cat ../common/requirements.txt | cut -f1 -d"#" | sed '/^\s*$/d' | xargs -n 1 pip3 install \ No newline at end of file diff --git a/scripts/build/build_node/Platform/Mac/install-xcode.sh b/scripts/build/build_node/Platform/Mac/install-xcode.sh new file mode 100644 index 0000000000..c55ebc38d3 --- /dev/null +++ b/scripts/build/build_node/Platform/Mac/install-xcode.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -euo pipefail + +# 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. + +XCODE_VER="11.4" +S3_BUCKET=$1 + +echo "Installing Xcode ${XCODE_VER}" +aws s3 cp ${S3_BUCKET}/Xcode$XCODE_VER.xip /tmp/ +cd /Applications + +if sudo xip -x /tmp/Xcode$XCODE_VER.xip ; then + sudo xcodebuild -license accept + rm /tmp/Xcode${XCODE_VER}.xip +else + echo "Installation failed!" + exit 1 +fi + +echo "Installing Xcode Command line tools ${XCODE_VER}" +aws s3 cp ${S3_BUCKET}/Command_Line_Tools_for_${XCODE_VER}.dmg /tmp/ +sudo hdiutil attach /tmp/Command_Line_Tools_for_${XCODE_VER}.dmg + +if sudo installer -pkg /Volumes/Command\ Line\ Developer\ Tools/Command\ Line\ Tools.pkg -target / ; then + sudo hdiutil detach /Volumes/Command\ Line\ Developer\ Tools/ + rm /tmp/Command_Line_Tools_for_${XCODE_VER}.dmg +else + echo "Installation failed!" + sudo hdiutil detach /Volumes/Command\ Line\ Developer\ Tools/ + exit 1 +fi + +echo "Installing XCode iOS packages" +sudo installer -pkg /Applications/Xcode.app/Contents/Resources/Packages/MobileDevice.pkg -target / +sudo installer -pkg /Applications/Xcode.app/Contents/Resources/Packages/MobileDeviceDevelopment.pkg -target / + +echo "Enabling developer mode" +sudo /usr/sbin/DevToolsSecurity --enable \ No newline at end of file diff --git a/scripts/build/build_node/Platform/Mac/jenkins-self-register-mac.sh b/scripts/build/build_node/Platform/Mac/jenkins-self-register-mac.sh new file mode 100644 index 0000000000..9812290b98 --- /dev/null +++ b/scripts/build/build_node/Platform/Mac/jenkins-self-register-mac.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -euo pipefail + +# 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. + +set +x + +# Function to get EC2 metadata within the instance +get_metadata () { + local response=$(curl -GLsX GET http://169.254.169.254/latest/meta-data/$1) + echo "${response}" +} + +# Get instance data +INSTANCE_ID=$(get_metadata "instance-id") +REGION=$(get_metadata "placement/availability-zone" | sed 's/.$//') +INSTANCE_PRIVATE_IP=$(get_metadata "local-ipv4") +INSTANCE_PUBLIC_IP=$(get_metadata "public-ipv4") +INSTANCE_NAME=$(aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values='Name'" --region $REGION --output=text --query="Tags[0].Value" | tr -d '\r') + +# Configuration parameters +CONTROLLER_URL=$1 +CONTROLLER_SECRET_ID=$2 +BUILD_USER=$(aws ssm get-parameters --names "shared.builderuser" --region $region --with-decryption | ConvertFrom-Json) +CONTROLLER_USERNAME=$(aws secretsmanager get-secret-value --secret-id "${CONTROLLER_SECRET_ID}" --query 'SecretString' --output text | python -c 'import sys, json;print(json.load(sys.stdin)["username"])') +CONTROLLER_PASSWORD=$(aws secretsmanager get-secret-value --secret-id "${CONTROLLER_SECRET_ID}" --query 'SecretString' --output text | python -c 'import sys, json;print(json.load(sys.stdin)["apitoken"])') +SSH_KEY="${BUILD_USER}-ssh-key" +NODE_NAME="EC2 (${REGION}) - ${INSTANCE_NAME} (${INSTANCE_ID})" +NODE_LABEL="mac-${REGION}" +ENV_PATH="$PATH:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin" + + +# Download CLI jar from the controller +curl "${CONTROLLER_URL}"/jnlpJars/jenkins-cli.jar -o ~/jenkins-cli.jar + +# Create node according to parameters passed in +cat < + ${NODE_NAME} + Ext IP: ${INSTANCE_PUBLIC_IP} + /Users/lybuilder/jenkins + 1 + EXCLUSIVE + + + ${INSTANCE_PRIVATE_IP} + 22 + ${SSH_KEY} + 60 + 10 + 15 + + true + + + + + + + + + + + 1 + PATH + ${ENV_PATH} + + + + + +EOF \ No newline at end of file diff --git a/scripts/build/package/package.py b/scripts/build/package/package.py index e0de0b8496..3b80b93c2d 100644 --- a/scripts/build/package/package.py +++ b/scripts/build/package/package.py @@ -69,7 +69,7 @@ def override_bootstrap_cfg(package_env): print('Override values in bootstrap.cfg') engine_root = package_env.get('ENGINE_ROOT') bootstrap_path = os.path.join(engine_root, 'bootstrap.cfg') - replace_values = {'sys_game_folder':'{}'.format(package_env.get('BOOTSTRAP_CFG_GAME_FOLDER'))} + replace_values = {'project_path':'{}'.format(package_env.get('BOOTSTRAP_CFG_GAME_FOLDER'))} try: with open(bootstrap_path, 'r') as bootstrap_cfg: content = bootstrap_cfg.read() diff --git a/scripts/build/package/package_filelists/all.json b/scripts/build/package/package_filelists/all.json index 32184202af..b1f3f270ca 100644 --- a/scripts/build/package/package_filelists/all.json +++ b/scripts/build/package/package_filelists/all.json @@ -9,6 +9,7 @@ ".p4ignore": "#exclude", ".submodules": "#exclude", "**/*.pyc": "#exclude", - "**/*.pdb": "#exclude" + "**/*.pdb": "#exclude", + "build/*/packages/*/*.stamp": "#exclude" } } \ No newline at end of file diff --git a/scripts/commit_validation/commit_validation/commit_validation.py b/scripts/commit_validation/commit_validation/commit_validation.py index 4c0dd73c1c..cfe20d3b94 100644 --- a/scripts/commit_validation/commit_validation/commit_validation.py +++ b/scripts/commit_validation/commit_validation/commit_validation.py @@ -165,6 +165,7 @@ SOURCE_AND_SCRIPT_FILE_EXTENSIONS: Tuple[str, ...] = SOURCE_FILE_EXTENSIONS + SC BUILD_FILE_PATTERNS: Tuple[re.Pattern, ...] = ( re.compile(r'.*CMakeLists\.txt'), + re.compile(r'.*Jenkinsfile') ) """File patterns for build files""" @@ -180,7 +181,6 @@ EXCLUDED_VALIDATION_PATTERNS = [ 'Code/Tools/CryFXC', 'Code/Tools/HLSLCrossCompiler', 'Code/Tools/HLSLCrossCompilerMETAL', - 'Code/Tools/ProfVis', 'Code/Tools/UniversalRemoteConsole', 'Docs', 'python/runtime', diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 5c50d741ca..89457997fb 100644 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -27,9 +27,21 @@ from pathlib import Path from pyside import add_pyside_environment, is_pyside_ready, uninstall_env logger = logging.getLogger() +logger.setLevel(logging.INFO) -dev_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) -sys.path.append(dev_path) +log_path = os.path.join(os.path.dirname(__file__), "logs") +if not os.path.isdir(log_path): + os.makedirs(log_path) +log_path = os.path.join(log_path, "project_manager.log") +log_file_handler = RotatingFileHandler(filename=log_path, maxBytes=1024 * 1024, backupCount=1) +formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') +log_file_handler.setFormatter(formatter) +logger.addHandler(log_file_handler) + +logger.info("Starting Project Manager") + +engine_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) +sys.path.append(engine_path) executable_path = '' @@ -40,9 +52,11 @@ def initialize_pyside_from_parser(): parser.add_argument('--executable_path', required=True, help='Path to Executable to launch with project') parser.add_argument('--binaries_path', default=None, help='Path to QT Binaries necessary for PySide. If not' 'provided executable_path folder is assumed') + parser.add_argument('--parent_pid', default=0, help='Process ID of launching process') args = parser.parse_args() + logger.info(f"parent_pid is {args.parent_pid}") global executable_path executable_path = args.executable_path binaries_path = args.binaries_path or os.path.dirname(executable_path) @@ -63,6 +77,9 @@ try: from PySide2.QtGui import QIcon, QStandardItemModel, QStandardItem except ImportError as e: logger.error(f"Failed to import PySide2 with error {e}") + exit(-1) + +logger.error(f"PySide2 imports successful") from cmake.Tools import engine_template from cmake.Tools import add_remove_gem @@ -129,17 +146,6 @@ class ProjectDialog(QObject): logger.addHandler(self.dialog_logger) logger.setLevel(logging.INFO) - log_path = os.path.join(os.path.dirname(__file__), "logs") - if not os.path.isdir(log_path): - os.makedirs(log_path) - log_path = os.path.join(log_path, "project_manager.log") - log_file_handler = RotatingFileHandler(filename=log_path, maxBytes=1024 * 1024, backupCount=1) - formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') - log_file_handler.setFormatter(formatter) - logger.addHandler(log_file_handler) - - logger.info("Starting Project Manager") - self.dialog_logger.signaller.send_to_dialog.connect(self.handle_log_message) self.displayed_projects = [] @@ -210,7 +216,7 @@ class ProjectDialog(QObject): return os.path.basename(self.path_for_selection()) def get_launch_project(self) -> str: - # We can't currently pass an absolute path, so we need to assume the folder lives under dev and just pass + # We can't currently pass an absolute path, so we need to assume the folder lives under engine and just pass # the base name of the selected project return os.path.basename(os.path.normpath(self.path_for_selection())) @@ -221,7 +227,7 @@ class ProjectDialog(QObject): :return: list of params """ launch_params = [executable_path, - f'-regset="/Amazon/AzCore/Bootstrap/sys_game_folder={self.get_launch_project()}"'] + f'-regset="/Amazon/AzCore/Bootstrap/project_path={self.get_launch_project()}"'] return launch_params def load_gems(self) -> None: @@ -238,14 +244,14 @@ class ProjectDialog(QObject): Actual load function for load_gems thread. Blocking call to lower level find method to fill out gems_list :return: None """ - self.gems_list = add_remove_gem.find_all_gems([os.path.join(dev_path, 'Gems')]) + self.gems_list = add_remove_gem.find_all_gems([os.path.join(engine_path, 'Gems')]) def load_template_list(self) -> None: """ Search for available templates to fill out template list :return: None """ - self.project_templates = engine_template.find_all_project_templates([os.path.join(dev_path, 'Templates')]) + self.project_templates = engine_template.find_all_project_templates([os.path.join(engine_path, 'Templates')]) def get_gem_info(self, gem_name: str) -> str: """ @@ -359,7 +365,7 @@ class ProjectDialog(QObject): will update the mru list with the new entry, if invalid will warn the user. :return: None """ - project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", dev_path) + project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", engine_path) if project_folder: self.add_new_project(project_folder) @@ -380,7 +386,7 @@ class ProjectDialog(QObject): remove_gems = self.get_selected_project_gems() for this_gem in remove_gems: gem_path = self.path_for_gem(this_gem) - add_remove_gem.add_remove_gem(False, dev_path, gem_path or os.path.join(dev_path, 'Gems', this_gem), + add_remove_gem.add_remove_gem(False, engine_path, gem_path or os.path.join(engine_path, 'Gems', this_gem), self.path_for_selection(), gem_name=this_gem) self.update_gems() @@ -449,7 +455,7 @@ class ProjectDialog(QObject): if not gem_info: logger.error(f'Unknown gem {this_gem}!') continue - add_remove_gem.add_remove_gem(True, dev_path, this_gem[1], self.path_for_selection(), + add_remove_gem.add_remove_gem(True, engine_path, this_gem[1], self.path_for_selection(), gem_name=gem_info.get('Name'), runtime_dependency=gem_info.get('Runtime', False), tool_dependency=gem_info.get('Tools', False)) @@ -515,12 +521,12 @@ class ProjectDialog(QObject): if not create_project_item: return - folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name", dev_path) + folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name", engine_path) folder_dialog.setFileMode(QFileDialog.AnyFile) folder_dialog.setOptions(QFileDialog.ShowDirsOnly) project_count = 0 project_name = "MyNewProject" - while os.path.exists(os.path.join(dev_path, project_name)): + while os.path.exists(os.path.join(engine_path, project_name)): project_name = f"MyNewProject{project_count}" project_count += 1 folder_dialog.selectFile(project_name) @@ -528,7 +534,7 @@ class ProjectDialog(QObject): if folder_dialog.exec(): project_folder = folder_dialog.selectedFiles() if project_folder: - if engine_template.create_project(dev_path, project_folder[0], create_project_item[1]) == 0: + if engine_template.create_project(engine_path, project_folder[0], create_project_item[1]) == 0: # Success self.add_new_project(project_folder[0], validate=False) msg_box = QMessageBox(parent=self.dialog) From e55b89553e571b558a8527881937a8255d78ef32 Mon Sep 17 00:00:00 2001 From: alexpete Date: Fri, 26 Mar 2021 16:16:24 -0700 Subject: [PATCH 2/2] Updated 3rdParty package url --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5244a5ea60..434d4d7f83 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ If you have the Git credential manager core installed, you should not be prompte ### Build Steps -1. Download the 3rdParty zip file from here: **[https://d2c171ws20a1rv.cloudfront.net/3rdParty-windows-no-symbols-rev7.zip](https://d2c171ws20a1rv.cloudfront.net/3rdParty-windows-no-symbols-rev7.zip)** +1. Download the 3rdParty zip file from here: **[https://d2c171ws20a1rv.cloudfront.net/3rdParty-windows-no-symbols-rev8.zip](https://d2c171ws20a1rv.cloudfront.net/3rdParty-windows-no-symbols-rev8.zip)** 2. Unzip this file into a writable folder. This will also act as a cache location for the 3rdParty downloader by default (configurable with the `LY_PACKAGE_DOWNLOAD_CACHE_LOCATION` environment variable) 3. Install the following redistributables to the following: - Visual Studio and VC++ redistributable can be installed to any location @@ -74,7 +74,7 @@ If you have the Git credential manager core installed, you should not be prompte 5. Configure the source into a solution using this command line, replacing to a path you've created ``` - cmake -B -S -G "Visual Studio 16 2019" -DLY_3RDPARTY_PATH=%LY_3RDPARTY_PATH% -DLY_UNITY_BUILD=ON -DLY_PROJECTS=AutomatedTesting -DLY_MONOLITHIC_GAME=1 + cmake -B -S -G "Visual Studio 16 2019" -DLY_3RDPARTY_PATH=%LY_3RDPARTY_PATH% -DLY_UNITY_BUILD=ON -DLY_PROJECTS=AutomatedTesting ``` 6. Alternatively, you can do this through the CMake GUI: @@ -107,4 +107,4 @@ If you have the Git credential manager core installed, you should not be prompte ## License -For terms please see the LICENSE*.TXT file at the root of this distribution. \ No newline at end of file +For terms please see the LICENSE*.TXT file at the root of this distribution.