Add support for Pack/Unpack Structure nodes and Enum constant in Anim Graph
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user