Merge branch 'main' into transform-float-scale-continued

This commit is contained in:
greerdv
2021-05-26 10:27:18 +01:00
76 changed files with 1769 additions and 796 deletions
@@ -1020,29 +1020,60 @@ namespace AZ
}
};
/// OnDemand reflection for AZStd::set
template<class t_Key, class t_Hasher, class t_EqualKey, class t_Allocator>
class Iterator_VM<AZStd::unordered_set<t_Key, t_Hasher, t_EqualKey, t_Allocator>>
{
public:
using ContainerType = AZStd::unordered_set<t_Key, t_Hasher, t_EqualKey, t_Allocator>;
using IteratorType = typename ContainerType::iterator;
Iterator_VM(ContainerType& container)
: m_iterator(container.begin())
, m_end(container.end())
{}
const t_Key& GetKeyUnchecked() const
{
return *m_iterator;
}
bool IsNotAtEnd() const
{
return m_iterator != m_end;
}
t_Key& ModValueUnchecked()
{
return *m_iterator;
}
void Next()
{
++m_iterator;
}
private:
IteratorType m_iterator;
IteratorType m_end;
};
/// OnDemand reflection for AZStd::unordered_set
template<class Key, class Hasher, class EqualKey, class Allocator>
struct OnDemandReflection< AZStd::unordered_set<Key, Hasher, EqualKey, Allocator> >
{
using ContainerType = AZStd::unordered_set<Key, Hasher, EqualKey, Allocator>;
using KeyListType = AZStd::vector<Key, Allocator>;
static AZ::Outcome<void, void> Erase(ContainerType& thisMap, Key& key)
using ValueIteratorType = Iterator_VM<ContainerType>;
static bool EraseCheck_VM(ContainerType& thisSet, Key& key)
{
const auto result = thisMap.erase(key);
if (result)
{
return AZ::Success();
}
else
{
return AZ::Failure();
}
return thisSet.erase(key) != 0;
}
static void Insert(ContainerType& thisSet, Key& key)
static ContainerType& ErasePost_VM(ContainerType& thisSet, [[maybe_unused]] Key&)
{
thisSet.insert(key);
return thisSet;
}
static KeyListType GetKeys(ContainerType& thisSet)
@@ -1055,6 +1086,17 @@ namespace AZ
return keys;
}
static ContainerType& Insert(ContainerType& thisSet, Key& key)
{
thisSet.insert(key);
return thisSet;
}
static ValueIteratorType Iterate_VM(ContainerType& thisContainer)
{
return ValueIteratorType(thisContainer);
}
static void Swap(ContainerType& thisSet, ContainerType& otherSet)
{
thisSet.swap(otherSet);
@@ -1064,33 +1106,68 @@ namespace AZ
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
BranchOnResultInfo emptyBranchInfo;
emptyBranchInfo.m_returnResultInBranches = true;
emptyBranchInfo.m_trueToolTip = "The container is empty";
emptyBranchInfo.m_falseToolTip = "The container is not empty";
auto ContainsTransparent = [](const ContainerType& containerType, typename ContainerType::key_type& key)->bool
{
return containerType.contains(key);
};
ExplicitOverloadInfo explicitOverloadInfo;
behaviorContext->Class<ContainerType>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly)
->Attribute(AZ::ScriptCanvasAttributes::PrettyName, ScriptCanvasOnDemandReflection::OnDemandPrettyName<ContainerType>::Get(*behaviorContext))
->Attribute(AZ::Script::Attributes::ToolTip, ScriptCanvasOnDemandReflection::OnDemandToolTip<ContainerType>::Get(*behaviorContext))
->Attribute(AZ::Script::Attributes::Category, ScriptCanvasOnDemandReflection::OnDemandCategoryName<ContainerType>::Get(*behaviorContext))
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::ScriptOwn)
->Method("BucketCount", static_cast<typename ContainerType::size_type(ContainerType::*)() const>(&ContainerType::bucket_count))
->Method("Erase", &Erase)
->Method("Empty", [](ContainerType& thisSet)->bool { return thisSet.empty(); })
->Method("Empty", static_cast<bool(ContainerType::*)() const>(&ContainerType::empty), { { { "Container", "The container to check if it is empty", nullptr, {} } } })
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Is Empty", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::BranchOnResult, emptyBranchInfo)
->Method("EraseCheck_VM", &EraseCheck_VM)
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Method("Erase", &ErasePost_VM)
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Erase", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::CheckedOperation, CheckedOperationInfo("EraseCheck_VM", {}, "Out", "Key Not Found", true))
->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup", "" }, { "ContainerGroup" }))
->Method("contains", ContainsTransparent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Has Key", "Containers"))
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Method("Insert", &Insert)
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Insert", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup", "", "" }, { "ContainerGroup" }))
->Method(k_sizeName, [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->size()); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Method("GetKeys", &GetKeys)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Method("GetSize", [](ContainerType& thisPtr) { return aznumeric_cast<int>(thisPtr.size()); })
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Get Size", "Containers"))
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Method("Reserve", static_cast<void(ContainerType::*)(typename ContainerType::size_type)>(&ContainerType::reserve))
->Method("Swap", &Swap)
->Method("Clear", [](ContainerType& thisContainer)->ContainerType& { thisContainer.clear(); return thisContainer; })
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Clear All Elements", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup" }, { "ContainerGroup" }))
->Method(k_iteratorConstructorName, &Iterate_VM)
;
behaviorContext->Class<ValueIteratorType>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly)
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::ScriptOwn)
->Method(k_iteratorGetKeyName, &ValueIteratorType::GetKeyUnchecked)
->Method(k_iteratorModValueName, &ValueIteratorType::ModValueUnchecked)
->Method(k_iteratorIsNotAtEndName, &ValueIteratorType::IsNotAtEnd)
->Method(k_iteratorNextName, &ValueIteratorType::Next)
;
}
}
};
template <>
@@ -165,7 +165,7 @@ namespace AZ
if (HasResult() != overload->HasResult())
{
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all");
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all: %s", m_name.c_str());
return false;
}
@@ -176,7 +176,7 @@ namespace AZ
if (!(methodResult->m_typeId == overloadResult->m_typeId && methodResult->m_traits == overloadResult->m_traits))
{
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all");
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all: %s", m_name.c_str());
return false;
}
}
@@ -575,7 +575,7 @@ namespace AZ
}
else
{
AZ_Error("BehaviorContext", false, "safety check declared for method %s but it was not found in the class");
AZ_Error("BehaviorContext", false, "Method: %s, declared safety check: %s, but it was not found in class: %s", method.m_name.c_str(), m_name.c_str(), checkedOperationInfo.m_safetyCheckName.c_str());
}
}
}
@@ -34,10 +34,17 @@ namespace BehaviorContextUtilitiesCPP
using argument_type = const BehaviorParameter*;
using result_type = size_t;
result_type operator()(const argument_type& value) const
{
result_type result = AZStd::hash<Uuid>()(value->m_typeId);
AZStd::hash_combine(result, CleanTraits(value->m_traits));
return result;
{
if (value)
{
result_type result = AZStd::hash<Uuid>()(value->m_typeId);
AZStd::hash_combine(result, CleanTraits(value->m_traits));
return result;
}
else
{
return 0;
}
}
};
@@ -45,7 +52,11 @@ namespace BehaviorContextUtilitiesCPP
{
bool operator()(const BehaviorParameter* left, const BehaviorParameter* right) const
{
return left->m_typeId == right->m_typeId && CleanTraits(left->m_traits) == CleanTraits(right->m_traits);
return (left == nullptr && right == nullptr)
|| (left != nullptr
&& right != nullptr
&& left->m_typeId == right->m_typeId
&& CleanTraits(left->m_traits) == CleanTraits(right->m_traits));
}
};
@@ -137,7 +148,7 @@ namespace AZ
for (size_t argIndex = 0, argSentinel = overload.GetNumArguments(); argIndex < argSentinel; ++argIndex)
{
auto overloadedArgIter = variance.m_input.find(argIndex);
if (overloadedArgIter != variance.m_input.end())
if (overloadedArgIter != variance.m_input.end() && overloadedArgIter->second[overloadIndex])
{
// if this doesn't work try the type name
overloadName += ReplaceCppArtifacts(overloadedArgIter->second[overloadIndex]->m_name);
@@ -185,16 +196,24 @@ namespace AZ
{
auto argument = overloads[overloadIndex].first->GetArgument(0);
const bool isThisPointer
= (argument->m_traits & AZ::BehaviorParameter::Traits::TR_THIS_PTR) != 0
|| AZ::FindAttribute(AZ::Script::Attributes::TreatAsMemberFunction, overloads[overloadIndex].first->m_attributes);
if (argument)
{
const bool isThisPointer
= (argument->m_traits & AZ::BehaviorParameter::Traits::TR_THIS_PTR) != 0
|| AZ::FindAttribute(AZ::Script::Attributes::TreatAsMemberFunction, overloads[overloadIndex].first->m_attributes);
oneArgIsThisPointer = oneArgIsThisPointer || isThisPointer;
oneArgIsThisPointer = oneArgIsThisPointer || isThisPointer;
}
types.insert(argument);
stripedArgs.emplace_back(argument);
}
if (types.size() == overloads.size())
{
variance.m_unambiguousInput.insert(0);
}
if (types.size() > 1 && (onThis == VariantOnThis::Yes || !oneArgIsThisPointer))
{
variance.m_input.insert(AZStd::make_pair(0, stripedArgs));
@@ -210,11 +229,15 @@ namespace AZ
for (size_t overloadIndex = 0, overloadSentinel = overloads.size(); overloadIndex < overloadSentinel; ++overloadIndex)
{
auto argument = overloads[overloadIndex].first->GetArgument(argIndex);
types.insert(argument);
stripedArgs.emplace_back(argument);
}
if (types.size() == overloads.size())
{
variance.m_unambiguousInput.insert(0);
}
if (types.size() > 1)
{
variance.m_input.insert(AZStd::make_pair(argIndex, stripedArgs));
@@ -27,6 +27,8 @@ namespace AZ
struct OverloadVariance
{
AZStd::unordered_map<size_t, AZStd::vector<const BehaviorParameter*>> m_input;
// the indices of inputs that make selection of overload unambiguous
AZStd::unordered_set<size_t> m_unambiguousInput;
AZStd::vector<const BehaviorParameter*> m_output;
};
@@ -2048,10 +2048,6 @@ LUA_API const Node* lua_getDummyNode()
return true;
}
else
{
AZ_Warning("Script", false, "Index %d is not a function!", functionIndex);
}
return false;
}
@@ -2078,7 +2074,6 @@ LUA_API const Node* lua_getDummyNode()
}
else
{
AZ_Warning("Script", lua_isnil(m_nativeContext, -1), "Name %s exists but is not a function!", functionName);
lua_pop(m_nativeContext, 1);
}
@@ -5888,7 +5883,6 @@ LUA_API const Node* lua_getDummyNode()
else
{
lua_pop(m_impl->m_lua, 1);
AZ_Warning("Script", false, "%s is not a function!", functionName);
}
return false;
}
@@ -5906,7 +5900,6 @@ LUA_API const Node* lua_getDummyNode()
else
{
lua_pop(m_impl->m_lua, 1);
AZ_Warning("Script", false, "CacheIndex %d is not a function!", cachedIndex);
}
return false;
}
@@ -10,6 +10,7 @@
*
*/
#include "AzCore/RTTI/TypeInfo.h"
#include <AzCore/Math/UuidSerializer.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/Serialization/Json/CastingHelpers.h>
@@ -61,6 +62,13 @@ namespace AZ
if (classData->m_azRtti && classData->m_azRtti->GetGenericTypeId() != typeId)
{
if (((classData->m_azRtti->GetTypeTraits() & (AZ::TypeTraits::is_signed | AZ::TypeTraits::is_unsigned)) != AZ::TypeTraits{0}) &&
context.GetSerializeContext()->GetUnderlyingTypeId(typeId) == classData->m_typeId)
{
// This value is from an enum, where a field has been reflected using ClassBuilder::Field, but the enum
// type itself has not been reflected using EnumBuilder. Treat it as an enum.
return LoadEnum(object, *classData, value, context);
}
serializer = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId());
if (serializer)
{
@@ -77,21 +85,18 @@ namespace AZ
{
return LoadEnum(object, *classData, value, context);
}
else if (classData->m_container)
if (classData->m_container)
{
return context.Report(Tasks::ReadField, Outcomes::Unsupported,
"The Json Serializer uses custom serializers to load containers. If this message is encountered "
"then a serializer for the target containers is missing, isn't registered or doesn't exist.");
}
else if (value.IsObject())
if (value.IsObject())
{
return LoadClass(object, *classData, value, context);
}
else
{
return context.Report(Tasks::ReadField, Outcomes::Unsupported,
AZStd::string::format("Reading into targets of type '%s' is not supported.", classData->m_name));
}
return context.Report(Tasks::ReadField, Outcomes::Unsupported,
AZStd::string::format("Reading into targets of type '%s' is not supported.", classData->m_name));
}
JsonSerializationResult::ResultCode JsonDeserializer::LoadToPointer(void* object, const Uuid& typeId,
@@ -233,8 +238,16 @@ namespace AZ
AZ::TypeId underlyingTypeId = AZ::TypeId::CreateNull();
if (!attributeReader.Read<AZ::TypeId>(underlyingTypeId))
{
return context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
"Unable to find underlying type of enum in class data.");
// for non-reflected enums, the passed-in classData already represents the enum's underlying type
if (context.GetSerializeContext()->GetUnderlyingTypeId(classData.m_typeId) == classData.m_typeId)
{
underlyingTypeId = classData.m_typeId;
}
else
{
return context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
"Unable to find underlying type of enum in class data.");
}
}
const SerializeContext::ClassData* underlyingClassData = context.GetSerializeContext()->FindClassData(underlyingTypeId);
@@ -21,7 +21,7 @@ namespace JsonSerializationTests
{
using JsonSerializationTestCases = ::testing::Types<
// Structures
SimpleClass, SimpleInheritence, MultipleInheritence, SimpleNested, SimpleEnumWrapper,
SimpleClass, SimpleInheritence, MultipleInheritence, SimpleNested, SimpleEnumWrapper, NonReflectedEnumWrapper,
// Pointers
SimpleNullPointer, SimpleAssignedPointer, ComplexAssignedPointer, ComplexNullInheritedPointer,
ComplexAssignedDifferentInheritedPointer, ComplexAssignedSameInheritedPointer,
@@ -373,6 +373,57 @@ namespace JsonSerializationTests
return MakeInstanceWithoutDefaults(AZStd::move(instance), json);
}
// NonReflectedEnumWrapper
bool NonReflectedEnumWrapper::Equals(const NonReflectedEnumWrapper& rhs, bool fullReflection) const
{
return !fullReflection || (m_enumClass == rhs.m_enumClass && m_rawEnum== rhs.m_rawEnum);
}
void NonReflectedEnumWrapper::Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context, bool fullReflection)
{
if (fullReflection)
{
// Note that the enums are not reflected using context->Enum<>
context->Class<NonReflectedEnumWrapper>()
->Field("enumClass", &NonReflectedEnumWrapper::m_enumClass)
->Field("rawEnum", &NonReflectedEnumWrapper::m_rawEnum);
}
}
InstanceWithSomeDefaults<NonReflectedEnumWrapper> NonReflectedEnumWrapper::GetInstanceWithSomeDefaults()
{
auto instance = AZStd::make_unique<NonReflectedEnumWrapper>();
instance->m_enumClass = NonReflectedEnumWrapper::SimpleEnumClass::Option2;
const char* strippedDefaults = R"(
{
"enumClass": 2
})";
const char* keptDefaults = R"(
{
"enumClass": 2,
"rawEnum": 0
})";
return MakeInstanceWithSomeDefaults(AZStd::move(instance),
strippedDefaults, keptDefaults);
}
InstanceWithoutDefaults<NonReflectedEnumWrapper> NonReflectedEnumWrapper::GetInstanceWithoutDefaults()
{
auto instance = AZStd::make_unique<NonReflectedEnumWrapper>();
instance->m_enumClass = NonReflectedEnumWrapper::SimpleEnumClass::Option2;
instance->m_rawEnum = NonReflectedEnumWrapper::SimpleRawEnum::RawOption1;
const char* json = R"(
{
"enumClass": 2,
"rawEnum": 1
})";
return MakeInstanceWithoutDefaults(AZStd::move(instance), json);
}
// TemplatedClass<int>
bool TemplatedClass<int>::Equals(const TemplatedClass<int>& rhs, bool fullReflection) const
@@ -134,6 +134,35 @@ namespace JsonSerializationTests
SimpleRawEnum m_rawEnum{};
};
struct NonReflectedEnumWrapper
{
enum class SimpleEnumClass
{
Option1 = 1,
Option2,
};
enum SimpleRawEnum
{
RawOption1 = 1,
RawOption2,
};
AZ_CLASS_ALLOCATOR(NonReflectedEnumWrapper, AZ::SystemAllocator, 0);
AZ_RTTI(NonReflectedEnumWrapper, "{A80D5B6B-2FD1-46E9-A7A9-44C5E2650526}");
static constexpr bool SupportsPartialDefaults = true;
NonReflectedEnumWrapper() = default;
virtual ~NonReflectedEnumWrapper() = default;
bool Equals(const NonReflectedEnumWrapper& rhs, bool fullReflection) const;
static void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context, bool fullReflection);
static InstanceWithSomeDefaults<NonReflectedEnumWrapper> GetInstanceWithSomeDefaults();
static InstanceWithoutDefaults<NonReflectedEnumWrapper> GetInstanceWithoutDefaults();
SimpleEnumClass m_enumClass{};
SimpleRawEnum m_rawEnum{};
};
template<typename T>
struct TemplatedClass
{
@@ -158,5 +187,7 @@ namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::SimpleEnumWrapper::SimpleEnumClass, "{AF6F1964-5B20-4689-BF23-F36B9C9AAE6A}");
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::SimpleEnumWrapper::SimpleRawEnum, "{EB24207F-B48F-4D8B-940D-3CD06A371739}");
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::NonReflectedEnumWrapper::SimpleEnumClass, "{E80E4A41-B29E-4B7C-B630-3B599172C837}");
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::NonReflectedEnumWrapper::SimpleRawEnum, "{C42AF28D-4F84-4540-972A-5B6EEFAB13FF}");
AZ_TYPE_INFO_TEMPLATE(JsonSerializationTests::TemplatedClass, "{CA4ADF74-66E7-4D16-B4AC-F71278C60EC7}", AZ_TYPE_INFO_TYPENAME);
}
@@ -99,51 +99,18 @@ namespace AzFramework::ProjectManager
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
}
{
const char projectsScript[] = "projects.py";
AZStd::string filename = "o3de";
AZ::IO::FixedMaxPath executablePath = AZ::Utils::GetExecutableDirectory();
executablePath /= filename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION;
AZ_Warning("ProjectManager", false, "No project provided - launching project selector.");
if (engineRootPath.empty())
if (!AZ::IO::SystemFile::Exists(executablePath.c_str()))
{
AZ_Error("ProjectManager", false, "Couldn't find engine root");
AZ_Error("ProjectManager", false, "%s not found", executablePath.c_str());
return false;
}
auto projectManagerPath = engineRootPath / "scripts" / "project_manager";
if (!AZ::IO::SystemFile::Exists((projectManagerPath / projectsScript).c_str()))
{
AZ_Error("ProjectManager", false, "%s not found at %s!", projectsScript, projectManagerPath.c_str());
return false;
}
AZ::IO::FixedMaxPathString executablePath;
AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath.data(), executablePath.capacity());
if (result.m_pathStored != AZ::Utils::ExecutablePathResult::Success)
{
AZ_Error("ProjectManager", false, "Could not determine executable path!");
return false;
}
AZ::IO::FixedMaxPath parentPath(executablePath.c_str());
auto exeFolder = parentPath.ParentPath();
AZStd::fixed_string<8> debugOption;
auto lastSep = exeFolder.Native().find_last_of(AZ_CORRECT_FILESYSTEM_SEPARATOR);
if (lastSep != AZStd::string_view::npos)
{
exeFolder = exeFolder.Native().substr(lastSep + 1);
}
if (exeFolder == "debug")
{
// We need to use the debug version of the python interpreter to load up our debug version of our libraries which work with the debug version of QT living in this folder
debugOption = "debug ";
}
AZ::IO::FixedMaxPath pythonPath = engineRootPath / "python";
pythonPath /= AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL;
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRIu32, pythonPath.Native().c_str(),
debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath.c_str(), AZ::Platform::GetCurrentProcessId());
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
processLaunchInfo.m_commandlineParameters = cmdPath;
processLaunchInfo.m_showWindow = false;
processLaunchInfo.m_commandlineParameters = executablePath.String();
launchSuccess = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
}
if (ownsSystemAllocator)
@@ -65,5 +65,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_googletest(
NAME AZ::AzNetworking.Tests
)
ly_add_googletest(
NAME AZ::AzNetworking.Tests.Sandbox
TARGET AZ::AzNetworking.Tests
TEST_SUITE sandbox
)
endif()
@@ -129,7 +129,7 @@ namespace UnitTest
#if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
TEST_F(TcpTransportTests, DISABLED_TestSingleClient)
#else
TEST_F(TcpTransportTests, TestSingleClient)
TEST_F(TcpTransportTests, SUITE_sandbox_TestSingleClient)
#endif // AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
{
TestTcpServer testServer;
@@ -157,7 +157,7 @@ namespace UnitTest
#if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
TEST_F(TcpTransportTests, DISABLED_TestMultipleClients)
#else
TEST_F(TcpTransportTests, TestMultipleClients)
TEST_F(TcpTransportTests, SUITE_sandbox_TestMultipleClients)
#endif // AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
{
constexpr uint32_t NumTestClients = 50;
@@ -14,9 +14,11 @@
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Script/ScriptSystemBus.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h>
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
@@ -222,21 +224,52 @@ namespace AzToolsFramework
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
m_rootInstance->SetTemplateSourcePath(relativePath);
bool newLevelFromTemplate = false;
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
// This has not been loaded yet, this is the case of being saved with a different name.
// Create it
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({m_rootInstance->m_containerEntity.get()});
AZStd::string watchFolder;
AZ::Data::AssetInfo assetInfo;
bool sourceInfoFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, DefaultLevelTemplateName,
assetInfo, watchFolder);
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
if (sourceInfoFound)
{
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
AZStd::string fullPath;
AZ::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), fullPath);
// Get the default prefab and copy the Dom over to the new template being saved
Prefab::TemplateId defaultId = m_loaderInterface->LoadTemplateFromFile(fullPath.c_str());
Prefab::PrefabDom& dom = m_prefabSystemComponent->FindTemplateDom(defaultId);
Prefab::PrefabDom levelDefaultDom;
levelDefaultDom.CopyFrom(dom, levelDefaultDom.GetAllocator());
Prefab::PrefabDomPath sourcePath("/Source");
sourcePath.Set(levelDefaultDom, relativePath.c_str());
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(levelDefaultDom));
newLevelFromTemplate = true;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(dom));
else
{
// Create an empty level since we couldn't find the default template
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({ m_rootInstance->m_containerEntity.get() });
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
{
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(dom));
}
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
AZ_Error("Prefab", false, "Couldn't add new template id '%i' when saving file '%.*s'", templateId, AZ_STRING_ARG(filename));
@@ -253,6 +286,13 @@ namespace AzToolsFramework
m_prefabSystemComponent->RemoveTemplate(prevTemplateId);
}
// If we have a new level from a template, we need to make sure to propagate the changes here otherwise
// the entities from the new template won't show up
if (newLevelFromTemplate)
{
m_prefabSystemComponent->PropagateTemplateChanges(templateId);
}
AZStd::string out;
if (m_loaderInterface->SaveTemplateToString(m_rootInstance->GetTemplateId(), out))
{
@@ -216,5 +216,7 @@ namespace AzToolsFramework
Prefab::PrefabLoaderInterface* m_loaderInterface;
AzFramework::EntityContextId m_entityContextId;
AZ::SerializeContext m_serializeContext;
static inline constexpr const char* DefaultLevelTemplateName = "Prefabs/Default_Level.prefab";
};
}
@@ -83,7 +83,7 @@ namespace AzToolsFramework
protected:
QWidget* GetFirstInTabOrder() override;
QWidget* GetLastInTabOrder() override;
void UpdateTabOrder() override;
void UpdateTabOrder() override;
void onChildComboBoxValueChange(int comboBoxIndex) override;
@@ -93,7 +93,7 @@ namespace AzToolsFramework
void addElementImpl(const AZStd::pair<T, AZStd::string>& genericValue);
QLabel* m_warningLabel = nullptr;
QLabel* m_warningLabel = nullptr;
DHQComboBox* m_pComboBox;
AZStd::vector<AZStd::pair<T, AZStd::string>> m_values;
AZ::AttributeFunction <void(const T&)>* m_postChangeNotifyCB{};
@@ -131,6 +131,11 @@ namespace AzToolsFramework
template<typename T>
AzToolsFramework::PropertyHandlerBase* RegisterGenericComboBoxHandler()
{
if (!AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler())
{
return nullptr;
}
auto propertyHandler = aznew GenericComboBoxHandler<T>();
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, propertyHandler);
return propertyHandler;