Add a new auto test for delete prefab workflow (#3143)
* Add a new auto test for delete prefab Signed-off-by: chiyteng <chiyteng@amazon.com>
This commit is contained in:
@@ -7,10 +7,14 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
# fmt:off
|
||||
class Tests():
|
||||
create_new_entity = ("Entity: 'CreateNewEntity' passed", "Entity: 'CreateNewEntity' failed")
|
||||
create_prefab = ("Prefab: 'CreatePrefab' passed", "Prefab: 'CreatePrefab' failed")
|
||||
instantiate_prefab = ("Prefab: 'InstantiatePrefab' passed", "Prefab: 'InstantiatePrefab' failed")
|
||||
new_prefab_position = ("Prefab: new prefab's position is at the expected position", "Prefab: new prefab's position is *not* at the expected position")
|
||||
create_new_entity = ("'CreateNewEntity' passed", "'CreateNewEntity' failed")
|
||||
create_prefab = ("'CreatePrefab' passed", "'CreatePrefab' failed")
|
||||
instantiate_prefab = ("'InstantiatePrefab' passed", "'InstantiatePrefab' failed")
|
||||
has_one_child = ("instantiated prefab contains only one child as expected", "instantiated prefab does *not* contain only one child as expected")
|
||||
instantiated_prefab_position = ("instantiated prefab's position is at the expected position", "instantiated prefab's position is *not* at the expected position")
|
||||
delete_prefab = ("'DeleteEntitiesAndAllDescendantsInInstance' passed", "'DeleteEntitiesAndAllDescendantsInInstance' failed")
|
||||
instantiated_prefab_removed = ("instantiated prefab's container entity has been removed", "instantiated prefab's container entity has *not* been removed")
|
||||
instantiated_child_removed = ("instantiated prefab's child entity has been removed", "instantiated prefab's child entity has *not* been removed")
|
||||
# fmt:on
|
||||
|
||||
def PrefabLevel_BasicWorkflow():
|
||||
@@ -18,6 +22,7 @@ def PrefabLevel_BasicWorkflow():
|
||||
This test will help verify if the following functions related to Prefab work as expected:
|
||||
- CreatePrefab
|
||||
- InstantiatePrefab
|
||||
- DeleteEntitiesAndAllDescendantsInInstance
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -35,31 +40,68 @@ def PrefabLevel_BasicWorkflow():
|
||||
from azlmbr.math import Vector3
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
EXPECTED_NEW_PREFAB_POSITION = Vector3(10.00, 20.0, 30.0)
|
||||
NEW_PREFAB_NAME = "new_prefab"
|
||||
NEW_PREFAB_FILE_NAME = NEW_PREFAB_NAME + ".prefab"
|
||||
NEW_PREFAB_FILE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), NEW_PREFAB_FILE_NAME)
|
||||
INSTANTIATED_PREFAB_POSITION = Vector3(10.00, 20.0, 30.0)
|
||||
INSTANTIATED_PREFAB_NAME = "instantiated_prefab"
|
||||
INSTANTIATED_CHILD_ENTITY_NAME = "child_1"
|
||||
TEST_LEVEL_FOLDER = "Prefab"
|
||||
TEST_LEVEL_NAME = "Base"
|
||||
|
||||
def find_entity_by_name(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entityIds = entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
|
||||
if entityIds and entityIds[0].IsValid():
|
||||
return entityIds[0]
|
||||
return None
|
||||
|
||||
def print_error_if_failed(prefab_operation_result):
|
||||
if not prefab_operation_result.IsSuccess():
|
||||
Report.info(f'Error message: {prefab_operation_result.GetError()}')
|
||||
|
||||
|
||||
# Open the test level
|
||||
helper.init_idle()
|
||||
helper.open_level("Prefab", "Base")
|
||||
helper.open_level(TEST_LEVEL_FOLDER, TEST_LEVEL_NAME)
|
||||
|
||||
# Create a new Entity at the root level
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
|
||||
Report.result(Tests.create_new_entity, new_entity_id.IsValid())
|
||||
|
||||
# Checks for prefab creation passed or not
|
||||
new_prefab_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'new_prefab.prefab')
|
||||
create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', [new_entity_id], new_prefab_file_path)
|
||||
Report.result(Tests.create_prefab, create_prefab_result)
|
||||
create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', [new_entity_id], NEW_PREFAB_FILE_PATH)
|
||||
Report.result(Tests.create_prefab, create_prefab_result.IsSuccess())
|
||||
print_error_if_failed(create_prefab_result)
|
||||
|
||||
# Checks for prefab instantiation passed or not
|
||||
container_entity_id = prefab.PrefabPublicRequestBus(bus.Broadcast, 'InstantiatePrefab', new_prefab_file_path, EntityId(), EXPECTED_NEW_PREFAB_POSITION)
|
||||
Report.result(Tests.instantiate_prefab, container_entity_id.IsValid())
|
||||
instantiate_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'InstantiatePrefab', NEW_PREFAB_FILE_PATH, EntityId(), INSTANTIATED_PREFAB_POSITION)
|
||||
Report.result(Tests.instantiate_prefab, instantiate_prefab_result.IsSuccess() and instantiate_prefab_result.GetValue().IsValid())
|
||||
print_error_if_failed(instantiate_prefab_result)
|
||||
|
||||
container_entity_id = instantiate_prefab_result.GetValue()
|
||||
editor.EditorEntityAPIBus(bus.Event, 'SetName', container_entity_id, INSTANTIATED_PREFAB_NAME)
|
||||
|
||||
children_entity_ids = editor.EditorEntityInfoRequestBus(bus.Event, 'GetChildren', container_entity_id)
|
||||
Report.result(Tests.has_one_child, len(children_entity_ids) is 1)
|
||||
|
||||
child_entity_id = children_entity_ids[0]
|
||||
editor.EditorEntityAPIBus(bus.Event, 'SetName', child_entity_id, INSTANTIATED_CHILD_ENTITY_NAME)
|
||||
|
||||
# Checks if the new prefab is at the correct position and if it fails, it will provide the expected postion and the actual postion of the entity in the Editor log
|
||||
new_prefab_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", container_entity_id)
|
||||
is_at_position = new_prefab_position.IsClose(EXPECTED_NEW_PREFAB_POSITION)
|
||||
Report.result(Tests.new_prefab_position, is_at_position)
|
||||
actual_prefab_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", container_entity_id)
|
||||
is_at_position = actual_prefab_position.IsClose(INSTANTIATED_PREFAB_POSITION)
|
||||
Report.result(Tests.instantiated_prefab_position, is_at_position)
|
||||
if not is_at_position:
|
||||
Report.info(f'Expected position: {EXPECTED_NEW_PREFAB_POSITION.ToString()}, actual position: {new_prefab_position.ToString()}')
|
||||
|
||||
Report.info(f'Expected position: {INSTANTIATED_PREFAB_POSITION.ToString()}, actual position: {actual_prefab_position.ToString()}')
|
||||
|
||||
# Checks for prefab deletion passed or not
|
||||
delete_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'DeleteEntitiesAndAllDescendantsInInstance', [container_entity_id])
|
||||
Report.result(Tests.delete_prefab, delete_prefab_result.IsSuccess())
|
||||
print_error_if_failed(delete_prefab_result)
|
||||
Report.result(Tests.instantiated_prefab_removed, find_entity_by_name(INSTANTIATED_PREFAB_NAME) is None)
|
||||
Report.result(Tests.instantiated_child_removed, find_entity_by_name(INSTANTIATED_CHILD_ENTITY_NAME) is None)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace AzToolsFramework
|
||||
m_prefabUndoCache.Destroy();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefabInMemory(const EntityIdList& entityIds, AZ::IO::PathView filePath)
|
||||
{
|
||||
EntityList inputEntityList, topLevelEntities;
|
||||
AZ::EntityId commonRootEntityId;
|
||||
@@ -264,7 +264,7 @@ namespace AzToolsFramework
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefabInDisk(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefabInDisk(const EntityIdList& entityIds, AZ::IO::PathView filePath)
|
||||
{
|
||||
auto result = CreatePrefabInMemory(entityIds, filePath);
|
||||
if (result.IsSuccess())
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace AzToolsFramework
|
||||
|
||||
// PrefabPublicInterface...
|
||||
PrefabOperationResult CreatePrefabInDisk(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
|
||||
const EntityIdList& entityIds, AZ::IO::PathView filePath) override;
|
||||
PrefabOperationResult CreatePrefabInMemory(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
|
||||
const EntityIdList& entityIds, AZ::IO::PathView filePath) override;
|
||||
InstantiatePrefabResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
PrefabOperationResult SavePrefab(AZ::IO::Path filePath) override;
|
||||
PrefabEntityResult CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) override;
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace AzToolsFramework
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefabInDisk(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
const EntityIdList& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
|
||||
/**
|
||||
* Create a prefab out of the entities provided, at the path provided, and keep it in memory.
|
||||
@@ -57,7 +57,7 @@ namespace AzToolsFramework
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefabInMemory(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
const EntityIdList& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
|
||||
@@ -11,13 +11,20 @@
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
using EntityIdList = AZStd::vector<AZ::EntityId>;
|
||||
|
||||
namespace Prefab
|
||||
{
|
||||
using PrefabOperationResult = AZ::Outcome<void, AZStd::string>;
|
||||
using InstantiatePrefabResult = AZ::Outcome<AZ::EntityId, AZStd::string>;
|
||||
|
||||
/**
|
||||
* The primary purpose of this bus is to facilitate writing automated tests for prefabs.
|
||||
* It calls PrefabPublicInterface internally to talk to the prefab system.
|
||||
@@ -40,14 +47,25 @@ namespace AzToolsFramework
|
||||
/**
|
||||
* Create a prefab out of the entities provided, at the path provided, and keep it in memory.
|
||||
* Automatically detects descendants of entities, and discerns between entities and child instances.
|
||||
* Return whether the creation succeeded or not.
|
||||
*/
|
||||
virtual bool CreatePrefabInMemory(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) = 0;
|
||||
virtual PrefabOperationResult CreatePrefabInMemory(
|
||||
const EntityIdList& entityIds, AZStd::string_view filePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
* Return the container entity id of the prefab instantiated if instantiation succeeded.
|
||||
*/
|
||||
virtual AZ::EntityId InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
|
||||
virtual InstantiatePrefabResult InstantiatePrefab(
|
||||
AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
|
||||
|
||||
/**
|
||||
* Deletes all entities and their descendants from the owning instance. Bails if the entities don't
|
||||
* all belong to the same instance.
|
||||
* Return whether the deletion succeeded or not.
|
||||
*/
|
||||
virtual PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) = 0;
|
||||
|
||||
};
|
||||
|
||||
using PrefabPublicRequestBus = AZ::EBus<PrefabPublicRequests>;
|
||||
|
||||
+11
-26
@@ -25,6 +25,7 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Event("CreatePrefabInMemory", &PrefabPublicRequests::CreatePrefabInMemory)
|
||||
->Event("InstantiatePrefab", &PrefabPublicRequests::InstantiatePrefab)
|
||||
->Event("DeleteEntitiesAndAllDescendantsInInstance", &PrefabPublicRequests::DeleteEntitiesAndAllDescendantsInInstance)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -44,36 +45,20 @@ namespace AzToolsFramework
|
||||
m_prefabPublicInterface = nullptr;
|
||||
}
|
||||
|
||||
bool PrefabPublicRequestHandler::CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath)
|
||||
PrefabOperationResult PrefabPublicRequestHandler::CreatePrefabInMemory(const EntityIdList& entityIds, AZStd::string_view filePath)
|
||||
{
|
||||
auto createPrefabOutcome = m_prefabPublicInterface->CreatePrefabInMemory(entityIds, filePath);
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("CreatePrefabInMemory", false,
|
||||
"Failed to create Prefab on file path '%.*s'. Error message: %s.",
|
||||
AZ_STRING_ARG(filePath),
|
||||
createPrefabOutcome.GetError().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_prefabPublicInterface->CreatePrefabInMemory(entityIds, filePath);
|
||||
}
|
||||
|
||||
AZ::EntityId PrefabPublicRequestHandler::InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
|
||||
InstantiatePrefabResult PrefabPublicRequestHandler::InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
|
||||
{
|
||||
auto instantiatePrefabOutcome = m_prefabPublicInterface->InstantiatePrefab(filePath, parent, position);
|
||||
if (!instantiatePrefabOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("InstantiatePrefab", false,
|
||||
"Failed to instantiate Prefab on file path '%.*s'. Error message: %s.",
|
||||
AZ_STRING_ARG(filePath),
|
||||
instantiatePrefabOutcome.GetError().c_str());
|
||||
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
return instantiatePrefabOutcome.GetValue();
|
||||
return m_prefabPublicInterface->InstantiatePrefab(filePath, parent, position);
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicRequestHandler::DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds)
|
||||
{
|
||||
return m_prefabPublicInterface->DeleteEntitiesAndAllDescendantsInInstance(entityIds);
|
||||
}
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+3
-2
@@ -31,8 +31,9 @@ namespace AzToolsFramework
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
bool CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) override;
|
||||
AZ::EntityId InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
PrefabOperationResult CreatePrefabInMemory(const EntityIdList& entityIds, AZStd::string_view filePath) override;
|
||||
InstantiatePrefabResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
|
||||
PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) override;
|
||||
|
||||
private:
|
||||
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user