Merge branch 'main' into jckand/FoundationAuto
This commit is contained in:
@@ -16,16 +16,16 @@
|
||||
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
# Enable after installing NodeJS and CDK on jenkins Windows AMI.
|
||||
#ly_add_pytest(
|
||||
# NAME AutomatedTesting::AWSTests
|
||||
# TEST_SUITE periodic
|
||||
# TEST_SERIAL
|
||||
# PATH ${CMAKE_CURRENT_LIST_DIR}/AWS/${PAL_PLATFORM_NAME}/
|
||||
# RUNTIME_DEPENDENCIES
|
||||
# Legacy::Editor
|
||||
# AZ::AssetProcessor
|
||||
# AutomatedTesting.Assets
|
||||
# COMPONENT
|
||||
# AWS
|
||||
#)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AWSTests
|
||||
TEST_SUITE periodic
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/${PAL_PLATFORM_NAME}/
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
AWS
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
@@ -68,6 +68,7 @@ class TestAWSClientAuthAnonymousCredentials(object):
|
||||
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
|
||||
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
|
||||
@@ -67,6 +67,7 @@ class TestAWSClientAuthPasswordSignIn(object):
|
||||
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
|
||||
|
||||
launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignUp']
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
@@ -87,6 +88,7 @@ class TestAWSClientAuthPasswordSignIn(object):
|
||||
)
|
||||
|
||||
launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignIn']
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
|
||||
+10
-4
@@ -10,8 +10,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import os
|
||||
from os.path import abspath
|
||||
import pytest
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
AWS_RESOURCE_MAPPINGS_KEY = 'AWSResourceMappings'
|
||||
AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY = 'AccountId'
|
||||
@@ -57,9 +61,9 @@ class ResourceMappings:
|
||||
stacks = response.get('Stacks', [])
|
||||
assert len(stacks) == 1, f'{stack_name} is invalid.'
|
||||
|
||||
self.__write_resource_mappings(stacks[0].get('Outputs', []))
|
||||
self._write_resource_mappings(stacks[0].get('Outputs', []))
|
||||
|
||||
def __write_resource_mappings(self, outputs, append_feature_name = True) -> None:
|
||||
def _write_resource_mappings(self, outputs, append_feature_name = True) -> None:
|
||||
with open(self._resource_mapping_file_path) as file_content:
|
||||
resource_mappings = json.load(file_content)
|
||||
|
||||
@@ -129,8 +133,10 @@ def resource_mappings(
|
||||
:return: ResourceMappings class object.
|
||||
"""
|
||||
|
||||
path = f'{workspace.paths.engine_root()}\\{project}\\Config\\{resource_mappings_filename}'
|
||||
resource_mappings_obj = ResourceMappings(path, aws_utils.assume_session().region_name, feature_name,
|
||||
path = f'{workspace.paths.engine_root()}/{project}/Config/{resource_mappings_filename}'
|
||||
logger.info(f'Resource mapping path : {path}')
|
||||
logger.info(f'Resource mapping resolved path : {abspath(path)}')
|
||||
resource_mappings_obj = ResourceMappings(abspath(path), aws_utils.assume_session().region_name, feature_name,
|
||||
aws_utils.assume_account_id(), workspace,
|
||||
aws_utils.client('cloudformation'))
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
@@ -26,19 +26,23 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
"""Holds tests for Atom components."""
|
||||
|
||||
@pytest.mark.test_case_id(
|
||||
"C32078130", # Display Mapper
|
||||
"C32078129", # Light
|
||||
"C32078131", # Radius Weight Modifier
|
||||
"C32078127", # PostFX Layer
|
||||
"C32078125", # Physical Sky
|
||||
"C32078115", # Global Skylight (IBL)
|
||||
"C32078121", # Exposure Control
|
||||
"C32078120", # Directional Light
|
||||
"C32078119", # DepthOfField
|
||||
"C32078118") # Decal (Atom)
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the following Atom components and verifies all "expected_lines" appear in Editor.log:
|
||||
1. Display Mapper
|
||||
2. Light
|
||||
3. Radius Weight Modifier
|
||||
4. PostFX Layer
|
||||
5. Physical Sky
|
||||
6. Global Skylight (IBL)
|
||||
7. Exposure Control
|
||||
8. Directional Light
|
||||
9. DepthOfField
|
||||
10. Decal (Atom)
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -224,7 +224,7 @@ void RCcontrollerTest_Simple::SubmitJob()
|
||||
|
||||
// This is a regresssion test to ensure the rccontroller can handle multiple jobs for the same file being completed before
|
||||
// the APM has a chance to send OnFinishedProcesssingJob events
|
||||
TEST_F(RCcontrollerTest_Simple, SameJobIsCompletedMultipleTimes_CompletesWithoutError)
|
||||
TEST_F(RCcontrollerTest_Simple, DISABLED_SameJobIsCompletedMultipleTimes_CompletesWithoutError)
|
||||
{
|
||||
using namespace AssetProcessor;
|
||||
|
||||
|
||||
@@ -97,6 +97,11 @@ namespace AZ
|
||||
return m_configFilePath.c_str();
|
||||
}
|
||||
|
||||
void Application::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const
|
||||
{
|
||||
appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Tool;
|
||||
}
|
||||
|
||||
void Application::SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations)
|
||||
{
|
||||
AZ::ComponentApplication::SetSettingsRegistrySpecializations(specializations);
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace AZ
|
||||
|
||||
const char* GetConfigFilePath() const;
|
||||
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& appType) const override;
|
||||
|
||||
protected:
|
||||
void SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations) override;
|
||||
|
||||
@@ -25,8 +25,11 @@
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Archive/IArchive.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
@@ -36,7 +39,6 @@
|
||||
|
||||
// SliceConverter reads in a slice file (saved in an ObjectStream format), instantiates it, creates a prefab out of the data,
|
||||
// and saves the prefab in a JSON format. This can be used for one-time migrations of slices or slice-based levels to prefabs.
|
||||
// This converter is still in an early state. It can convert trivial slices, but it cannot handle nested slices yet.
|
||||
//
|
||||
// If the slice contains legacy data, it will print out warnings / errors about the data that couldn't be serialized.
|
||||
// The prefab will be generated without that data.
|
||||
@@ -70,6 +72,20 @@ namespace AZ
|
||||
AZ_Error("Convert-Slice", false, "No json registration context found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connect to the Asset Processor so that we can get the correct source path to any nested slice references.
|
||||
if (!ConnectToAssetProcessor())
|
||||
{
|
||||
AZ_Error("Convert-Slice", false, " Failed to connect to the Asset Processor.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the asset catalog so that we can find any nested assets successfully. We also need to tick the tick bus
|
||||
// so that the OnCatalogLoaded event gets processed now, instead of during application shutdown.
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml");
|
||||
application.Tick();
|
||||
|
||||
AZStd::string logggingScratchBuffer;
|
||||
SetupLogging(logggingScratchBuffer, convertSettings.m_reporting, *commandLine);
|
||||
|
||||
@@ -80,83 +96,90 @@ namespace AZ
|
||||
verifySettings.m_serializeContext = application.GetSerializeContext();
|
||||
SetupLogging(logggingScratchBuffer, verifySettings.m_reporting, *commandLine);
|
||||
|
||||
auto archiveInterface = AZ::Interface<AZ::IO::IArchive>::Get();
|
||||
|
||||
// Find the Prefab System Component for use in creating and saving the prefab
|
||||
AZ::Entity* systemEntity = application.FindEntity(AZ::SystemEntityId);
|
||||
AZ_Assert(systemEntity != nullptr, "System entity doesn't exist.");
|
||||
auto prefabSystemComponent = systemEntity->FindComponent<AzToolsFramework::Prefab::PrefabSystemComponent>();
|
||||
AZ_Assert(prefabSystemComponent != nullptr, "Prefab System component doesn't exist");
|
||||
|
||||
bool result = true;
|
||||
rapidjson::StringBuffer scratchBuffer;
|
||||
|
||||
// Loop through the list of requested files and convert them.
|
||||
AZStd::vector<AZStd::string> fileList = Utilities::ReadFileListFromCommandLine(application, "files");
|
||||
for (AZStd::string& filePath : fileList)
|
||||
{
|
||||
bool packOpened = false;
|
||||
|
||||
AZ::IO::Path outputPath = filePath;
|
||||
outputPath.ReplaceExtension("prefab");
|
||||
|
||||
AZ_Printf("Convert-Slice", "------------------------------------------------------------------------------------------\n");
|
||||
AZ_Printf("Convert-Slice", "Converting '%s' to '%s'\n", filePath.c_str(), outputPath.c_str());
|
||||
|
||||
AZ::IO::Path inputPath = filePath;
|
||||
auto fileExtension = inputPath.Extension();
|
||||
if (fileExtension == ".ly")
|
||||
{
|
||||
// Special case: for level files, we need to open the .ly zip file and convert the levelentities.editor_xml file
|
||||
// inside of it. All the other files can be ignored as they are deprecated legacy system files that are no longer
|
||||
// loaded with prefab-based levels.
|
||||
packOpened = archiveInterface->OpenPack(filePath);
|
||||
inputPath.ReplaceFilename("levelentities.editor_xml");
|
||||
AZ_Warning("Convert-Slice", packOpened, " '%s' could not be opened as a pack file.\n", filePath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning(
|
||||
"Convert-Slice", (fileExtension == ".slice"),
|
||||
" Warning: Only .ly and .slice files are supported, conversion of '%.*s' may not work.\n",
|
||||
AZ_STRING_ARG(fileExtension.Native()));
|
||||
}
|
||||
|
||||
auto callback = [prefabSystemComponent, &outputPath, isDryRun]
|
||||
(void* classPtr, const Uuid& classId, [[maybe_unused]] SerializeContext* context)
|
||||
{
|
||||
if (classId != azrtti_typeid<AZ::Entity>())
|
||||
{
|
||||
AZ_Printf("Convert-Slice", " File not converted: Slice root is not an entity.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Entity* rootEntity = reinterpret_cast<AZ::Entity*>(classPtr);
|
||||
return ConvertSliceFile(prefabSystemComponent, outputPath, isDryRun, rootEntity);
|
||||
};
|
||||
|
||||
if (!Utilities::InspectSerializedFile(inputPath.c_str(), convertSettings.m_serializeContext, callback))
|
||||
{
|
||||
AZ_Warning("Convert-Slice", false, "Failed to load '%s'. File may not contain an object stream.", inputPath.c_str());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (packOpened)
|
||||
{
|
||||
[[maybe_unused]] bool closeResult = archiveInterface->ClosePack(filePath);
|
||||
AZ_Warning("Convert-Slice", closeResult, "Failed to close '%s'.", filePath.c_str());
|
||||
}
|
||||
|
||||
AZ_Printf("Convert-Slice", "Finished converting '%s' to '%s'\n", filePath.c_str(), outputPath.c_str());
|
||||
AZ_Printf("Convert-Slice", "------------------------------------------------------------------------------------------\n");
|
||||
bool convertResult = ConvertSliceFile(convertSettings.m_serializeContext, filePath, isDryRun);
|
||||
result = result && convertResult;
|
||||
}
|
||||
|
||||
DisconnectFromAssetProcessor();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SliceConverter::ConvertSliceFile(
|
||||
AzToolsFramework::Prefab::PrefabSystemComponent* prefabSystemComponent, AZ::IO::PathView outputPath, bool isDryRun,
|
||||
AZ::Entity* rootEntity)
|
||||
AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun)
|
||||
{
|
||||
bool result = true;
|
||||
bool packOpened = false;
|
||||
|
||||
auto archiveInterface = AZ::Interface<AZ::IO::IArchive>::Get();
|
||||
|
||||
AZ::IO::Path outputPath = slicePath;
|
||||
outputPath.ReplaceExtension("prefab");
|
||||
|
||||
AZ_Printf("Convert-Slice", "------------------------------------------------------------------------------------------\n");
|
||||
AZ_Printf("Convert-Slice", "Converting '%s' to '%s'\n", slicePath.c_str(), outputPath.c_str());
|
||||
|
||||
AZ::IO::Path inputPath = slicePath;
|
||||
auto fileExtension = inputPath.Extension();
|
||||
if (fileExtension == ".ly")
|
||||
{
|
||||
// Special case: for level files, we need to open the .ly zip file and convert the levelentities.editor_xml file
|
||||
// inside of it. All the other files can be ignored as they are deprecated legacy system files that are no longer
|
||||
// loaded with prefab-based levels.
|
||||
packOpened = archiveInterface->OpenPack(slicePath);
|
||||
inputPath.ReplaceFilename("levelentities.editor_xml");
|
||||
AZ_Warning("Convert-Slice", packOpened, " '%s' could not be opened as a pack file.\n", slicePath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning(
|
||||
"Convert-Slice", (fileExtension == ".slice"),
|
||||
" Warning: Only .ly and .slice files are supported, conversion of '%.*s' may not work.\n",
|
||||
AZ_STRING_ARG(fileExtension.Native()));
|
||||
}
|
||||
|
||||
auto callback = [&outputPath, isDryRun](void* classPtr, const Uuid& classId, SerializeContext* context)
|
||||
{
|
||||
if (classId != azrtti_typeid<AZ::Entity>())
|
||||
{
|
||||
AZ_Printf("Convert-Slice", " File not converted: Slice root is not an entity.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Entity* rootEntity = reinterpret_cast<AZ::Entity*>(classPtr);
|
||||
return ConvertSliceToPrefab(context, outputPath, isDryRun, rootEntity);
|
||||
};
|
||||
|
||||
// Read in the slice file and call the callback on completion to convert the read-in slice to a prefab.
|
||||
if (!Utilities::InspectSerializedFile(inputPath.c_str(), serializeContext, callback))
|
||||
{
|
||||
AZ_Warning("Convert-Slice", false, "Failed to load '%s'. File may not contain an object stream.", inputPath.c_str());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (packOpened)
|
||||
{
|
||||
[[maybe_unused]] bool closeResult = archiveInterface->ClosePack(slicePath);
|
||||
AZ_Warning("Convert-Slice", closeResult, "Failed to close '%s'.", slicePath.c_str());
|
||||
}
|
||||
|
||||
AZ_Printf("Convert-Slice", "Finished converting '%s' to '%s'\n", slicePath.c_str(), outputPath.c_str());
|
||||
AZ_Printf("Convert-Slice", "------------------------------------------------------------------------------------------\n");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SliceConverter::ConvertSliceToPrefab(
|
||||
AZ::SerializeContext* serializeContext, AZ::IO::PathView outputPath, bool isDryRun, AZ::Entity* rootEntity)
|
||||
{
|
||||
auto prefabSystemComponentInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
|
||||
|
||||
// Find the slice from the root entity.
|
||||
SliceComponent* sliceComponent = AZ::EntityUtils::FindFirstDerivedComponent<SliceComponent>(rootEntity);
|
||||
if (sliceComponent == nullptr)
|
||||
@@ -167,44 +190,21 @@ namespace AZ
|
||||
|
||||
// Get all of the entities from the slice.
|
||||
SliceComponent::EntityList sliceEntities = sliceComponent->GetNewEntities();
|
||||
if (sliceEntities.empty())
|
||||
{
|
||||
AZ_Printf("Convert-Slice", " File not converted: Slice entities could not be retrieved.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ_Warning("Convert-Slice", sliceComponent->GetSlices().empty(), " Slice depends on other slices, this conversion will lose data.\n");
|
||||
AZ_Printf("Convert-Slice", " Slice contains %zu entities.\n", sliceEntities.size());
|
||||
|
||||
// Create the Prefab with the entities from the slice
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sourceInstance(
|
||||
prefabSystemComponent->CreatePrefab(sliceEntities, {}, outputPath));
|
||||
prefabSystemComponentInterface->CreatePrefab(sliceEntities, {}, outputPath));
|
||||
|
||||
// Dispatch events here, because prefab creation might trigger asset loads in rare circumstances.
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
|
||||
// Set up the Prefab container entity to be a proper Editor entity. (This logic is normally triggered
|
||||
// via an EditorRequests EBus in CreatePrefab, but the subsystem that listens for it isn't present in this tool.)
|
||||
// Fix up the container entity to have the proper components and fix up the slice entities to have the proper hierarchy
|
||||
// with the container as the top-most parent.
|
||||
AzToolsFramework::Prefab::EntityOptionalReference container = sourceInstance->GetContainerEntity();
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, container->get());
|
||||
container->get().AddComponent(aznew AzToolsFramework::Prefab::EditorPrefabComponent());
|
||||
|
||||
// Reparent any root-level slice entities to the container entity.
|
||||
for (auto entity : sliceEntities)
|
||||
{
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
if (transformComponent)
|
||||
{
|
||||
if (!transformComponent->GetParentId().IsValid())
|
||||
{
|
||||
transformComponent->SetParent(container->get().GetId());
|
||||
}
|
||||
}
|
||||
}
|
||||
FixPrefabEntities(container->get(), sliceEntities);
|
||||
|
||||
auto templateId = sourceInstance->GetTemplateId();
|
||||
|
||||
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
|
||||
{
|
||||
AZ_Printf("Convert-Slice", " Path error. Path could be invalid, or the prefab may not be loaded in this level.\n");
|
||||
@@ -219,14 +219,27 @@ namespace AZ
|
||||
AZ_Printf("Convert-Slice", " Failed to convert prefab instance data to a PrefabDom.\n");
|
||||
return false;
|
||||
}
|
||||
prefabSystemComponent->UpdatePrefabTemplate(templateId, prefabDom);
|
||||
prefabSystemComponentInterface->UpdatePrefabTemplate(templateId, prefabDom);
|
||||
|
||||
// Dispatch events here, because prefab serialization might trigger asset loads in rare circumstances.
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
|
||||
// If this slice has nested slices, we need to loop through those, convert them to prefabs as well, and
|
||||
// set up the new nesting relationships correctly.
|
||||
const SliceComponent::SliceList& sliceList = sliceComponent->GetSlices();
|
||||
AZ_Printf("Convert-Slice", " Slice contains %zu nested slices.\n", sliceList.size());
|
||||
if (!sliceList.empty())
|
||||
{
|
||||
bool nestedSliceResult = ConvertNestedSlices(sliceComponent, sourceInstance.get(), serializeContext, isDryRun);
|
||||
if (!nestedSliceResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDryRun)
|
||||
{
|
||||
PrintPrefab(prefabDom, sourceInstance->GetTemplateSourcePath());
|
||||
PrintPrefab(templateId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -235,8 +248,187 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void SliceConverter::PrintPrefab(const AzToolsFramework::Prefab::PrefabDom& prefabDom, const AZ::IO::Path& templatePath)
|
||||
void SliceConverter::FixPrefabEntities(AZ::Entity& containerEntity, SliceComponent::EntityList& sliceEntities)
|
||||
{
|
||||
// Set up the Prefab container entity to be a proper Editor entity. (This logic is normally triggered
|
||||
// via an EditorRequests EBus in CreatePrefab, but the subsystem that listens for it isn't present in this tool.)
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, containerEntity);
|
||||
containerEntity.AddComponent(aznew AzToolsFramework::Prefab::EditorPrefabComponent());
|
||||
|
||||
// Reparent any root-level slice entities to the container entity.
|
||||
for (auto entity : sliceEntities)
|
||||
{
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
if (transformComponent)
|
||||
{
|
||||
if (!transformComponent->GetParentId().IsValid())
|
||||
{
|
||||
transformComponent->SetParent(containerEntity.GetId());
|
||||
transformComponent->UpdateCachedWorldTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SliceConverter::ConvertNestedSlices(
|
||||
SliceComponent* sliceComponent, AzToolsFramework::Prefab::Instance* sourceInstance,
|
||||
AZ::SerializeContext* serializeContext, bool isDryRun)
|
||||
{
|
||||
const SliceComponent::SliceList& sliceList = sliceComponent->GetSlices();
|
||||
auto prefabSystemComponentInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
|
||||
|
||||
for (auto& slice : sliceList)
|
||||
{
|
||||
// Get the nested slice asset
|
||||
auto sliceAsset = slice.GetSliceAsset();
|
||||
sliceAsset.QueueLoad();
|
||||
sliceAsset.BlockUntilLoadComplete();
|
||||
|
||||
// The slice list gives us asset IDs, and we need to get to the source path. So first we get the asset path from the ID,
|
||||
// then we get the source path from the asset path.
|
||||
|
||||
AZStd::string processedAssetPath;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
processedAssetPath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, sliceAsset.GetId());
|
||||
|
||||
AZStd::string assetPath;
|
||||
AzToolsFramework::AssetSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath,
|
||||
processedAssetPath, assetPath);
|
||||
if (assetPath.empty())
|
||||
{
|
||||
AZ_Warning("Convert-Slice", false,
|
||||
" Source path for nested slice '%s' could not be found, slice not converted.", processedAssetPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, convert the nested slice to a prefab.
|
||||
bool nestedSliceResult = ConvertSliceFile(serializeContext, assetPath, isDryRun);
|
||||
if (!nestedSliceResult)
|
||||
{
|
||||
AZ_Warning("Convert-Slice", nestedSliceResult, " Nested slice '%s' could not be converted.", assetPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the prefab template for the newly-created nested prefab.
|
||||
// To get the template, we need to take our absolute slice path and turn it into a project-relative prefab path.
|
||||
AZ::IO::Path nestedPrefabPath = assetPath;
|
||||
nestedPrefabPath.ReplaceExtension("prefab");
|
||||
|
||||
auto prefabLoaderInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabLoaderInterface>::Get();
|
||||
nestedPrefabPath = prefabLoaderInterface->GetRelativePathToProject(nestedPrefabPath);
|
||||
|
||||
AzToolsFramework::Prefab::TemplateId nestedTemplateId =
|
||||
prefabSystemComponentInterface->GetTemplateIdFromFilePath(nestedPrefabPath);
|
||||
AzToolsFramework::Prefab::TemplateReference nestedTemplate =
|
||||
prefabSystemComponentInterface->FindTemplate(nestedTemplateId);
|
||||
|
||||
// For each slice instance of the nested slice, convert it to a nested prefab instance instead.
|
||||
|
||||
auto instances = slice.GetInstances();
|
||||
AZ_Printf(
|
||||
"Convert-Slice", " Attaching %zu instances of nested slice '%s'.\n", instances.size(),
|
||||
nestedPrefabPath.Native().c_str());
|
||||
|
||||
for (auto& instance : instances)
|
||||
{
|
||||
bool instanceConvertResult = ConvertSliceInstance(instance, sliceAsset, nestedTemplate, sourceInstance);
|
||||
if (!instanceConvertResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SliceConverter::ConvertSliceInstance(
|
||||
[[maybe_unused]] AZ::SliceComponent::SliceInstance& instance,
|
||||
[[maybe_unused]] AZ::Data::Asset<AZ::SliceAsset>& sliceAsset,
|
||||
AzToolsFramework::Prefab::TemplateReference nestedTemplate,
|
||||
AzToolsFramework::Prefab::Instance* topLevelInstance)
|
||||
{
|
||||
auto instanceToTemplateInterface = AZ::Interface<AzToolsFramework::Prefab::InstanceToTemplateInterface>::Get();
|
||||
auto prefabSystemComponentInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
|
||||
|
||||
// Create a new unmodified prefab Instance for the nested slice instance.
|
||||
auto nestedInstance = AZStd::make_unique<AzToolsFramework::Prefab::Instance>();
|
||||
AzToolsFramework::Prefab::Instance::EntityList newEntities;
|
||||
if (!AzToolsFramework::Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(
|
||||
*nestedInstance, newEntities, nestedTemplate->get().GetPrefabDom()))
|
||||
{
|
||||
AZ_Error(
|
||||
"Convert-Slice", false, " Failed to load and instantiate nested Prefab Template '%s'.",
|
||||
nestedTemplate->get().GetFilePath().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the DOM for the unmodified nested instance. This will be used later below for generating the correct patch
|
||||
// to the top-level template DOM.
|
||||
AzToolsFramework::Prefab::PrefabDom unmodifiedNestedInstanceDom;
|
||||
instanceToTemplateInterface->GenerateDomForInstance(unmodifiedNestedInstanceDom, *(nestedInstance.get()));
|
||||
|
||||
// Currently, DataPatch conversions for nested slices aren't implemented, so all nested slice overrides will
|
||||
// be lost.
|
||||
AZ_Warning(
|
||||
"Convert-Slice", false, " Nested slice instances will lose all of their override data during conversion.",
|
||||
nestedTemplate->get().GetFilePath().c_str());
|
||||
|
||||
// Set the container entity of the nested prefab to have the top-level prefab as the parent.
|
||||
// Once DataPatch conversions are supported, this will need to change to nest the prefab under the appropriate entity
|
||||
// within the level.
|
||||
auto containerEntity = nestedInstance->GetContainerEntity();
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
containerEntity->get().FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
if (transformComponent)
|
||||
{
|
||||
transformComponent->SetParent(topLevelInstance->GetContainerEntityId());
|
||||
transformComponent->UpdateCachedWorldTransform();
|
||||
}
|
||||
|
||||
// Add the nested instance itself to the top-level prefab. To do this, we need to add it to our top-level instance,
|
||||
// create a patch out of it, and patch the top-level prefab template.
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomBefore;
|
||||
instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomBefore, *topLevelInstance);
|
||||
|
||||
AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance));
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomAfter;
|
||||
instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomAfter, *topLevelInstance);
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom addedInstancePatch;
|
||||
instanceToTemplateInterface->GeneratePatch(addedInstancePatch, topLevelInstanceDomBefore, topLevelInstanceDomAfter);
|
||||
instanceToTemplateInterface->PatchTemplate(addedInstancePatch, topLevelInstance->GetTemplateId());
|
||||
|
||||
// Get the DOM for the modified nested instance. Now that the data has been fixed up, and the instance has been added
|
||||
// to the top-level instance, we've got all the changes we need to generate the correct patch.
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom modifiedNestedInstanceDom;
|
||||
instanceToTemplateInterface->GenerateDomForInstance(modifiedNestedInstanceDom, addedInstance);
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom linkPatch;
|
||||
instanceToTemplateInterface->GeneratePatch(linkPatch, unmodifiedNestedInstanceDom, modifiedNestedInstanceDom);
|
||||
|
||||
prefabSystemComponentInterface->CreateLink(
|
||||
topLevelInstance->GetTemplateId(), addedInstance.GetTemplateId(), addedInstance.GetInstanceAlias(), linkPatch,
|
||||
AzToolsFramework::Prefab::InvalidLinkId);
|
||||
prefabSystemComponentInterface->PropagateTemplateChanges(topLevelInstance->GetTemplateId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SliceConverter::PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId)
|
||||
{
|
||||
auto prefabSystemComponentInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
|
||||
|
||||
auto prefabTemplate = prefabSystemComponentInterface->FindTemplate(templateId);
|
||||
auto& prefabDom = prefabTemplate->get().GetPrefabDom();
|
||||
const AZ::IO::Path& templatePath = prefabTemplate->get().GetFilePath();
|
||||
|
||||
rapidjson::StringBuffer prefabBuffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(prefabBuffer);
|
||||
prefabDom.Accept(writer);
|
||||
@@ -260,5 +452,41 @@ namespace AZ
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SliceConverter::ConnectToAssetProcessor()
|
||||
{
|
||||
AzFramework::AssetSystem::ConnectionSettings connectionSettings;
|
||||
AzFramework::AssetSystem::ReadConnectionSettingsFromSettingsRegistry(connectionSettings);
|
||||
|
||||
connectionSettings.m_launchAssetProcessorOnFailedConnection = true;
|
||||
connectionSettings.m_connectionDirection =
|
||||
AzFramework::AssetSystem::ConnectionSettings::ConnectionDirection::ConnectToAssetProcessor;
|
||||
connectionSettings.m_connectionIdentifier = AzFramework::AssetSystem::ConnectionIdentifiers::Editor;
|
||||
connectionSettings.m_loggingCallback = [](AZStd::string_view logData)
|
||||
{
|
||||
AZ_Printf("Convert-Slice", "%.*s\n", AZ_STRING_ARG(logData));
|
||||
};
|
||||
|
||||
bool connectedToAssetProcessor = false;
|
||||
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
connectedToAssetProcessor, &AzFramework::AssetSystemRequestBus::Events::EstablishAssetProcessorConnection,
|
||||
connectionSettings);
|
||||
|
||||
return connectedToAssetProcessor;
|
||||
}
|
||||
|
||||
void SliceConverter::DisconnectFromAssetProcessor()
|
||||
{
|
||||
AzFramework::AssetSystemRequestBus::Broadcast(
|
||||
&AzFramework::AssetSystem::AssetSystemRequests::StartDisconnectingAssetProcessor);
|
||||
|
||||
// Wait for the disconnect to finish.
|
||||
bool disconnected = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(disconnected,
|
||||
&AzFramework::AssetSystem::AssetSystemRequests::WaitUntilAssetProcessorDisconnected, AZStd::chrono::seconds(30));
|
||||
|
||||
AZ_Error("Convert-Slice", disconnected, "Asset Processor failed to disconnect successfully.");
|
||||
}
|
||||
|
||||
} // namespace SerializeContextTools
|
||||
} // namespace AZ
|
||||
|
||||
@@ -42,11 +42,20 @@ namespace AZ
|
||||
static bool ConvertSliceFiles(Application& application);
|
||||
|
||||
private:
|
||||
static bool ConnectToAssetProcessor();
|
||||
static void DisconnectFromAssetProcessor();
|
||||
|
||||
static bool ConvertSliceFile(AzToolsFramework::Prefab::PrefabSystemComponent* prefabSystemComponent,
|
||||
AZ::IO::PathView outputPath, bool isDryRun, AZ::Entity* rootEntity);
|
||||
|
||||
static void PrintPrefab(const AzToolsFramework::Prefab::PrefabDom& prefabDom, const AZ::IO::Path& templatePath);
|
||||
static bool ConvertSliceFile(AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun);
|
||||
static bool ConvertSliceToPrefab(
|
||||
AZ::SerializeContext* serializeContext, AZ::IO::PathView outputPath, bool isDryRun, AZ::Entity* rootEntity);
|
||||
static void FixPrefabEntities(AZ::Entity& containerEntity, SliceComponent::EntityList& sliceEntities);
|
||||
static bool ConvertNestedSlices(
|
||||
SliceComponent* sliceComponent, AzToolsFramework::Prefab::Instance* sourceInstance,
|
||||
AZ::SerializeContext* serializeContext, bool isDryRun);
|
||||
static bool SliceConverter::ConvertSliceInstance(
|
||||
AZ::SliceComponent::SliceInstance& instance, AZ::Data::Asset<AZ::SliceAsset>& sliceAsset,
|
||||
AzToolsFramework::Prefab::TemplateReference nestedTemplate, AzToolsFramework::Prefab::Instance* topLevelInstance);
|
||||
static void PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId);
|
||||
static bool SavePrefab(AzToolsFramework::Prefab::TemplateId templateId);
|
||||
};
|
||||
} // namespace SerializeContextTools
|
||||
|
||||
@@ -118,6 +118,8 @@ namespace SurfaceData
|
||||
|
||||
void EditorSurfaceDataSystemComponent::Deactivate()
|
||||
{
|
||||
m_surfaceTagNameAssets.clear();
|
||||
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::Components::EditorComponentBase::Deactivate();
|
||||
SurfaceDataTagProviderRequestBus::Handler::BusDisconnect();
|
||||
|
||||
@@ -9,6 +9,18 @@
|
||||
},
|
||||
"PythonAssetBuilder.Editor": {
|
||||
"AutoLoad": false
|
||||
},
|
||||
"AWSCore.Editor": {
|
||||
"AutoLoad": false
|
||||
},
|
||||
"AWSClientAuth": {
|
||||
"AutoLoad": false
|
||||
},
|
||||
"AWSClientAuth.Editor": {
|
||||
"AutoLoad": false
|
||||
},
|
||||
"AWSMetrics": {
|
||||
"AutoLoad": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user