Add support for Pack/Unpack Structure nodes and Enum constant in Anim Graph

This commit is contained in:
Wojtek Figat
2021-07-30 12:37:36 +02:00
parent c2de55f005
commit 563eecebda
9 changed files with 409 additions and 188 deletions

View File

@@ -8,7 +8,11 @@
#include "Engine/Engine/GameplayGlobals.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Level/Actor.h"
#include "Engine/Scripting/ManagedCLR/MType.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Utilities/StringConverter.h"
#define RAND Random::Rand()
@@ -37,6 +41,7 @@ VisjectExecutor::~VisjectExecutor()
void VisjectExecutor::OnError(Node* node, Box* box, const StringView& message)
{
Error(node, box, message);
LOG_STR(Error, message);
}
void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
@@ -99,15 +104,16 @@ void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
break;
}
case 9:
{
value = node->Values[0];
break;
}
// PI
case 10:
value = PI;
break;
// Enum
case 11:
value = node->Values[0];
break;
default:
break;
}
@@ -506,6 +512,175 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
break;
}
break;
}
// Pack Structure
case 26:
{
// Find type
const StringView typeName(node->Values[0]);
const StringAsANSI<100> typeNameAnsi(typeName.Get(), typeName.Length());
const StringAnsiView typeNameAnsiView(typeNameAnsi.Get(), typeName.Length());
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView);
if (!typeHandle)
{
const auto mclass = Scripting::FindClass(typeNameAnsiView);
if (mclass)
{
// Fallback to C#-only types
bool failed = false;
auto instance = mclass->CreateInstance();
value = instance;
auto& layoutCache = node->Values[1];
CHECK(layoutCache.Type.Type == VariantType::Blob);
MemoryReadStream stream((byte*)layoutCache.AsBlob.Data, layoutCache.AsBlob.Length);
const byte version = stream.ReadByte();
if (version == 1)
{
int32 fieldsCount;
stream.ReadInt32(&fieldsCount);
for (int32 boxId = 1; boxId < node->Boxes.Count(); boxId++)
{
box = &node->Boxes[boxId];
String fieldName;
stream.ReadString(&fieldName, 11);
VariantType fieldType;
stream.ReadVariantType(&fieldType);
if (box && box->HasConnection())
{
StringAsANSI<40> fieldNameAnsi(*fieldName, fieldName.Length());
auto field = mclass->GetField(fieldNameAnsi.Get());
if (field)
{
Variant fieldValue = eatBox(node, box->FirstConnection());
field->SetValue(instance, MUtils::VariantToManagedArgPtr(fieldValue, field->GetType(), failed));
}
}
}
}
}
else if (typeName.HasChars())
{
OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName));
}
return;
}
const ScriptingType& type = typeHandle.GetType();
// Allocate structure data and initialize it with native constructor
value.SetType(VariantType(VariantType::Structure, typeNameAnsiView));
// Setup structure fields
auto& layoutCache = node->Values[1];
CHECK(layoutCache.Type.Type == VariantType::Blob);
MemoryReadStream stream((byte*)layoutCache.AsBlob.Data, layoutCache.AsBlob.Length);
const byte version = stream.ReadByte();
if (version == 1)
{
int32 fieldsCount;
stream.ReadInt32(&fieldsCount);
for (int32 boxId = 1; boxId < node->Boxes.Count(); boxId++)
{
box = &node->Boxes[boxId];
String fieldName;
stream.ReadString(&fieldName, 11);
VariantType fieldType;
stream.ReadVariantType(&fieldType);
if (box && box->HasConnection())
{
const Variant fieldValue = eatBox(node, box->FirstConnection());
type.Struct.SetField(value.AsBlob.Data, fieldName, fieldValue);
}
}
}
break;
}
// Unpack Structure
case 36:
{
// Get value with structure data
const Variant structureValue = eatBox(node, node->GetBox(0)->FirstConnection());
if (!node->GetBox(0)->HasConnection())
return;
// Find type
const StringView typeName(node->Values[0]);
const StringAsANSI<100> typeNameAnsi(typeName.Get(), typeName.Length());
const StringAnsiView typeNameAnsiView(typeNameAnsi.Get(), typeName.Length());
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView);
if (!typeHandle)
{
const auto mclass = Scripting::FindClass(typeNameAnsiView);
if (mclass)
{
// Fallback to C#-only types
auto instance = (MonoObject*)structureValue;
CHECK(instance);
if (structureValue.Type.Type != VariantType::ManagedObject || mono_object_get_class(instance) != mclass->GetNative())
{
OnError(node, box, String::Format(TEXT("Cannot unpack value of type {0} to structure of type {1}"), String(MUtils::GetClassFullname(instance)), typeName));
return;
}
auto& layoutCache = node->Values[1];
CHECK(layoutCache.Type.Type == VariantType::Blob);
MemoryReadStream stream((byte*)layoutCache.AsBlob.Data, layoutCache.AsBlob.Length);
const byte version = stream.ReadByte();
if (version == 1)
{
int32 fieldsCount;
stream.ReadInt32(&fieldsCount);
for (int32 boxId = 1; boxId < node->Boxes.Count(); boxId++)
{
String fieldName;
stream.ReadString(&fieldName, 11);
VariantType fieldType;
stream.ReadVariantType(&fieldType);
if (box->ID == boxId)
{
StringAsANSI<40> fieldNameAnsi(*fieldName, fieldName.Length());
auto field = mclass->GetField(fieldNameAnsi.Get());
if (field)
value = MUtils::UnboxVariant(field->GetValueBoxed(instance));
break;
}
}
}
}
else if (typeName.HasChars())
{
OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName));
}
return;
}
const ScriptingType& type = typeHandle.GetType();
if (structureValue.Type.Type != VariantType::Structure || StringUtils::Compare(typeNameAnsi.Get(), structureValue.Type.TypeName) != 0)
{
OnError(node, box, String::Format(TEXT("Cannot unpack value of type {0} to structure of type {1}"), structureValue.Type, typeName));
return;
}
// Read structure field
auto& layoutCache = node->Values[1];
CHECK(layoutCache.Type.Type == VariantType::Blob);
MemoryReadStream stream((byte*)layoutCache.AsBlob.Data, layoutCache.AsBlob.Length);
const byte version = stream.ReadByte();
if (version == 1)
{
int32 fieldsCount;
stream.ReadInt32(&fieldsCount);
for (int32 boxId = 1; boxId < node->Boxes.Count(); boxId++)
{
String fieldName;
stream.ReadString(&fieldName, 11);
VariantType fieldType;
stream.ReadVariantType(&fieldType);
if (box->ID == boxId)
{
type.Struct.GetField(structureValue.AsBlob.Data, fieldName, value);
break;
}
}
}
break;
}
// Mask X, Y, Z, W
case 40: