Browse Source

Convert prefab to temp spawnable assets (#6179)

* Convert prefab to temp in-memory spawnable assets

Signed-off-by: chiyenteng <[email protected]>
chiyenteng 3 năm trước cách đây
mục cha
commit
ca49eedc5f
55 tập tin đã thay đổi với 752 bổ sung296 xóa
  1. 4 1
      AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_test_utils.py
  2. 0 1
      AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py
  3. 5 1
      AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py
  4. 9 3
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py
  5. 8 3
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py
  6. 6 3
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py
  7. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py
  8. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py
  9. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py
  10. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py
  11. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
  12. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py
  13. 8 8
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
  14. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py
  15. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py
  16. 4 4
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py
  17. 4 4
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py
  18. 4 4
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py
  19. 4 4
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py
  20. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py
  21. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py
  22. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py
  23. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py
  24. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py
  25. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py
  26. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py
  27. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py
  28. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py
  29. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py
  30. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py
  31. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py
  32. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py
  33. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py
  34. 4 4
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py
  35. 4 4
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py
  36. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py
  37. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py
  38. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py
  39. 21 16
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py
  40. 3 3
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py
  41. 40 4
      AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py
  42. 2 1
      Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h
  43. 38 159
      Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp
  44. 4 7
      Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h
  45. 30 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestBus.h
  46. 73 4
      Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.cpp
  47. 10 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.h
  48. 275 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.cpp
  49. 69 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h
  50. 20 0
      Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabConverterStackProfileNames.h
  51. 3 0
      Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake
  52. 27 21
      Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp
  53. 21 0
      Registry/prefab.test.setreg
  54. 8 2
      Tools/LyTestTools/ly_test_tools/o3de/editor_test.py
  55. 9 0
      Tools/LyTestTools/tests/unit/test_o3de_editor_test.py

+ 4 - 1
AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_test_utils.py

@@ -58,7 +58,10 @@ def launch_and_validate_results(request, test_directory, editor, editor_script,
     if null_renderer:
     if null_renderer:
         editor.args.extend(["-rhi=Null"])
         editor.args.extend(["-rhi=Null"])
     if enable_prefab_system:
     if enable_prefab_system:
-        editor.args.extend(["--regset=/Amazon/Preferences/EnablePrefabSystem=true"])
+        from os import path
+        editor.args.extend([
+            "--regset=/Amazon/Preferences/EnablePrefabSystem=true",
+            f"--regset-file={os.path.join(workspace.paths.engine_root(), 'Registry', 'prefab.test.setreg')}"])
     else:
     else:
         editor.args.extend(["--regset=/Amazon/Preferences/EnablePrefabSystem=false"])
         editor.args.extend(["--regset=/Amazon/Preferences/EnablePrefabSystem=false"])
 
 

+ 0 - 1
AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py

@@ -39,7 +39,6 @@ def get_prefab_file_path(prefab_path):
         prefab_path = name + ".prefab"
         prefab_path = name + ".prefab"
     return prefab_path
     return prefab_path
 
 
-
 def get_all_entity_ids():
 def get_all_entity_ids():
     return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
     return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
 
 

+ 5 - 1
AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py

@@ -12,6 +12,8 @@ import sys
 import pytest
 import pytest
 import time
 import time
 
 
+from os import path
+
 import ly_test_tools.environment.file_system as file_system
 import ly_test_tools.environment.file_system as file_system
 import ly_test_tools.environment.process_utils as process_utils
 import ly_test_tools.environment.process_utils as process_utils
 import ly_test_tools.environment.waiter as waiter
 import ly_test_tools.environment.waiter as waiter
@@ -98,7 +100,9 @@ class TestAutomationBase:
         if autotest_mode:
         if autotest_mode:
             pycmd += ["-autotest_mode"]
             pycmd += ["-autotest_mode"]
         if enable_prefab_system:
         if enable_prefab_system:
-            pycmd += ["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]
+            pycmd += [
+                "--regset=/Amazon/Preferences/EnablePrefabSystem=true",
+                f"--regset-file={path.join(workspace.paths.engine_root(), 'Registry', 'prefab.test.setreg')}"]
         else:
         else:
             pycmd += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
             pycmd += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
 
 

+ 9 - 3
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py

@@ -51,19 +51,22 @@ def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude():
 
 
     import os
     import os
 
 
+    import azlmbr.asset as asset
     import azlmbr.editor as editor
     import azlmbr.editor as editor
     import azlmbr.legacy.general as general
     import azlmbr.legacy.general as general
     import azlmbr.bus as bus
     import azlmbr.bus as bus
     import azlmbr.math as math
     import azlmbr.math as math
+    import azlmbr.prefab as prefab
 
 
     import editor_python_test_tools.hydra_editor_utils as hydra
     import editor_python_test_tools.hydra_editor_utils as hydra
+    from editor_python_test_tools.prefab_utils import Prefab
     from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
     from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
     from editor_python_test_tools.utils import Report
     from editor_python_test_tools.utils import Report
     from editor_python_test_tools.utils import TestHelper as helper
     from editor_python_test_tools.utils import TestHelper as helper
 
 
     # 1) Open an existing simple level
     # 1) Open an existing simple level
     helper.init_idle()
     helper.init_idle()
-    helper.open_level("Physics", "Base")
+    helper.open_level("", "Base")
 
 
     # Set view of planting area for visual debugging
     # Set view of planting area for visual debugging
     general.set_current_view_position(512.0, 500.0, 38.0)
     general.set_current_view_position(512.0, 500.0, 38.0)
@@ -71,8 +74,11 @@ def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude():
 
 
     # 2) Create a new entity with required vegetation area components
     # 2) Create a new entity with required vegetation area components
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
+
+    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "PinkFlower")[0]
+
+    spawner_entity = dynveg.create_prefab_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, flower_prefab)
 
 
     # Add a Vegetation Altitude Filter
     # Add a Vegetation Altitude Filter
     spawner_entity.add_component("Vegetation Altitude Filter")
     spawner_entity.add_component("Vegetation Altitude Filter")

+ 8 - 3
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py

@@ -32,7 +32,9 @@ def AltitudeFilter_FilterStageToggle():
     import os
     import os
 
 
     import azlmbr.legacy.general as general
     import azlmbr.legacy.general as general
+    import azlmbr.bus as bus
     import azlmbr.math as math
     import azlmbr.math as math
+    import azlmbr.prefab as prefab
 
 
     import editor_python_test_tools.hydra_editor_utils as hydra
     import editor_python_test_tools.hydra_editor_utils as hydra
     from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
     from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
@@ -44,13 +46,16 @@ def AltitudeFilter_FilterStageToggle():
 
 
     # Open an existing simple level
     # Open an existing simple level
     helper.init_idle()
     helper.init_idle()
-    helper.open_level("Physics", "Base")
+    helper.open_level("", "Base")
     general.set_current_view_position(512.0, 480.0, 38.0)
     general.set_current_view_position(512.0, 480.0, 38.0)
 
 
     # Create basic vegetation entity
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
     position = math.Vector3(512.0, 512.0, 32.0)
-    asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
+
+    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "PinkFlower")[0]
+
+    vegetation = dynveg.create_prefab_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, flower_prefab)
 
 
     # Add a Vegetation Altitude Filter to the vegetation area entity
     # Add a Vegetation Altitude Filter to the vegetation area entity
     vegetation.add_component("Vegetation Altitude Filter")
     vegetation.add_component("Vegetation Altitude Filter")

+ 6 - 3
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py

@@ -57,7 +57,7 @@ def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude():
 
 
     # 1) Open an existing simple level
     # 1) Open an existing simple level
     helper.init_idle()
     helper.init_idle()
-    helper.open_level("Physics", "Base")
+    helper.open_level("", "Base")
 
 
     # Set view of planting area for visual debugging
     # Set view of planting area for visual debugging
     general.set_current_view_position(512.0, 500.0, 38.0)
     general.set_current_view_position(512.0, 500.0, 38.0)
@@ -65,8 +65,11 @@ def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude():
 
 
     # 2) Create a new entity with required vegetation area components
     # 2) Create a new entity with required vegetation area components
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, asset_path)
+
+    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "PinkFlower")[0]
+
+    spawner_entity = dynveg.create_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, flower_prefab)
 
 
     # Add a Vegetation Altitude Filter
     # Add a Vegetation Altitude Filter
     spawner_entity.add_component("Vegetation Altitude Filter")
     spawner_entity.add_component("Vegetation Altitude Filter")

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py

@@ -111,7 +111,7 @@ def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea():
 
 
     # 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
     # 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
     # spawning empty assets
     # spawning empty assets
-    spawner_entity = dynveg.create_vegetation_area("Spawner Entity", center_point, 16.0, 16.0, 16.0, None)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", center_point, 16.0, 16.0, 16.0, None)
     spawner_entity.remove_component("Vegetation Asset List")
     spawner_entity.remove_component("Vegetation Asset List")
     spawner_entity.add_component("Vegetation Asset List Combiner")
     spawner_entity.add_component("Vegetation Asset List Combiner")
     spawner_entity.add_component("Vegetation Asset Weight Selector")
     spawner_entity.add_component("Vegetation Asset Weight Selector")

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py

@@ -67,8 +67,8 @@ def AssetWeightSelector_InstancesExpressBasedOnWeight():
     # valid slice entity, and one set to None
     # valid slice entity, and one set to None
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+                                                                               asset_path)
     desc_asset = hydra.get_component_property_value(spawner_entity.components[2],
     desc_asset = hydra.get_component_property_value(spawner_entity.components[2],
                                                     "Configuration|Embedded Assets")[0]
                                                     "Configuration|Embedded Assets")[0]
     desc_list = [desc_asset, desc_asset]
     desc_list = [desc_asset, desc_asset]

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py

@@ -72,8 +72,8 @@ def DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius():
     # 2) Create a new entity with required vegetation area components
     # 2) Create a new entity with required vegetation area components
     spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
     spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
     asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
     asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+                                                                               asset_path)
 
 
     # 3) Create a surface to plant on
     # 3) Create a surface to plant on
     surface_center_point = math.Vector3(512.0, 512.0, 32.0)
     surface_center_point = math.Vector3(512.0, 512.0, 32.0)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py

@@ -70,8 +70,8 @@ def DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius():
     # 2) Create a new entity with required vegetation area components
     # 2) Create a new entity with required vegetation area components
     spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
     spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
     asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
     asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+                                                                               asset_path)
 
 
     # 3) Create a surface to plant on
     # 3) Create a surface to plant on
     surface_center_point = math.Vector3(512.0, 512.0, 32.0)
     surface_center_point = math.Vector3(512.0, 512.0, 32.0)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py

@@ -80,7 +80,7 @@ def DynamicSliceInstanceSpawner_Embedded_E2E():
     # 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
     # 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path)
     spawner_entity.add_component("Script Canvas")
     spawner_entity.add_component("Script Canvas")
     instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
     instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
     instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
     instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py

@@ -70,8 +70,8 @@ def InstanceSpawnerPriority_LayerAndSubPriority():
     # 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
     # 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
     spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
     spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
+                                                                               asset_path)
     blocker_center_point = math.Vector3(516.0, 516.0, 32.0)
     blocker_center_point = math.Vector3(516.0, 516.0, 32.0)
     blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
     blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
 
 

+ 8 - 8
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py

@@ -86,17 +86,17 @@ def LayerBlender_E2E_Editor():
     # 2) Create 2 vegetation areas with different meshes
     # 2) Create 2 vegetation areas with different meshes
     purple_position = math.Vector3(504.0, 512.0, 32.0)
     purple_position = math.Vector3(504.0, 512.0, 32.0)
     purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity_1 = dynveg.create_vegetation_area("Purple Spawner",
-                                                     purple_position,
-                                                     16.0, 16.0, 1.0,
-                                                     purple_asset_path)
+    spawner_entity_1 = dynveg.create_dynamic_slice_vegetation_area("Purple Spawner",
+                                                                                 purple_position,
+                                                                                 16.0, 16.0, 1.0,
+                                                                                 purple_asset_path)
 
 
     pink_position = math.Vector3(520.0, 512.0, 32.0)
     pink_position = math.Vector3(520.0, 512.0, 32.0)
     pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity_2 = dynveg.create_vegetation_area("Pink Spawner",
-                                                     pink_position,
-                                                     16.0, 16.0, 1.0,
-                                                     pink_asset_path)
+    spawner_entity_2 = dynveg.create_dynamic_slice_vegetation_area("Pink Spawner",
+                                                                                 pink_position,
+                                                                                 16.0, 16.0, 1.0,
+                                                                                 pink_asset_path)
 
 
     base_position = math.Vector3(512.0, 512.0, 32.0)
     base_position = math.Vector3(512.0, 512.0, 32.0)
     dynveg.create_surface_entity("Surface Entity",
     dynveg.create_surface_entity("Surface Entity",

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py

@@ -68,8 +68,8 @@ def LayerBlocker_InstancesBlockedInConfiguredArea():
     # 2) Create a new instance spawner entity
     # 2) Create a new instance spawner entity
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+                                                                               asset_path)
 
 
     # 3) Create surface for planting on
     # 3) Create surface for planting on
     dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
     dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py

@@ -51,7 +51,7 @@ def LayerSpawner_FilterStageToggle():
     # Create a vegetation area with all needed components
     # Create a vegetation area with all needed components
     position = math.Vector3(512.0, 512.0, 32.0)
     position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
+    vegetation_entity = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
     vegetation_entity.add_component("Vegetation Altitude Filter")
     vegetation_entity.add_component("Vegetation Altitude Filter")
     vegetation_entity.add_component("Vegetation Position Modifier")
     vegetation_entity.add_component("Vegetation Position Modifier")
 
 

+ 4 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py

@@ -62,10 +62,10 @@ def LayerSpawner_InstancesPlantInAllSupportedShapes():
     # 2) Create basic vegetation area entity and set the properties
     # 2) Create basic vegetation area entity and set the properties
     entity_position = math.Vector3(125.0, 136.0, 32.0)
     entity_position = math.Vector3(125.0, 136.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    vegetation = dynveg.create_vegetation_area("Instance Spawner",
-                                               entity_position,
-                                               10.0, 10.0, 10.0,
-                                               asset_path)
+    vegetation = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner",
+                                                                           entity_position,
+                                                                           10.0, 10.0, 10.0,
+                                                                           asset_path)
     vegetation.remove_component("Box Shape")
     vegetation.remove_component("Box Shape")
     vegetation.add_component("Shape Reference")
     vegetation.add_component("Shape Reference")
 
 

+ 4 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py

@@ -101,10 +101,10 @@ def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera():
 
 
     # Create the two vegetation areas
     # Create the two vegetation areas
     test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    first_veg_entity = dynveg.create_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
-                                                     box_size, test_slice_asset_path)
-    second_veg_entity = dynveg.create_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size,
-                                                      box_size, test_slice_asset_path)
+    first_veg_entity = dynveg.create_dynamic_slice_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
+                                                                                 box_size, test_slice_asset_path)
+    second_veg_entity = dynveg.create_dynamic_slice_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size,
+                                                                                  box_size, test_slice_asset_path)
 
 
     # When the first viewport is active, the first area should be full of instances, and the second should be empty
     # When the first viewport is active, the first area should be full of instances, and the second should be empty
     general.set_active_viewport(0)
     general.set_active_viewport(0)

+ 4 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py

@@ -59,10 +59,10 @@ def MeshBlocker_InstancesBlockedByMesh():
     # Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     # Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
-                                                   entity_position,
-                                                   10.0, 10.0, 10.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner",
+                                                                               entity_position,
+                                                                               10.0, 10.0, 10.0,
+                                                                               asset_path)
 
 
     # Create surface entity to plant on
     # Create surface entity to plant on
     dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
     dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)

+ 4 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py

@@ -62,10 +62,10 @@ def MeshBlocker_InstancesBlockedByMeshHeightTuning():
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
-                                                   entity_position,
-                                                   10.0, 10.0, 10.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner",
+                                                                               entity_position,
+                                                                               10.0, 10.0, 10.0,
+                                                                               asset_path)
 
 
     # 3) Create surface entity to plant on
     # 3) Create surface entity to plant on
     dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
     dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py

@@ -91,7 +91,7 @@ def PhysXColliderSurfaceTagEmitter_E2E_Editor():
 
 
     # Create a new entity with required vegetation area components
     # Create a new entity with required vegetation area components
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path)
 
 
     # Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag
     # Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag
     spawner_entity.add_component("Vegetation Surface Mask Filter")
     spawner_entity.add_component("Vegetation Surface Mask Filter")

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py

@@ -74,8 +74,8 @@ def PositionModifier_AutoSnapToSurfaceWorks():
     # 2) Create a new entity with required vegetation area components and a Position Modifier
     # 2) Create a new entity with required vegetation area components and a Position Modifier
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+                                                                               asset_path)
 
 
     # Add a Vegetation Position Modifier and set offset values to 0
     # Add a Vegetation Position Modifier and set offset values to 0
     spawner_entity.add_component("Vegetation Position Modifier")
     spawner_entity.add_component("Vegetation Position Modifier")

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py

@@ -111,7 +111,7 @@ def PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets():
     # 2) Create a new entity with required vegetation area components
     # 2) Create a new entity with required vegetation area components
     spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
     spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path)
 
 
     # Add a Vegetation Position Modifier and set offset values to 0
     # Add a Vegetation Position Modifier and set offset values to 0
     spawner_entity.add_component("Vegetation Position Modifier")
     spawner_entity.add_component("Vegetation Position Modifier")

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py

@@ -88,7 +88,7 @@ def RotationModifierOverrides_InstancesRotateWithinRange():
     # 2) Create vegetation entity and add components
     # 2) Create vegetation entity and add components
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path)
     spawner_entity.add_component("Vegetation Rotation Modifier")
     spawner_entity.add_component("Vegetation Rotation Modifier")
     # Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
     # Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
     num_expected = 20 * 20
     num_expected = 20 * 20

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py

@@ -126,7 +126,7 @@ def RotationModifier_InstancesRotateWithinRange():
 
 
     # 2) Set up vegetation entities
     # 2) Set up vegetation entities
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path)
 
 
     additional_components = [
     additional_components = [
         "Vegetation Rotation Modifier"
         "Vegetation Rotation Modifier"

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py

@@ -100,7 +100,7 @@ def ScaleModifierOverrides_InstancesProperlyScale():
     # 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     # 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path)
 
 
     # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
     # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
     dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
     dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py

@@ -94,8 +94,8 @@ def ScaleModifier_InstancesProperlyScale():
     # Vegetation Scale Modifier
     # Vegetation Scale Modifier
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0,
+                                                                               asset_path)
     spawner_entity.add_component("Vegetation Scale Modifier")
     spawner_entity.add_component("Vegetation Scale Modifier")
 
 
     # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
     # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py

@@ -57,7 +57,7 @@ def ShapeIntersectionFilter_FilterStageToggle():
     # Create basic vegetation entity
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
     position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
+    vegetation = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
 
 
     # Create Surface for instances to plant on
     # Create Surface for instances to plant on
     dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
     dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py

@@ -70,8 +70,8 @@ def ShapeIntersectionFilter_InstancesPlantInAssignedShape():
     # 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
     # 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
+                                                                               asset_path)
     spawner_entity.add_component("Vegetation Shape Intersection Filter")
     spawner_entity.add_component("Vegetation Shape Intersection Filter")
 
 
     # Create a planting surface
     # Create a planting surface

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py

@@ -66,7 +66,7 @@ def SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment():
     # Create a spawner entity setup with all needed components
     # Create a spawner entity setup with all needed components
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
 
 
     # Create a sloped mesh surface for the instances to plant on
     # Create a sloped mesh surface for the instances to plant on
     center_point = math.Vector3(502.0, 512.0, 24.0)
     center_point = math.Vector3(502.0, 512.0, 24.0)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py

@@ -67,7 +67,7 @@ def SlopeAlignmentModifier_InstanceSurfaceAlignment():
     # Create a spawner entity setup with all needed components
     # Create a spawner entity setup with all needed components
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
 
 
     # Create a sloped mesh surface for the instances to plant on
     # Create a sloped mesh surface for the instances to plant on
     center_point = math.Vector3(502.0, 512.0, 24.0)
     center_point = math.Vector3(502.0, 512.0, 24.0)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py

@@ -72,7 +72,7 @@ def SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes():
     # 2) Create a new entity with required vegetation area components
     # 2) Create a new entity with required vegetation area components
     center_point = math.Vector3(512.0, 512.0, 32.0)
     center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
 
 
     # Add a Vegetation Slope Filter
     # Add a Vegetation Slope Filter
     spawner_entity.add_component("Vegetation Slope Filter")
     spawner_entity.add_component("Vegetation Slope Filter")

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py

@@ -66,7 +66,7 @@ def SpawnerSlices_SliceCreationAndVisibilityToggleWorks():
     # 2.1) Create basic vegetation entity
     # 2.1) Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
     position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    veg_1 = dynveg.create_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path)
+    veg_1 = dynveg.create_dynamic_slice_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path)
 
 
     # 2.2) Create slice from the entity
     # 2.2) Create slice from the entity
     slice_path = os.path.join("slices", "TestSlice_1.slice")
     slice_path = os.path.join("slices", "TestSlice_1.slice")
@@ -94,7 +94,7 @@ def SpawnerSlices_SliceCreationAndVisibilityToggleWorks():
 
 
     # 4) C2627905 A slice containing the Vegetation Layer Blender component can be created.
     # 4) C2627905 A slice containing the Vegetation Layer Blender component can be created.
     # 4.1) Create another vegetation entity to add to blender component
     # 4.1) Create another vegetation entity to add to blender component
-    veg_2 = dynveg.create_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "")
+    veg_2 = dynveg.create_dynamic_slice_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "")
 
 
     # 4.2) Create entity with Vegetation Layer Blender
     # 4.2) Create entity with Vegetation Layer Blender
     components_to_add = ["Box Shape", "Vegetation Layer Blender"]
     components_to_add = ["Box Shape", "Vegetation Layer Blender"]

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py

@@ -77,8 +77,8 @@ def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected():
     # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors
     # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+                                                                               asset_path)
     asset_list_component = spawner_entity.components[2]
     asset_list_component = spawner_entity.components[2]
     desc_asset = hydra.get_component_property_value(asset_list_component,
     desc_asset = hydra.get_component_property_value(asset_list_component,
                                                     "Configuration|Embedded Assets")[0]
                                                     "Configuration|Embedded Assets")[0]

+ 4 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py

@@ -99,10 +99,10 @@ def SurfaceMaskFilter_ExclusionList():
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
-                                                   entity_position,
-                                                   10.0, 10.0, 10.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner",
+                                                                               entity_position,
+                                                                               10.0, 10.0, 10.0,
+                                                                               asset_path)
 
 
     # 3) Add a Vegetation Surface Mask Filter component to the entity.
     # 3) Add a Vegetation Surface Mask Filter component to the entity.
     spawner_entity.add_component("Vegetation Surface Mask Filter")
     spawner_entity.add_component("Vegetation Surface Mask Filter")

+ 4 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py

@@ -100,10 +100,10 @@ def SurfaceMaskFilter_InclusionList():
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     entity_position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
-                                                   entity_position,
-                                                   10.0, 10.0, 10.0,
-                                                   asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner",
+                                                                               entity_position,
+                                                                               10.0, 10.0, 10.0,
+                                                                               asset_path)
 
 
     # 3) Add a Vegetation Surface Mask Filter component to the entity.
     # 3) Add a Vegetation Surface Mask Filter component to the entity.
     spawner_entity.add_component("Vegetation Surface Mask Filter")
     spawner_entity.add_component("Vegetation Surface Mask Filter")

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py

@@ -55,7 +55,7 @@ def SystemSettings_SectorPointDensity():
     # Create basic vegetation entity
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
     position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
+    dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
     dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
     dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
 
 
     # Count the number of vegetation instances in the vegetation area
     # Count the number of vegetation instances in the vegetation area

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py

@@ -51,7 +51,7 @@ def SystemSettings_SectorSize():
     # Create basic vegetation entity
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
     position = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
-    vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
+    vegetation = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
     dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
     dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
 
 
     # Add the Vegetation Debugger component to the Level Inspector
     # Add the Vegetation Debugger component to the Level Inspector

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py

@@ -54,7 +54,7 @@ def VegetationInstances_DespawnWhenOutOfRange():
     # Create vegetation layer spawner
     # Create vegetation layer spawner
     world_center = math.Vector3(512.0, 512.0, 32.0)
     world_center = math.Vector3(512.0, 512.0, 32.0)
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
     asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
-    spawner_entity = dynveg.create_vegetation_area("Spawner Instance", world_center, 16.0, 16.0, 16.0, asset_path)
+    spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Instance", world_center, 16.0, 16.0, 16.0, asset_path)
 
 
     # Create a surface to spawn on
     # Create a surface to spawn on
     dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0)
     dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0)

+ 21 - 16
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py

@@ -16,6 +16,20 @@ from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, E
 @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
 @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
 class TestAutomation(EditorTestSuite):
 class TestAutomation(EditorTestSuite):
+    class test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(EditorParallelTest):
+        from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module
+    
+    class test_AltitudeFilter_FilterStageToggle(EditorParallelTest):
+        from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module
+
+    class test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(EditorParallelTest):
+        from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module
+
+
[email protected]_main
[email protected]("launcher_platform", ['windows_editor'])
[email protected]("project", ["AutomatedTesting"])
+class TestAutomation_PrefabNotEnabled(EditorTestSuite):
 
 
     enable_prefab_system = False
     enable_prefab_system = False
 
 
@@ -36,19 +50,10 @@ class TestAutomation(EditorTestSuite):
     class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorParallelTest):
     class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorParallelTest):
         from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module
         from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module
 
 
-    class test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(EditorParallelTest):
-        from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module
-
-    class test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(EditorParallelTest):
-        from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module
-
-    class test_AltitudeFilter_FilterStageToggle(EditorParallelTest):
-        from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module
-
     class test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(EditorSingleTest):
     class test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(EditorSingleTest):
         # Custom teardown to remove slice asset created during test
         # Custom teardown to remove slice asset created during test
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_slices(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_slices(self, workspace)
         from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
         from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
 
 
     class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorParallelTest):
     class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorParallelTest):
@@ -161,27 +166,27 @@ class TestAutomation(EditorTestSuite):
 
 
         # Custom setup/teardown to remove test level created during test
         # Custom setup/teardown to remove test level created during test
         def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
         def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_level(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
 
 
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_level(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
 
 
     class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest):
     class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest):
         from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
         from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
 
 
         # Custom setup/teardown to remove test level created during test
         # Custom setup/teardown to remove test level created during test
         def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
         def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_level(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
 
 
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_level(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
 
 
     class test_LayerBlender_E2E_Editor(EditorSingleTest):
     class test_LayerBlender_E2E_Editor(EditorSingleTest):
         from .EditorScripts import LayerBlender_E2E_Editor as test_module
         from .EditorScripts import LayerBlender_E2E_Editor as test_module
 
 
         # Custom setup/teardown to remove test level created during test
         # Custom setup/teardown to remove test level created during test
         def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
         def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_level(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
 
 
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
         def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
-            TestAutomation.cleanup_test_level(self, workspace)
+            TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)

+ 3 - 3
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py

@@ -52,15 +52,15 @@ class TestAutomation(TestAutomationBase):
 
 
     def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
     def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
         from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module
         from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module
-        self._run_test(request, workspace, editor, test_module, enable_prefab_system=False)
+        self._run_test(request, workspace, editor, test_module)
 
 
     def test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
     def test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
         from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module
         from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module
-        self._run_test(request, workspace, editor, test_module, enable_prefab_system=False)
+        self._run_test(request, workspace, editor, test_module)
 
 
     def test_AltitudeFilter_FilterStageToggle(self, request, workspace, editor, launcher_platform):
     def test_AltitudeFilter_FilterStageToggle(self, request, workspace, editor, launcher_platform):
         from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module
         from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module
-        self._run_test(request, workspace, editor, test_module, enable_prefab_system=False)
+        self._run_test(request, workspace, editor, test_module)
 
 
     def test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(self, request, workspace, editor, remove_test_slice, launcher_platform):
     def test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(self, request, workspace, editor, remove_test_slice, launcher_platform):
         from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
         from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module

+ 40 - 4
AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py

@@ -8,14 +8,16 @@
 
 
 import os
 import os
 import sys
 import sys
+from pathlib import Path
 
 
+import azlmbr.areasystem as areasystem
 import azlmbr.asset as asset
 import azlmbr.asset as asset
 import azlmbr.bus as bus
 import azlmbr.bus as bus
 import azlmbr.components as components
 import azlmbr.components as components
 import azlmbr.math as math
 import azlmbr.math as math
-import azlmbr.vegetation as vegetation
-import azlmbr.areasystem as areasystem
 import azlmbr.paths
 import azlmbr.paths
+import azlmbr.prefab as prefab
+import azlmbr.vegetation as vegetation
 
 
 sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
 sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
 import editor_python_test_tools.hydra_editor_utils as hydra
 import editor_python_test_tools.hydra_editor_utils as hydra
@@ -91,7 +93,7 @@ def create_mesh_surface_entity_with_slopes(name, center_point, uniform_scale):
     return surface_entity
     return surface_entity
 
 
 
 
-def create_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, dynamic_slice_asset_path):
+def create_dynamic_slice_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, dynamic_slice_asset_path):
     # Create a vegetation area entity to use as our test vegetation spawner
     # Create a vegetation area entity to use as our test vegetation spawner
     spawner_entity = hydra.Entity(name)
     spawner_entity = hydra.Entity(name)
     spawner_entity.create_entity(
     spawner_entity.create_entity(
@@ -104,14 +106,48 @@ def create_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_
                                                                                           box_size_z))
                                                                                           box_size_z))
 
 
     # Set the vegetation area to a Dynamic Slice spawner with a specific slice asset selected
     # Set the vegetation area to a Dynamic Slice spawner with a specific slice asset selected
+    descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
     dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
     dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
     dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
     dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
-    descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
     descriptor.spawner = dynamic_slice_spawner
     descriptor.spawner = dynamic_slice_spawner
     spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
     spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
     return spawner_entity
     return spawner_entity
 
 
 
 
+def create_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, target_prefab):
+    # Create a vegetation area entity to use as our test vegetation spawner
+    spawner_entity = hydra.Entity(name)
+    spawner_entity.create_entity(
+        center_point,
+        ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
+        )
+    if spawner_entity.id.IsValid():
+        print(f"'{spawner_entity.name}' created")
+    spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(box_size_x, box_size_y,
+                                                                                          box_size_z))
+    # Get the in-memory spawnable asset id if exists
+    spawnable_name = Path(target_prefab.file_path).stem
+    spawnable_asset_id = prefab.PrefabPublicRequestBus(bus.Broadcast, 'GetInMemorySpawnableAssetId', 
+                                                      spawnable_name)
+
+    # Create the in-memory spawnable asset from given prefab if the spawnable does not exist
+    if not spawnable_asset_id.is_valid():
+        create_spawnable_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreateInMemorySpawnableAsset', 
+                                                                target_prefab.file_path, 
+                                                                spawnable_name)
+        assert create_spawnable_result.IsSuccess(), \
+            f"Prefab operation 'CreateInMemorySpawnableAssets' failed. Error: {create_spawnable_result.GetError()}"
+        spawnable_asset_id = create_spawnable_result.GetValue()
+
+    # Set the vegetation area to a prefab instance spawner with a specific prefab asset selected
+    descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
+    prefab_spawner = vegetation.PrefabInstanceSpawner()
+    prefab_spawner.SetPrefabAssetId(spawnable_asset_id)
+    descriptor.spawner = prefab_spawner
+    spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
+    return spawner_entity
+
+
 def create_blocker_area(name, center_point, box_size_x, box_size_y, box_size_z):
 def create_blocker_area(name, center_point, box_size_x, box_size_y, box_size_z):
     # Create a Vegetation Layer Blocker area
     # Create a Vegetation Layer Blocker area
     blocker_entity = hydra.Entity(name)
     blocker_entity = hydra.Entity(name)

+ 2 - 1
Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h

@@ -15,6 +15,7 @@
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/string.h>
 
 
 #include <AzToolsFramework/Prefab/Instance/Instance.h>
 #include <AzToolsFramework/Prefab/Instance/Instance.h>
+#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
 
 
 namespace AzToolsFramework
 namespace AzToolsFramework
 {
 {
@@ -47,7 +48,7 @@ namespace AzToolsFramework
 
 
         //! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
         //! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
         //! /return The vector of Assets generated by Prefab processing
         //! /return The vector of Assets generated by Prefab processing
-        virtual const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() = 0;
+        virtual const Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer::SpawnableAssets& GetPlayInEditorAssetData() const = 0;
 
 
         virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
         virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
         virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
         virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;

+ 38 - 159
Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp

@@ -25,6 +25,7 @@
 #include <AzToolsFramework/Prefab/PrefabLoader.h>
 #include <AzToolsFramework/Prefab/PrefabLoader.h>
 #include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
 #include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
 #include <AzToolsFramework/Prefab/PrefabUndoHelpers.h>
 #include <AzToolsFramework/Prefab/PrefabUndoHelpers.h>
+#include <AzToolsFramework/Prefab/Spawnable/PrefabConverterStackProfileNames.h>
 
 
 namespace AzToolsFramework
 namespace AzToolsFramework
 {
 {
@@ -379,9 +380,9 @@ namespace AzToolsFramework
         return m_rootInstance ? m_rootInstance->GetTemplateId() : Prefab::InvalidTemplateId;
         return m_rootInstance ? m_rootInstance->GetTemplateId() : Prefab::InvalidTemplateId;
     }
     }
 
 
-    const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData()
+    const Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer::SpawnableAssets& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData() const
     {
     {
-        return m_playInEditorData.m_assets;
+        return m_playInEditorData.m_assetsCache.GetAllInMemorySpawnableAssets();
     }
     }
 
 
     void PrefabEditorEntityOwnershipService::OnEntityRemoved(AZ::EntityId entityId)
     void PrefabEditorEntityOwnershipService::OnEntityRemoved(AZ::EntityId entityId)
@@ -405,176 +406,55 @@ namespace AzToolsFramework
         m_validateEntitiesCallback = AZStd::move(validateEntitiesCallback);
         m_validateEntitiesCallback = AZStd::move(validateEntitiesCallback);
     }
     }
 
 
-    void PrefabEditorEntityOwnershipService::LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets)
+    void PrefabEditorEntityOwnershipService::StartPlayInEditor()
     {
     {
-        // Start our loads on all assets by calling GetAsset from the AssetManager
-        for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
-        {
-            if (!asset.GetId().IsValid())
-            {
-                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
-                continue;
-            }
-
-            const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
-
-            if (loadBehavior == AZ::Data::AssetLoadBehavior::NoLoad)
-            {
-                continue;
-            }
-
-            AZ::Data::AssetId assetId = asset.GetId();
-            AZ::Data::AssetType assetType = asset.GetType();
-
-            asset = AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, loadBehavior);
-
-            if (!asset.GetId().IsValid())
-            {
-                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
-                continue;
-            }
-        }
+        // This is a workaround until the replacement for GameEntityContext is done
+        AzFramework::GameEntityContextEventBus::Broadcast(&AzFramework::GameEntityContextEventBus::Events::OnPreGameEntitiesStarted);
 
 
-        // For all Preload assets we block until they're ready
-        // We do this as a seperate pass so that we don't interrupt queuing up all other asset loads
-        for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
+        if (m_rootInstance && !m_playInEditorData.m_isEnabled)
         {
         {
-            if (!asset.GetId().IsValid())
+            // Construct the runtime entities and products
+            bool readyToCreateRootSpawnable = m_playInEditorData.m_assetsCache.IsActivated();
+            if (!readyToCreateRootSpawnable &&
+                !m_playInEditorData.m_assetsCache.Activate(Prefab::PrefabConversionUtils::PlayInEditor))
             {
             {
-                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
-                continue;
+                AZ_Error("Prefab", false, "Failed to create a prefab processing stack from key '%.*s'.", AZ_STRING_ARG(Prefab::PrefabConversionUtils::PlayInEditor));
+                return;
             }
             }
 
 
-            const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
-
-            if (loadBehavior != AZ::Data::AssetLoadBehavior::PreLoad)
+            auto createRootSpawnableResult = m_playInEditorData.m_assetsCache.CreateInMemorySpawnableAsset(m_rootInstance->GetTemplateId(), DefaultMainSpawnableName, true);
+            if (createRootSpawnableResult.IsSuccess())
             {
             {
-                continue;
-            }
+                // make sure that PRE_NOTIFY assets get their notify before we activate, so that we can preserve the order of 
+                // (load asset) -> (notify) -> (init) -> (activate)
+                AZ::Data::AssetManager::Instance().DispatchEvents();
 
 
-            asset.BlockUntilLoadComplete();
+                m_playInEditorData.m_entities.Reset(createRootSpawnableResult.GetValue());
+                m_playInEditorData.m_entities.SpawnAllEntities();
 
 
-            if (asset.IsError())
+                // This is a workaround until the replacement for GameEntityContext is done
+                AzFramework::GameEntityContextEventBus::Broadcast(
+                    &AzFramework::GameEntityContextEventBus::Events::OnGameEntitiesStarted);
+            }
+            else
             {
             {
-                AZ_Error("Prefab", false, "Asset with id %s failed to preload while entering game mode",
-                    asset.GetId().ToString<AZStd::string>().c_str());
-
-                continue;
+                AZ_Error("Prefab", false, "Failed to create the root spawnable due to the error: '%.*s'", AZ_STRING_ARG(createRootSpawnableResult.GetError()));
+                return;
             }
             }
-        }
-    }
-
-    void PrefabEditorEntityOwnershipService::StartPlayInEditor()
-    {
-        // This is a workaround until the replacement for GameEntityContext is done
-        AzFramework::GameEntityContextEventBus::Broadcast(&AzFramework::GameEntityContextEventBus::Events::OnPreGameEntitiesStarted);
 
 
-        if (m_rootInstance && !m_playInEditorData.m_isEnabled)
-        {
-            // Construct the runtime entities and products 
-            Prefab::TemplateReference templateReference = m_prefabSystemComponent->FindTemplate(m_rootInstance->GetTemplateId());
-            if (templateReference.has_value())
+            m_rootInstance->GetAllEntitiesInHierarchy([this](AZStd::unique_ptr<AZ::Entity>& entity)
             {
             {
-                bool converterLoaded = m_playInEditorData.m_converter.IsLoaded();
-                if (!converterLoaded)
+                AZ_Assert(entity, "Invalid entity found in root instance while starting play in editor.");
+                if (entity->GetState() == AZ::Entity::State::Active)
                 {
                 {
-                    converterLoaded = m_playInEditorData.m_converter.LoadStackProfile("PlayInEditor");
-                }
-                if (converterLoaded)
-                {
-                    // Use a random uuid as this is only a temporary source.
-                    AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext context(AZ::Uuid::CreateRandom());
-                    Prefab::PrefabDom copy;
-                    copy.CopyFrom(templateReference->get().GetPrefabDom(), copy.GetAllocator(), false);
-                    context.AddPrefab(DefaultMainSpawnableName, AZStd::move(copy));
-                    m_playInEditorData.m_converter.ProcessPrefab(context);
-                    if (context.HasCompletedSuccessfully() && !context.GetProcessedObjects().empty())
-                    {
-                        static constexpr size_t NoRootSpawnable = AZStd::numeric_limits<size_t>::max();
-                        size_t rootSpawnableIndex = NoRootSpawnable;
-
-                        // Create temporary assets from the processed data.
-                        for (auto& product : context.GetProcessedObjects())
-                        {
-                            if (product.GetAssetType() == AZ::AzTypeInfo<AzFramework::Spawnable>::Uuid() &&
-                                product.GetId() ==
-                                    AZStd::string::format("%s.%s", DefaultMainSpawnableName, AzFramework::Spawnable::FileExtension))
-                            {
-                                rootSpawnableIndex = m_playInEditorData.m_assets.size();
-                            }
-
-                            AZ::Data::AssetInfo info;
-                            info.m_assetId = product.GetAsset().GetId();
-                            info.m_assetType = product.GetAssetType();
-                            info.m_relativePath = product.GetId();
-
-                            AZ::Data::AssetCatalogRequestBus::Broadcast(
-                                &AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, info.m_assetId, info);
-                            m_playInEditorData.m_assets.emplace_back(product.ReleaseAsset().release(), AZ::Data::AssetLoadBehavior::Default);
-
-                            // Ensure the product asset is registered with the AssetManager
-                            // Hold on to the returned asset to keep ref count alive until we assign it the latest data
-                            AZ::Data::Asset<AZ::Data::AssetData> asset =
-                                AZ::Data::AssetManager::Instance().FindOrCreateAsset(info.m_assetId, info.m_assetType, AZ::Data::AssetLoadBehavior::Default);
-
-                            // Update the asset registered in the AssetManager with the data of our product from the Prefab Processor
-                            AZ::Data::AssetManager::Instance().AssignAssetData(m_playInEditorData.m_assets.back());
-                        }
-
-                        for (auto& product : context.GetProcessedObjects())
-                        {
-                            LoadReferencedAssets(product.GetReferencedAssets());
-                        }
-
-                        // make sure that PRE_NOTIFY assets get their notify before we activate, so that we can preserve the order of 
-                        // (load asset) -> (notify) -> (init) -> (activate)
-                        AZ::Data::AssetManager::Instance().DispatchEvents();
-
-                        if (rootSpawnableIndex != NoRootSpawnable)
-                        {
-                            m_playInEditorData.m_entities.Reset(m_playInEditorData.m_assets[rootSpawnableIndex]);
-                            m_playInEditorData.m_entities.SpawnAllEntities();
-                        }
-                        else
-                        {
-                            AZ_Error("Prefab", false,
-                                "Processing of the level prefab failed to produce a root spawnable while entering game mode. "
-                                "Unable to fully enter game mode.");
-                            return;
-                        }
-
-                        // This is a workaround until the replacement for GameEntityContext is done
-                        AzFramework::GameEntityContextEventBus::Broadcast(
-                            &AzFramework::GameEntityContextEventBus::Events::OnGameEntitiesStarted);
-                    }
-                    else
-                    {
-                        AZ_Error("Prefab", false,
-                            "Failed to convert the prefab into assets. "
-                            "Confirm that the 'PlayInEditor' prefab processor stack is capable of producing a useable product asset.");
-                        return;
-                    }
-                }
-                else
-                {
-                    AZ_Error("Prefab", false, "Failed to create a prefab processing stack from key 'PlayInEditor'.");
-                    return;
+                    entity->Deactivate();
+                    m_playInEditorData.m_deactivatedEntities.push_back(entity.get());
                 }
                 }
+                return true;
+            });
 
 
-                m_rootInstance->GetAllEntitiesInHierarchy([this](AZStd::unique_ptr<AZ::Entity>& entity)
-                    {
-                        AZ_Assert(entity, "Invalid entity found in root instance while starting play in editor.");
-                        if (entity->GetState() == AZ::Entity::State::Active)
-                        {
-                            entity->Deactivate();
-                            m_playInEditorData.m_deactivatedEntities.push_back(entity.get());
-                        }
-                        return true;
-                    });
-            }
+            m_playInEditorData.m_isEnabled = true;
         }
         }
-
-        m_playInEditorData.m_isEnabled = true;
     }
     }
 
 
     void PrefabEditorEntityOwnershipService::StopPlayInEditor()
     void PrefabEditorEntityOwnershipService::StopPlayInEditor()
@@ -588,7 +468,7 @@ namespace AzToolsFramework
 
 
             m_playInEditorData.m_entities.DespawnAllEntities();
             m_playInEditorData.m_entities.DespawnAllEntities();
             m_playInEditorData.m_entities.Alert(
             m_playInEditorData.m_entities.Alert(
-                [assets = AZStd::move(m_playInEditorData.m_assets),
+                [allSpawnableAssetData = m_playInEditorData.m_assetsCache.MoveAllInMemorySpawnableAssets(),
                  deactivatedEntities = AZStd::move(m_playInEditorData.m_deactivatedEntities)]([[maybe_unused]] uint32_t generation) mutable
                  deactivatedEntities = AZStd::move(m_playInEditorData.m_deactivatedEntities)]([[maybe_unused]] uint32_t generation) mutable
                 {
                 {
                     auto end = deactivatedEntities.rend();
                     auto end = deactivatedEntities.rend();
@@ -598,11 +478,10 @@ namespace AzToolsFramework
                         (*it)->Activate();
                         (*it)->Activate();
                     }
                     }
 
 
-                    for (auto& asset : assets)
+                    for (auto& [spawnableName, spawnableAssetData] : allSpawnableAssetData)
                     {
                     {
-                        if (asset)
+                        for (auto& asset : spawnableAssetData.m_assets)
                         {
                         {
-                            // Explicitly release because this needs to happen before the asset is unregistered.
                             asset.Release();
                             asset.Release();
                             AZ::Data::AssetCatalogRequestBus::Broadcast(
                             AZ::Data::AssetCatalogRequestBus::Broadcast(
                                 &AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset.GetId());
                                 &AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset.GetId());

+ 4 - 7
Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h

@@ -14,7 +14,7 @@
 #include <AzFramework/Spawnable/SpawnableEntitiesContainer.h>
 #include <AzFramework/Spawnable/SpawnableEntitiesContainer.h>
 #include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
 #include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
 #include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
 #include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
-#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
+#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
 
 
 namespace AzToolsFramework
 namespace AzToolsFramework
 {
 {
@@ -176,8 +176,7 @@ namespace AzToolsFramework
     private:
     private:
         struct PlayInEditorData
         struct PlayInEditorData
         {
         {
-            AzToolsFramework::Prefab::PrefabConversionUtils::PrefabConversionPipeline m_converter;
-            AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> m_assets;
+            AzToolsFramework::Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer m_assetsCache;
             AZStd::vector<AZ::Entity*> m_deactivatedEntities;
             AZStd::vector<AZ::Entity*> m_deactivatedEntities;
             AzFramework::SpawnableEntitiesContainer m_entities;
             AzFramework::SpawnableEntitiesContainer m_entities;
             bool m_isEnabled{ false };
             bool m_isEnabled{ false };
@@ -195,14 +194,12 @@ namespace AzToolsFramework
 
 
         Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
         Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
         Prefab::TemplateId GetRootPrefabTemplateId() override;
         Prefab::TemplateId GetRootPrefabTemplateId() override;
-        
-        const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetPlayInEditorAssetData() override;
+
+        const Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer::SpawnableAssets& GetPlayInEditorAssetData() const override;
         //////////////////////////////////////////////////////////////////////////
         //////////////////////////////////////////////////////////////////////////
 
 
         void OnEntityRemoved(AZ::EntityId entityId);
         void OnEntityRemoved(AZ::EntityId entityId);
 
 
-        void LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
-
         OnEntitiesAddedCallback m_entitiesAddedCallback;
         OnEntitiesAddedCallback m_entitiesAddedCallback;
         OnEntitiesRemovedCallback m_entitiesRemovedCallback;
         OnEntitiesRemovedCallback m_entitiesRemovedCallback;
         ValidateEntitiesCallback m_validateEntitiesCallback;
         ValidateEntitiesCallback m_validateEntitiesCallback;

+ 30 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestBus.h

@@ -8,6 +8,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AzCore/Asset/AssetCommon.h>
 #include <AzCore/Component/EntityId.h>
 #include <AzCore/Component/EntityId.h>
 #include <AzCore/EBus/EBus.h>
 #include <AzCore/EBus/EBus.h>
 #include <AzCore/IO/Path/Path.h>
 #include <AzCore/IO/Path/Path.h>
@@ -27,6 +28,7 @@ namespace AzToolsFramework
         using InstantiatePrefabResult = AZ::Outcome<AZ::EntityId, AZStd::string>;
         using InstantiatePrefabResult = AZ::Outcome<AZ::EntityId, AZStd::string>;
         using DuplicatePrefabResult = AZ::Outcome<EntityIdList, AZStd::string>;
         using DuplicatePrefabResult = AZ::Outcome<EntityIdList, AZStd::string>;
         using PrefabOperationResult = AZ::Outcome<void, AZStd::string>;
         using PrefabOperationResult = AZ::Outcome<void, AZStd::string>;
+        using CreateSpawnableResult = AZ::Outcome<AZ::Data::AssetId, AZStd::string>;
 
 
         /**
         /**
         * The primary purpose of this bus is to facilitate writing automated tests for prefabs.
         * The primary purpose of this bus is to facilitate writing automated tests for prefabs.
@@ -93,6 +95,34 @@ namespace AzToolsFramework
              * Returns the path to the prefab, or an empty path if the entity is owned by the level.
              * Returns the path to the prefab, or an empty path if the entity is owned by the level.
              */
              */
             virtual AZStd::string GetOwningInstancePrefabPath(AZ::EntityId entityId) const = 0;
             virtual AZStd::string GetOwningInstancePrefabPath(AZ::EntityId entityId) const = 0;
+
+            /**
+             * Convert a prefab on given file path with given name to in-memory spawnable asset. 
+             * Returns the asset id of the produced spawnable if creation succeeded;
+             * on failure, it comes with an error message detailing the cause of the error.
+             */
+            virtual CreateSpawnableResult CreateInMemorySpawnableAsset(AZStd::string_view prefabFilePath, AZStd::string_view spawnableName) = 0;
+
+            /**
+             * Remove in-memory spawnable asset with given name.
+             * Return an outcome object; on failure, it comes with an error message detailing the cause of the error.
+             */
+            virtual PrefabOperationResult RemoveInMemorySpawnableAsset(AZStd::string_view spawnableName) = 0;
+
+            /**
+             * Return whether an in-memory spawnable with given name exists or not.
+             */
+            virtual bool HasInMemorySpawnableAsset(AZStd::string_view spawnableName) const = 0;
+
+            /**
+             * Return an asset id of a spawnalbe with given name. Invalid asset id will be returned if the spawnable doesn't exist.
+             */
+            virtual AZ::Data::AssetId GetInMemorySpawnableAssetId(AZStd::string_view spawnableName) const = 0;
+
+            /**
+             * Remove all the in-memory spawnable assets.
+             */
+            virtual void RemoveAllInMemorySpawnableAssets() = 0;
         };
         };
 
 
         using PrefabPublicRequestBus = AZ::EBus<PrefabPublicRequests>;
         using PrefabPublicRequestBus = AZ::EBus<PrefabPublicRequests>;

+ 73 - 4
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.cpp

@@ -8,10 +8,16 @@
 
 
 #include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
 #include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
 
 
-#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
-
+#include <AzCore/Asset/AssetManager.h>
+#include <AzCore/Asset/AssetManagerBus.h>
 #include <AzCore/RTTI/BehaviorContext.h>
 #include <AzCore/RTTI/BehaviorContext.h>
 
 
+#include <AzToolsFramework/Prefab/PrefabLoader.h>
+#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
+#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
+#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
+#include <AzToolsFramework/Prefab/Spawnable/PrefabConverterStackProfileNames.h>
+
 namespace AzToolsFramework
 namespace AzToolsFramework
 {
 {
     namespace Prefab
     namespace Prefab
@@ -31,13 +37,18 @@ namespace AzToolsFramework
                     ->Event("DetachPrefab", &PrefabPublicRequests::DetachPrefab)
                     ->Event("DetachPrefab", &PrefabPublicRequests::DetachPrefab)
                     ->Event("DuplicateEntitiesInInstance", &PrefabPublicRequests::DuplicateEntitiesInInstance)
                     ->Event("DuplicateEntitiesInInstance", &PrefabPublicRequests::DuplicateEntitiesInInstance)
                     ->Event("GetOwningInstancePrefabPath", &PrefabPublicRequests::GetOwningInstancePrefabPath)
                     ->Event("GetOwningInstancePrefabPath", &PrefabPublicRequests::GetOwningInstancePrefabPath)
+                    ->Event("CreateInMemorySpawnableAsset", &PrefabPublicRequests::CreateInMemorySpawnableAsset)
+                    ->Event("RemoveInMemorySpawnableAsset", &PrefabPublicRequests::RemoveInMemorySpawnableAsset)
+                    ->Event("HasInMemorySpawnableAsset", &PrefabPublicRequests::HasInMemorySpawnableAsset)
+                    ->Event("GetInMemorySpawnableAssetId", &PrefabPublicRequests::GetInMemorySpawnableAssetId)
+                    ->Event("RemoveAllInMemorySpawnableAssets", &PrefabPublicRequests::RemoveAllInMemorySpawnableAssets)
                     ;
                     ;
             }
             }
         }
         }
 
 
         void PrefabPublicRequestHandler::Connect()
         void PrefabPublicRequestHandler::Connect()
         {
         {
-            m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
+            m_prefabPublicInterface = AZ::Interface<PrefabPublicInterface>::Get();
             AZ_Assert(m_prefabPublicInterface, "PrefabPublicRequestHandler - Could not retrieve instance of PrefabPublicInterface");
             AZ_Assert(m_prefabPublicInterface, "PrefabPublicRequestHandler - Could not retrieve instance of PrefabPublicInterface");
 
 
             PrefabPublicRequestBus::Handler::BusConnect();
             PrefabPublicRequestBus::Handler::BusConnect();
@@ -46,7 +57,7 @@ namespace AzToolsFramework
         void PrefabPublicRequestHandler::Disconnect()
         void PrefabPublicRequestHandler::Disconnect()
         {
         {
             PrefabPublicRequestBus::Handler::BusDisconnect();
             PrefabPublicRequestBus::Handler::BusDisconnect();
-
+            m_spawnableAssetContainer.Deactivate();
             m_prefabPublicInterface = nullptr;
             m_prefabPublicInterface = nullptr;
         }
         }
 
 
@@ -79,5 +90,63 @@ namespace AzToolsFramework
         {
         {
             return m_prefabPublicInterface->GetOwningInstancePrefabPath(entityId).Native();
             return m_prefabPublicInterface->GetOwningInstancePrefabPath(entityId).Native();
         }
         }
+
+        bool PrefabPublicRequestHandler::TryActivateSpawnableAssetContainer()
+        {
+            bool activated = m_spawnableAssetContainer.IsActivated();
+            if (!activated)
+            {
+                activated = m_spawnableAssetContainer.Activate(PrefabConversionUtils::IntegrationTests);
+            }
+
+            return activated;
+        }
+
+        CreateSpawnableResult PrefabPublicRequestHandler::CreateInMemorySpawnableAsset(AZStd::string_view prefabFilePath, AZStd::string_view spawnableName)
+        {
+            if (!TryActivateSpawnableAssetContainer())
+            {
+                return AZ::Failure(AZStd::string("Failed to activate Spawnable Asset Container"));
+            }
+
+            auto result = m_spawnableAssetContainer.CreateInMemorySpawnableAsset(prefabFilePath, spawnableName);
+            if (result.IsSuccess())
+            {
+                return AZ::Success(result.GetValue().GetId());
+            }
+            else
+            {
+                return AZ::Failure(result.TakeError());
+            }
+        }
+
+        PrefabOperationResult PrefabPublicRequestHandler::RemoveInMemorySpawnableAsset(AZStd::string_view spawnableName)
+        {
+            auto result = m_spawnableAssetContainer.RemoveInMemorySpawnableAsset(spawnableName);
+            if (result.IsSuccess())
+            {
+                return AZ::Success();
+            }
+            else
+            {
+                return AZ::Failure(result.TakeError());
+            }
+        }
+
+        bool PrefabPublicRequestHandler::HasInMemorySpawnableAsset(AZStd::string_view spawnableName) const
+        {
+            return m_spawnableAssetContainer.HasInMemorySpawnableAsset(spawnableName);
+        }
+
+        AZ::Data::AssetId PrefabPublicRequestHandler::GetInMemorySpawnableAssetId(AZStd::string_view spawnableName) const
+        {
+            return m_spawnableAssetContainer.GetInMemorySpawnableAssetId(spawnableName);
+        }
+
+        void PrefabPublicRequestHandler::RemoveAllInMemorySpawnableAssets()
+        {
+            m_spawnableAssetContainer.ClearAllInMemorySpawnableAssets();
+        }
+
     } // namespace Prefab
     } // namespace Prefab
 } // namespace AzToolsFramework
 } // namespace AzToolsFramework

+ 10 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicRequestHandler.h

@@ -12,6 +12,7 @@
 #include <AzCore/RTTI/RTTI.h>
 #include <AzCore/RTTI/RTTI.h>
 
 
 #include <AzToolsFramework/Prefab/PrefabPublicRequestBus.h>
 #include <AzToolsFramework/Prefab/PrefabPublicRequestBus.h>
+#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
 
 
 namespace AzToolsFramework
 namespace AzToolsFramework
 {
 {
@@ -37,9 +38,18 @@ namespace AzToolsFramework
             PrefabOperationResult DetachPrefab(const AZ::EntityId& containerEntityId) override;
             PrefabOperationResult DetachPrefab(const AZ::EntityId& containerEntityId) override;
             DuplicatePrefabResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) override;
             DuplicatePrefabResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) override;
             AZStd::string GetOwningInstancePrefabPath(AZ::EntityId entityId) const override;
             AZStd::string GetOwningInstancePrefabPath(AZ::EntityId entityId) const override;
+            CreateSpawnableResult CreateInMemorySpawnableAsset(AZStd::string_view prefabFilePath, AZStd::string_view spawnableName) override;
+            PrefabOperationResult RemoveInMemorySpawnableAsset(AZStd::string_view spawnableName) override;
+            bool HasInMemorySpawnableAsset(AZStd::string_view spawnableName) const override;
+            AZ::Data::AssetId GetInMemorySpawnableAssetId(AZStd::string_view spawnableName) const override;
+            void RemoveAllInMemorySpawnableAssets() override;
 
 
         private:
         private:
+            bool TryActivateSpawnableAssetContainer();
+
+            PrefabConversionUtils::InMemorySpawnableAssetContainer m_spawnableAssetContainer;
             PrefabPublicInterface* m_prefabPublicInterface = nullptr;
             PrefabPublicInterface* m_prefabPublicInterface = nullptr;
+
         };
         };
     } // namespace Prefab
     } // namespace Prefab
 } // namespace AzToolsFramework
 } // namespace AzToolsFramework

+ 275 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.cpp

@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
+
+#include <AzCore/Asset/AssetManager.h>
+#include <AzCore/Asset/AssetManagerBus.h>
+#include <AzToolsFramework/Prefab/PrefabLoader.h>
+#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
+#include <AzToolsFramework/Prefab/Spawnable/PrefabConverterStackProfileNames.h>
+
+namespace AzToolsFramework::Prefab::PrefabConversionUtils
+{
+    InMemorySpawnableAssetContainer::~InMemorySpawnableAssetContainer()
+    {
+        Deactivate();
+    }
+
+    bool InMemorySpawnableAssetContainer::Activate(AZStd::string_view stackProfile)
+    {
+        AZ_Assert(!IsActivated(),
+            "InMemorySpawnableAssetContainer - Unable to activate an instance of InMemorySpawnableAssetContainer as the instance is already active.");
+
+        m_prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
+        AZ_Assert(m_prefabSystemComponentInterface, "InMemorySpawnableAssetContainer - Could not retrieve instance of PrefabSystemComponentInterface");
+
+        m_loaderInterface = AZ::Interface<Prefab::PrefabLoaderInterface>::Get();
+        AZ_Assert(m_loaderInterface, "InMemorySpawnableAssetContainer - Could not retrieve instance of PrefabLoaderInterface");
+
+        m_stockProfile = stackProfile;
+        return m_converter.LoadStackProfile(m_stockProfile);
+    }
+
+    void InMemorySpawnableAssetContainer::Deactivate()
+    {
+        ClearAllInMemorySpawnableAssets();
+        m_stockProfile = "";
+        m_loaderInterface = nullptr;
+        m_prefabSystemComponentInterface = nullptr;
+    }
+
+    bool InMemorySpawnableAssetContainer::IsActivated() const
+    {
+        return m_converter.IsLoaded();
+    }
+
+    AZStd::string_view InMemorySpawnableAssetContainer::GetStockProfile() const
+    {
+        return m_stockProfile;
+    }
+
+    bool InMemorySpawnableAssetContainer::HasInMemorySpawnableAsset(AZStd::string_view spawnableName) const
+    {
+        return m_spawnableAssets.find(spawnableName) != m_spawnableAssets.end();
+    }
+
+    AZ::Data::AssetId InMemorySpawnableAssetContainer::GetInMemorySpawnableAssetId(AZStd::string_view spawnableName) const
+    {
+        auto found = m_spawnableAssets.find(spawnableName);
+        if (found != m_spawnableAssets.end())
+        {
+            return found->second.m_spawnableAssetId;
+        }
+        else
+        {
+            return  AZ::Data::AssetId();
+        }
+    }
+
+    auto InMemorySpawnableAssetContainer::RemoveInMemorySpawnableAsset(AZStd::string_view spawnableName) -> RemoveSpawnableResult
+    {
+        auto found = m_spawnableAssets.find(spawnableName);
+        if (found == m_spawnableAssets.end())
+        {
+            return AZ::Failure(AZStd::string::format("In-memory Spawnable '%.*s' doesn't exists.", AZ_STRING_ARG(spawnableName)));
+        }
+
+        for (auto& asset : found->second.m_assets)
+        {
+            asset.Release();
+            AZ::Data::AssetCatalogRequestBus::Broadcast(
+                &AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset.GetId());
+        }
+
+        m_spawnableAssets.erase(found);
+        return AZ::Success();
+    }
+
+    InMemorySpawnableAssetContainer::CreateSpawnableResult InMemorySpawnableAssetContainer::CreateInMemorySpawnableAsset(
+        AzToolsFramework::Prefab::TemplateId templateId, AZStd::string_view spawnableName, bool loadReferencedAssets)
+    {
+        if (!IsActivated())
+        {
+            return AZ::Failure(AZStd::string::format("Failed to create a prefab processing stack from key '%.*s'.", AZ_STRING_ARG(m_stockProfile)));
+        }
+
+        if (HasInMemorySpawnableAsset(spawnableName))
+        {
+            return AZ::Failure(AZStd::string::format("In-memory Spawnable '%.*s' already exists.", AZ_STRING_ARG(spawnableName)));
+        }
+
+        TemplateReference templateReference = m_prefabSystemComponentInterface->FindTemplate(templateId);
+        if (!templateReference.has_value())
+        {
+            return AZ::Failure(AZStd::string::format("Could not get Template DOM for given Template's id %llu .", templateId));
+        }
+
+        // Use a random uuid as this is only a temporary source.
+        PrefabConversionUtils::PrefabProcessorContext context(AZ::Uuid::CreateRandom());
+        PrefabDom copy;
+        copy.CopyFrom(templateReference->get().GetPrefabDom(), copy.GetAllocator(), false);
+        context.AddPrefab(spawnableName, AZStd::move(copy));
+        m_converter.ProcessPrefab(context);
+
+        if (!context.HasCompletedSuccessfully() || context.GetProcessedObjects().empty())
+        {
+            return AZ::Failure(AZStd::string::format(
+                "Failed to convert the prefab into assets. Please confirm that the '%.*s' prefab processor stack is capable of producing a usable product asset.",
+                AZ_STRING_ARG(PrefabConversionUtils::IntegrationTests)));
+        }
+
+        static constexpr size_t NoTargetSpawnable = AZStd::numeric_limits<size_t>::max();
+        size_t targetSpawnableIndex = NoTargetSpawnable;
+        AZStd::vector<AZ::Data::AssetId> assetIds;
+        SpawnableAssetData spawnableAssetData;
+        AZStd::string rootProductId(spawnableName);
+        rootProductId += AzFramework::Spawnable::DotFileExtension;
+
+        // Create temporary assets from the processed data.
+        for (auto& product : context.GetProcessedObjects())
+        {
+            if (product.GetAssetType() == azrtti_typeid<AzFramework::Spawnable>() && product.GetId() == rootProductId)
+            {
+                targetSpawnableIndex = spawnableAssetData.m_assets.size();
+            }
+
+            AZ::Data::AssetInfo info;
+            info.m_assetId = product.GetAsset().GetId();
+            info.m_assetType = product.GetAssetType();
+            info.m_relativePath = product.GetId();
+
+            AZ::Data::AssetCatalogRequestBus::Broadcast(
+                &AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, info.m_assetId, info);
+            spawnableAssetData.m_assets.emplace_back(product.ReleaseAsset().release(), AZ::Data::AssetLoadBehavior::Default);
+
+            // Ensure the product asset is registered with the AssetManager
+            // Hold on to the returned asset to keep ref count alive until we assign it the latest data
+            AZ::Data::Asset<AZ::Data::AssetData> asset =
+                AZ::Data::AssetManager::Instance().FindOrCreateAsset(info.m_assetId, info.m_assetType, AZ::Data::AssetLoadBehavior::Default);
+
+            // Update the asset registered in the AssetManager with the data of our product from the Prefab Processor
+            AZ::Data::AssetManager::Instance().AssignAssetData(spawnableAssetData.m_assets.back());
+        }
+
+        if (targetSpawnableIndex == NoTargetSpawnable)
+        {
+            return AZ::Failure(AZStd::string::format("Failed to produce the target spawnable '%.*s'.", AZ_STRING_ARG(spawnableName)));
+        }
+        
+        if (loadReferencedAssets)
+        {
+            for (auto& product : context.GetProcessedObjects())
+            {
+                LoadReferencedAssets(product.GetReferencedAssets());
+            }
+        }
+
+        auto& spawnableAssetDataAdded = m_spawnableAssets.emplace(spawnableName, spawnableAssetData).first->second;
+        spawnableAssetDataAdded.m_spawnableAssetId = spawnableAssetDataAdded.m_assets[targetSpawnableIndex].GetId();
+        return AZ::Success(spawnableAssetDataAdded.m_assets[targetSpawnableIndex]);
+    }
+
+    InMemorySpawnableAssetContainer::CreateSpawnableResult InMemorySpawnableAssetContainer::CreateInMemorySpawnableAsset(
+        AZStd::string_view prefabFilePath, AZStd::string_view spawnableName, bool loadReferencedAssets)
+    {
+        AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(prefabFilePath);
+        auto templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
+        if (templateId == InvalidTemplateId)
+        {
+            return AZ::Failure(AZStd::string::format("Template with source path '%.*s' is not found.", AZ_STRING_ARG(prefabFilePath)));
+        }
+
+        return CreateInMemorySpawnableAsset(templateId, spawnableName, loadReferencedAssets);
+    }
+
+    void InMemorySpawnableAssetContainer::ClearAllInMemorySpawnableAssets()
+    {
+        for (auto& [spawnableName, spawnableAssetData] : m_spawnableAssets)
+        {
+            for (auto& asset : spawnableAssetData.m_assets)
+            {
+                asset.Release();
+                AZ::Data::AssetCatalogRequestBus::Broadcast(
+                    &AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset.GetId());
+            }
+        }
+        
+        m_spawnableAssets.clear();
+    }
+
+    InMemorySpawnableAssetContainer::SpawnableAssets&& InMemorySpawnableAssetContainer::MoveAllInMemorySpawnableAssets()
+    {
+        return AZStd::move(m_spawnableAssets);
+    }
+
+    const InMemorySpawnableAssetContainer::SpawnableAssets& InMemorySpawnableAssetContainer::GetAllInMemorySpawnableAssets() const
+    {
+        return m_spawnableAssets;
+    }
+
+    void InMemorySpawnableAssetContainer::LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets)
+    {
+        // Start our loads on all assets by calling GetAsset from the AssetManager
+        for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
+        {
+            if (!asset.GetId().IsValid())
+            {
+                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
+                continue;
+            }
+
+            const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
+
+            if (loadBehavior == AZ::Data::AssetLoadBehavior::NoLoad)
+            {
+                continue;
+            }
+
+            AZ::Data::AssetId assetId = asset.GetId();
+            AZ::Data::AssetType assetType = asset.GetType();
+
+            asset = AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, loadBehavior);
+
+            if (!asset.GetId().IsValid())
+            {
+                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
+                continue;
+            }
+        }
+
+        // For all Preload assets we block until they're ready
+        // We do this as a separate pass so that we don't interrupt queuing up all other asset loads
+        for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
+        {
+            if (!asset.GetId().IsValid())
+            {
+                AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
+                continue;
+            }
+
+            const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
+
+            if (loadBehavior != AZ::Data::AssetLoadBehavior::PreLoad)
+            {
+                continue;
+            }
+
+            asset.BlockUntilLoadComplete();
+
+            if (asset.IsError())
+            {
+                AZ_Error("Prefab", false, "Asset with id %s failed to preload while entering game mode",
+                    asset.GetId().ToString<AZStd::string>().c_str());
+
+                continue;
+            }
+        }
+    }
+
+} // namespace AzToolsFramework::Prefab::PrefabConversionUtils

+ 69 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h

@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/std/containers/vector.h>
+#include <AzCore/std/string/string_view.h>
+#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
+
+namespace AzToolsFramework::Prefab
+{
+    class PrefabSystemComponentInterface;
+    class PrefabLoaderInterface;
+}
+
+namespace AzToolsFramework::Prefab::PrefabConversionUtils
+{
+
+    class InMemorySpawnableAssetContainer
+    {
+    public:
+        AZ_CLASS_ALLOCATOR(InMemorySpawnableAssetContainer, AZ::SystemAllocator, 0);
+
+        using Assets = AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>;
+        using CreateSpawnableResult = AZ::Outcome<AZ::Data::Asset<AZ::Data::AssetData>&, AZStd::string>;
+        using RemoveSpawnableResult = AZ::Outcome<void, AZStd::string>;
+
+        struct SpawnableAssetData
+        {
+            Assets m_assets;
+            AZ::Data::AssetId m_spawnableAssetId;
+        };
+        using SpawnableAssets = AZStd::unordered_map<AZStd::string, SpawnableAssetData>;
+
+        ~InMemorySpawnableAssetContainer();
+
+        bool Activate(AZStd::string_view stackProfile);
+        void Deactivate();
+        bool IsActivated() const;
+        AZStd::string_view GetStockProfile() const;
+
+        CreateSpawnableResult CreateInMemorySpawnableAsset(
+            AZStd::string_view prefabFilePath, AZStd::string_view spawnableName, bool loadReferencedAssets = false);
+        CreateSpawnableResult CreateInMemorySpawnableAsset(
+            AzToolsFramework::Prefab::TemplateId templateId, AZStd::string_view spawnableName, bool loadReferencedAssets = false);
+        RemoveSpawnableResult RemoveInMemorySpawnableAsset(AZStd::string_view spawnableName);
+        AZ::Data::AssetId GetInMemorySpawnableAssetId(AZStd::string_view spawnableName) const;
+        bool HasInMemorySpawnableAsset(AZStd::string_view spawnableName) const;
+
+        void ClearAllInMemorySpawnableAssets();
+        SpawnableAssets&& MoveAllInMemorySpawnableAssets();
+        const SpawnableAssets& GetAllInMemorySpawnableAssets() const;
+
+    private:
+        void LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
+
+        SpawnableAssets m_spawnableAssets;
+        PrefabConversionUtils::PrefabConversionPipeline m_converter;
+        AZStd::string_view m_stockProfile;
+        PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
+        PrefabLoaderInterface* m_loaderInterface = nullptr;
+    };
+} // namespace AzToolsFramework::Prefab::PrefabConversionUtils

+ 20 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabConverterStackProfileNames.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/Serialization/Json/JsonSerialization.h>
+#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
+
+namespace AzToolsFramework::Prefab::PrefabConversionUtils
+{
+    inline static constexpr AZStd::string_view PlayInEditor = "PlayInEditor";
+    inline static constexpr AZStd::string_view IntegrationTests = "IntegrationTests";
+
+} // namespace AzToolsFramework::Prefab::PrefabConversionUtils

+ 3 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake

@@ -720,10 +720,13 @@ set(FILES
     Prefab/Spawnable/EditorOnlyEntityHandler/UiEditorOnlyEntityHandler.cpp
     Prefab/Spawnable/EditorOnlyEntityHandler/UiEditorOnlyEntityHandler.cpp
     Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.h
     Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.h
     Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.cpp
     Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.cpp
+    Prefab/Spawnable/InMemorySpawnableAssetContainer.h
+    Prefab/Spawnable/InMemorySpawnableAssetContainer.cpp
     Prefab/Spawnable/PrefabCatchmentProcessor.h
     Prefab/Spawnable/PrefabCatchmentProcessor.h
     Prefab/Spawnable/PrefabCatchmentProcessor.cpp
     Prefab/Spawnable/PrefabCatchmentProcessor.cpp
     Prefab/Spawnable/PrefabConversionPipeline.h
     Prefab/Spawnable/PrefabConversionPipeline.h
     Prefab/Spawnable/PrefabConversionPipeline.cpp
     Prefab/Spawnable/PrefabConversionPipeline.cpp
+    Prefab/Spawnable/PrefabConverterStackProfileNames.h
     Prefab/Spawnable/ProcesedObjectStore.h
     Prefab/Spawnable/ProcesedObjectStore.h
     Prefab/Spawnable/ProcesedObjectStore.cpp
     Prefab/Spawnable/ProcesedObjectStore.cpp
     Prefab/Spawnable/PrefabProcessor.h
     Prefab/Spawnable/PrefabProcessor.h

+ 27 - 21
Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp

@@ -277,22 +277,25 @@ namespace Multiplayer
         }
         }
 
 
         // BeginGameMode and Prefab Processing have completed at this point
         // BeginGameMode and Prefab Processing have completed at this point
-        const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& assetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData();
+        const auto& allAssetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData();
         
         
         AZStd::vector<uint8_t> buffer;
         AZStd::vector<uint8_t> buffer;
         AZ::IO::ByteContainerStream byteStream(&buffer);
         AZ::IO::ByteContainerStream byteStream(&buffer);
 
 
         // Serialize Asset information and AssetData into a potentially large buffer
         // Serialize Asset information and AssetData into a potentially large buffer
-        for (const auto& asset : assetData)
+        for (auto& [spawnableName, spawnableAssetData] : allAssetData)
         {
         {
-            AZ::Data::AssetId assetId = asset.GetId();
-            AZStd::string assetHint = asset.GetHint();
-            uint32_t hintSize = aznumeric_cast<uint32_t>(assetHint.size());
-
-            byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast<void*>(&assetId));
-            byteStream.Write(sizeof(uint32_t), reinterpret_cast<void*>(&hintSize));
-            byteStream.Write(assetHint.size(), assetHint.data());
-            AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, asset.GetData(), asset.GetData()->GetType());
+            for (auto& asset : spawnableAssetData.m_assets)
+            {
+                AZ::Data::AssetId assetId = asset.GetId();
+                AZStd::string assetHint = asset.GetHint();
+                uint32_t hintSize = aznumeric_cast<uint32_t>(assetHint.size());
+
+                byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast<void*>(&assetId));
+                byteStream.Write(sizeof(uint32_t), reinterpret_cast<void*>(&hintSize));
+                byteStream.Write(assetHint.size(), assetHint.data());
+                AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, asset.GetData(), asset.GetData()->GetType());
+            }
         }
         }
 
 
         const AZ::CVarFixedString remoteAddress = editorsv_serveraddr;
         const AZ::CVarFixedString remoteAddress = editorsv_serveraddr;
@@ -364,24 +367,27 @@ namespace Multiplayer
 
 
         AZ_Printf("MultiplayerEditor", "Editor is sending the editor-server the level data packet.")
         AZ_Printf("MultiplayerEditor", "Editor is sending the editor-server the level data packet.")
 
 
-        const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& assetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData();
+        const auto& allAssetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData();
 
 
         AZStd::vector<uint8_t> buffer;
         AZStd::vector<uint8_t> buffer;
         AZ::IO::ByteContainerStream byteStream(&buffer);
         AZ::IO::ByteContainerStream byteStream(&buffer);
 
 
         // Serialize Asset information and AssetData into a potentially large buffer
         // Serialize Asset information and AssetData into a potentially large buffer
-        for (const auto& asset : assetData)
+        for (auto& [spawnableName, spawnableAssetData] : allAssetData)
         {
         {
-            AZ::Data::AssetId assetId = asset.GetId();
-            AZStd::string assetHint = asset.GetHint();
-            auto hintSize = aznumeric_cast<uint32_t>(assetHint.size());
-
-            byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast<void*>(&assetId));
-            byteStream.Write(sizeof(uint32_t), reinterpret_cast<void*>(&hintSize));
-            byteStream.Write(assetHint.size(), assetHint.data());
-            AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, asset.GetData(), asset.GetData()->GetType());
+            for (auto& asset : spawnableAssetData.m_assets)
+            {
+                AZ::Data::AssetId assetId = asset.GetId();
+                AZStd::string assetHint = asset.GetHint();
+                auto hintSize = aznumeric_cast<uint32_t>(assetHint.size());
+
+                byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast<void*>(&assetId));
+                byteStream.Write(sizeof(uint32_t), reinterpret_cast<void*>(&hintSize));
+                byteStream.Write(assetHint.size(), assetHint.data());
+                AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, asset.GetData(), asset.GetData()->GetType());
+            }
         }
         }
-
+        
         // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets
         // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets
         AZ::Interface<INetworkSpawnableLibrary>::Get()->BuildSpawnablesList();
         AZ::Interface<INetworkSpawnableLibrary>::Get()->BuildSpawnablesList();
 
 

+ 21 - 0
Registry/prefab.test.setreg

@@ -0,0 +1,21 @@
+{
+    "Amazon":
+    {
+        "Tools":
+        {
+            "Prefab":
+            {
+                "Processing":
+                {
+                    "Stack": {
+                        "IntegrationTests": 
+                        [
+                            { "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover" },
+                            { "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor" }
+                        ]
+                    }
+                }
+            }
+        }
+    }
+}

+ 8 - 2
Tools/LyTestTools/ly_test_tools/o3de/editor_test.py

@@ -43,6 +43,8 @@ import types
 import functools
 import functools
 import re
 import re
 
 
+from os import path
+
 import ly_test_tools.environment.file_system as file_system
 import ly_test_tools.environment.file_system as file_system
 import ly_test_tools.environment.waiter as waiter
 import ly_test_tools.environment.waiter as waiter
 import ly_test_tools.environment.process_utils as process_utils
 import ly_test_tools.environment.process_utils as process_utils
@@ -745,7 +747,9 @@ class EditorTestSuite():
         if test_spec.wait_for_debugger:
         if test_spec.wait_for_debugger:
             test_cmdline_args += ["--wait-for-debugger"]
             test_cmdline_args += ["--wait-for-debugger"]
         if self.enable_prefab_system:
         if self.enable_prefab_system:
-            test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]
+            test_cmdline_args += [
+                "--regset=/Amazon/Preferences/EnablePrefabSystem=true",
+                f"--regset-file={path.join(workspace.paths.engine_root(), 'Registry', 'prefab.test.setreg')}"]
         else:
         else:
             test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
             test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
 
 
@@ -812,7 +816,9 @@ class EditorTestSuite():
         if any([t.wait_for_debugger for t in test_spec_list]):
         if any([t.wait_for_debugger for t in test_spec_list]):
             test_cmdline_args += ["--wait-for-debugger"]
             test_cmdline_args += ["--wait-for-debugger"]
         if self.enable_prefab_system:
         if self.enable_prefab_system:
-            test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]
+            test_cmdline_args += [
+                "--regset=/Amazon/Preferences/EnablePrefabSystem=true",
+                f"--regset-file={path.join(workspace.paths.engine_root(), 'Registry', 'prefab.test.setreg')}"]
         else:
         else:
             test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
             test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
 
 

+ 9 - 0
Tools/LyTestTools/tests/unit/test_o3de_editor_test.py

@@ -594,6 +594,7 @@ class TestRunningTests(unittest.TestCase):
                                                      mock_get_output_results, mock_create):
                                                      mock_get_output_results, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec.__name__ = 'mock_test_name'
         mock_test_spec.__name__ = 'mock_test_name'
@@ -620,6 +621,7 @@ class TestRunningTests(unittest.TestCase):
                                                      mock_get_output_results, mock_create):
                                                      mock_get_output_results, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec.__name__ = 'mock_test_name'
         mock_test_spec.__name__ = 'mock_test_name'
@@ -647,6 +649,7 @@ class TestRunningTests(unittest.TestCase):
                                                      mock_get_output_results, mock_retrieve_crash, mock_create):
                                                      mock_get_output_results, mock_retrieve_crash, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec.__name__ = 'mock_test_name'
         mock_test_spec.__name__ = 'mock_test_name'
@@ -674,6 +677,7 @@ class TestRunningTests(unittest.TestCase):
                                                      mock_get_output_results, mock_create):
                                                      mock_get_output_results, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
         mock_test_spec.__name__ = 'mock_test_name'
         mock_test_spec.__name__ = 'mock_test_name'
@@ -699,6 +703,7 @@ class TestRunningTests(unittest.TestCase):
                                                             mock_retrieve_log, mock_retrieve_editor_log, mock_create):
                                                             mock_retrieve_log, mock_retrieve_editor_log, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_editor.get_returncode.return_value = 0
         mock_editor.get_returncode.return_value = 0
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
@@ -726,6 +731,7 @@ class TestRunningTests(unittest.TestCase):
                                                            mock_retrieve_log, mock_retrieve_editor_log, mock_get_results):
                                                            mock_retrieve_log, mock_retrieve_editor_log, mock_get_results):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_editor.get_returncode.return_value = 15
         mock_editor.get_returncode.return_value = 15
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
@@ -751,6 +757,7 @@ class TestRunningTests(unittest.TestCase):
                                                                  mock_get_results, mock_retrieve_crash, mock_create):
                                                                  mock_get_results, mock_retrieve_crash, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_editor.get_returncode.return_value = 1
         mock_editor.get_returncode.return_value = 1
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
@@ -785,6 +792,7 @@ class TestRunningTests(unittest.TestCase):
                                                                    mock_get_results, mock_retrieve_crash, mock_create):
                                                                    mock_get_results, mock_retrieve_crash, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_editor.get_returncode.return_value = 1
         mock_editor.get_returncode.return_value = 1
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()
@@ -821,6 +829,7 @@ class TestRunningTests(unittest.TestCase):
                                                                 mock_get_results, mock_create):
                                                                 mock_get_results, mock_create):
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
         mock_workspace = mock.MagicMock()
         mock_workspace = mock.MagicMock()
+        mock_workspace.paths.engine_root.return_value = ""
         mock_editor = mock.MagicMock()
         mock_editor = mock.MagicMock()
         mock_editor.wait.side_effect = ly_test_tools.launchers.exceptions.WaitTimeoutError()
         mock_editor.wait.side_effect = ly_test_tools.launchers.exceptions.WaitTimeoutError()
         mock_test_spec = mock.MagicMock()
         mock_test_spec = mock.MagicMock()