merging latest dev + resolving 1 conflict
Signed-off-by: Gene Walters <genewalt@amazon.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<EngineDependencies versionnumber="1.0.0">
|
||||
<Dependency path="libs/particles/preloadlibs.txt" optional="true" />
|
||||
<Dependency path="libs/gameaudio/wwise/*.xml" optional="false" />
|
||||
<Dependency path=":libs/gameaudio/wwise/levels/default_controls.xml" optional="false" />
|
||||
</EngineDependencies>
|
||||
@@ -3,9 +3,15 @@
|
||||
"Version": 1,
|
||||
"ClassName": "GlobalBuildOptions",
|
||||
"ClassData": {
|
||||
"ShaderCompilerArguments" : {
|
||||
"DefaultMatrixOrder" : "Row",
|
||||
"AzslcAdditionalFreeArguments" : "--strip-unused-srgs"
|
||||
"ShaderCompilerArguments": {
|
||||
"DefaultMatrixOrder": "Row",
|
||||
"AzslcAdditionalFreeArguments": "--strip-unused-srgs"
|
||||
},
|
||||
"PreprocessorOptions": {
|
||||
"predefinedMacros": [ "AZSL=17" ],
|
||||
"projectIncludePaths": [
|
||||
"Gems/AtomTressFX/Assets/Shaders"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import os, traceback, binascii, sys, json, pathlib
|
||||
import azlmbr.math
|
||||
import azlmbr.bus
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def get_mesh_node_names(sceneGraph):
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
meshDataList = []
|
||||
node = sceneGraph.get_root()
|
||||
children = []
|
||||
paths = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
paths.append(nodeName.get_path())
|
||||
|
||||
# store any node that has mesh data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if nodeContent.CastWithTypeName('MeshData'):
|
||||
if sceneGraph.is_node_end_point(node) is False:
|
||||
if (len(nodeName.get_path())):
|
||||
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return meshDataList, paths
|
||||
|
||||
def update_manifest(scene):
|
||||
import json
|
||||
import uuid, os
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
graph = sceneData.SceneGraph(scene.graph)
|
||||
# Get a list of all the mesh nodes, as well as all the nodes
|
||||
mesh_name_list, all_node_paths = get_mesh_node_names(graph)
|
||||
scene_manifest = sceneData.SceneManifest()
|
||||
|
||||
clean_filename = scene.sourceFilename.replace('.', '_')
|
||||
|
||||
# Compute the filename of the scene file
|
||||
source_basepath = scene.watchFolder
|
||||
source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
|
||||
source_filename_only = os.path.basename(clean_filename)
|
||||
|
||||
created_entities = []
|
||||
|
||||
# Loop every mesh node in the scene
|
||||
for activeMeshIndex in range(len(mesh_name_list)):
|
||||
mesh_name = mesh_name_list[activeMeshIndex]
|
||||
mesh_path = mesh_name.get_path()
|
||||
# Create a unique mesh group name using the filename + node name
|
||||
mesh_group_name = '{}_{}'.format(source_filename_only, mesh_name.get_name())
|
||||
# Remove forbidden filename characters from the name since this will become a file on disk later
|
||||
mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
|
||||
# Add the MeshGroup to the manifest and give it a unique ID
|
||||
mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
|
||||
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
|
||||
# Set our current node as the only node that is included in this MeshGroup
|
||||
scene_manifest.mesh_group_select_node(mesh_group, mesh_path)
|
||||
|
||||
# Explicitly remove all other nodes to prevent implicit inclusions
|
||||
for node in all_node_paths:
|
||||
if node != mesh_path:
|
||||
scene_manifest.mesh_group_unselect_node(mesh_group, node)
|
||||
|
||||
# Create an editor entity
|
||||
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
|
||||
# Add an EditorMeshComponent to the entity
|
||||
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
|
||||
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
|
||||
# The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
|
||||
# The assetHint will be converted to an AssetId later during prefab loading
|
||||
json_update = json.dumps({
|
||||
"Controller": { "Configuration": { "ModelAsset": {
|
||||
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
|
||||
});
|
||||
# Apply the JSON above to the component we created
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("UpdateComponentForEntity failed")
|
||||
|
||||
# Keep track of the entity we set up, we'll add them all to the prefab we're creating later
|
||||
created_entities.append(entity_id)
|
||||
|
||||
# Create a prefab with all our entities
|
||||
prefab_filename = source_filename_only + ".prefab"
|
||||
created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", created_entities, prefab_filename)
|
||||
|
||||
if created_template_id == azlmbr.prefab.InvalidTemplateId:
|
||||
raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
|
||||
|
||||
# Convert the prefab to a JSON string
|
||||
output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
|
||||
|
||||
if output.IsSuccess():
|
||||
jsonString = output.GetValue()
|
||||
uuid = azlmbr.math.Uuid_CreateRandom().ToString()
|
||||
jsonResult = json.loads(jsonString)
|
||||
# Add a PrefabGroup to the manifest and store the JSON on it
|
||||
scene_manifest.add_prefab_group(source_filename_only, uuid, jsonResult)
|
||||
else:
|
||||
raise RuntimeError("SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
|
||||
|
||||
# Convert the manifest to a JSON string and return it
|
||||
new_manifest = scene_manifest.export()
|
||||
|
||||
return new_manifest
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except RuntimeError as err:
|
||||
print (f'ERROR - {err}')
|
||||
log_exception_traceback()
|
||||
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -21,9 +21,9 @@ set(ENABLED_GEMS
|
||||
QtForPython
|
||||
PythonAssetBuilder
|
||||
Metastream
|
||||
|
||||
Camera
|
||||
EMotionFX
|
||||
AtomTressFX
|
||||
PhysX
|
||||
CameraFramework
|
||||
StartingPointMovement
|
||||
@@ -52,10 +52,7 @@ set(ENABLED_GEMS
|
||||
AWSCore
|
||||
AWSClientAuth
|
||||
AWSMetrics
|
||||
|
||||
|
||||
|
||||
|
||||
PrefabBuilder
|
||||
AudioSystem
|
||||
Multiplayer
|
||||
)
|
||||
|
||||
@@ -65,4 +65,18 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main_GPU_Optimized
|
||||
TEST_SUITE main
|
||||
TEST_REQUIRES gpu
|
||||
TEST_SERIAL
|
||||
TIMEOUT 1200
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU_Optimized.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -226,9 +226,9 @@ class TestMaterialEditor(object):
|
||||
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args):
|
||||
"""
|
||||
Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor.
|
||||
Checks for the "Finished loading viewport configurtions." success message post lounch.
|
||||
Checks for the "Finished loading viewport configurations." success message post launch.
|
||||
"""
|
||||
expected_lines = ["Finished loading viewport configurtions."]
|
||||
expected_lines = ["Finished loading viewport configurations."]
|
||||
unexpected_lines = [
|
||||
# "Trace::Assert",
|
||||
# "Trace::Error",
|
||||
@@ -241,7 +241,7 @@ class TestMaterialEditor(object):
|
||||
generic_launcher,
|
||||
editor_script="",
|
||||
run_python="--runpython",
|
||||
timeout=30,
|
||||
timeout=60,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=False,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
|
||||
from .atom_utils.atom_component_helper import create_screenshots_archive, golden_images_directory
|
||||
|
||||
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
# Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests.
|
||||
global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"]
|
||||
|
||||
class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest):
|
||||
use_null_renderer = False # Default is True
|
||||
screenshot_name = "AtomBasicLevelSetup.ppm"
|
||||
test_screenshots = [] # Gets set by setup()
|
||||
screenshot_directory = "" # Gets set by setup()
|
||||
|
||||
# Clear existing test screenshots before starting test.
|
||||
def setup(self, workspace):
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)]
|
||||
file_system.delete(test_screenshots, True, True)
|
||||
|
||||
from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module
|
||||
|
||||
golden_images = [os.path.join(golden_images_directory(), screenshot_name)]
|
||||
for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
|
||||
compare_screenshots(test_screenshot, golden_screenshot)
|
||||
create_screenshots_archive(screenshot_directory)
|
||||
@@ -3,13 +3,54 @@ Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
File to assist with common hydra component functions used across various Atom tests.
|
||||
"""
|
||||
import datetime
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
|
||||
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
|
||||
def create_screenshots_archive(screenshot_path):
|
||||
"""
|
||||
Creates a new zip file archive at archive_path containing all files listed within archive_path.
|
||||
:param screenshot_path: location containing the files to archive, the zip archive file will also be saved here.
|
||||
:return: None, but creates a new zip file archive inside path containing all of the files inside archive_path.
|
||||
"""
|
||||
files_to_archive = []
|
||||
|
||||
# Search for .png and .ppm files to add to the zip archive file.
|
||||
for (folder_name, sub_folders, file_names) in os.walk(screenshot_path):
|
||||
for file_name in file_names:
|
||||
if file_name.endswith(".png") or file_name.endswith(".ppm"):
|
||||
file_path = os.path.join(folder_name, file_name)
|
||||
files_to_archive.append(file_path)
|
||||
|
||||
# Setup variables for naming the zip archive file.
|
||||
timestamp = datetime.datetime.now().timestamp()
|
||||
formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S")
|
||||
screenshots_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip')
|
||||
|
||||
# Write all of the valid .png and .ppm files to the archive file.
|
||||
with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
|
||||
for file_path in files_to_archive:
|
||||
file_name = os.path.basename(file_path)
|
||||
zip_archive.write(file_path, file_name)
|
||||
|
||||
|
||||
def golden_images_directory():
|
||||
"""
|
||||
Uses this file location to return the valid location for golden image files.
|
||||
:return: The path to the golden_images directory, but raises an IOError if the golden_images directory is missing.
|
||||
"""
|
||||
current_file_directory = os.path.join(os.path.dirname(__file__))
|
||||
golden_images_dir = os.path.join(current_file_directory, '..', 'golden_images')
|
||||
|
||||
if not os.path.exists(golden_images_dir):
|
||||
raise IOError(
|
||||
f'golden_images" directory was not found at path "{golden_images_dir}"'
|
||||
f'Please add a "golden_images" directory inside: "{current_file_directory}"'
|
||||
)
|
||||
|
||||
return golden_images_dir
|
||||
|
||||
|
||||
def create_basic_atom_level(level_name):
|
||||
@@ -31,6 +72,9 @@ def create_basic_atom_level(level_name):
|
||||
import azlmbr.object
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
|
||||
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
|
||||
|
||||
# Create a new level.
|
||||
new_level_name = level_name
|
||||
|
||||
@@ -211,7 +211,7 @@ class Timeout:
|
||||
return time.time() > self.die_after
|
||||
|
||||
|
||||
screenshotsFolder = os.path.join(azlmbr.paths.devroot, "AtomTest", "Cache" "pc", "Screenshots")
|
||||
screenshotsFolder = os.path.join(azlmbr.paths.products, "Screenshots")
|
||||
|
||||
|
||||
class ScreenshotHelper:
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.render as render
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.utils import TestHelper
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from Atom.atom_utils.atom_constants import LIGHT_TYPES
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
# fmt: off
|
||||
class Tests :
|
||||
camera_component_added = ("Camera component was added", "Camera component wasn't added")
|
||||
camera_fov_set = ("Camera component FOV property set", "Camera component FOV property wasn't set")
|
||||
directional_light_component_added = ("Directional Light component added", "Directional Light component wasn't added")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
global_skylight_component_added = ("Global Skylight (IBL) component added", "Global Skylight (IBL) component wasn't added")
|
||||
global_skylight_diffuse_image_set = ("Global Skylight Diffuse Image property set", "Global Skylight Diffuse Image property wasn't set")
|
||||
global_skylight_specular_image_set = ("Global Skylight Specular Image property set", "Global Skylight Specular Image property wasn't set")
|
||||
ground_plane_material_asset_set = ("Ground Plane Material Asset was set", "Ground Plane Material Asset wasn't set")
|
||||
ground_plane_material_component_added = ("Ground Plane Material component added", "Ground Plane Material component wasn't added")
|
||||
ground_plane_mesh_asset_set = ("Ground Plane Mesh Asset property was set", "Ground Plane Mesh Asset property wasn't set")
|
||||
hdri_skybox_component_added = ("HDRi Skybox component added", "HDRi Skybox component wasn't added")
|
||||
hdri_skybox_cubemap_texture_set = ("HDRi Skybox Cubemap Texture property set", "HDRi Skybox Cubemap Texture property wasn't set")
|
||||
mesh_component_added = ("Mesh component added", "Mesh component wasn't added")
|
||||
no_assert_occurred = ("No asserts detected", "Asserts were detected")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
secondary_grid_spacing = ("Secondary Grid Spacing set", "Secondary Grid Spacing not set")
|
||||
sphere_material_component_added = ("Sphere Material component added", "Sphere Material component wasn't added")
|
||||
sphere_material_set = ("Sphere Material Asset was set", "Sphere Material Asset wasn't set")
|
||||
sphere_mesh_asset_set = ("Sphere Mesh Asset was set", "Sphere Mesh Asset wasn't set")
|
||||
viewport_set = ("Viewport set to correct size", "Viewport not set to correct size")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomGPU_BasicLevelSetup_SetsUpLevel():
|
||||
"""
|
||||
Summary:
|
||||
Sets up a level to match the AtomBasicLevelSetup.ppm golden image then takes a screenshot to verify the setup.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The scene can be setup for a basic level.
|
||||
The test screenshot matches the appearance of the AtomBasicLevelSetup.ppm golden image.
|
||||
|
||||
Test Steps:
|
||||
1. Close error windows and display helpers then update the viewport size.
|
||||
2. Create Default Level Entity.
|
||||
3. Create Grid Entity as a child entity of the Default Level Entity.
|
||||
4. Add Grid component to Grid Entity and set Secondary Grid Spacing.
|
||||
5. Create Global Skylight (IBL) Entity as a child entity of the Default Level Entity.
|
||||
6. Add HDRi Skybox component to the Global Skylight (IBL) Entity.
|
||||
7. Add Global Skylight (IBL) component to the Global Skylight (IBL) Entity.
|
||||
8. Set the Cubemap Texture property of the HDRi Skybox component.
|
||||
9. Set the Diffuse Image property of the Global Skylight (IBL) component.
|
||||
10. Set the Specular Image property of the Global Skylight (IBL) component.
|
||||
11. Create a Ground Plane Entity with a Material component that is a child entity of the Default Level Entity.
|
||||
12. Set the Material Asset property of the Material component for the Ground Plane Entity.
|
||||
13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Mesh Asset property.
|
||||
14. Create a Directional Light Entity as a child entity of the Default Level Entity.
|
||||
15. Add Directional Light component to Directional Light Entity and set entity rotation.
|
||||
16. Create a Sphere Entity as a child entity of the Default Level Entity then add a Material component.
|
||||
17. Set the Material Asset property of the Material component for the Sphere Entity.
|
||||
18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component.
|
||||
19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component.
|
||||
20. Set the Camera Entity rotation value and set the Camera component Field of View value.
|
||||
21. Enter game mode.
|
||||
22. Take screenshot.
|
||||
23. Exit game mode.
|
||||
24. Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
from math import isclose
|
||||
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
from Atom.atom_utils.screenshot_utils import ScreenshotHelper
|
||||
|
||||
MATERIAL_COMPONENT_NAME = "Material"
|
||||
MESH_COMPONENT_NAME = "Mesh"
|
||||
SCREENSHOT_NAME = "AtomBasicLevelSetup"
|
||||
SCREEN_WIDTH = 1280
|
||||
SCREEN_HEIGHT = 720
|
||||
DEGREE_RADIAN_FACTOR = 0.0174533
|
||||
|
||||
def initial_viewport_setup(screen_width, screen_height):
|
||||
general.set_viewport_size(screen_width, screen_height)
|
||||
general.update_viewport()
|
||||
result = isclose(
|
||||
a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and isclose(
|
||||
a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1)
|
||||
|
||||
return result
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Close error windows and display helpers then update the viewport size.
|
||||
helper.close_error_windows()
|
||||
helper.close_display_helpers()
|
||||
general.update_viewport()
|
||||
Report.critical_result(Tests.viewport_set, initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT))
|
||||
|
||||
# 2. Create Default Level Entity.
|
||||
default_level_entity_name = "Default Level"
|
||||
default_level_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(0.0, 0.0, 0.0), default_level_entity_name)
|
||||
|
||||
# 3. Create Grid Entity as a child entity of the Default Level Entity.
|
||||
grid_name = "Grid"
|
||||
grid_entity = EditorEntity.create_editor_entity(grid_name, default_level_entity.id)
|
||||
|
||||
# 4. Add Grid component to Grid Entity and set Secondary Grid Spacing.
|
||||
grid_component = grid_entity.add_component(grid_name)
|
||||
secondary_grid_spacing_property = "Controller|Configuration|Secondary Grid Spacing"
|
||||
secondary_grid_spacing_value = 1.0
|
||||
grid_component.set_component_property_value(secondary_grid_spacing_property, secondary_grid_spacing_value)
|
||||
secondary_grid_spacing_set = grid_component.get_component_property_value(
|
||||
secondary_grid_spacing_property) == secondary_grid_spacing_value
|
||||
Report.result(Tests.secondary_grid_spacing, secondary_grid_spacing_set)
|
||||
|
||||
# 5. Create Global Skylight (IBL) Entity as a child entity of the Default Level Entity.
|
||||
global_skylight_name = "Global Skylight (IBL)"
|
||||
global_skylight_entity = EditorEntity.create_editor_entity(global_skylight_name, default_level_entity.id)
|
||||
|
||||
# 6. Add HDRi Skybox component to the Global Skylight (IBL) Entity.
|
||||
hdri_skybox_name = "HDRi Skybox"
|
||||
hdri_skybox_component = global_skylight_entity.add_component(hdri_skybox_name)
|
||||
Report.result(Tests.hdri_skybox_component_added, global_skylight_entity.has_component(hdri_skybox_name))
|
||||
|
||||
# 7. Add Global Skylight (IBL) component to the Global Skylight (IBL) Entity.
|
||||
global_skylight_component = global_skylight_entity.add_component(global_skylight_name)
|
||||
Report.result(Tests.global_skylight_component_added, global_skylight_entity.has_component(global_skylight_name))
|
||||
|
||||
# 8. Set the Cubemap Texture property of the HDRi Skybox component.
|
||||
global_skylight_image_asset_path = os.path.join(
|
||||
"LightingPresets", "greenwich_park_02_4k_iblskyboxcm_iblspecular.exr.streamingimage")
|
||||
global_skylight_image_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", global_skylight_image_asset_path, math.Uuid(), False)
|
||||
hdri_skybox_cubemap_texture_property = "Controller|Configuration|Cubemap Texture"
|
||||
hdri_skybox_component.set_component_property_value(
|
||||
hdri_skybox_cubemap_texture_property, global_skylight_image_asset)
|
||||
Report.result(
|
||||
Tests.hdri_skybox_cubemap_texture_set,
|
||||
hdri_skybox_component.get_component_property_value(
|
||||
hdri_skybox_cubemap_texture_property) == global_skylight_image_asset)
|
||||
|
||||
# 9. Set the Diffuse Image property of the Global Skylight (IBL) component.
|
||||
# Re-use the same image that was used in the previous test step.
|
||||
global_skylight_diffuse_image_property = "Controller|Configuration|Diffuse Image"
|
||||
global_skylight_component.set_component_property_value(
|
||||
global_skylight_diffuse_image_property, global_skylight_image_asset)
|
||||
Report.result(
|
||||
Tests.global_skylight_diffuse_image_set,
|
||||
global_skylight_component.get_component_property_value(
|
||||
global_skylight_diffuse_image_property) == global_skylight_image_asset)
|
||||
|
||||
# 10. Set the Specular Image property of the Global Skylight (IBL) component.
|
||||
# Re-use the same image that was used in the previous test step.
|
||||
global_skylight_specular_image_property = "Controller|Configuration|Specular Image"
|
||||
global_skylight_component.set_component_property_value(
|
||||
global_skylight_specular_image_property, global_skylight_image_asset)
|
||||
global_skylight_specular_image_set = global_skylight_component.get_component_property_value(
|
||||
global_skylight_specular_image_property)
|
||||
Report.result(
|
||||
Tests.global_skylight_specular_image_set, global_skylight_specular_image_set == global_skylight_image_asset)
|
||||
|
||||
# 11. Create a Ground Plane Entity with a Material component that is a child entity of the Default Level Entity.
|
||||
ground_plane_name = "Ground Plane"
|
||||
ground_plane_entity = EditorEntity.create_editor_entity(ground_plane_name, default_level_entity.id)
|
||||
ground_plane_material_component = ground_plane_entity.add_component(MATERIAL_COMPONENT_NAME)
|
||||
Report.result(
|
||||
Tests.ground_plane_material_component_added, ground_plane_entity.has_component(MATERIAL_COMPONENT_NAME))
|
||||
|
||||
# 12. Set the Material Asset property of the Material component for the Ground Plane Entity.
|
||||
ground_plane_entity.set_local_uniform_scale(32.0)
|
||||
ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial")
|
||||
ground_plane_material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False)
|
||||
ground_plane_material_asset_property = "Default Material|Material Asset"
|
||||
ground_plane_material_component.set_component_property_value(
|
||||
ground_plane_material_asset_property, ground_plane_material_asset)
|
||||
Report.result(
|
||||
Tests.ground_plane_material_asset_set,
|
||||
ground_plane_material_component.get_component_property_value(
|
||||
ground_plane_material_asset_property) == ground_plane_material_asset)
|
||||
|
||||
# 13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Mesh Asset property.
|
||||
ground_plane_mesh_component = ground_plane_entity.add_component(MESH_COMPONENT_NAME)
|
||||
Report.result(Tests.mesh_component_added, ground_plane_entity.has_component(MESH_COMPONENT_NAME))
|
||||
ground_plane_mesh_asset_path = os.path.join("Objects", "plane.azmodel")
|
||||
ground_plane_mesh_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False)
|
||||
ground_plane_mesh_asset_property = "Controller|Configuration|Mesh Asset"
|
||||
ground_plane_mesh_component.set_component_property_value(
|
||||
ground_plane_mesh_asset_property, ground_plane_mesh_asset)
|
||||
Report.result(
|
||||
Tests.ground_plane_mesh_asset_set,
|
||||
ground_plane_mesh_component.get_component_property_value(
|
||||
ground_plane_mesh_asset_property) == ground_plane_mesh_asset)
|
||||
|
||||
# 14. Create a Directional Light Entity as a child entity of the Default Level Entity.
|
||||
directional_light_name = "Directional Light"
|
||||
directional_light_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(0.0, 0.0, 10.0), directional_light_name, default_level_entity.id)
|
||||
|
||||
# 15. Add Directional Light component to Directional Light Entity and set entity rotation.
|
||||
directional_light_entity.add_component(directional_light_name)
|
||||
directional_light_entity_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0)
|
||||
directional_light_entity.set_local_rotation(directional_light_entity_rotation)
|
||||
Report.result(
|
||||
Tests.directional_light_component_added, directional_light_entity.has_component(directional_light_name))
|
||||
|
||||
# 16. Create a Sphere Entity as a child entity of the Default Level Entity then add a Material component.
|
||||
sphere_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(0.0, 0.0, 1.0), "Sphere", default_level_entity.id)
|
||||
sphere_material_component = sphere_entity.add_component(MATERIAL_COMPONENT_NAME)
|
||||
Report.result(Tests.sphere_material_component_added, sphere_entity.has_component(MATERIAL_COMPONENT_NAME))
|
||||
|
||||
# 17. Set the Material Asset property of the Material component for the Sphere Entity.
|
||||
sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial")
|
||||
sphere_material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False)
|
||||
sphere_material_asset_property = "Default Material|Material Asset"
|
||||
sphere_material_component.set_component_property_value(sphere_material_asset_property, sphere_material_asset)
|
||||
Report.result(Tests.sphere_material_set, sphere_material_component.get_component_property_value(
|
||||
sphere_material_asset_property) == sphere_material_asset)
|
||||
|
||||
# 18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component.
|
||||
sphere_mesh_component = sphere_entity.add_component(MESH_COMPONENT_NAME)
|
||||
sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel")
|
||||
sphere_mesh_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False)
|
||||
sphere_mesh_asset_property = "Controller|Configuration|Mesh Asset"
|
||||
sphere_mesh_component.set_component_property_value(sphere_mesh_asset_property, sphere_mesh_asset)
|
||||
Report.result(Tests.sphere_mesh_asset_set, sphere_mesh_component.get_component_property_value(
|
||||
sphere_mesh_asset_property) == sphere_mesh_asset)
|
||||
|
||||
# 19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component.
|
||||
camera_name = "Camera"
|
||||
camera_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(5.5, -12.0, 9.0), camera_name, default_level_entity.id)
|
||||
camera_component = camera_entity.add_component(camera_name)
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
|
||||
|
||||
# 20. Set the Camera Entity rotation value and set the Camera component Field of View value.
|
||||
camera_entity_rotation = math.Vector3(
|
||||
DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0)
|
||||
camera_entity.set_local_rotation(camera_entity_rotation)
|
||||
camera_fov_property = "Controller|Configuration|Field of view"
|
||||
camera_fov_value = 60.0
|
||||
camera_component.set_component_property_value(camera_fov_property, camera_fov_value)
|
||||
azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
|
||||
Report.result(Tests.camera_fov_set, camera_component.get_component_property_value(
|
||||
camera_fov_property) == camera_fov_value)
|
||||
|
||||
# 21. Enter game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0)
|
||||
|
||||
# 22. Take screenshot.
|
||||
ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(f"{SCREENSHOT_NAME}.ppm")
|
||||
|
||||
# 23. Exit game mode.
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0)
|
||||
|
||||
# 24. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
Report.result(Tests.no_assert_occurred, not error_tracer.has_asserts)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomGPU_BasicLevelSetup_SetsUpLevel)
|
||||
@@ -16,7 +16,7 @@ import time
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import Atom.atom_utils.material_editor_utils as material_editor
|
||||
|
||||
@@ -27,10 +27,10 @@ TEST_MATERIAL_1 = "001_DefaultWhite.material"
|
||||
TEST_MATERIAL_2 = "002_BaseColorLerp.material"
|
||||
TEST_MATERIAL_3 = "003_MetalMatte.material"
|
||||
TEST_DATA_PATH = os.path.join(
|
||||
azlmbr.paths.devroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases"
|
||||
azlmbr.paths.engroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases"
|
||||
)
|
||||
MATERIAL_TYPE_PATH = os.path.join(
|
||||
azlmbr.paths.devroot, "Gems", "Atom", "Feature", "Common", "Assets",
|
||||
azlmbr.paths.engroot, "Gems", "Atom", "Feature", "Common", "Assets",
|
||||
"Materials", "Types", "StandardPBR.materialtype",
|
||||
)
|
||||
CACHE_FILE_EXTENSION = ".azmaterial"
|
||||
@@ -61,7 +61,7 @@ def run():
|
||||
print(f"Material opened: {material_editor.is_open(document_id)}")
|
||||
|
||||
# Verify if the test material exists initially
|
||||
target_path = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL)
|
||||
target_path = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL)
|
||||
print(f"Test asset doesn't exist initially: {not os.path.exists(target_path)}")
|
||||
|
||||
# 2) Test Case: Creating a New Material Using Existing One
|
||||
@@ -109,10 +109,10 @@ def run():
|
||||
# Assign new color to the material file and save the document as copy
|
||||
expected_color_1 = math.Color(0.5, 0.5, 0.5, 1.0)
|
||||
material_editor.set_property(document_id, property_name, expected_color_1)
|
||||
target_path_1 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_1)
|
||||
target_path_1 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_1)
|
||||
cache_file_name_1 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_1', '.material')
|
||||
cache_file_1 = f"{cache_file_name_1[0]}{CACHE_FILE_EXTENSION}"
|
||||
target_path_1_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_1)
|
||||
target_path_1_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_1)
|
||||
material_editor.save_document_as_copy(document_id, target_path_1)
|
||||
material_editor.wait_for_condition(lambda: os.path.exists(target_path_1_cache), 4.0)
|
||||
|
||||
@@ -120,10 +120,10 @@ def run():
|
||||
# Assign new color to the material file save the document as child
|
||||
expected_color_2 = math.Color(0.75, 0.75, 0.75, 1.0)
|
||||
material_editor.set_property(document_id, property_name, expected_color_2)
|
||||
target_path_2 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_2)
|
||||
target_path_2 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_2)
|
||||
cache_file_name_2 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_2', '.material')
|
||||
cache_file_2 = f"{cache_file_name_2[0]}{CACHE_FILE_EXTENSION}"
|
||||
target_path_2_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_2)
|
||||
target_path_2_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_2)
|
||||
material_editor.save_document_as_child(document_id, target_path_2)
|
||||
material_editor.wait_for_condition(lambda: os.path.exists(target_path_2_cache), 4.0)
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
|
||||
@@ -17,7 +17,7 @@ import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.editor as editor
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
|
||||
@@ -14,7 +14,7 @@ import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils
|
||||
|
||||
@@ -42,7 +42,6 @@ class TestEditorAutomation(object):
|
||||
"editor command line arg bar",
|
||||
"editor command line arg baz",
|
||||
"editor engroot set",
|
||||
"editor devroot set",
|
||||
"path resolved worked"
|
||||
]
|
||||
|
||||
|
||||
@@ -20,12 +20,6 @@ if (engroot is not None and len(engroot) is not 0):
|
||||
print ('engroot is {}'.format(engroot))
|
||||
print ('editor engroot set')
|
||||
|
||||
# make sure the @devroot@ exists as a azlmbr.paths property
|
||||
devroot = azlmbr.paths.devroot
|
||||
if (devroot is not None and len(devroot) != 0):
|
||||
print ('devroot is {}'.format(devroot))
|
||||
print ('editor devroot set')
|
||||
|
||||
# resolving a basic path
|
||||
path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl')
|
||||
if (len(path) != 0 and path.find('@engroot@') == -1):
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import azlmbr.entity as entity
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
|
||||
from automatedtesting_shared.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test
|
||||
pyRunFile @devroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done
|
||||
pyRunFile @engroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done
|
||||
@@ -1,2 +1,2 @@
|
||||
# this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test
|
||||
pyRunFile @devroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py
|
||||
pyRunFile @engroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py
|
||||
+16
@@ -361,3 +361,19 @@ class EditorEntity:
|
||||
:return: True if "isVisible" is enabled, False otherwise.
|
||||
"""
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id)
|
||||
|
||||
def set_local_uniform_scale(self, scale_float) -> None:
|
||||
"""
|
||||
Sets the "SetLocalUniformScale" value on the entity.
|
||||
:param scale_float: value for "SetLocalUniformScale" to set to.
|
||||
:return: None
|
||||
"""
|
||||
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", self.id, scale_float)
|
||||
|
||||
def set_local_rotation(self, vector3_rotation) -> None:
|
||||
"""
|
||||
Sets the "SetLocalRotation" value on the entity.
|
||||
:param vector3_rotation: The math.Vector3 value to use for rotation on the entity (uses radians).
|
||||
:return: None
|
||||
"""
|
||||
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, vector3_rotation)
|
||||
|
||||
+41
-14
@@ -4,18 +4,18 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
import math
|
||||
import traceback
|
||||
from typing import Callable, Tuple
|
||||
|
||||
import azlmbr
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.debug
|
||||
import json
|
||||
|
||||
import traceback
|
||||
|
||||
from typing import Callable, Tuple
|
||||
|
||||
class FailFast(Exception):
|
||||
"""
|
||||
@@ -127,6 +127,31 @@ class TestHelper:
|
||||
if ret:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def close_error_windows():
|
||||
"""
|
||||
Closes Error Report and Error Log windows that block focus if they are visible.
|
||||
:return: None
|
||||
"""
|
||||
if general.is_pane_visible("Error Report"):
|
||||
general.close_pane("Error Report")
|
||||
if general.is_pane_visible("Error Log"):
|
||||
general.close_pane("Error Log")
|
||||
|
||||
@staticmethod
|
||||
def close_display_helpers():
|
||||
"""
|
||||
Closes helper gizmos, anti-aliasing, and FPS meters.
|
||||
:return: None
|
||||
"""
|
||||
if general.is_helpers_shown():
|
||||
general.toggle_helpers()
|
||||
general.idle_wait(1.0)
|
||||
general.idle_wait(1.0)
|
||||
general.run_console("r_displayInfo=0")
|
||||
general.run_console("r_antialiasingmode=0")
|
||||
general.idle_wait(1.0)
|
||||
|
||||
|
||||
class Timeout:
|
||||
# type: (float) -> None
|
||||
@@ -149,6 +174,7 @@ class Timeout:
|
||||
def timed_out(self):
|
||||
return time.time() > self.die_after
|
||||
|
||||
|
||||
class Report:
|
||||
_results = []
|
||||
_exception = None
|
||||
@@ -290,8 +316,8 @@ class Report:
|
||||
Report.info(" x: {:.2f}, y: {:.2f}, z: {:.2f}".format(vector3.x, vector3.y, vector3.z))
|
||||
if magnitude is not None:
|
||||
Report.info(" magnitude: {:.2f}".format(magnitude))
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
Utility for scope tracing errors and warnings.
|
||||
Usage:
|
||||
@@ -303,7 +329,7 @@ Usage:
|
||||
|
||||
Report.result(Tests.warnings_not_found_in_section, not section_tracer.has_warnings)
|
||||
|
||||
'''
|
||||
'''
|
||||
class Tracer:
|
||||
def __init__(self):
|
||||
self.warnings = []
|
||||
@@ -349,10 +375,10 @@ class Tracer:
|
||||
self.line = args[1]
|
||||
self.function = args[2]
|
||||
self.message = args[3]
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return f"Assert: [{self.filename}:{self.function}:{self.line}]: {self.message}"
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return f"[Assert: {self.message}]"
|
||||
|
||||
@@ -360,21 +386,21 @@ class Tracer:
|
||||
def __init__(self, args):
|
||||
self.window = args[0]
|
||||
self.message = args[1]
|
||||
|
||||
|
||||
def _on_warning(self, args):
|
||||
warningInfo = Tracer.WarningInfo(args)
|
||||
self.warnings.append(warningInfo)
|
||||
Report.info("Tracer caught Warning: %s" % warningInfo.message)
|
||||
self.has_warnings = True
|
||||
return False
|
||||
|
||||
|
||||
def _on_error(self, args):
|
||||
errorInfo = Tracer.ErrorInfo(args)
|
||||
self.errors.append(errorInfo)
|
||||
Report.info("Tracer caught Error: %s" % errorInfo.message)
|
||||
self.has_errors = True
|
||||
return False
|
||||
|
||||
|
||||
def _on_assert(self, args):
|
||||
assertInfo = Tracer.AssertInfo(args)
|
||||
self.asserts.append(assertInfo)
|
||||
@@ -436,6 +462,7 @@ class AngleHelper:
|
||||
|
||||
def vector3_str(vector3):
|
||||
return "(x: {:.2f}, y: {:.2f}, z: {:.2f})".format(vector3.x, vector3.y, vector3.z)
|
||||
|
||||
|
||||
|
||||
def aabb_str(aabb):
|
||||
return "[Min: %s, Max: %s]" % (vector3_str(aabb.min), vector3_str(aabb.max))
|
||||
|
||||
@@ -96,19 +96,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
|
||||
## GradientSignal ##
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::GradientSignalTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/TestSuite_Periodic.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::GradientSignalTests_Periodic_Optimized
|
||||
TEST_SERIAL
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ def DynamicSliceInstanceSpawner_Embedded_E2E():
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.export_to_engine()
|
||||
pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
|
||||
pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak")
|
||||
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ def DynamicSliceInstanceSpawner_External_E2E():
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.export_to_engine()
|
||||
pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
|
||||
pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak")
|
||||
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ def LayerBlender_E2E_Editor():
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
general.export_to_engine()
|
||||
pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
|
||||
pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak")
|
||||
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
|
||||
|
||||
|
||||
|
||||
-1
@@ -10,7 +10,6 @@ import pytest
|
||||
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
|
||||
+3
-3
@@ -17,7 +17,7 @@ import azlmbr.vegetation as vegetation
|
||||
import azlmbr.areasystem as areasystem
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z
|
||||
# Create a "flat surface" entity to use as a plantable vegetation surface
|
||||
surface_entity = hydra.Entity(name)
|
||||
surface_entity.create_entity(
|
||||
center_point,
|
||||
center_point,
|
||||
["Box Shape", "Shape Surface Tag Emitter"]
|
||||
)
|
||||
if surface_entity.id.IsValid():
|
||||
@@ -56,7 +56,7 @@ def create_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_
|
||||
# Create a vegetation area entity to use as our test vegetation spawner
|
||||
spawner_entity = hydra.Entity(name)
|
||||
spawner_entity.create_entity(
|
||||
center_point,
|
||||
center_point,
|
||||
["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
|
||||
)
|
||||
if spawner_entity.id.IsValid():
|
||||
|
||||
@@ -25,28 +25,39 @@ import prefab.Prefab_Test_Utils as prefab_test_utils
|
||||
# This is a helper class which contains some of the useful information about a prefab instance.
|
||||
class PrefabInstance:
|
||||
|
||||
def __init__(self, name: str=None, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()):
|
||||
self.name = name
|
||||
def __init__(self, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()):
|
||||
self.prefab_file_name: str = prefab_file_name
|
||||
self.container_entity: EditorEntity = container_entity
|
||||
|
||||
def __eq__(self, other):
|
||||
return other and self.container_entity.id == other.container_entity.id
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.container_entity.id)
|
||||
|
||||
"""
|
||||
See if this instance is valid to be used with other prefab operations.
|
||||
:return: Whether the target instance is valid or not.
|
||||
"""
|
||||
def is_valid() -> bool:
|
||||
return self.container_entity.id.IsValid() and self.name is not None and self.prefab_file_name in Prefab.existing_prefabs
|
||||
return self.container_entity.id.IsValid() and self.prefab_file_name in Prefab.existing_prefabs
|
||||
|
||||
|
||||
"""
|
||||
Reparent this instance to target parent entity.
|
||||
The function will also check pop up dialog ui in editor to see if there's prefab cyclical dependency error while reparenting prefabs.
|
||||
:param parent_entity_id: The id of the entity this instance should be a child of in the transform hierarchy next.
|
||||
"""
|
||||
async def ui_reparent_prefab_instance(self, parent_entity_id: EntityId):
|
||||
container_entity_name = self.container_entity.get_name()
|
||||
current_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name)
|
||||
Report.info(f'current_children_entity_ids_having_prefab_name: {current_children_entity_ids_having_prefab_name}')
|
||||
container_entity_id_before_reparent = self.container_entity.id
|
||||
|
||||
original_parent = EditorEntity(self.container_entity.get_parent_id())
|
||||
original_parent_before_reparent_children_ids = set(original_parent.get_children_ids())
|
||||
|
||||
new_parent = EditorEntity(parent_entity_id)
|
||||
new_parent_before_reparent_children_ids = set(new_parent.get_children_ids())
|
||||
|
||||
pyside_utils.run_soon(lambda: self.container_entity.set_parent_entity(parent_entity_id))
|
||||
pyside_utils.run_soon(lambda: prefab_test_utils.wait_for_propagation())
|
||||
@@ -60,18 +71,23 @@ class PrefabInstance:
|
||||
except pyside_utils.EventLoopTimeoutException:
|
||||
pass
|
||||
|
||||
updated_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name)
|
||||
Report.info(f'updated_children_entity_ids_having_prefab_name: {updated_children_entity_ids_having_prefab_name}')
|
||||
new_child_with_reparented_prefab_name_added = len(updated_children_entity_ids_having_prefab_name) == len(current_children_entity_ids_having_prefab_name) + 1
|
||||
assert new_child_with_reparented_prefab_name_added, "No entity with reparented prefab name become a child of target parent entity"
|
||||
original_parent_after_reparent_children_ids = set(original_parent.get_children_ids())
|
||||
assert len(original_parent_after_reparent_children_ids) == len(original_parent_before_reparent_children_ids) - 1, \
|
||||
"The children count of the Prefab Instance's original parent should be decreased by 1."
|
||||
assert not container_entity_id_before_reparent in original_parent_after_reparent_children_ids, \
|
||||
"This Prefab Instance is still a child entity of its original parent entity."
|
||||
|
||||
new_parent_after_reparent_children_ids = set(new_parent.get_children_ids())
|
||||
assert len(new_parent_after_reparent_children_ids) == len(new_parent_before_reparent_children_ids) + 1, \
|
||||
"The children count of the Prefab Instance's new parent should be increased by 1."
|
||||
|
||||
updated_container_entity_id = set(updated_children_entity_ids_having_prefab_name).difference(current_children_entity_ids_having_prefab_name).pop()
|
||||
updated_container_entity = EditorEntity(updated_container_entity_id)
|
||||
updated_container_entity_parent_id = updated_container_entity.get_parent_id()
|
||||
has_correct_parent = updated_container_entity_parent_id.ToString() == parent_entity_id.ToString()
|
||||
assert has_correct_parent, "Prefab reparented is *not* under the expected parent entity"
|
||||
container_entity_id_after_reparent = set(new_parent_after_reparent_children_ids).difference(new_parent_before_reparent_children_ids).pop()
|
||||
reparented_container_entity = EditorEntity(container_entity_id_after_reparent)
|
||||
reparented_container_entity_parent_id = reparented_container_entity.get_parent_id()
|
||||
has_correct_parent = reparented_container_entity_parent_id.ToString() == parent_entity_id.ToString()
|
||||
assert has_correct_parent, "Prefab Instance reparented is *not* under the expected parent entity"
|
||||
|
||||
self.container_entity = EditorEntity(updated_container_entity_id)
|
||||
self.container_entity = reparented_container_entity
|
||||
|
||||
# This is a helper class which contains some of the useful information about a prefab template.
|
||||
class Prefab:
|
||||
@@ -81,7 +97,7 @@ class Prefab:
|
||||
def __init__(self, file_name: str):
|
||||
self.file_name:str = file_name
|
||||
self.file_path: str = prefab_test_utils.get_prefab_file_path(file_name)
|
||||
self.instances: dict = {}
|
||||
self.instances: set[PrefabInstance] = set()
|
||||
|
||||
"""
|
||||
Check if a prefab is ready to be used to generate its instances.
|
||||
@@ -122,10 +138,10 @@ class Prefab:
|
||||
:param entities: The entities that should form the new prefab (along with their descendants).
|
||||
:param file_name: A unique file name of new prefab.
|
||||
:param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as file_name.
|
||||
:return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error.
|
||||
:return: Created Prefab object and the very first PrefabInstance object owned by the prefab.
|
||||
"""
|
||||
@classmethod
|
||||
def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> Prefab:
|
||||
def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> (Prefab, PrefabInstance):
|
||||
assert not Prefab.is_prefab_loaded(file_name), f"Can't create Prefab '{file_name}' since the prefab already exists"
|
||||
|
||||
new_prefab = Prefab(file_name)
|
||||
@@ -133,18 +149,18 @@ class Prefab:
|
||||
create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', entity_ids, new_prefab.file_path)
|
||||
assert create_prefab_result.IsSuccess(), f"Prefab operation 'CreatePrefab' failed. Error: {create_prefab_result.GetError()}"
|
||||
|
||||
container_entity = EditorEntity(create_prefab_result.GetValue())
|
||||
container_entity_id = create_prefab_result.GetValue()
|
||||
container_entity = EditorEntity(container_entity_id)
|
||||
|
||||
if prefab_instance_name:
|
||||
container_entity.set_name(prefab_instance_name)
|
||||
else:
|
||||
prefab_instance_name = file_name
|
||||
|
||||
prefab_test_utils.wait_for_propagation()
|
||||
container_entity_id = prefab_test_utils.find_entity_by_unique_name(prefab_instance_name)
|
||||
new_prefab.instances[prefab_instance_name] = PrefabInstance(prefab_instance_name, file_name, EditorEntity(container_entity_id))
|
||||
|
||||
new_prefab_instance = PrefabInstance(file_name, EditorEntity(container_entity_id))
|
||||
new_prefab.instances.add(new_prefab_instance)
|
||||
Prefab.existing_prefabs[file_name] = new_prefab
|
||||
return new_prefab
|
||||
return new_prefab, new_prefab_instance
|
||||
|
||||
"""
|
||||
Remove target prefab instances.
|
||||
@@ -152,22 +168,15 @@ class Prefab:
|
||||
"""
|
||||
@classmethod
|
||||
def remove_prefabs(cls, prefab_instances: list[PrefabInstance]):
|
||||
instances_to_remove_name_counts = Counter()
|
||||
instances_removed_expected_name_counts = Counter()
|
||||
|
||||
entities_to_remove = [prefab_instance.container_entity for prefab_instance in prefab_instances]
|
||||
while entities_to_remove:
|
||||
entity = entities_to_remove.pop(-1)
|
||||
entity_name = entity.get_name()
|
||||
instances_to_remove_name_counts[entity_name] += 1
|
||||
|
||||
entity_ids_to_remove = []
|
||||
entity_id_queue = [prefab_instance.container_entity for prefab_instance in prefab_instances]
|
||||
while entity_id_queue:
|
||||
entity = entity_id_queue.pop(0)
|
||||
children_entity_ids = entity.get_children_ids()
|
||||
for child_entity_id in children_entity_ids:
|
||||
entities_to_remove.append(EditorEntity(child_entity_id))
|
||||
entity_id_queue.append(EditorEntity(child_entity_id))
|
||||
|
||||
for entity_name, entity_count in instances_to_remove_name_counts.items():
|
||||
entities = prefab_test_utils.find_entities_by_name(entity_name)
|
||||
instances_removed_expected_name_counts[entity_name] = len(entities) - entity_count
|
||||
entity_ids_to_remove.append(entity.id)
|
||||
|
||||
container_entity_ids = [prefab_instance.container_entity.id for prefab_instance in prefab_instances]
|
||||
delete_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'DeleteEntitiesAndAllDescendantsInInstance', container_entity_ids)
|
||||
@@ -175,28 +184,24 @@ class Prefab:
|
||||
|
||||
prefab_test_utils.wait_for_propagation()
|
||||
|
||||
prefab_entities_deleted = True
|
||||
for entity_name, expected_entity_count in instances_removed_expected_name_counts.items():
|
||||
actual_entity_count = len(prefab_test_utils.find_entities_by_name(entity_name))
|
||||
if actual_entity_count is not expected_entity_count:
|
||||
prefab_entities_deleted = False
|
||||
break
|
||||
|
||||
assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted."
|
||||
entity_ids_after_delete = set(prefab_test_utils.get_all_entities())
|
||||
for entity_id_removed in entity_ids_to_remove:
|
||||
if entity_id_removed in entity_ids_after_delete:
|
||||
assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted."
|
||||
|
||||
for instance in prefab_instances:
|
||||
instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_name)
|
||||
instance_deleted_prefab.instances.pop(instance.name)
|
||||
instance_deleted_prefab.instances.remove(instance)
|
||||
instance = PrefabInstance()
|
||||
|
||||
"""
|
||||
Instantiate an instance of this prefab.
|
||||
:param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name.
|
||||
:param parent_entity: The entity the prefab should be a child of in the transform hierarchy.
|
||||
:param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name.
|
||||
:param prefab_position: The position in world space the prefab should be instantiated in.
|
||||
:return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error.
|
||||
:return: Instantiated PrefabInstance object owned by this prefab.
|
||||
"""
|
||||
def instantiate(self, name: str=None, parent_entity: EditorEntity=None, prefab_position: Vector3=Vector3()) -> PrefabInstance:
|
||||
def instantiate(self, parent_entity: EditorEntity=None, name: str=None, prefab_position: Vector3=Vector3()) -> PrefabInstance:
|
||||
parent_entity_id = parent_entity.id if parent_entity is not None else EntityId()
|
||||
|
||||
instantiate_prefab_result = prefab.PrefabPublicRequestBus(
|
||||
@@ -209,13 +214,13 @@ class Prefab:
|
||||
|
||||
if name:
|
||||
container_entity.set_name(name)
|
||||
else:
|
||||
name = self.file_name
|
||||
|
||||
prefab_test_utils.wait_for_propagation()
|
||||
container_entity_id = prefab_test_utils.find_entity_by_unique_name(name)
|
||||
self.instances[name] = PrefabInstance(name, self.file_name, EditorEntity(container_entity_id))
|
||||
|
||||
new_prefab_instance = PrefabInstance(self.file_name, EditorEntity(container_entity_id))
|
||||
assert not new_prefab_instance in self.instances, "This prefab instance is already existed before this instantiation."
|
||||
self.instances.add(new_prefab_instance)
|
||||
|
||||
prefab_test_utils.check_entity_at_position(container_entity_id, prefab_position)
|
||||
|
||||
return container_entity_id
|
||||
return new_prefab_instance
|
||||
|
||||
+1
-2
@@ -22,11 +22,10 @@ def Prefab_BasicWorkflow_CreateAndDeletePrefab():
|
||||
car_prefab_entities = [car_entity]
|
||||
|
||||
# Checks for prefab creation passed or not
|
||||
car_prefab = Prefab.create_prefab(
|
||||
_, car = Prefab.create_prefab(
|
||||
car_prefab_entities, CAR_PREFAB_FILE_NAME)
|
||||
|
||||
# Checks for prefab deletion passed or not
|
||||
car = car_prefab.instances[CAR_PREFAB_FILE_NAME]
|
||||
Prefab.remove_prefabs([car])
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+2
-4
@@ -28,7 +28,7 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab():
|
||||
car_prefab_entities = [car_entity]
|
||||
|
||||
# Checks for prefab creation passed or not
|
||||
car_prefab = Prefab.create_prefab(
|
||||
_, car = Prefab.create_prefab(
|
||||
car_prefab_entities, CAR_PREFAB_FILE_NAME)
|
||||
|
||||
# Creates another new Entity at the root level
|
||||
@@ -36,12 +36,10 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab():
|
||||
wheel_prefab_entities = [wheel_entity]
|
||||
|
||||
# Checks for wheel prefab creation passed or not
|
||||
wheel_prefab = Prefab.create_prefab(
|
||||
_, wheel = Prefab.create_prefab(
|
||||
wheel_prefab_entities, WHEEL_PREFAB_FILE_NAME)
|
||||
|
||||
# Checks for prefab reparenting passed or not
|
||||
car = car_prefab.instances[CAR_PREFAB_FILE_NAME]
|
||||
wheel = wheel_prefab.instances[WHEEL_PREFAB_FILE_NAME]
|
||||
await wheel.ui_reparent_prefab_instance(car.container_entity.id)
|
||||
|
||||
run_test()
|
||||
|
||||
@@ -22,11 +22,11 @@ def Prefab_BasicWorkflow_InstantiatePrefab():
|
||||
# Checks for prefab instantiation passed or not
|
||||
test_prefab = Prefab.get_prefab(EXISTING_TEST_PREFAB_FILE_NAME)
|
||||
|
||||
instantiated_test_container_entity_id = test_prefab.instantiate(
|
||||
test_instance = test_prefab.instantiate(
|
||||
prefab_position=INSTANTIATED_TEST_PREFAB_POSITION)
|
||||
|
||||
prefab_test_utils.check_entity_children_count(
|
||||
instantiated_test_container_entity_id,
|
||||
test_instance.container_entity.id,
|
||||
EXPECTED_TEST_PREFAB_CHILDREN_COUNT)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -29,20 +29,8 @@ def find_entities_by_name(entity_name):
|
||||
searchFilter.names = [entity_name]
|
||||
return entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
|
||||
|
||||
def find_entity_by_unique_name(entity_name):
|
||||
unique_name_entity_found_result = (
|
||||
"Entity with a unique name found",
|
||||
"Entity with a unique name *not* found")
|
||||
|
||||
entities = find_entities_by_name(entity_name)
|
||||
unique_name_entity_found = len(entities) == 1
|
||||
Report.result(unique_name_entity_found_result, unique_name_entity_found)
|
||||
|
||||
if unique_name_entity_found:
|
||||
return entities[0]
|
||||
else:
|
||||
Report.info(f"{len(entities)} entities with name '{entity_name}' found")
|
||||
return EntityId()
|
||||
def get_all_entities():
|
||||
return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
|
||||
|
||||
def check_entity_at_position(entity_id, expected_entity_position):
|
||||
entity_at_expected_position_result = (
|
||||
|
||||
@@ -122,6 +122,7 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import Debugger_HappyPath_TargetMultipleEntities as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
|
||||
def test_EditMenu_Default_UndoRedo(self, request, workspace, editor, launcher_platform, project):
|
||||
from . import EditMenu_Default_UndoRedo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
@@ -181,6 +182,7 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import NodePalette_SearchText_Deletion as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
|
||||
def test_VariableManager_UnpinVariableType_Works(self, request, workspace, editor, launcher_platform):
|
||||
from . import VariableManager_UnpinVariableType_Works as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[General]
|
||||
version=1
|
||||
startScript="ImportActor -filename \"@assets@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n"
|
||||
startScript="ImportActor -filename \"@products@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n"
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[General]
|
||||
version=1
|
||||
startScript="ImportActor -filename \"@assets@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/rin_physics.animgraph\"\n"
|
||||
startScript="ImportActor -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_physics.animgraph\"\n"
|
||||
|
||||
@@ -51,6 +51,14 @@
|
||||
[
|
||||
"Gems/UiBasics"
|
||||
]
|
||||
},
|
||||
"Hair":
|
||||
{
|
||||
"SourcePaths":
|
||||
[
|
||||
"Gems/AtomTressFX/Assets",
|
||||
"Gems/AtomTressFX/Assets/Passes"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
"guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
"guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
"guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
"guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
"guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
"guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:827a63985273229050bf4f63030bcc666f045091fe81cf8157a9ca23b40074b6
|
||||
size 3214
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d8d24963e6e8765205bc79cbe2304fc39f1245ee75249e2834a71c96c3cab824
|
||||
size 22700
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"values": [
|
||||
{
|
||||
"$type": "ScriptProcessorRule",
|
||||
"scriptFilename": "Editor/Scripts/scene_mesh_to_prefab.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user