Add support for using interfaces in Visual Scripting
This commit is contained in:
@@ -338,6 +338,9 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public bool IsClass => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsInterface => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsArray => false;
|
||||
|
||||
@@ -371,6 +374,12 @@ namespace FlaxEditor.Content
|
||||
return Object.New(TypeName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ImplementInterface(ScriptType c)
|
||||
{
|
||||
return BaseType.ImplementInterface(c);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAttribute(Type attributeType, bool inherit)
|
||||
{
|
||||
|
||||
@@ -79,6 +79,18 @@ namespace FlaxEditor.Content
|
||||
return ScriptType.Null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GetTypes(List<ScriptType> result, Func<ScriptType, bool> checkFunc)
|
||||
{
|
||||
var visualScripts = VisualScriptItem.VisualScripts;
|
||||
for (var i = 0; i < visualScripts.Count; i++)
|
||||
{
|
||||
var t = visualScripts[i].ScriptType;
|
||||
if (checkFunc(t))
|
||||
result.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GetDerivedTypes(ScriptType baseType, List<ScriptType> result, Func<ScriptType, bool> checkFunc)
|
||||
{
|
||||
|
||||
@@ -76,9 +76,14 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
/// <summary>
|
||||
/// The all types collection from all assemblies (excluding C# system libraries). Includes only primitive and basic types from std lib.
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// The all valid types collection for the Visual Script property types (includes basic types like int/float, structures, object references).
|
||||
|
||||
@@ -775,6 +775,11 @@ namespace FlaxEditor.Scripting
|
||||
/// </summary>
|
||||
public bool IsClass => _managed != null ? _managed.IsClass : _custom != null && _custom.IsClass;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is an interface.
|
||||
/// </summary>
|
||||
public bool IsInterface => _managed != null ? _managed.IsInterface : _custom != null && _custom.IsInterface;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is an array.
|
||||
/// </summary>
|
||||
@@ -995,6 +1000,20 @@ namespace FlaxEditor.Scripting
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the current type implements the specified interface type. Checks this type, its base classes and implemented interfaces base interfaces too.
|
||||
/// </summary>
|
||||
/// <param name="c">The type of the interface to check.</param>
|
||||
/// <returns>True if this type implements the given interface, otherwise false.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is an instance of the current type.
|
||||
/// </summary>
|
||||
@@ -1014,6 +1033,8 @@ namespace FlaxEditor.Scripting
|
||||
/// <c>false</c> if none of these conditions are true, or if <paramref name="c" /> is <see cref="Null"/>.</returns>
|
||||
public bool IsAssignableFrom(ScriptType c)
|
||||
{
|
||||
if (IsInterface)
|
||||
return c.ImplementInterface(this);
|
||||
while (c != Null)
|
||||
{
|
||||
if (c == this)
|
||||
@@ -1377,6 +1398,11 @@ namespace FlaxEditor.Scripting
|
||||
/// </summary>
|
||||
bool IsClass { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is an interface.
|
||||
/// </summary>
|
||||
bool IsInterface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is an array.
|
||||
/// </summary>
|
||||
@@ -1428,6 +1454,13 @@ namespace FlaxEditor.Scripting
|
||||
/// <returns>The created instance of the object.</returns>
|
||||
object CreateInstance();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the current type implements the specified interface type. Checks this type, its base classes and implemented interfaces base interfaces too.
|
||||
/// </summary>
|
||||
/// <param name="c">The type of the interface to check.</param>
|
||||
/// <returns>True if this type implements the given interface, otherwise false.</returns>
|
||||
bool ImplementInterface(ScriptType c);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified attribute was defined for this type.
|
||||
/// </summary>
|
||||
@@ -1613,6 +1646,13 @@ namespace FlaxEditor.Scripting
|
||||
/// <returns>The type or null if failed.</returns>
|
||||
ScriptType GetType(string typeName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the types within all the loaded assemblies.
|
||||
/// </summary>
|
||||
/// <param name="result">The result collection. Elements will be added to it. Clear it before usage.</param>
|
||||
/// <param name="checkFunc">Additional callback used to check if the given type is valid. Returns true if add type, otherwise false.</param>
|
||||
void GetTypes(List<ScriptType> result, Func<ScriptType, bool> checkFunc);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the derived types from the given base type (excluding that type) within all the loaded assemblies.
|
||||
/// </summary>
|
||||
|
||||
@@ -151,6 +151,44 @@ namespace FlaxEditor.Scripting
|
||||
customTypesInfo.GetDerivedTypes(baseType, result, checkFunc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the types within the given assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The target assembly to check its types.</param>
|
||||
/// <param name="result">The result collection. Elements will be added to it. Clear it before usage.</param>
|
||||
/// <param name="checkFunc">Additional callback used to check if the given type is valid. Returns true if add type, otherwise false.</param>
|
||||
public static void GetTypes(Assembly assembly, List<ScriptType> result, Func<ScriptType, bool> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the types from all the loaded assemblies.
|
||||
/// </summary>
|
||||
/// <param name="result">The result collection. Elements will be added to it. Clear it before usage.</param>
|
||||
/// <param name="checkFunc">Additional callback used to check if the given type is valid. Returns true if add type, otherwise false.</param>
|
||||
/// <param name="checkAssembly">Additional callback used to check if the given assembly is valid. Returns true if search for types in the given assembly, otherwise false.</param>
|
||||
public static void GetTypes(List<ScriptType> result, Func<ScriptType, bool> checkFunc, Func<Assembly, bool> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the types that have the given attribute defined within the given assembly.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user