Browse Source

Integrating latest from github/staging
Integrating up through commit 5e1bdae

alexpete 4 years ago
parent
commit
36c4e827bd
100 changed files with 2012 additions and 4646 deletions
  1. 0 30
      .p4ignore
  2. 0 590
      AssetProcessorPlatformConfig.ini
  3. 224 15
      AssetProcessorPlatformConfig.setreg
  4. 66 45
      AutomatedReview/Jenkinsfile
  5. 8 0
      AutomatedTesting/CMakeLists.txt
  6. 0 197
      AutomatedTesting/Config/Editor.xml
  7. 0 179
      AutomatedTesting/Config/Game.xml
  8. 0 136
      AutomatedTesting/Config/Server.xml
  9. 0 16
      AutomatedTesting/Gem/AssetProcessorGemConfig.ini
  10. 23 0
      AutomatedTesting/Gem/AssetProcessorGemConfig.setreg
  11. 36 4
      AutomatedTesting/Gem/PythonTests/CMakeLists.txt
  12. 6 6
      AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_all_platforms_setup_fixture.py
  13. 1 1
      AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_external_project_setup_fixture.py
  14. 3 2
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests_2.py
  15. 15 19
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_gui_tests_2.py
  16. 1 1
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/missing_dependency_tests.py
  17. 2 2
      AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py
  18. 3 2
      AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py
  19. 2 8
      AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Active.py
  20. 30 0
      AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Sandbox.py
  21. 36 6
      AutomatedTesting/Registry/assets_scan_folders.setreg
  22. 4 1
      AutomatedTesting/TestAssets/test_chunks_builder.py
  23. 1 1
      AutomatedTesting/UI/TextureAtlas/sample.texatlas
  24. 0 298
      AutomatedTesting/gems.json
  25. 2 2
      BuildReleaseAuxiliaryContent.py
  26. 22 5
      CMakeLists.txt
  27. 1 1
      Code/CryEngine/Cry3DEngine/3DEngineRender.cpp
  28. 1 1
      Code/CryEngine/Cry3DEngine/3dEngine.cpp
  29. 2 12
      Code/CryEngine/Cry3DEngine/3dEngineLoad.cpp
  30. 2 1
      Code/CryEngine/Cry3DEngine/LightEntity.cpp
  31. 1 14
      Code/CryEngine/Cry3DEngine/Material.cpp
  32. 1 14
      Code/CryEngine/Cry3DEngine/Material.h
  33. 1 9
      Code/CryEngine/Cry3DEngine/StatObj.h
  34. 0 4
      Code/CryEngine/Cry3DEngine/StatObjConstr.cpp
  35. 1 1
      Code/CryEngine/CryCommon/IAudioSystem.h
  36. 1 6
      Code/CryEngine/CryCommon/IMaterial.h
  37. 7 189
      Code/CryEngine/CryCommon/ISystem.h
  38. 7 8
      Code/CryEngine/CryCommon/MaterialUtils.h
  39. 0 18
      Code/CryEngine/CryCommon/Mocks/ISystemMock.h
  40. 0 160
      Code/CryEngine/CryCommon/ParseEngineConfig.h
  41. 1 1
      Code/CryEngine/CryCommon/ProjectDefines.h
  42. 0 1
      Code/CryEngine/CryCommon/crycommon_files.cmake
  43. 0 630
      Code/CryEngine/CrySystem/BootProfiler.cpp
  44. 0 67
      Code/CryEngine/CrySystem/BootProfiler.h
  45. 1 12
      Code/CryEngine/CrySystem/DebugCallStack.cpp
  46. 7 11
      Code/CryEngine/CrySystem/IDebugCallStack.cpp
  47. 0 647
      Code/CryEngine/CrySystem/LoadingProfiler.cpp
  48. 0 69
      Code/CryEngine/CrySystem/LoadingProfiler.h
  49. 4 6
      Code/CryEngine/CrySystem/NotificationNetwork.cpp
  50. 1 1
      Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp
  51. 12 28
      Code/CryEngine/CrySystem/System.cpp
  52. 3 33
      Code/CryEngine/CrySystem/System.h
  53. 3 9
      Code/CryEngine/CrySystem/SystemCFG.cpp
  54. 44 297
      Code/CryEngine/CrySystem/SystemInit.cpp
  55. 0 15
      Code/CryEngine/CrySystem/SystemWin32.cpp
  56. 0 115
      Code/CryEngine/CrySystem/Tests/Test_BootProfiler.cpp
  57. 5 10
      Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp
  58. 2 2
      Code/CryEngine/CrySystem/UnitTests/CryPakUnitTests.cpp
  59. 2 2
      Code/CryEngine/CrySystem/VisRegTest.cpp
  60. 0 4
      Code/CryEngine/CrySystem/crysystem_files.cmake
  61. 2 2
      Code/CryEngine/RenderDll/Common/Renderer.cpp
  62. 10 12
      Code/CryEngine/RenderDll/Common/Shaders/RemoteCompiler.cpp
  63. 99 32
      Code/CryEngine/RenderDll/Common/Shaders/RemoteShaderCompilerUnitTests.cpp
  64. 4 3
      Code/CryEngine/RenderDll/Common/Shaders/ShaderCache.cpp
  65. 1 1
      Code/CryEngine/RenderDll/Common/Shaders/ShaderCore.cpp
  66. 1 1
      Code/CryEngine/RenderDll/Common/Shaders/ShaderSerialize.cpp
  67. 2 2
      Code/CryEngine/RenderDll/XRenderD3D9/D3DHWShaderCompiling.cpp
  68. 3 2
      Code/CryEngine/RenderDll/XRenderD3D9/D3DSystem.cpp
  69. 209 117
      Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
  70. 32 34
      Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
  71. 5 0
      Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h
  72. 4 2
      Code/Framework/AzCore/AzCore/Console/Console.cpp
  73. 14 25
      Code/Framework/AzCore/AzCore/IO/FileIO.h
  74. 4 4
      Code/Framework/AzCore/AzCore/IO/Path/Path.h
  75. 3 3
      Code/Framework/AzCore/AzCore/IO/Path/Path.inl
  76. 1 0
      Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
  77. 53 0
      Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp
  78. 12 0
      Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h
  79. 186 122
      Code/Framework/AzCore/AzCore/Settings/CommandLine.cpp
  80. 37 14
      Code/Framework/AzCore/AzCore/Settings/CommandLine.h
  81. 9 1
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp
  82. 400 229
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
  83. 59 24
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h
  84. 52 28
      Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp
  85. 47 4
      Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h
  86. 1 0
      Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h
  87. 1 0
      Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h
  88. 43 0
      Code/Framework/AzCore/AzCore/Utils/Utils.cpp
  89. 16 5
      Code/Framework/AzCore/AzCore/Utils/Utils.h
  90. 5 0
      Code/Framework/AzCore/AzCore/std/string/fixed_string.h
  91. 17 0
      Code/Framework/AzCore/AzCore/std/string/fixed_string.inl
  92. 16 0
      Code/Framework/AzCore/AzCore/std/string/string.h
  93. 16 0
      Code/Framework/AzCore/AzCore/std/string/string_view.h
  94. 5 5
      Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp
  95. 1 0
      Code/Framework/AzCore/Platform/Android/platform_android_files.cmake
  96. 22 0
      Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp
  97. 19 4
      Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp
  98. 4 4
      Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp
  99. 1 1
      Code/Framework/AzCore/Platform/Linux/AzCore/Utils/Utils_Linux.cpp
  100. 1 1
      Code/Framework/AzCore/Platform/Mac/AzCore/Utils/Utils_Mac.cpp

+ 0 - 30
.p4ignore

@@ -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

+ 0 - 590
AssetProcessorPlatformConfig.ini

@@ -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}

+ 224 - 15
Engine/Registry/AssetProcessorPlatformConfig.setreg → 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}"
                 }
             }
         }
     }
-}
+}

+ 66 - 45
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

+ 8 - 0
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)

+ 0 - 197
AutomatedTesting/Config/Editor.xml

@@ -1,197 +0,0 @@
-<ObjectStream version="1">
-	<Class name="ComponentApplication::Descriptor" version="2" type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
-		<Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecordsSaveNames" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecordsAttemptDecodeImmediately" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="int" field="recordingMode" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
-		<Class name="AZ::u64" field="stackRecordLevels" value="5" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="unsigned int" field="pageSize" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="unsigned int" field="poolPageSize" value="4096" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="unsigned int" field="blockAlignment" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="bool" field="enableDrilling" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="useOverrunDetection" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="useMalloc" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="AZStd::vector" field="allocatorRemappings" type="{82897F6E-6389-5BEF-B427-761DB35AC1CC}"/>
-		<Class name="AZStd::vector" field="modules" type="{8E779F80-AEAA-565B-ABB1-DE10B18CF995}">
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Maestro.Editor.3b9a978ed6f742a1acb99f74379a342c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LmbrCentral.Editor.ff06785f7145416b9d46fde39098cb0c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShine.Editor.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.HttpRequestor.28479e255bde466e91fc34eec808d9c7.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptEvents.Editor.32d8ba21703e4bbbb08487366e48dd69.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ExpressionEvaluation.4c6f9df57ca2468f93c8d860ee6a1167.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AssetValidation.5a5c3c10b91d4b4ea8baef474c5b5d49.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Gestures.6056556b6088413984309c4a413593ad.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CertificateManager.659cffff33b14a10835bafc6ea623f98.v0.0.1" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.DebugDraw.Editor.66239f50bf754354b514c850c8b841fb.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AudioSystem.Editor.6f63f2b6d07f4b89b4b7c86ebee7feb8.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GameLift.76de765796504906b73be7365a9bff06.v2.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.SceneProcessing.Editor.7c2578f634df4345aca98d671e39b8ab.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GraphCanvas.Editor.875b6fcbdeea44deaae7984ad9bb6cdc.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.InAppPurchases.92fe57eae7d3402a90761973678c079a.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AutomatedTesting.afc25e1593194d6283d9ff744ab6d5a1.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.EditorPythonBindings.Editor.b658359393884c4381c2fe2952b1472a.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Metastream.c02d7efe05134983b5699d9ee7594c3a.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.WhiteBox.Editor.c5833dbda2e045d3a5f16b7414280c27.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ImageProcessing.Editor.eeffbd9211cf4ce0b5cc73696b427cbe.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TestAssetBuilder.Editor.f5c92f1560714010ba30467d93feecef.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Camera.Editor.f910686b6725452fbfc4671f95f733c6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.EMotionFX.Editor.044a63ea67d04479aa5daf62ded9d9ca.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GraphModel.Editor.0844f64a3acf4f5abf3a535dc9b63bc9.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysX.Editor.4e08125824434932a0fe3717259caa47.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CameraFramework.54f2763fe191432fa681ce4a354eedf5.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.SurfaceData.Editor.5de82d29d6094bfe97c1a4d35fcd5fbe.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AudioEngineWwise.Editor.67a80e2ac865406c990f2715feb55f7f.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointMovement.73d8779dc28a4123b7c9ed76217464af.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointCamera.834070b9537d44df83559e2045c3859f.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptCanvasGem.Editor.869a0d0ec11a45c299917d45c81555e6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GradientSignal.Editor.8825563d9d964ec3be3bab681f3bd9f2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ImGui.Editor.bab8807a1bc646b3909f3cc200ffeedf.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ChatPlay.bfbc60c63ffd4b00927003735b26ce99.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TouchBending.Editor.c58d2057f3724b22ae0df0be68a4e316.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.FastNoise.Editor.c5f23032407f49ca8d8de1733423565c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShineExamples.c7935ecf5e8047fe8ca947b34b11cadb.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Vegetation.Editor.f394e7cf54424bba89615381bba9511b.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointInput.Editor.09f4bedeee614358bc36788e77f97e51.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LandscapeCanvas.Editor.19c2b2d5018940108baf252934b8e6bf.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptCanvasPhysics.1c27519a4dda4ffaaeebf91514e5b1e8.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysXDebug.Editor.516145e2d9904b13813f1b54605e26a6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-		</Class>
-	</Class>
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="SystemEntity" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}"/>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="AZStd::vector" field="Components" type="{2BADE35A-6F1B-4698-B2BC-3373D010020C}">
-			<Class name="PhysicsSystemComponent" field="element" value="" version="1" type="{1586DBA1-F5F0-49AB-9F59-AE62C0E60AE0}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="5881970355815182227" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="NavigationSystemComponent" field="element" value="" version="1" type="{3D27484B-00C4-4F3F-9605-2BF3E5C317FF}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="3408791856679455729" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="EditorSelectionAccentSystemComponent" field="element" value="" type="{6E0F0E2C-1FE5-4AFB-9672-DC92B3D2D844}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="4281709857282575192" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="AudioSystemComponent" field="element" version="1" type="{666E28D2-FC99-4D41-861D-3758C5070653}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="4028172539943260142" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="LyShineSystemComponent" field="element" value="" type="{B0C78B8D-1E5B-47D7-95D0-EC69C0513804}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="13584318858523138243" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="LyEditorMetricsSystemComponent" field="element" value="" type="{B8C74085-F6B7-4E2F-8135-78C991CC53C5}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="8970396848016072155" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="StereoRendererComponent" field="element" version="1" type="{BBFE0965-5564-4739-8219-AFE8209A5E57}"/>
-		</Class>
-	</Class>
-</ObjectStream>
-

+ 0 - 179
AutomatedTesting/Config/Game.xml

@@ -1,179 +0,0 @@
-<ObjectStream version="1">
-	<Class name="ComponentApplication::Descriptor" version="2" type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
-		<Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecordsSaveNames" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecordsAttemptDecodeImmediately" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="int" field="recordingMode" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
-		<Class name="AZ::u64" field="stackRecordLevels" value="5" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="unsigned int" field="pageSize" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="unsigned int" field="poolPageSize" value="4096" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="unsigned int" field="blockAlignment" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="bool" field="enableDrilling" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="useOverrunDetection" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="useMalloc" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="AZStd::vector" field="allocatorRemappings" type="{82897F6E-6389-5BEF-B427-761DB35AC1CC}"/>
-		<Class name="AZStd::vector" field="modules" type="{8E779F80-AEAA-565B-ABB1-DE10B18CF995}">
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Maestro.3b9a978ed6f742a1acb99f74379a342c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShine.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.HttpRequestor.28479e255bde466e91fc34eec808d9c7.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptEvents.32d8ba21703e4bbbb08487366e48dd69.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ExpressionEvaluation.4c6f9df57ca2468f93c8d860ee6a1167.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AssetValidation.5a5c3c10b91d4b4ea8baef474c5b5d49.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Gestures.6056556b6088413984309c4a413593ad.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CertificateManager.659cffff33b14a10835bafc6ea623f98.v0.0.1" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.DebugDraw.66239f50bf754354b514c850c8b841fb.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AudioSystem.6f63f2b6d07f4b89b4b7c86ebee7feb8.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GameLift.76de765796504906b73be7365a9bff06.v2.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GraphCanvas.875b6fcbdeea44deaae7984ad9bb6cdc.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.InAppPurchases.92fe57eae7d3402a90761973678c079a.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AutomatedTesting.afc25e1593194d6283d9ff744ab6d5a1.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Metastream.c02d7efe05134983b5699d9ee7594c3a.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.WhiteBox.c5833dbda2e045d3a5f16b7414280c27.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Camera.f910686b6725452fbfc4671f95f733c6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.EMotionFX.044a63ea67d04479aa5daf62ded9d9ca.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysX.4e08125824434932a0fe3717259caa47.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CameraFramework.54f2763fe191432fa681ce4a354eedf5.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.SurfaceData.5de82d29d6094bfe97c1a4d35fcd5fbe.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AudioEngineWwise.67a80e2ac865406c990f2715feb55f7f.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointMovement.73d8779dc28a4123b7c9ed76217464af.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointCamera.834070b9537d44df83559e2045c3859f.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptCanvasGem.869a0d0ec11a45c299917d45c81555e6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GradientSignal.8825563d9d964ec3be3bab681f3bd9f2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ImGui.bab8807a1bc646b3909f3cc200ffeedf.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ChatPlay.bfbc60c63ffd4b00927003735b26ce99.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TouchBending.c58d2057f3724b22ae0df0be68a4e316.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.FastNoise.c5f23032407f49ca8d8de1733423565c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShineExamples.c7935ecf5e8047fe8ca947b34b11cadb.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Vegetation.f394e7cf54424bba89615381bba9511b.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointInput.09f4bedeee614358bc36788e77f97e51.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptCanvasPhysics.1c27519a4dda4ffaaeebf91514e5b1e8.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysXDebug.516145e2d9904b13813f1b54605e26a6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-		</Class>
-	</Class>
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="SystemEntity" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}"/>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="AZStd::vector" field="Components" type="{2BADE35A-6F1B-4698-B2BC-3373D010020C}">
-			<Class name="PhysicsSystemComponent" field="element" value="" version="1" type="{1586DBA1-F5F0-49AB-9F59-AE62C0E60AE0}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="14545574550664822512" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="NavigationSystemComponent" field="element" value="" version="1" type="{3D27484B-00C4-4F3F-9605-2BF3E5C317FF}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="9809863829757322975" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="LyShineSystemComponent" field="element" value="" type="{B0C78B8D-1E5B-47D7-95D0-EC69C0513804}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="3706545825063126910" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="AudioSystemComponent" field="element" version="1" type="{666E28D2-FC99-4D41-861D-3758C5070653}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="17265601292746528732" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="StereoRendererComponent" field="element" version="1" type="{BBFE0965-5564-4739-8219-AFE8209A5E57}"/>
-			<Class name="LmbrCentralSystemComponent" field="element" value="" version="1" type="{CE249D37-C1D6-4A64-932D-C937B0EC2B8C}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="17265313386362322770" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-			<Class name="AssetDatabaseComponent" field="element" value="" version="1" type="{D5A73BCC-0098-4D1E-8FE4-C86101E374AC}">
-				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
-					<Class name="AZ::u64" field="Id" value="18338415854038604706" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-				</Class>
-			</Class>
-		</Class>
-	</Class>
-</ObjectStream>
-

+ 0 - 136
AutomatedTesting/Config/Server.xml

@@ -1,136 +0,0 @@
-<ObjectStream version="3">
-	<Class name="ComponentApplication::Descriptor" version="2" type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
-		<Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecordsSaveNames" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="allocationRecordsAttemptDecodeImmediately" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="int" field="recordingMode" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
-		<Class name="AZ::u64" field="stackRecordLevels" value="5" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="unsigned int" field="pageSize" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="unsigned int" field="poolPageSize" value="4096" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="unsigned int" field="blockAlignment" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-		<Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		<Class name="bool" field="enableDrilling" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="useOverrunDetection" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="useMalloc" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="AZStd::vector" field="allocatorRemappings" type="{82897F6E-6389-5BEF-B427-761DB35AC1CC}"/>
-		<Class name="AZStd::vector" field="modules" type="{8E779F80-AEAA-565B-ABB1-DE10B18CF995}">
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Maestro.3b9a978ed6f742a1acb99f74379a342c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShine.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.HttpRequestor.28479e255bde466e91fc34eec808d9c7.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptEvents.32d8ba21703e4bbbb08487366e48dd69.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ExpressionEvaluation.4c6f9df57ca2468f93c8d860ee6a1167.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AssetValidation.5a5c3c10b91d4b4ea8baef474c5b5d49.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Gestures.6056556b6088413984309c4a413593ad.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CertificateManager.659cffff33b14a10835bafc6ea623f98.v0.0.1" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.DebugDraw.66239f50bf754354b514c850c8b841fb.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AudioSystem.6f63f2b6d07f4b89b4b7c86ebee7feb8.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GameLift.76de765796504906b73be7365a9bff06.v2.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.GraphCanvas.875b6fcbdeea44deaae7984ad9bb6cdc.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.InAppPurchases.92fe57eae7d3402a90761973678c079a.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AutomatedTesting.afc25e1593194d6283d9ff744ab6d5a1.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Metastream.c02d7efe05134983b5699d9ee7594c3a.v1.0.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.WhiteBox.c5833dbda2e045d3a5f16b7414280c27.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Camera.f910686b6725452fbfc4671f95f733c6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.EMotionFX.044a63ea67d04479aa5daf62ded9d9ca.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysX.4e08125824434932a0fe3717259caa47.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysXCharacters.50f9ae1e09ac471bbd9d86ca8063ddf9.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CameraFramework.54f2763fe191432fa681ce4a354eedf5.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.AudioEngineWwise.67a80e2ac865406c990f2715feb55f7f.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointMovement.73d8779dc28a4123b7c9ed76217464af.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointCamera.834070b9537d44df83559e2045c3859f.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptCanvasGem.869a0d0ec11a45c299917d45c81555e6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ImGui.bab8807a1bc646b3909f3cc200ffeedf.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ChatPlay.bfbc60c63ffd4b00927003735b26ce99.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShineExamples.c7935ecf5e8047fe8ca947b34b11cadb.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.StartingPointInput.09f4bedeee614358bc36788e77f97e51.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ScriptCanvasPhysics.1c27519a4dda4ffaaeebf91514e5b1e8.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
-				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.PhysXDebug.516145e2d9904b13813f1b54605e26a6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
-			</Class>
-		</Class>
-	</Class>
-	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
-		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
-			<Class name="AZ::u64" field="id" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
-		</Class>
-		<Class name="AZStd::string" field="Name" value="SystemEntity" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-		<Class name="AZStd::vector" field="Components" type="{13D58FF9-1088-5C69-9A1F-C2A144B57B78}"/>
-		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-		<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
-	</Class>
-</ObjectStream>
-

+ 0 - 16
AutomatedTesting/Gem/AssetProcessorGemConfig.ini

@@ -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\\/.*

+ 23 - 0
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\\\\/.*"
+                }
+            }
+        }
+    }
+}

+ 36 - 4
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()
 

+ 6 - 6
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

+ 1 - 1
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
 

+ 3 - 2
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')
 

+ 15 - 19
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)

+ 1 - 1
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")

+ 2 - 2
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)

+ 3 - 2
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

+ 2 - 8
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
 
-
[email protected]_main
[email protected]_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)
-

+ 30 - 0
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
+
+
[email protected]_sandbox
[email protected]("launcher_platform", ['windows_editor'])
[email protected]("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)

+ 36 - 6
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"
                 ]
             }

+ 4 - 1
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)):

+ 1 - 1
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
 

+ 0 - 298
AutomatedTesting/gems.json

@@ -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"
-        }
-    ]
-}

+ 2 - 2
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
 
 

+ 22 - 5
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()

+ 1 - 1
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)

+ 1 - 1
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)

+ 2 - 12
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<struct IStatObj*>* pStatObjTable = NULL;

+ 2 - 1
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;

+ 1 - 14
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;

+ 1 - 14
Code/CryEngine/Cry3DEngine/Material.h

@@ -18,7 +18,6 @@
 #include <IMaterial.h>
 
 #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;

+ 1 - 9
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<uint16> 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;
 

+ 0 - 4
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
 }
 
 //////////////////////////////////////////////////////////////////////////

+ 1 - 1
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;
         };
 

+ 1 - 6
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;

+ 7 - 189
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.

+ 7 - 8
Code/CryEngine/CryCommon/MaterialUtils.h

@@ -15,10 +15,12 @@
 
 #include <AzCore/base.h>
 #include <AzCore/IO/SystemFile.h> // for max path len
-#include <ISystem.h>
 #include <AzCore/std/string/string.h>
+#include <AzCore/Utils/Utils.h>
 #include <AzFramework/StringFunc/StringFunc.h>
 
+#include <ISystem.h>
+
 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)

+ 0 - 18
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,

+ 0 - 160
Code/CryEngine/CryCommon/ParseEngineConfig.h

@@ -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 <AzCore/base.h>
-#include <AzCore/IO/SystemFile.h>
-#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
-#include <AzCore/Utils/Utils.h>
-#include <AzFramework/Platform/PlatformDefaults.h>
-
-// 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<AZ::u16>(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());
-        }
-        
-    }
-};

+ 1 - 1
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)

+ 0 - 1
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

+ 0 - 630
Code/CryEngine/CrySystem/BootProfiler.cpp

@@ -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 <stack>
-#include <AzFramework/IO/FileOperations.h>
-
-
-namespace
-{
-    StaticInstance<CBootProfiler, AZStd::no_destruct<CBootProfiler>> 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<CBootProfilerRecord*> 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("&", "&amp;");
-            label.replace("<", "&lt;");
-            label.replace(">", "&gt;");
-            label.replace("\"", "&quot;");
-            label.replace("'", "&apos;");
-
-            if (m_args.size() > 0)
-            {
-                m_args.replace("&", "&amp;");
-                m_args.replace("<", "&lt;");
-                m_args.replace(">", "&gt;");
-                m_args.replace("\"", "&quot;");
-                m_args.replace("'", "&apos;");
-                m_args.replace("%", "&#37;");
-            }
-
-            sprintf_s(buf, buf_size, "%s<block name=\"%s\" totalTimeMS=\"%f\" startTime=\"%" PRIu64 "\" stopTime=\"%" PRIu64 "\" args=\"%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</block>\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, "<root>\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<thread name=\"%s\" totalTimeMS=\"%f\" startTime=\"%" PRIu64 "\" stopTime=\"%" PRIu64 "\" > \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</thread>\n");
-            AZ::IO::Print(fileHandle, buf);
-        }
-    }
-
-    sprintf_s(buf, buf_size, "</root>\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<AZStd::recursive_mutex> 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<AZStd::recursive_mutex> 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<AZStd::recursive_mutex> 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<AZStd::recursive_mutex> recordGuard{ m_recordMutex };
-    if (m_pCurrentSession)
-    {
-        return m_pCurrentSession->StartBlock(name, args);
-    }
-    return NULL;
-}
-
-void CBootProfiler::StopBlock(CBootProfilerRecord* record)
-{
-    AZStd::lock_guard<AZStd::recursive_mutex> recordGuard{ m_recordMutex };
-    if (m_pCurrentSession)
-    {
-        m_pCurrentSession->StopBlock(record);
-    }
-}
-
-void CBootProfiler::StartFrame(const char* name)
-{
-    AZStd::lock_guard<AZStd::recursive_mutex> recordGuard{ m_recordMutex };
-    if (CV_sys_bp_frames)
-    {
-        StartSession("frames");
-        m_pFrameRecord = StartBlock(name, NULL);
-    }
-}
-
-void CBootProfiler::StopFrame()
-{
-    AZStd::lock_guard<AZStd::recursive_mutex> 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

+ 0 - 67
Code/CryEngine/CrySystem/BootProfiler.h

@@ -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 <AzCore/std/string/string.h>
-#include <AzCore/std/containers/unordered_map.h>
-#include <AzCore/std/parallel/mutex.h>
-
-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<AZStd::string, CBootProfilerSession*> 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

+ 1 - 12
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("<CrySystem> 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]);
                                 }
                             }
                         }

+ 7 - 11
Code/CryEngine/CrySystem/IDebugCallStack.cpp

@@ -20,8 +20,8 @@
 #include "System.h"
 #include <AzFramework/IO/FileOperations.h>
 #include <AzCore/NativeUI/NativeUIRequests.h>
-
-#include <AzFramework/StringFunc/StringFunc.h>
+#include <AzCore/StringFunc/StringFunc.h>
+#include <AzCore/Utils/Utils.h>
 //#if !defined(LINUX)
 
 #include <ISystem.h>
@@ -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());

+ 0 - 647
Code/CryEngine/CrySystem/LoadingProfiler.cpp

@@ -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<SLoadingTimeContainer*> 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<SLoadingTimeContainer> 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<SLoadingTimeContainer*> 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<SLoadingProfilerInfo>& profilers)
-{
-    UpdateSelfStatistics(m_pRoot[m_iActiveRoot]);
-
-    PodArray<SLoadingTimeContainer> 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<SLoadingTimeContainer>& 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<SLoadingTimeContainer>& 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<MAX_LOADING_TIME_PROFILER_STACK_DEPTH> 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</%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

+ 0 - 69
Code/CryEngine/CrySystem/LoadingProfiler.h

@@ -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<SLoadingTimeContainer>&);
-    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<SLoadingProfilerInfo>& 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>&, 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

+ 4 - 6
Code/CryEngine/CrySystem/NotificationNetwork.cpp

@@ -16,6 +16,7 @@
 #include <ISystem.h>
 
 #include <AzCore/Socket/AzSocket.h>
+#include <AzCore/Utils/Utils.h>
 
 #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;
 

+ 1 - 1
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");

+ 12 - 28
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 <IThreadManager.h>
@@ -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 <PNoise3.h>
 #include <StringUtils.h>
@@ -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<AZ::IO::FileIOBase> CSystem::CreateLocalFileIO()
     return std::make_shared<AZ::IO::LocalFileIO>();
 }
 
-const char* CSystem::GetAssetsPlatform() const
-{
-    return m_assetPlatform.c_str();
-}
-
 IViewSystem* CSystem::GetIViewSystem()
 {
     return m_pViewSystem;

+ 3 - 33
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<AZ::IO::FileIOBase> 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<AzFramework::MissingAssetLogger> 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<CTimeValue, float> > m_updateTimes;
 
     CMemoryFragmentationProfiler    m_MemoryFragmentationProfiler;

+ 3 - 9
Code/CryEngine/CrySystem/SystemCFG.cpp

@@ -23,6 +23,7 @@
 
 #include <AzCore/Console/IConsole.h>
 #include <AzCore/Interface/Interface.h>
+#include <AzCore/Utils/Utils.h>
 #include <AzFramework/StringFunc/StringFunc.h>
 
 #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__);
 }
 

+ 44 - 297
Code/CryEngine/CrySystem/SystemInit.cpp

@@ -68,6 +68,7 @@
 #include <LoadScreenBus.h>
 #include <LyShine/Bus/UiSystemBus.h>
 #include <AzFramework/Logging/MissingAssetLogger.h>
+#include <AzFramework/Platform/PlatformDefaults.h>
 #include <AzFramework/API/AtomActiveInterface.h>
 #include <AzCore/Interface/Interface.h>
 #include <AzCore/Utils/Utils.h>
@@ -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<AZ::DynamicModuleHandle> CSystem::LoadDynamiclibrary(const cha
 {
     AZStd::unique_ptr<AZ::DynamicModuleHandle> 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<InjectEnvironmentFunction>(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<AZ::IO::IArchive>::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=<value>" 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<AzFramework::MissingAssetLogger>();
 
         //////////////////////////////////////////////////////////////////////////
@@ -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 <filename>");
 
-    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);

+ 0 - 15
Code/CryEngine/CrySystem/SystemWin32.cpp

@@ -92,13 +92,6 @@ static AZStd::vector<AZStd::string> 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("<CrySystem> Last System Error: %s", szSysErrorMessage);
     }
 
-    if (const char* pLoadingProfilerCallstack = GetLoadingProfilerCallstack())
-    {
-        if (pLoadingProfilerCallstack[0])
-        {
-            CryLogAlways("<CrySystem> LoadingProfilerCallstack: %s", pLoadingProfilerCallstack);
-        }
-    }
-
     if (GetUserCallback())
     {
         GetUserCallback()->OnError(szBuffer);

+ 0 - 115
Code/CryEngine/CrySystem/Tests/Test_BootProfiler.cpp

@@ -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 <AzTest/AzTest.h>
-#include <AzCore/UnitTest/UnitTest.h>
-#include <AzCore/UnitTest/TestTypes.h>
-#include <AzCore/Memory/AllocatorScope.h>
-#include <AzCore/std/string/string.h>
-#include <BootProfiler.h>
-
-#if defined(ENABLE_LOADING_PROFILER)
-
-namespace UnitTests
-{
-    using BootProfilerTestAllocatorScope = AZ::AllocatorScope<AZ::LegacyAllocator, CryStringAllocator>;
-    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

+ 5 - 10
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);
-}
+}

+ 2 - 2
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;

+ 2 - 2
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");

+ 0 - 4
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

+ 2 - 2
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();

+ 10 - 12
Code/CryEngine/RenderDll/Common/Shaders/RemoteCompiler.cpp

@@ -20,6 +20,7 @@
 #include <AzCore/Socket/AzSocket.h>
 #include <AzCore/NativeUI/NativeUIRequests.h>
 #include <AzCore/PlatformId/PlatformId.h>
+#include <AzCore/Utils/Utils.h>
 #include <AzFramework/Network/SocketConnection.h>
 #include <AzFramework/Asset/AssetSystemTypes.h>
 
@@ -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())

+ 99 - 32
Code/CryEngine/RenderDll/Common/Shaders/RemoteShaderCompilerUnitTests.cpp

@@ -13,16 +13,61 @@
 #include <AzTest/AzTest.h>
 #include <AzCore/UnitTest/TestTypes.h>
 #include <AzCore/Memory/AllocatorScope.h>
+#include <AzCore/Settings/SettingsRegistry.h>
 #include <AzCore/UnitTest/UnitTest.h>
 #include "Mocks/IConsoleMock.h"
 #include "Mocks/ICVarMock.h"
 #include "Mocks/ISystemMock.h"
 #include "RemoteCompiler.h"
 
+
+namespace AZ
+{
+    class SettingsRegistrySimpleMock;
+    using NiceSettingsRegistrySimpleMock = ::testing::NiceMock<SettingsRegistrySimpleMock>;
+
+    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<char>*));
+        MOCK_METHOD5(
+            MergeSettingsFolder,
+            bool(AZStd::string_view, const Specializations&, AZStd::string_view, AZStd::string_view, AZStd::vector<char>*));
+    };
+} // namespace AZ
+
+
 namespace NRemoteCompiler
 {
     using ::testing::NiceMock;
     using ::testing::Return;
+    using ::testing::DoAll;
 
     using SystemAllocatorScope = AZ::AllocatorScope<AZ::LegacyAllocator, CryStringAllocator>;
 
@@ -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<SystemMock> m_system;
             NiceMock<ConsoleMock> m_console;
             NiceMock<CVarMock> m_cvarMock;
+            AZ::NiceSettingsRegistrySimpleMock m_settings;
             SSystemGlobalEnvironment m_stubEnv;
         };
 
         AZStd::unique_ptr<DataMembers> 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<uint8> 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<uint8> 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<uint8> 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";

+ 4 - 3
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])

+ 1 - 1
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)
         {

+ 1 - 1
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:

+ 2 - 2
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);
 

+ 3 - 2
Code/CryEngine/RenderDll/XRenderD3D9/D3DSystem.cpp

@@ -70,6 +70,7 @@
 #endif
 
 #include "../Common/RenderCapabilities.h"
+#include <AzCore/Utils/Utils.h>
 
 #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);
 

+ 209 - 117
Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp

@@ -20,6 +20,8 @@
 #include <AzCore/Component/ComponentApplication.h>
 #include <AzCore/Component/TickBus.h>
 
+#include <AzCore/Debug/LocalFileEventLogger.h>
+
 #include <AzCore/Memory/AllocationRecords.h>
 
 #include <AzCore/Memory/OverrunDetectionAllocator.h>
@@ -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<AZ::Debug::IEventLogger>::Get() == nullptr)
+        {
+            m_eventLogger.reset(new AZ::Debug::LocalFileEventLogger);
+        }
+        else
+        {
+            m_eventLogger = EventLoggerPtr(static_cast<AZ::Debug::LocalFileEventLogger*>(AZ::Interface<AZ::Debug::IEventLogger>::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<SettingsRegistryImpl>();
 
         // 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<AZStd::string, commandOptions.size()> 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<AZ::OSString> 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<AZStd::string_view> 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<RegistryKeySize>::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<AZ::StringFunc::Path::FixedString> 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)

+ 32 - 34
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 <AzCore/Component/ComponentApplicationBus.h>
 #include <AzCore/Component/Component.h>
 #include <AzCore/Component/Entity.h>
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Debug/ProfileModuleInit.h>
-#include <AzCore/Debug/LocalFileEventLogger.h>
 #include <AzCore/Memory/AllocationRecords.h>
 #include <AzCore/Memory/OSAllocator.h>
 #include <AzCore/Module/DynamicModuleHandle.h>
@@ -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/<project>/pc
-            const char* m_cacheRootPath = nullptr;
-
-            //! The path to the project in the asset cache folder.  For instance: ./cache/<project>/pc/<project>
-            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<typename Iterator>
         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<IEventLogger>.
-        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<AZ::Debug::LocalFileEventLogger, EventLoggerDeleter>;
+        EventLoggerPtr m_eventLogger;
     };
 }
-
-#endif // AZCORE_COMPONENT_APPLICATION_H
-#pragma once

+ 5 - 0
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.

+ 4 - 2
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);
         }
     }

+ 14 - 25
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<OpenMode>(static_cast<AZ::u32>(a) | static_cast<AZ::u32>(b));
-        }
-
-        inline OpenMode operator & (OpenMode a, OpenMode b)
-        {
-            return static_cast<OpenMode>(static_cast<AZ::u32>(a) & static_cast<AZ::u32>(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<AZ::IO::FixedMaxPath> 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<AZ::IO::FixedMaxPath> 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;
 

+ 4 - 4
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

+ 3 - 3
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 <typename StringType>
-    [[nodiscard]] constexpr bool BasicPath<StringType>::IsRelativeTo() const
+    [[nodiscard]] constexpr bool BasicPath<StringType>::IsRelativeTo(const PathView& base) const
     {
-        return static_cast<PathView>(*this).IsRelative();
+        return static_cast<PathView>(*this).IsRelativeTo(base);
     }
 
     template <typename StringType>

+ 1 - 0
Code/Framework/AzCore/AzCore/Math/MathReflection.cpp

@@ -369,6 +369,7 @@ namespace AZ
         context.Serializer<JsonVector2Serializer>()->HandlesType<Vector2>();
         context.Serializer<JsonVector3Serializer>()->HandlesType<Vector3>();
         context.Serializer<JsonVector4Serializer>()->HandlesType<Vector4>();
+        context.Serializer<JsonQuaternionSerializer>()->HandlesType<Quaternion>();
     }
 
     void MathReflect(ReflectContext* context)

+ 53 - 0
Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp

@@ -14,6 +14,7 @@
 #include <AzCore/Math/Vector2.h>
 #include <AzCore/Math/Vector3.h>
 #include <AzCore/Math/Vector4.h>
+#include <AzCore/Math/Quaternion.h>
 #include <AzCore/Math/MathVectorSerializer.h>
 #include <AzCore/Serialization/Json/JsonSerialization.h>
 #include <AzCore/Serialization/Json/RegistrationContext.h>
@@ -238,4 +239,56 @@ namespace AZ
     {
         return JsonMathVectorSerializerInternal::Store<Vector4, 4>(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<Quaternion*>(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<float>());
+            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<float>(), itr->value, context);
+                if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+                {
+                    return intermediate;
+                }
+            }
+
+            auto eulerAnglesDegrees = Vector3::CreateFromFloat3(values);
+            reinterpret_cast<Quaternion*>(outputValue)->SetFromEulerDegrees(eulerAnglesDegrees);
+            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read quaternion.");
+        }
+
+        return JsonMathVectorSerializerInternal::Load<Quaternion, 4>(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<Quaternion, 4>(outputValue, inputValue, defaultValue, valueTypeId, context);
+    }
 }

+ 12 - 0
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;
+    };
 }

+ 186 - 122
Code/Framework/AzCore/AzCore/Settings/CommandLine.cpp

@@ -10,11 +10,11 @@
 *
 */
 
-#include <AzCore/Settings/CommandLine.h>
+#include <AzCore/AzCore_Traits_Platform.h>
+#include <AzCore/std/functional.h>
 #include <AzCore/std/string/conversions.h>
+#include <AzCore/Settings/CommandLine.h>
 #include <AzCore/StringFunc/StringFunc.h>
-#include <AzCore/AzCore_Traits_Platform.h>
-#include <AzCore/std/tuple.h>
 
 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<int>(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<AZStd::string_view> 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<AZStd::string> 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<iter, bool>
-                   // 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<AZStd::string> 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, &currentPosIndex](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();
     }
 }

+ 37 - 14
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<AZStd::string>;
+
+        struct CommandArgument
+        {
+            AZStd::string m_option;
+            AZStd::string m_value;
+        };
+        using ArgumentVector = AZStd::vector<CommandArgument>;
+
         CommandLine();
 
         /**
          * Initializes a CommandLine instance which uses the provided commandLineOptionPreix for parsing switches
          */
         CommandLine(AZStd::string_view commandLineOptionPrefix);
-
-        using ParamContainer = AZStd::vector<AZStd::string>;
-        using ParamMap = AZStd::unordered_map<AZStd::string, ParamContainer>;
         /**
         * 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;

+ 9 - 1
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;
             }
         }

+ 400 - 229
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<AZStd::string_view, MaxAppRootPathsToScan> 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<AZStd::fixed_string<AZ::IO::MaxPathLength>> 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<AZ::IO::MaxPathLength> 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<char>::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<EngineInfo> 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<AZ::IO::MaxPathLength> 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<char>::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(&registry) / 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(&registry);
-        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<bufferSize>::format("%s/sys_game_folder", BootstrapSettingsRootKey);
+        auto buffer = AZStd::fixed_string<bufferSize>::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<bufferSize>::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<bufferSize>::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<int>(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<AZ::IO::FixedMaxPathString> 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<bufferSize>::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<int>(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<int>(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<char>* 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<char>* scratchBuffer)
     {
         // Unlike other paths, the path can't be overwritten by the dev settings because that would create a circular dependency.
-        auto mergePath = GetAppRoot(&registry);
-        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<int>(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<int>(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<int>(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<AZ::IO::RapidJSONStreamWriter>,
-                rapidjson::Writer<AZ::IO::RapidJSONStreamWriter>>;
-            SettingsWriter m_writer;
-            AZ::IO::RapidJSONStreamWriter m_rapidJsonStream;
-            DumperSettings m_dumperSettings;
-            AZStd::stack<bool> 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<rapidjson::PrettyWriter<AZ::IO::RapidJSONStreamWriter>>(m_rapidJsonStream);
-                }
-                else
-                {
-                    m_writer.emplace<rapidjson::Writer<AZ::IO::RapidJSONStreamWriter>>(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<rapidjson::StringBuffer> m_writer;
+
+            AZ::IO::RapidJSONStreamWriter m_rapidJsonStream;
+            DumperSettings m_dumperSettings;
+            AZStd::stack<bool> m_includeNameStack;
+            bool m_result{ true };
         };
 
         SettingsExportVisitor visitor(stream, dumperSettings);

+ 59 - 24
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. <ProjectPath>/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. <ProjectPath>/Cache/<assetplatform>
     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<char>* 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<char>* 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 <arg> Sets a value in the registry. See MergeCommandLineArgument for options for <arg>
     //!     example: --regset "/My/String/Value=String value set"
+    //! --regremove <arg> Removes a value in the registry
+    //!    example: --regremove "/My/String/Value"
+    //! only when executeCommands is true are the following options supported:
     //! --regdump <path> 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<bool(AZStd::string_view path)> 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":{ <Dumped values> }
+        //!   }
+        //! }
+        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);
 

+ 52 - 28
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();
                 }
 

+ 47 - 4
Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h

@@ -12,6 +12,7 @@
 
 #pragma once
 
+#include <AzCore/IO/Path/Path_fwd.h>
 #include <AzCore/std/function/function_fwd.h>
 #include <AzCore/std/string/fixed_string.h>
 #include <AzCore/std/string/string.h>
@@ -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<MaxPathLength>;
+            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);
 

+ 1 - 0
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&));

+ 1 - 0
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;

+ 43 - 0
Code/Framework/AzCore/AzCore/Utils/Utils.cpp

@@ -16,6 +16,8 @@
 #include <AzCore/IO/GenericStreams.h>
 #include <AzCore/IO/SystemFile.h>
 #include <AzCore/IO/Path/Path.h>
+#include <AzCore/Settings/SettingsRegistry.h>
+#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
 #include <AzCore/StringFunc/StringFunc.h>
 
 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<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath)
     {
         AZ::IO::FixedMaxPath filePathFixed = filePath; // Because FileIOStream requires a null-terminated string

+ 16 - 5
Code/Framework/AzCore/AzCore/Utils/Utils.h

@@ -16,6 +16,8 @@
 #include <AzCore/base.h>
 #include <AzCore/IO/Path/Path.h>
 #include <AzCore/Outcome/Outcome.h>
+#include <AzCore/IO/Path/Path.h>
+#include <AzCore/Settings/SettingsRegistry.h>
 #include <AzCore/std/optional.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/fixed_string.h>
@@ -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. "<userhome>/.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<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath();
+        AZStd::optional<AZ::IO::FixedMaxPathString> 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<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path);
+        AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path);
 
         //! Save a string to a file. Otherwise returns a failure with error message.
         AZ::Outcome<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath);

+ 5 - 0
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;

+ 17 - 0
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<class Element, size_t MaxElementCount, class Traits>
+    inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::contains(const basic_fixed_string& other) const -> bool
+    {
+        return find(other) != npos;
+    }
+    template<class Element, size_t MaxElementCount, class Traits>
+    inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::contains(value_type c) const -> bool
+    {
+        return find(c) != npos;
+    }
+    template<class Element, size_t MaxElementCount, class Traits>
+    inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::contains(const_pointer s) const -> bool
+    {
+        return find(s) != npos;
+    }
+
     template<class Element, size_t MaxElementCount, class Traits>
     inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::find(const basic_fixed_string& rhs, size_type offset) const -> size_type
     {

+ 16 - 0
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;

+ 16 - 0
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
         {

+ 5 - 5
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<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
+        AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
         {
             const char* appRoot = AZ::Android::Utils::FindAssetsDirectory();
-            return appRoot ? AZStd::make_optional<AZStd::fixed_string<MaxPathLength>>(appRoot) : AZStd::nullopt;
+            return appRoot ? AZStd::make_optional<AZ::IO::FixedMaxPathString>(appRoot) : AZStd::nullopt;
         }
 
         AZStd::optional<AZ::IO::FixedMaxPathString> GetDevWriteStoragePath()
@@ -64,10 +64,10 @@ namespace AZ
             return writeStorage ? AZStd::make_optional<AZ::IO::FixedMaxPathString>(writeStorage) : AZStd::nullopt;
         }
 
-        AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path)
+        AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path)
         {
-            AZStd::fixed_string<MaxPathLength> absolutePath;
-            AZStd::fixed_string<MaxPathLength> srcPath{ path };
+            AZ::IO::FixedMaxPathString absolutePath;
+            AZ::IO::FixedMaxPathString srcPath{ path };
             if (AZ::Android::Utils::IsApkPath(srcPath.c_str()))
             {
                 return srcPath;

+ 1 - 0
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

+ 22 - 0
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 <AzCore/Utils/Utils.h>
+
+namespace AZ::Utils
+{
+    AZ::IO::FixedMaxPathString GetEngineManifestPath()
+    {
+        return {};
+    }
+    
+} // namespace AZ::Utils

+ 19 - 4
Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp

@@ -12,7 +12,7 @@
 
 #include <AzCore/Utils/Utils.h>
 
-#include <stdlib.h>
+#include <cstdlib>
 
 namespace AZ
 {
@@ -25,10 +25,25 @@ namespace AZ
 
         void NativeErrorMessageBox(const char*, const char*) {}
 
-        AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path)
+        AZ::IO::FixedMaxPathString GetEngineManifestPath()
         {
-            AZStd::fixed_string<MaxPathLength> absolutePath;
-            AZStd::fixed_string<MaxPathLength> 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<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path)
+        {
+            AZ::IO::FixedMaxPathString absolutePath;
+            AZ::IO::FixedMaxPathString srcPath{ path };
 
             if (char* result = realpath(srcPath.c_str(), absolutePath.data()); result)
             {

+ 4 - 4
Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp

@@ -47,7 +47,7 @@ namespace AZ
             return result;
         }
 
-        AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
+        AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
         {
             return AZStd::nullopt;
         }
@@ -57,10 +57,10 @@ namespace AZ
             return AZStd::nullopt;
         }
 
-        AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path)
+        AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path)
         {
-            AZStd::fixed_string<MaxPathLength> absolutePath;
-            AZStd::fixed_string<MaxPathLength> 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<char>::length(absolutePath.data()));

+ 1 - 1
Code/Framework/AzCore/Platform/Linux/AzCore/Utils/Utils_Linux.cpp

@@ -45,7 +45,7 @@ namespace AZ
             return result;
         }
 
-        AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
+        AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
         {
             return AZStd::nullopt;
         }

+ 1 - 1
Code/Framework/AzCore/Platform/Mac/AzCore/Utils/Utils_Mac.cpp

@@ -16,7 +16,7 @@
 
 namespace AZ::Utils
 {
-    AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
+    AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
     {
         return AZStd::nullopt;
     }

Some files were not shown because too many files changed in this diff