Added two complex prefab tests (#5089)

* Added two complex prefab tests

* Fix compile error

* Added extra methods, fixed test failure

* Addressed PR commments

* More PR comments

* Fix space

* Fix ar error
monroegm-disable-blank-issue-2
AMZN-AlexOteiza 4 years ago committed by GitHub
parent de4658b16c
commit e871dff70e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -107,6 +107,19 @@ class EditorComponent:
return type_ids
def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
"""
Converts a vector3-like element into a azlmbr.math.Vector3
"""
if isinstance(xyz, Tuple) or isinstance(xyz, List):
assert len(xyz) == 3, ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
return math.Vector3(float(xyz[0]), float(xyz[1]), float(xyz[2]))
elif isinstance(xyz, type(math.Vector3())):
return xyz
else:
raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
class EditorEntity:
"""
Entity class is used to create and interact with Editor Entities.
@ -183,15 +196,6 @@ class EditorEntity:
:return: EditorEntity class object
"""
def convert_to_azvector3(xyz) -> math.Vector3:
if isinstance(xyz, Tuple) or isinstance(xyz, List):
assert len(xyz) == 3, ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
return math.Vector3(*xyz)
elif isinstance(xyz, type(math.Vector3())):
return xyz
else:
raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
if parent_id is None:
parent_id = azlmbr.entity.EntityId()
@ -206,7 +210,7 @@ class EditorEntity:
return entity
# Methods
def set_name(self, entity_name: str):
def set_name(self, entity_name: str) -> None:
"""
Given entity_name, sets name to Entity
:param: entity_name: Name of the entity to set
@ -324,7 +328,7 @@ class EditorEntity:
self.start_status = status
return status
def set_start_status(self, desired_start_status: str):
def set_start_status(self, desired_start_status: str) -> None:
"""
Set an entity as active/inactive at beginning of runtime or it is editor-only,
given its entity id and the start status then return set success
@ -382,18 +386,75 @@ class EditorEntity:
"""
return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id)
# World Transform Functions
def get_world_translation(self) -> azlmbr.math.Vector3:
"""
Gets the world translation of the entity
"""
return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
def set_world_translation(self, new_translation) -> None:
"""
Sets the new world translation of the current entity
"""
new_translation = convert_to_azvector3(new_translation)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetWorldTranslation", self.id, new_translation)
def get_world_rotation(self) -> azlmbr.math.Quaternion:
"""
Gets the world rotation of the entity
"""
return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldRotation", self.id)
def set_world_rotation(self, new_rotation):
"""
Sets the new world rotation of the current entity
"""
new_rotation = convert_to_azvector3(new_rotation)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetWorldRotation", self.id, new_rotation)
# Local Transform Functions
def get_local_uniform_scale(self) -> float:
"""
Gets the local uniform scale of the entity
"""
return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalUniformScale", self.id)
def set_local_uniform_scale(self, scale_float) -> None:
"""
Sets the "SetLocalUniformScale" value on the entity.
Sets the local uniform scale value(relative to the parent) 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:
def get_local_rotation(self) -> azlmbr.math.Quaternion:
"""
Gets the local rotation of the entity
"""
return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalRotation", self.id)
def set_local_rotation(self, new_rotation) -> None:
"""
Sets the "SetLocalRotation" value on the entity.
Sets the set the local rotation(relative to the parent) of the current 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)
new_rotation = convert_to_azvector3(new_rotation)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, new_rotation)
def get_local_translation(self) -> azlmbr.math.Vector3:
"""
Gets the local translation of the current entity.
:return: The math.Vector3 value of the local translation.
"""
return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalTranslation", self.id)
def set_local_translation(self, new_translation) -> None:
"""
Sets the local translation(relative to the parent) of the current entity.
:param vector3_translation: The math.Vector3 value to use for translation on the entity.
:return: None
"""
new_translation = convert_to_azvector3(new_translation)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalTranslation", self.id, new_translation)

@ -138,6 +138,14 @@ class PrefabInstance:
self.container_entity = reparented_container_entity
current_instance_prefab.instances.add(self)
def get_direct_child_entities(self):
"""
Returns the entities only contained in the current prefab instance.
This function does not return entities contained in other child instances
"""
return self.container_entity.get_children()
# This is a helper class which contains some of the useful information about a prefab template.
class Prefab:

@ -55,3 +55,11 @@ class TestAutomation(TestAutomationBase):
def test_PrefabBasicWorkflow_CreateAndDuplicatePrefab(self, request, workspace, editor, launcher_platform):
from .tests import PrefabBasicWorkflow_CreateAndDuplicatePrefab as test_module
self._run_prefab_test(request, workspace, editor, test_module)
def test_PrefabComplexWorflow_CreatePrefabOfChildEntity(self, request, workspace, editor, launcher_platform):
from .tests import PrefabComplexWorflow_CreatePrefabOfChildEntity as test_module
self._run_prefab_test(request, workspace, editor, test_module, autotest_mode=False)
def test_PrefabComplexWorflow_CreatePrefabInsidePrefab(self, request, workspace, editor, launcher_platform):
from .tests import PrefabComplexWorflow_CreatePrefabInsidePrefab as test_module
self._run_prefab_test(request, workspace, editor, test_module, autotest_mode=False)

@ -0,0 +1,57 @@
"""
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
"""
def PrefabComplexWorflow_CreatePrefabInsidePrefab():
"""
Test description:
- Creates an entity with a physx collider
- Creates a prefab "Outer_prefab" and an instance based of that entity
- Creates a prefab "Inner_prefab" inside "Outer_prefab" based the entity contained inside of it
Checks that the entity is correctly handlded by the prefab system checking the name and that it contains the physx collider
"""
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.prefab_utils import Prefab
import PrefabTestUtils as prefab_test_utils
prefab_test_utils.open_base_tests_level()
# Creates a new Entity at the root level
# Asserts if creation didn't succeed
entity = EditorEntity.create_editor_entity_at((100.0, 100.0, 100.0), name = "TestEntity")
assert entity.id.IsValid(), "Couldn't create entity"
entity.add_component("PhysX Collider")
assert entity.has_component("PhysX Collider"), "Attempted to add a PhysX Collider but no physx collider collider was found afterwards"
# Create a prefab based on that entity
outer_prefab, outer_instance = Prefab.create_prefab([entity], "Outer_prefab")
# The test should be now inside the outer prefab instance.
entity = outer_instance.get_direct_child_entities()[0]
# We track if that is the same entity by checking the name and if it still contains the component that we created before
assert entity.get_name() == "TestEntity", f"Entity name inside outer_prefab doesn't match the original name, original:'TestEntity' current:'{entity.get_name()}'"
assert entity.has_component("PhysX Collider"), "Entity name inside outer_prefab doesn't have the collider component it should"
# Now, create another prefab, based on the entity that is inside outer_prefab
inner_prefab, inner_instance = Prefab.create_prefab([entity], "Inner_prefab")
# The test entity should now be inside the inner prefab instance
entity = inner_instance.get_direct_child_entities()[0]
# We track if that is the same entity by checking the name and if it still contains the component that we created before
assert entity.get_name() == "TestEntity", f"Entity name inside inner_prefab doesn't match the original name, original:'TestEntity' current:'{entity.get_name()}'"
assert entity.has_component("PhysX Collider"), "Entity name inside inner_prefab doesn't have the collider component it should"
# Verify hierarchy of entities:
# Outer_prefab
# |- Inner_prefab
# | |- TestEntity
assert entity.get_parent_id() == inner_instance.container_entity.id
assert inner_instance.container_entity.get_parent_id() == outer_instance.container_entity.id
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(PrefabComplexWorflow_CreatePrefabInsidePrefab)

@ -0,0 +1,52 @@
"""
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
"""
def PrefabComplexWorflow_CreatePrefabOfChildEntity():
"""
Test description:
- Creates two entities, parent and child. Child entity has Parent entity as its parent.
- Creates a prefab of the child entity.
Test is successful if the new instanced prefab of the child has the parent entity id
"""
CAR_PREFAB_FILE_NAME = 'car_prefab'
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.prefab_utils import Prefab
import PrefabTestUtils as prefab_test_utils
prefab_test_utils.open_base_tests_level()
# Creates a new Entity at the root level
# Asserts if creation didn't succeed
parent_entity = EditorEntity.create_editor_entity_at((100.0, 100.0, 100.0))
assert parent_entity.id.IsValid(), "Couldn't create parent entity"
child_entity = EditorEntity.create_editor_entity(parent_id=parent_entity.id)
assert child_entity.id.IsValid(), "Couldn't create child entity"
assert child_entity.get_world_translation().IsClose(parent_entity.get_world_translation()), f"Child entity position{child_entity.get_world_translation().ToString()}" \
f" is not located at the same position as the parent{parent_entity.get_world_translation().ToString()}"
# Asserts if prefab creation doesn't succeed
child_prefab, child_instance = Prefab.create_prefab([child_entity], CAR_PREFAB_FILE_NAME)
child_entity_on_child_instance = child_instance.get_direct_child_entities()[0]
assert child_instance.container_entity.get_parent_id().IsValid(), "Newly instanced entity has no parent"
assert child_instance.container_entity.get_parent_id() == parent_entity.id, "Newly instanced entity parent does not match the expected parent"
assert child_instance.container_entity.get_world_translation().IsClose(parent_entity.get_world_translation()), "Newly instanced entity position is not located at the same position as the parent"
# Move the parent position, it should update the child position
parent_entity.set_world_translation((200.0, 200.0, 200.0))
child_instance_translation = child_instance.container_entity.get_world_translation()
assert child_instance_translation.IsClose(azlmbr.math.Vector3(200.0, 200.0, 200.0)), f"Instance position position{child_instance_translation.ToString()} didn't get updated" \
f" to the same position as the parent{parent_entity.get_world_translation().ToString()}"
child_translation = child_entity_on_child_instance.get_world_translation()
assert child_translation.IsClose(azlmbr.math.Vector3(200.0, 200.0, 200.0)), f"Entity position{child_translation.ToString()} of the instance didn't get updated" \
f" to the same position as the parent{parent_entity.get_world_translation().ToString()}"
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(PrefabComplexWorflow_CreatePrefabOfChildEntity)

@ -4137,7 +4137,15 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware);
Editor::EditorQtApplication* app = Editor::EditorQtApplication::newInstance(argc, argv);
if (app->arguments().contains("-autotest_mode"))
QStringList qArgs = app->arguments();
const bool is_automated_test = AZStd::any_of(qArgs.begin(), qArgs.end(),
[](const QString& elem)
{
return elem.endsWith("autotest_mode") || elem.endsWith("runpythontest");
}
);
if (is_automated_test)
{
// Nullroute all stdout to null for automated tests, this way we make sure
// that the test result output is not polluted with unrelated output data.

@ -168,6 +168,11 @@ namespace AZ
//! Rotation modifiers
//! @{
//! Set the world rotation matrix using the composition of rotations around
//! the principle axes in the order of z-axis first and y-axis and then x-axis.
//! @param eulerRadianAngles A Vector3 denoting radian angles of the rotations around each principle axis.
virtual void SetWorldRotation([[maybe_unused]] const AZ::Vector3& eulerAnglesRadian) {}
//! Sets the entity's rotation in the world in quaternion notation.
//! The origin of the axes is the entity's position in world space.
//! @param quaternion A quaternion that represents the rotation to use for the entity.

@ -323,6 +323,13 @@ namespace AzFramework
return localZ;
}
void TransformComponent::SetWorldRotation(const AZ::Vector3& eulerAnglesRadian)
{
AZ::Transform newWorldTransform = m_worldTM;
newWorldTransform.SetRotation(AZ::Quaternion::CreateFromEulerAnglesRadians(eulerAnglesRadian));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetWorldRotationQuaternion(const AZ::Quaternion& quaternion)
{
AZ::Transform newWorldTransform = m_worldTM;

@ -108,6 +108,7 @@ namespace AzFramework
float GetLocalZ() override;
// Rotation modifiers
void SetWorldRotation(const AZ::Vector3& eulerAnglesRadian) override;
void SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) override;
AZ::Vector3 GetWorldRotation() override;

Loading…
Cancel
Save