Merge branch 'development' into cmake/linux_fix_warn_unused

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
monroegm-disable-blank-issue-2
Esteban Papp 4 years ago
commit d91dbe3d92

@ -13,8 +13,6 @@ set(FILES
Instance/InstanceData.h
Instance/InstanceData.cpp
Instance/InstanceDatabase.h
Serialization/Json/JsonUtils.h
Serialization/Json/JsonUtils.cpp
std/containers/array_view.h
std/containers/fixed_vector_set.h
std/containers/lru_cache.h

@ -10,7 +10,6 @@ set(FILES
ArrayView.cpp
ConcurrencyCheckerTests.cpp
InstanceDatabase.cpp
JsonSerializationUtilsTests.cpp
lru_cache.cpp
Main.cpp
vector_set.cpp

@ -81,9 +81,14 @@ namespace AZ
azrtti_typeid<decltype(componentMap)>(),
inputValue, "Components", context);
static TypeId genericComponentWrapperTypeId("{68D358CA-89B9-4730-8BA6-E181DEA28FDE}");
for (auto& [componentKey, component] : componentMap)
{
entityInstance->m_components.emplace_back(component);
// if underlying type is genericComponentWrapperTypeId, the template is null and the component should not be addded
if (component->GetUnderlyingComponentType() != genericComponentWrapperTypeId)
{
entityInstance->m_components.emplace_back(component);
}
}
result.Combine(componentLoadResult);

@ -209,39 +209,35 @@ namespace AZ
//! performance sensitive code.
AZ_INLINE bool CompareAnyValue(const AZStd::any& lhs, const AZStd::any& rhs)
{
bool isEqual = false;
if (lhs.type() != rhs.type())
if (lhs.type() == rhs.type())
{
return false;
}
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(lhs.type());
if (classData)
{
if (classData->m_serializer)
const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(lhs.type());
if (classData)
{
isEqual = classData->m_serializer->CompareValueData(AZStd::any_cast<void>(&lhs), AZStd::any_cast<void>(&rhs));
}
else
{
AZStd::vector<AZ::u8> myData;
AZ::IO::ByteContainerStream<decltype(myData)> myDataStream(&myData);
AZ::Utils::SaveObjectToStream(myDataStream, AZ::ObjectStream::ST_BINARY, AZStd::any_cast<void>(&lhs), lhs.type());
AZStd::vector<AZ::u8> otherData;
AZ::IO::ByteContainerStream<decltype(otherData)> otherDataStream(&otherData);
AZ::Utils::SaveObjectToStream(otherDataStream, AZ::ObjectStream::ST_BINARY, AZStd::any_cast<void>(&rhs), rhs.type());
isEqual = (myData.size() == otherData.size()) && (memcmp(myData.data(), otherData.data(), myData.size()) == 0);
if (classData->m_serializer)
{
return classData->m_serializer->CompareValueData(AZStd::any_cast<void>(&lhs), AZStd::any_cast<void>(&rhs));
}
else
{
AZStd::vector<AZ::u8> myData;
AZ::IO::ByteContainerStream<decltype(myData)> myDataStream(&myData);
AZ::Utils::SaveObjectToStream(myDataStream, AZ::ObjectStream::ST_BINARY, AZStd::any_cast<void>(&lhs), lhs.type());
AZStd::vector<AZ::u8> otherData;
AZ::IO::ByteContainerStream<decltype(otherData)> otherDataStream(&otherData);
AZ::Utils::SaveObjectToStream(otherDataStream, AZ::ObjectStream::ST_BINARY, AZStd::any_cast<void>(&rhs), rhs.type());
return (myData.size() == otherData.size()) && (memcmp(myData.data(), otherData.data(), myData.size()) == 0);
}
}
}
return isEqual;
return false;
}
}
}

@ -213,9 +213,13 @@ namespace AZ
void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context, ContinuationFlags flags)
{
bool loadAsNewInstance = (flags & ContinuationFlags::LoadAsNewInstance) == ContinuationFlags::LoadAsNewInstance;
JsonDeserializer::UseTypeDeserializer useCustom = (flags & ContinuationFlags::IgnoreTypeSerializer) == ContinuationFlags::IgnoreTypeSerializer
? JsonDeserializer::UseTypeDeserializer::No
: JsonDeserializer::UseTypeDeserializer::Yes;
return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer
? JsonDeserializer::LoadToPointer(object, typeId, value, context)
: JsonDeserializer::Load(object, typeId, value, loadAsNewInstance, context);
? JsonDeserializer::LoadToPointer(object, typeId, value, useCustom, context)
: JsonDeserializer::Load(object, typeId, value, loadAsNewInstance, useCustom, context);
}
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring(
@ -224,11 +228,15 @@ namespace AZ
{
using namespace JsonSerializationResult;
JsonSerializer::UseTypeSerializer useCustom = (flags & ContinuationFlags::IgnoreTypeSerializer) == ContinuationFlags::IgnoreTypeSerializer
? JsonSerializer::UseTypeSerializer::No
: JsonSerializer::UseTypeSerializer::Yes;
if ((flags & ContinuationFlags::ReplaceDefault) == ContinuationFlags::ReplaceDefault && !context.ShouldKeepDefaults())
{
if ((flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer)
{
return JsonSerializer::StoreFromPointer(output, object, nullptr, typeId, context);
return JsonSerializer::StoreFromPointer(output, object, nullptr, typeId, useCustom, context);
}
else
{
@ -241,19 +249,19 @@ namespace AZ
{
return result;
}
return result.Combine(JsonSerializer::Store(output, object, nullptr, typeId, context));
return result.Combine(JsonSerializer::Store(output, object, nullptr, typeId, useCustom, context));
}
else
{
void* defaultObjectPtr = AZStd::any_cast<void>(&newDefaultObject);
return JsonSerializer::Store(output, object, defaultObjectPtr, typeId, context);
return JsonSerializer::Store(output, object, defaultObjectPtr, typeId, useCustom, context);
}
}
}
return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer ?
JsonSerializer::StoreFromPointer(output, object, defaultObject, typeId, context) :
JsonSerializer::Store(output, object, defaultObject, typeId, context);
JsonSerializer::StoreFromPointer(output, object, defaultObject, typeId, useCustom, context) :
JsonSerializer::Store(output, object, defaultObject, typeId, useCustom, context);
}
JsonSerializationResult::ResultCode BaseJsonSerializer::LoadTypeId(Uuid& typeId, const rapidjson::Value& input,

@ -159,12 +159,13 @@ namespace AZ
enum class ContinuationFlags
{
None = 0, //! No extra flags.
ResolvePointer = 1 << 0, //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance.
ReplaceDefault = 1 << 1, //! The default value provided for storing will be replaced with a newly created one.
LoadAsNewInstance = 1 << 2 //! Treats the value as if it's a newly created instance. This may trigger serializers marked with
//! OperationFlags::InitializeNewInstance. Used for instance by pointers or new instances added to
//! an array.
None = 0, //! No extra flags.
ResolvePointer = 1 << 0, //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance.
ReplaceDefault = 1 << 1, //! The default value provided for storing will be replaced with a newly created one.
LoadAsNewInstance = 1 << 2, //! Treats the value as if it's a newly created instance. This may trigger serializers marked with
//! OperationFlags::InitializeNewInstance. Used for instance by pointers or new instances added to
//! an array.
IgnoreTypeSerializer = 1 << 3, //! Ignore the custom/specific serializer for the TypeId
};
enum class OperationFlags

@ -38,7 +38,8 @@ namespace AZ
}
JsonSerializationResult::ResultCode JsonDeserializer::Load(
void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context)
void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, UseTypeDeserializer custom,
JsonDeserializerContext& context)
{
using namespace AZ::JsonSerializationResult;
@ -48,8 +49,8 @@ namespace AZ
"Target object for Json Serialization is pointing to nothing during loading.");
}
BaseJsonSerializer* serializer = context.GetRegistrationContext()->GetSerializerForType(typeId);
if (serializer)
if (BaseJsonSerializer* serializer
= (custom == UseTypeDeserializer::Yes ? context.GetRegistrationContext()->GetSerializerForType(typeId) : nullptr))
{
return DeserializerDefaultCheck(serializer, object, typeId, value, isNewInstance, context);
}
@ -70,8 +71,11 @@ namespace AZ
// 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)
if (BaseJsonSerializer* serializer
= (custom == UseTypeDeserializer::Yes)
? context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId())
: nullptr)
{
return DeserializerDefaultCheck(serializer, object, typeId, value, isNewInstance, context);
}
@ -101,7 +105,7 @@ namespace AZ
}
JsonSerializationResult::ResultCode JsonDeserializer::LoadToPointer(void* object, const Uuid& typeId,
const rapidjson::Value& value, JsonDeserializerContext& context)
const rapidjson::Value& value, UseTypeDeserializer useCustom, JsonDeserializerContext& context)
{
using namespace JsonSerializationResult;
@ -134,7 +138,7 @@ namespace AZ
const SerializeContext::ClassData* resolvedClassData = context.GetSerializeContext()->FindClassData(resolvedTypeId);
if (resolvedClassData)
{
status = JsonDeserializer::Load(*objectPtr, resolvedTypeId, value, true, context);
status = JsonDeserializer::Load(*objectPtr, resolvedTypeId, value, true, useCustom, context);
*objectPtr = resolvedClassData->m_azRtti->Cast(*objectPtr, typeId);
@ -171,11 +175,11 @@ namespace AZ
}
AZ_Assert(classElement.m_azRtti->GetTypeId() == classElement.m_typeId,
"Type id mismatch during deserialization of a json file. (%s vs %s)");
return LoadToPointer(object, classElement.m_typeId, value, context);
return LoadToPointer(object, classElement.m_typeId, value, UseTypeDeserializer::Yes, context);
}
else
{
return Load(object, classElement.m_typeId, value, false, context);
return Load(object, classElement.m_typeId, value, false, UseTypeDeserializer::Yes, context);
}
}
@ -571,11 +575,23 @@ namespace AZ
if (loadedTypeId.m_determination == TypeIdDetermination::FailedToDetermine ||
loadedTypeId.m_determination == TypeIdDetermination::FailedDueToMultipleTypeIds)
{
AZStd::string_view message = loadedTypeId.m_determination == TypeIdDetermination::FailedDueToMultipleTypeIds ?
"Unable to resolve provided type because the same name points to multiple types." :
"Unable to resolve provided type.";
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown, message);
return ResolvePointerResult::FullyProcessed;
auto typeField = pointerData.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeField != pointerData.MemberEnd() && typeField->value.IsString())
{
const char* format = loadedTypeId.m_determination == TypeIdDetermination::FailedToDetermine ?
"Unable to resolve provided type: %.*s." :
"Unable to resolve provided type %.*s because the same name points to multiple types.";
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
AZStd::string::format(format, typeField->value.GetStringLength(), typeField->value.GetString()));
}
else
{
const char* message = loadedTypeId.m_determination == TypeIdDetermination::FailedToDetermine ?
"Unable to resolve provided type." :
"Unable to resolve provided type because the same name points to multiple types.";
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown, message);
}
return ResolvePointerResult::FullyProcessed;
}
if (loadedTypeId.m_typeId != objectType)

@ -28,6 +28,11 @@ namespace AZ
FullyProcessed,
ContinueProcessing
};
enum class UseTypeDeserializer : bool
{
No,
Yes
};
enum class TypeIdDetermination : u8
{
ExplicitTypeId, // Type id was explicitly defined using "$type".
@ -55,10 +60,11 @@ namespace AZ
JsonDeserializer(JsonDeserializer&& rhs) = delete;
static JsonSerializationResult::ResultCode Load(
void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context);
void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, UseTypeDeserializer useCustom,
JsonDeserializerContext& context);
static JsonSerializationResult::ResultCode LoadToPointer(void* object, const Uuid& typeId, const rapidjson::Value& value,
JsonDeserializerContext& context);
UseTypeDeserializer useCustom, JsonDeserializerContext& context);
static JsonSerializationResult::ResultCode LoadWithClassElement(void* object, const rapidjson::Value& value,
const SerializeContext::ClassElement& classElement, JsonDeserializerContext& context);

@ -245,7 +245,7 @@ namespace AZ
{
StackedString path(StackedString::Format::JsonPointer);
JsonDeserializerContext context(settings);
result = JsonDeserializer::Load(object, objectType, root, false, context);
result = JsonDeserializer::Load(object, objectType, root, false, JsonDeserializer::UseTypeDeserializer::Yes, context);
}
return result;
}
@ -322,7 +322,7 @@ namespace AZ
JsonSerializerContext context(settings, allocator);
StackedString path(StackedString::Format::ContextPath);
result = JsonSerializer::Store(output, object, defaultObject, objectType, context);
result = JsonSerializer::Store(output, object, defaultObject, objectType, JsonSerializer::UseTypeSerializer::Yes, context);
}
return result;
}

@ -20,7 +20,7 @@
namespace AZ
{
JsonSerializationResult::ResultCode JsonSerializer::Store(rapidjson::Value& output, const void* object, const void* defaultObject,
const Uuid& typeId, JsonSerializerContext& context)
const Uuid& typeId, UseTypeSerializer custom, JsonSerializerContext& context)
{
using namespace JsonSerializationResult;
@ -32,8 +32,8 @@ namespace AZ
// First check if there's a generic serializer registered for this. This makes it possible to use serializers that
// are not (directly) registered with the Serialize Context.
auto serializer = context.GetRegistrationContext()->GetSerializerForType(typeId);
if (serializer)
if (BaseJsonSerializer* serializer
= (custom == UseTypeSerializer::Yes ? context.GetRegistrationContext()->GetSerializerForType(typeId) : nullptr))
{
// Start by setting the object to be an explicit default.
output.SetObject();
@ -57,17 +57,18 @@ namespace AZ
"No factory available to create a default object for comparison.");
}
void* defaultObjectPtr = AZStd::any_cast<void>(&defaultObjectInstance);
ResultCode conversionResult = StoreWithClassData(output, object, defaultObjectPtr, *classData, StoreTypeId::No, context);
ResultCode conversionResult = StoreWithClassData(output, object, defaultObjectPtr, *classData, StoreTypeId::No
, UseTypeSerializer::Yes, context);
return ResultCode::Combine(result, conversionResult);
}
else
{
return StoreWithClassData(output, object, defaultObject, *classData, StoreTypeId::No, context);
return StoreWithClassData(output, object, defaultObject, *classData, StoreTypeId::No, custom, context);
}
}
JsonSerializationResult::ResultCode JsonSerializer::StoreFromPointer(rapidjson::Value& output, const void* object,
const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context)
const void* defaultObject, const Uuid& typeId, UseTypeSerializer custom, JsonSerializerContext& context)
{
using namespace JsonSerializationResult;
@ -85,19 +86,21 @@ namespace AZ
AZ_Assert(classData->m_azRtti->GetTypeId() == typeId, "Type id mismatch in '%s' during serialization to a json file. (%s vs %s)",
classData->m_name, classData->m_azRtti->GetTypeId().ToString<AZStd::string>().c_str(), typeId.ToString<AZStd::string>().c_str());
return StoreWithClassDataFromPointer(output, object, defaultObject, *classData, context);
return StoreWithClassDataFromPointer(output, object, defaultObject, *classData, custom, context);
}
JsonSerializationResult::ResultCode JsonSerializer::StoreWithClassData(rapidjson::Value& node, const void* object,
const void* defaultObject, const SerializeContext::ClassData& classData, StoreTypeId storeTypeId,
JsonSerializerContext& context)
UseTypeSerializer custom, JsonSerializerContext& context)
{
using namespace JsonSerializationResult;
// Start by setting the object to be an explicit default.
node.SetObject();
auto serializer = context.GetRegistrationContext()->GetSerializerForType(classData.m_typeId);
auto serializer = custom == UseTypeSerializer::Yes
? context.GetRegistrationContext()->GetSerializerForType(classData.m_typeId) : nullptr;
if (serializer)
{
ResultCode result = serializer->Store(node, object, defaultObject, classData.m_typeId, context);
@ -153,7 +156,7 @@ namespace AZ
}
JsonSerializationResult::ResultCode JsonSerializer::StoreWithClassDataFromPointer(rapidjson::Value& output, const void* object,
const void* defaultObject, const SerializeContext::ClassData& classData, JsonSerializerContext& context)
const void* defaultObject, const SerializeContext::ClassData& classData, UseTypeSerializer custom, JsonSerializerContext& context)
{
using namespace JsonSerializationResult;
@ -175,7 +178,7 @@ namespace AZ
}
else
{
return StoreWithClassData(output, object, defaultObject, *resolvedClassData, storeTypeId, context);
return StoreWithClassData(output, object, defaultObject, *resolvedClassData, storeTypeId, custom, context);
}
}
@ -220,8 +223,8 @@ namespace AZ
{
rapidjson::Value value;
ResultCode result = classElement.m_flags & SerializeContext::ClassElement::FLG_POINTER ?
StoreWithClassDataFromPointer(value, object, defaultObject, *elementClassData, context):
StoreWithClassData(value, object, defaultObject, *elementClassData, StoreTypeId::No, context);
StoreWithClassDataFromPointer(value, object, defaultObject, *elementClassData, UseTypeSerializer::Yes, context):
StoreWithClassData(value, object, defaultObject, *elementClassData, StoreTypeId::No, UseTypeSerializer::Yes, context);
if (result.GetProcessing() != Processing::Halted)
{
if (parentNode.IsObject())

@ -26,6 +26,11 @@ namespace AZ
No,
Yes
};
enum class UseTypeSerializer : bool
{
No,
Yes
};
enum class ResolvePointerResult
{
FullyProcessed,
@ -41,16 +46,18 @@ namespace AZ
JsonSerializer(JsonSerializer&& rhs) = delete;
static JsonSerializationResult::ResultCode Store(rapidjson::Value& output, const void* object, const void* defaultObject,
const Uuid& typeId, JsonSerializerContext& context);
const Uuid& typeId, UseTypeSerializer useCustom, JsonSerializerContext& context);
static JsonSerializationResult::ResultCode StoreFromPointer(rapidjson::Value& output, const void* object, const void* defaultObject,
const Uuid& typeId, JsonSerializerContext& context);
const Uuid& typeId, UseTypeSerializer custom, JsonSerializerContext& context);
static JsonSerializationResult::ResultCode StoreWithClassData(rapidjson::Value& node, const void* object, const void* defaultObject,
const SerializeContext::ClassData& classData, StoreTypeId storeTypeId, JsonSerializerContext& context);
const SerializeContext::ClassData& classData, StoreTypeId storeTypeId, UseTypeSerializer custom,
JsonSerializerContext& context);
static JsonSerializationResult::ResultCode StoreWithClassDataFromPointer(rapidjson::Value& output, const void* object,
const void* defaultObject, const SerializeContext::ClassData& classData, JsonSerializerContext& context);
const void* defaultObject, const SerializeContext::ClassData& classData, UseTypeSerializer custom,
JsonSerializerContext& context);
static JsonSerializationResult::ResultCode StoreWithClassElement(rapidjson::Value& parentNode, const void* object,
const void* defaultObject, const SerializeContext::ClassElement& classElement, JsonSerializerContext& context);

@ -6,7 +6,6 @@
*
*/
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/base.h>
#include <AzCore/Component/ComponentApplicationBus.h>
@ -23,6 +22,8 @@
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace AZ
{
namespace JsonSerializationUtils
@ -331,6 +332,11 @@ namespace AZ
// validate class name
auto classData = loadSettings.m_serializeContext->FindClassData(classId);
if (!classData)
{
return AZ::Failure(AZStd::string::format("Try to load class from Id %s", classId.ToString<AZStd::string>().c_str()));
}
if (azstricmp(classData->m_name, className) != 0)
{
return AZ::Failure(AZStd::string::format("Try to load class %s from class %s data", classData->m_name, className));
@ -342,9 +348,9 @@ namespace AZ
{
return AZ::Failure(deserializeErrors);
}
return AZ::Success();
}
}
AZ::Outcome<AZStd::any, AZStd::string> LoadAnyObjectFromStream(IO::GenericStream& stream, const JsonDeserializerSettings* settings)
{

@ -531,6 +531,8 @@ set(FILES
Serialization/Json/JsonStringConversionUtils.h
Serialization/Json/JsonSystemComponent.h
Serialization/Json/JsonSystemComponent.cpp
Serialization/Json/JsonUtils.h
Serialization/Json/JsonUtils.cpp
Serialization/Json/MapSerializer.h
Serialization/Json/MapSerializer.cpp
Serialization/Json/RegistrationContext.h

@ -13,7 +13,7 @@
#include <AzTest/AzTest.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace UnitTest
{

@ -104,6 +104,7 @@ set(FILES
Serialization/Json/JsonSerializationResultTests.cpp
Serialization/Json/JsonSerializationTests.h
Serialization/Json/JsonSerializationTests.cpp
Serialization/Json/JsonSerializationUtilsTests.cpp
Serialization/Json/JsonSerializerConformityTests.h
Serialization/Json/JsonSerializerMock.h
Serialization/Json/MapSerializerTests.cpp

@ -253,6 +253,15 @@ namespace AzToolsFramework
settings.m_metadata.Add(&entityIdMapper);
settings.m_metadata.Create<InstanceEntityScrubber>(newlyAddedEntities);
AZStd::string scratchBuffer;
auto issueReportingCallback = [&scratchBuffer](
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
{
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
};
settings.m_reporting = AZStd::move(issueReportingCallback);
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings);
AZ::Data::AssetManager::Instance().ResumeAssetRelease();

@ -383,6 +383,13 @@ void SRemoteClient::Run()
bool ok = true;
bool autoCompleteDoneSent = false;
// Send a message that is used to verify that the Remote Console connected
SNoDataEvent<eCET_ConnectMessage> connectMessage;
SRemoteEventFactory::GetInst()->WriteToBuffer(&connectMessage, szBuff, size, kDefaultBufferSize);
ok &= SendPackage(szBuff, size);
ok &= RecvPackage(szBuff, size);
ok &= m_pServer->ReadBuffer(szBuff, size);
while (ok)
{
// read data
@ -531,6 +538,7 @@ SRemoteEventFactory::SRemoteEventFactory()
REGISTER_EVENT_NODATA(eCET_Strobo_FrameInfoStart);
REGISTER_EVENT_STRING(eCET_Strobo_FrameInfoAdd);
REGISTER_EVENT_NODATA(eCET_ConnectMessage);
}
/////////////////////////////////////////////////////////////////////////////////////////////

@ -60,6 +60,7 @@ enum EConsoleEventType
eCET_Strobo_FrameInfoStart,
eCET_Strobo_FrameInfoAdd,
eCET_ConnectMessage,
};
struct SRemoteEventFactory;

@ -37,7 +37,7 @@
#include <AzFramework/Application/Application.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace ImageProcessingAtom
{

@ -12,7 +12,7 @@
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace AZ

@ -19,7 +19,7 @@
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroupLayout.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzFramework/IO/FileOperations.h> // [GFX TODO] Remove when [ATOM-15472]

@ -14,7 +14,7 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace AZ
{

@ -24,7 +24,7 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace AZ
{

@ -11,7 +11,7 @@
#include <AzFramework/IO/LocalFileIO.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RHI.Edit/ShaderPlatformInterface.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Reflect/Asset/AssetReference.h>

@ -24,7 +24,7 @@
#include <Atom/RHI.Reflect/PipelineLayoutDescriptor.h>
#include <Atom/RHI.Reflect/ShaderStageFunction.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Debug/TraceContext.h>

@ -21,7 +21,7 @@
#include <AzCore/IO/FileIO.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>

@ -18,7 +18,7 @@
#include <Atom/RPI.Edit/Shader/ShaderVariantTreeAssetCreator.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Reflect/Shader/ShaderVariantKey.h>
#include <Atom/RHI.Edit/Utils.h>

@ -17,7 +17,7 @@
#include <Atom/Utils/DdsFile.h>
#include <Atom/Utils/PpmFile.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Jobs/JobCompletion.h>

@ -20,7 +20,7 @@
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/RTTI/BehaviorContext.h>

@ -8,7 +8,7 @@
#include <Atom/RHI.Edit/Utils.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzFramework/Process/ProcessCommunicator.h>
#include <AzFramework/Process/ProcessWatcher.h>

@ -10,9 +10,7 @@
#include <AzCore/JSON/document.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
@ -120,6 +118,7 @@ namespace AZ
AZ_Error("AZ::RPI::JsonUtils", false, "Failed to load object from json string: %s", loadResult.GetError().c_str());
return false;
}
} // namespace JsonUtils
} // namespace RPI
} // namespace AZ

@ -19,7 +19,7 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/ConvertibleSource.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>

@ -13,7 +13,7 @@
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>

@ -11,7 +11,7 @@
#include <AzCore/Asset/AssetManagerBus.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Reflect/Asset/AssetReference.h>
#include <Atom/RPI.Reflect/Pass/PassAsset.h>

@ -16,7 +16,7 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RHI.Reflect/BufferPoolDescriptor.h>
#include <Atom/RHI.Reflect/ImagePoolDescriptor.h>

@ -11,7 +11,7 @@
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/Json/JsonSerializationResult.h>

@ -21,7 +21,7 @@
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/StackedString.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace AZ
{

@ -22,7 +22,7 @@
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>

@ -10,7 +10,7 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/Json/JsonSerializationResult.h>

@ -15,7 +15,7 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/std/string/string.h>

@ -23,7 +23,7 @@
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RHI/ScopeProducerFunction.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/std/smart_ptr/make_shared.h>

@ -17,7 +17,7 @@
#include <AzCore/std/sort.h>
#include <AzCore/Interface/Interface.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RHI/CpuProfiler.h>
#include <Atom/RHI/FrameGraphBuilder.h>

@ -6,7 +6,7 @@
*
*/
#include <Atom/RPI.Public/Shader/Metrics/ShaderMetrics.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace AZ
{

@ -15,7 +15,7 @@
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils//Utils.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzFramework/IO/LocalFileIO.h>

@ -13,7 +13,7 @@
#include <AzCore/Serialization/Utils.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/ConvertibleSource.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>

@ -16,7 +16,7 @@
#include <AzCore/Serialization/Utils.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RHI.Reflect/ReflectSystemComponent.h>

@ -8,7 +8,7 @@
#include <AzTest/AzTest.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RHI.Reflect/BufferPoolDescriptor.h>
#include <Atom/RHI.Reflect/ImagePoolDescriptor.h>

@ -15,7 +15,7 @@
#include <AzCore/IO/TextStreamWriters.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/JSON/prettywriter.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
namespace UnitTest

@ -19,7 +19,6 @@
#include <Atom/RPI.Public/Material/Material.h>
#include <Material/MaterialAssetTestUtils.h>
//#include <AtomCore/Serialization/Json/JsonUtils.h>
namespace UnitTest
{
using namespace AZ;

@ -11,7 +11,7 @@
#include <Common/JsonTestUtils.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialPropertySerializer.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Common/TestUtils.h>
#include <Tests/Serialization/Json/JsonSerializerConformityTests.h>

@ -20,7 +20,7 @@
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Material/Material.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzFramework/StringFunc/StringFunc.h>

@ -25,7 +25,7 @@
#include <Atom/ImageProcessing/ImageObject.h>
#include <Atom/ImageProcessing/ImageProcessingBus.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>

@ -13,7 +13,7 @@
#include <AzFramework/StringFunc/StringFunc.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
// Included so we can deduce the asset type from asset paths.
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>

@ -11,6 +11,11 @@
#include <ExpressionEvaluation/ExpressionEngine/ExpressionTypes.h>
namespace AZ
{
class ExpressionTreeVariableDescriptorSerializer;
}
namespace ExpressionEvaluation
{
// Holds all of the tokeniszed information from parsing an expression string.
@ -20,8 +25,22 @@ namespace ExpressionEvaluation
{
// Friend class for reflection
friend class ExpressionEvaluationSystemComponent;
friend class ExpressionTreeVariableDescriptorSerializer;
public:
struct VariableDescriptor
{
AZ_TYPE_INFO(VariableDescriptor, "{5E1A0044-E0E7-46D3-8BC6-A22E226ADB83}");
VariableDescriptor()
{
m_supportedTypes.push_back(azrtti_typeid<double>());
}
AZStd::vector< AZ::Uuid > m_supportedTypes;
ExpressionVariable m_value;
};
AZ_RTTI(ExpressionTree, "{4CCF3DFD-2EA8-47CB-AF25-353BC034EF42}");
AZ_CLASS_ALLOCATOR(ExpressionTree, AZ::SystemAllocator, 0);
@ -147,18 +166,6 @@ namespace ExpressionEvaluation
private:
struct VariableDescriptor
{
AZ_TYPE_INFO(VariableDescriptor, "{5E1A0044-E0E7-46D3-8BC6-A22E226ADB83}");
VariableDescriptor()
{
m_supportedTypes.push_back(azrtti_typeid<double>());
}
AZStd::vector< AZ::Uuid > m_supportedTypes;
ExpressionVariable m_value;
};
AZStd::unordered_map< AZ::Crc32, VariableDescriptor > m_variables;

@ -0,0 +1,181 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/Memory.h>
#include <AzCore/Serialization/AZStdAnyDataContainer.inl>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <ExpressionEvaluation/ExpressionEngine/ExpressionTypes.h>
namespace AZ
{
class ElementInformationSerializer
: public BaseJsonSerializer
{
public:
AZ_RTTI(ElementInformationSerializer, "{B33E6AA9-C700-4E3D-857C-55F362AFE57A}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
private:
using ElementInformation = ExpressionEvaluation::ElementInformation;
static const char* EmptyAnyIdentifier;
static bool IsEmptyAny(const rapidjson::Value& typeId)
{
if (typeId.IsString())
{
AZStd::string_view typeName(typeId.GetString(), typeId.GetStringLength());
return typeName == EmptyAnyIdentifier;
}
return false;
}
JsonSerializationResult::Result Load
( void* outputValue
, const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context) override
{
namespace JSR = JsonSerializationResult;
AZ_Assert(outputValueTypeId == azrtti_typeid<ElementInformation>(), "ElementInformationSerializer Load against "
"output typeID that was not ElementInformation");
AZ_Assert(outputValue, "ElementInformationSerializer Load against null output");
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
auto outputDatum = reinterpret_cast<ElementInformation*>(outputValue);
result.Combine(ContinueLoadingFromJsonObjectField
( &outputDatum->m_id
, azrtti_typeid<decltype(outputDatum->m_id)>()
, inputValue
, "Id"
, context));
// any storage begin
{
AZ::Uuid typeId = AZ::Uuid::CreateNull();
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
return context.Report
( JSR::Tasks::ReadField
, JSR::Outcomes::Missing
, AZStd::string::format("ElementInformationSerializer::Load failed to load the %s member"
, JsonSerialization::TypeIdFieldIdentifier));
}
if (!IsEmptyAny(typeIdMember->value))
{
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
if (typeId.IsNull())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
, "ElementInformationSerializer::Load failed to load the AZ TypeId of the value");
}
AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId);
if (storage.empty() || storage.type() != typeId)
{
return context.Report(result, "ElementInformationSerializer::Load failed to load a value matched the "
"reported AZ TypeId. The C++ declaration may have been deleted or changed.");
}
result.Combine
( ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "Value", context));
outputDatum->m_extraStore = storage;
}
}
// any storage end
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ElementInformationSerializer Load finished loading ElementInformation"
: "ElementInformationSerializer Load failed to load ElementInformation");
}
JsonSerializationResult::Result Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, const Uuid& valueTypeId, JsonSerializerContext& context) override
{
namespace JSR = JsonSerializationResult;
AZ_Assert(valueTypeId == azrtti_typeid<ElementInformation>(), "ElementInformation Store against value typeID that "
"was not ElementInformation");
AZ_Assert(inputValue, "ElementInformation Store against null inputValue pointer ");
auto inputScriptDataPtr = reinterpret_cast<const ElementInformation*>(inputValue);
auto defaultScriptDataPtr = reinterpret_cast<const ElementInformation*>(defaultValue);
if (defaultScriptDataPtr)
{
if (inputScriptDataPtr->m_id == defaultScriptDataPtr->m_id
&& AZ::Helpers::CompareAnyValue(inputScriptDataPtr->m_extraStore, defaultScriptDataPtr->m_extraStore))
{
return context.Report
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "ElementInformation Store used defaults for "
"ElementInformation");
}
}
JSR::ResultCode result(JSR::Tasks::WriteValue);
outputValue.SetObject();
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "Id"
, &inputScriptDataPtr->m_id
, defaultScriptDataPtr ? &defaultScriptDataPtr->m_id : nullptr
, azrtti_typeid<decltype(inputScriptDataPtr->m_id)>()
, context));
if (!inputScriptDataPtr->m_extraStore.empty())
{
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_extraStore.type(), context));
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(typeValue)
, context.GetJsonAllocator());
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "Value"
, AZStd::any_cast<void>(const_cast<AZStd::any*>(&inputScriptDataPtr->m_extraStore))
, defaultScriptDataPtr ? AZStd::any_cast<void>(const_cast<AZStd::any*>(&defaultScriptDataPtr->m_extraStore)) : nullptr
, inputScriptDataPtr->m_extraStore.type()
, context));
}
else
{
rapidjson::Value emptyAny;
AZStd::string emptyAnyName(EmptyAnyIdentifier);
emptyAny.SetString(emptyAnyName.c_str(), aznumeric_caster(emptyAnyName.size()), context.GetJsonAllocator());
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(emptyAny)
, context.GetJsonAllocator());
}
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ElementInformation Store finished saving ElementInformation"
: "ElementInformation Store failed to save ElementInformation");
}
};
AZ_CLASS_ALLOCATOR_IMPL(ElementInformationSerializer, SystemAllocator, 0);
const char* ElementInformationSerializer::EmptyAnyIdentifier = "Empty AZStd::any";
}

@ -6,16 +6,17 @@
*
*/
#include <ExpressionEvaluationSystemComponent.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <ExpressionEngine/InternalTypes.h>
#include <ExpressionEngine/MathOperators/MathExpressionOperators.h>
#include <ExpressionEngine/Utils.h>
#include <ExpressionEvaluationSystemComponent.h>
#include <ExpressionPrimitivesSerializers.inl>
#include <ElementInformationSerializer.inl>
namespace ExpressionEvaluation
{
@ -146,6 +147,12 @@ namespace ExpressionEvaluation
;
}
}
if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast<AZ::JsonRegistrationContext*>(context))
{
jsonContext->Serializer<AZ::ExpressionTreeVariableDescriptorSerializer>()->HandlesType<ExpressionTree::VariableDescriptor>();
jsonContext->Serializer<AZ::ElementInformationSerializer>()->HandlesType<ElementInformation>();
}
}
void ExpressionEvaluationSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)

@ -0,0 +1,147 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/Memory.h>
#include <AzCore/Serialization/AZStdAnyDataContainer.inl>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <ExpressionEvaluation/ExpressionEngine/ExpressionTree.h>
namespace AZ
{
class ExpressionTreeVariableDescriptorSerializer
: public BaseJsonSerializer
{
public:
AZ_RTTI(ExpressionTreeVariableDescriptorSerializer, "{5EFF37D6-BD54-45C6-9FC6-B1E0D3A8204C}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
private:
using VariableDescriptor = ExpressionEvaluation::ExpressionTree::VariableDescriptor;
JsonSerializationResult::Result Load
( void* outputValue
, const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context) override
{
namespace JSR = JsonSerializationResult;
AZ_Assert(outputValueTypeId == azrtti_typeid<VariableDescriptor>(), "ExpressionTreeVariableDescriptorSerializer Load against "
"output typeID that was not VariableDescriptor");
AZ_Assert(outputValue, "ExpressionTreeVariableDescriptorSerializer Load against null output");
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
auto outputDatum = reinterpret_cast<VariableDescriptor*>(outputValue);
result.Combine(ContinueLoadingFromJsonObjectField
( &outputDatum->m_supportedTypes
, azrtti_typeid<decltype(outputDatum->m_supportedTypes)>()
, inputValue
, "SupportedTypes"
, context));
// any storage begin
AZ::Uuid typeId = AZ::Uuid::CreateNull();
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
return context.Report
( JSR::Tasks::ReadField
, JSR::Outcomes::Missing
, AZStd::string::format("ExpressionTreeVariableDescriptorSerializer::Load failed to load the %s member"
, JsonSerialization::TypeIdFieldIdentifier));
}
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
if (typeId.IsNull())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
, "ExpressionTreeVariableDescriptorSerializer::Load failed to load the AZ TypeId of the value");
}
AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId);
if (storage.empty() || storage.type() != typeId)
{
return context.Report(result, "ExpressionTreeVariableDescriptorSerializer::Load failed to load a value matched the "
"reported AZ TypeId. The C++ declaration may have been deleted or changed.");
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "Value", context));
outputDatum->m_value = storage;
// any storage end
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ExpressionTreeVariableDescriptorSerializer Load finished loading VariableDescriptor"
: "ExpressionTreeVariableDescriptorSerializer Load failed to load VariableDescriptor");
}
JsonSerializationResult::Result Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, const Uuid& valueTypeId, JsonSerializerContext& context) override
{
namespace JSR = JsonSerializationResult;
AZ_Assert(valueTypeId == azrtti_typeid<VariableDescriptor>(), "VariableDescriptor Store against value typeID that "
"was not VariableDescriptor");
AZ_Assert(inputValue, "VariableDescriptor Store against null inputValue pointer ");
auto inputScriptDataPtr = reinterpret_cast<const VariableDescriptor*>(inputValue);
auto defaultScriptDataPtr = reinterpret_cast<const VariableDescriptor*>(defaultValue);
if (defaultScriptDataPtr)
{
if (inputScriptDataPtr->m_supportedTypes == defaultScriptDataPtr->m_supportedTypes
&& AZ::Helpers::CompareAnyValue(inputScriptDataPtr->m_value, defaultScriptDataPtr->m_value))
{
return context.Report
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "VariableDescriptor Store used defaults for "
"VariableDescriptor");
}
}
JSR::ResultCode result(JSR::Tasks::WriteValue);
outputValue.SetObject();
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "SupportedTypes"
, &inputScriptDataPtr->m_supportedTypes
, defaultScriptDataPtr ? &defaultScriptDataPtr->m_supportedTypes : nullptr
, azrtti_typeid<decltype(inputScriptDataPtr->m_supportedTypes)>()
, context));
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_value.type(), context));
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(typeValue)
, context.GetJsonAllocator());
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "Value"
, AZStd::any_cast<void>(const_cast<AZStd::any*>(&inputScriptDataPtr->m_value))
, defaultScriptDataPtr ? AZStd::any_cast<void>(const_cast<AZStd::any*>(&defaultScriptDataPtr->m_value)) : nullptr
, inputScriptDataPtr->m_value.type()
, context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "VariableDescriptor Store finished saving VariableDescriptor"
: "VariableDescriptor Store failed to save VariableDescriptor");
}
};
AZ_CLASS_ALLOCATOR_IMPL(ExpressionTreeVariableDescriptorSerializer, SystemAllocator, 0);
}

@ -13,6 +13,8 @@ set(FILES
Include/ExpressionEvaluation/ExpressionEngine/ExpressionTypes.h
Source/ExpressionEvaluationSystemComponent.cpp
Source/ExpressionEvaluationSystemComponent.h
Source/ExpressionPrimitivesSerializers.inl
Source/ElementInformationSerializer.inl
Source/ExpressionEngine/ExpressionElementParser.h
Source/ExpressionEngine/ExpressionPrimitive.cpp
Source/ExpressionEngine/ExpressionPrimitive.h

@ -114,11 +114,13 @@ namespace ScriptCanvasEditor
ScriptCanvas::ScriptCanvasData& ScriptCanvasAsset::GetScriptCanvasData()
{
AZ_Assert(m_data != nullptr, "ScriptCanvasData not initialized, it must be created on construction");
return *m_data;
}
const ScriptCanvas::ScriptCanvasData& ScriptCanvasAsset::GetScriptCanvasData() const
{
AZ_Assert(m_data != nullptr, "ScriptCanvasData not initialized, it must be created on construction");
return *m_data;
}
}

@ -6,29 +6,47 @@
*
*/
#include <ScriptCanvas/Assets/ScriptCanvasAssetHandler.h>
#include <ScriptCanvas/Assets/ScriptCanvasAsset.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/std/string/string_view.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <Core/ScriptCanvasBus.h>
#include <GraphCanvas/GraphCanvasBus.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Assets/ScriptCanvasAsset.h>
#include <ScriptCanvas/Assets/ScriptCanvasAssetHandler.h>
#include <ScriptCanvas/Bus/ScriptCanvasBus.h>
#include <Core/ScriptCanvasBus.h>
#include <ScriptCanvas/Components/EditorGraph.h>
#include <ScriptCanvas/Components/EditorScriptCanvasComponent.h>
#include <ScriptCanvas/Components/EditorGraphVariableManagerComponent.h>
#include <ScriptCanvas/Components/EditorScriptCanvasComponent.h>
#include <ScriptCanvas/Core/SerializationListener.h>
#include <GraphCanvas/GraphCanvasBus.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/std/string/string_view.h>
namespace ScriptCanvasAssetHandlerCpp
{
using namespace ScriptCanvas;
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
void CollectNodes(const GraphData::NodeContainer& container, SerializationListeners& listeners)
{
for (auto& nodeEntity : container)
{
if (nodeEntity)
{
if (auto listener = azrtti_cast<SerializationListener*>(AZ::EntityUtils::FindFirstDerivedComponent<Node>(nodeEntity)))
{
listeners.push_back(listener);
}
}
}
}
}
namespace ScriptCanvasEditor
{
@ -75,26 +93,84 @@ namespace ScriptCanvasEditor
}
}
AZ::Data::AssetHandler::LoadResult ScriptCanvasAssetHandler::LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB)
AZ::Data::AssetHandler::LoadResult ScriptCanvasAssetHandler::LoadAssetData
( const AZ::Data::Asset<AZ::Data::AssetData>& assetTarget
, AZStd::shared_ptr<AZ::Data::AssetDataStream> streamSource
, [[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB)
{
auto* scriptCanvasAsset = asset.GetAs<ScriptCanvasAsset>();
AZ_Assert(scriptCanvasAsset, "This should be an scene slice asset, as this is the only type we process!");
if (scriptCanvasAsset && m_serializeContext)
namespace JSRU = AZ::JsonSerializationUtils;
using namespace ScriptCanvas;
auto* scriptCanvasAssetTarget = assetTarget.GetAs<ScriptCanvasAsset>();
AZ_Assert(scriptCanvasAssetTarget, "This should be a ScriptCanvasAsset, as this is the only type we process!");
if (m_serializeContext
&& streamSource
&& scriptCanvasAssetTarget)
{
stream->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
// tolerate unknown classes in the editor. Let the asset processor warn about bad nodes...
bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*stream, scriptCanvasAsset->GetScriptCanvasData(), m_serializeContext, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES));
return loadSuccess ? AZ::Data::AssetHandler::LoadResult::LoadComplete : AZ::Data::AssetHandler::LoadResult::Error;
streamSource->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
auto& scriptCanvasDataTarget = scriptCanvasAssetTarget->GetScriptCanvasData();
AZStd::vector<AZ::u8> byteBuffer;
byteBuffer.resize_no_construct(streamSource->GetLength());
AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStreamSource(&byteBuffer);
const size_t bytesRead = streamSource->Read(byteBuffer.size(), byteBuffer.data());
scriptCanvasDataTarget.m_scriptCanvasEntity.reset(nullptr);
if (bytesRead == streamSource->GetLength())
{
byteStreamSource.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
AZ::JsonDeserializerSettings settings;
settings.m_serializeContext = m_serializeContext;
settings.m_metadata.Create<SerializationListeners>();
// attempt JSON deserialization...
if (JSRU::LoadObjectFromStreamByType
( &scriptCanvasDataTarget
, azrtti_typeid<ScriptCanvasData>()
, byteStreamSource
, &settings).IsSuccess())
{
if (auto graphData = scriptCanvasAssetTarget->GetScriptCanvasGraph()
? scriptCanvasAssetTarget->GetScriptCanvasGraph()->GetGraphData()
: nullptr)
{
auto listeners = settings.m_metadata.Find<SerializationListeners>();
AZ_Assert(listeners, "Failed to create SerializationListeners");
ScriptCanvasAssetHandlerCpp::CollectNodes(graphData->m_nodes, *listeners);
for (auto listener : *listeners)
{
listener->OnDeserialize();
}
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
}
else
{
AZ_Warning("ScriptCanvas", false, "ScriptCanvasAssetHandler::LoadAssetData failed to load graph data from JOSON");
}
}
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
else
{// ...if there is a failure, check if it is saved in the old format
byteStreamSource.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
// tolerate unknown classes in the editor. Let the asset processor warn about bad nodes...
if (AZ::Utils::LoadObjectFromStreamInPlace
(byteStreamSource
, scriptCanvasDataTarget
, m_serializeContext
, AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES)))
{
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
}
}
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
}
}
return AZ::Data::AssetHandler::LoadResult::Error;
return AZ::Data::AssetHandler::LoadResult::Error;
}
bool ScriptCanvasAssetHandler::SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZ::IO::GenericStream* stream)
{
return SaveAssetData(asset.GetAs<ScriptCanvasAsset>(), stream);
@ -105,20 +181,42 @@ namespace ScriptCanvasEditor
return SaveAssetData(assetData, stream, AZ::DataStream::ST_XML);
}
bool ScriptCanvasAssetHandler::SaveAssetData(const ScriptCanvasAsset* assetData, AZ::IO::GenericStream* stream, AZ::DataStream::StreamType streamType)
bool ScriptCanvasAssetHandler::SaveAssetData
( const ScriptCanvasAsset* assetData
, AZ::IO::GenericStream* stream
, [[maybe_unused]] AZ::DataStream::StreamType streamType)
{
if (assetData && m_serializeContext)
namespace JSRU = AZ::JsonSerializationUtils;
using namespace ScriptCanvas;
if (m_serializeContext
&& stream
&& assetData
&& assetData->GetScriptCanvasGraph()
&& assetData->GetScriptCanvasGraph()->GetGraphData())
{
AZStd::vector<char> byteBuffer;
AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, streamType);
bool scriptCanvasAssetSaved = objStream->WriteClass(&assetData->GetScriptCanvasData());
objStream->Finalize();
scriptCanvasAssetSaved = stream->Write(byteBuffer.size(), byteBuffer.data()) == byteBuffer.size() && scriptCanvasAssetSaved;
return scriptCanvasAssetSaved;
}
auto graphData = assetData->GetScriptCanvasGraph()->GetGraphData();
AZ::JsonSerializerSettings settings;
settings.m_metadata.Create<SerializationListeners>();
auto listeners = settings.m_metadata.Find<SerializationListeners>();
AZ_Assert(listeners, "Failed to create SerializationListeners");
ScriptCanvasAssetHandlerCpp::CollectNodes(graphData->m_nodes, *listeners);
settings.m_keepDefaults = false;
settings.m_serializeContext = m_serializeContext;
for (auto listener : *listeners)
{
listener->OnSerialize();
}
return false;
return JSRU::SaveObjectToStream<ScriptCanvasData>(&assetData->GetScriptCanvasData(), *stream, nullptr, &settings).IsSuccess();
}
else
{
AZ_Error("ScriptCanvas", false, "Saving ScriptCavas assets in the handler requires a valid IO stream, "
"asset pointer, and serialize context");
return false;
}
}
void ScriptCanvasAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
@ -126,17 +224,11 @@ namespace ScriptCanvasEditor
delete ptr;
}
//=========================================================================
// GetSerializeContext
//=========================================================================.
AZ::SerializeContext* ScriptCanvasAssetHandler::GetSerializeContext() const
{
return m_serializeContext;
}
//=========================================================================
// SetSerializeContext
//=========================================================================.
void ScriptCanvasAssetHandler::SetSerializeContext(AZ::SerializeContext* context)
{
m_serializeContext = context;
@ -147,22 +239,17 @@ namespace ScriptCanvasEditor
EBUS_EVENT_RESULT(m_serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
if (!m_serializeContext)
{
AZ_Error("Script Canvas", false, "ScriptCanvasAssetHandler: No serialize context provided! We will not be able to process Graph Asset type");
AZ_Error("Script Canvas", false, "ScriptCanvasAssetHandler: No serialize context provided! "
"We will not be able to process Graph Asset type");
}
}
}
//=========================================================================
// GetHandledAssetTypes
//=========================================================================.
void ScriptCanvasAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
{
assetTypes.push_back(GetAssetType());
}
//=========================================================================
// GetAssetType
//=========================================================================.
AZ::Data::AssetType ScriptCanvasAssetHandler::GetAssetType() const
{
return ScriptCanvasAssetHandler::GetAssetTypeStatic();
@ -178,38 +265,24 @@ namespace ScriptCanvasEditor
return azrtti_typeid<ScriptCanvasAsset>();
}
//=========================================================================
// GetAssetTypeExtensions
//=========================================================================.
void ScriptCanvasAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
{
ScriptCanvasAsset::Description description;
extensions.push_back(description.GetExtensionImpl());
}
//=========================================================================
// GetComponentTypeId
//=========================================================================.
AZ::Uuid ScriptCanvasAssetHandler::GetComponentTypeId() const
{
return azrtti_typeid<EditorScriptCanvasComponent>();
}
//=========================================================================
// GetGroup
//=========================================================================.
const char* ScriptCanvasAssetHandler::GetGroup() const
{
return ScriptCanvas::AssetDescription::GetGroup<ScriptCanvasEditor::ScriptCanvasAsset>();
}
//=========================================================================
// GetBrowserIcon
//=========================================================================.
const char* ScriptCanvasAssetHandler::GetBrowserIcon() const
{
return ScriptCanvas::AssetDescription::GetIconPath<ScriptCanvasEditor::ScriptCanvasAsset>();
}
}

@ -734,7 +734,7 @@ namespace ScriptCanvasEditor
{
ui->statusTableView->clearSelection();
if (auto model = GetActiveData().second->GetModel())
if (auto model = GetActiveData().second ? GetActiveData().second->GetModel() : nullptr)
{
model->Clear();
model->RunValidation(m_activeGraphIds.scriptCanvasId);

@ -43,10 +43,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
namespace {{attribute_Namespace}}
{
{% endif %}
{% set className = Class.attrib['Name'] %}
{% set baseClass = Class.attrib['Base'] %}
{% set baseClasses = ", ".join(Class.attrib['Base'].split(';')) if Class.attrib['Base'] is string else "ScriptCanvas::Node" %}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
////
@ -66,7 +64,7 @@ namespace {{attribute_Namespace}}
// You must #include the generated header into the source header
#define SCRIPTCANVAS_NODE_{{ className }} \
public: \
AZ_COMPONENT({{ className }}, "{{ classUuid }}"{% if baseClass is defined %}, {{ baseClass }}{% endif %}); \
AZ_COMPONENT({{ className }}, "{{ classUuid }}", {{ baseClasses }} ); \
static void Reflect(AZ::ReflectContext* reflection); \
void ConfigureSlots() override; \
bool RequiresDynamicSlotOrdering() const override; \

@ -4,6 +4,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
#}
{% import 'ScriptCanvas_Macros.jinja' as macros %}
{% macro add_attribute(attribute, tags) %}
{% set value = tags[attribute] %}
{% if value is defined %}
@ -26,7 +28,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
#include "{{ xml.attrib['Include'] }}"
{% for Class in xml.iter('Class') %}
{% set baseClass = Class.attrib['Base'].split(';')[0] if Class.attrib['Base'] is string else "ScriptCanvas::Node" %}
{% set attribute_Namespace = undefined %}
{%- if Class.attrib['Namespace'] is defined %}
{% if Class.attrib['Namespace'] != "None" %}
@ -42,10 +44,8 @@ namespace {{attribute_Namespace}}
void {{ Class.attrib['QualifiedName'] }}::ConfigureSlots()
{
{% if Class.attrib['Base'] is defined %}
{{ Class.attrib['Base'] }}::ConfigureSlots();
{{ baseClass }}::ConfigureSlots();
{% endif %}
{% for Property in Class.iter('Property') %}
{% if Property.attrib['IsInput'] | booleanTrue %}
// {{ Property.attrib['Name'] }}
@ -208,15 +208,15 @@ void {{ Class.attrib['QualifiedName'] }}::Reflect(AZ::ReflectContext* context)
{% endfor %}
{% endif %}
{% if Class.attrib['Base'] is defined %}
static_assert((std::is_base_of<ScriptCanvas::Node, {{ Class.attrib['Base'] }}>::value), "Script Canvas nodes require the first base class to be derived from ScriptCanvas::Node");
static_assert((std::is_base_of<ScriptCanvas::Node, {{ baseClass }}>::value), "Script Canvas nodes require the first base class to be derived from ScriptCanvas::Node");
{% endif %}
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<{{ Class.attrib['QualifiedName'] }}{% if Class.attrib['Base'] is defined %}, {{ Class.attrib['Base'] }}{% endif %}>()
serializeContext->Class<{{ Class.attrib['QualifiedName'] }}, {{ baseClass }}>()
{% if Class.attrib['EventHandler'] is defined %}
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
->EventHandler<{{ Class.attrib['EventHandler'] }}>()
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
{% endif %}
{% if Class.attrib['Version'] is defined %}
->Version({{ Class.attrib['Version'] }}{% if Class.attrib['VersionConverter'] is defined %}, &{{ Class.attrib['VersionConverter'] }}{% endif %})

@ -160,7 +160,9 @@ void {{attribute_QualifiedName}}::Reflect(AZ::ReflectContext* context)
{
{% if ExtendReflectionSerialize is defined %} auto {{preSerialize}} = {% else %} {% endif %}serializeContext->Class<{{ attribute_Name }}{% if attribute_Base is defined %}, {{ attribute_Base }}{% endif %}>(){{postSerialize}}
{% if attribute_EventHandler is defined %}
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
{{preSerialize}}->EventHandler<{{ attribute_EventHandler }}>(){{postSerialize}}
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
{% endif %}
{# Serialized Properties #}

@ -173,11 +173,10 @@ AZStd::tuple<{{returnTypes|join(", ")}}>
{# ------- #}
{# ------------------------------------------------------------------------------------- #}
{# NODEABLES #}
{# TODO-LS: This macro lacks parsing the parameters provided to a Contract tag #}
{# TODO: This macro lacks parsing the parameters provided to a Contract tag #}
{%- macro AddContract(configurationName, item) -%}
{% set contracts = [] %}

@ -24,6 +24,8 @@
#include <Core/NamedId.h>
#include <ScriptCanvas/Grammar/PrimitivesDeclarations.h>
#define OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED
namespace AZ
{
class Entity;
@ -94,7 +96,7 @@ namespace ScriptCanvas
struct VersionData
{
AZ_TYPE_INFO(VersionData, "{14C629F6-467B-46FE-8B63-48FDFCA42175}");
AZ_TYPE_INFO(VersionData, "{52036892-DA63-4199-AC6A-9BAFE6B74EFC}");
static void Reflect(AZ::ReflectContext* context);

@ -2041,7 +2041,7 @@ namespace ScriptCanvas
}
}
void Datum::OnWriteEnd()
void Datum::OnDeserialize()
{
if (m_type.GetType() == Data::eType::BehaviorContextObject)
{
@ -2059,18 +2059,27 @@ namespace ScriptCanvas
}
else
{
AZ_Error("Script Canvas", false, AZStd::string::format("Datum type (%s) de-serialized, but no such class found in the behavior context", m_type.GetAZType().ToString<AZStd::string>().c_str()).c_str());
AZ_Error("ScriptCanvas", false, AZStd::string::format("Datum type (%s) de-serialized, but no such class found in the behavior context", m_type.GetAZType().ToString<AZStd::string>().c_str()).c_str());
}
}
}
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void Datum::OnWriteEnd()
{
OnDeserialize();
}
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
void Datum::Reflect(AZ::ReflectContext* reflection)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<Datum>()
->Version(DatumHelpers::Version::Current, &DatumHelpers::VersionConverter)
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
->EventHandler<SerializeContextEventHandler>()
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
->Field("m_isUntypedStorage", &Datum::m_isOverloadedStorage)
->Field("m_type", &Datum::m_type)
->Field("m_originality", &Datum::m_originality)

@ -8,14 +8,15 @@
#pragma once
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/string/string_view.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Core/SerializationListener.h>
#include <ScriptCanvas/Data/BehaviorContextObject.h>
#include <ScriptCanvas/Data/Data.h>
#include <ScriptCanvas/Data/DataTrait.h>
#include <ScriptCanvas/Data/BehaviorContextObject.h>
#include <AzCore/Outcome/Outcome.h>
namespace AZ
{
@ -33,11 +34,12 @@ namespace ScriptCanvas
/// A Datum is used to provide generic storage for all data types in ScriptCanvas, and provide a common interface to accessing, modifying, and displaying them
/// in the editor, regardless of their actual ScriptCanvas or BehaviorContext type.
class Datum final
: public SerializationListener
{
friend class AZ::DatumSerializer;
public:
AZ_TYPE_INFO(Datum, "{8B836FC0-98A8-4A81-8651-35C7CA125451}");
AZ_RTTI(Datum, "{8B836FC0-98A8-4A81-8651-35C7CA125451}", SerializationListener);
AZ_CLASS_ALLOCATOR(Datum, AZ::SystemAllocator, 0);
enum class eOriginality : int
@ -234,6 +236,7 @@ namespace ScriptCanvas
}
};
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
class SerializeContextEventHandler : public AZ::SerializeContext::IEventHandler
{
public:
@ -244,6 +247,7 @@ namespace ScriptCanvas
datum->OnWriteEnd();
}
};
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
friend class SerializeContextEventHandler;
@ -341,9 +345,11 @@ namespace ScriptCanvas
void OnDatumEdited();
void OnReadBegin();
void OnDeserialize() override;
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void OnWriteEnd();
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
AZ_INLINE bool SatisfiesTraits(AZ::u8 behaviorValueTraits) const;

@ -19,17 +19,17 @@ namespace AZ
namespace ScriptCanvas
{
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
class GraphDataEventHandler : public AZ::SerializeContext::IEventHandler
{
public:
/// Called to rebuild the Endpoint map
void OnWriteEnd(void* classPtr) override
{
auto* graphData = reinterpret_cast<GraphData*>(classPtr);
graphData->BuildEndpointMap();
graphData->LoadDependentAssets();
reinterpret_cast<GraphData*>(classPtr)->OnDeserialized();
}
};
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
void GraphData::Reflect(AZ::ReflectContext* context)
{
@ -42,7 +42,9 @@ namespace ScriptCanvas
serializeContext->Class<GraphData>()
->Version(4, &GraphData::VersionConverter)
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
->EventHandler<GraphDataEventHandler>()
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
->Field("m_nodes", &GraphData::m_nodes)
->Field("m_connections", &GraphData::m_connections)
->Field("m_dependentAssets", &GraphData::m_dependentAssets)
@ -215,4 +217,10 @@ namespace ScriptCanvas
m_dependentAssets.clear();
}
void GraphData::OnDeserialized()
{
BuildEndpointMap();
LoadDependentAssets();
}
}

@ -37,6 +37,7 @@ namespace ScriptCanvas
void BuildEndpointMap();
void Clear(bool deleteData = false);
void LoadDependentAssets();
void OnDeserialized();
using NodeContainer = AZStd::unordered_set<AZ::Entity*>;
using ConnectionContainer = AZStd::vector<AZ::Entity*>;

@ -60,6 +60,7 @@ namespace ScriptCanvas
// Node
/////////
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
class NodeEventHandler
: public AZ::SerializeContext::IEventHandler
{
@ -67,9 +68,10 @@ namespace ScriptCanvas
void OnWriteEnd(void* objectPtr) override
{
auto node = reinterpret_cast<Node*>(objectPtr);
node->RebuildInternalState();
node->OnDeserialize();
}
};
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
bool NodeVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& nodeElementNode)
{
@ -420,7 +422,9 @@ namespace ScriptCanvas
serializeContext->RegisterGenericType<AZStd::unordered_map<SlotId, Deprecated::VariableInfo>>();
serializeContext->Class<Node, AZ::Component>()
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
->EventHandler<NodeEventHandler>()
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
->Version(NodeCpp::Version::Current, &NodeVersionConverter)
->Field("Slots", &Node::m_slots)
->Field("Datums", &Node::m_slotDatums)
@ -2614,6 +2618,11 @@ namespace ScriptCanvas
}
}
void Node::OnDeserialize()
{
RebuildInternalState();
}
void Node::OnEndpointConnected(const Endpoint& endpoint)
{
const SlotId& currentSlotId = EndpointNotificationBus::GetCurrentBusId()->GetSlotId();

@ -14,25 +14,23 @@
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/tuple.h>
#include <ScriptCanvas/CodeGen/NodeableCodegen.h>
#include <ScriptCanvas/Core/Contracts/TypeContract.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Core/DatumBus.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Core/SubgraphInterface.h>
#include <ScriptCanvas/Core/ExecutionNotificationsBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Core/SerializationListener.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Core/SubgraphInterface.h>
#include <ScriptCanvas/Debugger/StatusBus.h>
#include <ScriptCanvas/Debugger/ValidationEvents/ValidationEvent.h>
#include <ScriptCanvas/Execution/ErrorBus.h>
#include <ScriptCanvas/Execution/ExecutionBus.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
#include <ScriptCanvas/Grammar/Primitives.h>
#include <ScriptCanvas/Debugger/ValidationEvents/ValidationEvent.h>
#include <ScriptCanvas/CodeGen/NodeableCodegen.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
#define SCRIPT_CANVAS_CALL_ON_INDEX_SEQUENCE(lambdaInterior)\
int dummy[]{ 0, ( lambdaInterior , 0)... };\
@ -65,6 +63,7 @@ namespace ScriptCanvas
struct BehaviorContextMethodHelper;
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
template<typename t_Class>
class SerializeContextReadWriteHandler : public AZ::SerializeContext::IEventHandler
{
@ -128,6 +127,7 @@ namespace ScriptCanvas
deserializedObject->OnWriteEnd();
}
};
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
// List of slots that will be create visual only slots on the nodes.
// Useful for special configurations or editor only concepts.
@ -401,6 +401,7 @@ namespace ScriptCanvas
, public DatumNotificationBus::Handler
, public NodeRequestBus::Handler
, public EndpointNotificationBus::MultiHandler
, public SerializationListener
{
friend class Graph;
friend class RuntimeComponent;
@ -472,7 +473,7 @@ namespace ScriptCanvas
public:
AZ_COMPONENT(Node, "{52B454AE-FA7E-4FE9-87D3-A1CAB235C691}");
AZ_COMPONENT(Node, "{52B454AE-FA7E-4FE9-87D3-A1CAB235C691}", SerializationListener);
static void Reflect(AZ::ReflectContext* reflection);
Node();
@ -821,6 +822,7 @@ namespace ScriptCanvas
//////////////////////////////////////////////////////////////////////////
protected:
void OnDeserialize() override;
virtual void OnReconfigurationBegin() {}
virtual void OnReconfigurationEnd() {}

@ -0,0 +1,25 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace ScriptCanvas
{
class SerializationListener
{
public:
AZ_RTTI(SerializationListener, "{CA4EE281-30B3-4928-BCD8-9305CE75E463}");
virtual ~SerializationListener() {}
virtual void OnSerialize() {}
virtual void OnDeserialize() {}
};
using SerializationListeners = AZStd::vector<SerializationListener*>;
}

@ -17,26 +17,12 @@
namespace ScriptCanvas
{
void BehaviorContextObject::OnReadBegin()
{
if (!IsOwned())
{
Clear();
}
}
void BehaviorContextObject::OnWriteEnd()
{
// Id Remapping invokes this method as well, not just serializing from an ObjectStream
}
void BehaviorContextObject::Reflect(AZ::ReflectContext* reflection)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<BehaviorContextObject>()
->Version(0)
->EventHandler<SerializeContextEventHandler>()
->Field("m_flags", &BehaviorContextObject::m_flags)
->Field("m_object", &BehaviorContextObject::m_object)
;
@ -55,24 +41,11 @@ namespace ScriptCanvas
}
}
void BehaviorContextObject::SerializeContextEventHandler::OnReadBegin(void* classPtr)
{
BehaviorContextObject* object = reinterpret_cast<BehaviorContextObject*>(classPtr);
object->OnReadBegin();
}
void BehaviorContextObject::SerializeContextEventHandler::OnWriteEnd(void* classPtr)
{
BehaviorContextObject* object = reinterpret_cast<BehaviorContextObject*>(classPtr);
object->OnWriteEnd();
}
BehaviorContextObjectPtr BehaviorContextObject::CloneObject(const AZ::BehaviorClass& behaviorClass)
{
if (SystemRequestBus::HasHandlers())
{
AZStd::vector<char> buffer;
{
bool wasOwned = IsOwned();
m_flags |= Flags::Owned;
@ -87,7 +60,6 @@ namespace ScriptCanvas
}
AZ::IO::ByteContainerStream<AZStd::vector<char>> readStream(&buffer);
BehaviorContextObject* newObject = CreateDefault(behaviorClass);
AZ::Utils::LoadObjectFromStreamInPlace(readStream, (*newObject));
@ -124,6 +96,12 @@ namespace ScriptCanvas
: BehaviorContextObjectPtr(aznew BehaviorContextObject(reference, GetAnyTypeInfoReference(typeID), referenceFlags));
}
void BehaviorContextObject::Deserialize(BehaviorContextObject& target, const AZ::BehaviorClass& behaviorClass, AZStd::any& source)
{
target.m_object = AZStd::move(AZStd::any(AZStd::any_cast<void>(&source), GetAnyTypeInfoObject(behaviorClass)));
target.m_flags = Owned;
}
void BehaviorContextObject::release()
{
if (--m_referenceCount == 0)

@ -22,6 +22,7 @@
namespace AZ
{
class ReflectContext;
class BehaviorContextObjectSerializer;
}
namespace ScriptCanvas
@ -29,6 +30,8 @@ namespace ScriptCanvas
class BehaviorContextObject final
{
friend struct AZStd::IntrusivePtrCountPolicy<BehaviorContextObject>;
friend class Datum;
friend class AZ::BehaviorContextObjectSerializer;
public:
AZ_TYPE_INFO(BehaviorContextObject, "{B735214D-5182-4536-B748-61EC83C1F007}");
@ -69,16 +72,6 @@ namespace ScriptCanvas
Reference = 1 << 3,
};
class SerializeContextEventHandler : public AZ::SerializeContext::IEventHandler
{
public:
/// Called right before we start reading from the instance pointed by classPtr.
void OnReadBegin(void* classPtr) override;
/// Called after we are done writing to the instance pointed by classPtr.
void OnWriteEnd(void* classPtr) override;
};
template<typename... Args>
static AZ::BehaviorObject InvokeConstructor(const AZ::BehaviorClass& behaviorClass, void* resultPtr, Args&&... args);
@ -90,6 +83,8 @@ namespace ScriptCanvas
AZ_INLINE static BehaviorContextObject* CreateDefaultHeap(const AZ::BehaviorClass& behaviorClass);
static void Deserialize(BehaviorContextObject& target, const AZ::BehaviorClass& behaviorClass, AZStd::any& source);
// use the SSO optimization on behavior class size ALIGNED with a placement new of behavior class create
AZ_FORCE_INLINE static AnyTypeInfo GetAnyTypeInfoObject(const AZ::BehaviorClass& behaviorClass);
@ -110,6 +105,7 @@ namespace ScriptCanvas
// it is very important to track these from the moment they are created...
friend struct AZ::Serialize::InstanceFactory<BehaviorContextObject, true, false>;
friend struct AZ::AnyTypeInfoConcept<BehaviorContextObject, void>;
//...so don't use the ctors, use the Create functions...
//...the friend declarations are here for compatibility with the serialization system only
AZ_FORCE_INLINE BehaviorContextObject() = default;
@ -128,10 +124,6 @@ namespace ScriptCanvas
AZ_FORCE_INLINE bool IsOwned() const;
void OnReadBegin();
void OnWriteEnd();
AZ_FORCE_INLINE void add_ref();
void release();

@ -602,14 +602,23 @@ namespace ScriptCanvas
}
}
void EBusEventHandler::OnWriteEnd()
void EBusEventHandler::OnDeserialize()
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_mutex);
if (!m_ebus)
{
CreateHandler(m_ebusName);
}
Node::OnDeserialize();
}
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void EBusEventHandler::OnWriteEnd()
{
OnDeserialize();
}
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
NodeTypeIdentifier EBusEventHandler::GetOutputNodeType(const SlotId& slotId) const
{

@ -138,7 +138,11 @@ namespace ScriptCanvas
void SetAutoConnectToGraphOwner(bool enabled);
void OnDeserialize();
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void OnWriteEnd();
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
AZStd::string GetNodeName() const override
{

@ -313,6 +313,7 @@ namespace ScriptCanvas
}
PopulateNodeType();
m_warnOnMissingFunction = true;
}
bool Method::InitializeOverloaded([[maybe_unused]] const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName)
@ -739,10 +740,11 @@ namespace ScriptCanvas
return TupleType{ nullptr, MethodType::Count, EventType::Count, nullptr };
}
void Method::OnWriteEnd()
void Method::OnDeserialize()
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_mutex);
m_warnOnMissingFunction = true;
const AZ::BehaviorClass* bcClass{};
const AZ::BehaviorMethod* method{};
EventType eventType;
@ -758,14 +760,22 @@ namespace ScriptCanvas
{
AZ_Warning("ScriptCanvas", !m_warnOnMissingFunction, "method node failed to deserialize properly");
}
}
if (m_resultSlotIDs.empty())
{
m_resultSlotIDs.emplace_back(SlotId{});
}
Node::OnDeserialize();
}
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void Method::OnWriteEnd()
{
OnDeserialize();
}
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
bool Method::BranchesOnResult() const
{
@ -829,7 +839,9 @@ namespace ScriptCanvas
{
serializeContext->Class<Method, Node>()
->Version(MethodCPP::eVersion::Current, &MethodCPP::MethodVersionConverter)
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
->EventHandler<SerializeContextOnWriteEndHandler<Method>>()
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
->Field("methodType", &Method::m_methodType)
->Field("methodName", &Method::m_lookupName)
->Field("className", &Method::m_className)

@ -22,7 +22,6 @@ namespace AZ
namespace ScriptCanvas
{
AZ::Outcome<void, AZStd::string> IsExposable(const AZ::BehaviorMethod& method);
Grammar::FunctionPrototype ToSignature(const AZ::BehaviorMethod& method);
@ -31,7 +30,8 @@ namespace ScriptCanvas
{
namespace Core
{
class Method : public Node
class Method
: public Node
{
public:
AZ_COMPONENT(Method, "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF}", Node);
@ -107,7 +107,11 @@ namespace ScriptCanvas
SlotId GetBusSlotId() const;
void OnDeserialize();
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void OnWriteEnd();
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
virtual bool IsMethodOverloaded() const { return false; }
@ -180,7 +184,7 @@ namespace ScriptCanvas
AZStd::vector<SlotId> m_inputSlots;
AZStd::vector<SlotId> m_resultSlotIDs;
AZStd::recursive_mutex m_mutex; // post-serialization
bool m_warnOnMissingFunction = true;
bool m_warnOnMissingFunction = false;
Method(const Method&) = delete;
};

@ -60,7 +60,9 @@ namespace ScriptCanvas
{
serializeContext->Class<MethodOverloaded, Method>()
->Version(MethodOverloadedCpp::Version::Current, &MethodOverloadedVersionConverter)
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
->EventHandler<SerializeContextReadWriteHandler<MethodOverloaded>>()
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
->Field("orderedInputSlotIds", &MethodOverloaded::m_orderedInputSlotIds)
->Field("outputSlotIds", &MethodOverloaded::m_outputSlotIds)
;
@ -186,6 +188,7 @@ namespace ScriptCanvas
RefreshActiveIndexes();
ConfigureContracts();
SetWarnOnMissingFunction(true);
}
SlotId MethodOverloaded::AddMethodInputSlot(const MethodConfiguration& config, size_t argumentIndex)
@ -397,20 +400,14 @@ namespace ScriptCanvas
return signature;
}
void MethodOverloaded::OnReadBegin()
{
}
void MethodOverloaded::OnReadEnd()
{
}
void MethodOverloaded::OnWriteBegin()
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
void MethodOverloaded::OnWriteEnd()
{
SetWarnOnMissingFunction(false);
OnDeserialize();
}
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
void MethodOverloaded::OnWriteEnd()
void MethodOverloaded::OnDeserialize()
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(GetMutex());
@ -462,6 +459,7 @@ namespace ScriptCanvas
}
SetWarnOnMissingFunction(true);
Node::OnDeserialize();
}
void MethodOverloaded::SetupMethodData(const AZ::BehaviorMethod* behaviorMethod, const AZ::BehaviorClass* behaviorClass)

@ -33,7 +33,9 @@ namespace ScriptCanvas
, public OverloadContractInterface
{
private:
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
friend class SerializeContextReadWriteHandler<MethodOverloaded>;
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
public:
static void Reflect(AZ::ReflectContext* reflectContext);
@ -91,13 +93,15 @@ namespace ScriptCanvas
// \todo make execution thread sensitive, which can then support generic programming
Grammar::FunctionPrototype GetInputSignature() const;
#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)////
// SerializeContextReadWriteHandler
void OnReadBegin();
void OnReadEnd();
void OnWriteBegin();
void OnReadBegin() {}
void OnReadEnd() {}
void OnWriteBegin() {}
void OnWriteEnd();
////
#endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED)
void OnDeserialize() override;
void SetupMethodData(const AZ::BehaviorMethod* lookupMethod, const AZ::BehaviorClass* lookupClass);
void ConfigureContracts();

@ -5,7 +5,6 @@
QualifiedName="ScriptCanvas::Nodes::Logic::Gate"
PreferredClassName="If"
Uuid="{F19CC10A-02FD-4E75-ADAA-9CFBD8A4E2F8}"
Base="ScriptCanvas::Node"
Icon="Icons/ScriptCanvas/Print.png"
Version="0"
GeneratePropertyFriend="True"

@ -0,0 +1,149 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Serialization/AZStdAnyDataContainer.inl>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Serialization/BehaviorContextObjectSerializer.h>
using namespace ScriptCanvas;
namespace AZ
{
AZ_CLASS_ALLOCATOR_IMPL(BehaviorContextObjectSerializer, SystemAllocator, 0);
JsonSerializationResult::Result BehaviorContextObjectSerializer::Load
( void* outputValue
, [[maybe_unused]] const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context)
{
namespace JSR = JsonSerializationResult;
AZ_Assert(outputValueTypeId == azrtti_typeid<BehaviorContextObject>(), "BehaviorContextObjectSerializer Load against output typeID"
"that was not BehaviorContextObject");
AZ_Assert(outputValue, "BehaviorContextObjectSerializer Load against null output");
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
auto outputBehaviorContextObject = reinterpret_cast<BehaviorContextObject*>(outputValue);
bool isOwned = false;
result.Combine(ContinueLoadingFromJsonObjectField
( &isOwned
, azrtti_typeid<bool>()
, inputValue
, "isOwned"
, context));
if (isOwned)
{
AZStd::any storage;
{ // any storage begin
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
return context.Report
(JSR::Tasks::ReadField
, JSR::Outcomes::Missing
, AZStd::string::format("BehaviorContextObjectSerializer::Load failed to load the %s member"
, JsonSerialization::TypeIdFieldIdentifier));
}
AZ::Uuid typeId;
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
if (typeId.IsNull())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
, "BehaviorContextObjectSerializer::Load failed to load the AZ TypeId of the value");
}
storage = context.GetSerializeContext()->CreateAny(typeId);
if (storage.empty() || storage.type() != typeId)
{
return context.Report(result, "BehaviorContextObjectSerializer::Load failed to load a value matched the reported AZ "
"TypeId. The C++ declaration may have been deleted or changed.");
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "value", context));
} // any storage end
auto bcClass = AZ::BehaviorContextHelper::GetClass(storage.type());
BehaviorContextObject::Deserialize(*outputBehaviorContextObject, *bcClass, storage);
}
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "BehaviorContextObjectSerializer Load finished loading BehaviorContextObject"
: "BehaviorContextObjectSerializer Load failed to load BehaviorContextObject");
}
JsonSerializationResult::Result BehaviorContextObjectSerializer::Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, [[maybe_unused]] const Uuid& valueTypeId
, JsonSerializerContext& context)
{
namespace JSR = JsonSerializationResult;
AZ_Assert(valueTypeId == azrtti_typeid<BehaviorContextObject>(), "BehaviorContextObjectSerializer Store against value typeID that "
"was not BehaviorContextObject");
AZ_Assert(inputValue, "BehaviorContextObjectSerializer Store against null inputValue pointer ");
auto defaultScriptDataPtr = reinterpret_cast<const BehaviorContextObject*>(defaultValue);
auto inputScriptDataPtr = reinterpret_cast<const BehaviorContextObject*>(inputValue);
if (defaultScriptDataPtr)
{
if (AZ::Helpers::CompareAnyValue(inputScriptDataPtr->ToAny(), defaultScriptDataPtr->ToAny()))
{
return context.Report
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "BehaviorContextObjectSerializer Store used defaults "
"for BehaviorContextObject");
}
}
outputValue.SetObject();
JSR::ResultCode result(JSR::Tasks::WriteValue);
const bool isInputOwned = inputScriptDataPtr->IsOwned();
const bool isDefaultOwned = defaultScriptDataPtr ? defaultScriptDataPtr->IsOwned() : false;
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "isOwned"
, &isInputOwned
, &isDefaultOwned
, azrtti_typeid<bool>()
, context));
if (isInputOwned)
{
// any storage begin
{
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->ToAny().type(), context));
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(typeValue)
, context.GetJsonAllocator());
}
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "value"
, inputScriptDataPtr->Get()
, defaultScriptDataPtr ? defaultScriptDataPtr->Get() : nullptr
, inputScriptDataPtr->ToAny().type()
, context));
// datum storage end
}
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "BehaviorContextObjectSerializer Store finished saving BehaviorContextObject"
: "BehaviorContextObjectSerializer Store failed to save BehaviorContextObject");
}
}

@ -0,0 +1,37 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/Memory.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
class BehaviorContextObjectSerializer
: public BaseJsonSerializer
{
public:
AZ_RTTI(BehaviorContextObjectSerializer, "{88469C4C-923F-4508-A45C-33DDBB91074E}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
private:
JsonSerializationResult::Result Load
( void* outputValue
, const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context) override;
JsonSerializationResult::Result Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, const Uuid& valueTypeId, JsonSerializerContext& context) override;
};
}

@ -50,10 +50,23 @@ namespace AZ
, "scriptCanvasType"
, context));
AZStd::any storage;
{ // datum storage begin
AZ::Uuid typeId = AZ::Uuid::CreateNull();
// datum storage begin
auto isNullPointerMember = inputValue.FindMember("isNullPointer");
if (isNullPointerMember == inputValue.MemberEnd())
{
return context.Report
( JSR::Tasks::ReadField
, JSR::Outcomes::Missing
, "DatumSerializer::Load failed to load the 'isNullPointer'' member");
}
if (isNullPointerMember->value.GetBool())
{
*outputDatum = Datum(scType, Datum::eOriginality::Original);
}
else
{
AZ::Uuid typeId = AZ::Uuid::CreateNull();
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
@ -71,7 +84,7 @@ namespace AZ
, "DatumSerializer::Load failed to load the AZ TypeId of the value");
}
storage = context.GetSerializeContext()->CreateAny(typeId);
AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId);
if (storage.empty() || storage.type() != typeId)
{
return context.Report(result, "DatumSerializer::Load failed to load a value matched the reported AZ TypeId. "
@ -79,22 +92,25 @@ namespace AZ
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "value", context));
*outputDatum = Datum(scType, Datum::eOriginality::Original, AZStd::any_cast<void>(&storage), scType.GetAZType());
} // datum storage end
AZStd::string label;
AZ_Assert(azrtti_typeid<decltype(outputDatum->m_datumLabel)>() == azrtti_typeid<decltype(label)>()
, "m_datumLabel type changed and won't load properly");
result.Combine(ContinueLoadingFromJsonObjectField
result.Combine(ContinueLoadingFromJsonObjectField
( &label
, azrtti_typeid<decltype(outputDatum->m_datumLabel)>()
, inputValue
, "label"
, context));
outputDatum->SetLabel(label);
Datum copy(scType, Datum::eOriginality::Original, AZStd::any_cast<void>(&storage), scType.GetAZType());
copy.SetLabel(label);
*outputDatum = copy;
if (auto listeners = context.GetMetadata().Find<SerializationListeners>())
{
listeners->push_back(outputDatum);
}
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "DatumSerializer Load finished loading Datum"
: "DatumSerializer Load failed to load Datum");
@ -123,7 +139,7 @@ namespace AZ
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "DatumSerializer Store used defaults for Datum");
}
}
JSR::ResultCode result(JSR::Tasks::WriteValue);
outputValue.SetObject();
@ -142,26 +158,32 @@ namespace AZ
, defaultScriptDataPtr ? &defaultScriptDataPtr->GetType() : nullptr
, azrtti_typeid<decltype(inputScriptDataPtr->GetType())>()
, context));
{ // datum storage begin
{
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->GetType().GetAZType(), context));
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(typeValue)
, context.GetJsonAllocator());
}
// datum storage begin
auto inputObjectSource = inputScriptDataPtr->GetAsDanger();
outputValue.AddMember("isNullPointer", rapidjson::Value(inputObjectSource == nullptr), context.GetJsonAllocator());
if (inputObjectSource)
{
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->GetType().GetAZType(), context));
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(typeValue)
, context.GetJsonAllocator());
auto defaultObjectSource = defaultScriptDataPtr ? defaultScriptDataPtr->GetAsDanger() : nullptr;
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "value"
, inputScriptDataPtr->GetAsDanger()
, defaultScriptDataPtr ? defaultScriptDataPtr->GetAsDanger() : nullptr
, inputObjectSource
, defaultObjectSource
, inputScriptDataPtr->GetType().GetAZType()
, context));
} // datum storage end
}
// datum storage end
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "label"
@ -174,5 +196,4 @@ namespace AZ
? "DatumSerializer Store finished saving Datum"
: "DatumSerializer Store failed to save Datum");
}
}

@ -50,6 +50,7 @@ namespace AZ
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&outputVariable->value), typeId, inputValue, "value", context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "RuntimeVariableSerializer Load finished loading RuntimeVariable"
: "RuntimeVariableSerializer Load failed to load RuntimeVariable");

@ -7,7 +7,6 @@
*/
#include <iostream>
#include <AzCore/Component/EntityUtils.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
@ -23,8 +22,9 @@
#include <ScriptCanvas/Execution/ExecutionPerformanceTimer.h>
#include <ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Serialization/RuntimeVariableSerializer.h>
#include <ScriptCanvas/Serialization/DatumSerializer.h>
#include <ScriptCanvas/Serialization/BehaviorContextObjectSerializer.h>
#include <ScriptCanvas/Serialization/RuntimeVariableSerializer.h>
#include <ScriptCanvas/SystemComponent.h>
#include <ScriptCanvas/Variable/GraphVariableManagerComponent.h>
@ -59,6 +59,7 @@ namespace ScriptCanvas
{
void SystemComponent::Reflect(AZ::ReflectContext* context)
{
VersionData::Reflect(context);
Nodeable::Reflect(context);
ReflectLibraries(context);
@ -88,13 +89,9 @@ namespace ScriptCanvas
if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast<AZ::JsonRegistrationContext*>(context))
{
jsonContext->Serializer<AZ::RuntimeVariableSerializer>()
->HandlesType<RuntimeVariable>()
;
jsonContext->Serializer<AZ::DatumSerializer>()
->HandlesType<Datum>()
;
jsonContext->Serializer<AZ::DatumSerializer>()->HandlesType<Datum>();
jsonContext->Serializer<AZ::BehaviorContextObjectSerializer>()->HandlesType<BehaviorContextObject>();
jsonContext->Serializer<AZ::RuntimeVariableSerializer>()->HandlesType<RuntimeVariable>();
}
#if defined(SC_EXECUTION_TRACE_ENABLED)

@ -74,6 +74,7 @@ set(FILES
Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp
Include/ScriptCanvas/Core/NodeableNodeOverloaded.h
Include/ScriptCanvas/Core/NodeFunctionGeneric.h
Include/ScriptCanvas/Core/SerializationListener.h
Include/ScriptCanvas/Core/Slot.cpp
Include/ScriptCanvas/Core/Slot.h
Include/ScriptCanvas/Core/SlotConfigurationDefaults.h
@ -539,6 +540,8 @@ set(FILES
Include/ScriptCanvas/Profiler/Aggregator.cpp
Include/ScriptCanvas/Profiler/DrillerEvents.h
Include/ScriptCanvas/Profiler/DrillerEvents.cpp
Include/ScriptCanvas/Serialization/BehaviorContextObjectSerializer.h
Include/ScriptCanvas/Serialization/BehaviorContextObjectSerializer.cpp
Include/ScriptCanvas/Serialization/DatumSerializer.h
Include/ScriptCanvas/Serialization/DatumSerializer.cpp
Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.h

@ -0,0 +1,125 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/Features/SrgSemantics.azsli>
#include <viewsrg.srgi>
struct VertexInput
{
float2 Position : POSITION;
float2 UV : UV;
};
struct VertexOutput
{
float4 Position : SV_Position;
float3 Normal : NORMAL;
float2 UV : UV;
};
ShaderResourceGroup ObjectSrg : SRG_PerObject
{
Texture2D<float4> HeightmapImage;
Sampler LinearSampler
{
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
row_major float3x4 m_modelToWorld;
float m_heightScale;
float2 m_uvMin;
float2 m_uvMax;
float2 m_uvStep;
}
float4x4 GetObject_WorldMatrix()
{
float4x4 modelToWorld = float4x4(
float4(1, 0, 0, 0),
float4(0, 1, 0, 0),
float4(0, 0, 1, 0),
float4(0, 0, 0, 1));
modelToWorld[0] = ObjectSrg::m_modelToWorld[0];
modelToWorld[1] = ObjectSrg::m_modelToWorld[1];
modelToWorld[2] = ObjectSrg::m_modelToWorld[2];
return modelToWorld;
}
float GetHeight(float2 origUv)
{
float2 uv = clamp(origUv, 0.0f, 1.0f);
return ObjectSrg::m_heightScale * (ObjectSrg::HeightmapImage.SampleLevel(ObjectSrg::LinearSampler, uv, 0).r - 0.5f);
}
VertexOutput MainVS(in VertexInput input)
{
VertexOutput output;
// Clamp the UVs *after* lerping to ensure that everything aligns properly right to the edge.
// We use out-of-bounds UV values to denote vertices that need to be removed.
float2 origUv = lerp(ObjectSrg::m_uvMin, ObjectSrg::m_uvMax, input.UV);
float2 uv = clamp(origUv, 0.0f, 1.0f);
// Loop up the height and calculate our final position.
float height = GetHeight(uv);
float3 worldPosition = mul(GetObject_WorldMatrix(), float4(input.Position, height, 1.0f)).xyz;
output.Position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0f));
// Remove all vertices outside our bounds by turning them into NaN positions.
output.Position = output.Position / ((origUv.x >= 0.0f && origUv.x < 1.0f && origUv.y >= 0.0f && origUv.y < 1.0f) ? 1.0f : 0.0f);
// Calculate normal
float2 gridSize = {1.0f, 1.0f};
float up = GetHeight(uv + ObjectSrg::m_uvStep * float2(-1.0f, 0.0f));
float right = GetHeight(uv + ObjectSrg::m_uvStep * float2( 0.0f, 1.0f));
float down = GetHeight(uv + ObjectSrg::m_uvStep * float2( 1.0f, 0.0f));
float left = GetHeight(uv + ObjectSrg::m_uvStep * float2( 0.0f, -1.0f));
float dydx = (right - left) * gridSize[0];
float dydz = (down - up) * gridSize[1];
output.Normal = normalize(float3(dydx, 2.0f, dydz));
output.UV = uv;
return output;
}
struct PixelOutput
{
float4 m_color : SV_Target0;
};
PixelOutput MainPS(in VertexOutput input)
{
PixelOutput output;
// Hard-coded fake light direction
float3 lightDirection = normalize(float3(1.0, -1.0, 1.0));
// Fake light intensity ranges from 1.0 for normals directly facing the light to zero for those
// directly facing away.
float lightDot = dot(normalize(input.Normal), lightDirection);
float lightIntensity = lightDot * 0.5 + 0.5;
// add a small amount of ambient and reduce direct light to keep in 0-1 range
lightIntensity = saturate(0.1 + lightIntensity * 0.9);
// The lightIntensity should not affect alpha so only apply it to rgb.
//output.m_color.rgb = ((input.Normal + float3(1.0, 1.0, 1.0)) / 2.0);
output.m_color.rgb = float3(1.0, 1.0, 1.0) * lightIntensity;
output.m_color.a = 1.0f;
return output;
}

@ -0,0 +1,37 @@
{
"Source" : "Terrain",
"RasterState" : { "CullMode" : "None" },
"DepthStencilState" : {
"Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
},
"BlendState" : {
"Enable" : true,
"BlendSource" : "One",
"BlendAlphaSource" : "One",
"BlendDest" : "AlphaSourceInverse",
"BlendAlphaDest" : "AlphaSourceInverse",
"BlendAlphaOp" : "Add"
},
"DrawList" : "forward",
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}

@ -0,0 +1,231 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Components/TerrainHeightGradientListComponent.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
namespace Terrain
{
void TerrainHeightGradientListConfig::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainHeightGradientListConfig, AZ::ComponentConfig>()
->Version(1)
->Field("GradientEntities", &TerrainHeightGradientListConfig::m_gradientEntities)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<TerrainHeightGradientListConfig>(
"Terrain Height Gradient List Component", "Provide height data for a region of the world")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(0, &TerrainHeightGradientListConfig::m_gradientEntities, "Gradient Entities", "Ordered list of gradients to use as height providers.")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, true)
->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC_CE("GradientService"))
;
}
}
}
void TerrainHeightGradientListComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainHeightProviderService"));
}
void TerrainHeightGradientListComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainHeightProviderService"));
services.push_back(AZ_CRC_CE("GradientService"));
}
void TerrainHeightGradientListComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainAreaService"));
services.push_back(AZ_CRC_CE("BoxShapeService"));
}
void TerrainHeightGradientListComponent::Reflect(AZ::ReflectContext* context)
{
TerrainHeightGradientListConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainHeightGradientListComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &TerrainHeightGradientListComponent::m_configuration)
;
}
}
TerrainHeightGradientListComponent::TerrainHeightGradientListComponent(const TerrainHeightGradientListConfig& configuration)
: m_configuration(configuration)
{
}
void TerrainHeightGradientListComponent::Activate()
{
LmbrCentral::DependencyNotificationBus::Handler::BusConnect(GetEntityId());
Terrain::TerrainAreaHeightRequestBus::Handler::BusConnect(GetEntityId());
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
// Make sure we get update notifications whenever this entity or any dependent gradient entity changes in any way.
// We'll use that to notify the terrain system that the height information needs to be refreshed.
m_dependencyMonitor.Reset();
m_dependencyMonitor.ConnectOwner(GetEntityId());
m_dependencyMonitor.ConnectDependency(GetEntityId());
for (auto& entityId : m_configuration.m_gradientEntities)
{
if (entityId != GetEntityId())
{
m_dependencyMonitor.ConnectDependency(entityId);
}
}
// Cache any height data needed and notify that the area has changed.
OnCompositionChanged();
}
void TerrainHeightGradientListComponent::Deactivate()
{
m_dependencyMonitor.Reset();
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
Terrain::TerrainAreaHeightRequestBus::Handler::BusDisconnect();
LmbrCentral::DependencyNotificationBus::Handler::BusDisconnect();
// Since this height data will no longer exist, notify the terrain system to refresh the area.
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId());
}
bool TerrainHeightGradientListComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const TerrainHeightGradientListConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool TerrainHeightGradientListComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TerrainHeightGradientListConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
float TerrainHeightGradientListComponent::GetHeight(float x, float y)
{
float maxSample = 0.0f;
GradientSignal::GradientSampleParams params(AZ::Vector3(x, y, 0.0f));
// Right now, when the list contains multiple entries, we will use the highest point from each gradient.
// This is needed in part because gradients don't really have world bounds, so they exist everywhere but generally have a value
// of 0 outside their data bounds if they're using bounded data. We should examine the possibility of extending the gradient API
// to provide actual bounds so that it's possible to detect if the gradient even 'exists' in an area, at which point we could just
// make this list a prioritized list from top to bottom for any points that overlap.
for (auto& gradientId : m_configuration.m_gradientEntities)
{
float sample = 0.0f;
GradientSignal::GradientRequestBus::EventResult(sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
maxSample = AZ::GetMax(maxSample, sample);
}
const float height = AZ::Lerp(m_cachedShapeBounds.GetMin().GetZ(), m_cachedShapeBounds.GetMax().GetZ(), maxSample);
return AZ::GetClamp(height, m_cachedMinWorldHeight, m_cachedMaxWorldHeight);
}
void TerrainHeightGradientListComponent::GetHeight(
const AZ::Vector3& inPosition, AZ::Vector3& outPosition, [[maybe_unused]] Sampler sampleFilter = Sampler::DEFAULT)
{
const float height = GetHeight(inPosition.GetX(), inPosition.GetY());
outPosition.SetZ(height);
}
void TerrainHeightGradientListComponent::GetNormal(
const AZ::Vector3& inPosition, AZ::Vector3& outNormal, [[maybe_unused]] Sampler sampleFilter = Sampler::DEFAULT)
{
const float x = inPosition.GetX();
const float y = inPosition.GetY();
if ((x >= m_cachedShapeBounds.GetMin().GetX()) && (x <= m_cachedShapeBounds.GetMax().GetX()) &&
(y >= m_cachedShapeBounds.GetMin().GetY()) && (y <= m_cachedShapeBounds.GetMax().GetY()))
{
AZ::Vector2 fRange = (m_cachedHeightQueryResolution / 2.0f) + AZ::Vector2(0.05f);
AZ::Vector3 v1(x - fRange.GetX(), y - fRange.GetY(), GetHeight(x - fRange.GetX(), y - fRange.GetY()));
AZ::Vector3 v2(x - fRange.GetX(), y + fRange.GetY(), GetHeight(x - fRange.GetX(), y + fRange.GetY()));
AZ::Vector3 v3(x + fRange.GetX(), y - fRange.GetY(), GetHeight(x + fRange.GetX(), y - fRange.GetY()));
AZ::Vector3 v4(x + fRange.GetX(), y + fRange.GetY(), GetHeight(x + fRange.GetX(), y + fRange.GetY()));
outNormal = (v3 - v2).Cross(v4 - v1).GetNormalized();
}
}
void TerrainHeightGradientListComponent::OnCompositionChanged()
{
RefreshMinMaxHeights();
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId());
}
void TerrainHeightGradientListComponent::RefreshMinMaxHeights()
{
// Get the height range of our height provider based on the shape component.
LmbrCentral::ShapeComponentRequestsBus::EventResult(m_cachedShapeBounds, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
// Get the height range of the entire world
m_cachedHeightQueryResolution = AZ::Vector2(1.0f);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
m_cachedHeightQueryResolution, &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainGridResolution);
AZ::Aabb worldBounds = AZ::Aabb::CreateNull();
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
worldBounds, &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainAabb);
// Save off the min/max heights so that we don't have to re-query them on every single height query.
m_cachedMinWorldHeight = worldBounds.GetMin().GetZ();
m_cachedMaxWorldHeight = worldBounds.GetMax().GetZ();
}
void TerrainHeightGradientListComponent::OnTerrainDataChanged(
[[maybe_unused]] const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask)
{
if (dataChangedMask & TerrainDataChangedMask::Settings)
{
// If the terrain system settings changed, it's possible that the world bounds have changed, which can affect our height data.
// Refresh the min/max heights and notify that the height data for this area needs to be refreshed.
OnCompositionChanged();
}
}
}

@ -0,0 +1,101 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Jobs/JobManagerBus.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Aabb.h>
#include <LmbrCentral/Dependency/DependencyMonitor.h>
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
#include <LmbrCentral/Shape/ShapeComponentBus.h>
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
#include <TerrainSystem/TerrainSystemBus.h>
namespace LmbrCentral
{
template<typename, typename>
class EditorWrappedComponentBase;
}
namespace Terrain
{
class TerrainHeightGradientListConfig
: public AZ::ComponentConfig
{
public:
AZ_CLASS_ALLOCATOR(TerrainHeightGradientListConfig, AZ::SystemAllocator, 0);
AZ_RTTI(TerrainHeightGradientListConfig, "{C5FD71A9-0722-4D4C-B605-EBEBF90C628F}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
AZStd::vector<AZ::EntityId> m_gradientEntities;
};
class TerrainHeightGradientListComponent
: public AZ::Component
, private Terrain::TerrainAreaHeightRequestBus::Handler
, private LmbrCentral::DependencyNotificationBus::Handler
, private AzFramework::Terrain::TerrainDataNotificationBus::Handler
{
public:
template<typename, typename>
friend class LmbrCentral::EditorWrappedComponentBase;
AZ_COMPONENT(TerrainHeightGradientListComponent, "{1BB3BA6C-6D4A-4636-B542-F23ECBA8F2AB}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void Reflect(AZ::ReflectContext* context);
TerrainHeightGradientListComponent(const TerrainHeightGradientListConfig& configuration);
TerrainHeightGradientListComponent() = default;
~TerrainHeightGradientListComponent() = default;
void GetHeight(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, Sampler sampleFilter) override;
void GetNormal(const AZ::Vector3& inPosition, AZ::Vector3& outNormal, Sampler sampleFilter) override;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// LmbrCentral::DependencyNotificationBus
void OnCompositionChanged() override;
//////////////////////////////////////////////////////////////////////////
// AzFramework::Terrain::TerrainDataNotificationBus
void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override;
private:
TerrainHeightGradientListConfig m_configuration;
///////////////////////////////////////////
void GetNormalSynchronous(float x, float y, AZ::Vector3& normal);
void RefreshMinMaxHeights();
float GetHeight(float x, float y);
float m_cachedMinWorldHeight{ 0.0f };
float m_cachedMaxWorldHeight{ 0.0f };
AZ::Vector2 m_cachedHeightQueryResolution{ 1.0f, 1.0f };
AZ::Aabb m_cachedShapeBounds;
LmbrCentral::DependencyMonitor m_dependencyMonitor;
};
}

@ -0,0 +1,160 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Components/TerrainLayerSpawnerComponent.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <GradientSignal/Ebuses/GradientRequestBus.h>
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
#include <TerrainSystem/TerrainSystemBus.h>
namespace Terrain
{
void TerrainLayerSpawnerConfig::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainLayerSpawnerConfig, AZ::ComponentConfig>()
->Version(1)
->Field("Layer", &TerrainLayerSpawnerConfig::m_layer)
->Field("Priority", &TerrainLayerSpawnerConfig::m_priority)
->Field("UseGroundPlane", &TerrainLayerSpawnerConfig::m_useGroundPlane)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<TerrainLayerSpawnerConfig>(
"Terrain Layer Spawner Component", "Provide terrain data for a region of the world")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &TerrainLayerSpawnerConfig::m_layer, "Layer Priority", "Defines a high level order that terrain spawners are applied")
->Attribute(AZ::Edit::Attributes::EnumValues, &TerrainLayerSpawnerConfig::GetSelectableLayers)
->DataElement(AZ::Edit::UIHandlers::Slider, &TerrainLayerSpawnerConfig::m_priority, "Sub Priority", "Defines order terrain spawners are applied within a layer. Larger numbers = higher priority")
->Attribute(AZ::Edit::Attributes::Min, AreaConstants::s_priorityMin)
->Attribute(AZ::Edit::Attributes::Max, AreaConstants::s_priorityMax)
->Attribute(AZ::Edit::Attributes::SoftMin, AreaConstants::s_priorityMin)
->Attribute(AZ::Edit::Attributes::SoftMax, AreaConstants::s_prioritySoftMax)
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainLayerSpawnerConfig::m_useGroundPlane, "Use Ground Plane", "Determines whether or not to provide a default ground plane")
;
}
}
}
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> TerrainLayerSpawnerConfig::GetSelectableLayers() const
{
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> selectableLayers;
selectableLayers.push_back({ AreaConstants::s_backgroundLayer, AZStd::string("Background") });
selectableLayers.push_back({ AreaConstants::s_foregroundLayer, AZStd::string("Foreground") });
return selectableLayers;
}
void TerrainLayerSpawnerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("TerrainAreaService"));
}
void TerrainLayerSpawnerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("TerrainAreaService"));
}
void TerrainLayerSpawnerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("BoxShapeService"));
}
void TerrainLayerSpawnerComponent::Reflect(AZ::ReflectContext* context)
{
TerrainLayerSpawnerConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainLayerSpawnerComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &TerrainLayerSpawnerComponent::m_configuration)
;
}
}
TerrainLayerSpawnerComponent::TerrainLayerSpawnerComponent(const TerrainLayerSpawnerConfig& configuration)
: m_configuration(configuration)
{
}
void TerrainLayerSpawnerComponent::Activate()
{
AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId());
TerrainAreaRequestBus::Handler::BusConnect(GetEntityId());
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RegisterArea, GetEntityId());
}
void TerrainLayerSpawnerComponent::Deactivate()
{
TerrainAreaRequestBus::Handler::BusDisconnect();
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::UnregisterArea, GetEntityId());
AZ::TransformNotificationBus::Handler::BusDisconnect();
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect();
}
bool TerrainLayerSpawnerComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const TerrainLayerSpawnerConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool TerrainLayerSpawnerComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TerrainLayerSpawnerConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
void TerrainLayerSpawnerComponent::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, [[maybe_unused]] const AZ::Transform& world)
{
RefreshArea();
}
void TerrainLayerSpawnerComponent::OnShapeChanged([[maybe_unused]] ShapeChangeReasons changeReason)
{
RefreshArea();
}
void TerrainLayerSpawnerComponent::RegisterArea()
{
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RegisterArea, GetEntityId());
}
void TerrainLayerSpawnerComponent::RefreshArea()
{
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId());
}
}

@ -0,0 +1,97 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Jobs/JobManagerBus.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
#include <TerrainSystem/TerrainSystemBus.h>
#include <AzCore/Component/TransformBus.h>
#include <LmbrCentral/Shape/ShapeComponentBus.h>
#include <AzCore/Math/Aabb.h>
namespace LmbrCentral
{
template<typename, typename>
class EditorWrappedComponentBase;
}
namespace Terrain
{
namespace AreaConstants
{
static const AZ::u32 s_backgroundLayer = 0;
static const AZ::u32 s_foregroundLayer = 1;
static const AZ::u32 s_priorityMin = 0;
static const AZ::u32 s_priorityMax = 10000; //arbitrary number because std::numeric_limits<AZ::u32>::max() always dislays -1 in RPE
static const AZ::u32 s_prioritySoftMax = 100; //design specified slider range
}
class TerrainLayerSpawnerConfig
: public AZ::ComponentConfig
{
public:
AZ_CLASS_ALLOCATOR(TerrainLayerSpawnerConfig, AZ::SystemAllocator, 0);
AZ_RTTI(TerrainLayerSpawnerConfig, "{8E0695DE-E843-4858-BAEA-70953E74C810}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> GetSelectableLayers() const;
AZ::u32 m_layer = AreaConstants::s_foregroundLayer;
AZ::u32 m_priority = AreaConstants::s_priorityMin;
bool m_useGroundPlane = true;
};
class TerrainLayerSpawnerComponent
: public AZ::Component
, private AZ::TransformNotificationBus::Handler
, private LmbrCentral::ShapeComponentNotificationsBus::Handler
, private Terrain::TerrainAreaRequestBus::Handler
{
public:
template<typename, typename>
friend class LmbrCentral::EditorWrappedComponentBase;
AZ_COMPONENT(TerrainLayerSpawnerComponent, "{3848605F-A4EA-478C-B710-84AB8DCA9EC5}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void Reflect(AZ::ReflectContext* context);
TerrainLayerSpawnerComponent(const TerrainLayerSpawnerConfig& configuration);
TerrainLayerSpawnerComponent() = default;
~TerrainLayerSpawnerComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// AZ::TransformNotificationBus::Handler
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
// ShapeComponentNotificationsBus
void OnShapeChanged(ShapeChangeReasons changeReason) override;
void RegisterArea() override;
void RefreshArea() override;
private:
TerrainLayerSpawnerConfig m_configuration;
};
}

@ -14,6 +14,8 @@
#include <AzCore/Serialization/EditContextConstants.inl>
#include <Atom/RPI.Public/FeatureProcessorFactory.h>
#include <TerrainRenderer/TerrainFeatureProcessor.h>
#include <TerrainSystem/TerrainSystem.h>
namespace Terrain
{
@ -32,6 +34,8 @@ namespace Terrain
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
Terrain::TerrainFeatureProcessor::Reflect(context);
}
}
@ -60,9 +64,18 @@ namespace Terrain
void TerrainSystemComponent::Activate()
{
// Currently, the Terrain System Component owns the Terrain System instance because the Terrain World component gets recreated
// every time an entity is added or removed to a level. If this ever changes, the Terrain System ownership could move into
// the level component.
m_terrainSystem = new TerrainSystem();
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<Terrain::TerrainFeatureProcessor>();
}
void TerrainSystemComponent::Deactivate()
{
delete m_terrainSystem;
m_terrainSystem = nullptr;
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<Terrain::TerrainFeatureProcessor>();
}
}

@ -0,0 +1,123 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Components/TerrainWorldComponent.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace Terrain
{
void TerrainWorldConfig::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainWorldConfig, AZ::ComponentConfig>()
->Version(1)
->Field("WorldMin", &TerrainWorldConfig::m_worldMin)
->Field("WorldMax", &TerrainWorldConfig::m_worldMax)
->Field("HeightQueryResolution", &TerrainWorldConfig::m_heightQueryResolution)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<TerrainWorldConfig>(
"Terrain World Component", "Data required for the terrain system to run")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMin, "World Bounds (Min)", "")
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMax, "World Bounds (Max)", "")
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "")
;
}
}
}
void TerrainWorldComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainService"));
}
void TerrainWorldComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainService"));
}
void TerrainWorldComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& services)
{
}
void TerrainWorldComponent::Reflect(AZ::ReflectContext* context)
{
TerrainWorldConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainWorldComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &TerrainWorldComponent::m_configuration)
;
}
}
TerrainWorldComponent::TerrainWorldComponent(const TerrainWorldConfig& configuration)
: m_configuration(configuration)
{
}
TerrainWorldComponent::~TerrainWorldComponent()
{
}
void TerrainWorldComponent::Activate()
{
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::SetWorldMin, m_configuration.m_worldMin);
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::SetWorldMax, m_configuration.m_worldMax);
TerrainSystemServiceRequestBus::Broadcast(
&TerrainSystemServiceRequestBus::Events::SetHeightQueryResolution, m_configuration.m_heightQueryResolution);
// Currently, the Terrain System Component owns the Terrain System instance because the Terrain World component gets recreated
// every time an entity is added or removed to a level. If this ever changes, the Terrain System ownership could move into
// the level component.
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::Activate);
}
void TerrainWorldComponent::Deactivate()
{
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::Deactivate);
}
bool TerrainWorldComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const TerrainWorldConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool TerrainWorldComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TerrainWorldConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
}

@ -0,0 +1,64 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Vector3.h>
#include <TerrainSystem/TerrainSystem.h>
namespace LmbrCentral
{
template<typename, typename>
class EditorWrappedComponentBase;
}
namespace Terrain
{
class TerrainWorldConfig
: public AZ::ComponentConfig
{
public:
AZ_CLASS_ALLOCATOR(TerrainWorldConfig, AZ::SystemAllocator, 0);
AZ_RTTI(TerrainWorldConfig, "{295844DB-20DD-45B2-94DB-4245D5AE9AFF}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
AZ::Vector3 m_worldMin{ 0.0f, 0.0f, 0.0f };
AZ::Vector3 m_worldMax{ 1024.0f, 1024.0f, 1024.0f };
AZ::Vector2 m_heightQueryResolution{ 1.0f, 1.0f };
};
class TerrainWorldComponent
: public AZ::Component
{
public:
template<typename, typename>
friend class LmbrCentral::EditorWrappedComponentBase;
AZ_COMPONENT(TerrainWorldComponent, "{4734EFDC-135D-4BF5-BE57-4F9AD03ADF78}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void Reflect(AZ::ReflectContext* context);
TerrainWorldComponent(const TerrainWorldConfig& configuration);
TerrainWorldComponent() = default;
~TerrainWorldComponent() override;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
private:
TerrainWorldConfig m_configuration;
};
}

@ -0,0 +1,322 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Components/TerrainWorldDebuggerComponent.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
namespace Terrain
{
void TerrainWorldDebuggerConfig::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainWorldDebuggerConfig, AZ::ComponentConfig>()
->Version(1)
->Field("DebugWireframe", &TerrainWorldDebuggerConfig::m_drawWireframe)
->Field("DebugWorldBounds", &TerrainWorldDebuggerConfig::m_drawWorldBounds)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<TerrainWorldDebuggerConfig>(
"Terrain World Debugger Component", "Optional component for enabling terrain debugging features.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldDebuggerConfig::m_drawWireframe, "Show Wireframe", "")
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldDebuggerConfig::m_drawWorldBounds, "Show World Bounds", "");
}
}
}
void TerrainWorldDebuggerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainDebugService"));
}
void TerrainWorldDebuggerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainDebugService"));
}
void TerrainWorldDebuggerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainService"));
}
void TerrainWorldDebuggerComponent::Reflect(AZ::ReflectContext* context)
{
TerrainWorldDebuggerConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainWorldDebuggerComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &TerrainWorldDebuggerComponent::m_configuration)
;
}
}
TerrainWorldDebuggerComponent::TerrainWorldDebuggerComponent(const TerrainWorldDebuggerConfig& configuration)
: m_configuration(configuration)
{
}
TerrainWorldDebuggerComponent::~TerrainWorldDebuggerComponent()
{
}
void TerrainWorldDebuggerComponent::Activate()
{
m_wireframeBounds = AZ::Aabb::CreateNull();
TerrainSystemServiceRequestBus::Broadcast(
&TerrainSystemServiceRequestBus::Events::SetDebugWireframe, m_configuration.m_drawWireframe);
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId());
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
}
void TerrainWorldDebuggerComponent::Deactivate()
{
TerrainSystemServiceRequestBus::Broadcast(
&TerrainSystemServiceRequestBus::Events::SetDebugWireframe, false);
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
m_wireframeBounds = AZ::Aabb::CreateNull();
m_wireframeSectors.clear();
}
bool TerrainWorldDebuggerComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const TerrainWorldDebuggerConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool TerrainWorldDebuggerComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TerrainWorldDebuggerConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
AZ::Aabb TerrainWorldDebuggerComponent::GetWorldBounds()
{
AZ::Aabb terrainAabb = AZ::Aabb::CreateFromPoint(AZ::Vector3::CreateZero());
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
terrainAabb, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb);
return terrainAabb;
}
AZ::Aabb TerrainWorldDebuggerComponent::GetLocalBounds()
{
// This is a level component, so the local bounds will always be the same as the world bounds.
return GetWorldBounds();
}
void TerrainWorldDebuggerComponent::DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
{
// Draw a wireframe box around the entire terrain world bounds
if (m_configuration.m_drawWorldBounds)
{
AZ::Color outlineColor(1.0f, 0.0f, 0.0f, 1.0f);
AZ::Aabb aabb = GetWorldBounds();
debugDisplay.SetColor(outlineColor);
debugDisplay.DrawWireBox(aabb.GetMin(), aabb.GetMax());
}
// Draw a wireframe representation of the terrain surface
if (m_configuration.m_drawWireframe && !m_wireframeSectors.empty())
{
// Start by assuming we'll draw the entire world.
AZ::Aabb drawingAabb = GetWorldBounds();
// Assuming we can get the camera, reduce the drawing bounds to a fixed distance around the camera.
if (auto viewportContextRequests = AZ::RPI::ViewportContextRequests::Get(); viewportContextRequests)
{
// Get the current camera position.
AZ::RPI::ViewportContextPtr viewportContext = viewportContextRequests->GetViewportContextById(viewportInfo.m_viewportId);
AZ::Vector3 cameraPos = viewportContext->GetCameraTransform().GetTranslation();
// Determine how far to draw in each direction in world space based on our MaxSectorsToDraw
AZ::Vector2 queryResolution = AZ::Vector2(1.0f);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainGridResolution);
AZ::Vector3 viewDistance(
queryResolution.GetX() * SectorSizeInGridPoints * sqrtf(MaxSectorsToDraw),
queryResolution.GetY() * SectorSizeInGridPoints * sqrtf(MaxSectorsToDraw),
0.0f);
// Create an AABB around the camera based on how far we want to be able to draw in each direction and clamp the
// drawing AABB to it.
AZ::Aabb cameraAabb = AZ::Aabb::CreateFromMinMax(
AZ::Vector3(
cameraPos.GetX() - viewDistance.GetX(), cameraPos.GetY() - viewDistance.GetY(), drawingAabb.GetMin().GetZ()),
AZ::Vector3(
cameraPos.GetX() + viewDistance.GetX(), cameraPos.GetY() + viewDistance.GetY(), drawingAabb.GetMin().GetZ()));
drawingAabb.Clamp(cameraAabb);
}
// For each sector, if it appears within our view distance, draw it.
for (auto& sector : m_wireframeSectors)
{
if (drawingAabb.Overlaps(sector.m_aabb))
{
if (!sector.m_lineVertices.empty())
{
const AZ::Color primaryColor = AZ::Color(0.25f, 0.25f, 0.25f, 1.0f);
debugDisplay.DrawLines(sector.m_lineVertices, primaryColor);
}
else
{
AZ_Warning("Debug", false, "empty sector!");
}
}
}
}
}
void TerrainWorldDebuggerComponent::RefreshCachedWireframeGrid(const AZ::Aabb& dirtyRegion)
{
// Get the terrain world bounds and grid resolution.
AZ::Aabb worldBounds = GetWorldBounds();
AZ::Vector2 queryResolution = AZ::Vector2(1.0f);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainGridResolution);
// Calculate the world size of each sector. Note that this size actually ends at the last point, not the last square.
// So for example, the sector size for 3 points will go from (*--*--*) even though it will be used to draw (*--*--*--).
const float xSectorSize = (queryResolution.GetX() * SectorSizeInGridPoints);
const float ySectorSize = (queryResolution.GetY() * SectorSizeInGridPoints);
// Calculate the total number of sectors to cache. The world bounds might not be evenly divisible by sector bounds, so we add
// an extra sector's worth of size in each direction so that clamping down to an integer still accounts for that fractional sector.
const int32_t numSectorsX = aznumeric_cast<int32_t>((worldBounds.GetXExtent() + xSectorSize) / xSectorSize);
const int32_t numSectorsY = aznumeric_cast<int32_t>((worldBounds.GetYExtent() + ySectorSize) / ySectorSize);
// If we haven't cached anything before, or if the world bounds has changed, clear our cache structure and repopulate it
// with WireframeSector entries with the proper AABB sizes.
if (!m_wireframeBounds.IsValid() || !dirtyRegion.IsValid() || !m_wireframeBounds.IsClose(worldBounds))
{
m_wireframeBounds = worldBounds;
m_wireframeSectors.clear();
m_wireframeSectors.reserve(numSectorsX * numSectorsY);
for (int32_t ySector = 0; ySector < numSectorsY; ySector++)
{
for (int32_t xSector = 0; xSector < numSectorsX; xSector++)
{
// For each sector, set up the AABB for the sector and reserve memory for the line vertices.
WireframeSector sector;
sector.m_lineVertices.reserve(VerticesPerSector);
sector.m_aabb = AZ::Aabb::CreateFromMinMax(
AZ::Vector3(
worldBounds.GetMin().GetX() + (xSector * xSectorSize), worldBounds.GetMin().GetY() + (ySector * ySectorSize),
worldBounds.GetMin().GetZ()),
AZ::Vector3(
worldBounds.GetMin().GetX() + ((xSector + 1) * xSectorSize),
worldBounds.GetMin().GetY() + ((ySector + 1) * ySectorSize), worldBounds.GetMax().GetZ()));
sector.m_aabb.Clamp(worldBounds);
m_wireframeSectors.push_back(AZStd::move(sector));
}
}
// Notify the visibility system that our bounds have changed.
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
&AzFramework::IEntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId());
}
// For each sector, if it overlaps with the dirty region, clear it out and recache the wireframe line data.
for (auto& sector : m_wireframeSectors)
{
if (dirtyRegion.IsValid() && !dirtyRegion.Overlaps(sector.m_aabb))
{
continue;
}
sector.m_lineVertices.clear();
for (float y = sector.m_aabb.GetMin().GetY(); y < sector.m_aabb.GetMax().GetY(); y += queryResolution.GetY())
{
for (float x = sector.m_aabb.GetMin().GetX(); x < sector.m_aabb.GetMax().GetX(); x += queryResolution.GetX())
{
float x1 = x + queryResolution.GetX();
float y1 = y + queryResolution.GetY();
float z00 = 0.0f;
float z01 = 0.0f;
float z10 = 0.0f;
bool terrainExists;
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
z00, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x, y,
AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, &terrainExists);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
z01, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x, y1,
AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, &terrainExists);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
z10, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x1, y,
AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, &terrainExists);
sector.m_lineVertices.push_back(AZ::Vector3(x, y, z00));
sector.m_lineVertices.push_back(AZ::Vector3(x1, y, z10));
sector.m_lineVertices.push_back(AZ::Vector3(x, y, z00));
sector.m_lineVertices.push_back(AZ::Vector3(x, y1, z01));
}
}
}
}
void TerrainWorldDebuggerComponent::OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask)
{
if (dataChangedMask & (TerrainDataChangedMask::Settings | TerrainDataChangedMask::HeightData))
{
RefreshCachedWireframeGrid(dirtyRegion);
}
}
} // namespace Terrain

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save