diff --git a/Source/Editor/Content/Items/VisualScriptItem.cs b/Source/Editor/Content/Items/VisualScriptItem.cs index c1ccf5d73..32b12d232 100644 --- a/Source/Editor/Content/Items/VisualScriptItem.cs +++ b/Source/Editor/Content/Items/VisualScriptItem.cs @@ -338,6 +338,9 @@ namespace FlaxEditor.Content /// public bool IsClass => true; + /// + public bool IsInterface => false; + /// public bool IsArray => false; @@ -371,6 +374,12 @@ namespace FlaxEditor.Content return Object.New(TypeName); } + /// + public bool ImplementInterface(ScriptType c) + { + return BaseType.ImplementInterface(c); + } + /// public bool HasAttribute(Type attributeType, bool inherit) { diff --git a/Source/Editor/Content/Proxy/VisualScriptProxy.cs b/Source/Editor/Content/Proxy/VisualScriptProxy.cs index 207527da0..5f44d0880 100644 --- a/Source/Editor/Content/Proxy/VisualScriptProxy.cs +++ b/Source/Editor/Content/Proxy/VisualScriptProxy.cs @@ -79,6 +79,18 @@ namespace FlaxEditor.Content return ScriptType.Null; } + /// + public void GetTypes(List result, Func checkFunc) + { + var visualScripts = VisualScriptItem.VisualScripts; + for (var i = 0; i < visualScripts.Count; i++) + { + var t = visualScripts[i].ScriptType; + if (checkFunc(t)) + result.Add(t); + } + } + /// public void GetDerivedTypes(ScriptType baseType, List result, Func checkFunc) { diff --git a/Source/Editor/Modules/SourceCodeEditing/CachedTypesCollection.cs b/Source/Editor/Modules/SourceCodeEditing/CachedTypesCollection.cs index fe0c565e5..86a4e8d6b 100644 --- a/Source/Editor/Modules/SourceCodeEditing/CachedTypesCollection.cs +++ b/Source/Editor/Modules/SourceCodeEditing/CachedTypesCollection.cs @@ -76,9 +76,14 @@ namespace FlaxEditor.Modules.SourceCodeEditing /// protected virtual void Search() { - // Special case for attributes - if (_type.Type != null && new ScriptType(typeof(Attribute)).IsAssignableFrom(_type)) + if (_type == ScriptType.Null) { + // Special case for all types + TypeUtils.GetTypes(_list, _checkFunc, _checkAssembly); + } + else if (_type.Type != null && new ScriptType(typeof(Attribute)).IsAssignableFrom(_type)) + { + // Special case for attributes TypeUtils.GetTypesWithAttributeDefined(_type.Type, _list, _checkFunc, _checkAssembly); } else diff --git a/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs b/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs index 254006e5f..30f1a64a1 100644 --- a/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs +++ b/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs @@ -157,7 +157,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing /// /// The all types collection from all assemblies (excluding C# system libraries). Includes only primitive and basic types from std lib. /// - public readonly CachedTypesCollection All = new CachedAllTypesCollection(8096, new ScriptType(typeof(object)), type => true, HasAssemblyValidAnyTypes); + public readonly CachedTypesCollection All = new CachedAllTypesCollection(8096, ScriptType.Null, type => true, HasAssemblyValidAnyTypes); /// /// The all valid types collection for the Visual Script property types (includes basic types like int/float, structures, object references). diff --git a/Source/Editor/Scripting/ScriptType.cs b/Source/Editor/Scripting/ScriptType.cs index bfe3ca250..ada049c08 100644 --- a/Source/Editor/Scripting/ScriptType.cs +++ b/Source/Editor/Scripting/ScriptType.cs @@ -775,6 +775,11 @@ namespace FlaxEditor.Scripting /// public bool IsClass => _managed != null ? _managed.IsClass : _custom != null && _custom.IsClass; + /// + /// Gets a value indicating whether the type is an interface. + /// + public bool IsInterface => _managed != null ? _managed.IsInterface : _custom != null && _custom.IsInterface; + /// /// Gets a value indicating whether the type is an array. /// @@ -995,6 +1000,20 @@ namespace FlaxEditor.Scripting return false; } + /// + /// Determines whether the current type implements the specified interface type. Checks this type, its base classes and implemented interfaces base interfaces too. + /// + /// The type of the interface to check. + /// True if this type implements the given interface, otherwise false. + public bool ImplementInterface(ScriptType c) + { + if (c._managed != null && _managed != null) + return c._managed.IsAssignableFrom(_managed); + if (_custom != null) + return _custom.ImplementInterface(c); + return false; + } + /// /// Determines whether the specified object is an instance of the current type. /// @@ -1014,6 +1033,8 @@ namespace FlaxEditor.Scripting /// false if none of these conditions are true, or if is . public bool IsAssignableFrom(ScriptType c) { + if (IsInterface) + return c.ImplementInterface(this); while (c != Null) { if (c == this) @@ -1377,6 +1398,11 @@ namespace FlaxEditor.Scripting /// bool IsClass { get; } + /// + /// Gets a value indicating whether the type is an interface. + /// + bool IsInterface { get; } + /// /// Gets a value indicating whether the type is an array. /// @@ -1428,6 +1454,13 @@ namespace FlaxEditor.Scripting /// The created instance of the object. object CreateInstance(); + /// + /// Determines whether the current type implements the specified interface type. Checks this type, its base classes and implemented interfaces base interfaces too. + /// + /// The type of the interface to check. + /// True if this type implements the given interface, otherwise false. + bool ImplementInterface(ScriptType c); + /// /// Determines whether the specified attribute was defined for this type. /// @@ -1613,6 +1646,13 @@ namespace FlaxEditor.Scripting /// The type or null if failed. ScriptType GetType(string typeName); + /// + /// Gets all the types within all the loaded assemblies. + /// + /// The result collection. Elements will be added to it. Clear it before usage. + /// Additional callback used to check if the given type is valid. Returns true if add type, otherwise false. + void GetTypes(List result, Func checkFunc); + /// /// Gets all the derived types from the given base type (excluding that type) within all the loaded assemblies. /// diff --git a/Source/Editor/Scripting/TypeUtils.cs b/Source/Editor/Scripting/TypeUtils.cs index 5a49814dd..aaa0cc3db 100644 --- a/Source/Editor/Scripting/TypeUtils.cs +++ b/Source/Editor/Scripting/TypeUtils.cs @@ -151,6 +151,44 @@ namespace FlaxEditor.Scripting customTypesInfo.GetDerivedTypes(baseType, result, checkFunc); } + /// + /// Gets all the types within the given assembly. + /// + /// The target assembly to check its types. + /// The result collection. Elements will be added to it. Clear it before usage. + /// Additional callback used to check if the given type is valid. Returns true if add type, otherwise false. + public static void GetTypes(Assembly assembly, List result, Func checkFunc) + { + var types = assembly.GetTypes(); + for (int i = 0; i < types.Length; i++) + { + var t = new ScriptType(types[i]); + if (checkFunc(t)) + result.Add(t); + } + } + + /// + /// Gets all the types from all the loaded assemblies. + /// + /// The result collection. Elements will be added to it. Clear it before usage. + /// Additional callback used to check if the given type is valid. Returns true if add type, otherwise false. + /// Additional callback used to check if the given assembly is valid. Returns true if search for types in the given assembly, otherwise false. + public static void GetTypes(List result, Func checkFunc, Func checkAssembly) + { + // C#/C++ types + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + for (int i = 0; i < assemblies.Length; i++) + { + if (checkAssembly(assemblies[i])) + GetTypes(assemblies[i], result, checkFunc); + } + + // Custom types + foreach (var customTypesInfo in CustomTypes) + customTypesInfo.GetTypes(result, checkFunc); + } + /// /// Gets all the types that have the given attribute defined within the given assembly. /// diff --git a/Source/Editor/Surface/SurfaceStyle.cs b/Source/Editor/Surface/SurfaceStyle.cs index db25b9f09..198fd7c67 100644 --- a/Source/Editor/Surface/SurfaceStyle.cs +++ b/Source/Editor/Surface/SurfaceStyle.cs @@ -178,7 +178,7 @@ namespace FlaxEditor.Surface color = Colors.Enum; else if (type.IsValueType) color = Colors.Structures; - else if (new ScriptType(typeof(FlaxEngine.Object)).IsAssignableFrom(type)) + else if (new ScriptType(typeof(FlaxEngine.Object)).IsAssignableFrom(type) || type.IsInterface) color = Colors.Object; else if (hint == ConnectionsHint.Vector) color = Colors.Vector; diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index ef444afd9..3b9d5a620 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -1060,13 +1060,14 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp // Get instance object void* mInstance = nullptr; + const bool withInterfaces = !mMethod->IsStatic() && mMethod->GetParentClass()->IsInterface(); if (!mMethod->IsStatic()) { // Box instance into C# object MonoObject* instanceObject = MUtils::BoxVariant(instance); // Validate instance - if (!instanceObject || !mono_class_is_subclass_of(mono_object_get_class(instanceObject), mMethod->GetParentClass()->GetNative(), false)) + if (!instanceObject || !mono_class_is_subclass_of(mono_object_get_class(instanceObject), mMethod->GetParentClass()->GetNative(), withInterfaces)) { if (!instanceObject) LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) without object instance", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount); @@ -1101,7 +1102,7 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp // Invoke the method MonoObject* exception = nullptr; - MonoObject* resultObject = mMethod->Invoke(mInstance, params, &exception); + MonoObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MonoObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception); if (exception) { MException ex(exception);