From 44518e88d567f3e3ea590d029c5ca6392fc6cb65 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 18 Jul 2023 09:48:43 +0200 Subject: [PATCH] Fix crash when using Vector3 soft casting in Visual Scripts --- Source/Engine/Core/Types/Variant.cpp | 117 +++++++++++++++++++++++++ Source/Engine/Core/Types/Variant.h | 3 + Source/Engine/Scripting/Scripting.cpp | 18 +++- Source/Engine/Visject/VisjectGraph.cpp | 4 + Source/Engine/Visject/VisjectGraph.h | 1 + 5 files changed, 142 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 8232d415f..973e494f1 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -2796,6 +2796,122 @@ String Variant::ToString() const } } +void Variant::Inline() +{ + VariantType::Types type = VariantType::Null; + byte data[sizeof(Matrix)]; + if (Type.Type == VariantType::Structure && AsBlob.Data && AsBlob.Length <= sizeof(Matrix)) + { + for (int32 i = 2; i < VariantType::MAX; i++) + { + if (StringUtils::Compare(Type.TypeName, InBuiltTypesTypeNames[i]) == 0) + { + type = (VariantType::Types)i; + break; + } + } + if (type == VariantType::Null) + { + // Aliases + if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector2") == 0) + type = VariantType::Types::Vector2; + else if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector3") == 0) + type = VariantType::Types::Vector3; + else if (StringUtils::Compare(Type.TypeName, "FlaxEngine.Vector4") == 0) + type = VariantType::Types::Vector4; + } + if (type != VariantType::Null) + Platform::MemoryCopy(data, AsBlob.Data, AsBlob.Length); + } + if (type != VariantType::Null) + { + switch (type) + { + case VariantType::Bool: + *this = *(bool*)data; + break; + case VariantType::Int: + *this = *(int32*)data; + break; + case VariantType::Uint: + *this = *(uint32*)data; + break; + case VariantType::Int64: + *this = *(int64*)data; + break; + case VariantType::Uint64: + *this = *(uint64*)data; + break; + case VariantType::Float: + *this = *(float*)data; + break; + case VariantType::Double: + *this = *(double*)data; + break; + case VariantType::Float2: + *this = *(Float2*)data; + break; + case VariantType::Float3: + *this = *(Float3*)data; + break; + case VariantType::Float4: + *this = *(Float4*)data; + break; + case VariantType::Color: + *this = *(Color*)data; + break; + case VariantType::Guid: + *this = *(Guid*)data; + break; + case VariantType::BoundingBox: + *this = Variant(*(BoundingBox*)data); + break; + case VariantType::BoundingSphere: + *this = *(BoundingSphere*)data; + break; + case VariantType::Quaternion: + *this = *(Quaternion*)data; + break; + case VariantType::Transform: + *this = Variant(*(Transform*)data); + break; + case VariantType::Rectangle: + *this = *(Rectangle*)data; + break; + case VariantType::Ray: + *this = Variant(*(Ray*)data); + break; + case VariantType::Matrix: + *this = Variant(*(Matrix*)data); + break; + case VariantType::Int2: + *this = *(Int2*)data; + break; + case VariantType::Int3: + *this = *(Int3*)data; + break; + case VariantType::Int4: + *this = *(Int4*)data; + break; + case VariantType::Int16: + *this = *(int16*)data; + break; + case VariantType::Uint16: + *this = *(uint16*)data; + break; + case VariantType::Double2: + *this = *(Double2*)data; + break; + case VariantType::Double3: + *this = *(Double3*)data; + break; + case VariantType::Double4: + *this = *(Double4*)data; + break; + } + } +} + bool Variant::CanCast(const Variant& v, const VariantType& to) { if (v.Type == to) @@ -3682,6 +3798,7 @@ void Variant::AllocStructure() const ScriptingType& type = typeHandle.GetType(); AsBlob.Length = type.Size; AsBlob.Data = Allocator::Allocate(AsBlob.Length); + Platform::MemoryClear(AsBlob.Data, AsBlob.Length); type.Struct.Ctor(AsBlob.Data); } else if (typeName == "System.Int16" || typeName == "System.UInt16") diff --git a/Source/Engine/Core/Types/Variant.h b/Source/Engine/Core/Types/Variant.h index 7745307c3..9776c8e0b 100644 --- a/Source/Engine/Core/Types/Variant.h +++ b/Source/Engine/Core/Types/Variant.h @@ -359,6 +359,9 @@ public: void SetAsset(Asset* asset); String ToString() const; + // Inlines potential value type into in-built format (eg. Vector3 stored as Structure, or String stored as ManagedObject). + void Inline(); + FORCE_INLINE Variant Cast(const VariantType& to) const { return Cast(*this, to); diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index e2d709653..bbfa802f1 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -476,12 +476,28 @@ bool Scripting::Load() // Load FlaxEngine const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll"); - if (((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->Load(flaxEnginePath)) + auto* flaxEngineModule = (NativeBinaryModule*)GetBinaryModuleFlaxEngine(); + if (flaxEngineModule->Assembly->Load(flaxEnginePath)) { LOG(Error, "Failed to load FlaxEngine C# assembly."); return true; } + // Insert type aliases for vector types that don't exist in C++ but are just typedef (properly redirect them to actual types) + // TODO: add support for automatic typedef aliases setup for scripting module to properly lookup type from the alias typename +#if USE_LARGE_WORLDS + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double2"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double3"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Double4"]; +#else + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float2"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float3"]; + flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float4"]; +#endif + flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector2")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"]; + flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector3")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"]; + flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector4")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"]; + #if USE_EDITOR // Skip loading game modules in Editor on startup - Editor loads them later during splash screen (eg. after first compilation) static bool SkipFirstLoad = true; diff --git a/Source/Engine/Visject/VisjectGraph.cpp b/Source/Engine/Visject/VisjectGraph.cpp index 37154e09f..ca4495f67 100644 --- a/Source/Engine/Visject/VisjectGraph.cpp +++ b/Source/Engine/Visject/VisjectGraph.cpp @@ -675,6 +675,10 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value) } } } + + // For in-built structures try to convert it into internal format for better comparability with the scripting + value.Inline(); + break; } // Unpack Structure diff --git a/Source/Engine/Visject/VisjectGraph.h b/Source/Engine/Visject/VisjectGraph.h index 238823afd..0d841f3d4 100644 --- a/Source/Engine/Visject/VisjectGraph.h +++ b/Source/Engine/Visject/VisjectGraph.h @@ -246,6 +246,7 @@ public: void ProcessGroupCollections(Box* box, Node* node, Value& value); protected: + void InlineVariantStruct(Variant& v); virtual Value eatBox(Node* caller, Box* box) = 0; virtual Graph* GetCurrentGraph() const = 0;