Merge branch 'main' into Prefab/CreatePrefab

This commit is contained in:
srikappa
2021-04-19 17:26:53 -07:00
117 changed files with 1845 additions and 1265 deletions
@@ -578,16 +578,6 @@ namespace AzToolsFramework
*/
virtual bool IsEditorInIsolationMode() = 0;
/*!
* Get the engine root path that the current tool is running under.
*/
virtual const char* GetEngineRootPath() const = 0;
/**
* Get the version of the engine the current tools application is running under
*/
virtual const char* GetEngineVersion() const = 0;
/**
* Creates and adds a new entity to the tools application from components which match at least one of the requiredTags
* The tag matching occurs on AZ::Edit::SystemComponentTags attribute from the reflected class data in the serialization context
@@ -224,112 +224,6 @@ namespace AzToolsFramework
} // Internal
#define AZ_MAX_ENGINE_VERSION_LEN 64
// Private Implementation class to manage the engine root and version
// Note: We are not using any AzCore classes because the ToolsApplication
// initialization happens early on, before the Allocators get instantiated,
// so we are using Qt privately instead
class ToolsApplication::EngineConfigImpl
{
private:
friend class ToolsApplication;
typedef QMap<QString, QString> EngineJsonMap;
EngineConfigImpl(const char* logWindow, const char* fileName)
: m_logWindow(logWindow)
, m_fileName(fileName)
{
m_engineRoot[0] = '\0';
m_engineVersion[0] = '\0';
}
char m_engineRoot[AZ_MAX_PATH_LEN];
char m_engineVersion[AZ_MAX_ENGINE_VERSION_LEN];
EngineJsonMap m_engineConfigMap;
const char* m_logWindow;
const char* m_fileName;
// Read an engine configuration into a map of key/value pairs
bool ReadEngineConfigIntoMap(QString engineJsonPath, EngineJsonMap& engineJsonMap)
{
QFile engineJsonFile(engineJsonPath);
if (!engineJsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
AZ_Warning(m_logWindow, false, "Unable to open file '%s' in the current root directory", engineJsonPath.toUtf8().data());
return false;
}
QByteArray engineJsonData = engineJsonFile.readAll();
engineJsonFile.close();
QJsonDocument engineJsonDoc(QJsonDocument::fromJson(engineJsonData));
if (engineJsonDoc.isNull())
{
AZ_Warning(m_logWindow, false, "Unable to read file '%s' in the current root directory", engineJsonPath.toUtf8().data());
return false;
}
QJsonObject engineJsonRoot = engineJsonDoc.object();
for (const QString& configKey : engineJsonRoot.keys())
{
QJsonValue configValue = engineJsonRoot[configKey];
if (configValue.isString() || configValue.isDouble())
{
// Only map strings and numbers, ignore every other type
engineJsonMap[configKey] = configValue.toString();
}
else
{
AZ_Warning(m_logWindow, false, "Ignoring key '%s' from '%s', unsupported type.", configKey.toUtf8().data(), engineJsonPath.toUtf8().data());
}
}
return true;
}
// Initialize the engine config object based on the current
bool Initialize(const char* currentEngineRoot)
{
// Start with the app root as the engine root (legacy), but check to see if the engine root
// is external to the app root
azstrncpy(m_engineRoot, AZ_ARRAY_SIZE(m_engineRoot), currentEngineRoot, strlen(currentEngineRoot) + 1);
// From the appRoot, check and see if we can read any external engine reference in engine.json
QString engineJsonFileName = QString(m_fileName);
QString engineJsonFilePath = QDir(currentEngineRoot).absoluteFilePath(engineJsonFileName);
// From the appRoot, check and see if we can read any external engine reference in engine.json
if (!QFile::exists(engineJsonFilePath))
{
AZ_Warning(m_logWindow, false, "Unable to find '%s' in the current app root directory.", m_fileName);
return false;
}
if (!ReadEngineConfigIntoMap(engineJsonFilePath, m_engineConfigMap))
{
AZ_Warning(m_logWindow, false, "Defaulting root engine path to '%s'", currentEngineRoot);
return false;
}
// Read in the local engine version value
auto localEngineVersionValue = m_engineConfigMap.find(QString(AzToolsFramework::Internal::s_engineConfigEngineVersionKey));
QString localEngineVersion(localEngineVersionValue.value());
azstrncpy(m_engineVersion, AZ_ARRAY_SIZE(m_engineVersion), localEngineVersion.toUtf8().data(), localEngineVersion.length() + 1);
return true;
}
const char* GetEngineRoot() const
{
return m_engineRoot;
}
const char* GetEngineVersion() const
{
return m_engineVersion;
}
};
ToolsApplication::ToolsApplication(int* argc, char*** argv)
: AzFramework::Application(argc, argv)
, m_selectionBounds(AZ::Aabb())
@@ -339,7 +233,6 @@ namespace AzToolsFramework
, m_isInIsolationMode(false)
{
ToolsApplicationRequests::Bus::Handler::BusConnect();
m_engineConfigImpl.reset(new ToolsApplication::EngineConfigImpl(AzToolsFramework::Internal::s_startupLogWindow, AzToolsFramework::Internal::s_engineConfigFileName));
m_undoCache.RegisterToUndoCacheInterface();
}
@@ -391,7 +284,6 @@ namespace AzToolsFramework
void ToolsApplication::Start(const Descriptor& descriptor, const StartupParameters& startupParameters/* = StartupParameters()*/)
{
Application::Start(descriptor, startupParameters);
InitializeEngineConfig();
m_editorEntityManager.Start();
@@ -399,14 +291,6 @@ namespace AzToolsFramework
AZ_Assert(m_editorEntityAPI, "ToolsApplication - Could not retrieve instance of EditorEntityAPI");
}
void ToolsApplication::InitializeEngineConfig()
{
if (!m_engineConfigImpl->Initialize(GetEngineRoot()))
{
AZ_Warning(AzToolsFramework::Internal::s_startupLogWindow, false, "Defaulting engine root path to '%s'", GetEngineRoot());
}
}
void ToolsApplication::StartCommon(AZ::Entity* systemEntity)
{
Application::StartCommon(systemEntity);
@@ -1832,16 +1716,6 @@ namespace AzToolsFramework
return m_isInIsolationMode;
}
const char* ToolsApplication::GetEngineRootPath() const
{
return m_engineConfigImpl->GetEngineRoot();
}
const char* ToolsApplication::GetEngineVersion() const
{
return m_engineConfigImpl->GetEngineVersion();
}
void ToolsApplication::CreateAndAddEntityFromComponentTags(const AZStd::vector<AZ::Crc32>& requiredTags, const char* entityName)
{
if (!entityName || !entityName[0])
@@ -150,8 +150,6 @@ namespace AzToolsFramework
void EnterEditorIsolationMode() override;
void ExitEditorIsolationMode() override;
bool IsEditorInIsolationMode() override;
const char* GetEngineRootPath() const override;
const char* GetEngineVersion() const override;
void CreateAndAddEntityFromComponentTags(const AZStd::vector<AZ::Crc32>& requiredTags, const char* entityName) override;
@@ -174,7 +172,6 @@ namespace AzToolsFramework
void CreateUndosForDirtyEntities();
void ConsistencyCheckUndoCache();
void InitializeEngineConfig();
AZ::Aabb m_selectionBounds;
EntityIdList m_selectedEntities;
EntityIdList m_highlightedEntities;
@@ -186,9 +183,6 @@ namespace AzToolsFramework
bool m_isInIsolationMode;
EntityIdSet m_isolatedEntityIdSet;
class EngineConfigImpl;
AZStd::unique_ptr<EngineConfigImpl> m_engineConfigImpl;
EditorEntityAPI* m_editorEntityAPI = nullptr;
EditorEntityManager m_editorEntityManager;
@@ -136,6 +136,48 @@ namespace AzToolsFramework
return entity->GetName();
}
EntityList EntityIdListToEntityList(const EntityIdList& inputEntityIds)
{
EntityList entities;
entities.reserve(inputEntityIds.size());
for (AZ::EntityId entityId : inputEntityIds)
{
if (!entityId.IsValid())
{
continue;
}
if (auto entity = GetEntityById(entityId))
{
entities.emplace_back(entity);
}
}
return entities;
}
EntityList EntityIdSetToEntityList(const EntityIdSet& inputEntityIds)
{
EntityList entities;
entities.reserve(inputEntityIds.size());
for (AZ::EntityId entityId : inputEntityIds)
{
if (!entityId.IsValid())
{
continue;
}
if (auto entity = GetEntityById(entityId))
{
entities.emplace_back(entity);
}
}
return entities;
}
void GetAllComponentsForEntity(const AZ::Entity* entity, AZ::Entity::ComponentArrayType& componentsOnEntity)
{
if (entity)
@@ -1068,6 +1110,45 @@ namespace AzToolsFramework
return !allEntityClonesContainer.m_entities.empty();
}
EntityIdSet GetCulledEntityHierarchy(const EntityIdList& entities)
{
EntityIdSet culledEntities;
for (const AZ::EntityId& entityId : entities)
{
bool selectionIncludesTransformHeritage = false;
AZ::EntityId parentEntityId = entityId;
do
{
AZ::EntityId nextParentId;
AZ::TransformBus::EventResult(
/*result*/ nextParentId,
/*address*/ parentEntityId,
&AZ::TransformBus::Events::GetParentId);
parentEntityId = nextParentId;
if (!parentEntityId.IsValid())
{
break;
}
for (const AZ::EntityId& parentCheck : entities)
{
if (parentCheck == parentEntityId)
{
selectionIncludesTransformHeritage = true;
break;
}
}
} while (parentEntityId.IsValid() && !selectionIncludesTransformHeritage);
if (!selectionIncludesTransformHeritage)
{
culledEntities.insert(entityId);
}
}
return culledEntities;
}
namespace Internal
{
void CloneSliceEntitiesAndChildren(
@@ -47,6 +47,9 @@ namespace AzToolsFramework
AZStd::string GetEntityName(const AZ::EntityId& entityId, const AZStd::string_view& nameOverride = {});
EntityList EntityIdListToEntityList(const EntityIdList& inputEntityIds);
EntityList EntityIdSetToEntityList(const EntityIdSet& inputEntityIds);
template <typename... ComponentTypes>
struct AddComponents
{
@@ -202,4 +205,8 @@ namespace AzToolsFramework
/// Wrap EBus SetSelectedEntities call.
void SelectEntities(const AzToolsFramework::EntityIdList& entities);
/// Return a set of entities, culling any that have an ancestor in the list.
/// e.g. This is useful for getting a concise set of entities that need to be duplicated.
EntityIdSet GetCulledEntityHierarchy(const EntityIdList& entities);
}; // namespace AzToolsFramework
@@ -153,7 +153,7 @@ namespace AzToolsFramework
AZ::EntityId& commonRootEntityId, InstanceOptionalReference& commonRootEntityOwningInstance)
{
// Retrieve entityList from entityIds
EntityIdListToEntityList(entityIds, inputEntityList);
inputEntityList = EntityIdListToEntityList(entityIds);
// Find common root and top level entities
bool entitiesHaveCommonRoot = false;
@@ -485,8 +485,7 @@ namespace AzToolsFramework
InstanceOptionalReference instance = GetOwnerInstanceByEntityId(entityIds[0]);
// Retrieve entityList from entityIds
EntityList inputEntityList;
EntityIdListToEntityList(entityIds, inputEntityList);
EntityList inputEntityList = EntityIdListToEntityList(entityIds);
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -833,18 +832,5 @@ namespace AzToolsFramework
return true;
}
void PrefabPublicHandler::EntityIdListToEntityList(const EntityIdList& inputEntityIds, EntityList& outEntities)
{
outEntities.reserve(inputEntityIds.size());
for (AZ::EntityId entityId : inputEntityIds)
{
if (entityId.IsValid())
{
outEntities.emplace_back(GetEntityById(entityId));
}
}
}
}
}
@@ -99,7 +99,6 @@ namespace AzToolsFramework
static Instance* GetParentInstance(Instance* instance);
static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant);
static void GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation);
static void EntityIdListToEntityList(const EntityIdList& inputEntityIds, EntityList& outEntities);
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
@@ -38,6 +38,7 @@ AZ_POP_DISABLE_WARNING
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/Asset/SimpleAsset.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
@@ -1212,9 +1213,8 @@ namespace AzToolsFramework
if (!QFile::exists(path))
{
const char* engineRoot = nullptr;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(engineRoot, &AzToolsFramework::ToolsApplicationRequests::GetEngineRootPath);
QDir engineDir = engineRoot ? QDir(engineRoot) : QDir::current();
AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath();
QDir engineDir = !engineRoot.empty() ? QDir(QString(engineRoot.c_str())) : QDir::current();
path = engineDir.absoluteFilePath(iconPath.c_str());
}
@@ -68,7 +68,7 @@ namespace UnitTest
{
assets[idx] = AssetId(AZ::Uuid::CreateRandom(), 0);
AZ::Data::AssetInfo info;
info.m_relativePath = AZStd::string::format("Asset%d.txt", idx);
info.m_relativePath = AZStd::string::format("asset%d.txt", idx);
m_assetsPath[idx] = info.m_relativePath;
info.m_assetId = assets[idx];
m_assetRegistry->RegisterAsset(assets[idx], info);
@@ -623,7 +623,7 @@ namespace UnitTest
EXPECT_TRUE(Search(assetList1, assets[fileIndex]));
if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{
AZStd::string fileContent = AZStd::string::format("Asset%d.txt", fileIndex);
AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex);
m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str());
m_fileStreams[0][fileIndex].Close();
}
@@ -654,7 +654,7 @@ namespace UnitTest
EXPECT_TRUE(Search(assetList1, assets[fileIndex]));
if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{
AZStd::string fileContent = AZStd::string::format("Asset%d.txt", fileIndex + 1);// changing file content
AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex + 1);// changing file content
m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str());
m_fileStreams[0][fileIndex].Close();
}
@@ -987,7 +987,7 @@ namespace UnitTest
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
m_assetSeedManager->RemoveSeedAsset("Asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList();
EXPECT_EQ(secondSeedList.size(), 0);
}
@@ -1003,7 +1003,7 @@ namespace UnitTest
m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
m_assetSeedManager->RemoveSeedAsset("Asset0.txt", AzFramework::PlatformFlags::Platform_PC);
m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC);
const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList();
EXPECT_EQ(secondSeedList.size(), 1);
}
@@ -1017,7 +1017,7 @@ namespace UnitTest
EXPECT_EQ(seedList.size(), 1);
m_assetSeedManager->RemoveSeedAsset("Asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
m_assetSeedManager->RemoveSeedAsset("asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX);
const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList();
EXPECT_EQ(secondSeedList.size(), 1);
}
@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzTest/AzTest.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
namespace UnitTest
{
class EditorEntityHelpersTest
: public ToolsApplicationFixture
{
void SetUpEditorFixtureImpl() override
{
m_parent1 = CreateDefaultEditorEntity("Parent1");
m_child1 = CreateDefaultEditorEntity("Child1");
m_child2 = CreateDefaultEditorEntity("Child2");
m_grandChild1 = CreateDefaultEditorEntity("GrandChild1");
m_parent2 = CreateDefaultEditorEntity("Parent2");
AZ::TransformBus::Event(m_child1, &AZ::TransformBus::Events::SetParent, m_parent1);
AZ::TransformBus::Event(m_child2, &AZ::TransformBus::Events::SetParent, m_parent1);
AZ::TransformBus::Event(m_grandChild1, &AZ::TransformBus::Events::SetParent, m_child1);
}
public:
AZ::EntityId m_parent1;
AZ::EntityId m_child1;
AZ::EntityId m_child2;
AZ::EntityId m_grandChild1;
AZ::EntityId m_parent2;
};
TEST_F(EditorEntityHelpersTest, EditorEntityHelpersTests_GetCulledEntityHierarchy)
{
AzToolsFramework::EntityIdList testEntityIds{ m_parent1, m_child1, m_child2, m_grandChild1, m_parent2 };
AzToolsFramework::EntityIdSet culledSet = AzToolsFramework::GetCulledEntityHierarchy(testEntityIds);
// There should only be two EntityIds returned (m_parent1, and m_parent2),
// since all the others should be culled out since they have a common ancestor
// in the list already
using ::testing::UnorderedElementsAre;
EXPECT_THAT(culledSet, UnorderedElementsAre(m_parent1, m_parent2));
}
}
@@ -85,7 +85,9 @@ set(FILES
Prefab/SpawnableSortEntitiesTestFixture.cpp
Prefab/SpawnableSortEntitiesTestFixture.h
Entity/EditorEntityContextComponentTests.cpp
Entity/EditorEntityHelpersTests.cpp
Entity/EditorEntitySearchComponentTests.cpp
Entity/EditorEntitySelectionTests.cpp
SliceStabilityTests/SliceStabilityTestFramework.h
SliceStabilityTests/SliceStabilityTestFramework.cpp
SliceStabilityTests/SliceStabilityCreateTests.cpp