Browse Source

Updated the SetregBuilder to generate per launcher aggregate setreg (#16137)

* Updated the SetregBuilder to generate per launcher aggregate setreg

The Setreg builder will now generate a `bootstrap.<launcher-type>.<config>.setreg` file.

There are now 9 setreg files that are generated
1. `bootstrap.client.debug.setreg` - loads in the `${project}.GameLauncher` (ClientLauncher) built in the debug configuration
1. `bootstrap.client.profile.setreg` - loads in the `${project}.GameLauncher` (ClientLauncher) built in the profile configuration
1. `bootstrap.client.release.setreg` - loads in the `${project}.GameLauncher` (ClientLauncher) built in the release configuration
1. `bootstrap.server.debug.setreg` - loads in the `${project}.ServerLauncher` (ServerLauncher) built in the debug configuration
1. `bootstrap.server.profile.setreg` - loads in the `${project}.ServerLauncher` (ServerLauncher) built in the profile configuration
1. `bootstrap.server.release.setreg` - loads in the `${project}.ServerLauncher` (ServerLauncher) built in the release configuration
1. `bootstrap.unified.debug.setreg` - loads in the `${project}.UnifiedLauncher` (UnifiedLauncher) built in the debug configuration
1. `bootstrap.unified.profile.setreg` - loads in the `${project}.UnifiedLauncher` (UnifiedLauncher) built in the profile configuration
1. `bootstrap.unified.release.setreg` - loads in the `${project}.UnifiedLauncher` (UnifiedLauncher) built in the release configuration

The Unified Launcher code has been updated to add the launcher type of
the running launcher to the Settings Registry on execution.

The AzGameFramework GameApplication::MergeSettingsToRegistry now reades the launcher type setting to determine the `bootstrap.<launcher-type>.<config>.setreg` file to load.

An additional change is that the launcher type is now added as a
specialization in the settings registry which is used when merging
folders.

For example this means when running the `${project}.GameLauncher`,
settings that will only load in the client launcher can also be placed
in a `<custom-name>.client.setreg file.
For the server launcher a `<custom-name>.server.setreg` can be used to
load server specific settings.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Downgrading log messages which are meant for developers log level

The messages were spamming the console and log on startup and are only
useful for developers debugging those systems(Network, Streamer or
SettingsRegistry)

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Updated the Asset Bundler to save out the AssetSeed files using JSON serialization

The loading of ObjectStream XML Asset seed files remain supported and
this change is 100% backwards compatible.

The `*.seed` file is loaded and first check if it starts with the
ObjectStream XML tag `<`.
If it does, it loads using the ObjectStream Serialization.
Otherwise the file is loading using Json Serialziation

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Converted the Engine Asset Seed List file to JSON by resaving it

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Modified the Asset Bundler GUI settings location

The Common Asset Bundler settings are now saved to the
`<project-path>/Registry` directory.
The User Asset Bundler settings are now saved to the
`<project-path>/user/Registry` directory.

Signed-off-by: lumberyard-employee-dm <[email protected]>

* Grammar and typo fixes for the AssetBundler and bootstrap setreg changes

Signed-off-by: lumberyard-employee-dm <[email protected]>

---------

Signed-off-by: lumberyard-employee-dm <[email protected]>
lumberyard-employee-dm 2 năm trước cách đây
mục cha
commit
cdbbbcf992
25 tập tin đã thay đổi với 648 bổ sung376 xóa
  1. 284 236
      Assets/Engine/SeedAssetList.seed
  2. 3 3
      Code/Framework/AzCore/AzCore/Serialization/Json/JsonUtils.cpp
  3. 9 2
      Code/Framework/AzCore/AzCore/Serialization/Json/JsonUtils.h
  4. 14 4
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
  5. 15 10
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
  6. 8 4
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h
  7. 16 16
      Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StreamerConfiguration_Windows.cpp
  8. 18 8
      Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
  9. 3 3
      Code/Framework/AzNetworking/Platform/Common/WinAPI/AzNetworking/Utilities/NetworkCommon_WinAPI.cpp
  10. 46 15
      Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSeedManager.cpp
  11. 5 0
      Code/LauncherUnified/Game.cpp
  12. 9 1
      Code/LauncherUnified/Launcher.cpp
  13. 5 2
      Code/LauncherUnified/Launcher.h
  14. 5 0
      Code/LauncherUnified/Server.cpp
  15. 5 0
      Code/LauncherUnified/Tests/Test.cpp
  16. 5 0
      Code/LauncherUnified/Unified.cpp
  17. 98 1
      Code/Tools/AssetBundler/CMakeLists.txt
  18. 14 13
      Code/Tools/AssetBundler/source/ui/AssetBundlerTabWidget.cpp
  19. 7 4
      Code/Tools/AssetBundler/tests/DummyProject/SeedAssetList.seed
  20. 4 0
      Code/Tools/AssetBundler/tests/DummyProject/SeedAssetListObjectStreamXML.seed
  21. 8 9
      Code/Tools/AssetBundler/tests/applicationManagerTests.cpp
  22. 26 25
      Code/Tools/AssetBundler/tests/tests_main.cpp
  23. 34 16
      Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
  24. 3 3
      Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp
  25. 4 1
      cmake/Tools/layout_tool.py

+ 284 - 236
Assets/Engine/SeedAssetList.seed

@@ -1,236 +1,284 @@
-<ObjectStream version="3">
-  <Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{2FB1A7EF-557C-577E-94E6-DC1F331E374F}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/config.dat" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{1103CB60-BE8D-56C0-AE9D-98EF531C7106}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/gpu/android_gpus.xml" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{AD7E02A2-5658-5138-95F2-47347A9C1BE1}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/gpu/android_models.xml" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{7646BFFB-B94B-5593-8669-9B387B4669D6}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/gpu/ios_models.xml" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{F408D747-032E-5409-BBDF-2C4AAA5FD385}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/perfhud_pc.xml" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{34B60E74-28FA-57C4-9A2E-77515A083AC5}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/averagememoryusage.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{D84DBC88-3637-5876-B249-E92EA9BCD0F5}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/highmemoryusage.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{98BA37F2-74C0-54CD-8109-F71276E834FE}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/livepreview.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{DAC6670C-4A48-5661-B0DC-030071B2F2AB}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/lowmemoryusage.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{9AF56C8A-4B9F-5B20-A77D-E30114E032D6}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/navigationprocessing.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{B6A22033-75B8-5580-80D7-0568C08AAFF3}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/nullsoundsystem.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{8AE41B60-4004-5749-8B50-5EF6E5151342}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/shadercompiling.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{B150AA1E-B38A-5827-AABE-A072E7C2477F}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/streaming.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{F43241FB-ECDE-55A9-BA59-AE19AF495F62}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engineassets/icons/streamingterrain.tif.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{E03A8D59-7F4C-5C84-9D05-339A65C65E2C}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="fonts/default-ui.font" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{D4279574-B13F-5B71-B5D2-BE04FA3A0C81}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="127" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="fonts/default.font" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{368A249D-7AC3-5B44-A6FC-8FDDF7C2AA62}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/cvargroups/sys_spec_full.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{FD38C182-1AFC-514C-99E5-BB1AB60C4A31}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/android_high.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{A81A509B-C473-583A-9675-AC159B274231}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/android_high_nogmem.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{08D52EFB-D7FB-5266-905F-1599F8D29C77}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/android_low.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{78605B06-1772-5B60-AEF4-4F5DD3AAA665}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/android_malit760.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{9452506B-6F3D-5907-B631-78AD00C7A555}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/android_medium.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{E68C7CB3-DE0B-5A2C-914B-F2E50F48D4F3}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/android_veryhigh.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{6971FAB8-2ABE-5830-AE34-081B35970662}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/ios_high.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{ECFC3EF0-4B9D-504B-8DC6-231CA22E2EDB}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/ios_low.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{3B603071-F68A-515F-BE93-7592E08EA56B}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/ios_medium.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{7DC7B81A-6E95-567E-8BBA-30957B97312A}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="config/spec/ios_veryhigh.cfg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{2DEEC017-D5F2-585D-A729-F68D51AF6E07}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="engine_dependencies.xml" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-    <Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
-      <Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
-        <Class name="AZ::Uuid" field="guid" value="{3B28A661-E723-5EBE-AB52-EC5829D88C31}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
-        <Class name="unsigned int" field="subId" value="-2010443522" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      </Class>
-      <Class name="unsigned int" field="platformFlags" value="255" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
-      <Class name="AZStd::string" field="pathHint" value="bootstrap.game.release.setreg" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
-    </Class>
-  </Class>
-</ObjectStream>
+{
+    "Type": "JsonSerialization",
+    "Version": 1,
+    "ClassName": "AZStd::vector<SeedInfo, allocator>",
+    "ClassData": [
+        {
+            "assetId": {
+                "guid": "{2FB1A7EF-557C-577E-94E6-DC1F331E374F}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/config.dat"
+        },
+        {
+            "assetId": {
+                "guid": "{1103CB60-BE8D-56C0-AE9D-98EF531C7106}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/gpu/android_gpus.xml"
+        },
+        {
+            "assetId": {
+                "guid": "{AD7E02A2-5658-5138-95F2-47347A9C1BE1}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/gpu/android_models.xml"
+        },
+        {
+            "assetId": {
+                "guid": "{7646BFFB-B94B-5593-8669-9B387B4669D6}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/gpu/ios_models.xml"
+        },
+        {
+            "assetId": {
+                "guid": "{F408D747-032E-5409-BBDF-2C4AAA5FD385}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/perfhud_pc.xml"
+        },
+        {
+            "assetId": {
+                "guid": "{34B60E74-28FA-57C4-9A2E-77515A083AC5}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/averagememoryusage.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{D84DBC88-3637-5876-B249-E92EA9BCD0F5}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/highmemoryusage.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{98BA37F2-74C0-54CD-8109-F71276E834FE}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/livepreview.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{DAC6670C-4A48-5661-B0DC-030071B2F2AB}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/lowmemoryusage.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{9AF56C8A-4B9F-5B20-A77D-E30114E032D6}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/navigationprocessing.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{B6A22033-75B8-5580-80D7-0568C08AAFF3}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/nullsoundsystem.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{8AE41B60-4004-5749-8B50-5EF6E5151342}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/shadercompiling.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{B150AA1E-B38A-5827-AABE-A072E7C2477F}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/streaming.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{F43241FB-ECDE-55A9-BA59-AE19AF495F62}",
+                "subId": 1000
+            },
+            "platformFlags": 127,
+            "pathHint": "engineassets/icons/streamingterrain.tif.streamingimage"
+        },
+        {
+            "assetId": {
+                "guid": "{E03A8D59-7F4C-5C84-9D05-339A65C65E2C}"
+            },
+            "platformFlags": 127,
+            "pathHint": "fonts/default-ui.font"
+        },
+        {
+            "assetId": {
+                "guid": "{D4279574-B13F-5B71-B5D2-BE04FA3A0C81}"
+            },
+            "platformFlags": 127,
+            "pathHint": "fonts/default.font"
+        },
+        {
+            "assetId": {
+                "guid": "{368A249D-7AC3-5B44-A6FC-8FDDF7C2AA62}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/cvargroups/sys_spec_full.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{FD38C182-1AFC-514C-99E5-BB1AB60C4A31}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/android_high.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{A81A509B-C473-583A-9675-AC159B274231}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/android_high_nogmem.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{08D52EFB-D7FB-5266-905F-1599F8D29C77}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/android_low.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{78605B06-1772-5B60-AEF4-4F5DD3AAA665}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/android_malit760.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{9452506B-6F3D-5907-B631-78AD00C7A555}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/android_medium.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{E68C7CB3-DE0B-5A2C-914B-F2E50F48D4F3}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/android_veryhigh.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{6971FAB8-2ABE-5830-AE34-081B35970662}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/ios_high.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{ECFC3EF0-4B9D-504B-8DC6-231CA22E2EDB}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/ios_low.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B603071-F68A-515F-BE93-7592E08EA56B}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/ios_medium.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{7DC7B81A-6E95-567E-8BBA-30957B97312A}"
+            },
+            "platformFlags": 255,
+            "pathHint": "config/spec/ios_veryhigh.cfg"
+        },
+        {
+            "assetId": {
+                "guid": "{2DEEC017-D5F2-585D-A729-F68D51AF6E07}"
+            },
+            "platformFlags": 255,
+            "pathHint": "engine_dependencies.xml"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 2872571093
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.client.release.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 3617796014
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.client.profile.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 3128343591
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.client.debug.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 68654025
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.server.release.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 3046526190
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.server.profile.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 2583959823
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.server.debug.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 2402393288
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.unified.release.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 1383733705
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.unified.profile.setreg"
+        },
+        {
+            "assetId": {
+                "guid": "{3B28A661-E723-5EBE-AB52-EC5829D88C31}",
+                "subId": 4106752934
+            },
+            "platformFlags": 255,
+            "pathHint": "bootstrap.unified.debug.setreg"
+        }
+    ]
+}

+ 3 - 3
Code/Framework/AzCore/AzCore/Serialization/Json/JsonUtils.cpp

@@ -292,10 +292,10 @@ namespace AZ::JsonSerializationUtils
         }
 
         auto dataItr = jsonDocument.FindMember(ClassDataTag);
-        // data can be empty but it should be an object
-        if (dataItr != jsonDocument.MemberEnd() && !dataItr->value.IsObject())
+        // data can be empty but it should be an object or array
+        if (dataItr != jsonDocument.MemberEnd() && (!dataItr->value.IsObject() && !dataItr->value.IsArray()))
         {
-            return AZ::Failure(AZStd::string::format("ClassData should be an object"));
+            return AZ::Failure(AZStd::string::format("ClassData should be an object or array"));
         }
 
         return AZ::Success();

+ 9 - 2
Code/Framework/AzCore/AzCore/Serialization/Json/JsonUtils.h

@@ -25,7 +25,7 @@ namespace AZ
     struct JsonSerializerSettings;
     struct JsonDeserializerSettings;
 
-    // Utility functions which use json serializer/deserializer to save/load object to file/stream 
+    // Utility functions which use json serializer/deserializer to save/load object to file/stream
     namespace JsonSerializationUtils
     {
         struct WriteJsonSettings
@@ -77,7 +77,7 @@ namespace AZ
 
         //! Parse a json stream. Returns a failure with error message if the content is not valid JSON.
         AZ::Outcome<rapidjson::Document, AZStd::string> ReadJsonStream(IO::GenericStream& stream);
-        
+
         //! Load object with known class type
         //! Even if errorsOut contains errors, the load to an object could have succeeded
         AZ::Outcome<void, AZStd::string> LoadObjectFromStringByType(void* objectToLoad, const Uuid& objectType, AZStd::string_view source,
@@ -118,6 +118,13 @@ namespace AZ
             return LoadObjectFromStream(objectToLoad, inputFileStream, settings);
         }
 
+        template <typename ObjectType>
+        AZ::Outcome<void, AZStd::string> LoadObjectFromString(ObjectType& objectToLoad, AZStd::string_view source,
+            const JsonDeserializerSettings* settings = nullptr)
+        {
+            return LoadObjectFromStringByType(&objectToLoad, AzTypeInfo<ObjectType>::Uuid(), source, settings);
+        }
+
         //! Load any object
         AZ::Outcome<AZStd::any, AZStd::string> LoadAnyObjectFromStream(IO::GenericStream& stream, const JsonDeserializerSettings* settings = nullptr);
         AZ::Outcome<AZStd::any, AZStd::string> LoadAnyObjectFromFile(const AZStd::string& filePath,const JsonDeserializerSettings* settings = nullptr);

+ 14 - 4
Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h

@@ -44,7 +44,7 @@ namespace AZ
         static constexpr char PlatformFolder[] = "Platform";
 
         //! Represents a fixed size non-allocating string type that can be used to query the settings registry using Get()
-        //! If the value is longer than FixedValueString::max_size(), then either the heap allocating 
+        //! If the value is longer than FixedValueString::max_size(), then either the heap allocating
         //! AZStd::string overload must be used or the Visit method must be used
         using FixedValueString = AZ::StringFunc::Path::FixedString;
 
@@ -83,6 +83,16 @@ namespace AZ
             AZStd::fixed_vector<TagName, MaxCount> m_names;
             AZStd::fixed_vector<size_t, MaxCount> m_hashes;
         };
+        // The Settings Registry specialization is a list of tags between
+        // <dots> that are part of a .setreg(patch) file that is used
+        // to determine if the file should be loaded
+        // It is of the form <basename>.<tag1>.<tag2> ... .<tagN>.setreg
+        // Example tag files are:
+        // 1. streamer.editor.setreg
+        //  -> the filename tag here is "editor"
+        // 2. custom_settings.asset_processor.windows.setreg
+        //  -> the filename tags here are "asset_processor" and "windows"
+        using FilenameTags = Specializations;
 
         //! Type of the store value, or None if there's no value stored.
         enum class Type
@@ -217,7 +227,7 @@ namespace AZ
         //! @return Whether or not entries could be visited.
         virtual bool Visit(Visitor& visitor, AZStd::string_view path) const = 0;
         //! Traverses over the entries in the Settings Registry. Use this version if only the names and/or types are needed.
-        //! @param callback A callback function that will repeatedly be called as entries are encountered. 
+        //! @param callback A callback function that will repeatedly be called as entries are encountered.
         //! @param path An offset at which traversal should start.
         //! @return Whether or not entries could be visited.
         virtual bool Visit(const VisitorCallback& callback, AZStd::string_view path) const = 0;
@@ -315,7 +325,7 @@ namespace AZ
         //! @param value The new value to store.
         //! @return Whether or not the value was stored. An invalid path will return false;
         virtual bool Set(AZStd::string_view path, const char* value) = 0;
-        
+
         //! Sets the value at the provided path to the serialized version of the provided struct/class.
         //! Classes used for this call need to be registered with the Serialize Context.
         //! Prefer to use SetObject(AZStd::string_view path, const T& result) over this one.
@@ -332,7 +342,7 @@ namespace AZ
         template<typename T>
         bool SetObject(AZStd::string_view path, const T& value) { return SetObject(path, &value, azrtti_typeid(value)); }
 
-        //! Remove the value at the provided path 
+        //! Remove the value at the provided path
         //! @param path The path to a value that should be removed
         //! @return Whether or not the path was found and removed. An invalid path will return false;
         virtual bool Remove(AZStd::string_view path) = 0;

+ 15 - 10
Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp

@@ -264,7 +264,7 @@ namespace AZ::Internal
             return AZ::Success();
         }
 
-        // If the engine has no version information or is not known incompatible then assume compatible 
+        // If the engine has no version information or is not known incompatible then assume compatible
         const auto engineVersionKey = FixedValueString::format("%s/version", EngineSettingsRootKey);
         if(FixedValueString engineVersionValue; settingsRegistry.Get(engineVersionValue, engineVersionKey))
         {
@@ -341,7 +341,7 @@ namespace AZ::Internal
         // Visit over the engine paths list and merge the engine.json files to settings registry.
         // Merge project.json to settings registry.  The "engine" key contains the engine name and optional version specifier.
         // When we find a match for "engine_name" value against the "engine" we check if the engine "version" is compatible
-        // with any version specifier in the project's "engine" key. 
+        // with any version specifier in the project's "engine" key.
         // If the engine is compatible we check if it is more compatible than the previously found most compatible engine.
         // Finally, merge in the engine and project settings for the most compatible engine into the registry and
         // return the path of the most compatible engine
@@ -393,7 +393,7 @@ namespace AZ::Internal
                 EngineInfo mostCompatibleEngineInfo;
                 AZ::IO::FixedMaxPath projectUserPath;
                 settingsRegistry.Get(projectUserPath.Native(), FilePathKey_ProjectUserPath);
-        
+
                 AZ::SettingsRegistryImpl scratchSettingsRegistry;
 
                 // Look through the manifest engines for the most compatible engine
@@ -871,16 +871,21 @@ namespace AZ::SettingsRegistryMergeUtils
         registry.Visit(visitor, SpecializationsRootKey);
     }
 
-    void MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(SettingsRegistryInterface& registry, AZStd::string_view targetName)
+    void MergeSettingsToRegistry_AddSpecialization(SettingsRegistryInterface& registry, AZStd::string_view value)
     {
-        registry.Set(BuildTargetNameKey, targetName);
-
-        // Add specializations to the target registry based on the name of the Build System Target
         auto targetSpecialization = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%.*s",
-            SpecializationsRootKey, aznumeric_cast<int>(targetName.size()), targetName.data());
+            SpecializationsRootKey, AZ_STRING_ARG(value));
         registry.Set(targetSpecialization, true);
     }
 
+    void MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(SettingsRegistryInterface& registry,
+        AZStd::string_view targetName)
+    {
+        registry.Set(BuildTargetNameKey, targetName);
+        // Add specializations to the target registry based on the name of the Build System Target
+        MergeSettingsToRegistry_AddSpecialization(registry, targetName);
+    }
+
     bool MergeSettingsToRegistry_ConfigFile(SettingsRegistryInterface& registry, AZStd::string_view filePath,
         const ConfigParserSettings& configParserSettings)
     {
@@ -933,7 +938,7 @@ namespace AZ::SettingsRegistryMergeUtils
             // While all parsing and formatting errors are actual errors, config files that are not present
             // is not an error as they are always optional.  In this case, show a brief trace message
             // that indicates the location the file could be placed at in order to run it.
-            AZ_TracePrintf("SettingsRegistryMergeUtils", "Optional config file \"%s\" not found.\n", configPath.c_str());
+            AZ_Trace("SettingsRegistryMergeUtils", "Optional config file \"%s\" not found.\n", configPath.c_str());
             return false;
         }
 
@@ -1410,7 +1415,7 @@ namespace AZ::SettingsRegistryMergeUtils
         // Provide mappings for the engine root directroy, project product directory(<project-root>/Cache/<asset-platform>),
         // project user directory (<project-root>/user), project log directory (<project-root>/user/log)
         // command line options to regset options
-        // 
+        //
         // A mapping for the project-build-path option which represents the CMake binary directory
         // supplied during configure is also available to be mapped to a regset setting
         //

+ 8 - 4
Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h

@@ -21,8 +21,8 @@ namespace AZ::IO
 namespace AZ::SettingsRegistryMergeUtils
 {
     inline constexpr const char* OrganizationRootKey = "/Amazon";
-    inline constexpr const char* BuildTargetNameKey = "/Amazon/AzCore/Settings/BuildTargetName";
-    inline constexpr const char* SpecializationsRootKey = "/Amazon/AzCore/Settings/Specializations";
+    inline constexpr const char* BuildTargetNameKey = "/O3DE/Settings/BuildTargetName";
+    inline constexpr const char* SpecializationsRootKey = "/O3DE/Settings/Specializations";
     inline constexpr const char* BootstrapSettingsRootKey = "/Amazon/AzCore/Bootstrap";
     inline constexpr const char* FilePathsRootKey = "/O3DE/Runtime/FilePaths";
     inline constexpr const char* FilePathKey_BinaryFolder = "/O3DE/Runtime/FilePaths/BinaryFolder";
@@ -126,6 +126,10 @@ namespace AZ::SettingsRegistryMergeUtils
     //! The SpecializationsRootKey is visited to retrieve any specializations stored within that section of that registry
     void QuerySpecializationsFromRegistry(SettingsRegistryInterface& registry, SettingsRegistryInterface::Specializations& specializations);
 
+    //! Adds value as a string under the Settings Registry `SpecializationsRootKey`
+    //! The specializations can be queried using the QuerySpecializationsFromRegistry function above
+    void MergeSettingsToRegistry_AddSpecialization(SettingsRegistryInterface& registry, AZStd::string_view value);
+
     //! Adds name of current build system target to the Settings Registry specialization section
     //! A build system target is the name used by the build system to build a particular executable or library
     void MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(SettingsRegistryInterface& registry, AZStd::string_view targetName);
@@ -273,13 +277,13 @@ namespace AZ::SettingsRegistryMergeUtils
     //! --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.
-    //! 
+    //!
     //! The CommandsToParse structure determines which options should be processed from the command line
     //! `CommandsToParse::m_parseRegdumpCommands=true` allows the --regdump and --regdumpall commands to be processed
     //! `CommandsToParse::m_parseRegsetCommands=true` allows the --regset command to be processed
     //! `CommandsToParse::m_parseRegremveCommands=true` allows the --regremove command to be processed
     //! `CommandsToParse::m_parseRegsetFileCommands=true` allows the --regset-file command to be processed
-    //! 
+    //!
     //! Note that this function is only called in development builds and is compiled out in release builds.
     void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, AZ::CommandLine commandLine,
         const CommandsToParse& commandsToParse = {});

+ 16 - 16
Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StreamerConfiguration_Windows.cpp

@@ -34,7 +34,7 @@ namespace AZ::IO
         return value;
     }
 
-    static void CollectIoAdaptor(HANDLE deviceHandle, DriveInformation& info, const char* driveName, bool reportHardware)
+    static void CollectIoAdaptor(HANDLE deviceHandle, DriveInformation& info, [[maybe_unused]] const char* driveName, bool reportHardware)
     {
         STORAGE_ADAPTER_DESCRIPTOR adapterDescriptor{};
         STORAGE_PROPERTY_QUERY query{};
@@ -73,7 +73,7 @@ namespace AZ::IO
 
             if (reportHardware)
             {
-                AZ_Printf(
+                AZ_Trace(
                     "Streamer",
                     "Adapter for drive '%s':\n"
                     "    Bus: %s %i.%i\n"
@@ -112,7 +112,7 @@ namespace AZ::IO
             if (reportHardware)
             {
 
-                AZ_Printf("Streamer",
+                AZ_Trace("Streamer",
                     "    Drive type: %s\n",
                     trimDescriptor.TrimEnabled ? "SSD" : "HDD");
             }
@@ -121,7 +121,7 @@ namespace AZ::IO
         {
             if (reportHardware)
             {
-                AZ_Printf("Streamer", "    Drive type couldn't be determined.");
+                AZ_Trace("Streamer", "    Drive type couldn't be determined.");
             }
         }
     }
@@ -141,7 +141,7 @@ namespace AZ::IO
             information.m_logicalSectorSize = aznumeric_caster(alignmentDescriptor.BytesPerLogicalSector);
             if (reportHardware)
             {
-                AZ_Printf(
+                AZ_Trace(
                     "Streamer",
                     "    Physical sector size: %i bytes\n"
                     "    Logical sector size: %i bytes\n",
@@ -151,7 +151,7 @@ namespace AZ::IO
         }
     }
 
-    static void CollectDriveInfo(HANDLE deviceHandle, const char* driveName, bool reportHardware)
+    static void CollectDriveInfo(HANDLE deviceHandle, [[maybe_unused]] const char* driveName, bool reportHardware)
     {
         STORAGE_DEVICE_DESCRIPTOR sizeRequest{};
         STORAGE_PROPERTY_QUERY query{};
@@ -170,8 +170,8 @@ namespace AZ::IO
             {
                 if (reportHardware)
                 {
-                    auto deviceDescriptor = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(buffer.get());
-                    AZ_Printf("Streamer",
+                    [[maybe_unused]] auto deviceDescriptor = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(buffer.get());
+                    AZ_Trace("Streamer",
                         "Drive info for '%s':\n"
                         "    Id: %s%s%s%s%s\n",
                         driveName,
@@ -199,7 +199,7 @@ namespace AZ::IO
             information.m_ioChannelCount = aznumeric_caster(capabilityDescriptor.LunMaxIoCount);
             if (reportHardware)
             {
-                AZ_Printf(
+                AZ_Trace(
                     "Streamer",
                     "    Max IO count (LUN): %i\n"
                     "    Max IO count (Adapter): %i\n",
@@ -224,7 +224,7 @@ namespace AZ::IO
             information.m_hasSeekPenalty = seekPenaltyDescriptor.IncursSeekPenalty ? true : false;
             if (reportHardware)
             {
-                AZ_Printf("Streamer",
+                AZ_Trace("Streamer",
                     "    Has seek penalty: %s\n",
                     information.m_hasSeekPenalty ? "Yes" : "No");
             }
@@ -277,7 +277,7 @@ namespace AZ::IO
                     {
                         if (reportHardware)
                         {
-                            AZ_Printf("Streamer", "Skipping drive '%s' because no paths make use of it.\n", driveIt);
+                            AZ_Trace("Streamer", "Skipping drive '%s' because no paths make use of it.\n", driveIt);
                         }
                         while (*driveIt++);
                         continue;
@@ -322,14 +322,14 @@ namespace AZ::IO
 
                                     if (reportHardware)
                                     {
-                                        AZ_Printf("Streamer", "\n");
+                                        AZ_Trace("Streamer", "\n");
                                     }
                                 }
                                 else
                                 {
                                     if (reportHardware)
                                     {
-                                        AZ_Printf(
+                                        AZ_Trace(
                                             "Streamer", "Skipping drive '%s' because device does not support queuing requests.\n", driveIt);
                                     }
                                 }
@@ -338,7 +338,7 @@ namespace AZ::IO
                             {
                                 if (reportHardware)
                                 {
-                                    AZ_Printf(
+                                    AZ_Trace(
                                         "Streamer", "Drive '%s' is on the same storage drive as '%s'.\n",
                                         driveIt, driveInformationEntry->second.m_paths[0].c_str());
                                 }
@@ -349,7 +349,7 @@ namespace AZ::IO
                         {
                             if (reportHardware)
                             {
-                                AZ_Printf(
+                                AZ_Trace(
                                     "Streamer", "Skipping drive '%s' because device is not registered with OS as a storage device.\n",
                                     driveIt);
                             }
@@ -366,7 +366,7 @@ namespace AZ::IO
                 {
                     if (reportHardware)
                     {
-                        AZ_Printf("Streamer", "Skipping drive '%s', as it the type of drive is not supported.\n", driveIt);
+                        AZ_Trace("Streamer", "Skipping drive '%s', as it the type of drive is not supported.\n", driveIt);
                     }
                 }
 

+ 18 - 8
Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp

@@ -72,15 +72,25 @@ namespace AzGameFramework
 
         MergeSharedSettings(registry, specializations, scratchBuffer);
 
-        // Used the lowercase the platform name since the bootstrap.game.<config>.setreg is being loaded
-        // from the asset cache root where all the files are in lowercased from regardless of the filesystem case-sensitivity
-        static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE  ".setreg";
-
-        AZ::IO::FixedMaxPath cacheRootPath;
-        if (registry.Get(cacheRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
+        // Query the launcher type from the registry
+        constexpr AZStd::string_view LauncherTypeTag = "/O3DE/Runtime/LauncherType";
+        using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
+        if (FixedValueString launcherType; registry.Get(launcherType, LauncherTypeTag)
+            && !launcherType.empty())
         {
-            cacheRootPath /= filename;
-            registry.MergeSettingsFile(cacheRootPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "", &scratchBuffer);
+            // The bootstrap setreg file that is loaded is in the form of
+            // bootstrap.<launcher-type-lower>.<config-lower>.setreg
+            AZ::IO::FixedMaxPath filename = "bootstrap.";
+            filename.Native() += launcherType;
+            filename.Native() += '.';
+            filename.Native() += AZ_BUILD_CONFIGURATION_TYPE ".setreg";
+
+            AZ::IO::FixedMaxPath cacheRootPath;
+            if (registry.Get(cacheRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
+            {
+                cacheRootPath /= filename;
+                registry.MergeSettingsFile(cacheRootPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "", &scratchBuffer);
+            }
         }
 
         MergeUserSettings(registry, specializations, scratchBuffer);

+ 3 - 3
Code/Framework/AzNetworking/Platform/Common/WinAPI/AzNetworking/Utilities/NetworkCommon_WinAPI.cpp

@@ -27,14 +27,14 @@ namespace AzNetworking
                 return false;
             }
 
-            AZLOG_INFO("Network layer initialized");
+            AZLOG_DEBUG("Network layer initialized");
             return true;
         }
 
         bool SocketLayerShutdown()
         {
             WSACleanup();
-            AZLOG_INFO("Network layer shut down");
+            AZLOG_DEBUG("Network layer shut down");
             return true;
         }
 
@@ -88,7 +88,7 @@ namespace AzNetworking
     #if AZ_TRAIT_OS_IS_HOST_OS_PLATFORM
             FormatMessageA
             (
-                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
+                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                 nullptr,
                 errorCode,
                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

+ 46 - 15
Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSeedManager.cpp

@@ -12,11 +12,12 @@
 #include <AzCore/IO/FileIO.h>
 #include <AzCore/Math/Sha1.h>
 #include <AzCore/Serialization/Utils.h>
+#include <AzCore/Serialization/Json/JsonUtils.h>
 #include <AzCore/Slice/SliceAsset.h>
+#include <AzCore/StringFunc/StringFunc.h>
 #include <AzCore/Asset/AssetManagerBus.h>
 #include <AzFramework/FileTag/FileTagBus.h>
 #include <AzFramework/FileTag/FileTag.h>
-#include <AzFramework/StringFunc/StringFunc.h>
 #include <AzToolsFramework/Asset/AssetDebugInfo.h>
 #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogBus.h>
 #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
@@ -31,7 +32,6 @@ const char ScriptCanvasFunctionCompiled[] = "scriptcanvas_fn_compiled";
 
 namespace AzToolsFramework
 {
-
     AZStd::string GetSeedPath(AZ::Data::AssetId assetId, AzFramework::PlatformFlags platformFlags)
     {
         using namespace AzToolsFramework;
@@ -45,7 +45,7 @@ namespace AzToolsFramework
                 return assetPath;
             }
         }
-        
+
         AZ_Warning("AssetSeedManager", false, "Unable to resolve path of Seed asset (%s) for the given platforms (%s).\n", assetId.ToString<AZStd::string>().c_str(), AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(platformFlags).c_str());
 
         return {};
@@ -289,7 +289,7 @@ namespace AzToolsFramework
     {
         for (auto iter = m_assetSeedList.begin(); iter != m_assetSeedList.end(); ++iter)
         {
-            if (AzFramework::StringFunc::Equal(iter->m_assetRelativePath.c_str(), pathHint.c_str()))
+            if (AZ::StringFunc::Equal(iter->m_assetRelativePath.c_str(), pathHint.c_str()))
             {
                 return iter->m_assetId;
             }
@@ -409,12 +409,12 @@ namespace AzToolsFramework
             // source asset type, we will fix the fileextension.
 
             AZStd::string fileExtension;
-            AzFramework::StringFunc::Path::GetExtension(seedPath.c_str(), fileExtension, false);
+            AZ::StringFunc::Path::GetExtension(seedPath.c_str(), fileExtension, false);
             auto found = m_sourceAssetTypeToRuntimeAssetTypeMap.find(fileExtension);
 
             if (found != m_sourceAssetTypeToRuntimeAssetTypeMap.end())
             {
-                AzFramework::StringFunc::Path::ReplaceExtension(seedPath, found->second.c_str());
+                AZ::StringFunc::Path::ReplaceExtension(seedPath, found->second.c_str());
                 AZ_Warning("AssetSeedManager", false, "( %s ) is an editor only asset. We wil use seed asset( %s ) instead.\n", assetPath.c_str(), seedPath.c_str());
             }
             else
@@ -431,10 +431,10 @@ namespace AzToolsFramework
     void AssetSeedManager::PopulateAssetTypeMap()
     {
         AZStd::string sliceFileExtension;
-        AzFramework::StringFunc::Path::GetExtension(AZ::SliceAsset::GetFileFilter(), sliceFileExtension, false);
+        AZ::StringFunc::Path::GetExtension(AZ::SliceAsset::GetFileFilter(), sliceFileExtension, false);
 
         AZStd::string dynamicSliceFileExtension;
-        AzFramework::StringFunc::Path::GetExtension(AZ::DynamicSliceAsset::GetFileFilter(), dynamicSliceFileExtension, false);
+        AZ::StringFunc::Path::GetExtension(AZ::DynamicSliceAsset::GetFileFilter(), dynamicSliceFileExtension, false);
 
         m_sourceAssetTypeToRuntimeAssetTypeMap[sliceFileExtension] = dynamicSliceFileExtension;
         m_sourceAssetTypeToRuntimeAssetTypeMap[ScriptCanvas] = ScriptCanvasCompiled;
@@ -484,7 +484,7 @@ namespace AzToolsFramework
 
             AZ::Data::AssetInfo seedAssetInfo = GetAssetInfoById(m_assetSeedList[idx].m_assetId, platformIndex, m_assetSeedList[idx].m_seedListFilePath, m_assetSeedList[idx].m_assetRelativePath);
 
-            if (optionalDebugList && 
+            if (optionalDebugList &&
                 optionalDebugList->m_fileDebugInfoList.find(seedAssetInfo.m_assetId) == optionalDebugList->m_fileDebugInfoList.end())
             {
                 optionalDebugList->m_fileDebugInfoList[seedAssetInfo.m_assetId].m_assetId = seedAssetInfo.m_assetId;
@@ -546,7 +546,7 @@ namespace AzToolsFramework
     }
 
     AssetFileInfoList AssetSeedManager::GetDependencyList(AzFramework::PlatformId platformIndex, const AZStd::unordered_set<AZ::Data::AssetId>& exclusionList, AssetFileDebugInfoList* optionalDebugList, const AZStd::vector<AZStd::string>& wildcardPatternExclusionList) const
-    {     
+    {
         AssetSeedManager::AssetsInfoList  assetInfoList = AZStd::move(GetDependenciesInfo(platformIndex, exclusionList, optionalDebugList, wildcardPatternExclusionList));
 
         AssetFileInfoList assetFileInfoList;
@@ -561,7 +561,7 @@ namespace AzToolsFramework
                 if (!assetInfo.m_relativePath.empty())
                 {
                     AZStd::string assetPath;
-                    AzFramework::StringFunc::Path::Join(assetRoot.c_str(), assetInfo.m_relativePath.c_str(), assetPath);
+                    AZ::StringFunc::Path::Join(assetRoot.c_str(), assetInfo.m_relativePath.c_str(), assetPath);
                     if (!fileIO->Exists(assetPath.c_str()))
                     {
                         AZ_Warning("AssetSeedManager", false, "Asset ( %s ) does not exist in the cache folder.\n", assetPath.c_str());
@@ -680,7 +680,7 @@ namespace AzToolsFramework
 
     AZ::Outcome<void, AZStd::string> AssetSeedManager::ValidateSeedFileExtension(const AZStd::string& path)
     {
-        if (!AzFramework::StringFunc::EndsWith(path, SeedFileExtension))
+        if (!AZ::StringFunc::EndsWith(path, SeedFileExtension))
         {
             return AZ::Failure(AZStd::string::format(
                 "Invalid Seed List file path ( %s ). Invalid file extension, Seed List files can only have ( .%s ) extension.\n",
@@ -739,7 +739,7 @@ namespace AzToolsFramework
             return false;
         }
 
-        return AZ::Utils::SaveObjectToFile(destinationPath, AZ::DataStream::StreamType::ST_XML, &m_assetSeedList);
+        return static_cast<bool>(AZ::JsonSerializationUtils::SaveObjectToFile(&m_assetSeedList, destinationPath));
     }
 
     void AssetSeedManager::UpdateSeedPath()
@@ -772,11 +772,42 @@ namespace AzToolsFramework
         }
 
         AzFramework::AssetSeedList assetSeedList;
-        if (!AZ::Utils::LoadObjectFromFileInPlace(sourceFilePath.c_str(), assetSeedList))
+
+        // As the seed file can support both JSON and ObjectStream XML
+        // It is opened and read into memory first
+        AZ::IO::FileIOStream assetSeedStream;
+        if (!assetSeedStream.Open(sourceFilePath.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary))
         {
             return false;
         }
 
+        auto ReadAssetSeedData = [&assetSeedStream](char* buffer, size_t size) -> size_t
+        {
+            return assetSeedStream.Read(size, buffer);
+        };
+
+        AZStd::string assetSeedData;
+        assetSeedData.resize_and_overwrite(assetSeedStream.GetLength(), ReadAssetSeedData);
+
+        // If the asset seed file starts with the ObjectStream XML stream tag
+        // then load the data using the ObjectStream
+        constexpr AZ::u8 xmlObjectStreamTag = '<';
+        if (assetSeedData.starts_with(xmlObjectStreamTag))
+        {
+            if (!AZ::Utils::LoadObjectFromBufferInPlace(assetSeedData.c_str(), assetSeedData.size(), assetSeedList))
+            {
+                return false;
+            }
+        }
+        else
+        {
+            // Load the asset seed file using Json Serialization
+            if (!AZ::JsonSerializationUtils::LoadObjectFromString(assetSeedList, assetSeedData))
+            {
+                return false;
+            }
+        }
+
         for (AzFramework::SeedInfo& seedInfo : assetSeedList)
         {
             AddSeedAsset(seedInfo.m_assetId, seedInfo.m_platformFlags, seedInfo.m_assetRelativePath, sourceFilePath.c_str());
@@ -843,7 +874,7 @@ namespace AzToolsFramework
 
     AZ::Outcome<void, AZStd::string> AssetFileInfoList::ValidateAssetListFileExtension(const AZStd::string& path)
     {
-        if (!AzFramework::StringFunc::EndsWith(path, AssetListFileExtension))
+        if (!AZ::StringFunc::EndsWith(path, AssetListFileExtension))
         {
             return AZ::Failure(AZStd::string::format(
                 "Invalid Asset List file path ( %s ). Invalid file extension, Asset List files can only have ( .%s ) extension.\n",

+ 5 - 0
Code/LauncherUnified/Game.cpp

@@ -22,4 +22,9 @@ namespace O3DELauncher
     {
         return "@log@/Game.log";
     }
+
+    const char* GetLauncherTypeSpecialization()
+    {
+        return "client";
+    }
 }

+ 9 - 1
Code/LauncherUnified/Launcher.cpp

@@ -128,6 +128,8 @@ namespace
 
 namespace O3DELauncher
 {
+    inline constexpr AZStd::string_view LauncherTypeTag = "/O3DE/Runtime/LauncherType";
+
     AZ_CVAR(bool, bg_ConnectToAssetProcessor, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "If true, the process will launch and connect to the asset processor");
 
     bool PlatformMainInfo::CopyCommandLine(int argc, char** argv)
@@ -411,6 +413,12 @@ namespace O3DELauncher
         const AZStd::string_view buildTargetName = GetBuildTargetName();
         AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(*settingsRegistry, buildTargetName);
 
+        //Store the launcher type to the Settings Registry
+        AZStd::string_view launcherType = GetLauncherTypeSpecialization();
+        settingsRegistry->Set(LauncherTypeTag, launcherType);
+        // Also add the launcher type as a specialization as well
+        AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddSpecialization(*settingsRegistry, launcherType);
+
         AZ_TracePrintf("Launcher", R"(Running project "%.*s")" "\n"
             R"(The project name has been successfully set in the Settings Registry at key "%s/project_name")"
             R"( for Launcher target "%.*s")" "\n",
@@ -559,7 +567,7 @@ namespace O3DELauncher
                 auto autoExecFile = AZ::IO::FixedMaxPath{pathToAssets} / "autoexec.cfg";
                 AZ::Interface<AZ::IConsole>::Get()->ExecuteConfigFile(autoExecFile.Native());
 
-                // Find out if console command file was passed 
+                // Find out if console command file was passed
                 // via --console-command-file=%filename% and execute it
                 ExecuteConsoleCommandFile(gameApplication);
 

+ 5 - 2
Code/LauncherUnified/Launcher.h

@@ -92,7 +92,7 @@ namespace O3DELauncher
     AZStd::string_view GetBuildTargetName();
 
     //////////////////////////////////////////////////////////////////////////
-    // The following functions are defined per launcher type (e.g. Game/Server)
+    // The following functions are defined per launcher type (e.g. Client/Server/Unified)
     //////////////////////////////////////////////////////////////////////////
 
     //! Indicates if it should wait for a connection to the AssetProcessor (will attempt to open it if true)
@@ -103,5 +103,8 @@ namespace O3DELauncher
 
     //! Gets the name of the log file to use
     const char* GetLogFilename();
-}
 
+    //! Returns the SettingsRegistry specialization tag
+    //! that can be used to load settings for the specific launcher
+    const char* GetLauncherTypeSpecialization();
+}

+ 5 - 0
Code/LauncherUnified/Server.cpp

@@ -23,4 +23,9 @@ namespace O3DELauncher
     {
         return "@log@/Server.log";
     }
+
+    const char* GetLauncherTypeSpecialization()
+    {
+        return "server";
+    }
 }

+ 5 - 0
Code/LauncherUnified/Tests/Test.cpp

@@ -25,6 +25,11 @@ namespace O3DELauncher
         return "@log@/Game.log";
     }
 
+    const char* GetLauncherTypeSpecialization()
+    {
+        return "client";
+    }
+
     AZStd::string_view GetBuildTargetName()
     {
 #if !defined (LY_CMAKE_TARGET)

+ 5 - 0
Code/LauncherUnified/Unified.cpp

@@ -22,4 +22,9 @@ namespace O3DELauncher
     {
         return "@log@/Unified.log";
     }
+
+    const char* GetLauncherTypeSpecialization()
+    {
+        return "unified";
+    }
 }

+ 98 - 1
Code/Tools/AssetBundler/CMakeLists.txt

@@ -58,7 +58,7 @@ ly_add_target(
     AUTOMOC
     AUTOUIC
     AUTORCC
-    FILES_CMAKE 
+    FILES_CMAKE
         assetbundlergui_files.cmake
         assetbundler_exe_files.cmake
         Platform/${PAL_PLATFORM_NAME}/assetbundlergui_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
@@ -107,4 +107,101 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
         TEST_COMMAND $<TARGET_FILE:AZ::AssetBundler.Tests> --unittest
     )
 
+    # Copy test files needed for asset processor test to the executable directory
+    # This allows the test to reference its files using a portable path that can be provided
+    # to users on other machines
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/AssetProcessorPlatformConfig.setreg
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir
+    )
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Assets/Engine/SeedAssetList.seed
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Assets/Engine
+    )
+
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/DummyProject/AssetProcessorGamePlatformConfig.setreg
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/DummyProject/project.json
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/DummyProject/SeedAssetList.seed
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/DummyProject/SeedAssetListObjectStreamXML.seed
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/DummyProject
+    )
+
+     ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemA/AssetProcessorGemConfig.setreg
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemA/gem.json
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemA
+    )
+
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemA/Assets/seedList.seed
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemA/Assets
+    )
+
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemB/gem.json
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemB
+    )
+
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemB/Assets/seedList.seed
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemB/Assets
+    )
+
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemB/Assets/Platforms/GemBSharedAssetList.seed
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemB/Assets/Platforms/randomfile.txt
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemB/Assets/Platforms
+    )
+
+    ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemB/Assets/Platforms/ios/AssetSeedList.seed
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemB/Assets/Platforms/ios
+    )
+
+     ly_add_target_files(
+        TARGETS
+            AssetBundler.Tests
+        FILES
+            ${CMAKE_CURRENT_SOURCE_DIR}/tests/Gems/GemC/gem.json
+        OUTPUT_SUBDIRECTORY
+            AssetBundler.Tests.dir/Gems/GemC
+    )
+
 endif()

+ 14 - 13
Code/Tools/AssetBundler/source/ui/AssetBundlerTabWidget.cpp

@@ -13,7 +13,6 @@
 
 #include <AzCore/Utils/Utils.h>
 #include <AzFramework/IO/LocalFileIO.h>
-#include <AzFramework/StringFunc/StringFunc.h>
 #include <AzQtComponents/Utilities/DesktopUtilities.h>
 
 #include <QApplication>
@@ -28,8 +27,8 @@
 
 namespace AssetBundler
 {
-    const char AssetBundlerCommonSettingsFile[] = "AssetBundlerCommonSettings.json";
-    const char AssetBundlerUserSettingsFile[] = "AssetBundlerUserSettings.json";
+    constexpr AZ::IO::PathView AssetBundlerCommonSettingsFile = "AssetBundlerCommonSettings.json";
+    constexpr AZ::IO::PathView AssetBundlerUserSettingsFile = "AssetBundlerUserSettings.json";
 
     const char ScanPathsKey[] = "ScanPaths";
 
@@ -188,7 +187,7 @@ namespace AssetBundler
 
     void AssetBundlerTabWidget::AddScanPathToAssetBundlerSettings(AssetBundlingFileType fileType, AZStd::string filePath)
     {
-        AZStd::string defaultFolderPath;
+        AZ::IO::Path defaultFolderPath;
         switch (fileType)
         {
         case AssetBundlingFileType::SeedListFileType:
@@ -212,10 +211,10 @@ namespace AssetBundler
             break;
         }
 
-        AzFramework::StringFunc::Path::Normalize(filePath);
-        AzFramework::StringFunc::Path::Normalize(defaultFolderPath);
+        auto normalizedFilePath = AZ::IO::PathView(filePath).LexicallyNormal();
+        defaultFolderPath = defaultFolderPath.LexicallyNormal();
 
-        if (AzFramework::StringFunc::StartsWith(filePath, defaultFolderPath))
+        if (normalizedFilePath.IsRelativeTo(defaultFolderPath))
         {
             // file is already in a watched folder, no need to add it to the settings file
             return;
@@ -342,16 +341,18 @@ namespace AssetBundler
 
     AZStd::string AssetBundlerTabWidget::GetAssetBundlerUserSettingsFile(const char* currentProjectFolderPath)
     {
-        AZStd::string absoluteFilePath;
-        AzFramework::StringFunc::Path::ConstructFull(currentProjectFolderPath, AssetBundlerUserSettingsFile, absoluteFilePath);
-        return absoluteFilePath;
+        AZ::IO::Path absoluteFilePath = AZ::IO::Path(currentProjectFolderPath)
+            / AZ::SettingsRegistryInterface::DevUserRegistryFolder
+            / AssetBundlerUserSettingsFile;
+        return absoluteFilePath.Native();
     }
 
     AZStd::string AssetBundlerTabWidget::GetAssetBundlerCommonSettingsFile(const char* currentProjectFolderPath)
     {
-        AZStd::string absoluteFilePath;
-        AzFramework::StringFunc::Path::ConstructFull(currentProjectFolderPath, AssetBundlerCommonSettingsFile, absoluteFilePath);
-        return absoluteFilePath;
+        AZ::IO::Path absoluteFilePath = AZ::IO::Path(currentProjectFolderPath)
+            / AZ::SettingsRegistryInterface::RegistryFolder
+            / AssetBundlerCommonSettingsFile;
+        return absoluteFilePath.Native();
     }
 
     void AssetBundlerTabWidget::CreateEmptyAssetBundlerSettings(const AZStd::string& filePath)

+ 7 - 4
Code/Tools/AssetBundler/tests/DummyProject/SeedAssetList.seed

@@ -1,4 +1,7 @@
-<ObjectStream version="3">
-	<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}"/>
-</ObjectStream>
-
+{
+    "Type": "JsonSerialization",
+    "Version": 1,
+    "ClassName": "AZStd::vector<SeedInfo, allocator>",
+    "ClassData": [
+    ]
+}

+ 4 - 0
Code/Tools/AssetBundler/tests/DummyProject/SeedAssetListObjectStreamXML.seed

@@ -0,0 +1,4 @@
+<ObjectStream version="3">
+	<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}"/>
+</ObjectStream>
+

+ 8 - 9
Code/Tools/AssetBundler/tests/applicationManagerTests.cpp

@@ -49,7 +49,7 @@ namespace AssetBundler
         : public UnitTest::LeakDetectionFixture
     {
     public:
-        
+
         void SetUp() override
         {
             UnitTest::LeakDetectionFixture::SetUp();
@@ -67,8 +67,7 @@ namespace AssetBundler
             }
             auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
                 + "/project_path";
-            AZ::IO::FixedMaxPath enginePath;
-            registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
+            AZ::IO::FixedMaxPath enginePath = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*registry);
             registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
             AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
 
@@ -81,17 +80,17 @@ namespace AssetBundler
             m_data->m_applicationManager->Start(AzFramework::Application::Descriptor(), startupParameters);
 
             // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
-            // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash 
+            // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
             // in the unit tests.
             AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
 
-            AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
-            ASSERT_TRUE(!engineRoot.empty()) << "Unable to locate engine root.\n";
-            m_data->m_testEngineRoot = (engineRoot / RelativeTestFolder).String();
+            AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
+            ASSERT_TRUE(!executableDirectory.empty()) << "Unable to locate engine root.\n";
+            m_data->m_testEngineRoot = (executableDirectory / RelativeTestFolder).String();
 
             m_data->m_localFileIO = aznew AZ::IO::LocalFileIO();
             m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
-            // we need to set it to nullptr first because otherwise the 
+            // we need to set it to nullptr first because otherwise the
             // underneath code assumes that we might be leaking the previous instance
             AZ::IO::FileIOBase::SetInstance(nullptr);
             AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO);
@@ -139,7 +138,7 @@ namespace AssetBundler
             // Add the gem to the list of active gems
             AZ::Test::AddActiveGem(gemName, * settingsRegistry);
 
-            // Set the Gem path underneat the o3de Manifest section of the SettingsRegistry
+            // Set the Gem path underneath the o3de Manifest section of the SettingsRegistry
             auto gemSourcePathKey = FixedValueString::format("%s/%s/Path",
                 AZ::SettingsRegistryMergeUtils::ManifestGemsRootKey, gemName.c_str());
             auto gemSourcePath = AZ::IO::Path(m_data->m_testEngineRoot) / "Gems" / gemName;

+ 26 - 25
Code/Tools/AssetBundler/tests/tests_main.cpp

@@ -9,7 +9,6 @@
 #include <AzFramework/API/ApplicationAPI.h>
 #include <AzFramework/FileFunc/FileFunc.h>
 #include <AzFramework/IO/LocalFileIO.h>
-#include <AzFramework/StringFunc/StringFunc.h>
 #include <AzToolsFramework/Application/ToolsApplication.h>
 #include <AzToolsFramework/Asset/AssetBundler.h>
 #include <AzFramework/Platform/PlatformDefaults.h>
@@ -83,7 +82,7 @@ namespace AssetBundler
         ASSERT_EQ(platformIdentifier, "pc");
     }
 
-    const char RelativeTestFolder[] = "Code/Tools/AssetBundler/tests";
+    const char RelativeTestFolder[] = "AssetBundler.Tests.dir";
     const char GemsFolder[] = "Gems";
     constexpr auto EngineFolder = AZ::IO::FixedMaxPath("Assets") / "Engine";
     const char PlatformsFolder[] = "Platforms";
@@ -94,7 +93,7 @@ namespace AssetBundler
     {
     public:
         void SetUp() override
-        {          
+        {
             AZ::SettingsRegistryInterface* registry = nullptr;
             if (!AZ::SettingsRegistry::Get())
             {
@@ -107,15 +106,14 @@ namespace AssetBundler
             }
             auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
                 + "/project_path";
-            AZ::IO::FixedMaxPath enginePath;
-            registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
+            AZ::IO::FixedMaxPath enginePath = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*registry);
             registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
             AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
 
-            AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
-            if (engineRoot.empty())
+            AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
+            if (executableDirectory.empty())
             {
-                GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to locate engine root.\n").c_str());
+                GTEST_FATAL_FAILURE_(AZStd::string::format("Unable to locate executable.\n").c_str());
             }
 
             m_data = AZStd::make_unique<StaticData>();
@@ -123,15 +121,16 @@ namespace AssetBundler
             m_data->m_application.get()->Start(AzFramework::Application::Descriptor());
 
             // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
-            // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash 
+            // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
             // in the unit tests.
             AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
 
-            m_data->m_testEngineRoot = (engineRoot / RelativeTestFolder).LexicallyNormal().String();
+            // Set the test engine root to be the executable directory
+            m_data->m_testEngineRoot = (executableDirectory / RelativeTestFolder).LexicallyNormal().String();
 
             m_data->m_localFileIO = aznew AZ::IO::LocalFileIO();
             m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
-            // we need to set it to nullptr first because otherwise the 
+            // we need to set it to nullptr first because otherwise the
             // underneath code assumes that we might be leaking the previous instance
             AZ::IO::FileIOBase::SetInstance(nullptr);
             AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO);
@@ -141,13 +140,19 @@ namespace AssetBundler
 
             auto absoluteEngineSeedFilePath = m_data->m_testEngineRoot / EngineFolder / "SeedAssetList";
             absoluteEngineSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension());
-            m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(absoluteEngineSeedFilePath, true));
+            m_data->m_gemSeedFilePairList.push_back({ absoluteEngineSeedFilePath.Native(), true});
 
             AddGemData(m_data->m_testEngineRoot.c_str(), "GemC", false);
 
-            AZStd::string absoluteProjectSeedFilePath;
-            AzFramework::StringFunc::Path::ConstructFull(m_data->m_testEngineRoot.c_str(), DummyProjectFolder, "SeedAssetList", AzToolsFramework::AssetSeedManager::GetSeedFileExtension(), absoluteProjectSeedFilePath, true);
-            m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(absoluteProjectSeedFilePath, true));
+
+            auto absoluteProjectJsonSeedFilePath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder / "SeedAssetList";
+            absoluteProjectJsonSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension());
+            m_data->m_gemSeedFilePairList.push_back({ absoluteProjectJsonSeedFilePath.Native(), true });
+
+            // Add an explicit ObjectStream format XML seed file to validate that it loads successfully
+            auto absoluteProjectObjectStreamSeedFilePath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder / "SeedAssetListObjectStreamXML";
+            absoluteProjectObjectStreamSeedFilePath.ReplaceExtension(AzToolsFramework::AssetSeedManager::GetSeedFileExtension());
+            m_data->m_gemSeedFilePairList.push_back({ absoluteProjectObjectStreamSeedFilePath.Native(), true });
         }
         void TearDown() override
         {
@@ -196,9 +201,7 @@ namespace AssetBundler
                     AZStd::string::format("*.%s", AzToolsFramework::AssetSeedManager::GetSeedFileExtension()).c_str(),
                     [&](const char* fileName)
                 {
-                    AZStd::string normalizedFilePath = fileName;
-                    AzFramework::StringFunc::Path::Normalize(normalizedFilePath);
-                    m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(normalizedFilePath, seedFileExists));
+                    m_data->m_gemSeedFilePairList.push_back({ AZ::IO::PathView(fileName).LexicallyNormal().String(), seedFileExists });
                     return true;
                 });
             }
@@ -215,9 +218,7 @@ namespace AssetBundler
                     AZStd::list<AZStd::string> seedFiles = result.TakeValue();
                     for (AZStd::string& seedFile : seedFiles)
                     {
-                        AZStd::string normalizedFilePath = seedFile;
-                        AzFramework::StringFunc::Path::Normalize(normalizedFilePath);
-                        m_data->m_gemSeedFilePairList.emplace_back(AZStd::make_pair(normalizedFilePath, seedFileExists));
+                        m_data->m_gemSeedFilePairList.push_back({ AZ::IO::PathView(seedFile).LexicallyNormal().String(), seedFileExists });
                     }
                 }
             }
@@ -249,10 +250,10 @@ namespace AssetBundler
     {
         // DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/
         auto dummyProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder;
-        auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC);
+        auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.Native(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC);
         ASSERT_EQ(defaultSeedList.size(), 5); //adding one for the engine seed file and one for the project file
 
-        // Validate whether both GemA and GemB seed file are present  
+        // Validate whether both GemA and GemB seed file are present
         EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemAIndex].first), defaultSeedList.end());
         EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIndex].first), defaultSeedList.end());
         EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBSharedFileIndex].first), defaultSeedList.end());
@@ -266,11 +267,11 @@ namespace AssetBundler
     {
         // DummyProject and fake Engine/Gem structure lives at dev/Code/Tools/AssetBundler/tests/
         auto dummyProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectFolder;
-        auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.c_str(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS);
+        auto defaultSeedList = AssetBundler::GetDefaultSeedListFiles(m_data->m_testEngineRoot.Native(), dummyProjectPath.Native(), m_data->m_gemInfoList, AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_IOS);
         ASSERT_EQ(defaultSeedList.size(), 6); //adding one for the engine seed file and one for the project file
 
 
-        // Validate whether both GemA and GemB seed file are present  
+        // Validate whether both GemA and GemB seed file are present
         EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemAIndex].first), defaultSeedList.end());
         EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBIndex].first), defaultSeedList.end());
         EXPECT_NE(defaultSeedList.find(m_data->m_gemSeedFilePairList[GemBSharedFileIndex].first), defaultSeedList.end());

+ 34 - 16
Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp

@@ -35,7 +35,7 @@ namespace AssetProcessor
         builderDesc.m_busId = m_builderId;
         builderDesc.m_createJobFunction = AZStd::bind(&SettingsRegistryBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
         builderDesc.m_processJobFunction = AZStd::bind(&SettingsRegistryBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
-        builderDesc.m_version = 1;
+        builderDesc.m_version = 2;
 
         AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDesc);
 
@@ -129,7 +129,7 @@ namespace AssetProcessor
         response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
 
         AZStd::vector<AZStd::string> excludes = ReadExcludesFromRegistry();
-        // Exclude the AssetProcessor settings from the game regsitry
+        // Exclude the AssetProcessor settings from the game registry
         excludes.emplace_back(AssetProcessor::AssetProcessorSettingsKey);
 
         AZStd::vector<char> scratchBuffer;
@@ -138,7 +138,7 @@ namespace AssetProcessor
         AzFramework::PlatformHelper::AppendPlatformCodeNames(platformCodes, request.m_platformInfo.m_identifier);
         AZ_Assert(platformCodes.size() <= 1, "A one-to-one mapping of asset type platform identifier"
             " to platform codename is required in the SettingsRegistryBuilder."
-            " The bootstrap.game is now only produced per build configuration and doesn't take into account"
+            " The bootstrap.<launcher-type>.<config>.setreg is now only produced per launcher type + build configuration and doesn't take into account"
             " different platforms names");
 
         const AZStd::string& assetPlatformIdentifier = request.m_jobDescription.GetPlatformIdentifier();
@@ -146,18 +146,24 @@ namespace AssetProcessor
         const char* launcherType = assetPlatformIdentifier != AzFramework::PlatformHelper::GetPlatformName(AzFramework::PlatformId::SERVER)
             ? "_GameLauncher" : "_ServerLauncher";
 
-        AZ::SettingsRegistryInterface::Specializations specializations[] =
+        AZ::SettingsRegistryInterface::FilenameTags specializations[] =
         {
-            { AZStd::string_view{"release"}, AZStd::string_view{"game"} },
-            { AZStd::string_view{"profile"}, AZStd::string_view{"game"} },
-            { AZStd::string_view{"debug"}, AZStd::string_view{"game"} }
+            { AZStd::string_view{"client"}, AZStd::string_view{"release"} },
+            { AZStd::string_view{"client"} , AZStd::string_view{"profile"} },
+            { AZStd::string_view{"client"}, AZStd::string_view{"debug"} },
+            { AZStd::string_view{"server"}, AZStd::string_view{"release"} },
+            { AZStd::string_view{"server"} , AZStd::string_view{"profile"} },
+            { AZStd::string_view{"server"}, AZStd::string_view{"debug"} },
+            { AZStd::string_view{"unified"}, AZStd::string_view{"release"} },
+            { AZStd::string_view{"unified"} , AZStd::string_view{"profile"} },
+            { AZStd::string_view{"unified"}, AZStd::string_view{"debug"} }
         };
 
         // Add the project specific specializations
         auto projectName = AZ::Utils::GetProjectName();
         if (!projectName.empty())
         {
-            for (AZ::SettingsRegistryInterface::Specializations& specialization : specializations)
+            for (AZ::SettingsRegistryInterface::FilenameTags& specialization : specializations)
             {
                 specialization.Append(projectName);
                 // The Game Launcher normally has a build target name of <ProjectName>Launcher
@@ -167,7 +173,7 @@ namespace AssetProcessor
             }
         }
 
-        AZ::IO::Path outputPath = AZ::IO::Path(request.m_tempDirPath) / "bootstrap.game.";
+        AZ::IO::Path outputPath = AZ::IO::Path(request.m_tempDirPath) / "bootstrap.";
         size_t extensionOffset = outputPath.Native().size();
 
         if (!platformCodes.empty())
@@ -189,7 +195,7 @@ namespace AssetProcessor
             AZStd::string_view platform = platformCodes.front();
             for (size_t i = 0; i < AZStd::size(specializations); ++i)
             {
-                const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i];
+                const AZ::SettingsRegistryInterface::FilenameTags& specialization = specializations[i];
                 if (m_isShuttingDown)
                 {
                     response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
@@ -225,7 +231,7 @@ namespace AssetProcessor
                     // to a local SettingsRegistry.
                     // The reason this is needed is so that the call to
                     // `MergeSettingsToRegistry_GemRegistries` below is able to locate each gems root directory
-                    // that will be merged into the bootstrap.game.<configuration>.setreg file
+                    // that will be merged into the bootstrap.<launcher-type>.<configuration>.setreg file
                     // This is used by the GameLauncher applications to read from a single merged .setreg file
                     // containing the settings needed to run a game/simulation without have access to the source code base registry
                     auto CopySettingsToLocalRegistry = [&registry, settingsRegistry, copiedSettings = AZStd::string()]
@@ -253,10 +259,12 @@ namespace AssetProcessor
                 if (auto& operationMessages = mergeResult.GetMessages();
                     !operationMessages.empty())
                 {
-                    AZStd::string_view buildConfiguration(specialization.GetSpecialization(0));
-                    AZ_Info("Settings Registry Builder", R"(Configuration: "%.*s")" "\n"
+                    AZStd::string_view launcherString = specialization.GetSpecialization(0);
+                    AZStd::string_view buildConfiguration = specialization.GetSpecialization(1);
+                    AZ_Info("Settings Registry Builder", R"(Launcher Type: "%.*s", Build configuration: "%.*s")" "\n"
                         "Merging the Engine, Gem, Project Registry directories resulted in the following messages:\n%s\n",
-                        AZ_STRING_ARG(buildConfiguration), operationMessages.c_str());
+                        AZ_STRING_ARG(launcherString), AZ_STRING_ARG(buildConfiguration),
+                         operationMessages.c_str());
                 }
 
                 // The Gem Root Key and Manifest Gems Root is removed now that each gems "<gem-root>/Registry" directory
@@ -279,6 +287,9 @@ namespace AssetProcessor
                     AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(registry, "", outputStream, dumperSettings))
                 {
                     AZStd::string_view specializationString(specialization.GetSpecialization(0));
+                    outputPath.Native() += specializationString; // Append launcher type (client, server, or unified)
+                    specializationString = specialization.GetSpecialization(1);
+                    outputPath.Native() += '.';
                     outputPath.Native() += specializationString; // Append configuration
                     outputPath.Native() += ".setreg";
 
@@ -296,11 +307,18 @@ namespace AssetProcessor
                     }
                     file.Close();
 
-                    const AZ::u32 hashedSpecialization = static_cast<AZ::u32>(AZStd::hash<AZStd::string_view>{}(specializationString));
+                    // Hash all specializations tags
+                    size_t hashedSpecialization{};
+                    for (size_t specIndex{}; specIndex < specialization.GetCount(); ++specIndex)
+                    {
+                        AZStd::hash_combine(hashedSpecialization, specialization.GetSpecialization(specIndex));
+                    }
                     AZ_Assert(hashedSpecialization != 0, "Product ID generation failed for specialization %.*s."
                         " This can result in a product ID collision with other builders for this asset.",
                         AZ_STRING_ARG(specializationString));
-                    response.m_outputProducts.emplace_back(outputPath.Native(), m_assetType, hashedSpecialization);
+
+                    auto setregSubId = static_cast<AZ::u32>(hashedSpecialization);
+                    response.m_outputProducts.emplace_back(outputPath.Native(), m_assetType, setregSubId);
                     response.m_outputProducts.back().m_dependenciesHandled = true;
 
                     outputPath.Native().erase(extensionOffset);

+ 3 - 3
Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp

@@ -461,7 +461,7 @@ namespace AtomToolsFramework
                     {
                         layoutSettingsMenu->addAction(
                             layoutName.c_str(),
-                            [this, layoutName, windowState]()
+                            [this, windowState]()
                             {
                                 m_advancedDockManager->restoreState(
                                     QByteArray(windowState.data(), aznumeric_cast<int>(windowState.size())));
@@ -483,7 +483,7 @@ namespace AtomToolsFramework
                         // Since these layouts were created and saved by the user, give them the option to restore and delete them.
                         layoutMenu->addAction(
                             tr("Load"),
-                            [this, layoutName, windowState]()
+                            [this, windowState]()
                             {
                                 m_advancedDockManager->restoreState(
                                     QByteArray(windowState.data(), aznumeric_cast<int>(windowState.size())));
@@ -556,7 +556,7 @@ namespace AtomToolsFramework
 
     void AtomToolsMainWindow::RestoreSavedLayout()
     {
-        // Attempt to restore the layout that was saved the last time the application was closed. 
+        // Attempt to restore the layout that was saved the last time the application was closed.
         const AZStd::string windowState = GetSettingsObject("/O3DE/AtomToolsFramework/MainWindow/WindowState", AZStd::string());
         if (!windowState.empty())
         {

+ 4 - 1
cmake/Tools/layout_tool.py

@@ -366,7 +366,10 @@ def sync_layout_vfs(target_platform, project_path, asset_type, warning_on_missin
     create_link(vfs_asset_source, temp_vfs_layout_project_config_path, copy)
 
     # Copy minimum assets to the layout necessary for vfs
-    root_assets = ['engine.json', 'bootstrap.game.debug.setreg', 'bootstrap.game.profile.setreg', 'bootstrap.game.release.setreg']
+    root_assets = ['engine.json',
+                   'bootstrap.client.debug.setreg', 'bootstrap.client.profile.setreg', 'bootstrap.client.release.setreg',
+                   'bootstrap.server.debug.setreg', 'bootstrap.server.profile.setreg', 'bootstrap.server.release.setreg',
+                   'bootstrap.unified.debug.setreg', 'bootstrap.unified.profile.setreg', 'bootstrap.unified.release.setreg']
     for root_asset in root_assets:
         logging.debug("Copying %s -> %s",  os.path.join(project_asset_folder, root_asset), layout_target)
         shutil.copy2(os.path.join(project_asset_folder, root_asset), layout_target)