Merge remote-tracking branch 'origin/master' into gi
# Conflicts: # Source/Editor/Windows/Assets/VisualScriptWindow.cs
This commit is contained in:
@@ -222,7 +222,7 @@ void VisualScriptExecutor::ProcessGroupParameters(Box* box, Node* node, Value& v
|
||||
LOG(Error, "Failed to access Visual Script parameter for {0}.", stack.Stack->Instance->ToString());
|
||||
PrintStack(LogType::Error);
|
||||
}
|
||||
if (node->Boxes[2].HasConnection())
|
||||
if (box->ID == 0 && node->Boxes[2].HasConnection())
|
||||
eatBox(node, node->Boxes[2].FirstConnection());
|
||||
break;
|
||||
}
|
||||
@@ -1154,17 +1154,19 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
|
||||
arrayValue.NodeId = node->ID;
|
||||
arrayValue.BoxId = 1;
|
||||
arrayValue.Value = tryGetValue(node->GetBox(1), Value::Null);
|
||||
if (arrayValue.Value.Type.Type != VariantType::Array)
|
||||
if (arrayValue.Value.Type.Type == VariantType::Array)
|
||||
{
|
||||
const int32 count = arrayValue.Value.AsArray().Count();
|
||||
for (; iteratorValue.Value.AsInt < count; iteratorValue.Value.AsInt++)
|
||||
{
|
||||
boxBase = node->GetBox(3);
|
||||
if (boxBase->HasConnection())
|
||||
eatBox(node, boxBase->FirstConnection());
|
||||
}
|
||||
}
|
||||
else if (arrayValue.Value.Type.Type != VariantType::Null)
|
||||
{
|
||||
OnError(node, boxBase, String::Format(TEXT("Input value {0} is not an array."), arrayValue.Value));
|
||||
return;
|
||||
}
|
||||
const int32 count = arrayValue.Value.AsArray().Count();
|
||||
for (; iteratorValue.Value.AsInt < count; iteratorValue.Value.AsInt++)
|
||||
{
|
||||
boxBase = node->GetBox(3);
|
||||
if (boxBase->HasConnection())
|
||||
eatBox(node, boxBase->FirstConnection());
|
||||
}
|
||||
boxBase = node->GetBox(6);
|
||||
if (boxBase->HasConnection())
|
||||
@@ -1190,6 +1192,88 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Dictionary For Each
|
||||
case 8:
|
||||
{
|
||||
const auto scope = ThreadStacks.Get().Stack->Scope;
|
||||
int32 iteratorIndex = 0;
|
||||
for (; iteratorIndex < scope->ReturnedValues.Count(); iteratorIndex++)
|
||||
{
|
||||
const auto& e = scope->ReturnedValues[iteratorIndex];
|
||||
if (e.NodeId == node->ID && e.BoxId == 0)
|
||||
break;
|
||||
}
|
||||
int32 dictionaryIndex = 0;
|
||||
for (; iteratorIndex < scope->ReturnedValues.Count(); dictionaryIndex++)
|
||||
{
|
||||
const auto& e = scope->ReturnedValues[dictionaryIndex];
|
||||
if (e.NodeId == node->ID && e.BoxId == 1)
|
||||
break;
|
||||
}
|
||||
switch (boxBase->ID)
|
||||
{
|
||||
// Loop
|
||||
case 0:
|
||||
{
|
||||
if (iteratorIndex == scope->ReturnedValues.Count())
|
||||
{
|
||||
if (dictionaryIndex == scope->ReturnedValues.Count())
|
||||
dictionaryIndex++;
|
||||
scope->ReturnedValues.AddOne();
|
||||
}
|
||||
if (dictionaryIndex == scope->ReturnedValues.Count())
|
||||
scope->ReturnedValues.AddOne();
|
||||
auto& iteratorValue = scope->ReturnedValues[iteratorIndex];
|
||||
iteratorValue.NodeId = node->ID;
|
||||
iteratorValue.BoxId = 0;
|
||||
auto& dictionaryValue = scope->ReturnedValues[dictionaryIndex];
|
||||
dictionaryValue.NodeId = node->ID;
|
||||
dictionaryValue.BoxId = 1;
|
||||
dictionaryValue.Value = tryGetValue(node->GetBox(4), Value::Null);
|
||||
if (dictionaryValue.Value.Type.Type == VariantType::Dictionary)
|
||||
{
|
||||
auto& dictionary = *dictionaryValue.Value.AsDictionary;
|
||||
iteratorValue.Value = dictionary.Begin().Index();
|
||||
int32 end = dictionary.End().Index();
|
||||
while (iteratorValue.Value.AsInt < end)
|
||||
{
|
||||
boxBase = node->GetBox(3);
|
||||
if (boxBase->HasConnection())
|
||||
eatBox(node, boxBase->FirstConnection());
|
||||
Dictionary<Variant, Variant>::Iterator it(dictionary, iteratorValue.Value.AsInt);
|
||||
++it;
|
||||
iteratorValue.Value.AsInt = it.Index();
|
||||
}
|
||||
}
|
||||
else if (dictionaryValue.Value.Type.Type != VariantType::Null)
|
||||
{
|
||||
OnError(node, boxBase, String::Format(TEXT("Input value {0} is not a dictionary."), dictionaryValue.Value));
|
||||
return;
|
||||
}
|
||||
boxBase = node->GetBox(6);
|
||||
if (boxBase->HasConnection())
|
||||
eatBox(node, boxBase->FirstConnection());
|
||||
break;
|
||||
}
|
||||
// Key
|
||||
case 1:
|
||||
if (iteratorIndex != scope->ReturnedValues.Count() && dictionaryIndex != scope->ReturnedValues.Count())
|
||||
value = Dictionary<Variant, Variant>::Iterator(*scope->ReturnedValues[dictionaryIndex].Value.AsDictionary, scope->ReturnedValues[iteratorIndex].Value.AsInt)->Key;
|
||||
break;
|
||||
// Value
|
||||
case 2:
|
||||
if (iteratorIndex != scope->ReturnedValues.Count() && dictionaryIndex != scope->ReturnedValues.Count())
|
||||
value = Dictionary<Variant, Variant>::Iterator(*scope->ReturnedValues[dictionaryIndex].Value.AsDictionary, scope->ReturnedValues[iteratorIndex].Value.AsInt)->Value;
|
||||
break;
|
||||
// Break
|
||||
case 5:
|
||||
// Reset loop iterator
|
||||
if (iteratorIndex != scope->ReturnedValues.Count())
|
||||
scope->ReturnedValues[iteratorIndex].Value.AsInt = MAX_int32 - 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,6 +245,7 @@ public:
|
||||
Dictionary& _collection;
|
||||
int32 _index;
|
||||
|
||||
public:
|
||||
Iterator(Dictionary& collection, const int32 index)
|
||||
: _collection(collection)
|
||||
, _index(index)
|
||||
@@ -257,8 +258,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Iterator(const Iterator& i)
|
||||
: _collection(i._collection)
|
||||
, _index(i._index)
|
||||
@@ -272,6 +271,10 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
FORCE_INLINE int32 Index() const
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool IsEnd() const
|
||||
{
|
||||
|
||||
@@ -1679,7 +1679,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector2 left, Vector2 right)
|
||||
{
|
||||
return Mathf.NearEqual(left.X, left.X) && Mathf.NearEqual(left.Y, right.Y);
|
||||
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1691,7 +1691,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Vector2 left, Vector2 right)
|
||||
{
|
||||
return !Mathf.NearEqual(left.X, left.X) || !Mathf.NearEqual(left.Y, right.Y);
|
||||
return !Mathf.NearEqual(left.X, right.X) || !Mathf.NearEqual(left.Y, right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1445,7 +1445,7 @@ namespace FlaxEngine
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector4 left, Vector4 right)
|
||||
{
|
||||
return left.Equals(ref right);
|
||||
return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y) && Mathf.NearEqual(left.Z, right.Z) && Mathf.NearEqual(left.W, right.W);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace
|
||||
"FlaxEngine.Ray",// Ray
|
||||
"FlaxEngine.Matrix",// Matrix
|
||||
"System.Object[]",// Array
|
||||
"Dictionary<System.Object,System.Object>",// Dictionary
|
||||
"System.Collections.Generic.Dictionary`2[System.Object,System.Object]",// Dictionary
|
||||
"System.Object",// ManagedObject
|
||||
"System.Type",// Typename
|
||||
"FlaxEngine.Int2"// Int2
|
||||
@@ -767,6 +767,12 @@ Variant::Variant(const Array<Variant, HeapAllocation>& v)
|
||||
new(array)Array<Variant, HeapAllocation>(v);
|
||||
}
|
||||
|
||||
Variant::Variant(Dictionary<Variant, Variant>&& v)
|
||||
: Type(VariantType::Dictionary)
|
||||
{
|
||||
AsDictionary = New<Dictionary<Variant, Variant>>(MoveTemp(v));
|
||||
}
|
||||
|
||||
Variant::Variant(const Dictionary<Variant, Variant>& v)
|
||||
: Type(VariantType::Dictionary)
|
||||
{
|
||||
|
||||
@@ -228,6 +228,7 @@ public:
|
||||
explicit Variant(const Matrix& v);
|
||||
Variant(Array<Variant, HeapAllocation>&& v);
|
||||
Variant(const Array<Variant, HeapAllocation>& v);
|
||||
explicit Variant(Dictionary<Variant, Variant, HeapAllocation>&& v);
|
||||
explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v);
|
||||
explicit Variant(const Span<byte>& v);
|
||||
explicit Variant(const CommonValue& v);
|
||||
|
||||
@@ -210,7 +210,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
||||
/// <returns>The child actor or null.</returns>
|
||||
API_FUNCTION() Actor* GetChild(const MClass* type) const;
|
||||
API_FUNCTION() Actor* GetChild(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child actor of the given type.
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
||||
/// <returns>The child actors.</returns>
|
||||
API_FUNCTION() Array<Actor*> GetChildren(const MClass* type) const;
|
||||
API_FUNCTION() Array<Actor*> GetChildren(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child actors of the given type.
|
||||
@@ -273,7 +273,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type.</param>
|
||||
/// <returns>The script or null.</returns>
|
||||
API_FUNCTION() Script* GetScript(const MClass* type) const;
|
||||
API_FUNCTION() Script* GetScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the script of the given type from this actor.
|
||||
@@ -290,7 +290,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type.</param>
|
||||
/// <returns>The scripts.</returns>
|
||||
API_FUNCTION() Array<Script*> GetScripts(const MClass* type) const;
|
||||
API_FUNCTION() Array<Script*> GetScripts(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scripts of the given type from this actor.
|
||||
@@ -702,7 +702,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
||||
/// <returns>Actor instance if found, null otherwise.</returns>
|
||||
API_FUNCTION() Actor* FindActor(const MClass* type) const;
|
||||
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the actor of the given type in this actor hierarchy (checks this actor and all children hierarchy).
|
||||
@@ -719,7 +719,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
||||
/// <returns>Script instance if found, null otherwise.</returns>
|
||||
API_FUNCTION() Script* FindScript(const MClass* type) const;
|
||||
API_FUNCTION() Script* FindScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the script of the given type in this actor hierarchy (checks this actor and all children hierarchy).
|
||||
|
||||
@@ -362,7 +362,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
||||
/// <returns>Found actor or null.</returns>
|
||||
API_FUNCTION() static Actor* FindActor(const MClass* type);
|
||||
API_FUNCTION() static Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the actor of the given type in all the loaded scenes.
|
||||
@@ -379,7 +379,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type.</param>
|
||||
/// <returns>Found script or null.</returns>
|
||||
API_FUNCTION() static Script* FindScript(const MClass* type);
|
||||
API_FUNCTION() static Script* FindScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the script of the given type in all the loaded scenes.
|
||||
@@ -396,14 +396,14 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
||||
/// <returns>Found actors list.</returns>
|
||||
API_FUNCTION() static Array<Actor*> GetActors(const MClass* type);
|
||||
API_FUNCTION() static Array<Actor*> GetActors(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type);
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the scripts of the given type in all the loaded scenes.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type.</param>
|
||||
/// <returns>Found scripts list.</returns>
|
||||
API_FUNCTION() static Array<Script*> GetScripts(const MClass* type);
|
||||
API_FUNCTION() static Array<Script*> GetScripts(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find scene with given ID.
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
/// <summary>
|
||||
/// Utility interop between C++ and C# for Dictionary collection.
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API ManagedDictionary
|
||||
{
|
||||
MonoObject* Instance;
|
||||
@@ -74,17 +77,13 @@ struct FLAXENGINE_API ManagedDictionary
|
||||
return result;
|
||||
}
|
||||
|
||||
static ManagedDictionary New(MonoType* keyType, MonoType* valueType)
|
||||
static MonoReflectionType* GetClass(MonoType* keyType, MonoType* valueType)
|
||||
{
|
||||
ManagedDictionary result;
|
||||
|
||||
auto domain = mono_domain_get();
|
||||
auto scriptingClass = Scripting::GetStaticClass();
|
||||
CHECK_RETURN(scriptingClass, result);
|
||||
CHECK_RETURN(scriptingClass, nullptr);
|
||||
auto makeGenericMethod = scriptingClass->GetMethod("MakeGenericType", 2);
|
||||
CHECK_RETURN(makeGenericMethod, result);
|
||||
auto createMethod = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2);
|
||||
CHECK_RETURN(createMethod, result);
|
||||
CHECK_RETURN(makeGenericMethod, nullptr);
|
||||
|
||||
auto genericType = MUtils::GetType(StdTypesContainer::Instance()->DictionaryClass->GetNative());
|
||||
auto genericArgs = mono_array_new(domain, mono_get_object_class(), 2);
|
||||
@@ -100,9 +99,25 @@ struct FLAXENGINE_API ManagedDictionary
|
||||
{
|
||||
MException ex(exception);
|
||||
ex.Log(LogType::Error, TEXT(""));
|
||||
return result;
|
||||
return nullptr;
|
||||
}
|
||||
return (MonoReflectionType*)dictionaryType;
|
||||
}
|
||||
|
||||
static ManagedDictionary New(MonoType* keyType, MonoType* valueType)
|
||||
{
|
||||
ManagedDictionary result;
|
||||
auto dictionaryType = GetClass(keyType, valueType);
|
||||
if (!dictionaryType)
|
||||
return result;
|
||||
|
||||
auto scriptingClass = Scripting::GetStaticClass();
|
||||
CHECK_RETURN(scriptingClass, result);
|
||||
auto createMethod = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2);
|
||||
CHECK_RETURN(createMethod, result);
|
||||
|
||||
MObject* exception = nullptr;
|
||||
void* params[2];
|
||||
params[0] = dictionaryType;
|
||||
params[1] = nullptr;
|
||||
auto instance = createMethod->Invoke(nullptr, params, &exception);
|
||||
|
||||
@@ -19,11 +19,42 @@
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/ScriptingObject.h"
|
||||
#include "Engine/Scripting/StdTypesContainer.h"
|
||||
#include "Engine/Scripting/InternalCalls/ManagedDictionary.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
// Inlined mono private types to access MonoType internals
|
||||
|
||||
typedef struct _MonoGenericClass MonoGenericClass;
|
||||
typedef struct _MonoGenericContext MonoGenericContext;
|
||||
|
||||
struct _MonoGenericInst
|
||||
{
|
||||
unsigned int id;
|
||||
unsigned int type_argc : 22;
|
||||
unsigned int is_open : 1;
|
||||
MonoType* type_argv[MONO_ZERO_LEN_ARRAY];
|
||||
};
|
||||
|
||||
struct _MonoGenericContext
|
||||
{
|
||||
MonoGenericInst* class_inst;
|
||||
MonoGenericInst* method_inst;
|
||||
};
|
||||
|
||||
struct _MonoGenericClass
|
||||
{
|
||||
MonoClass* container_class;
|
||||
MonoGenericContext context;
|
||||
unsigned int is_dynamic : 1;
|
||||
unsigned int is_tb_open : 1;
|
||||
unsigned int need_sync : 1;
|
||||
MonoClass* cached_class;
|
||||
class MonoImageSet* owner;
|
||||
};
|
||||
|
||||
struct _MonoType
|
||||
{
|
||||
union
|
||||
@@ -43,6 +74,21 @@ struct _MonoType
|
||||
unsigned int pinned : 1;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// typeName in format System.Collections.Generic.Dictionary`2[KeyType,ValueType]
|
||||
void GetDictionaryKeyValueTypes(const StringAnsiView& typeName, MonoClass*& keyClass, MonoClass*& valueClass)
|
||||
{
|
||||
const int32 keyStart = typeName.Find('[');
|
||||
const int32 keyEnd = typeName.Find(',');
|
||||
const int32 valueEnd = typeName.Find(']');
|
||||
const StringAnsiView keyTypename(*typeName + keyStart + 1, keyEnd - keyStart - 1);
|
||||
const StringAnsiView valueTypename(*typeName + keyEnd + 1, valueEnd - keyEnd - 1);
|
||||
keyClass = Scripting::FindClassNative(keyTypename);
|
||||
valueClass = Scripting::FindClassNative(valueTypename);
|
||||
}
|
||||
}
|
||||
|
||||
StringView MUtils::ToString(MonoString* str)
|
||||
{
|
||||
if (str == nullptr)
|
||||
@@ -439,6 +485,30 @@ Variant MUtils::UnboxVariant(MonoObject* value)
|
||||
}
|
||||
return v;
|
||||
}
|
||||
case MONO_TYPE_GENERICINST:
|
||||
{
|
||||
if (StringUtils::Compare(mono_class_get_name(klass), "Dictionary`2") == 0 && StringUtils::Compare(mono_class_get_namespace(klass), "System.Collections.Generic") == 0)
|
||||
{
|
||||
// Dictionary
|
||||
ManagedDictionary managed(value);
|
||||
MonoArray* managedKeys = managed.GetKeys();
|
||||
auto length = managedKeys ? (int32)mono_array_length(managedKeys) : 0;
|
||||
Dictionary<Variant, Variant> native;
|
||||
native.EnsureCapacity(length);
|
||||
for (int32 i = 0; i < length; i++)
|
||||
{
|
||||
MonoObject* keyManaged = mono_array_get(managedKeys, MonoObject*, i);
|
||||
MonoObject* valueManaged = managed.GetValue(keyManaged);
|
||||
native.Add(UnboxVariant(keyManaged), UnboxVariant(valueManaged));
|
||||
}
|
||||
Variant v(MoveTemp(native));
|
||||
StringAnsi typeName;
|
||||
GetClassFullname(klass, typeName);
|
||||
v.Type.SetTypeName(typeName);
|
||||
return v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mono_class_is_subclass_of(klass, Asset::GetStaticClass()->GetNative(), false) != 0)
|
||||
@@ -473,7 +543,6 @@ Variant MUtils::UnboxVariant(MonoObject* value)
|
||||
}
|
||||
return Variant(value);
|
||||
}
|
||||
// TODO: support any dictionary unboxing
|
||||
|
||||
return Variant(value);
|
||||
}
|
||||
@@ -642,7 +711,31 @@ MonoObject* MUtils::BoxVariant(const Variant& value)
|
||||
}
|
||||
return (MonoObject*)managed;
|
||||
}
|
||||
// TODO: VariantType::Dictionary
|
||||
case VariantType::Dictionary:
|
||||
{
|
||||
// Get dictionary key and value types
|
||||
MonoClass *keyClass, *valueClass;
|
||||
GetDictionaryKeyValueTypes(value.Type.GetTypeName(), keyClass, valueClass);
|
||||
if (!keyClass || !valueClass)
|
||||
{
|
||||
LOG(Error, "Invalid type to box {0}", value.Type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate managed dictionary
|
||||
ManagedDictionary managed = ManagedDictionary::New(mono_class_get_type(keyClass), mono_class_get_type(valueClass));
|
||||
if (!managed.Instance)
|
||||
return nullptr;
|
||||
|
||||
// Add native keys and values
|
||||
const auto& dictionary = *value.AsDictionary;
|
||||
for (const auto& e : dictionary)
|
||||
{
|
||||
managed.Add(BoxVariant(e.Key), BoxVariant(e.Value));
|
||||
}
|
||||
|
||||
return managed.Instance;
|
||||
}
|
||||
case VariantType::Structure:
|
||||
{
|
||||
if (value.AsBlob.Data == nullptr)
|
||||
@@ -684,7 +777,6 @@ void MUtils::GetClassFullname(MonoObject* obj, MString& fullname)
|
||||
{
|
||||
if (obj == nullptr)
|
||||
return;
|
||||
|
||||
MonoClass* monoClass = mono_object_get_class(obj);
|
||||
GetClassFullname(monoClass, fullname);
|
||||
}
|
||||
@@ -693,11 +785,13 @@ void MUtils::GetClassFullname(MonoClass* monoClass, MString& fullname)
|
||||
{
|
||||
static MString plusStr("+");
|
||||
static MString dotStr(".");
|
||||
MonoClass* nestingClass = mono_class_get_nesting_type(monoClass);
|
||||
MonoClass* lastClass = monoClass;
|
||||
|
||||
// Name
|
||||
fullname = mono_class_get_name(monoClass);
|
||||
|
||||
// Outer class for nested types
|
||||
MonoClass* nestingClass = mono_class_get_nesting_type(monoClass);
|
||||
MonoClass* lastClass = monoClass;
|
||||
while (nestingClass)
|
||||
{
|
||||
lastClass = nestingClass;
|
||||
@@ -705,9 +799,27 @@ void MUtils::GetClassFullname(MonoClass* monoClass, MString& fullname)
|
||||
nestingClass = mono_class_get_nesting_type(nestingClass);
|
||||
}
|
||||
|
||||
// Namespace
|
||||
const char* lastClassNamespace = mono_class_get_namespace(lastClass);
|
||||
if (lastClassNamespace && *lastClassNamespace)
|
||||
fullname = lastClassNamespace + dotStr + fullname;
|
||||
|
||||
// Generic instance arguments
|
||||
const MonoType* monoType = mono_class_get_type(monoClass);
|
||||
if (monoType && monoType->type == MONO_TYPE_GENERICINST)
|
||||
{
|
||||
fullname += '[';
|
||||
MString tmp;
|
||||
for (unsigned int i = 0; i < monoType->data.generic_class->context.class_inst->type_argc; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
fullname += ',';
|
||||
MonoType* argType = monoType->data.generic_class->context.class_inst->type_argv[i];
|
||||
GetClassFullname(mono_type_get_class(argType), tmp);
|
||||
fullname += tmp;
|
||||
}
|
||||
fullname += ']';
|
||||
}
|
||||
}
|
||||
|
||||
void MUtils::GetClassFullname(MonoReflectionType* type, MString& fullname)
|
||||
@@ -715,7 +827,7 @@ void MUtils::GetClassFullname(MonoReflectionType* type, MString& fullname)
|
||||
if (!type)
|
||||
return;
|
||||
MonoType* monoType = mono_reflection_type_get_type(type);
|
||||
MonoClass* monoClass = mono_type_get_class(monoType);
|
||||
MonoClass* monoClass = mono_class_from_mono_type(monoType);
|
||||
GetClassFullname(monoClass, fullname);
|
||||
}
|
||||
|
||||
@@ -729,7 +841,7 @@ MonoClass* MUtils::GetClass(MonoReflectionType* type)
|
||||
if (!type)
|
||||
return nullptr;
|
||||
MonoType* monoType = mono_reflection_type_get_type(type);
|
||||
return mono_type_get_class(monoType);
|
||||
return mono_class_from_mono_type(monoType);
|
||||
}
|
||||
|
||||
MonoClass* MUtils::GetClass(const VariantType& value)
|
||||
@@ -805,6 +917,17 @@ MonoClass* MUtils::GetClass(const VariantType& value)
|
||||
return mono_array_class_get(mclass->GetNative(), 1);
|
||||
}
|
||||
return mono_array_class_get(mono_get_object_class(), 1);
|
||||
case VariantType::Dictionary:
|
||||
{
|
||||
MonoClass *keyClass, *valueClass;
|
||||
GetDictionaryKeyValueTypes(value.GetTypeName(), keyClass, valueClass);
|
||||
if (!keyClass || !valueClass)
|
||||
{
|
||||
LOG(Error, "Invalid type to box {0}", value.ToString());
|
||||
return nullptr;
|
||||
}
|
||||
return GetClass(ManagedDictionary::GetClass(mono_class_get_type(keyClass), mono_class_get_type(valueClass)));
|
||||
}
|
||||
case VariantType::ManagedObject:
|
||||
return mono_get_object_class();
|
||||
default: ;
|
||||
@@ -1052,6 +1175,15 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
|
||||
object = nullptr;
|
||||
return object;
|
||||
}
|
||||
case MONO_TYPE_GENERICINST:
|
||||
{
|
||||
if (value.Type.Type == VariantType::Null)
|
||||
return nullptr;
|
||||
MonoObject* object = BoxVariant(value);
|
||||
if (object && !mono_class_is_subclass_of(mono_object_get_class(object), mono_class_from_mono_type(type.GetNative()), false))
|
||||
object = nullptr;
|
||||
return object;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
#include "Engine/Core/Cache.h"
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/ManagedSerialization.h"
|
||||
@@ -458,12 +457,11 @@ void ReadStream::ReadVariant(Variant* data)
|
||||
auto& dictionary = *data->AsDictionary;
|
||||
dictionary.Clear();
|
||||
dictionary.EnsureCapacity(count);
|
||||
Variant key, value;
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
Variant key;
|
||||
ReadVariant(&key);
|
||||
ReadVariant(&value);
|
||||
dictionary.Add(key, value);
|
||||
ReadVariant(&dictionary[MoveTemp(key)]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,18 @@ void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Dictionary
|
||||
case 14:
|
||||
{
|
||||
value = Variant(Dictionary<Variant, Variant>());
|
||||
String typeName = TEXT("System.Collections.Generic.Dictionary`2[");
|
||||
typeName += (StringView)node->Values[0];
|
||||
typeName += ',';
|
||||
typeName += (StringView)node->Values[1];
|
||||
typeName += ']';
|
||||
value.Type.SetTypeName(typeName);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1257,6 +1269,8 @@ void VisjectExecutor::ProcessGroupCollections(Box* box, Node* node, Value& value
|
||||
{
|
||||
// Array
|
||||
Variant v = tryGetValue(node->GetBox(0), Value::Null);
|
||||
if (v.Type.Type == VariantType::Null)
|
||||
v = Variant(Array<Variant>());
|
||||
ENSURE(v.Type.Type == VariantType::Array, String::Format(TEXT("Input value {0} is not an array."), v));
|
||||
auto& array = v.AsArray();
|
||||
Box* b;
|
||||
@@ -1359,4 +1373,65 @@ void VisjectExecutor::ProcessGroupCollections(Box* box, Node* node, Value& value
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (node->TypeID < 200)
|
||||
{
|
||||
// Dictionary
|
||||
Variant v = tryGetValue(node->GetBox(0), Value::Null);
|
||||
if (v.Type.Type == VariantType::Null)
|
||||
v = Variant(Dictionary<Variant, Variant>());
|
||||
ENSURE(v.Type.Type == VariantType::Dictionary, String::Format(TEXT("Input value {0} is not a dictionary."), v));
|
||||
auto& dictionary = *v.AsDictionary;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Count
|
||||
case 101:
|
||||
value = dictionary.Count();
|
||||
break;
|
||||
// Contains Key
|
||||
case 102:
|
||||
{
|
||||
Variant inKey = tryGetValue(node->GetBox(1), 0, Value::Null);
|
||||
value = dictionary.ContainsKey(inKey);
|
||||
break;
|
||||
}
|
||||
// Contains Value
|
||||
case 103:
|
||||
{
|
||||
Variant inValue = tryGetValue(node->GetBox(2), 0, Value::Null);
|
||||
value = dictionary.ContainsValue(inValue);
|
||||
break;
|
||||
}
|
||||
// Clear
|
||||
case 104:
|
||||
dictionary.Clear();
|
||||
value = MoveTemp(v);
|
||||
break;
|
||||
// Remove
|
||||
case 105:
|
||||
{
|
||||
Variant inKey = tryGetValue(node->GetBox(1), 0, Value::Null);
|
||||
dictionary.Remove(inKey);
|
||||
value = MoveTemp(v);
|
||||
break;
|
||||
}
|
||||
// Set
|
||||
case 106:
|
||||
{
|
||||
Variant inKey = tryGetValue(node->GetBox(1), 0, Value::Null);
|
||||
Variant inValue = tryGetValue(node->GetBox(2), 1, Value::Null);
|
||||
dictionary[MoveTemp(inKey)] = MoveTemp(inValue);
|
||||
value = MoveTemp(v);
|
||||
break;
|
||||
}
|
||||
// Get
|
||||
case 107:
|
||||
{
|
||||
Variant key = tryGetValue(node->GetBox(1), 0, Value::Null);
|
||||
Variant* valuePtr = dictionary.TryGet(key);
|
||||
ENSURE(valuePtr, TEXT("Missing key to get."));
|
||||
value = MoveTemp(*valuePtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user