Convert prefab to temp spawnable assets (#6179)
* Convert prefab to temp in-memory spawnable assets Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com>
This commit is contained in:
+4
-1
@@ -58,7 +58,10 @@ def launch_and_validate_results(request, test_directory, editor, editor_script,
|
||||
if null_renderer:
|
||||
editor.args.extend(["-rhi=Null"])
|
||||
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:
|
||||
editor.args.extend(["--regset=/Amazon/Preferences/EnablePrefabSystem=false"])
|
||||
|
||||
|
||||
-1
@@ -39,7 +39,6 @@ def get_prefab_file_path(prefab_path):
|
||||
prefab_path = name + ".prefab"
|
||||
return prefab_path
|
||||
|
||||
|
||||
def get_all_entity_ids():
|
||||
return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import sys
|
||||
import pytest
|
||||
import time
|
||||
|
||||
from os import path
|
||||
|
||||
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.waiter as waiter
|
||||
@@ -98,7 +100,9 @@ class TestAutomationBase:
|
||||
if autotest_mode:
|
||||
pycmd += ["-autotest_mode"]
|
||||
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:
|
||||
pycmd += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
|
||||
|
||||
|
||||
+9
-3
@@ -51,19 +51,22 @@ def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude():
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.prefab as prefab
|
||||
|
||||
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 editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
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
|
||||
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
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
|
||||
+8
-3
@@ -32,7 +32,9 @@ def AltitudeFilter_FilterStageToggle():
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.prefab as prefab
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
|
||||
@@ -44,13 +46,16 @@ def AltitudeFilter_FilterStageToggle():
|
||||
|
||||
# Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
helper.open_level("", "Base")
|
||||
general.set_current_view_position(512.0, 480.0, 38.0)
|
||||
|
||||
# Create basic vegetation entity
|
||||
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
|
||||
vegetation.add_component("Vegetation Altitude Filter")
|
||||
|
||||
+6
-3
@@ -57,7 +57,7 @@ def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude():
|
||||
|
||||
# 1) Open an existing simple level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "Base")
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Set view of planting area for visual debugging
|
||||
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
|
||||
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
|
||||
spawner_entity.add_component("Vegetation Altitude Filter")
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea():
|
||||
|
||||
# 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
|
||||
# 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.add_component("Vegetation Asset List Combiner")
|
||||
spawner_entity.add_component("Vegetation Asset Weight Selector")
|
||||
|
||||
+2
-2
@@ -67,8 +67,8 @@ def AssetWeightSelector_InstancesExpressBasedOnWeight():
|
||||
# valid slice entity, and one set to None
|
||||
spawner_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", 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],
|
||||
"Configuration|Embedded Assets")[0]
|
||||
desc_list = [desc_asset, desc_asset]
|
||||
|
||||
+2
-2
@@ -72,8 +72,8 @@ def DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius():
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
|
||||
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
|
||||
surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ def DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius():
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
|
||||
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
|
||||
surface_center_point = math.Vector3(512.0, 512.0, 32.0)
|
||||
|
||||
+1
-1
@@ -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
|
||||
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, 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")
|
||||
instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
|
||||
instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ def InstanceSpawnerPriority_LayerAndSubPriority():
|
||||
# 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
|
||||
spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
|
||||
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_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
|
||||
|
||||
|
||||
+8
-8
@@ -86,17 +86,17 @@ def LayerBlender_E2E_Editor():
|
||||
# 2) Create 2 vegetation areas with different meshes
|
||||
purple_position = math.Vector3(504.0, 512.0, 32.0)
|
||||
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_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)
|
||||
dynveg.create_surface_entity("Surface Entity",
|
||||
|
||||
+2
-2
@@ -68,8 +68,8 @@ def LayerBlocker_InstancesBlockedInConfiguredArea():
|
||||
# 2) Create a new instance spawner entity
|
||||
spawner_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", 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
|
||||
dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ def LayerSpawner_FilterStageToggle():
|
||||
# Create a vegetation area with all needed components
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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 Position Modifier")
|
||||
|
||||
|
||||
+4
-4
@@ -62,10 +62,10 @@ def LayerSpawner_InstancesPlantInAllSupportedShapes():
|
||||
# 2) Create basic vegetation area entity and set the properties
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
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.add_component("Shape Reference")
|
||||
|
||||
|
||||
+4
-4
@@ -101,10 +101,10 @@ def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera():
|
||||
|
||||
# Create the two vegetation areas
|
||||
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
|
||||
general.set_active_viewport(0)
|
||||
|
||||
+4
-4
@@ -59,10 +59,10 @@ def MeshBlocker_InstancesBlockedByMesh():
|
||||
# Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
|
||||
|
||||
+4
-4
@@ -62,10 +62,10 @@ def MeshBlocker_InstancesBlockedByMeshHeightTuning():
|
||||
# 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ def PhysXColliderSurfaceTagEmitter_E2E_Editor():
|
||||
|
||||
# Create a new entity with required vegetation area components
|
||||
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
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
|
||||
+2
-2
@@ -74,8 +74,8 @@ def PositionModifier_AutoSnapToSurfaceWorks():
|
||||
# 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)
|
||||
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
|
||||
spawner_entity.add_component("Vegetation Position Modifier")
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ def PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets():
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
|
||||
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
|
||||
spawner_entity.add_component("Vegetation Position Modifier")
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ def RotationModifierOverrides_InstancesRotateWithinRange():
|
||||
# 2) Create vegetation entity and add components
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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")
|
||||
# Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
|
||||
num_expected = 20 * 20
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ def RotationModifier_InstancesRotateWithinRange():
|
||||
|
||||
# 2) Set up vegetation entities
|
||||
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 = [
|
||||
"Vegetation Rotation Modifier"
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ def ScaleModifierOverrides_InstancesProperlyScale():
|
||||
# 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)
|
||||
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
|
||||
dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
|
||||
|
||||
+2
-2
@@ -94,8 +94,8 @@ def ScaleModifier_InstancesProperlyScale():
|
||||
# Vegetation Scale Modifier
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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")
|
||||
|
||||
# Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ def ShapeIntersectionFilter_FilterStageToggle():
|
||||
# Create basic vegetation entity
|
||||
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)
|
||||
vegetation = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
|
||||
|
||||
# Create Surface for instances to plant on
|
||||
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ def ShapeIntersectionFilter_InstancesPlantInAssignedShape():
|
||||
# 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)
|
||||
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")
|
||||
|
||||
# Create a planting surface
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ def SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment():
|
||||
# Create a spawner entity setup with all needed components
|
||||
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, 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
|
||||
center_point = math.Vector3(502.0, 512.0, 24.0)
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ def SlopeAlignmentModifier_InstanceSurfaceAlignment():
|
||||
# Create a spawner entity setup with all needed components
|
||||
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, 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
|
||||
center_point = math.Vector3(502.0, 512.0, 24.0)
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ def SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes():
|
||||
# 2) Create a new entity with required vegetation area components
|
||||
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)
|
||||
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
|
||||
spawner_entity.add_component("Vegetation Slope Filter")
|
||||
|
||||
+2
-2
@@ -66,7 +66,7 @@ def SpawnerSlices_SliceCreationAndVisibilityToggleWorks():
|
||||
# 2.1) Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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
|
||||
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.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
|
||||
components_to_add = ["Box Shape", "Vegetation Layer Blender"]
|
||||
|
||||
+2
-2
@@ -77,8 +77,8 @@ def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected():
|
||||
# 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)
|
||||
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]
|
||||
desc_asset = hydra.get_component_property_value(asset_list_component,
|
||||
"Configuration|Embedded Assets")[0]
|
||||
|
||||
+4
-4
@@ -99,10 +99,10 @@ def SurfaceMaskFilter_ExclusionList():
|
||||
# 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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.
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
|
||||
+4
-4
@@ -100,10 +100,10 @@ def SurfaceMaskFilter_InclusionList():
|
||||
# 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
|
||||
entity_position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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.
|
||||
spawner_entity.add_component("Vegetation Surface Mask Filter")
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ def SystemSettings_SectorPointDensity():
|
||||
# Create basic vegetation entity
|
||||
position = math.Vector3(512.0, 512.0, 32.0)
|
||||
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)
|
||||
|
||||
# Count the number of vegetation instances in the vegetation area
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ def SystemSettings_SectorSize():
|
||||
# Create basic vegetation entity
|
||||
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, 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)
|
||||
|
||||
# Add the Vegetation Debugger component to the Level Inspector
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ def VegetationInstances_DespawnWhenOutOfRange():
|
||||
# Create vegetation layer spawner
|
||||
world_center = math.Vector3(512.0, 512.0, 32.0)
|
||||
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
|
||||
dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0)
|
||||
|
||||
@@ -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("project", ["AutomatedTesting"])
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.SUITE_main
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation_PrefabNotEnabled(EditorTestSuite):
|
||||
|
||||
enable_prefab_system = False
|
||||
|
||||
@@ -36,19 +50,10 @@ class TestAutomation(EditorTestSuite):
|
||||
class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorParallelTest):
|
||||
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):
|
||||
# Custom teardown to remove slice asset created during test
|
||||
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
|
||||
|
||||
class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorParallelTest):
|
||||
@@ -161,27 +166,27 @@ class TestAutomation(EditorTestSuite):
|
||||
|
||||
# Custom setup/teardown to remove test level created during test
|
||||
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):
|
||||
TestAutomation.cleanup_test_level(self, workspace)
|
||||
TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
|
||||
|
||||
class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest):
|
||||
from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
|
||||
|
||||
# Custom setup/teardown to remove test level created during test
|
||||
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):
|
||||
TestAutomation.cleanup_test_level(self, workspace)
|
||||
TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
|
||||
|
||||
class test_LayerBlender_E2E_Editor(EditorSingleTest):
|
||||
from .EditorScripts import LayerBlender_E2E_Editor as test_module
|
||||
|
||||
# Custom setup/teardown to remove test level created during test
|
||||
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):
|
||||
TestAutomation.cleanup_test_level(self, workspace)
|
||||
TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace)
|
||||
|
||||
@@ -52,15 +52,15 @@ class TestAutomation(TestAutomationBase):
|
||||
|
||||
def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
|
||||
|
||||
+40
-4
@@ -8,14 +8,16 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.components as components
|
||||
import azlmbr.math as math
|
||||
import azlmbr.vegetation as vegetation
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.paths
|
||||
import azlmbr.prefab as prefab
|
||||
import azlmbr.vegetation as vegetation
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
spawner_entity = hydra.Entity(name)
|
||||
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))
|
||||
|
||||
# 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.SetSliceAssetPath(dynamic_slice_asset_path)
|
||||
descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
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):
|
||||
# Create a Vegetation Layer Blocker area
|
||||
blocker_entity = hydra.Entity(name)
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -47,7 +48,7 @@ namespace AzToolsFramework
|
||||
|
||||
//! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
|
||||
//! /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 SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
|
||||
|
||||
+45
-166
@@ -25,6 +25,7 @@
|
||||
#include <AzToolsFramework/Prefab/PrefabLoader.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabUndoHelpers.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabConverterStackProfileNames.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -379,9 +380,9 @@ namespace AzToolsFramework
|
||||
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)
|
||||
@@ -405,65 +406,6 @@ namespace AzToolsFramework
|
||||
m_validateEntitiesCallback = AZStd::move(validateEntitiesCallback);
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::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 seperate 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::StartPlayInEditor()
|
||||
{
|
||||
// This is a workaround until the replacement for GameEntityContext is done
|
||||
@@ -471,110 +413,48 @@ namespace AzToolsFramework
|
||||
|
||||
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())
|
||||
// Construct the runtime entities and products
|
||||
bool readyToCreateRootSpawnable = m_playInEditorData.m_assetsCache.IsActivated();
|
||||
if (!readyToCreateRootSpawnable &&
|
||||
!m_playInEditorData.m_assetsCache.Activate(Prefab::PrefabConversionUtils::PlayInEditor))
|
||||
{
|
||||
bool converterLoaded = m_playInEditorData.m_converter.IsLoaded();
|
||||
if (!converterLoaded)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
AZ_Error("Prefab", false, "Failed to create a prefab processing stack from key '%.*s'.", AZ_STRING_ARG(Prefab::PrefabConversionUtils::PlayInEditor));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_playInEditorData.m_isEnabled = true;
|
||||
auto createRootSpawnableResult = m_playInEditorData.m_assetsCache.CreateInMemorySpawnableAsset(m_rootInstance->GetTemplateId(), DefaultMainSpawnableName, true);
|
||||
if (createRootSpawnableResult.IsSuccess())
|
||||
{
|
||||
// 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();
|
||||
|
||||
m_playInEditorData.m_entities.Reset(createRootSpawnableResult.GetValue());
|
||||
m_playInEditorData.m_entities.SpawnAllEntities();
|
||||
|
||||
// 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 create the root spawnable due to the error: '%.*s'", AZ_STRING_ARG(createRootSpawnableResult.GetError()));
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::StopPlayInEditor()
|
||||
@@ -588,7 +468,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_playInEditorData.m_entities.DespawnAllEntities();
|
||||
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
|
||||
{
|
||||
auto end = deactivatedEntities.rend();
|
||||
@@ -598,11 +478,10 @@ namespace AzToolsFramework
|
||||
(*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();
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::UnregisterAsset, asset.GetId());
|
||||
|
||||
+4
-7
@@ -14,7 +14,7 @@
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesContainer.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -176,8 +176,7 @@ namespace AzToolsFramework
|
||||
private:
|
||||
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;
|
||||
AzFramework::SpawnableEntitiesContainer m_entities;
|
||||
bool m_isEnabled{ false };
|
||||
@@ -195,14 +194,12 @@ namespace AzToolsFramework
|
||||
|
||||
Prefab::InstanceOptionalReference GetRootPrefabInstance() 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 LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
|
||||
|
||||
OnEntitiesAddedCallback m_entitiesAddedCallback;
|
||||
OnEntitiesRemovedCallback m_entitiesRemovedCallback;
|
||||
ValidateEntitiesCallback m_validateEntitiesCallback;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
@@ -27,6 +28,7 @@ namespace AzToolsFramework
|
||||
using InstantiatePrefabResult = AZ::Outcome<AZ::EntityId, AZStd::string>;
|
||||
using DuplicatePrefabResult = AZ::Outcome<EntityIdList, 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.
|
||||
@@ -93,6 +95,34 @@ namespace AzToolsFramework
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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>;
|
||||
|
||||
+73
-4
@@ -8,10 +8,16 @@
|
||||
|
||||
#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 <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 Prefab
|
||||
@@ -31,13 +37,18 @@ namespace AzToolsFramework
|
||||
->Event("DetachPrefab", &PrefabPublicRequests::DetachPrefab)
|
||||
->Event("DuplicateEntitiesInInstance", &PrefabPublicRequests::DuplicateEntitiesInInstance)
|
||||
->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()
|
||||
{
|
||||
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
|
||||
m_prefabPublicInterface = AZ::Interface<PrefabPublicInterface>::Get();
|
||||
AZ_Assert(m_prefabPublicInterface, "PrefabPublicRequestHandler - Could not retrieve instance of PrefabPublicInterface");
|
||||
|
||||
PrefabPublicRequestBus::Handler::BusConnect();
|
||||
@@ -46,7 +57,7 @@ namespace AzToolsFramework
|
||||
void PrefabPublicRequestHandler::Disconnect()
|
||||
{
|
||||
PrefabPublicRequestBus::Handler::BusDisconnect();
|
||||
|
||||
m_spawnableAssetContainer.Deactivate();
|
||||
m_prefabPublicInterface = nullptr;
|
||||
}
|
||||
|
||||
@@ -79,5 +90,63 @@ namespace AzToolsFramework
|
||||
{
|
||||
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 AzToolsFramework
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicRequestBus.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/InMemorySpawnableAssetContainer.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -37,9 +38,18 @@ namespace AzToolsFramework
|
||||
PrefabOperationResult DetachPrefab(const AZ::EntityId& containerEntityId) override;
|
||||
DuplicatePrefabResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) 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:
|
||||
bool TryActivateSpawnableAssetContainer();
|
||||
|
||||
PrefabConversionUtils::InMemorySpawnableAssetContainer m_spawnableAssetContainer;
|
||||
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+275
@@ -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,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,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
|
||||
@@ -720,10 +720,13 @@ set(FILES
|
||||
Prefab/Spawnable/EditorOnlyEntityHandler/UiEditorOnlyEntityHandler.cpp
|
||||
Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.h
|
||||
Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.cpp
|
||||
Prefab/Spawnable/InMemorySpawnableAssetContainer.h
|
||||
Prefab/Spawnable/InMemorySpawnableAssetContainer.cpp
|
||||
Prefab/Spawnable/PrefabCatchmentProcessor.h
|
||||
Prefab/Spawnable/PrefabCatchmentProcessor.cpp
|
||||
Prefab/Spawnable/PrefabConversionPipeline.h
|
||||
Prefab/Spawnable/PrefabConversionPipeline.cpp
|
||||
Prefab/Spawnable/PrefabConverterStackProfileNames.h
|
||||
Prefab/Spawnable/ProcesedObjectStore.h
|
||||
Prefab/Spawnable/ProcesedObjectStore.cpp
|
||||
Prefab/Spawnable/PrefabProcessor.h
|
||||
|
||||
@@ -277,22 +277,25 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
// 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;
|
||||
AZ::IO::ByteContainerStream byteStream(&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());
|
||||
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());
|
||||
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;
|
||||
@@ -364,24 +367,27 @@ namespace Multiplayer
|
||||
|
||||
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;
|
||||
AZ::IO::ByteContainerStream byteStream(&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());
|
||||
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());
|
||||
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
|
||||
AZ::Interface<INetworkSpawnableLibrary>::Get()->BuildSpawnablesList();
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"Amazon":
|
||||
{
|
||||
"Tools":
|
||||
{
|
||||
"Prefab":
|
||||
{
|
||||
"Processing":
|
||||
{
|
||||
"Stack": {
|
||||
"IntegrationTests":
|
||||
[
|
||||
{ "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover" },
|
||||
{ "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,8 @@ import types
|
||||
import functools
|
||||
import re
|
||||
|
||||
from os import path
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
import ly_test_tools.environment.waiter as waiter
|
||||
import ly_test_tools.environment.process_utils as process_utils
|
||||
@@ -745,7 +747,9 @@ class EditorTestSuite():
|
||||
if test_spec.wait_for_debugger:
|
||||
test_cmdline_args += ["--wait-for-debugger"]
|
||||
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:
|
||||
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]):
|
||||
test_cmdline_args += ["--wait-for-debugger"]
|
||||
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:
|
||||
test_cmdline_args += ["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]
|
||||
|
||||
|
||||
@@ -594,6 +594,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_get_output_results, mock_create):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_test_spec = mock.MagicMock()
|
||||
mock_test_spec.__name__ = 'mock_test_name'
|
||||
@@ -620,6 +621,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_get_output_results, mock_create):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_test_spec = mock.MagicMock()
|
||||
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_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_test_spec = mock.MagicMock()
|
||||
mock_test_spec.__name__ = 'mock_test_name'
|
||||
@@ -674,6 +677,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_get_output_results, mock_create):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_test_spec = mock.MagicMock()
|
||||
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_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_editor.get_returncode.return_value = 0
|
||||
mock_test_spec = mock.MagicMock()
|
||||
@@ -726,6 +731,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_retrieve_log, mock_retrieve_editor_log, mock_get_results):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_editor.get_returncode.return_value = 15
|
||||
mock_test_spec = mock.MagicMock()
|
||||
@@ -751,6 +757,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_get_results, mock_retrieve_crash, mock_create):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_editor.get_returncode.return_value = 1
|
||||
mock_test_spec = mock.MagicMock()
|
||||
@@ -785,6 +792,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_get_results, mock_retrieve_crash, mock_create):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_editor.get_returncode.return_value = 1
|
||||
mock_test_spec = mock.MagicMock()
|
||||
@@ -821,6 +829,7 @@ class TestRunningTests(unittest.TestCase):
|
||||
mock_get_results, mock_create):
|
||||
mock_test_suite = ly_test_tools.o3de.editor_test.EditorTestSuite()
|
||||
mock_workspace = mock.MagicMock()
|
||||
mock_workspace.paths.engine_root.return_value = ""
|
||||
mock_editor = mock.MagicMock()
|
||||
mock_editor.wait.side_effect = ly_test_tools.launchers.exceptions.WaitTimeoutError()
|
||||
mock_test_spec = mock.MagicMock()
|
||||
|
||||
Reference in New Issue
Block a user