diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
index 905722d103..7051b9983c 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
@@ -4,10 +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 logging
+import os
import pytest
+import ly_test_tools.environment.file_system as file_system
+import editor_python_test_tools.hydra_test_utils as hydra
+
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
+logger = logging.getLogger(__name__)
+TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
+
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@@ -114,3 +122,73 @@ class TestAutomation(EditorTestSuite):
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
+
+
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
+class TestMaterialEditorBasicTests(object):
+ @pytest.fixture(autouse=True)
+ def setup_teardown(self, request, workspace, project):
+ def delete_files():
+ file_system.delete(
+ [
+ os.path.join(workspace.paths.project(), "Materials", "test_material.material"),
+ os.path.join(workspace.paths.project(), "Materials", "test_material_1.material"),
+ os.path.join(workspace.paths.project(), "Materials", "test_material_2.material"),
+ ],
+ True,
+ True,
+ )
+ # Cleanup our newly created materials
+ delete_files()
+
+ def teardown():
+ # Cleanup our newly created materials
+ delete_files()
+
+ request.addfinalizer(teardown)
+
+ @pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
+ @pytest.mark.test_case_id("C34448113") # Creating a New Asset.
+ @pytest.mark.test_case_id("C34448114") # Opening an Existing Asset.
+ @pytest.mark.test_case_id("C34448115") # Closing Selected Material.
+ @pytest.mark.test_case_id("C34448116") # Closing All Materials.
+ @pytest.mark.test_case_id("C34448117") # Closing all but Selected Material.
+ @pytest.mark.test_case_id("C34448118") # Saving Material.
+ @pytest.mark.test_case_id("C34448119") # Saving as a New Material.
+ @pytest.mark.test_case_id("C34448120") # Saving as a Child Material.
+ @pytest.mark.test_case_id("C34448121") # Saving all Open Materials.
+ def test_MaterialEditorBasicTests(
+ self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name):
+
+ expected_lines = [
+ "Material opened: True",
+ "Test asset doesn't exist initially: True",
+ "New asset created: True",
+ "New Material opened: True",
+ "Material closed: True",
+ "All documents closed: True",
+ "Close All Except Selected worked as expected: True",
+ "Actual Document saved with changes: True",
+ "Document saved as copy is saved with changes: True",
+ "Document saved as child is saved with changes: True",
+ "Save All worked as expected: True",
+ ]
+ unexpected_lines = [
+ "Traceback (most recent call last):"
+ ]
+
+ hydra.launch_and_validate_results(
+ request,
+ TEST_DIRECTORY,
+ generic_launcher,
+ "hydra_AtomMaterialEditor_BasicTests.py",
+ run_python="--runpython",
+ timeout=43,
+ expected_lines=expected_lines,
+ unexpected_lines=unexpected_lines,
+ halt_on_unexpected=True,
+ null_renderer=True,
+ log_file_name="MaterialEditor.log",
+ enable_prefab_system=False,
+ )
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
index 29f90e6807..c9182070f6 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
@@ -83,77 +83,6 @@ class TestAtomEditorComponentsMain(object):
)
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
-@pytest.mark.system
-class TestMaterialEditorBasicTests(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project):
- def delete_files():
- file_system.delete(
- [
- os.path.join(workspace.paths.project(), "Materials", "test_material.material"),
- os.path.join(workspace.paths.project(), "Materials", "test_material_1.material"),
- os.path.join(workspace.paths.project(), "Materials", "test_material_2.material"),
- ],
- True,
- True,
- )
- # Cleanup our newly created materials
- delete_files()
-
- def teardown():
- # Cleanup our newly created materials
- delete_files()
-
- request.addfinalizer(teardown)
-
- @pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
- @pytest.mark.test_case_id("C34448113") # Creating a New Asset.
- @pytest.mark.test_case_id("C34448114") # Opening an Existing Asset.
- @pytest.mark.test_case_id("C34448115") # Closing Selected Material.
- @pytest.mark.test_case_id("C34448116") # Closing All Materials.
- @pytest.mark.test_case_id("C34448117") # Closing all but Selected Material.
- @pytest.mark.test_case_id("C34448118") # Saving Material.
- @pytest.mark.test_case_id("C34448119") # Saving as a New Material.
- @pytest.mark.test_case_id("C34448120") # Saving as a Child Material.
- @pytest.mark.test_case_id("C34448121") # Saving all Open Materials.
- def test_MaterialEditorBasicTests(
- self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name):
-
- expected_lines = [
- "Material opened: True",
- "Test asset doesn't exist initially: True",
- "New asset created: True",
- "New Material opened: True",
- "Material closed: True",
- "All documents closed: True",
- "Close All Except Selected worked as expected: True",
- "Actual Document saved with changes: True",
- "Document saved as copy is saved with changes: True",
- "Document saved as child is saved with changes: True",
- "Save All worked as expected: True",
- ]
- unexpected_lines = [
- "Traceback (most recent call last):"
- ]
-
- hydra.launch_and_validate_results(
- request,
- TEST_DIRECTORY,
- generic_launcher,
- "hydra_AtomMaterialEditor_BasicTests.py",
- run_python="--runpython",
- timeout=120,
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- halt_on_unexpected=True,
- null_renderer=True,
- log_file_name="MaterialEditor.log",
- enable_prefab_system=False,
- )
-
-
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAutomation(EditorTestSuite):
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
index b21c74de19..f7ff970541 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
@@ -162,6 +162,13 @@ def select_model_config(configname):
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SelectModelPresetByName", configname)
+def destroy_main_window():
+ """
+ Closes the Material Editor window
+ """
+ azlmbr.atomtools.AtomToolsMainWindowFactoryRequestBus(azlmbr.bus.Broadcast, "DestroyMainWindow")
+
+
def wait_for_condition(function, timeout_in_seconds=1.0):
# type: (function, float) -> bool
"""
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
index 9f8f6c44b2..baad02318d 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
@@ -186,6 +186,11 @@ def run():
material_editor.set_property(document2_id, property2_name, initial_color)
material_editor.save_all()
material_editor.close_all_documents()
+ material_editor.wait_for_condition(lambda:
+ (not material_editor.is_open(document1_id)) and
+ (not material_editor.is_open(document2_id)) and
+ (not material_editor.is_open(document3_id)), 2.0)
+ material_editor.destroy_main_window()
if __name__ == "__main__":
diff --git a/Code/Editor/NewLevelDialog.cpp b/Code/Editor/NewLevelDialog.cpp
index c773acdb6f..a97eb30f57 100644
--- a/Code/Editor/NewLevelDialog.cpp
+++ b/Code/Editor/NewLevelDialog.cpp
@@ -115,7 +115,6 @@ CNewLevelDialog::~CNewLevelDialog()
void CNewLevelDialog::OnStartup()
{
UpdateData(false);
- setFocus();
}
void CNewLevelDialog::UpdateData(bool fromUi)
diff --git a/Code/Editor/NewLevelDialog.ui b/Code/Editor/NewLevelDialog.ui
index 14227fbb53..93a88dc897 100644
--- a/Code/Editor/NewLevelDialog.ui
+++ b/Code/Editor/NewLevelDialog.ui
@@ -133,6 +133,9 @@
1
+
+ LEVEL
+
diff --git a/Code/Framework/AzTest/AzTest/Platform/Windows/ScopedAutoTempDirectory_Windows.cpp b/Code/Framework/AzTest/AzTest/Platform/Windows/ScopedAutoTempDirectory_Windows.cpp
index fcda5d351a..b5314eda14 100644
--- a/Code/Framework/AzTest/AzTest/Platform/Windows/ScopedAutoTempDirectory_Windows.cpp
+++ b/Code/Framework/AzTest/AzTest/Platform/Windows/ScopedAutoTempDirectory_Windows.cpp
@@ -8,57 +8,41 @@
#include
+#include
#include
#include
#include
-#include
+#include
-namespace AZ
+namespace AZ::Test
{
- namespace Test
+ ScopedAutoTempDirectory::ScopedAutoTempDirectory()
{
- ScopedAutoTempDirectory::ScopedAutoTempDirectory()
- {
- constexpr const DWORD bufferSize = static_cast(AZ::IO::MaxPathLength);
+ using UuidString = AZStd::fixed_string;
+ constexpr DWORD bufferSize = static_cast(AZ::IO::MaxPathLength);
- char tempDir[bufferSize] = {0};
- GetTempPathA(bufferSize, tempDir);
+ wchar_t tempDirW[AZ::IO::MaxPathLength]{};
+ GetTempPathW(bufferSize, tempDirW);
- char workingTempPathBuffer[bufferSize] = {'\0'};
+ AZ::IO::FixedMaxPath tempDirectoryRoot;
+ AZStd::to_string(tempDirectoryRoot.Native(), tempDirW);
- int maxAttempts = 2000; // Prevent an infinite loop by setting an arbitrary maximum attempts at finding an available temp folder name
- while (maxAttempts > 0)
+ constexpr int MaxAttempts = 255;
+ for (int i = 0; i < MaxAttempts; ++i)
+ {
+ AZ::IO::FixedMaxPath testPath = tempDirectoryRoot /
+ AZ::IO::FixedMaxPathString::format("UnitTest-%s",
+ AZ::Uuid::CreateRandom().ToString().c_str());
+ // Try to create the temp directory if it doesn't exist
+ if (!AZ::IO::SystemFile::Exists(testPath.c_str()) && AZ::IO::SystemFile::CreateDir(testPath.c_str()))
{
- // Use the system's tick count to base the folder name
- ULONGLONG currentTick = GetTickCount64();
- azsnprintf(workingTempPathBuffer, bufferSize, "%sUnitTest-%X", tempDir, aznumeric_cast(currentTick));
-
- // Check if the requested directory name is available and re-generate if it already exists
- bool exists = AZ::IO::SystemFile::Exists(workingTempPathBuffer);
- if (exists)
- {
- Sleep(1);
- maxAttempts--;
- continue;
- }
+ azstrncpy(AZStd::data(m_tempDirectory), AZStd::size(m_tempDirectory),
+ testPath.c_str(), testPath.Native().size());
break;
}
-
- AZ_Error("AzTest", maxAttempts > 0, "Unable to determine a temp directory");
-
- if (maxAttempts > 0)
- {
- // Create the temp directory and track it for deletion
- bool tempDirectoryCreated = AZ::IO::SystemFile::CreateDir(workingTempPathBuffer);
- if (tempDirectoryCreated)
- {
- azstrncpy(m_tempDirectory, AZ::IO::MaxPathLength, workingTempPathBuffer, AZ::IO::MaxPathLength);
- }
- else
- {
- AZ_Error("AzTest", false, "Unable to create temp directory %s", workingTempPathBuffer);
- }
- }
}
- } // Test
-} // AZ
+
+ AZ_Error("AzTest", m_tempDirectory[0] != '\0', "Unable to create temp path within directory %s after %d attempts",
+ tempDirectoryRoot.c_str(), MaxAttempts);
+ }
+} // AZ::Test
diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp
index 8c2c0e80b6..c51728a5c3 100644
--- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp
+++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp
@@ -17,6 +17,7 @@
#include
#include
+#include
#include
namespace Terrain
@@ -43,11 +44,25 @@ namespace Terrain
AZ::Edit::UIHandlers::ComboBox, &TerrainPhysicsSurfaceMaterialMapping::m_surfaceTag, "Surface Tag",
"Surface type to map to a physics material.")
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainPhysicsSurfaceMaterialMapping::m_materialId, "Material ID", "")
+ ->ElementAttribute(Physics::Attributes::MaterialLibraryAssetId, &TerrainPhysicsSurfaceMaterialMapping::GetMaterialLibraryId)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true);
}
}
}
+
+ AZ::Data::AssetId TerrainPhysicsSurfaceMaterialMapping::GetMaterialLibraryId()
+ {
+ if (const auto* physicsSystem = AZ::Interface::Get())
+ {
+ if (const auto* physicsConfiguration = physicsSystem->GetConfiguration())
+ {
+ return physicsConfiguration->m_materialLibraryAsset.GetId();
+ }
+ }
+ return {};
+ }
+
void TerrainPhysicsColliderConfig::Reflect(AZ::ReflectContext* context)
{
TerrainPhysicsSurfaceMaterialMapping::Reflect(context);
diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h
index 1a7fbf9c72..8a70f282d0 100644
--- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h
+++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h
@@ -36,6 +36,9 @@ namespace Terrain
SurfaceData::SurfaceTag m_surfaceTag;
Physics::MaterialId m_materialId;
+
+ private:
+ static AZ::Data::AssetId GetMaterialLibraryId();
};
class TerrainPhysicsColliderConfig