Implement .NET 7 runtime support and bindings generation

This commit is contained in:
2022-11-17 19:49:39 +02:00
parent fe943ca010
commit 96dc279ebd
89 changed files with 6009 additions and 503 deletions

View File

@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Content.Import namespace FlaxEditor.Content.Import
@@ -93,6 +94,7 @@ namespace FlaxEditor.Content.Import
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct InternalOptions internal struct InternalOptions
{ {
[MarshalAs(UnmanagedType.I1)]
public AudioFormat Format; public AudioFormat Format;
public byte DisableStreaming; public byte DisableStreaming;
public byte Is3D; public byte Is3D;
@@ -144,7 +146,7 @@ namespace FlaxEditor.Content.Import
/// Audio asset import entry. /// Audio asset import entry.
/// </summary> /// </summary>
/// <seealso cref="AssetImportEntry" /> /// <seealso cref="AssetImportEntry" />
public class AudioImportEntry : AssetImportEntry public partial class AudioImportEntry : AssetImportEntry
{ {
private AudioImportSettings _settings = new AudioImportSettings(); private AudioImportSettings _settings = new AudioImportSettings();
@@ -182,8 +184,9 @@ namespace FlaxEditor.Content.Import
#region Internal Calls #region Internal Calls
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.AudioImportEntry::Internal_GetAudioImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static extern bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
#endregion #endregion
} }

View File

@@ -1,8 +1,10 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Content.Import namespace FlaxEditor.Content.Import
@@ -355,6 +357,7 @@ namespace FlaxEditor.Content.Import
private bool ShowAnimation => Type == ModelType.Animation; private bool ShowAnimation => Type == ModelType.Animation;
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(InternalOptionsMarshaler))]
internal struct InternalOptions internal struct InternalOptions
{ {
public ModelType Type; public ModelType Type;
@@ -410,6 +413,162 @@ namespace FlaxEditor.Content.Import
public int ObjectIndex; public int ObjectIndex;
} }
[CustomMarshaller(typeof(InternalOptions), MarshalMode.Default, typeof(InternalOptionsMarshaler))]
internal static class InternalOptionsMarshaler
{
[Unmanaged]
[StructLayout(LayoutKind.Sequential)]
internal struct InternalOptionsNative
{
public int Type;
// Geometry
public byte CalculateNormals;
public float SmoothingNormalsAngle;
public byte FlipNormals;
public float SmoothingTangentsAngle;
public byte CalculateTangents;
public byte OptimizeMeshes;
public byte MergeMeshes;
public byte ImportLODs;
public byte ImportVertexColors;
public byte ImportBlendShapes;
public int LightmapUVsSource;
//[MarshalAs(UnmanagedType.LPWStr)]
public IntPtr CollisionMeshesPrefix;
// Transform
public float Scale;
public Quaternion Rotation;
public Float3 Translation;
public byte CenterGeometry;
// Animation
public int Duration;
public float FramesRangeStart;
public float FramesRangeEnd;
public float DefaultFrameRate;
public float SamplingRate;
public byte SkipEmptyCurves;
public byte OptimizeKeyframes;
public byte EnableRootMotion;
//[MarshalAs(UnmanagedType.LPWStr)]
public IntPtr RootNodeName;
// Level Of Detail
public byte GenerateLODs;
public int BaseLOD;
public int LODCount;
public float TriangleReduction;
// Misc
public byte ImportMaterials;
public byte ImportTextures;
public byte RestoreMaterialsOnReimport;
// SDF
public byte GenerateSDF;
public float SDFResolution;
// Splitting
public byte SplitObjects;
public int ObjectIndex;
}
internal static InternalOptions ConvertToManaged(InternalOptionsNative unmanaged) => ToManaged(unmanaged);
internal static InternalOptionsNative ConvertToUnmanaged(InternalOptions managed) => ToNative(managed);
internal static InternalOptions ToManaged(InternalOptionsNative managed)
{
return new InternalOptions()
{
Type = (ModelType)managed.Type,
CalculateNormals = managed.CalculateNormals,
SmoothingNormalsAngle = managed.SmoothingNormalsAngle,
FlipNormals = managed.FlipNormals,
SmoothingTangentsAngle = managed.SmoothingTangentsAngle,
CalculateTangents = managed.CalculateTangents,
OptimizeMeshes = managed.OptimizeMeshes,
MergeMeshes = managed.MergeMeshes,
ImportLODs = managed.ImportLODs,
ImportVertexColors = managed.ImportVertexColors,
ImportBlendShapes = managed.ImportBlendShapes,
LightmapUVsSource = (ModelLightmapUVsSource)managed.LightmapUVsSource,
CollisionMeshesPrefix = ManagedString.ToManaged(managed.CollisionMeshesPrefix),
Scale = managed.Scale,
Rotation = managed.Rotation,
Translation = managed.Translation,
CenterGeometry = managed.CenterGeometry,
Duration = (AnimationDuration)managed.Duration,
FramesRangeStart = managed.FramesRangeStart,
FramesRangeEnd = managed.FramesRangeEnd,
DefaultFrameRate = managed.DefaultFrameRate,
SamplingRate = managed.SamplingRate,
SkipEmptyCurves = managed.SkipEmptyCurves,
OptimizeKeyframes = managed.OptimizeKeyframes,
EnableRootMotion = managed.EnableRootMotion,
RootNodeName = ManagedString.ToManaged(managed.RootNodeName),
GenerateLODs = managed.GenerateLODs,
BaseLOD = managed.BaseLOD,
LODCount = managed.LODCount,
TriangleReduction = managed.TriangleReduction,
ImportMaterials = managed.ImportMaterials,
ImportTextures = managed.ImportTextures,
RestoreMaterialsOnReimport = managed.RestoreMaterialsOnReimport,
GenerateSDF = managed.GenerateSDF,
SDFResolution = managed.SDFResolution,
SplitObjects = managed.SplitObjects,
ObjectIndex = managed.ObjectIndex,
};
}
internal static InternalOptionsNative ToNative(InternalOptions managed)
{
return new InternalOptionsNative()
{
Type = (int)managed.Type,
CalculateNormals = managed.CalculateNormals,
SmoothingNormalsAngle = managed.SmoothingNormalsAngle,
FlipNormals = managed.FlipNormals,
SmoothingTangentsAngle = managed.SmoothingTangentsAngle,
CalculateTangents = managed.CalculateTangents,
OptimizeMeshes = managed.OptimizeMeshes,
MergeMeshes = managed.MergeMeshes,
ImportLODs = managed.ImportLODs,
ImportVertexColors = managed.ImportVertexColors,
ImportBlendShapes = managed.ImportBlendShapes,
LightmapUVsSource = (int)managed.LightmapUVsSource,
CollisionMeshesPrefix = ManagedString.ToNative(managed.CollisionMeshesPrefix),
Scale = managed.Scale,
Rotation = managed.Rotation,
Translation = managed.Translation,
CenterGeometry = managed.CenterGeometry,
Duration = (int)managed.Duration,
FramesRangeStart = managed.FramesRangeStart,
FramesRangeEnd = managed.FramesRangeEnd,
DefaultFrameRate = managed.DefaultFrameRate,
SamplingRate = managed.SamplingRate,
SkipEmptyCurves = managed.SkipEmptyCurves,
OptimizeKeyframes = managed.OptimizeKeyframes,
EnableRootMotion = managed.EnableRootMotion,
RootNodeName = ManagedString.ToNative(managed.RootNodeName),
GenerateLODs = managed.GenerateLODs,
BaseLOD = managed.BaseLOD,
LODCount = managed.LODCount,
TriangleReduction = managed.TriangleReduction,
ImportMaterials = managed.ImportMaterials,
ImportTextures = managed.ImportTextures,
RestoreMaterialsOnReimport = managed.RestoreMaterialsOnReimport,
GenerateSDF = managed.GenerateSDF,
SDFResolution = managed.SDFResolution,
SplitObjects = managed.SplitObjects,
ObjectIndex = managed.ObjectIndex,
};
}
internal static void Free(InternalOptionsNative unmanaged)
{
}
}
internal void ToInternal(out InternalOptions options) internal void ToInternal(out InternalOptions options)
{ {
options = new InternalOptions options = new InternalOptions
@@ -511,7 +670,7 @@ namespace FlaxEditor.Content.Import
/// Model asset import entry. /// Model asset import entry.
/// </summary> /// </summary>
/// <seealso cref="AssetImportEntry" /> /// <seealso cref="AssetImportEntry" />
public class ModelImportEntry : AssetImportEntry public partial class ModelImportEntry : AssetImportEntry
{ {
private ModelImportSettings _settings = new ModelImportSettings(); private ModelImportSettings _settings = new ModelImportSettings();
@@ -548,8 +707,8 @@ namespace FlaxEditor.Content.Import
#region Internal Calls #region Internal Calls
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.ModelImportEntry::Internal_GetModelImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static extern void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result); internal static partial void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
#endregion #endregion
} }

View File

@@ -1,10 +1,12 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEngine; using FlaxEngine;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
@@ -297,6 +299,7 @@ namespace FlaxEditor.Content.Import
public List<SpriteInfo> Sprites = new List<SpriteInfo>(); public List<SpriteInfo> Sprites = new List<SpriteInfo>();
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(InternalOptionsMarshaler))]
internal struct InternalOptions internal struct InternalOptions
{ {
public TextureFormatType Type; public TextureFormatType Type;
@@ -318,6 +321,85 @@ namespace FlaxEditor.Content.Import
public string[] SpriteNames; public string[] SpriteNames;
} }
[CustomMarshaller(typeof(InternalOptions), MarshalMode.Default, typeof(InternalOptionsMarshaler))]
internal static class InternalOptionsMarshaler
{
[StructLayout(LayoutKind.Sequential)]
internal struct InternalOptionsNative
{
public byte Type;
public byte IsAtlas;
public byte NeverStream;
public byte Compress;
public byte IndependentChannels;
public byte sRGB;
public byte GenerateMipMaps;
public byte FlipY;
public byte Resize;
public byte PreserveAlphaCoverage;
public float PreserveAlphaCoverageReference;
public float Scale;
public int MaxSize;
public int TextureGroup;
public Int2 Size;
public IntPtr SpriteAreas;
public IntPtr SpriteNames;
}
internal static InternalOptions ConvertToManaged(InternalOptionsNative unmanaged) => ToManaged(unmanaged);
internal static InternalOptionsNative ConvertToUnmanaged(InternalOptions managed) => ToNative(managed);
internal static InternalOptions ToManaged(InternalOptionsNative managed)
{
return new InternalOptions()
{
Type = (TextureFormatType)managed.Type,
IsAtlas = managed.IsAtlas,
NeverStream = managed.NeverStream,
Compress = managed.Compress,
IndependentChannels = managed.IndependentChannels,
sRGB = managed.sRGB,
GenerateMipMaps = managed.GenerateMipMaps,
FlipY = managed.FlipY,
Resize = managed.Resize,
PreserveAlphaCoverage = managed.PreserveAlphaCoverage,
PreserveAlphaCoverageReference = managed.PreserveAlphaCoverageReference,
Scale = managed.Scale,
MaxSize = managed.MaxSize,
TextureGroup = managed.TextureGroup,
Size = managed.Size,
SpriteAreas = managed.SpriteAreas != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<Rectangle>((ManagedArray)GCHandle.FromIntPtr(managed.SpriteAreas).Target) : null,
SpriteNames = managed.SpriteNames != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<string>((ManagedArray)GCHandle.FromIntPtr(managed.SpriteNames).Target) : null,
};
}
internal static InternalOptionsNative ToNative(InternalOptions managed)
{
return new InternalOptionsNative()
{
Type = (byte)managed.Type,
IsAtlas = managed.IsAtlas,
NeverStream = managed.NeverStream,
Compress = managed.Compress,
IndependentChannels = managed.IndependentChannels,
sRGB = managed.sRGB,
GenerateMipMaps = managed.GenerateMipMaps,
FlipY = managed.FlipY,
Resize = managed.Resize,
PreserveAlphaCoverage = managed.PreserveAlphaCoverage,
PreserveAlphaCoverageReference = managed.PreserveAlphaCoverageReference,
Scale = managed.Scale,
MaxSize = managed.MaxSize,
TextureGroup = managed.TextureGroup,
Size = managed.Size,
SpriteAreas = managed.SpriteAreas?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas)))) : IntPtr.Zero,
SpriteNames = managed.SpriteNames?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames)))) : IntPtr.Zero,
};
}
internal static void Free(InternalOptionsNative unmanaged)
{
}
}
internal void ToInternal(out InternalOptions options) internal void ToInternal(out InternalOptions options)
{ {
options = new InternalOptions options = new InternalOptions
@@ -406,7 +488,7 @@ namespace FlaxEditor.Content.Import
/// Texture asset import entry. /// Texture asset import entry.
/// </summary> /// </summary>
/// <seealso cref="AssetImportEntry" /> /// <seealso cref="AssetImportEntry" />
public class TextureImportEntry : AssetImportEntry public partial class TextureImportEntry : AssetImportEntry
{ {
private TextureImportSettings _settings = new TextureImportSettings(); private TextureImportSettings _settings = new TextureImportSettings();
@@ -509,8 +591,9 @@ namespace FlaxEditor.Content.Import
#region Internal Calls #region Internal Calls
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.TextureImportEntry::Internal_GetTextureImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
#endregion #endregion
} }

View File

@@ -4,13 +4,15 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEditor.CustomEditors.Editors; using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.CustomEditors namespace FlaxEditor.CustomEditors
{ {
internal static class CustomEditorsUtil internal static partial class CustomEditorsUtil
{ {
internal static readonly Dictionary<Type, string> InBuildTypeNames = new Dictionary<Type, string>() internal static readonly Dictionary<Type, string> InBuildTypeNames = new Dictionary<Type, string>()
{ {
@@ -129,7 +131,8 @@ namespace FlaxEditor.CustomEditors
return new GenericEditor(); return new GenericEditor();
} }
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.CustomEditors.CustomEditorsUtil::Internal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern Type Internal_GetCustomEditor(Type targetType); [return: MarshalUsing(typeof(SystemTypeMarshaller))]
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
} }
} }

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.Content.Import; using FlaxEditor.Content.Import;
using FlaxEditor.Content.Settings; using FlaxEditor.Content.Settings;
@@ -20,6 +21,8 @@ using FlaxEngine.Assertions;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Json; using FlaxEngine.Json;
#pragma warning disable CS1591
namespace FlaxEditor namespace FlaxEditor
{ {
/// <summary> /// <summary>
@@ -59,17 +62,20 @@ namespace FlaxEditor
/// <summary> /// <summary>
/// Gets a value indicating whether this Editor is running a dev instance of the engine. /// Gets a value indicating whether this Editor is running a dev instance of the engine.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::IsDevInstance", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool IsDevInstance(); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool IsDevInstance();
/// <summary> /// <summary>
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services). /// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::IsOfficialBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool IsOfficialBuild(); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool IsOfficialBuild();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_IsPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_IsPlayMode(); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_IsPlayMode();
/// <summary> /// <summary>
/// True if the editor is running now in a play mode. Assigned by the managed editor instance. /// True if the editor is running now in a play mode. Assigned by the managed editor instance.
@@ -1206,6 +1212,7 @@ namespace FlaxEditor
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(VisualScriptLocalMarshaller))]
internal struct VisualScriptLocal internal struct VisualScriptLocal
{ {
public string Value; public string Value;
@@ -1214,7 +1221,48 @@ namespace FlaxEditor
public int BoxId; public int BoxId;
} }
[CustomMarshaller(typeof(VisualScriptLocal), MarshalMode.Default, typeof(VisualScriptLocalMarshaller))]
internal static class VisualScriptLocalMarshaller
{
[StructLayout(LayoutKind.Sequential)]
internal struct VisualScriptLocalNative
{
public IntPtr Value;
public IntPtr ValueTypeName;
public uint NodeId;
public int BoxId;
}
internal static VisualScriptLocal ConvertToManaged(VisualScriptLocalNative unmanaged) => ToManaged(unmanaged);
internal static VisualScriptLocalNative ConvertToUnmanaged(VisualScriptLocal managed) => ToNative(managed);
internal static VisualScriptLocal ToManaged(VisualScriptLocalNative managed)
{
return new VisualScriptLocal()
{
Value = ManagedString.ToManaged(managed.Value),
ValueTypeName = ManagedString.ToManaged(managed.ValueTypeName),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static VisualScriptLocalNative ToNative(VisualScriptLocal managed)
{
return new VisualScriptLocalNative()
{
Value = ManagedString.ToNative(managed.Value),
ValueTypeName = ManagedString.ToNative(managed.ValueTypeName),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static void Free(VisualScriptLocalNative unmanaged)
{
}
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(VisualScriptStackFrameMarshaller))]
internal struct VisualScriptStackFrame internal struct VisualScriptStackFrame
{ {
public VisualScript Script; public VisualScript Script;
@@ -1222,6 +1270,43 @@ namespace FlaxEditor
public int BoxId; public int BoxId;
} }
[CustomMarshaller(typeof(VisualScriptStackFrame), MarshalMode.Default, typeof(VisualScriptStackFrameMarshaller))]
internal static class VisualScriptStackFrameMarshaller
{
[StructLayout(LayoutKind.Sequential)]
internal struct VisualScriptStackFrameNative
{
public IntPtr Script;
public uint NodeId;
public int BoxId;
}
internal static VisualScriptStackFrame ConvertToManaged(VisualScriptStackFrameNative unmanaged) => ToManaged(unmanaged);
internal static VisualScriptStackFrameNative ConvertToUnmanaged(VisualScriptStackFrame managed) => ToNative(managed);
internal static VisualScriptStackFrame ToManaged(VisualScriptStackFrameNative managed)
{
return new VisualScriptStackFrame()
{
Script = VisualScriptMarshaller.ConvertToManaged(managed.Script),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static VisualScriptStackFrameNative ToNative(VisualScriptStackFrame managed)
{
return new VisualScriptStackFrameNative()
{
Script = VisualScriptMarshaller.ConvertToUnmanaged(managed.Script),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static void Free(VisualScriptStackFrameNative unmanaged)
{
}
}
internal void BuildCommand(string arg) internal void BuildCommand(string arg)
{ {
if (TryBuildCommand(arg)) if (TryBuildCommand(arg))
@@ -1419,116 +1504,133 @@ namespace FlaxEditor
Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode; Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode;
} }
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern int Internal_ReadOutputLogs(string[] outMessages, byte[] outLogTypes, long[] outLogTimes); internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref byte[] outLogTypes, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref long[] outLogTimes, int outCapacity);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_SetPlayMode(bool value); internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern string Internal_GetProjectPath(); internal static partial string Internal_GetProjectPath();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_Import", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_Import(string inputPath, string outputPath, IntPtr arg); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_Import(string inputPath, string outputPath, IntPtr arg);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportTexture", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportModel", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportAudio", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetAudioClipMetadata", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize); internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_SaveJsonAsset(string outputPath, string data, string typename); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CopyCache", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_CopyCache(ref Guid dstId, ref Guid srcId); internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_BakeLightmaps", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_BakeLightmaps(bool cancel); internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern string Internal_GetShaderAssetSourceCode(IntPtr obj); internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_GetCollisionWires(IntPtr collisionData, out Float3[] triangles, out int[] indices); internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] out int[] indices);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef); internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_SetOptions(ref InternalOptions options); internal static partial void Internal_SetOptions(ref InternalOptions options);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_DrawNavMesh", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_DrawNavMesh(); internal static partial void Internal_DrawNavMesh();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_CloseSplashScreen(); internal static partial void Internal_CloseSplashScreen();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CreateAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_CreateAsset(NewAssetType type, string outputPath); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CreateAsset(NewAssetType type, string outputPath);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern string Internal_CanImport(string extension); internal static partial string Internal_CanImport(string extension);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_CanExport(string path); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CanExport(string path);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_Export(string inputPath, string outputFolder); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_Export(string inputPath, string outputFolder);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetIsEveryAssemblyLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_GetIsEveryAssemblyLoaded(); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_GetIsEveryAssemblyLoaded();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetLastProjectOpenedEngineBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern int Internal_GetLastProjectOpenedEngineBuild(); internal static partial int Internal_GetLastProjectOpenedEngineBuild();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetIsCSGActive", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_GetIsCSGActive(); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_GetIsCSGActive();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime); internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern VisualScriptLocal[] Internal_GetVisualScriptLocals(); [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)]
internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames(); [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)]
internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame(); internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_EvaluateVisualScriptLocal", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_DeserializeSceneObject(IntPtr sceneObject, string json); internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_LoadAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_LoadAsset(ref Guid id); internal static partial void Internal_LoadAsset(ref Guid id);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanSetToRoot", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern float Internal_GetAnimationTime(IntPtr animatedModel); internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_SetAnimationTime(IntPtr animatedModel, float time); internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
#endregion #endregion
} }

View File

@@ -10,6 +10,7 @@ using FlaxEditor.GUI.Timeline.Tracks;
using FlaxEditor.Utilities; using FlaxEditor.Utilities;
using FlaxEditor.Viewport.Previews; using FlaxEditor.Viewport.Previews;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Utilities;
namespace FlaxEditor.GUI.Timeline namespace FlaxEditor.GUI.Timeline
{ {

View File

@@ -323,20 +323,25 @@ namespace CustomEditorsUtilInternal
{ {
MonoReflectionType* GetCustomEditor(MonoReflectionType* targetType) MonoReflectionType* GetCustomEditor(MonoReflectionType* targetType)
{ {
SCRIPTING_EXPORT("FlaxEditor.CustomEditors.CustomEditorsUtil::Internal_GetCustomEditor")
return CustomEditorsUtil::GetCustomEditor(targetType); return CustomEditorsUtil::GetCustomEditor(targetType);
} }
} }
namespace LayersAndTagsSettingsInternal1 namespace LayersAndTagsSettingsInternal1
{ {
MonoArray* GetCurrentTags() MonoArray* GetCurrentTags(int* tagsCount)
{ {
SCRIPTING_EXPORT("FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentTags")
*tagsCount = Level::Tags.Count();
return MUtils::ToArray(Level::Tags); return MUtils::ToArray(Level::Tags);
} }
MonoArray* GetCurrentLayers() MonoArray* GetCurrentLayers(int* layersCount)
{ {
return MUtils::ToArray(Span<String>(Level::Layers, Math::Max(1, Level::GetNonEmptyLayerNamesCount()))); SCRIPTING_EXPORT("FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentLayers")
*layersCount = Math::Max(1, Level::GetNonEmptyLayerNamesCount());
return MUtils::ToArray(Span<String>(Level::Layers, *layersCount));
} }
} }
@@ -344,6 +349,7 @@ namespace GameSettingsInternal1
{ {
void Apply() void Apply()
{ {
SCRIPTING_EXPORT("FlaxEditor.Content.Settings.GameSettings::Apply")
LOG(Info, "Apply game settings"); LOG(Info, "Apply game settings");
GameSettings::Load(); GameSettings::Load();
} }
@@ -380,6 +386,7 @@ class ManagedEditorInternal
public: public:
static bool IsDevInstance() static bool IsDevInstance()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::IsDevInstance")
#if COMPILE_WITH_DEV_ENV #if COMPILE_WITH_DEV_ENV
return true; return true;
#else #else
@@ -389,6 +396,7 @@ public:
static bool IsOfficialBuild() static bool IsOfficialBuild()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::IsOfficialBuild")
#if OFFICIAL_BUILD #if OFFICIAL_BUILD
return true; return true;
#else #else
@@ -398,18 +406,20 @@ public:
static bool IsPlayMode() static bool IsPlayMode()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_IsPlayMode")
return Editor::IsPlayMode; return Editor::IsPlayMode;
} }
static int32 ReadOutputLogs(MonoArray* outMessages, MonoArray* outLogTypes, MonoArray* outLogTimes) static int32 ReadOutputLogs(MonoArray** outMessages, MonoArray** outLogTypes, MonoArray** outLogTimes, int outArraySize)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ReadOutputLogs")
ScopeLock lock(CachedLogDataLocker); ScopeLock lock(CachedLogDataLocker);
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr) if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
return 0; return 0;
int32 count = 0; int32 count = 0;
const int32 maxCount = (int32)mono_array_length(outMessages); const int32 maxCount = outArraySize;//(int32)mono_array_length(*outMessages);
byte* ptr = CachedLogData.Get(); byte* ptr = CachedLogData.Get();
byte* end = ptr + CachedLogData.Count(); byte* end = ptr + CachedLogData.Count();
@@ -429,9 +439,9 @@ public:
auto msgObj = MUtils::ToString(StringView(msg, length)); auto msgObj = MUtils::ToString(StringView(msg, length));
mono_array_setref(outMessages, count, msgObj); mono_array_setref(*outMessages, count, msgObj);
mono_array_set(outLogTypes, byte, count, type); mono_array_set(*outLogTypes, byte, count, type);
mono_array_set(outLogTimes, int64, count, time); mono_array_set(*outLogTimes, int64, count, time);
count++; count++;
} }
@@ -445,21 +455,25 @@ public:
static void SetPlayMode(bool value) static void SetPlayMode(bool value)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetPlayMode")
Editor::IsPlayMode = value; Editor::IsPlayMode = value;
} }
static MonoString* GetProjectPath() static MonoString* GetProjectPath()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetProjectPath")
return MUtils::ToString(Editor::Project->ProjectPath); return MUtils::ToString(Editor::Project->ProjectPath);
} }
static void CloseSplashScreen() static void CloseSplashScreen()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CloseSplashScreen")
Editor::CloseSplashScreen(); Editor::CloseSplashScreen();
} }
static bool CloneAssetFile(MonoString* dstPathObj, MonoString* srcPathObj, Guid* dstId) static bool CloneAssetFile(MonoString* dstPathObj, MonoString* srcPathObj, Guid* dstId)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CloneAssetFile")
// Get normalized paths // Get normalized paths
String dstPath, srcPath; String dstPath, srcPath;
MUtils::ToString(dstPathObj, dstPath); MUtils::ToString(dstPathObj, dstPath);
@@ -489,6 +503,7 @@ public:
static bool CreateAsset(NewAssetType type, MonoString* outputPathObj) static bool CreateAsset(NewAssetType type, MonoString* outputPathObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CreateAsset")
String tag; String tag;
switch (type) switch (type)
{ {
@@ -541,6 +556,7 @@ public:
static bool CreateVisualScript(MonoString* outputPathObj, MonoString* baseTypenameObj) static bool CreateVisualScript(MonoString* outputPathObj, MonoString* baseTypenameObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CreateVisualScript")
String outputPath; String outputPath;
MUtils::ToString(outputPathObj, outputPath); MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath); FileSystem::NormalizePath(outputPath);
@@ -551,6 +567,7 @@ public:
static MonoString* CanImport(MonoString* extensionObj) static MonoString* CanImport(MonoString* extensionObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanImport")
String extension; String extension;
MUtils::ToString(extensionObj, extension); MUtils::ToString(extensionObj, extension);
if (extension.Length() > 0 && extension[0] == '.') if (extension.Length() > 0 && extension[0] == '.')
@@ -561,6 +578,7 @@ public:
static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg) static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_Import")
String inputPath, outputPath; String inputPath, outputPath;
MUtils::ToString(inputPathObj, inputPath); MUtils::ToString(inputPathObj, inputPath);
MUtils::ToString(outputPathObj, outputPath); MUtils::ToString(outputPathObj, outputPath);
@@ -572,6 +590,7 @@ public:
static bool ImportTexture(MonoString* inputPathObj, MonoString* outputPathObj, InternalTextureOptions* optionsObj) static bool ImportTexture(MonoString* inputPathObj, MonoString* outputPathObj, InternalTextureOptions* optionsObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportTexture")
ImportTexture::Options options; ImportTexture::Options options;
InternalTextureOptions::Convert(optionsObj, &options); InternalTextureOptions::Convert(optionsObj, &options);
@@ -580,6 +599,7 @@ public:
static bool ImportModel(MonoString* inputPathObj, MonoString* outputPathObj, InternalModelOptions* optionsObj) static bool ImportModel(MonoString* inputPathObj, MonoString* outputPathObj, InternalModelOptions* optionsObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportModel")
ImportModelFile::Options options; ImportModelFile::Options options;
InternalModelOptions::Convert(optionsObj, &options); InternalModelOptions::Convert(optionsObj, &options);
@@ -588,6 +608,7 @@ public:
static bool ImportAudio(MonoString* inputPathObj, MonoString* outputPathObj, InternalAudioOptions* optionsObj) static bool ImportAudio(MonoString* inputPathObj, MonoString* outputPathObj, InternalAudioOptions* optionsObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportAudio")
ImportAudio::Options options; ImportAudio::Options options;
InternalAudioOptions::Convert(optionsObj, &options); InternalAudioOptions::Convert(optionsObj, &options);
@@ -596,6 +617,7 @@ public:
static void GetAudioClipMetadata(AudioClip* clip, int32* originalSize, int32* importedSize) static void GetAudioClipMetadata(AudioClip* clip, int32* originalSize, int32* importedSize)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetAudioClipMetadata")
INTERNAL_CALL_CHECK(clip); INTERNAL_CALL_CHECK(clip);
*originalSize = clip->AudioHeader.OriginalSize; *originalSize = clip->AudioHeader.OriginalSize;
*importedSize = clip->AudioHeader.ImportedSize; *importedSize = clip->AudioHeader.ImportedSize;
@@ -603,6 +625,7 @@ public:
static bool SaveJsonAsset(MonoString* outputPathObj, MonoString* dataObj, MonoString* dataTypeNameObj) static bool SaveJsonAsset(MonoString* outputPathObj, MonoString* dataObj, MonoString* dataTypeNameObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SaveJsonAsset")
String outputPath; String outputPath;
MUtils::ToString(outputPathObj, outputPath); MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath); FileSystem::NormalizePath(outputPath);
@@ -623,6 +646,8 @@ public:
static bool GetTextureImportOptions(MonoString* pathObj, InternalTextureOptions* result) static bool GetTextureImportOptions(MonoString* pathObj, InternalTextureOptions* result)
{ {
SCRIPTING_EXPORT("FlaxEditor.Content.Import.TextureImportEntry::Internal_GetTextureImportOptions")
String path; String path;
MUtils::ToString(pathObj, path); MUtils::ToString(pathObj, path);
FileSystem::NormalizePath(path); FileSystem::NormalizePath(path);
@@ -641,6 +666,7 @@ public:
static void GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result) static void GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result)
{ {
SCRIPTING_EXPORT("FlaxEditor.Content.Import.ModelImportEntry::Internal_GetModelImportOptions")
// Initialize defaults // Initialize defaults
ImportModelFile::Options options; ImportModelFile::Options options;
if (const auto* graphicsSettings = GraphicsSettings::Get()) if (const auto* graphicsSettings = GraphicsSettings::Get())
@@ -660,6 +686,7 @@ public:
static bool GetAudioImportOptions(MonoString* pathObj, InternalAudioOptions* result) static bool GetAudioImportOptions(MonoString* pathObj, InternalAudioOptions* result)
{ {
SCRIPTING_EXPORT("FlaxEditor.Content.Import.AudioImportEntry::Internal_GetAudioImportOptions")
String path; String path;
MUtils::ToString(pathObj, path); MUtils::ToString(pathObj, path);
FileSystem::NormalizePath(path); FileSystem::NormalizePath(path);
@@ -678,6 +705,7 @@ public:
static bool CanExport(MonoString* pathObj) static bool CanExport(MonoString* pathObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanExport")
#if COMPILE_WITH_ASSETS_EXPORTER #if COMPILE_WITH_ASSETS_EXPORTER
String path; String path;
MUtils::ToString(pathObj, path); MUtils::ToString(pathObj, path);
@@ -691,6 +719,7 @@ public:
static bool Export(MonoString* inputPathObj, MonoString* outputFolderObj) static bool Export(MonoString* inputPathObj, MonoString* outputFolderObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_Export")
#if COMPILE_WITH_ASSETS_EXPORTER #if COMPILE_WITH_ASSETS_EXPORTER
String inputPath; String inputPath;
MUtils::ToString(inputPathObj, inputPath); MUtils::ToString(inputPathObj, inputPath);
@@ -708,11 +737,13 @@ public:
static void CopyCache(Guid* dstId, Guid* srcId) static void CopyCache(Guid* dstId, Guid* srcId)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CopyCache")
ShaderCacheManager::CopyCache(*dstId, *srcId); ShaderCacheManager::CopyCache(*dstId, *srcId);
} }
static void BakeLightmaps(bool cancel) static void BakeLightmaps(bool cancel)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_BakeLightmaps")
auto builder = ShadowsOfMordor::Builder::Instance(); auto builder = ShadowsOfMordor::Builder::Instance();
if (cancel) if (cancel)
builder->CancelBuild(); builder->CancelBuild();
@@ -722,6 +753,7 @@ public:
static MonoString* GetShaderAssetSourceCode(BinaryAsset* obj) static MonoString* GetShaderAssetSourceCode(BinaryAsset* obj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetShaderAssetSourceCode")
INTERNAL_CALL_CHECK_RETURN(obj, nullptr); INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
if (obj->WaitForLoaded()) if (obj->WaitForLoaded())
DebugLog::ThrowNullReference(); DebugLog::ThrowNullReference();
@@ -747,6 +779,7 @@ public:
static bool CookMeshCollision(MonoString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit) static bool CookMeshCollision(MonoString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CookMeshCollision")
#if COMPILE_WITH_PHYSICS_COOKING #if COMPILE_WITH_PHYSICS_COOKING
CollisionCooking::Argument arg; CollisionCooking::Argument arg;
String path; String path;
@@ -767,6 +800,7 @@ public:
static void GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices) static void GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetCollisionWires")
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None) if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
return; return;
@@ -792,32 +826,38 @@ public:
static void GetEditorBoxWithChildren(Actor* obj, BoundingBox* result) static void GetEditorBoxWithChildren(Actor* obj, BoundingBox* result)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetEditorBoxWithChildren")
INTERNAL_CALL_CHECK(obj); INTERNAL_CALL_CHECK(obj);
*result = obj->GetEditorBoxChildren(); *result = obj->GetEditorBoxChildren();
} }
static void SetOptions(ManagedEditor::InternalOptions* options) static void SetOptions(ManagedEditor::InternalOptions* options)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetOptions")
ManagedEditor::ManagedEditorOptions = *options; ManagedEditor::ManagedEditorOptions = *options;
} }
static void DrawNavMesh() static void DrawNavMesh()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_DrawNavMesh")
Navigation::DrawNavMesh(); Navigation::DrawNavMesh();
} }
static bool GetIsEveryAssemblyLoaded() static bool GetIsEveryAssemblyLoaded()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetIsEveryAssemblyLoaded")
return Scripting::IsEveryAssemblyLoaded(); return Scripting::IsEveryAssemblyLoaded();
} }
static int32 GetLastProjectOpenedEngineBuild() static int32 GetLastProjectOpenedEngineBuild()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetLastProjectOpenedEngineBuild")
return Editor::LastProjectOpenedEngineBuild; return Editor::LastProjectOpenedEngineBuild;
} }
static bool GetIsCSGActive() static bool GetIsCSGActive()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetIsCSGActive")
#if COMPILE_WITH_CSG_BUILDER #if COMPILE_WITH_CSG_BUILDER
return CSG::Builder::IsActive(); return CSG::Builder::IsActive();
#else #else
@@ -827,6 +867,7 @@ public:
static void RunVisualScriptBreakpointLoopTick(float deltaTime) static void RunVisualScriptBreakpointLoopTick(float deltaTime)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_RunVisualScriptBreakpointLoopTick")
// Update // Update
Platform::Tick(); Platform::Tick();
Engine::HasFocus = (Engine::MainWindow && Engine::MainWindow->IsFocused()) || Platform::GetHasFocus(); Engine::HasFocus = (Engine::MainWindow && Engine::MainWindow->IsFocused()) || Platform::GetHasFocus();
@@ -921,6 +962,7 @@ public:
static MonoArray* GetVisualScriptLocals() static MonoArray* GetVisualScriptLocals()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptLocals")
MonoArray* result = nullptr; MonoArray* result = nullptr;
const auto stack = VisualScripting::GetThreadStackTop(); const auto stack = VisualScripting::GetThreadStackTop();
if (stack && stack->Scope) if (stack && stack->Scope)
@@ -969,6 +1011,7 @@ public:
static MonoArray* GetVisualScriptStackFrames() static MonoArray* GetVisualScriptStackFrames()
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptStackFrames")
MonoArray* result = nullptr; MonoArray* result = nullptr;
const auto stack = VisualScripting::GetThreadStackTop(); const auto stack = VisualScripting::GetThreadStackTop();
if (stack) if (stack)
@@ -1022,6 +1065,7 @@ public:
static bool EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocalManaged* local) static bool EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocalManaged* local)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_EvaluateVisualScriptLocal")
Variant v; Variant v;
if (VisualScripting::Evaluate(script, VisualScripting::GetThreadStackTop()->Instance, local->NodeId, local->BoxId, v)) if (VisualScripting::Evaluate(script, VisualScripting::GetThreadStackTop()->Instance, local->NodeId, local->BoxId, v))
{ {
@@ -1034,6 +1078,7 @@ public:
static void DeserializeSceneObject(SceneObject* sceneObject, MonoString* jsonObj) static void DeserializeSceneObject(SceneObject* sceneObject, MonoString* jsonObj)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_DeserializeSceneObject")
PROFILE_CPU_NAMED("DeserializeSceneObject"); PROFILE_CPU_NAMED("DeserializeSceneObject");
StringAnsi json; StringAnsi json;
@@ -1062,11 +1107,13 @@ public:
static void LoadAsset(Guid* id) static void LoadAsset(Guid* id)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_LoadAsset")
Content::LoadAsync<Asset>(*id); Content::LoadAsync<Asset>(*id);
} }
static bool CanSetToRoot(Prefab* prefab, Actor* targetActor) static bool CanSetToRoot(Prefab* prefab, Actor* targetActor)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanSetToRoot")
// Reference: Prefab::ApplyAll(Actor* targetActor) // Reference: Prefab::ApplyAll(Actor* targetActor)
if (targetActor->GetPrefabID() != prefab->GetID()) if (targetActor->GetPrefabID() != prefab->GetID())
return false; return false;
@@ -1089,11 +1136,13 @@ public:
static float GetAnimationTime(AnimatedModel* animatedModel) static float GetAnimationTime(AnimatedModel* animatedModel)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetAnimationTime")
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f; return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;
} }
static void SetAnimationTime(AnimatedModel* animatedModel, float time) static void SetAnimationTime(AnimatedModel* animatedModel, float time)
{ {
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetAnimationTime")
if (animatedModel && animatedModel->GraphInstance.State.Count() == 1) if (animatedModel && animatedModel->GraphInstance.State.Count() == 1)
animatedModel->GraphInstance.State[0].Animation.TimePosition = time; animatedModel->GraphInstance.State[0].Animation.TimePosition = time;
} }

View File

@@ -375,7 +375,9 @@ namespace FlaxEditor.Modules
Thread.Sleep(0); Thread.Sleep(0);
_workerThread.Join(1000); _workerThread.Join(1000);
_workerThread.Abort(); #if !USE_NETCORE
_workerThread.Abort(); // Deprecated in .NET 7
#endif
_workerThread = null; _workerThread = null;
} }

View File

@@ -257,7 +257,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
{ {
Profiler.BeginEvent("GetXmlDocs"); Profiler.BeginEvent("GetXmlDocs");
var uri = new UriBuilder(assembly.CodeBase); var uri = new UriBuilder(Utils.GetAssemblyLocation(assembly));
var path = Uri.UnescapeDataString(uri.Path); var path = Uri.UnescapeDataString(uri.Path);
var name = assembly.GetName().Name; var name = assembly.GetName().Name;
var xmlFilePath = Path.Combine(Path.GetDirectoryName(path), name + ".xml"); var xmlFilePath = Path.Combine(Path.GetDirectoryName(path), name + ".xml");

View File

@@ -391,9 +391,27 @@ namespace FlaxEditor.Modules.SourceCodeEditing
private static bool HasAssemblyValidAnyTypes(Assembly assembly) private static bool HasAssemblyValidAnyTypes(Assembly assembly)
{ {
var codeBase = Utils.GetAssemblyLocation(assembly);
#if USE_NETCORE
if (assembly.ManifestModule.FullyQualifiedName == "<In Memory Module>")
return false;
if (string.IsNullOrEmpty(codeBase))
return true;
// Skip runtime related assemblies
string repositoryUrl = assembly.GetCustomAttributes<AssemblyMetadataAttribute>().FirstOrDefault(x => x.Key == "RepositoryUrl")?.Value ?? "";
if (repositoryUrl != "https://github.com/dotnet/runtime")
return true;
#else
if (string.IsNullOrEmpty(codeBase))
return true;
// Skip assemblies from in-build Mono directory // Skip assemblies from in-build Mono directory
var codeBase = assembly.CodeBase; if (!codeBase.Contains("/Mono/lib/mono/"))
return string.IsNullOrEmpty(codeBase) || !codeBase.Contains("/Mono/lib/mono/"); return true;
#endif
return false;
} }
private static bool HasAssemblyValidScriptingTypes(Assembly a) private static bool HasAssemblyValidScriptingTypes(Assembly a)

View File

@@ -24,7 +24,7 @@ namespace FlaxEditor
var type = plugin.GetType(); var type = plugin.GetType();
var assembly = type.Assembly; var assembly = type.Assembly;
var assemblyPath = assembly.Location; var assemblyPath = Utils.GetAssemblyLocation(assembly);
var assemblyName = assembly.GetName().Name; var assemblyName = assembly.GetName().Name;
var dotEditorPos = assemblyName.LastIndexOf(".Editor", StringComparison.OrdinalIgnoreCase); var dotEditorPos = assemblyName.LastIndexOf(".Editor", StringComparison.OrdinalIgnoreCase);
if (dotEditorPos != -1) if (dotEditorPos != -1)

View File

@@ -41,8 +41,10 @@ namespace FlaxEditor.Progress.Handlers
private void OnScriptsReload() private void OnScriptsReload()
{ {
#if !USE_NETCORE
// Clear types cache // Clear types cache
Newtonsoft.Json.JsonSerializer.ClearCache(); Newtonsoft.Json.JsonSerializer.ClearCache();
#endif
} }
private void OnScriptsReloadEnd() private void OnScriptsReloadEnd()

View File

@@ -176,6 +176,7 @@ bool ScriptsBuilder::IsReady()
void ScriptsBuilder::MarkWorkspaceDirty() void ScriptsBuilder::MarkWorkspaceDirty()
{ {
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_MarkWorkspaceDirty")
ScopeLock scopeLock(_locker); ScopeLock scopeLock(_locker);
_lastSourceCodeEdited = DateTime::Now(); _lastSourceCodeEdited = DateTime::Now();
_wasProjectStructureChanged = true; _wasProjectStructureChanged = true;
@@ -183,6 +184,7 @@ void ScriptsBuilder::MarkWorkspaceDirty()
void ScriptsBuilder::CheckForCompile() void ScriptsBuilder::CheckForCompile()
{ {
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_CheckForCompile")
ScopeLock scopeLock(_locker); ScopeLock scopeLock(_locker);
if (IsSourceDirty()) if (IsSourceDirty())
Compile(); Compile();
@@ -205,6 +207,7 @@ void ScriptsBuilderImpl::onScriptsReloadEnd()
void ScriptsBuilder::Compile() void ScriptsBuilder::Compile()
{ {
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_Compile")
ScopeLock scopeLock(_locker); ScopeLock scopeLock(_locker);
// Request compile job // Request compile job

View File

@@ -6,7 +6,9 @@ using System.Linq;
using FlaxEditor.Options; using FlaxEditor.Options;
using FlaxEditor.SceneGraph.Actors; using FlaxEditor.SceneGraph.Actors;
using FlaxEngine; using FlaxEngine;
using FlaxEditor.Utilities;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
using Utils = FlaxEngine.Utils;
namespace FlaxEditor.States namespace FlaxEditor.States
{ {

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine; using FlaxEngine;
using FlaxEditor.Utilities;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
namespace FlaxEditor.States namespace FlaxEditor.States

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine; using FlaxEngine;
using FlaxEditor.Utilities;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
namespace FlaxEditor.States namespace FlaxEditor.States

View File

@@ -12,6 +12,7 @@ using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
using FlaxEngine.Utilities;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -587,7 +588,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < _parameters.Length; i++) for (int i = 0; i < _parameters.Length; i++)
{ {
writer.Write(_parameters[i].Name); // Parameter name writer.Write(_parameters[i].Name); // Parameter name
Utilities.VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
} }
SetValue(2, stream.ToArray()); SetValue(2, stream.ToArray());
} }
@@ -605,7 +606,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < parametersCount; i++) for (int i = 0; i < parametersCount; i++)
{ {
var parameterName = reader.ReadString(); // Parameter name var parameterName = reader.ReadString(); // Parameter name
var boxType = Utilities.VariantUtils.ReadVariantType(reader); // Box type var boxType = VariantUtils.ReadVariantType(reader); // Box type
MakeBox(i + 1, parameterName, boxType); MakeBox(i + 1, parameterName, boxType);
} }
} }
@@ -788,14 +789,14 @@ namespace FlaxEditor.Surface.Archetypes
{ {
reader.ReadByte(); // Version reader.ReadByte(); // Version
signature.IsStatic = reader.ReadBoolean(); // Is Static signature.IsStatic = reader.ReadBoolean(); // Is Static
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type signature.ReturnType = VariantUtils.ReadVariantScriptType(reader); // Return type
var parametersCount = reader.ReadInt32(); // Parameters count var parametersCount = reader.ReadInt32(); // Parameters count
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>(); signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
for (int i = 0; i < parametersCount; i++) for (int i = 0; i < parametersCount; i++)
{ {
ref var param = ref signature.Params[i]; ref var param = ref signature.Params[i];
param.Name = Utilities.Utils.ReadStr(reader, 11); // Parameter name param.Name = Utilities.Utils.ReadStr(reader, 11); // Parameter name
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type param.Type = VariantUtils.ReadVariantScriptType(reader); // Parameter type
param.IsOut = reader.ReadByte() != 0; // Is parameter out param.IsOut = reader.ReadByte() != 0; // Is parameter out
} }
} }
@@ -809,14 +810,14 @@ namespace FlaxEditor.Surface.Archetypes
{ {
reader.ReadByte(); // Version reader.ReadByte(); // Version
signature.IsStatic = reader.ReadBoolean(); // Is Static signature.IsStatic = reader.ReadBoolean(); // Is Static
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type signature.ReturnType = VariantUtils.ReadVariantScriptType(reader); // Return type
var parametersCount = reader.ReadInt32(); // Parameters count var parametersCount = reader.ReadInt32(); // Parameters count
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>(); signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
for (int i = 0; i < parametersCount; i++) for (int i = 0; i < parametersCount; i++)
{ {
ref var param = ref signature.Params[i]; ref var param = ref signature.Params[i];
param.Name = reader.ReadString(); // Parameter name param.Name = reader.ReadString(); // Parameter name
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type param.Type = VariantUtils.ReadVariantScriptType(reader); // Parameter type
param.IsOut = reader.ReadByte() != 0; // Is parameter out param.IsOut = reader.ReadByte() != 0; // Is parameter out
} }
} }
@@ -833,13 +834,13 @@ namespace FlaxEditor.Surface.Archetypes
{ {
writer.Write((byte)4); // Version writer.Write((byte)4); // Version
writer.Write(methodInfo.IsStatic); // Is Static writer.Write(methodInfo.IsStatic); // Is Static
Utilities.VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type
writer.Write(parameters.Length); // Parameters count writer.Write(parameters.Length); // Parameters count
for (int i = 0; i < parameters.Length; i++) for (int i = 0; i < parameters.Length; i++)
{ {
ref var param = ref parameters[i]; ref var param = ref parameters[i];
Utilities.Utils.WriteStr(writer, param.Name, 11); // Parameter name Utilities.Utils.WriteStr(writer, param.Name, 11); // Parameter name
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
writer.Write((byte)(param.IsOut ? 1 : 0)); // Is parameter out writer.Write((byte)(param.IsOut ? 1 : 0)); // Is parameter out
} }
return stream.ToArray(); return stream.ToArray();
@@ -1461,14 +1462,14 @@ namespace FlaxEditor.Surface.Archetypes
if (_signature.IsVirtual) if (_signature.IsVirtual)
flags |= Flags.Virtual; flags |= Flags.Virtual;
writer.Write((byte)flags); // Flags writer.Write((byte)flags); // Flags
Utilities.VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type
var parametersCount = _signature.Parameters?.Length ?? 0; var parametersCount = _signature.Parameters?.Length ?? 0;
writer.Write(parametersCount); // Parameters count writer.Write(parametersCount); // Parameters count
for (int i = 0; i < parametersCount; i++) for (int i = 0; i < parametersCount; i++)
{ {
ref var param = ref _signature.Parameters[i]; ref var param = ref _signature.Parameters[i];
Utilities.Utils.WriteStrAnsi(writer, param.Name, 13); // Parameter name Utilities.Utils.WriteStrAnsi(writer, param.Name, 13); // Parameter name
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
writer.Write((byte)0); // Is parameter out writer.Write((byte)0); // Is parameter out
writer.Write((byte)0); // Has default value writer.Write((byte)0); // Has default value
} }
@@ -1497,13 +1498,13 @@ namespace FlaxEditor.Surface.Archetypes
var flags = (Flags)reader.ReadByte(); // Flags var flags = (Flags)reader.ReadByte(); // Flags
_signature.IsStatic = (flags & Flags.Static) == Flags.Static; _signature.IsStatic = (flags & Flags.Static) == Flags.Static;
_signature.IsVirtual = (flags & Flags.Virtual) == Flags.Virtual; _signature.IsVirtual = (flags & Flags.Virtual) == Flags.Virtual;
_signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return Type _signature.ReturnType = VariantUtils.ReadVariantScriptType(reader); // Return Type
var parametersCount = reader.ReadInt32(); // Parameters count var parametersCount = reader.ReadInt32(); // Parameters count
_signature.Parameters = new Parameter[parametersCount]; _signature.Parameters = new Parameter[parametersCount];
for (int i = 0; i < parametersCount; i++) for (int i = 0; i < parametersCount; i++)
{ {
var paramName = Utilities.Utils.ReadStrAnsi(reader, 13); // Parameter name var paramName = Utilities.Utils.ReadStrAnsi(reader, 13); // Parameter name
var paramType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type var paramType = VariantUtils.ReadVariantScriptType(reader); // Parameter type
var isOut = reader.ReadByte() != 0; // Is parameter out var isOut = reader.ReadByte() != 0; // Is parameter out
var hasDefaultValue = reader.ReadByte() != 0; // Has default value var hasDefaultValue = reader.ReadByte() != 0; // Has default value
_signature.Parameters[i] = new Parameter _signature.Parameters[i] = new Parameter

View File

@@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
using FlaxEngine.Utilities;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Surface.Archetypes namespace FlaxEditor.Surface.Archetypes
@@ -167,7 +168,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++) for (int i = 0; i < fieldsLength; i++)
{ {
Utilities.Utils.WriteStr(writer, fields[i].Name, 11); // Field type Utilities.Utils.WriteStr(writer, fields[i].Name, 11); // Field type
Utilities.VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type
} }
Values[1] = stream.ToArray(); Values[1] = stream.ToArray();
} }
@@ -184,7 +185,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++) for (int i = 0; i < fieldsLength; i++)
{ {
var fieldName = Utilities.Utils.ReadStr(reader, 11); // Field name var fieldName = Utilities.Utils.ReadStr(reader, 11); // Field name
var fieldType = Utilities.VariantUtils.ReadVariantType(reader); // Field type var fieldType = VariantUtils.ReadVariantType(reader); // Field type
MakeBox(i + 1, fieldName, new ScriptType(fieldType)); MakeBox(i + 1, fieldName, new ScriptType(fieldType));
} }
} }

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.Loader;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors; using FlaxEditor.CustomEditors.Editors;
@@ -118,8 +119,13 @@ namespace FlaxEditor.Surface
using (var stream = new MemoryStream()) using (var stream = new MemoryStream())
{ {
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
var formatter = new BinaryFormatter(); var formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011
formatter.Serialize(stream, attributes); formatter.Serialize(stream, attributes);
#pragma warning restore SYSLIB0011
_oldData = stream.ToArray(); _oldData = stream.ToArray();
} }
editor.Select(new Proxy editor.Select(new Proxy
@@ -141,8 +147,13 @@ namespace FlaxEditor.Surface
} }
using (var stream = new MemoryStream()) using (var stream = new MemoryStream())
{ {
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
var formatter = new BinaryFormatter(); var formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011
formatter.Serialize(stream, newValue); formatter.Serialize(stream, newValue);
#pragma warning restore SYSLIB0011
var newData = stream.ToArray(); var newData = stream.ToArray();
if (!_oldData.SequenceEqual(newData)) if (!_oldData.SequenceEqual(newData))
{ {

View File

@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using FlaxEngine; using FlaxEngine;
@@ -54,8 +56,13 @@ namespace FlaxEditor.Surface
{ {
try try
{ {
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
var formatter = new BinaryFormatter(); var formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011
return (Attribute[])formatter.Deserialize(stream); return (Attribute[])formatter.Deserialize(stream);
#pragma warning restore SYSLIB0011
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -122,8 +129,13 @@ namespace FlaxEditor.Surface
} }
using (var stream = new MemoryStream()) using (var stream = new MemoryStream())
{ {
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
var formatter = new BinaryFormatter(); var formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011
formatter.Serialize(stream, attributes); formatter.Serialize(stream, attributes);
#pragma warning restore SYSLIB0011
AddEntry(AttributeMetaTypeID, stream.ToArray()); AddEntry(AttributeMetaTypeID, stream.ToArray());
} }
} }

View File

@@ -10,6 +10,7 @@ using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Elements; using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Utilities; using FlaxEditor.Utilities;
using FlaxEngine.Utilities;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Surface namespace FlaxEditor.Surface

View File

@@ -8,6 +8,7 @@ using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
using FlaxEditor.Utilities; using FlaxEditor.Utilities;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Utilities;
using Utils = FlaxEditor.Utilities.Utils; using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.Surface namespace FlaxEditor.Surface

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine; using FlaxEngine;
using FlaxEditor.Utilities;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
namespace FlaxEditor.Tools.Terrain.Sculpt namespace FlaxEditor.Tools.Terrain.Sculpt

View File

@@ -445,7 +445,7 @@ namespace FlaxEditor.Windows
int logCount; int logCount;
do do
{ {
logCount = Editor.Internal_ReadOutputLogs(_outMessages, _outLogTypes, _outLogTimes); logCount = Editor.Internal_ReadOutputLogs(ref _outMessages, ref _outLogTypes, ref _outLogTimes, OutCapacity);
for (int i = 0; i < logCount; i++) for (int i = 0; i < logCount; i++)
{ {

View File

@@ -19,16 +19,16 @@ namespace FlaxEngine
{ {
get get
{ {
fixed (char* name = &Name0) fixed (short* name = Name0)
{ {
return new string(name); return new string((char*)name);
} }
} }
} }
internal unsafe bool NameStartsWith(string prefix) internal unsafe bool NameStartsWith(string prefix)
{ {
fixed (char* name = &Name0) fixed (short* name = Name0)
{ {
fixed (char* p = prefix) fixed (char* p = prefix)
{ {

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace FlaxEngine namespace FlaxEngine
{ {
@@ -44,6 +45,7 @@ namespace FlaxEngine
/// The node evaluation context structure. /// The node evaluation context structure.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(ContextMarshaler))]
public struct Context public struct Context
{ {
/// <summary> /// <summary>
@@ -92,6 +94,61 @@ namespace FlaxEngine
public AnimatedModel Instance; public AnimatedModel Instance;
} }
[CustomMarshaller(typeof(Context), MarshalMode.Default, typeof(ContextMarshaler))]
internal static class ContextMarshaler
{
[StructLayout(LayoutKind.Sequential)]
public struct ContextNative
{
public IntPtr Graph;
public IntPtr GraphExecutor;
public IntPtr Node;
public uint NodeId;
public int BoxId;
public float DeltaTime;
public ulong CurrentFrameIndex;
public IntPtr BaseModel;
public IntPtr Instance;
}
internal static Context ConvertToManaged(ContextNative unmanaged) => ToManaged(unmanaged);
internal static ContextNative ConvertToUnmanaged(Context managed) => ToNative(managed);
internal static Context ToManaged(ContextNative managed)
{
return new Context()
{
Graph = managed.Graph,
GraphExecutor = managed.GraphExecutor,
Node = managed.Node,
NodeId = managed.NodeId,
BoxId = managed.BoxId,
DeltaTime = managed.DeltaTime,
CurrentFrameIndex = managed.CurrentFrameIndex,
BaseModel = SkinnedModelMarshaller.ConvertToManaged(managed.BaseModel),
Instance = AnimatedModelMarshaller.ConvertToManaged(managed.Instance),
};
}
internal static ContextNative ToNative(Context managed)
{
return new ContextNative()
{
Graph = managed.Graph,
GraphExecutor = managed.GraphExecutor,
Node = managed.Node,
NodeId = managed.NodeId,
BoxId = managed.BoxId,
DeltaTime = managed.DeltaTime,
CurrentFrameIndex = managed.CurrentFrameIndex,
BaseModel = SkinnedModelMarshaller.ConvertToUnmanaged(managed.BaseModel),
Instance = AnimatedModelMarshaller.ConvertToUnmanaged(managed.Instance),
};
}
internal static void Free(ContextNative unmanaged)
{
}
}
/// <summary> /// <summary>
/// The animation graph 'impulse' connections data container (the actual transfer is done via pointer as it gives better performance). /// The animation graph 'impulse' connections data container (the actual transfer is done via pointer as it gives better performance).
/// Container for skeleton nodes transformation hierarchy and any other required data. /// Container for skeleton nodes transformation hierarchy and any other required data.
@@ -203,14 +260,16 @@ namespace FlaxEngine
#region Internal Calls #region Internal Calls
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_HasConnection")]
internal static extern bool Internal_HasConnection(ref CustomNode.Context context, int boxId); [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetInputValue")]
internal static extern object Internal_GetInputValue(ref CustomNode.Context context, int boxId); [return: MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))]
internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")]
internal static extern IntPtr Internal_GetOutputImpulseData(ref CustomNode.Context context); internal static partial IntPtr Internal_GetOutputImpulseData(ref AnimationGraph.CustomNode.Context context);
#endregion #endregion
} }

View File

@@ -13,8 +13,8 @@
#include "Engine/Content/Assets/SkinnedModel.h" #include "Engine/Content/Assets/SkinnedModel.h"
#if USE_MONO #if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
struct InternalInitData struct InternalInitData
{ {
@@ -52,6 +52,7 @@ namespace AnimGraphInternal
{ {
bool HasConnection(InternalContext* context, int32 boxId) bool HasConnection(InternalContext* context, int32 boxId)
{ {
SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_HasConnection")
const auto box = context->Node->TryGetBox(boxId); const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr) if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId"); DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -60,6 +61,7 @@ namespace AnimGraphInternal
MonoObject* GetInputValue(InternalContext* context, int32 boxId) MonoObject* GetInputValue(InternalContext* context, int32 boxId)
{ {
SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_GetInputValue")
const auto box = context->Node->TryGetBox(boxId); const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr) if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId"); DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -77,14 +79,13 @@ namespace AnimGraphInternal
AnimGraphImpulse* GetOutputImpulseData(InternalContext* context) AnimGraphImpulse* GetOutputImpulseData(InternalContext* context)
{ {
SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")
const auto nodes = context->Node->GetNodes(context->GraphExecutor); const auto nodes = context->Node->GetNodes(context->GraphExecutor);
context->GraphExecutor->InitNodes(nodes); context->GraphExecutor->InitNodes(nodes);
return nodes; return nodes;
} }
} }
#endif
void AnimGraphExecutor::initRuntime() void AnimGraphExecutor::initRuntime()
{ {
#if USE_MONO #if USE_MONO
@@ -122,7 +123,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
internalContext.Instance = context.Data->Object ? context.Data->Object->GetOrCreateManagedInstance() : nullptr; internalContext.Instance = context.Data->Object ? context.Data->Object->GetOrCreateManagedInstance() : nullptr;
// Peek managed object // Peek managed object
const auto obj = mono_gchandle_get_target(data.Handle); const auto obj = MUtils::GetGCHandleTarget(data.Handle);
if (obj == nullptr) if (obj == nullptr)
{ {
LOG(Warning, "Custom node instance is null."); LOG(Warning, "Custom node instance is null.");
@@ -166,7 +167,7 @@ void AnimGraph::ClearCustomNode(Node* node)
if (data.Handle) if (data.Handle)
{ {
#if USE_MONO #if USE_MONO
mono_gchandle_free(data.Handle); MUtils::FreeGCHandle(data.Handle);
#endif #endif
data.Handle = 0; data.Handle = 0;
} }
@@ -216,7 +217,7 @@ bool AnimGraph::InitCustomNode(Node* node)
// Allocate managed node object (create GC handle to prevent destruction) // Allocate managed node object (create GC handle to prevent destruction)
const auto obj = type->CreateInstance(); const auto obj = type->CreateInstance();
const auto handleGC = mono_gchandle_new(obj, false); const auto handleGC = MUtils::NewGCHandle(obj, false);
// Initialize node // Initialize node
InternalInitData initData; InternalInitData initData;
@@ -228,7 +229,7 @@ bool AnimGraph::InitCustomNode(Node* node)
load->Invoke(obj, params, &exception); load->Invoke(obj, params, &exception);
if (exception) if (exception)
{ {
mono_gchandle_free(handleGC); MUtils::FreeGCHandle(handleGC);
MException ex(exception); MException ex(exception);
ex.Log(LogType::Warning, TEXT("AnimGraph")); ex.Log(LogType::Warning, TEXT("AnimGraph"));

View File

@@ -516,7 +516,7 @@ public:
/// <summary> /// <summary>
/// The GC handle to the managed instance of the node object. /// The GC handle to the managed instance of the node object.
/// </summary> /// </summary>
uint32 Handle; gchandle Handle;
}; };
struct CurveData struct CurveData

View File

@@ -13,6 +13,7 @@
#include "Engine/Threading/MainThreadTask.h" #include "Engine/Threading/MainThreadTask.h"
#include "Engine/Threading/ConcurrentTaskQueue.h" #include "Engine/Threading/ConcurrentTaskQueue.h"
#if USE_MONO #if USE_MONO
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
#endif #endif
@@ -270,7 +271,7 @@ void Asset::OnManagedInstanceDeleted()
if (_gcHandle) if (_gcHandle)
{ {
#if USE_MONO #if USE_MONO
mono_gchandle_free(_gcHandle); MUtils::FreeGCHandle(_gcHandle);
#endif #endif
_gcHandle = 0; _gcHandle = 0;
} }

View File

@@ -93,3 +93,14 @@
#endif #endif
#define PACK_STRUCT(__Declaration__) PACK_BEGIN() __Declaration__ PACK_END() #define PACK_STRUCT(__Declaration__) PACK_BEGIN() __Declaration__ PACK_END()
#define SCRIPTING_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
#define SCRIPTING_EXPORT_DEBUG(name) __pragma(message("/EXPORT:" #name "=" __FUNCDNAME__)) \
__pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
// TODO: try this one with clang:
//#ifdef _MSC_VER
//#define SCRIPTING_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
//#endif
//#ifdef __GNUC__
//#define SCRIPTING_EXPORT(name) asm(".section .drectve\n\t.ascii \" -export:" #name "=" __FUNCDNAME__ "\"");
//#endif

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Content.Settings namespace FlaxEditor.Content.Settings
@@ -562,8 +563,8 @@ namespace FlaxEditor.Content.Settings
/// <summary> /// <summary>
/// Loads the current game settings asset and applies it to the engine runtime configuration. /// Loads the current game settings asset and applies it to the engine runtime configuration.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.GameSettings::Apply")]
public static extern void Apply(); public static partial void Apply();
#endif #endif
} }
} }

View File

@@ -2,6 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Content.Settings namespace FlaxEditor.Content.Settings
@@ -24,14 +26,26 @@ namespace FlaxEditor.Content.Settings
/// Gets the current tags collection. /// Gets the current tags collection.
/// </summary> /// </summary>
/// <returns>The tags collection.</returns> /// <returns>The tags collection.</returns>
[MethodImpl(MethodImplOptions.InternalCall)] internal static string[] GetCurrentTags()
internal static extern string[] GetCurrentTags(); {
return GetCurrentTags(out int _);
}
/// <summary> /// <summary>
/// Gets the current layer names (max 32 items but trims last empty items). /// Gets the current layer names (max 32 items but trims last empty items).
/// </summary> /// </summary>
/// <returns>The layers.</returns> /// <returns>The layers.</returns>
[MethodImpl(MethodImplOptions.InternalCall)] public static string[] GetCurrentLayers()
public static extern string[] GetCurrentLayers(); {
return GetCurrentLayers(out int _);
}
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentTags", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
[return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "tagCount")]
internal static partial string[] GetCurrentTags(out int tagCount);
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
[return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "layerCount")]
internal static partial string[] GetCurrentLayers(out int layerCount);
} }
} }

View File

@@ -18,6 +18,16 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
@@ -25,9 +35,9 @@ namespace FlaxEngine.TypeConverters
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
if (v.Length == 4) if (v.Length == 4)
return new Color(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3])); return new Color(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
if (v.Length == 3) if (v.Length == 3)
return new Color(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), 1.0f); return new Color(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), 1.0f);
throw new FormatException("Invalid Color value format."); throw new FormatException("Invalid Color value format.");
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
@@ -39,7 +49,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Color)value; var v = (Color)value;
return v.R + "," + v.G + "," + v.B + "," + v.A; return v.R.ToString(culture) + "," + v.G.ToString(culture) + "," + v.B.ToString(culture) + "," + v.A.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Double2(double.Parse(v[0]), double.Parse(v[1])); return new Double2(double.Parse(v[0], culture), double.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Double2)value; var v = (Double2)value;
return v.X + "," + v.Y; return v.X.ToString(culture) + "," + v.Y.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Double3(double.Parse(v[0]), double.Parse(v[1]), double.Parse(v[2])); return new Double3(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Double3)value; var v = (Double3)value;
return v.X + "," + v.Y + "," + v.Z; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Double4(double.Parse(v[0]), double.Parse(v[1]), double.Parse(v[2]), double.Parse(v[3])); return new Double4(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture), double.Parse(v[3], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Double4)value; var v = (Double4)value;
return v.X + "," + v.Y + "," + v.Z + "," + v.W; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Float2(float.Parse(v[0]), float.Parse(v[1])); return new Float2(float.Parse(v[0], culture), float.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Float2)value; var v = (Float2)value;
return v.X + "," + v.Y; return v.X.ToString(culture) + "," + v.Y.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Float3(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2])); return new Float3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Float3)value; var v = (Float3)value;
return v.X + "," + v.Y + "," + v.Z; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Float4(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3])); return new Float4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Float4)value; var v = (Float4)value;
return v.X + "," + v.Y + "," + v.Z + "," + v.W; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Int2(int.Parse(v[0]), int.Parse(v[1])); return new Int2(int.Parse(v[0], culture), int.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Int2)value; var v = (Int2)value;
return v.X + "," + v.Y; return v.X.ToString(culture) + "," + v.Y.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Int3(int.Parse(v[0]), int.Parse(v[1]), int.Parse(v[2])); return new Int3(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Int3)value; var v = (Int3)value;
return v.X + "," + v.Y + "," + v.Z; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Int4(int.Parse(v[0]), int.Parse(v[1]), int.Parse(v[2]), int.Parse(v[3])); return new Int4(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture), int.Parse(v[3], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Int4)value; var v = (Int4)value;
return v.X + "," + v.Y + "," + v.Z + "," + v.W; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Quaternion(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3])); return new Quaternion(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Quaternion)value; var v = (Quaternion)value;
return v.X + "," + v.Y + "," + v.Z + "," + v.W; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Vector2(float.Parse(v[0]), float.Parse(v[1])); return new Vector2(float.Parse(v[0], culture), float.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Vector2)value; var v = (Vector2)value;
return v.X + "," + v.Y; return v.X.ToString(culture) + "," + v.Y.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Vector3(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2])); return new Vector3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Vector3)value; var v = (Vector3)value;
return v.X + "," + v.Y + "," + v.Z; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) if (value is string str)
{ {
string[] v = str.Split(','); string[] v = str.Split(',');
return new Vector4(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3])); return new Vector4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
var v = (Vector4)value; var v = (Vector4)value;
return v.X + "," + v.Y + "," + v.Z + "," + v.W; return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }

View File

@@ -619,7 +619,11 @@ Variant::Variant(Asset* v)
Variant::Variant(_MonoObject* v) Variant::Variant(_MonoObject* v)
: Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr) : Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr)
{ {
AsUint = v ? mono_gchandle_new(v, true) : 0; #if USE_NETCORE
AsUint64 = v ? MUtils::NewGCHandle(v, true) : 0;
#else
AsUint = v ? MUtils::NewGCHandle(v, true) : 0;
#endif
} }
#else #else
@@ -957,9 +961,13 @@ Variant::~Variant()
Delete(AsDictionary); Delete(AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
if (AsUint64)
MUtils::FreeGCHandle(AsUint64);
break;
#elif USE_MONO
if (AsUint) if (AsUint)
mono_gchandle_free(AsUint); MUtils::FreeGCHandle(AsUint);
break; break;
#endif #endif
default: ; default: ;
@@ -1088,8 +1096,10 @@ Variant& Variant::operator=(const Variant& other)
AsDictionary = New<Dictionary<Variant, Variant>>(*other.AsDictionary); AsDictionary = New<Dictionary<Variant, Variant>>(*other.AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
AsUint = other.AsUint ? mono_gchandle_new(mono_gchandle_get_target(other.AsUint), true) : 0; AsUint64 = other.AsUint64 ? MUtils::NewGCHandle(MUtils::GetGCHandleTarget(other.AsUint64), true) : 0;
#elif USE_MONO
AsUint = other.AsUint ? MUtils::NewGCHandle(MUtils::GetGCHandleTarget(other.AsUint), true) : 0;
#endif #endif
break; break;
case VariantType::Null: case VariantType::Null:
@@ -1217,7 +1227,7 @@ bool Variant::operator==(const Variant& other) const
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_MONO
// TODO: invoke C# Equality logic? // TODO: invoke C# Equality logic?
return AsUint == other.AsUint || mono_gchandle_get_target(AsUint) == mono_gchandle_get_target(other.AsUint); return AsUint == other.AsUint || MUtils::GetGCHandleTarget(AsUint) == MUtils::GetGCHandleTarget(other.AsUint);
#endif #endif
default: default:
return false; return false;
@@ -1308,8 +1318,10 @@ Variant::operator bool() const
case VariantType::Asset: case VariantType::Asset:
return AsAsset != nullptr; return AsAsset != nullptr;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
return AsUint != 0 && mono_gchandle_get_target(AsUint) != nullptr; return AsUint64 != 0 && MUtils::GetGCHandleTarget(AsUint64) != nullptr;
#elif USE_MONO
return AsUint != 0 && MUtils::GetGCHandleTarget(AsUint) != nullptr;
#endif #endif
default: default:
return false; return false;
@@ -1578,8 +1590,10 @@ Variant::operator void*() const
case VariantType::Blob: case VariantType::Blob:
return AsBlob.Data; return AsBlob.Data;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
return AsUint ? mono_gchandle_get_target(AsUint) : nullptr; return AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
#elif USE_MONO
return AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
#endif #endif
default: default:
return nullptr; return nullptr;
@@ -1623,8 +1637,10 @@ Variant::operator ScriptingObject*() const
Variant::operator _MonoObject*() const Variant::operator _MonoObject*() const
{ {
#if USE_MONO #if USE_NETCORE
return Type.Type == VariantType::ManagedObject && AsUint ? mono_gchandle_get_target(AsUint) : nullptr; return Type.Type == VariantType::ManagedObject && AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
#elif USE_MONO
return Type.Type == VariantType::ManagedObject && AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
#else #else
return nullptr; return nullptr;
#endif #endif
@@ -2337,9 +2353,14 @@ void Variant::SetType(const VariantType& type)
Delete(AsDictionary); Delete(AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
if (AsUint64)
MUtils::FreeGCHandle(AsUint64);
break;
#elif USE_MONO
if (AsUint) if (AsUint)
mono_gchandle_free(AsUint); MUtils::FreeGCHandle(AsUint);
break;
#endif #endif
break; break;
default: ; default: ;
@@ -2447,9 +2468,14 @@ void Variant::SetType(VariantType&& type)
Delete(AsDictionary); Delete(AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
if (AsUint64)
MUtils::FreeGCHandle(AsUint64);
break;
#elif USE_MONO
if (AsUint) if (AsUint)
mono_gchandle_free(AsUint); MUtils::FreeGCHandle(AsUint);
break;
#endif #endif
break; break;
default: ; default: ;
@@ -2632,7 +2658,11 @@ void Variant::SetManagedObject(_MonoObject* object)
{ {
if (Type.Type != VariantType::ManagedObject) if (Type.Type != VariantType::ManagedObject)
SetType(VariantType(VariantType::ManagedObject, mono_object_get_class(object))); SetType(VariantType(VariantType::ManagedObject, mono_object_get_class(object)));
AsUint = mono_gchandle_new(object, true); #if USE_NETCORE
AsUint64 = MUtils::NewGCHandle(object, true);
#else
AsUint = MUtils::NewGCHandle(object, true);
#endif
} }
else else
{ {
@@ -2751,8 +2781,10 @@ String Variant::ToString() const
case VariantType::Typename: case VariantType::Typename:
return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0); return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0);
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
return AsUint ? String(MUtils::ToString(mono_object_to_string(mono_gchandle_get_target(AsUint), nullptr))) : TEXT("null"); return AsUint64 ? String(MUtils::ToString(mono_object_to_string(MUtils::GetGCHandleTarget(AsUint64), nullptr))) : TEXT("null");
#elif USE_MONO
return AsUint ? String(MUtils::ToString(mono_object_to_string(MUtils::GetGCHandleTarget(AsUint), nullptr))) : TEXT("null");
#endif #endif
default: default:
return String::Empty; return String::Empty;
@@ -3671,7 +3703,12 @@ void Variant::AllocStructure()
Platform::MemoryCopy(AsBlob.Data, data, AsBlob.Length); Platform::MemoryCopy(AsBlob.Data, data, AsBlob.Length);
#else #else
Type.Type = VariantType::ManagedObject; Type.Type = VariantType::ManagedObject;
AsUint = mono_gchandle_new(instance, true);
#if USE_NETCORE
AsUint64 = MUtils::NewGCHandle(instance, true);
#else
AsUint = MUtils::NewGCHandle(instance, true);
#endif
#endif #endif
} }
else else
@@ -3763,8 +3800,10 @@ uint32 GetHash(const Variant& key)
case VariantType::Typename: case VariantType::Typename:
return GetHash((const char*)key.AsBlob.Data); return GetHash((const char*)key.AsBlob.Data);
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO #if USE_NETCORE
return key.AsUint ? (uint32)mono_object_hash(mono_gchandle_get_target(key.AsUint)) : 0; return key.AsUint64 ? (uint32)mono_object_hash(MUtils::GetGCHandleTarget(key.AsUint64)) : 0;
#elif USE_MONO
return key.AsUint ? (uint32)mono_object_hash(MUtils::GetGCHandleTarget(key.AsUint)) : 0;
#endif #endif
default: default:
return 0; return 0;

View File

@@ -4,10 +4,12 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security; using System.Security;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace FlaxEngine namespace FlaxEngine
{ {
internal sealed class DebugLogHandler : ILogHandler internal partial class DebugLogHandler : ILogHandler
{ {
/// <summary> /// <summary>
/// Occurs on sending a log message. /// Occurs on sending a log message.
@@ -64,14 +66,14 @@ namespace FlaxEngine
Debug.Logger.LogException(exception); Debug.Logger.LogException(exception);
} }
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_LogWrite", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_LogWrite(LogType level, string msg); internal static partial void Internal_LogWrite(LogType level, string msg);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_Log", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_Log(LogType level, string msg, IntPtr obj, string stackTrace); internal static partial void Internal_Log(LogType level, string msg, IntPtr obj, string stackTrace);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_LogException", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_LogException(Exception exception, IntPtr obj); internal static partial void Internal_LogException([MarshalUsing(typeof(FlaxEngine.ExceptionMarshaller))] Exception exception, IntPtr obj);
[SecuritySafeCritical] [SecuritySafeCritical]
public static string Internal_GetStackTrace() public static string Internal_GetStackTrace()

File diff suppressed because it is too large Load Diff

View File

@@ -1277,6 +1277,7 @@ bool Level::SaveAllScenes()
void Level::SaveAllScenesAsync() void Level::SaveAllScenesAsync()
{ {
SCRIPTING_EXPORT("FlaxEngine.Level::Internal_SaveAllScenesAsync")
ScopeLock lock(_sceneActionsLocker); ScopeLock lock(_sceneActionsLocker);
for (int32 i = 0; i < Scenes.Count(); i++) for (int32 i = 0; i < Scenes.Count(); i++)
_sceneActions.Enqueue(New<SaveSceneAction>(Scenes[i])); _sceneActions.Enqueue(New<SaveSceneAction>(Scenes[i]));
@@ -1381,6 +1382,7 @@ bool Level::UnloadAllScenes()
void Level::UnloadAllScenesAsync() void Level::UnloadAllScenesAsync()
{ {
SCRIPTING_EXPORT("FlaxEngine.Level::Internal_UnloadAllScenesAsync")
ScopeLock lock(_sceneActionsLocker); ScopeLock lock(_sceneActionsLocker);
_sceneActions.Enqueue(New<UnloadScenesAction>()); _sceneActions.Enqueue(New<UnloadScenesAction>());
} }

View File

@@ -50,14 +50,14 @@ int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmd
#endif #endif
Platform::PreInit(hInstance); Platform::PreInit(hInstance);
__try //__try
{ {
return Engine::Main(lpCmdLine); return Engine::Main(lpCmdLine);
} }
__except (SehExceptionHandler(GetExceptionInformation())) /*__except (SehExceptionHandler(GetExceptionInformation()))
{ {
return -1; return -1;
} }*/
} }
#endif #endif

View File

@@ -303,6 +303,7 @@ bool NetworkManager::StartHost()
void NetworkManager::Stop() void NetworkManager::Stop()
{ {
SCRIPTING_EXPORT("FlaxEngine.Networking.NetworkManager::Internal_Stop");
if (Mode == NetworkManagerMode::Offline && State == NetworkConnectionState::Offline) if (Mode == NetworkManagerMode::Offline && State == NetworkConnectionState::Offline)
return; return;
PROFILE_CPU(); PROFILE_CPU();

View File

@@ -175,6 +175,7 @@ public:
/// <param name="size">Size of the memory to copy in bytes</param> /// <param name="size">Size of the memory to copy in bytes</param>
FORCE_INLINE static void MemoryCopy(void* dst, const void* src, uint64 size) FORCE_INLINE static void MemoryCopy(void* dst, const void* src, uint64 size)
{ {
SCRIPTING_EXPORT("FlaxEngine.Utils::MemoryCopy")
memcpy(dst, src, static_cast<size_t>(size)); memcpy(dst, src, static_cast<size_t>(size));
} }
@@ -196,6 +197,7 @@ public:
/// <param name="size">Size of the memory to clear in bytes</param> /// <param name="size">Size of the memory to clear in bytes</param>
FORCE_INLINE static void MemoryClear(void* dst, uint64 size) FORCE_INLINE static void MemoryClear(void* dst, uint64 size)
{ {
SCRIPTING_EXPORT("FlaxEngine.Utils::MemoryClear")
memset(dst, 0, static_cast<size_t>(size)); memset(dst, 0, static_cast<size_t>(size));
} }
@@ -207,6 +209,7 @@ public:
/// <param name="size">Size of the memory to compare in bytes.</param> /// <param name="size">Size of the memory to compare in bytes.</param>
FORCE_INLINE static int32 MemoryCompare(const void* buf1, const void* buf2, uint64 size) FORCE_INLINE static int32 MemoryCompare(const void* buf1, const void* buf2, uint64 size)
{ {
SCRIPTING_EXPORT("FlaxEngine.Utils::MemoryCompare")
return memcmp(buf1, buf2, static_cast<size_t>(size)); return memcmp(buf1, buf2, static_cast<size_t>(size));
} }

View File

@@ -1658,6 +1658,7 @@ DragDropEffect LinuxWindow::DoDragDrop(const StringView& data)
void LinuxClipboard::Clear() void LinuxClipboard::Clear()
{ {
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
SetText(StringView::Empty); SetText(StringView::Empty);
} }

View File

@@ -110,6 +110,7 @@ Float2 MacUtils::GetScreensOrigin()
void MacClipboard::Clear() void MacClipboard::Clear()
{ {
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents]; [pasteboard clearContents];
} }

View File

@@ -16,6 +16,7 @@ typedef struct _DROPFILES
void WindowsClipboard::Clear() void WindowsClipboard::Clear()
{ {
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
OpenClipboard(nullptr); OpenClipboard(nullptr);
EmptyClipboard(); EmptyClipboard();
CloseClipboard(); CloseClipboard();

View File

@@ -699,6 +699,7 @@ void Render2D::Begin(GPUContext* context, GPUTextureView* output, GPUTextureView
void Render2D::End() void Render2D::End()
{ {
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_End")
RENDER2D_CHECK_RENDERING_STATE; RENDER2D_CHECK_RENDERING_STATE;
ASSERT(Context != nullptr && Output != nullptr); ASSERT(Context != nullptr && Output != nullptr);
ASSERT(GUIShader != nullptr); ASSERT(GUIShader != nullptr);
@@ -814,6 +815,7 @@ void Render2D::PeekTransform(Matrix3x3& transform)
void Render2D::PopTransform() void Render2D::PopTransform()
{ {
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopTransform")
RENDER2D_CHECK_RENDERING_STATE; RENDER2D_CHECK_RENDERING_STATE;
ASSERT(TransformLayersStack.HasItems()); ASSERT(TransformLayersStack.HasItems());
@@ -855,6 +857,7 @@ void Render2D::PeekClip(Rectangle& clipRect)
void Render2D::PopClip() void Render2D::PopClip()
{ {
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopClip")
RENDER2D_CHECK_RENDERING_STATE; RENDER2D_CHECK_RENDERING_STATE;
ClipLayersStack.Pop(); ClipLayersStack.Pop();
@@ -876,6 +879,7 @@ void Render2D::PeekTint(Color& tint)
void Render2D::PopTint() void Render2D::PopTint()
{ {
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopTint")
RENDER2D_CHECK_RENDERING_STATE; RENDER2D_CHECK_RENDERING_STATE;
TintLayersStack.Pop(); TintLayersStack.Pop();

View File

@@ -64,8 +64,7 @@ namespace FlaxEngine
/// <param name="rect">The rectangle to draw.</param> /// <param name="rect">The rectangle to draw.</param>
public static void DrawSprite(SpriteHandle spriteHandle, Rectangle rect) public static void DrawSprite(SpriteHandle spriteHandle, Rectangle rect)
{ {
var color = Color.White; DrawSprite(spriteHandle, rect, Color.White);
Internal_DrawSprite(ref spriteHandle, ref rect, ref color);
} }
/// <summary> /// <summary>
@@ -86,8 +85,7 @@ namespace FlaxEngine
/// <param name="rect">The rectangle to draw.</param> /// <param name="rect">The rectangle to draw.</param>
public static void DrawSpritePoint(SpriteHandle spriteHandle, Rectangle rect) public static void DrawSpritePoint(SpriteHandle spriteHandle, Rectangle rect)
{ {
var color = Color.White; DrawSpritePoint(spriteHandle, rect, Color.White);
Internal_DrawSpritePoint(ref spriteHandle, ref rect, ref color);
} }
/// <summary> /// <summary>

View File

@@ -15,7 +15,9 @@ namespace FlaxEngine
/// <param name="customActors">The custom set of actors to render. If empty, the loaded scenes will be rendered.</param> /// <param name="customActors">The custom set of actors to render. If empty, the loaded scenes will be rendered.</param>
public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List<Actor> customActors) public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List<Actor> customActors)
{ {
Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), Utils.ExtractArrayFromList(customActors)); var temp = Utils.ExtractArrayFromList(customActors);
var tempCount = temp.Length;
Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), ref temp, ref tempCount);
} }
} }
} }

View File

@@ -820,22 +820,33 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
{ {
#if USE_MONO #if USE_MONO
MonoMethodSignature* sig = mono_method_signature(method->GetNative()); MonoMethodSignature* sig = mono_method_signature(method->GetNative());
if (method->IsStatic() != signature.IsStatic || /*if (method->IsStatic() != signature.IsStatic ||
method->GetName() != signature.Name || method->GetName() != signature.Name ||
(int32)mono_signature_get_param_count(sig) != signature.Params.Count()) (int32)mono_signature_get_param_count(sig) != signature.Params.Count())
continue;*/
if (method->IsStatic() != signature.IsStatic)
continue;
if (method->GetName() != signature.Name)
continue;
if ((int32)mono_signature_get_param_count(sig) != signature.Params.Count())
continue; continue;
void* sigParams = nullptr; void* sigParams = nullptr;
mono_signature_get_params(sig, &sigParams); MonoType* type = mono_signature_get_params(sig, &sigParams);
bool isValid = true; bool isValid = true;
for (int32 paramIdx = 0; paramIdx < signature.Params.Count(); paramIdx++) int paramIdx = 0;
while (type != nullptr)
{ {
auto& param = signature.Params[paramIdx]; auto& param = signature.Params[paramIdx];
if (param.IsOut != (mono_signature_param_is_out(sig, paramIdx) != 0) || if (param.IsOut != (mono_signature_param_is_out(sig, paramIdx) != 0) ||
!VariantTypeEquals(param.Type, ((MonoType**)sigParams)[paramIdx])) !VariantTypeEquals(param.Type, type))
{ {
auto asdf = VariantTypeEquals(param.Type, type);
isValid = false; isValid = false;
break; break;
} }
type = mono_signature_get_params(sig, &sigParams);
paramIdx++;
} }
if (isValid && VariantTypeEquals(signature.ReturnType, mono_signature_get_return_type(sig))) if (isValid && VariantTypeEquals(signature.ReturnType, mono_signature_get_return_type(sig)))
return method; return method;
@@ -1187,8 +1198,6 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
#if USE_MONO #if USE_MONO
const auto mMethod = (MMethod*)method; const auto mMethod = (MMethod*)method;
MonoMethodSignature* signature = mono_method_signature(mMethod->GetNative()); MonoMethodSignature* signature = mono_method_signature(mMethod->GetNative());
void* signatureParams = nullptr;
mono_signature_get_params(signature, &signatureParams);
const int32 parametersCount = mono_signature_get_param_count(signature); const int32 parametersCount = mono_signature_get_param_count(signature);
if (paramValues.Length() != parametersCount) if (paramValues.Length() != parametersCount)
{ {
@@ -1222,20 +1231,25 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
void** params = (void**)alloca(parametersCount * sizeof(void*)); void** params = (void**)alloca(parametersCount * sizeof(void*));
bool failed = false; bool failed = false;
bool hasOutParams = false; bool hasOutParams = false;
for (int32 paramIdx = 0; paramIdx < parametersCount; paramIdx++) void* sigParams = nullptr;
MonoType* type = mono_signature_get_params(signature, &sigParams);
for (int paramIdx = 0; type != nullptr;)
{ {
auto& paramValue = paramValues[paramIdx]; auto& paramValue = paramValues[paramIdx];
const bool isOut = mono_signature_param_is_out(signature, paramIdx) != 0; const bool isOut = mono_signature_param_is_out(signature, paramIdx) != 0;
hasOutParams |= isOut; hasOutParams |= isOut;
// Marshal parameter for managed method // Marshal parameter for managed method
MType paramType(((MonoType**)signatureParams)[paramIdx]); MType paramType(type);
params[paramIdx] = MUtils::VariantToManagedArgPtr(paramValue, paramType, failed); params[paramIdx] = MUtils::VariantToManagedArgPtr(paramValue, paramType, failed);
if (failed) if (failed)
{ {
LOG(Error, "Failed to marshal parameter {5}:{4} of method '{0}.{1}' (args count: {2}), value type: {6}, value: {3}", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount, paramValue, paramType.ToString(), paramIdx, paramValue.Type); LOG(Error, "Failed to marshal parameter {5}:{4} of method '{0}.{1}' (args count: {2}), value type: {6}, value: {3}", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount, paramValue, paramType.ToString(), paramIdx, paramValue.Type);
return true; return true;
} }
type = mono_signature_get_params(signature, &sigParams);
paramIdx++;
} }
// Invoke the method // Invoke the method

View File

@@ -0,0 +1,166 @@
#include "CoreCLR.h"
#include "Engine/Core/Log.h"
#include "Engine/Platform/Platform.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Debug/DebugLog.h"
#include "Engine/Core/Collections/Dictionary.h"
#include <nethost.h>
#include <coreclr_delegates.h>
#include <hostfxr.h>
#if PLATFORM_WINDOWS
#include <combaseapi.h> // CoTask*
#undef SetEnvironmentVariable
#undef LoadLibrary
#endif
#if COMPILE_WITH_PROFILER
#endif
namespace CoreCLRPrivate
{
}
static Dictionary<String, void*> cachedFunctions;
static String assemblyName = TEXT("FlaxEngine.CSharp");
static Char* typeName = TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp");
hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config;
hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line;
hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate;
hostfxr_close_fn hostfxr_close;
load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer;
get_function_pointer_fn get_function_pointer;
hostfxr_set_error_writer_fn hostfxr_set_error_writer;
hostfxr_get_dotnet_environment_info_result_fn hostfxr_get_dotnet_environment_info_result;
hostfxr_run_app_fn hostfxr_run_app;
bool CoreCLR::LoadHostfxr(const String& library_path)
{
Platform::SetEnvironmentVariable(TEXT("DOTNET_MULTILEVEL_LOOKUP"), TEXT("0")); // FIXME: not needed with .NET 7
Platform::SetEnvironmentVariable(TEXT("DOTNET_TieredPGO"), TEXT("1"));
Platform::SetEnvironmentVariable(TEXT("DOTNET_TC_QuickJitForLoops"), TEXT("1"));
Platform::SetEnvironmentVariable(TEXT("DOTNET_ReadyToRun"), TEXT("0"));
char_t hostfxrPath[1024];
size_t hostfxrPathSize = sizeof(hostfxrPath) / sizeof(char_t);
get_hostfxr_parameters params;
params.size = sizeof(hostfxr_initialize_parameters);
params.assembly_path = library_path.Get();
params.dotnet_root = nullptr;//dotnetRoot.Get();
int rc = get_hostfxr_path(hostfxrPath, &hostfxrPathSize, &params);
if (rc != 0)
{
LOG(Error, "Failed to find hostfxr: {0:x}", (unsigned int)rc);
return false;
}
LOG(Info, "Found hostfxr in {0}", hostfxrPath);
void *hostfxr = Platform::LoadLibrary(hostfxrPath);
hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)Platform::GetProcAddress(hostfxr, "hostfxr_initialize_for_runtime_config");
hostfxr_initialize_for_dotnet_command_line = (hostfxr_initialize_for_dotnet_command_line_fn)Platform::GetProcAddress(hostfxr, "hostfxr_initialize_for_dotnet_command_line");
hostfxr_get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)Platform::GetProcAddress(hostfxr, "hostfxr_get_runtime_delegate");
hostfxr_close = (hostfxr_close_fn)Platform::GetProcAddress(hostfxr, "hostfxr_close");
hostfxr_set_error_writer = (hostfxr_set_error_writer_fn)Platform::GetProcAddress(hostfxr, "hostfxr_set_error_writer");
hostfxr_get_dotnet_environment_info_result = (hostfxr_get_dotnet_environment_info_result_fn)Platform::GetProcAddress(hostfxr, "hostfxr_get_dotnet_environment_info_result");
hostfxr_run_app = (hostfxr_run_app_fn)Platform::GetProcAddress(hostfxr, "hostfxr_run_app");
return true;
}
bool CoreCLR::InitHostfxr(const String& config_path, const String& library_path)
{
const wchar_t* argv[1] = { library_path.Get() };
hostfxr_initialize_parameters params;
params.size = sizeof(hostfxr_initialize_parameters);
params.host_path = library_path.Get();
params.dotnet_root = nullptr;//dotnetRoot.Get(); // This probably must be set
hostfxr_handle handle = nullptr;
// Initialize hosting component, hostfxr_initialize_for_dotnet_command_line is used here
// to allow self-contained engine installation to be used when needed.
int rc = hostfxr_initialize_for_dotnet_command_line(1, argv, &params, &handle);
if (rc != 0 || handle == nullptr)
{
LOG(Error, "Failed to initialize hostfxr: {0:x}", (unsigned int)rc);
hostfxr_close(handle);
return false;
}
void* pget_function_pointer = nullptr;
rc = hostfxr_get_runtime_delegate(handle, hdt_get_function_pointer, &pget_function_pointer);
if (rc != 0 || pget_function_pointer == nullptr)
LOG(Error, "Failed to get runtime delegate hdt_get_function_pointer: {0:x}", (unsigned int)rc);
hostfxr_close(handle);
get_function_pointer = (get_function_pointer_fn)pget_function_pointer;
return true;
}
void* CoreCLR::GetFunctionPointerFromDelegate(const String& methodName)
{
void* fun;
if (cachedFunctions.TryGet(methodName, fun))
return fun;
String delegateTypeName = String::Format(TEXT("{0}+{1}Delegate, {2}"), TEXT("FlaxEngine.NativeInterop"), methodName, assemblyName);
int rc = get_function_pointer(typeName, methodName.Get(), delegateTypeName.Get(), nullptr, nullptr, &fun);
if (rc != 0)
LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc);
cachedFunctions.Add(String(methodName), fun);
return fun;
}
void* CoreCLR::GetStaticMethodPointer(const String& methodName)
{
void* fun;
if (cachedFunctions.TryGet(methodName, fun))
return fun;
int rc = get_function_pointer(typeName, methodName.Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun);
if (rc != 0)
LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc);
cachedFunctions.Add(String(methodName), fun);
return fun;
}
void* CoreCLR::Allocate(int size)
{
#if PLATFORM_WINDOWS
void* ptr = CoTaskMemAlloc(size);
#else
void* ptr = malloc(size);
#endif
#if COMPILE_WITH_PROFILER
Platform::OnMemoryAlloc(ptr, size);
#endif
return ptr;
}
void CoreCLR::Free(void* ptr)
{
#if COMPILE_WITH_PROFILER
Platform::OnMemoryFree(ptr);
#endif
#if PLATFORM_WINDOWS
CoTaskMemFree(ptr);
#else
free(ptr);
#endif
}

View File

@@ -0,0 +1,48 @@
#pragma once
// FIXME
#include <ThirdParty/mono-2.0/mono/metadata/blob.h>
#include "Engine/Core/Types/String.h"
#include "Engine/Scripting/Types.h"
#if defined(_WIN32)
#define CORECLR_DELEGATE_CALLTYPE __stdcall
#else
#define CORECLR_DELEGATE_CALLTYPE
#endif
class CoreCLR
{
private:
public:
static bool LoadHostfxr(const String& library_path);
static bool InitHostfxr(const String& config_path, const String& library_path);
static void* GetFunctionPointerFromDelegate(const String& methodName);
static void* GetStaticMethodPointer(const String& methodName);
template<typename RetType, typename ...Args>
static RetType CallStaticMethodInternal(const String& methodName, Args... args)
{
typedef RetType(CORECLR_DELEGATE_CALLTYPE* fun)(Args...);
fun function = (fun)GetStaticMethodPointer(methodName);
return function(args...);
}
template<typename RetType, typename ...Args>
static RetType CallStaticMethodInternalPointer(void* funPtr, Args... args)
{
typedef RetType(CORECLR_DELEGATE_CALLTYPE* fun)(Args...);
fun function = (fun)funPtr;
return function(args...);
}
static const char* GetClassFullname(void* klass);
static void* Allocate(int size);
static void Free(void* ptr);
static gchandle NewGCHandle(void* obj, bool pinned);
static gchandle NewGCHandleWeakref(void* obj, bool track_resurrection);
static void* GetGCHandleTarget(const gchandle& gchandle);
static void FreeGCHandle(const gchandle& gchandle);
};

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,9 @@ extern "C" FLAXENGINE_API void mono_add_internal_call(const char* name, const vo
#else #else
#define ADD_INTERNAL_CALL(fullName, method) extern void DotNetAddInternalCall(const wchar_t* fullName, void* function);
#define ADD_INTERNAL_CALL(fullName, method) DotNetAddInternalCall(TEXT(fullName), (void*)(method))
#define INTERNAL_CALL_CHECK(obj) #define INTERNAL_CALL_CHECK(obj)
#define INTERNAL_CALL_CHECK_EXP(expression) #define INTERNAL_CALL_CHECK_EXP(expression)
#define INTERNAL_CALL_CHECK_RETURN(obj, defaultValue) #define INTERNAL_CALL_CHECK_RETURN(obj, defaultValue)

View File

@@ -6,17 +6,20 @@
#include "Engine/Scripting/MException.h" #include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h" #include "Engine/Scripting/ManagedCLR/MUtils.h"
#if USE_MONO
namespace UtilsInternal namespace UtilsInternal
{ {
MonoObject* ExtractArrayFromList(MonoObject* obj) MonoObject* ExtractArrayFromList(MonoObject* obj)
{ {
#if USE_MONO
auto klass = mono_object_get_class(obj); auto klass = mono_object_get_class(obj);
auto field = mono_class_get_field_from_name(klass, "_items"); auto field = mono_class_get_field_from_name(klass, "_items");
MonoObject* o; MonoObject* o;
mono_field_get_value(obj, field, &o); mono_field_get_value(obj, field, &o);
return o; return o;
#else
SCRIPTING_EXPORT("FlaxEngine.Utils::Internal_ExtractArrayFromList")
return nullptr;
#endif
} }
} }
@@ -24,6 +27,7 @@ namespace DebugLogHandlerInternal
{ {
void LogWrite(LogType level, MonoString* msgObj) void LogWrite(LogType level, MonoString* msgObj)
{ {
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_LogWrite")
StringView msg; StringView msg;
MUtils::ToString(msgObj, msg); MUtils::ToString(msgObj, msg);
Log::Logger::Write(level, msg); Log::Logger::Write(level, msg);
@@ -31,6 +35,8 @@ namespace DebugLogHandlerInternal
void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace) void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace)
{ {
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_Log")
if (msgObj == nullptr) if (msgObj == nullptr)
return; return;
@@ -45,8 +51,11 @@ namespace DebugLogHandlerInternal
Log::Logger::Write(level, msg); Log::Logger::Write(level, msg);
} }
void LogException(MonoException* exception, ScriptingObject* obj) void LogException(MonoException* exception, ScriptingObject* obj)
{ {
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_LogException")
#if USE_MONO
if (exception == nullptr) if (exception == nullptr)
return; return;
@@ -57,13 +66,16 @@ namespace DebugLogHandlerInternal
// Print exception including inner exceptions // Print exception including inner exceptions
// TODO: maybe option for build to threat warnings and errors as fatal errors? // TODO: maybe option for build to threat warnings and errors as fatal errors?
ex.Log(LogType::Warning, objName.GetText()); ex.Log(LogType::Warning, objName.GetText());
#endif
} }
} }
namespace FlaxLogWriterInternal namespace FlaxLogWriterInternal
{ {
void WriteStringToLog(MonoString* msgObj) void WriteStringToLog(MonoString* msgObj)
{ {
SCRIPTING_EXPORT("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog")
if (msgObj == nullptr) if (msgObj == nullptr)
return; return;
StringView msg; StringView msg;
@@ -72,8 +84,6 @@ namespace FlaxLogWriterInternal
} }
} }
#endif
void registerFlaxEngineInternalCalls() void registerFlaxEngineInternalCalls()
{ {
AnimGraphExecutor::initRuntime(); AnimGraphExecutor::initRuntime();

View File

@@ -86,7 +86,11 @@ struct FLAXENGINE_API ManagedDictionary
CHECK_RETURN(makeGenericMethod, nullptr); CHECK_RETURN(makeGenericMethod, nullptr);
auto genericType = MUtils::GetType(StdTypesContainer::Instance()->DictionaryClass->GetNative()); auto genericType = MUtils::GetType(StdTypesContainer::Instance()->DictionaryClass->GetNative());
#if USE_NETCORE
auto genericArgs = mono_array_new(domain, mono_get_intptr_class(), 2);
#else
auto genericArgs = mono_array_new(domain, mono_get_object_class(), 2); auto genericArgs = mono_array_new(domain, mono_get_object_class(), 2);
#endif
mono_array_set(genericArgs, MonoReflectionType*, 0, mono_type_get_object(domain, keyType)); mono_array_set(genericArgs, MonoReflectionType*, 0, mono_type_get_object(domain, keyType));
mono_array_set(genericArgs, MonoReflectionType*, 1, mono_type_get_object(domain, valueType)); mono_array_set(genericArgs, MonoReflectionType*, 1, mono_type_get_object(domain, valueType));

View File

@@ -12,6 +12,10 @@
#include "Engine/Platform/Thread.h" #include "Engine/Platform/Thread.h"
#include "Engine/Scripting/MException.h" #include "Engine/Scripting/MException.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Platform/FileSystem.h"
#if USE_NETCORE
#include "Engine/Scripting/DotNet/CoreCLR.h"
#endif
#if USE_MONO #if USE_MONO
#ifdef USE_MONO_AOT_MODULE #ifdef USE_MONO_AOT_MODULE
#include "Engine/Core/Types/TimeSpan.h" #include "Engine/Core/Types/TimeSpan.h"
@@ -52,6 +56,9 @@ MDomain* MCore::GetActiveDomain()
MDomain* MCore::CreateDomain(const MString& domainName) MDomain* MCore::CreateDomain(const MString& domainName)
{ {
#if USE_NETCORE
return nullptr;
#else
#if USE_MONO_AOT #if USE_MONO_AOT
LOG(Fatal, "Scripts can run only in single domain mode with AOT mode enabled."); LOG(Fatal, "Scripts can run only in single domain mode with AOT mode enabled.");
return nullptr; return nullptr;
@@ -74,10 +81,13 @@ MDomain* MCore::CreateDomain(const MString& domainName)
#endif #endif
MDomains.Add(domain); MDomains.Add(domain);
return domain; return domain;
#endif
} }
void MCore::UnloadDomain(const MString& domainName) void MCore::UnloadDomain(const MString& domainName)
{ {
#if USE_NETCORE
#else
int32 i = 0; int32 i = 0;
for (; i < MDomains.Count(); i++) for (; i < MDomains.Count(); i++)
{ {
@@ -103,9 +113,46 @@ void MCore::UnloadDomain(const MString& domainName)
#endif #endif
Delete(domain); Delete(domain);
MDomains.RemoveAtKeepOrder(i); MDomains.RemoveAtKeepOrder(i);
#endif
} }
#if USE_MONO #if USE_NETCORE
bool MCore::LoadEngine()
{
const String csharpLibraryPath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
const String csharpRuntimeConfigPath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.runtimeconfig.json");
if (!FileSystem::FileExists(csharpLibraryPath))
LOG(Fatal, "LoadHostfxr failed");
if (!FileSystem::FileExists(csharpRuntimeConfigPath))
LOG(Fatal, "LoadHostfxr failed");
// Locate hostfxr and load it
if (!CoreCLR::LoadHostfxr(csharpLibraryPath))
LOG(Fatal, "LoadHostfxr failed");
// Initialize hosting component
if (!CoreCLR::InitHostfxr(csharpRuntimeConfigPath, csharpLibraryPath))
LOG(Fatal, "LoadAssembly failed");
const String hostExecutable = Platform::GetExecutableFilePath();
CoreCLR::CallStaticMethodInternal<void, const wchar_t*>(TEXT("Init"), hostExecutable.Get());
MRootDomain = New<MDomain>("Root");
MDomains.Add(MRootDomain);
/*char* buildInfo = mono_get_runtime_build_info();
LOG(Info, "Managed runtime version: {0} (.NET)", String(buildInfo));
mono_free(buildInfo);*/
return false;
}
void MCore::UnloadEngine()
{
MDomains.ClearDelete();
MRootDomain = nullptr;
}
#elif USE_MONO
#if 0 #if 0
@@ -518,7 +565,7 @@ bool MCore::LoadEngine()
} }
#endif #endif
// Init Mono // Init managed runtime
#if PLATFORM_ANDROID #if PLATFORM_ANDROID
const char* monoVersion = "mobile"; const char* monoVersion = "mobile";
#else #else
@@ -530,6 +577,7 @@ bool MCore::LoadEngine()
MRootDomain->_monoDomain = monoRootDomain; MRootDomain->_monoDomain = monoRootDomain;
MDomains.Add(MRootDomain); MDomains.Add(MRootDomain);
#if !USE_NETCORE
auto exePath = Platform::GetExecutableFilePath(); auto exePath = Platform::GetExecutableFilePath();
auto configDir = StringUtils::GetDirectoryName(exePath).ToStringAnsi(); auto configDir = StringUtils::GetDirectoryName(exePath).ToStringAnsi();
auto configFilename = StringUtils::GetFileName(exePath).ToStringAnsi() + ".config"; auto configFilename = StringUtils::GetFileName(exePath).ToStringAnsi() + ".config";
@@ -542,10 +590,11 @@ bool MCore::LoadEngine()
#endif #endif
mono_domain_set_config(monoRootDomain, configDir.Get(), configFilename.Get()); mono_domain_set_config(monoRootDomain, configDir.Get(), configFilename.Get());
mono_thread_set_main(mono_thread_current()); mono_thread_set_main(mono_thread_current());
#endif
// Info // Info
char* buildInfo = mono_get_runtime_build_info(); char* buildInfo = mono_get_runtime_build_info();
LOG(Info, "Mono version: {0}", String(buildInfo)); LOG(Info, "Managed runtime version: {0} (Mono)", String(buildInfo));
mono_free(buildInfo); mono_free(buildInfo);
return false; return false;
@@ -672,7 +721,7 @@ void MCore::GC::WaitForPendingFinalizers()
#endif #endif
} }
#if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB #if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB && !USE_NETCORE
// Export Mono functions // Export Mono functions
#pragma comment(linker, "/export:mono_add_internal_call") #pragma comment(linker, "/export:mono_add_internal_call")

View File

@@ -84,7 +84,7 @@ public:
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is the fastest way of calling managed code. /// This is the fastest way of calling managed code.
/// Get thunk from class if you want to call static method. You to call it from method of a instance wrapper to call a specific instance. /// Get thunk from class if you want to call static method. You need to call it from method of a instance wrapper to call a specific instance.
/// </remarks> /// </remarks>
/// <returns>The method thunk pointer.</returns> /// <returns>The method thunk pointer.</returns>
void* GetThunk(); void* GetThunk();

View File

@@ -24,6 +24,10 @@
#include "Engine/Utilities/StringConverter.h" #include "Engine/Utilities/StringConverter.h"
#include "Engine/Content/Asset.h" #include "Engine/Content/Asset.h"
#if USE_NETCORE
#include "Engine/Scripting/DotNet/CoreCLR.h"
#endif
#if USE_MONO #if USE_MONO
// Inlined mono private types to access MonoType internals // Inlined mono private types to access MonoType internals
@@ -356,11 +360,17 @@ Variant MUtils::UnboxVariant(MonoObject* value)
return Variant::Null; return Variant::Null;
const auto& stdTypes = *StdTypesContainer::Instance(); const auto& stdTypes = *StdTypesContainer::Instance();
const auto klass = mono_object_get_class(value); const auto klass = mono_object_get_class(value);
MonoType* monoType = mono_class_get_type(klass);
const MonoTypeEnum monoTypeId = (MonoTypeEnum)mono_type_get_type(monoType);
#if USE_NETCORE
void* unboxed = mono_object_unbox(value);
#else
void* unboxed = (byte*)value + sizeof(MonoObject); void* unboxed = (byte*)value + sizeof(MonoObject);
const MonoType* monoType = mono_class_get_type(klass); #endif
// Fast type detection for in-built types // Fast type detection for in-built types
switch (monoType->type) switch (monoTypeId)
{ {
case MONO_TYPE_VOID: case MONO_TYPE_VOID:
return Variant(VariantType(VariantType::Void)); return Variant(VariantType(VariantType::Void));
@@ -660,7 +670,11 @@ MonoObject* MUtils::BoxVariant(const Variant& value)
case VariantType::Guid: case VariantType::Guid:
return mono_value_box(mono_domain_get(), stdTypes.GuidClass->GetNative(), (void*)&value.AsData); return mono_value_box(mono_domain_get(), stdTypes.GuidClass->GetNative(), (void*)&value.AsData);
case VariantType::String: case VariantType::String:
#if USE_NETCORE
return (MonoObject*)MUtils::ToString((StringView)value); return (MonoObject*)MUtils::ToString((StringView)value);
#else
return (MonoObject*)MUtils::ToString((StringView)value);
#endif
case VariantType::Quaternion: case VariantType::Quaternion:
return mono_value_box(mono_domain_get(), stdTypes.QuaternionClass->GetNative(), (void*)&value.AsData); return mono_value_box(mono_domain_get(), stdTypes.QuaternionClass->GetNative(), (void*)&value.AsData);
case VariantType::BoundingSphere: case VariantType::BoundingSphere:
@@ -844,7 +858,11 @@ MonoObject* MUtils::BoxVariant(const Variant& value)
return nullptr; return nullptr;
} }
case VariantType::ManagedObject: case VariantType::ManagedObject:
return value.AsUint ? mono_gchandle_get_target(value.AsUint) : nullptr; #if USE_NETCORE
return value.AsUint64 ? MUtils::GetGCHandleTarget(value.AsUint64) : nullptr;
#else
return value.AsUint ? MUtils::GetGCHandleTarget(value.AsUint) : nullptr;
#endif
case VariantType::Typename: case VariantType::Typename:
{ {
const auto klass = Scripting::FindClassNative((StringAnsiView)value); const auto klass = Scripting::FindClassNative((StringAnsiView)value);
@@ -869,6 +887,9 @@ void MUtils::GetClassFullname(MonoObject* obj, MString& fullname)
void MUtils::GetClassFullname(MonoClass* monoClass, MString& fullname) void MUtils::GetClassFullname(MonoClass* monoClass, MString& fullname)
{ {
#if USE_NETCORE
fullname = CoreCLR::GetClassFullname(monoClass);
#else
static MString plusStr("+"); static MString plusStr("+");
static MString dotStr("."); static MString dotStr(".");
@@ -906,6 +927,7 @@ void MUtils::GetClassFullname(MonoClass* monoClass, MString& fullname)
} }
fullname += ']'; fullname += ']';
} }
#endif
} }
void MUtils::GetClassFullname(MonoReflectionType* type, MString& fullname) void MUtils::GetClassFullname(MonoReflectionType* type, MString& fullname)
@@ -1138,7 +1160,8 @@ BytesContainer MUtils::LinkArray(MonoArray* arrayObj)
void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed) void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed)
{ {
// Convert Variant into matching managed type and return pointer to data for the method invocation // Convert Variant into matching managed type and return pointer to data for the method invocation
switch (type.GetNative()->type) MonoTypeEnum monoType = (MonoTypeEnum)mono_type_get_type(type.GetNative());
switch (monoType)
{ {
case MONO_TYPE_BOOLEAN: case MONO_TYPE_BOOLEAN:
if (value.Type.Type != VariantType::Bool) if (value.Type.Type != VariantType::Bool)
@@ -1183,7 +1206,11 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
return MUtils::ToString((StringView)value); return MUtils::ToString((StringView)value);
case MONO_TYPE_VALUETYPE: case MONO_TYPE_VALUETYPE:
{ {
#if !USE_NETCORE
MonoClass* klass = type.GetNative()->data.klass; MonoClass* klass = type.GetNative()->data.klass;
#else
MonoClass* klass = mono_type_get_class(type.GetNative());
#endif
if (mono_class_is_enum(klass)) if (mono_class_is_enum(klass))
{ {
if (value.Type.Type != VariantType::Enum) if (value.Type.Type != VariantType::Enum)
@@ -1305,15 +1332,52 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
MonoObject* MUtils::ToManaged(const Version& value) MonoObject* MUtils::ToManaged(const Version& value)
{ {
#if USE_NETCORE
auto scriptingClass = Scripting::GetStaticClass();
CHECK_RETURN(scriptingClass, nullptr);
auto versionToManaged = scriptingClass->GetMethod("VersionToManaged", 4);
CHECK_RETURN(versionToManaged, nullptr);
int major = value.Major();
int minor = value.Minor();
int build = value.Build();
int revision = value.Revision();
void* params[4];
params[0] = &major;
params[1] = &minor;
params[2] = &build;
params[3] = &revision;
auto obj = versionToManaged->Invoke(nullptr, params, nullptr);
#else
auto obj = mono_object_new(mono_domain_get(), Scripting::FindClassNative("System.Version")); auto obj = mono_object_new(mono_domain_get(), Scripting::FindClassNative("System.Version"));
Platform::MemoryCopy((byte*)obj + sizeof(MonoObject), &value, sizeof(Version)); Platform::MemoryCopy((byte*)obj + sizeof(MonoObject), &value, sizeof(Version));
#endif
return obj; return obj;
} }
Version MUtils::ToNative(MonoObject* value) Version MUtils::ToNative(MonoObject* value)
{ {
if (value) if (value)
#if USE_NETCORE
{
auto ver = Version();
auto scriptingClass = Scripting::GetStaticClass();
CHECK_RETURN(scriptingClass, ver);
auto versionToNative = scriptingClass->GetMethod("VersionToNative", 2);
CHECK_RETURN(versionToNative, ver);
void* params[2];
params[0] = value;
params[1] = &ver;
versionToNative->Invoke(nullptr, params, nullptr);
return ver;
}
#else
return *(Version*)((byte*)value + sizeof(MonoObject)); return *(Version*)((byte*)value + sizeof(MonoObject));
#endif
return Version(); return Version();
} }

View File

@@ -14,6 +14,11 @@
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#if USE_NETCORE
#include "Engine/Scripting/DotNet/CoreCLR.h"
#include "Engine/Core/Collections/BitArray.h"
#endif
struct Version; struct Version;
namespace MUtils namespace MUtils
@@ -53,6 +58,19 @@ struct MConverter
void ToNativeArray(Array<T, AllocationType>& result, MonoArray* data, int32 length); void ToNativeArray(Array<T, AllocationType>& result, MonoArray* data, int32 length);
}; };
#if USE_NETCORE
// Pass-through converter for ScriptingObjects (passed as GCHandles)
template<>
struct MConverter<void*>
{
void Unbox(void*& result, MonoObject* data)
{
CHECK(data);
result = data;
}
};
#endif
// Converter for POD types (that can use raw memory copy). // Converter for POD types (that can use raw memory copy).
template<typename T> template<typename T>
struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class ScriptingObject, typename TRemovePointer<T>::Type>>>::Value>::Type> struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class ScriptingObject, typename TRemovePointer<T>::Type>>>::Value>::Type>
@@ -86,12 +104,22 @@ struct MConverter<String>
{ {
MonoObject* Box(const String& data, MonoClass* klass) MonoObject* Box(const String& data, MonoClass* klass)
{ {
#if USE_NETCORE
MonoString* str = MUtils::ToString(data);
return mono_value_box(nullptr, klass, str);
#else
return (MonoObject*)MUtils::ToString(data); return (MonoObject*)MUtils::ToString(data);
#endif
} }
void Unbox(String& result, MonoObject* data) void Unbox(String& result, MonoObject* data)
{ {
#if USE_NETCORE
MonoString* str = (MonoString*)mono_object_unbox(data);
result = MUtils::ToString(str);
#else
result = MUtils::ToString((MonoString*)data); result = MUtils::ToString((MonoString*)data);
#endif
} }
void ToManagedArray(MonoArray* result, const Span<String>& data) void ToManagedArray(MonoArray* result, const Span<String>& data)
@@ -564,6 +592,72 @@ namespace MUtils
return ToArray(Span<String>(data.Get(), data.Count()), mono_get_string_class()); return ToArray(Span<String>(data.Get(), data.Count()), mono_get_string_class());
} }
#if USE_NETCORE
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container.
/// The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
FORCE_INLINE bool* ToBoolArray(const Array<bool>& data)
{
bool* arr = (bool*)CoreCLR::Allocate(data.Count() * sizeof(bool));
memcpy(arr, data.Get(), data.Count() * sizeof(bool));
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container.
/// The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
FORCE_INLINE bool* ToBoolArray(const BitArray<>& data)
{
bool* arr = (bool*)CoreCLR::Allocate(data.Count() * sizeof(bool));
//memcpy(arr, data.Get(), data.Count() * sizeof(bool));
for (int i = 0; i < data.Count(); i++)
arr[i] = data[i];
return arr;
}
#endif
FORCE_INLINE gchandle NewGCHandle(MonoObject* obj, bool pinned)
{
#if USE_NETCORE
return CoreCLR::NewGCHandle(obj, pinned);
#else
return mono_gchandle_new(obj, pinned);
#endif
}
FORCE_INLINE gchandle NewGCHandleWeakref(MonoObject* obj, bool track_resurrection)
{
#if USE_NETCORE
return CoreCLR::NewGCHandleWeakref(obj, track_resurrection);
#else
return mono_gchandle_new_weak_ref(obj, track_resurrection);
#endif
}
FORCE_INLINE MonoObject* GetGCHandleTarget(const gchandle& handle)
{
#if USE_NETCORE
return (MonoObject*)CoreCLR::GetGCHandleTarget(handle);
#else
return mono_gchandle_get_target(handle);
#endif
}
FORCE_INLINE void FreeGCHandle(const gchandle& handle)
{
#if USE_NETCORE
CoreCLR::FreeGCHandle(handle);
#else
mono_gchandle_free(handle);
#endif
}
extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed); extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed);
extern MonoObject* ToManaged(const Version& value); extern MonoObject* ToManaged(const Version& value);
extern Version ToNative(MonoObject* value); extern Version ToNative(MonoObject* value);

View File

@@ -2,6 +2,8 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
// ReSharper disable UnassignedReadonlyField // ReSharper disable UnassignedReadonlyField
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
@@ -13,13 +15,14 @@ namespace FlaxEngine
/// Base class for all objects Flax can reference. Every object has unique identifier. /// Base class for all objects Flax can reference. Every object has unique identifier.
/// </summary> /// </summary>
[Serializable] [Serializable]
public abstract class Object [NativeMarshalling(typeof(ObjectMarshaller))]
public abstract partial class Object
{ {
/// <summary> /// <summary>
/// The pointer to the unmanaged object (native C++ instance). /// The pointer to the unmanaged object (native C++ instance).
/// </summary> /// </summary>
[NonSerialized] [NonSerialized]
protected readonly IntPtr __unmanagedPtr; internal readonly IntPtr __unmanagedPtr;
/// <summary> /// <summary>
/// The object unique identifier. /// The object unique identifier.
@@ -248,35 +251,35 @@ namespace FlaxEngine
#region Internal Calls #region Internal Calls
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Create1", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern Object Internal_Create1(Type type); internal static partial Object Internal_Create1([MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Create2", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern Object Internal_Create2(string typeName); internal static partial Object Internal_Create2(string typeName);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_ManagedInstanceCreated(Object managedInstance); internal static partial void Internal_ManagedInstanceCreated(Object managedInstance);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_ManagedInstanceDeleted(IntPtr nativeInstance); internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Destroy", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_Destroy(IntPtr obj, float timeLeft); internal static partial void Internal_Destroy(IntPtr obj, float timeLeft);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_GetTypeName", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern string Internal_GetTypeName(IntPtr obj); internal static partial string Internal_GetTypeName(IntPtr obj);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_FindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern Object Internal_FindObject(ref Guid id, Type type); internal static partial Object Internal_FindObject(ref Guid id, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_TryFindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern Object Internal_TryFindObject(ref Guid id, Type type); internal static partial Object Internal_TryFindObject(ref Guid id, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ChangeID", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern void Internal_ChangeID(IntPtr obj, ref Guid id); internal static partial void Internal_ChangeID(IntPtr obj, ref Guid id);
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_GetUnmanagedInterface", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
internal static extern IntPtr Internal_GetUnmanagedInterface(IntPtr obj, Type type); internal static partial IntPtr Internal_GetUnmanagedInterface(IntPtr obj, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
#endregion #endregion
} }

View File

@@ -40,6 +40,7 @@ namespace ProfilerInternal
void BeginEvent(MonoString* nameObj) void BeginEvent(MonoString* nameObj)
{ {
SCRIPTING_EXPORT("FlaxEngine.Profiler::BeginEvent")
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
const StringView name((const Char*)mono_string_chars(nameObj), mono_string_length(nameObj)); const StringView name((const Char*)mono_string_chars(nameObj), mono_string_length(nameObj));
ProfilerCPU::BeginEvent(*name); ProfilerCPU::BeginEvent(*name);
@@ -78,6 +79,7 @@ namespace ProfilerInternal
void EndEvent() void EndEvent()
{ {
SCRIPTING_EXPORT("FlaxEngine.Profiler::EndEvent")
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
#if TRACY_ENABLE #if TRACY_ENABLE
tracy::ScopedZone::End(); tracy::ScopedZone::End();
@@ -88,6 +90,7 @@ namespace ProfilerInternal
void BeginEventGPU(MonoString* nameObj) void BeginEventGPU(MonoString* nameObj)
{ {
SCRIPTING_EXPORT("FlaxEngine.Profiler::BeginEventGPU")
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
const auto index = ProfilerGPU::BeginEvent((const Char*)mono_string_chars(nameObj)); const auto index = ProfilerGPU::BeginEvent((const Char*)mono_string_chars(nameObj));
ManagedEventsGPU.Push(index); ManagedEventsGPU.Push(index);
@@ -96,6 +99,7 @@ namespace ProfilerInternal
void EndEventGPU() void EndEventGPU()
{ {
SCRIPTING_EXPORT("FlaxEngine.Profiler::EndEventGPU")
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
const auto index = ManagedEventsGPU.Pop(); const auto index = ManagedEventsGPU.Pop();
ProfilerGPU::EndEvent(index); ProfilerGPU::EndEvent(index);
@@ -111,16 +115,19 @@ public:
#if USE_MONO #if USE_MONO
static bool HasGameModulesLoaded() static bool HasGameModulesLoaded()
{ {
SCRIPTING_EXPORT("FlaxEngine.Scripting::HasGameModulesLoaded")
return Scripting::HasGameModulesLoaded(); return Scripting::HasGameModulesLoaded();
} }
static bool IsTypeFromGameScripts(MonoReflectionType* type) static bool IsTypeFromGameScripts(MonoReflectionType* type)
{ {
SCRIPTING_EXPORT("FlaxEngine.Scripting::IsTypeFromGameScripts")
return Scripting::IsTypeFromGameScripts(Scripting::FindClass(MUtils::GetClass(type))); return Scripting::IsTypeFromGameScripts(Scripting::FindClass(MUtils::GetClass(type)));
} }
static void FlushRemovedObjects() static void FlushRemovedObjects()
{ {
SCRIPTING_EXPORT("FlaxEngine.Scripting::FlushRemovedObjects")
ASSERT(IsInMainThread()); ASSERT(IsInMainThread());
ObjectsRemovalService::Flush(); ObjectsRemovalService::Flush();
} }

View File

@@ -903,6 +903,7 @@ ScriptingObject* Scripting::FindObject(const MObject* managedInstance)
void Scripting::OnManagedInstanceDeleted(ScriptingObject* obj) void Scripting::OnManagedInstanceDeleted(ScriptingObject* obj)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_ManagedInstanceDeleted")
PROFILE_CPU(); PROFILE_CPU();
ASSERT(obj); ASSERT(obj);

View File

@@ -5,6 +5,8 @@ using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -65,7 +67,7 @@ namespace FlaxEngine
/// <summary> /// <summary>
/// C# scripting service. /// C# scripting service.
/// </summary> /// </summary>
public static class Scripting public static partial class Scripting
{ {
private static readonly List<Action> UpdateActions = new List<Action>(); private static readonly List<Action> UpdateActions = new List<Action>();
private static readonly MainThreadTaskScheduler MainThreadTaskScheduler = new MainThreadTaskScheduler(); private static readonly MainThreadTaskScheduler MainThreadTaskScheduler = new MainThreadTaskScheduler();
@@ -207,6 +209,21 @@ namespace FlaxEngine
return result; return result;
} }
internal static IntPtr VersionToManaged(int major, int minor, int build, int revision)
{
Version version = new Version(major, minor, Math.Max(build, 0), Math.Max(revision, 0));
return GCHandle.ToIntPtr(GCHandle.Alloc(version));
}
internal static void VersionToNative(IntPtr versionHandle, IntPtr nativePtr)
{
Version version = (Version)GCHandle.FromIntPtr(versionHandle).Target;
Marshal.WriteInt32(nativePtr, 0, version.Major);
Marshal.WriteInt32(nativePtr, 4, version.Minor);
Marshal.WriteInt32(nativePtr, 8, version.Build);
Marshal.WriteInt32(nativePtr, 12, version.Revision);
}
private static void CreateGuiStyle() private static void CreateGuiStyle()
{ {
var style = new Style var style = new Style
@@ -283,21 +300,23 @@ namespace FlaxEngine
/// Returns true if game scripts assembly has been loaded. /// Returns true if game scripts assembly has been loaded.
/// </summary> /// </summary>
/// <returns>True if game scripts assembly is loaded, otherwise false.</returns> /// <returns>True if game scripts assembly is loaded, otherwise false.</returns>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Scripting::HasGameModulesLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern bool HasGameModulesLoaded(); [return: MarshalAs(UnmanagedType.U1)]
public static partial bool HasGameModulesLoaded();
/// <summary> /// <summary>
/// Returns true if given type is from one of the game scripts assemblies. /// Returns true if given type is from one of the game scripts assemblies.
/// </summary> /// </summary>
/// <returns>True if the type is from game assembly, otherwise false.</returns> /// <returns>True if the type is from game assembly, otherwise false.</returns>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Scripting::IsTypeFromGameScripts", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern bool IsTypeFromGameScripts(Type type); [return: MarshalAs(UnmanagedType.U1)]
public static partial bool IsTypeFromGameScripts([MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
/// <summary> /// <summary>
/// Flushes the removed objects (disposed objects using Object.Destroy). /// Flushes the removed objects (disposed objects using Object.Destroy).
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Scripting::FlushRemovedObjects", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern void FlushRemovedObjects(); public static partial void FlushRemovedObjects();
} }
/// <summary> /// <summary>
@@ -306,32 +325,32 @@ namespace FlaxEngine
/// <remarks> /// <remarks>
/// Profiler is available in the editor and Debug/Development builds. Release builds don't have profiling tools. /// Profiler is available in the editor and Debug/Development builds. Release builds don't have profiling tools.
/// </remarks> /// </remarks>
public static class Profiler public static partial class Profiler
{ {
/// <summary> /// <summary>
/// Begins profiling a piece of code with a custom label. /// Begins profiling a piece of code with a custom label.
/// </summary> /// </summary>
/// <param name="name">The name of the event.</param> /// <param name="name">The name of the event.</param>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::BeginEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern void BeginEvent(string name); public static partial void BeginEvent(string name);
/// <summary> /// <summary>
/// Ends profiling an event. /// Ends profiling an event.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::EndEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern void EndEvent(); public static partial void EndEvent();
/// <summary> /// <summary>
/// Begins GPU profiling a piece of code with a custom label. /// Begins GPU profiling a piece of code with a custom label.
/// </summary> /// </summary>
/// <param name="name">The name of the event.</param> /// <param name="name">The name of the event.</param>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::BeginEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern void BeginEventGPU(string name); public static partial void BeginEventGPU(string name);
/// <summary> /// <summary>
/// Ends GPU profiling an event. /// Ends GPU profiling an event.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::EndEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
public static extern void EndEventGPU(); public static partial void EndEventGPU();
} }
} }

View File

@@ -68,9 +68,13 @@ ScriptingObject* ScriptingObject::NewObject(const ScriptingTypeHandle& typeHandl
MObject* ScriptingObject::GetManagedInstance() const MObject* ScriptingObject::GetManagedInstance() const
{ {
#if USE_NETCORE
const gchandle handle = Platform::AtomicRead((int64*)&_gcHandle);
#elif USE_MONO
const gchandle handle = Platform::AtomicRead((int32*)&_gcHandle);
#endif
#if USE_MONO #if USE_MONO
const int32 handle = Platform::AtomicRead((int32*)&_gcHandle); return handle ? MUtils::GetGCHandleTarget(handle) : nullptr;
return handle ? mono_gchandle_get_target(handle) : nullptr;
#else #else
return nullptr; return nullptr;
#endif #endif
@@ -211,7 +215,7 @@ void ScriptingObject::OnManagedInstanceDeleted()
if (_gcHandle) if (_gcHandle)
{ {
#if USE_MONO #if USE_MONO
mono_gchandle_free(_gcHandle); MUtils::FreeGCHandle(_gcHandle);
#endif #endif
_gcHandle = 0; _gcHandle = 0;
} }
@@ -236,10 +240,15 @@ bool ScriptingObject::CreateManaged()
if (!managedInstance) if (!managedInstance)
return true; return true;
// Prevent form object GC destruction // Prevent from object GC destruction
auto handle = mono_gchandle_new(managedInstance, false); auto handle = MUtils::NewGCHandle(managedInstance, false);
#if USE_NETCORE
auto oldHandle = Platform::InterlockedCompareExchange((int64*)&_gcHandle, *(int64*)&handle, 0);
if (*(uint64*)&oldHandle != 0)
#else
auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0); auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0);
if (*(uint32*)&oldHandle != 0) if (*(uint32*)&oldHandle != 0)
#endif
{ {
// Other thread already created the object before // Other thread already created the object before
if (const auto monoClass = GetClass()) if (const auto monoClass = GetClass())
@@ -252,7 +261,7 @@ bool ScriptingObject::CreateManaged()
monoUnmanagedPtrField->SetValue(managedInstance, &param); monoUnmanagedPtrField->SetValue(managedInstance, &param);
} }
} }
mono_gchandle_free(handle); MUtils::FreeGCHandle(handle);
return true; return true;
} }
#endif #endif
@@ -337,7 +346,7 @@ void ScriptingObject::DestroyManaged()
// Clear the handle // Clear the handle
if (_gcHandle) if (_gcHandle)
{ {
mono_gchandle_free(_gcHandle); MUtils::FreeGCHandle(_gcHandle);
_gcHandle = 0; _gcHandle = 0;
} }
#else #else
@@ -448,9 +457,14 @@ bool ManagedScriptingObject::CreateManaged()
return true; return true;
// Cache the GC handle to the object (used to track the target object because it can be moved in a memory) // Cache the GC handle to the object (used to track the target object because it can be moved in a memory)
auto handle = mono_gchandle_new_weakref(managedInstance, false); auto handle = MUtils::NewGCHandleWeakref(managedInstance, false);
#if USE_NETCORE
auto oldHandle = Platform::InterlockedCompareExchange((int64*)&_gcHandle, *(int64*)&handle, 0);
if (*(uint64*)&oldHandle != 0)
#else
auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0); auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0);
if (*(uint32*)&oldHandle != 0) if (*(uint32*)&oldHandle != 0)
#endif
{ {
// Other thread already created the object before // Other thread already created the object before
if (const auto monoClass = GetClass()) if (const auto monoClass = GetClass())
@@ -463,7 +477,7 @@ bool ManagedScriptingObject::CreateManaged()
monoUnmanagedPtrField->SetValue(managedInstance, &param); monoUnmanagedPtrField->SetValue(managedInstance, &param);
} }
} }
mono_gchandle_free(handle); MUtils::FreeGCHandle(handle);
return true; return true;
} }
#endif #endif
@@ -487,6 +501,7 @@ public:
static MonoObject* Create1(MonoReflectionType* type) static MonoObject* Create1(MonoReflectionType* type)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_Create1")
// Peek class for that type (handle generic class cases) // Peek class for that type (handle generic class cases)
if (!type) if (!type)
DebugLog::ThrowArgumentNull("type"); DebugLog::ThrowArgumentNull("type");
@@ -550,6 +565,7 @@ public:
static MonoObject* Create2(MonoString* typeNameObj) static MonoObject* Create2(MonoString* typeNameObj)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_Create2")
// Get typename // Get typename
if (typeNameObj == nullptr) if (typeNameObj == nullptr)
DebugLog::ThrowArgumentNull("typeName"); DebugLog::ThrowArgumentNull("typeName");
@@ -587,6 +603,7 @@ public:
static void ManagedInstanceCreated(MonoObject* managedInstance) static void ManagedInstanceCreated(MonoObject* managedInstance)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_ManagedInstanceCreated")
MonoClass* typeClass = mono_object_get_class(managedInstance); MonoClass* typeClass = mono_object_get_class(managedInstance);
// Get the assembly with that class // Get the assembly with that class
@@ -625,12 +642,12 @@ public:
if (auto* managedScriptingObject = dynamic_cast<ManagedScriptingObject*>(obj)) if (auto* managedScriptingObject = dynamic_cast<ManagedScriptingObject*>(obj))
{ {
// Managed // Managed
managedScriptingObject->_gcHandle = mono_gchandle_new_weakref(managedInstance, false); managedScriptingObject->_gcHandle = MUtils::NewGCHandleWeakref(managedInstance, false);
} }
else else
{ {
// Persistent // Persistent
obj->_gcHandle = mono_gchandle_new(managedInstance, false); obj->_gcHandle = MUtils::NewGCHandle(managedInstance, false);
} }
MClass* monoClass = obj->GetClass(); MClass* monoClass = obj->GetClass();
@@ -657,6 +674,7 @@ public:
static void Destroy(ScriptingObject* obj, float timeLeft) static void Destroy(ScriptingObject* obj, float timeLeft)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_Destroy")
// Use scaled game time for removing actors/scripts by the user (maybe expose it to the api?) // Use scaled game time for removing actors/scripts by the user (maybe expose it to the api?)
const bool useGameTime = timeLeft > ZeroTolerance; const bool useGameTime = timeLeft > ZeroTolerance;
@@ -666,12 +684,14 @@ public:
static MonoString* GetTypeName(ScriptingObject* obj) static MonoString* GetTypeName(ScriptingObject* obj)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_GetTypeName")
INTERNAL_CALL_CHECK_RETURN(obj, nullptr); INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
return MUtils::ToString(obj->GetType().Fullname); return MUtils::ToString(obj->GetType().Fullname);
} }
static MonoObject* FindObject(Guid* id, MonoReflectionType* type) static MonoObject* FindObject(Guid* id, MonoReflectionType* type)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_FindObject")
if (!id->IsValid()) if (!id->IsValid())
return nullptr; return nullptr;
auto klass = MUtils::GetClass(type); auto klass = MUtils::GetClass(type);
@@ -701,6 +721,7 @@ public:
static MonoObject* TryFindObject(Guid* id, MonoReflectionType* type) static MonoObject* TryFindObject(Guid* id, MonoReflectionType* type)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_TryFindObject")
ScriptingObject* obj = Scripting::TryFindObject(*id); ScriptingObject* obj = Scripting::TryFindObject(*id);
if (obj && !obj->Is(MUtils::GetClass(type))) if (obj && !obj->Is(MUtils::GetClass(type)))
obj = nullptr; obj = nullptr;
@@ -709,12 +730,14 @@ public:
static void ChangeID(ScriptingObject* obj, Guid* id) static void ChangeID(ScriptingObject* obj, Guid* id)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_ChangeID")
INTERNAL_CALL_CHECK(obj); INTERNAL_CALL_CHECK(obj);
obj->ChangeID(*id); obj->ChangeID(*id);
} }
static void* GetUnmanagedInterface(ScriptingObject* obj, MonoReflectionType* type) static void* GetUnmanagedInterface(ScriptingObject* obj, MonoReflectionType* type)
{ {
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_GetUnmanagedInterface")
if (obj && type) if (obj && type)
{ {
auto typeClass = MUtils::GetClass(type); auto typeClass = MUtils::GetClass(type);

View File

@@ -21,7 +21,7 @@ public:
protected: protected:
uint32 _gcHandle; gchandle _gcHandle;
ScriptingTypeHandle _type; ScriptingTypeHandle _type;
Guid _id; Guid _id;

View File

@@ -31,7 +31,7 @@ typedef void MObject;
#else #else
#define USE_MONO 1 #define USE_MONO 1
#define USE_NETCORE 0 #define USE_NETCORE 1
// Enables using single (root) app domain for the user scripts // Enables using single (root) app domain for the user scripts
#define USE_SCRIPTING_SINGLE_DOMAIN 1 #define USE_SCRIPTING_SINGLE_DOMAIN 1
@@ -49,6 +49,17 @@ typedef void MObject;
#define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE #define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE
#endif #endif
#if USE_NETCORE
struct _MonoDomain {};
struct _MonoThread {};
#endif
#if USE_NETCORE
typedef unsigned long long gchandle;
#else
typedef uint32 gchandle;
#endif
// Mono types declarations // Mono types declarations
typedef struct _MonoClass MonoClass; typedef struct _MonoClass MonoClass;
typedef struct _MonoDomain MonoDomain; typedef struct _MonoDomain MonoDomain;

View File

@@ -6,13 +6,15 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace FlaxEngine namespace FlaxEngine
{ {
/// <summary> /// <summary>
/// Class with helper functions. /// Class with helper functions.
/// </summary> /// </summary>
public static class Utils public static partial class Utils
{ {
/// <summary> /// <summary>
/// Copies data from one memory location to another using an unmanaged memory pointers. /// Copies data from one memory location to another using an unmanaged memory pointers.
@@ -35,8 +37,8 @@ namespace FlaxEngine
/// <param name="source">The source location.</param> /// <param name="source">The source location.</param>
/// <param name="destination">The destination location.</param> /// <param name="destination">The destination location.</param>
/// <param name="length">The length (amount of bytes to copy).</param> /// <param name="length">The length (amount of bytes to copy).</param>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::MemoryCopy")]
public static extern void MemoryCopy(IntPtr destination, IntPtr source, ulong length); public static partial void MemoryCopy(IntPtr destination, IntPtr source, ulong length);
/// <summary> /// <summary>
/// Clears the memory region with zeros. /// Clears the memory region with zeros.
@@ -44,8 +46,8 @@ namespace FlaxEngine
/// <remarks>Uses low-level platform impl.</remarks> /// <remarks>Uses low-level platform impl.</remarks>
/// <param name="dst">Destination memory address</param> /// <param name="dst">Destination memory address</param>
/// <param name="size">Size of the memory to clear in bytes</param> /// <param name="size">Size of the memory to clear in bytes</param>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::MemoryClear")]
public static extern void MemoryClear(IntPtr dst, ulong size); public static partial void MemoryClear(IntPtr dst, ulong size);
/// <summary> /// <summary>
/// Compares two blocks of the memory. /// Compares two blocks of the memory.
@@ -54,8 +56,8 @@ namespace FlaxEngine
/// <param name="buf1">The first buffer address.</param> /// <param name="buf1">The first buffer address.</param>
/// <param name="buf2">The second buffer address.</param> /// <param name="buf2">The second buffer address.</param>
/// <param name="size">Size of the memory to compare in bytes.</param> /// <param name="size">Size of the memory to compare in bytes.</param>
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::MemoryCompare")]
public static extern int MemoryCompare(IntPtr buf1, IntPtr buf2, ulong size); public static partial int MemoryCompare(IntPtr buf1, IntPtr buf2, ulong size);
/// <summary> /// <summary>
/// Rounds the floating point value up to 1 decimal place. /// Rounds the floating point value up to 1 decimal place.
@@ -94,7 +96,11 @@ namespace FlaxEngine
/// <returns>The empty array object.</returns> /// <returns>The empty array object.</returns>
public static T[] GetEmptyArray<T>() public static T[] GetEmptyArray<T>()
{ {
#if USE_NETCORE
return Array.Empty<T>();
#else
return Enumerable.Empty<T>() as T[]; return Enumerable.Empty<T>() as T[];
#endif
} }
/// <summary> /// <summary>
@@ -209,10 +215,50 @@ namespace FlaxEngine
return result; return result;
} }
/// <summary>
/// Gets the location of the assembly.
/// </summary>
/// <param name="assembly">The assembly.</param>
/// <returns>Path in the filesystem</returns>
public static string GetAssemblyLocation(Assembly assembly)
{
#if USE_NETCORE
if (!string.IsNullOrEmpty(assembly.Location))
return assembly.Location;
if (NativeInterop.AssemblyLocations.TryGetValue(assembly.FullName, out string assemblyLocation))
return assemblyLocation;
return null;
#else
return assembly.Location;
#endif
}
#if USE_MONO
internal static T[] ExtractArrayFromList<T>(List<T> list) internal static T[] ExtractArrayFromList<T>(List<T> list)
{ {
return list != null ? (T[])Internal_ExtractArrayFromList(list) : null; return list != null ? (T[])Internal_ExtractArrayFromList(list) : null;
} }
#else
private class ExtractArrayFromListContext<T>
{
public static FieldInfo? itemsField;
}
internal static T[] ExtractArrayFromList<T>(List<T> list)
{
if (list == null)
return null;
if (ExtractArrayFromListContext<T>.itemsField == null)
{
Type listType = typeof(List<T>);
ExtractArrayFromListContext<T>.itemsField = listType.GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance);
}
return (T[])ExtractArrayFromListContext<T>.itemsField.GetValue(list); // boxing is slower;
}
#endif
internal static Float2[] ConvertCollection(Vector2[] v) internal static Float2[] ConvertCollection(Vector2[] v)
{ {
@@ -295,8 +341,9 @@ namespace FlaxEngine
return result; return result;
} }
[MethodImpl(MethodImplOptions.InternalCall)] [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::Internal_ExtractArrayFromList")]
internal static extern Array Internal_ExtractArrayFromList(object list); [return: MarshalUsing(typeof(FlaxEngine.SystemArrayMarshaller))]
internal static partial Array Internal_ExtractArrayFromList([MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))] object list);
/// <summary> /// <summary>
/// Reads the color from the binary stream. /// Reads the color from the binary stream.

View File

@@ -4,11 +4,14 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
#if FLAX_EDITOR
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Utilities;
#endif
using FlaxEngine; using FlaxEngine;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace FlaxEditor.Utilities namespace FlaxEngine.Utilities
{ {
/// <summary> /// <summary>
/// Editor utilities and helper functions for Variant type. /// Editor utilities and helper functions for Variant type.
@@ -76,6 +79,7 @@ namespace FlaxEditor.Utilities
#endif #endif
} }
#if FLAX_EDITOR
internal static VariantType ToVariantType(this Type type) internal static VariantType ToVariantType(this Type type)
{ {
VariantType variantType; VariantType variantType;
@@ -107,7 +111,9 @@ namespace FlaxEditor.Utilities
variantType = VariantType.Pointer; variantType = VariantType.Pointer;
else if (type == typeof(string)) else if (type == typeof(string))
variantType = VariantType.String; variantType = VariantType.String;
else if (type == typeof(Type) || type == typeof(ScriptType)) else if (type == typeof(Type))
variantType = VariantType.Typename;
else if (type == typeof(ScriptType))
variantType = VariantType.Typename; variantType = VariantType.Typename;
else if (typeof(Asset).IsAssignableFrom(type)) else if (typeof(Asset).IsAssignableFrom(type))
variantType = VariantType.Asset; variantType = VariantType.Asset;
@@ -1286,5 +1292,6 @@ namespace FlaxEditor.Utilities
stream.WriteEndObject(); stream.WriteEndObject();
} }
#endif
} }
} }

View File

@@ -0,0 +1,6 @@
#include "VisjectScript.h"
VisjectScript::VisjectScript(const SpawnParams& params)
: Script(params)
{
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/Script.h"
/// <summary>
///
/// </summary>
API_CLASS(Namespace = "FlaxEngine.Visject") class FLAXENGINE_API VisjectScript : public Script
{
API_AUTO_SERIALIZATION();
DECLARE_SCRIPTING_TYPE(VisjectScript);
};

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using BuildData = Flax.Build.Builder.BuildData; using BuildData = Flax.Build.Builder.BuildData;
namespace Flax.Build.Bindings namespace Flax.Build.Bindings
@@ -171,7 +172,11 @@ namespace Flax.Build.Bindings
// Skip for collections // Skip for collections
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer" || typeInfo.Type == "Dictionary" || typeInfo.Type == "HashSet") && typeInfo.GenericArgs != null) if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer" || typeInfo.Type == "Dictionary" || typeInfo.Type == "HashSet") && typeInfo.GenericArgs != null)
#if !USE_NETCORE
return false; return false;
#else
return true;
#endif
// Skip for special types // Skip for special types
if (typeInfo.GenericArgs == null) if (typeInfo.GenericArgs == null)
@@ -219,6 +224,40 @@ namespace Flax.Build.Bindings
return false; return false;
} }
#if USE_NETCORE
/// <summary>
/// Check if structure contains unblittable types that would require custom marshaller for the structure.
/// </summary>
public static bool UseCustomMarshalling(BuildData buildData, StructureInfo structureInfo, ApiTypeInfo caller)
{
if (structureInfo.Fields.Any(x => !x.IsStatic &&
(x.Type.IsObjectRef || x.Type.Type == "Dictionary" || x.Type.Type == "Version")
&& x.Type.Type != "uint8" && x.Type.Type != "byte"))
{
return true;
}
foreach (var field in structureInfo.Fields)
{
if (field.Type.Type == structureInfo.FullNameNative)
continue;
if (field.IsStatic)
continue;
if (field.Type.Type == "String")
return true;
var fieldApiType = FindApiTypeInfo(buildData, field.Type, caller);
if (fieldApiType is StructureInfo fieldStructureInfo && UseCustomMarshalling(buildData, fieldStructureInfo, caller))
return true;
else if (fieldApiType is ClassInfo)
return true;
}
return false;
}
#endif
/// <summary> /// <summary>
/// Finds the API type information. /// Finds the API type information.
/// </summary> /// </summary>

View File

@@ -278,15 +278,15 @@ namespace Flax.Build.Bindings
} }
// Object reference property // Object reference property
if ((typeInfo.Type == "ScriptingObjectReference" || if (typeInfo.IsObjectRef)
typeInfo.Type == "AssetReference" ||
typeInfo.Type == "WeakAssetReference" ||
typeInfo.Type == "SoftAssetReference" ||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller); return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller);
// Array or Span or DataContainer // Array or Span or DataContainer
#if USE_NETCORE
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer" || typeInfo.Type == "MonoArray") && typeInfo.GenericArgs != null)
#else
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null) if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
#endif
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller) + "[]"; return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller) + "[]";
// Dictionary // Dictionary
@@ -361,11 +361,7 @@ namespace Flax.Build.Bindings
} }
// Object reference property // Object reference property
if ((typeInfo.Type == "ScriptingObjectReference" || if (typeInfo.IsObjectRef)
typeInfo.Type == "AssetReference" ||
typeInfo.Type == "WeakAssetReference" ||
typeInfo.Type == "SoftAssetReference" ||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
return "IntPtr"; return "IntPtr";
// Function // Function
@@ -419,11 +415,7 @@ namespace Flax.Build.Bindings
} }
// Object reference property // Object reference property
if ((typeInfo.Type == "ScriptingObjectReference" || if (typeInfo.IsObjectRef)
typeInfo.Type == "AssetReference" ||
typeInfo.Type == "WeakAssetReference" ||
typeInfo.Type == "SoftAssetReference" ||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
return "FlaxEngine.Object.GetUnmanagedPtr({0})"; return "FlaxEngine.Object.GetUnmanagedPtr({0})";
// Default // Default
@@ -443,8 +435,38 @@ namespace Flax.Build.Bindings
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller); returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller);
} }
#if USE_NETCORE
string returnMarshalType = "";
if (returnValueType == "bool")
returnMarshalType = "MarshalAs(UnmanagedType.U1)";
else if (returnValueType == "System.Type")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.SystemTypeMarshaller))";
else if (returnValueType == "CultureInfo")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.CultureInfoMarshaller))";
else if (functionInfo.ReturnType.Type == "Variant")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))";
else if (FindApiTypeInfo(buildData, functionInfo.ReturnType, caller)?.IsInterface ?? false)
{
// Interfaces are not supported by NativeMarshallingAttribute, marshal the parameter
returnMarshalType = $"MarshalUsing(typeof({returnValueType}Marshaller))";
}
else if (returnValueType == "byte[]")
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 0)";
else if (returnValueType == "bool[]")
{
// Boolean arrays does not support custom marshalling for some unkown reason...
returnMarshalType = $"MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = {functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters?.Count ?? 0)})";
}
#endif
#if !USE_NETCORE
contents.AppendLine().Append(indent).Append("[MethodImpl(MethodImplOptions.InternalCall)]"); contents.AppendLine().Append(indent).Append("[MethodImpl(MethodImplOptions.InternalCall)]");
contents.AppendLine().Append(indent).Append("internal static extern "); contents.AppendLine().Append(indent).Append("internal static partial ");
#else
contents.AppendLine().Append(indent).Append($"[LibraryImport(\"FlaxEngine\", EntryPoint = \"{caller.FullNameManaged}::Internal_{functionInfo.UniqueName}\", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]");
if (!string.IsNullOrEmpty(returnMarshalType))
contents.AppendLine().Append(indent).Append($"[return: {returnMarshalType}]");
contents.AppendLine().Append(indent).Append("internal static partial ");
#endif
contents.Append(returnValueType).Append(" Internal_").Append(functionInfo.UniqueName).Append('('); contents.Append(returnValueType).Append(" Internal_").Append(functionInfo.UniqueName).Append('(');
var separator = false; var separator = false;
@@ -461,6 +483,30 @@ namespace Flax.Build.Bindings
separator = true; separator = true;
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller); var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller);
#if USE_NETCORE
string parameterMarshalType = "";
if (nativeType == "System.Type")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.SystemTypeMarshaller))";
else if (parameterInfo.Type.Type == "CultureInfo")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.CultureInfoMarshaller))";
else if (parameterInfo.Type.Type == "Variant") // object
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))";
else if (parameterInfo.Type.Type == "MonoArray")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.SystemArrayMarshaller))";
else if (parameterInfo.Type.Type == "Array" && parameterInfo.Type.GenericArgs.Count > 0 && parameterInfo.Type.GenericArgs[0].Type == "bool")
parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == parameterInfo.Name + "Count"))})";
else if (parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BytesContainer" || nativeType == "Array")
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (nativeType == "bool")
parameterMarshalType = "MarshalAs(UnmanagedType.U1)";
else if (nativeType == "char")
parameterMarshalType = "MarshalAs(UnmanagedType.I2)";
if (!string.IsNullOrEmpty(parameterMarshalType))
contents.Append($"[{parameterMarshalType}] ");
#endif
if (parameterInfo.IsOut) if (parameterInfo.IsOut)
contents.Append("out "); contents.Append("out ");
else if (parameterInfo.IsRef || UsePassByReference(buildData, parameterInfo.Type, caller)) else if (parameterInfo.IsRef || UsePassByReference(buildData, parameterInfo.Type, caller))
@@ -484,6 +530,21 @@ namespace Flax.Build.Bindings
separator = true; separator = true;
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller); var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller);
#if USE_NETCORE
string parameterMarshalType = "";
if (parameterInfo.IsOut && parameterInfo.DefaultValue == "var resultAsRef")
{
if (functionInfo.Glue.UseResultReferenceCount)
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.DictionaryMarshaller<,>), ConstantElementCount = 0)";
}
if (nativeType == "System.Type")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.SystemTypeMarshaller))";
if (!string.IsNullOrEmpty(parameterMarshalType))
contents.Append($"[{parameterMarshalType}] ");
#endif
if (parameterInfo.IsOut) if (parameterInfo.IsOut)
contents.Append("out "); contents.Append("out ");
else if (parameterInfo.IsRef || UsePassByReference(buildData, parameterInfo.Type, caller)) else if (parameterInfo.IsRef || UsePassByReference(buildData, parameterInfo.Type, caller))
@@ -500,6 +561,17 @@ namespace Flax.Build.Bindings
private static void GenerateCSharpWrapperFunctionCall(BuildData buildData, StringBuilder contents, ApiTypeInfo caller, FunctionInfo functionInfo, bool isSetter = false) private static void GenerateCSharpWrapperFunctionCall(BuildData buildData, StringBuilder contents, ApiTypeInfo caller, FunctionInfo functionInfo, bool isSetter = false)
{ {
#if USE_NETCORE
for (var i = 0; i < functionInfo.Parameters.Count; i++)
{
var parameterInfo = functionInfo.Parameters[i];
if (parameterInfo.Type.IsArray || parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "BytesContainer" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BitArray")
{
if (!parameterInfo.IsOut)
contents.Append($"var {parameterInfo.Name}Count = {(isSetter ? "value" : parameterInfo.Name)}?.Length ?? 0; ");
}
}
#endif
if (functionInfo.Glue.UseReferenceForResult) if (functionInfo.Glue.UseReferenceForResult)
{ {
} }
@@ -613,6 +685,9 @@ namespace Flax.Build.Bindings
{ {
// Write attribute for C++ calling code // Write attribute for C++ calling code
contents.Append(indent).AppendLine("[Unmanaged]"); contents.Append(indent).AppendLine("[Unmanaged]");
// Skip boilerplate code when using debugger
//contents.Append(indent).AppendLine("[System.Diagnostics.DebuggerStepThrough]");
} }
if (isDeprecated || apiTypeInfo.IsDeprecated) if (isDeprecated || apiTypeInfo.IsDeprecated)
{ {
@@ -698,6 +773,15 @@ namespace Flax.Build.Bindings
// Class begin // Class begin
GenerateCSharpAttributes(buildData, contents, indent, classInfo, useUnmanaged); GenerateCSharpAttributes(buildData, contents, indent, classInfo, useUnmanaged);
#if USE_NETCORE
string marshallerName = "";
if (!classInfo.IsStatic)
{
marshallerName = classInfo.Name + "Marshaller";
contents.Append(indent).AppendLine($"[NativeMarshalling(typeof({marshallerName}))]");
//contents.Append(indent).AppendLine($"[NativeMarshalling(typeof(FlaxEngine.GCHandleMarshaller2<{classInfo.Name}>.GCHandleMarshaller3<{classInfo.Name}>))]");
}
#endif
contents.Append(indent); contents.Append(indent);
GenerateCSharpAccessLevel(contents, classInfo.Access); GenerateCSharpAccessLevel(contents, classInfo.Access);
if (classInfo.IsStatic) if (classInfo.IsStatic)
@@ -862,11 +946,19 @@ namespace Flax.Build.Bindings
contents.Append(indent).Append('}').AppendLine(); contents.Append(indent).Append('}').AppendLine();
contents.AppendLine(); contents.AppendLine();
#if !USE_NETCORE
contents.Append(indent).Append("[MethodImpl(MethodImplOptions.InternalCall)]").AppendLine(); contents.Append(indent).Append("[MethodImpl(MethodImplOptions.InternalCall)]").AppendLine();
contents.Append(indent).Append($"internal static extern void Internal_{eventInfo.Name}_Bind("); contents.Append(indent).Append($"internal static extern void Internal_{eventInfo.Name}_Bind(");
if (!eventInfo.IsStatic) if (!eventInfo.IsStatic)
contents.Append("IntPtr obj, "); contents.Append("IntPtr obj, ");
contents.Append("bool bind);"); contents.Append("bool bind);");
#else
contents.Append(indent).Append($"[LibraryImport(\"FlaxEngine\", EntryPoint = \"{classInfo.FullNameManaged}::Internal_{eventInfo.Name}_Bind\", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]").AppendLine();
contents.Append(indent).Append($"internal static partial void Internal_{eventInfo.Name}_Bind(");
if (!eventInfo.IsStatic)
contents.Append("IntPtr obj, ");
contents.Append("[MarshalAs(UnmanagedType.U1)] bool bind);");
#endif
contents.AppendLine(); contents.AppendLine();
} }
@@ -1100,6 +1192,64 @@ namespace Flax.Build.Bindings
indent = indent.Substring(0, indent.Length - 4); indent = indent.Substring(0, indent.Length - 4);
contents.AppendLine(indent + "}"); contents.AppendLine(indent + "}");
#if USE_NETCORE
if (!string.IsNullOrEmpty(marshallerName))
{
string marshallerDefinition = $$"""
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.ManagedToUnmanagedIn, typeof({{marshallerName}}.ManagedToNative))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.UnmanagedToManagedOut, typeof({{marshallerName}}.ManagedToNative))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.ElementIn, typeof({{marshallerName}}.ManagedToNative))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.ManagedToUnmanagedOut, typeof({{marshallerName}}.NativeToManaged))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.UnmanagedToManagedIn, typeof({{marshallerName}}.NativeToManaged))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.ElementOut, typeof({{marshallerName}}.NativeToManaged))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.ManagedToUnmanagedRef, typeof({{marshallerName}}.Bidirectional))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.UnmanagedToManagedRef, typeof({{marshallerName}}.Bidirectional))]
[CustomMarshaller(typeof({{classInfo.Name}}), MarshalMode.ElementRef, typeof({{marshallerName}}))]
internal static class {{marshallerName}}
{
public static class NativeToManaged
{
public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})GCHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged);
public static void Free(IntPtr unmanaged) => GCHandleMarshaller.NativeToManaged.Free(unmanaged);
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => GCHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed);
public static void Free(IntPtr unmanaged) => GCHandleMarshaller.ManagedToNative.Free(unmanaged);
}
public struct Bidirectional
{
GCHandleMarshaller.Bidirectional marsh;
public void FromManaged({{classInfo.Name}} managed) => marsh.FromManaged(managed);
public IntPtr ToUnmanaged() => marsh.ToUnmanaged();
public void FromUnmanaged(IntPtr unmanaged) => marsh.FromUnmanaged(unmanaged);
public {{classInfo.Name}} ToManaged() => ({{classInfo.Name}})marsh.ToManaged();
public void Free() => marsh.Free();
}
internal static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => ({{classInfo.Name}})GCHandleMarshaller.ConvertToManaged(unmanaged);
internal static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);
internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);
internal static {{classInfo.Name}} ToManaged(IntPtr managed) => ({{classInfo.Name}})GCHandleMarshaller.ToManaged(managed);
internal static IntPtr ToNative({{classInfo.Name}} managed) => GCHandleMarshaller.ToNative(managed);
}
""";
contents.AppendLine(marshallerDefinition);
/*contents.AppendLine();
contents.Append(indent).AppendLine("/// <summary>");
contents.Append(indent).AppendLine("/// ");
contents.Append(indent).AppendLine("/// </summary>");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({classInfo.Name}), MarshalMode.Default, typeof({marshallerName}))]");
contents.Append(indent).AppendLine($"public static class {marshallerName}");
contents.Append(indent).AppendLine("{");
contents.Append(indent + " ").AppendLine($"internal static {classInfo.Name} ConvertToManaged(IntPtr unmanaged) => ({classInfo.Name})GCHandleMarshaller.ConvertToManaged(unmanaged);");
contents.Append(indent + " ").AppendLine($"internal static IntPtr ConvertToUnmanaged({classInfo.Name} managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);");
contents.Append(indent + " ").AppendLine("internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);");
contents.Append(indent).AppendLine("}");*/
}
#endif
// Namespace end // Namespace end
if (!string.IsNullOrEmpty(classInfo.Namespace)) if (!string.IsNullOrEmpty(classInfo.Namespace))
{ {
@@ -1119,13 +1269,318 @@ namespace Flax.Build.Bindings
contents.AppendLine("{"); contents.AppendLine("{");
indent += " "; indent += " ";
} }
#if USE_NETCORE
// Generate blittable structure
string structNativeMarshaling = "";
if (UseCustomMarshalling(buildData, structureInfo, structureInfo))
{
string marshallerName = structureInfo.Name + "Marshaller";
structNativeMarshaling = $"[NativeMarshalling(typeof({marshallerName}))]";
contents.Append(indent).AppendLine($"/// <summary>");
contents.Append(indent).AppendLine($"/// Marshaller for unblittable type <see cref=\"{structureInfo.Name}\"/>.");
contents.Append(indent).AppendLine($"/// </summary>");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.ManagedToUnmanagedIn, typeof({marshallerName}.ManagedToNative))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.UnmanagedToManagedOut, typeof({marshallerName}.ManagedToNative))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.ElementIn, typeof({marshallerName}.ManagedToNative))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.ManagedToUnmanagedOut, typeof({marshallerName}.NativeToManaged))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.UnmanagedToManagedIn, typeof({marshallerName}.NativeToManaged))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.ElementOut, typeof({marshallerName}.NativeToManaged))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.ManagedToUnmanagedRef, typeof({marshallerName}.Bidirectional))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.UnmanagedToManagedRef, typeof({marshallerName}.Bidirectional))]");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({structureInfo.Name}), MarshalMode.ElementRef, typeof({marshallerName}))]");
contents.Append(indent).AppendLine($"internal static unsafe class {marshallerName}");
contents.Append(indent).AppendLine("{");
indent += " ";
StringBuilder toManagedContent = new StringBuilder();
StringBuilder toNativeContent = new StringBuilder();
StringBuilder freeContents = new StringBuilder();
StringBuilder freeContents2 = new StringBuilder();
{
// Native struct begin
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, true);
contents.Append(indent).AppendLine("[StructLayout(LayoutKind.Sequential)]");
contents.Append(indent);
contents.Append("internal struct ").Append(structureInfo.Name).Append("Internal");
if (structureInfo.BaseType != null && structureInfo.IsPod)
contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = structureInfo.BaseType.Name }, structureInfo));
contents.AppendLine();
contents.Append(indent + "{");
indent += " ";
toNativeContent.Append($"return new {structureInfo.Name}Internal() {{ ");
toManagedContent.Append($"return new {structureInfo.Name}() {{ ");
bool useSeparator = false;
foreach (var fieldInfo in structureInfo.Fields)
{
if (fieldInfo.IsStatic || fieldInfo.IsConstexpr)
continue;
contents.AppendLine();
string type, originalType;
if (fieldInfo.Type.IsArray && (fieldInfo.NoArray || structureInfo.IsPod))
{
// Fixed-size array that needs to be inlined into structure instead of passing it as managed array
fieldInfo.Type.IsArray = false;
originalType = type = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo);
fieldInfo.Type.IsArray = true;
}
else
originalType = type = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo);
contents.Append(indent);
if (fieldInfo.Access == AccessLevel.Public)
contents.Append("public ");
else if (fieldInfo.Access == AccessLevel.Protected)
contents.Append("protected ");
else if (fieldInfo.Access == AccessLevel.Private)
contents.Append("private ");
if (fieldInfo.IsConstexpr)
contents.Append("const ");
else if (fieldInfo.IsStatic)
contents.Append("static ");
var apiType = FindApiTypeInfo(buildData, fieldInfo.Type, structureInfo);
bool internalType = apiType is StructureInfo fieldStructureInfo && UseCustomMarshalling(buildData, fieldStructureInfo, structureInfo);
string internalTypeMarshaler = "";
if (fieldInfo.Type.IsArray && (fieldInfo.NoArray || structureInfo.IsPod))
{
contents.Append(type).Append(' ').Append(fieldInfo.Name + "0;").AppendLine();
for (int i = 1; i < fieldInfo.Type.ArraySize; i++)
{
contents.AppendLine();
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic);
contents.Append(indent);
if (fieldInfo.Access == AccessLevel.Public)
contents.Append("public ");
else if (fieldInfo.Access == AccessLevel.Protected)
contents.Append("protected ");
else if (fieldInfo.Access == AccessLevel.Private)
contents.Append("private ");
if (fieldInfo.IsStatic)
contents.Append("static ");
contents.Append(type).Append(' ').Append(fieldInfo.Name + i).Append(';').AppendLine();
}
}
else
{
if (fieldInfo.Type.IsObjectRef || fieldInfo.Type.Type == "Dictionary")
type = "IntPtr";
else if (fieldInfo.Type.IsPtr && !originalType.EndsWith("*"))
type = "IntPtr";
else if (fieldInfo.Type.Type == "Array")
{
type = "IntPtr";
apiType = FindApiTypeInfo(buildData, fieldInfo.Type.GenericArgs[0], structureInfo);
internalType = apiType is StructureInfo elementStructureInfo && UseCustomMarshalling(buildData, elementStructureInfo, structureInfo);
}
else if (fieldInfo.Type.Type == "Version")
type = "IntPtr";
else if (type == "string")
type = "IntPtr";
else if (type == "bool")
type = "byte";
else if (type == "object")
type = "VariantNative";
else if (internalType)
{
internalTypeMarshaler = type + "Marshaller";
type = $"{internalTypeMarshaler}.{type}Internal";
}
//else if (type == "Guid")
// type = "GuidNative";
contents.Append(type).Append(' ').Append(fieldInfo.Name);
contents.Append(';').AppendLine();
}
// Generate struct constructor/getter and deconstructor/setter function
if (fieldInfo.NoArray && fieldInfo.Type.IsArray)
continue;
if (type == "VariantNative")
continue; // FIXME
if (useSeparator)
{
toManagedContent.Append(", ");
toNativeContent.Append(", ");
freeContents2.Append("");
freeContents.Append("");
}
useSeparator = true;
toManagedContent.Append(fieldInfo.Name);
toManagedContent.Append(" = ");
toNativeContent.Append(fieldInfo.Name);
toNativeContent.Append(" = ");
if (fieldInfo.Type.IsObjectRef)
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({fieldInfo.Type.GenericArgs[0].Type})GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null");
toNativeContent.Append($"managed.{fieldInfo.Name} != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
// ScriptingObject handle is passed from native side, do not release it
//freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
}
else if (fieldInfo.Type.Type == "ScriptingObject")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? (FlaxEngine.Object)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null");
toNativeContent.Append($"managed.{fieldInfo.Name} != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
}
else if (fieldInfo.Type.IsPtr && originalType != "IntPtr" && !originalType.EndsWith("*"))
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null");
toNativeContent.Append($"managed.{fieldInfo.Name} != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak)) : IntPtr.Zero");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
}
else if (fieldInfo.Type.Type == "Dictionary")
{
string dictionaryArgs = String.Join(", ",
fieldInfo.Type.GenericArgs.Select(x => CSharpNativeToManagedBasicTypes.ContainsKey(x.Type) ? CSharpNativeToManagedBasicTypes[x.Type] : x.Type).ToArray());
toManagedContent.Append(
$"managed.{fieldInfo.Name} != IntPtr.Zero ? (System.Collections.Generic.{fieldInfo.Type.Type}<{dictionaryArgs}>)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null");
toNativeContent.Append(
$"GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak))");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
}
else if (fieldInfo.Type.Type == "Array")
{
if (internalType)
{
string originalElementType = originalType.Substring(0, originalType.Length - 2);
string originalElementTypeMarshaller = originalElementType + "Marshaller";
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.NativeArrayToManagedArray<{originalElementType}, {originalElementTypeMarshaller}.{originalElementType}Internal>(((ManagedArray)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).array as {originalElementTypeMarshaller}.{originalElementType}Internal[], {originalElementTypeMarshaller}.ToManaged) : null");
toNativeContent.Append($"GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(managed.{fieldInfo.Name}), GCHandleType.Weak))");
}
else if (fieldInfo.Type.GenericArgs[0].IsObjectRef)
{
string originalElementType = originalType.Substring(0, originalType.Length - 2);
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>((ManagedArray)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null");
toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(NativeInterop.ManagedArrayToGCHandleArray(managed.{fieldInfo.Name})), GCHandleType.Weak)) : IntPtr.Zero");
}
else
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})(((ManagedArray)GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target).array) : null");
toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? GCHandle.ToIntPtr(GCHandle.Alloc(ManagedArray.Get(managed.{fieldInfo.Name}), GCHandleType.Weak)) : IntPtr.Zero");
}
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Unsafe.Unbox<ManagedArray>(handle.Target).Release(); handle.Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle handle = GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Unsafe.Unbox<ManagedArray>(handle.Target).Release(); handle.Free(); }}");
}
else if (fieldInfo.Type.Type == "Version")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? ({originalType})GCHandle.FromIntPtr(managed.{fieldInfo.Name}).Target : null");
toNativeContent.Append($"GCHandle.ToIntPtr(GCHandle.Alloc(managed.{fieldInfo.Name}, GCHandleType.Weak))");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ GCHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
}
else if (originalType == "string")
{
toManagedContent.Append($"ManagedString.ToManaged(managed.{fieldInfo.Name})");
toNativeContent.Append($"ManagedString.ToNative(managed.{fieldInfo.Name})");
freeContents.AppendLine($"ManagedString.Free(unmanaged.{fieldInfo.Name});");
freeContents2.AppendLine($"ManagedString.Free(unmanaged.{fieldInfo.Name});");
}
else if (originalType == "bool")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != 0");
toNativeContent.Append($"managed.{fieldInfo.Name} ? (byte)1 : (byte)0");
}
else if (internalType)
{
toManagedContent.Append($"{internalTypeMarshaler}.ToManaged(managed.{fieldInfo.Name})");
toNativeContent.Append($"{internalTypeMarshaler}.ToNative(managed.{fieldInfo.Name})");
freeContents.AppendLine($"{internalTypeMarshaler}.Free(unmanaged.{fieldInfo.Name});");
freeContents2.AppendLine($"{internalTypeMarshaler}.Free(unmanaged.{fieldInfo.Name});");
}
/*else if (originalType == "Guid")
{
toManagedContent.Append("(Guid)managed.").Append(fieldInfo.Name);
toNativeContent.Append("(GuidNative)managed.").Append(fieldInfo.Name);
}*/
else
{
toManagedContent.Append("managed.").Append(fieldInfo.Name);
toNativeContent.Append("managed.").Append(fieldInfo.Name);
}
}
// Native struct end
indent = indent.Substring(0, indent.Length - 4);
contents.AppendLine(indent + "}").AppendLine();
toManagedContent.AppendLine(" };");
toNativeContent.AppendLine(" };");
}
var indent2 = indent + " ";
var indent3 = indent2 + " ";
// NativeToManaged stateless shape
// NOTE: GCHandles of FlaxEngine.Object must not be released in this case
contents.Append(indent).AppendLine($"public static class NativeToManaged").Append(indent).AppendLine("{");
contents.Append(indent2).AppendLine($"public static {structureInfo.Name} ConvertToManaged({structureInfo.Name}Internal unmanaged) => {marshallerName}.ToManaged(unmanaged);");
contents.Append(indent2).AppendLine($"public static void Free({structureInfo.Name}Internal unmanaged)");
contents.Append(indent2).AppendLine("{").Append(indent3).AppendLine(freeContents2.Replace("\n", "\n" + indent3).ToString().TrimEnd()).Append(indent2).AppendLine("}");
contents.Append(indent).AppendLine("}");
// ManagedToNative stateless shape
contents.Append(indent).AppendLine($"public static class ManagedToNative").Append(indent).AppendLine("{");
contents.Append(indent2).AppendLine($"public static {structureInfo.Name}Internal ConvertToUnmanaged({structureInfo.Name} managed) => {marshallerName}.ToNative(managed);");
contents.Append(indent2).AppendLine($"public static void Free({structureInfo.Name}Internal unmanaged) => {marshallerName}.Free(unmanaged);");
contents.Append(indent).AppendLine("}");
// Bidirectional stateful shape
// NOTE: GCHandles of FlaxEngine.Object must not be released unless they were allocated by this marshaller
contents.Append(indent).AppendLine($"public struct Bidirectional").Append(indent).AppendLine("{");
contents.Append(indent2).AppendLine($"{structureInfo.Name} managed;");
contents.Append(indent2).AppendLine($"{structureInfo.Name}Internal? unmanaged;");
contents.Append(indent2).AppendLine($"public void FromManaged({structureInfo.Name} managed) {{ this.managed = managed; }}");
contents.Append(indent2).AppendLine($"public {structureInfo.Name}Internal ToUnmanaged() {{ unmanaged = {marshallerName}.ToNative(managed); return unmanaged.Value; }}");
//contents.Append(indent2).AppendLine($"public void FromUnmanaged({structureInfo.Name}Internal unmanaged) {{ {marshallerName}.Free(this.unmanaged.Value); this.unmanaged = unmanaged; }}");
contents.Append(indent2).AppendLine($"public void FromUnmanaged({structureInfo.Name}Internal unmanaged) {{ this.unmanaged = unmanaged; }}");
contents.Append(indent2).AppendLine($"public {structureInfo.Name} ToManaged() {{ managed = {marshallerName}.ToManaged(unmanaged.Value); unmanaged = null; return managed; }}");
contents.Append(indent2).AppendLine($"public void Free() {{ if (unmanaged.HasValue) {{ NativeToManaged.Free(unmanaged.Value); unmanaged = null; }} }}");
contents.Append(indent).AppendLine("}");
// Bidirectional stateless shape
contents.Append(indent).AppendLine($"internal static {structureInfo.Name} ConvertToManaged({structureInfo.Name}Internal unmanaged) => ToManaged(unmanaged);");
contents.Append(indent).AppendLine($"internal static {structureInfo.Name}Internal ConvertToUnmanaged({structureInfo.Name} managed) => ToNative(managed);");
contents.Append(indent).AppendLine($"internal static void Free({structureInfo.Name}Internal unmanaged)");
contents.Append(indent).AppendLine("{").Append(indent2).AppendLine(freeContents.Replace("\n", "\n" + indent2).ToString().TrimEnd()).Append(indent).AppendLine("}");
// Managed/native converters
contents.Append(indent).AppendLine($"internal static {structureInfo.Name} ToManaged({structureInfo.Name}Internal managed)");
contents.Append(indent).AppendLine("{").Append(indent2).AppendLine(toManagedContent.Replace("\n", "\n" + indent2).ToString().TrimEnd()).Append(indent).AppendLine("}");
contents.Append(indent).AppendLine($"internal static {structureInfo.Name}Internal ToNative({structureInfo.Name} managed)");
contents.Append(indent).AppendLine("{").Append(indent2).AppendLine(toNativeContent.Replace("\n", "\n" + indent2).ToString().TrimEnd()).Append(indent).AppendLine("}");
indent = indent.Substring(0, indent.Length - 4);
contents.Append(indent).AppendLine("}");
}
#endif
// Struct docs // Struct docs
GenerateCSharpComment(contents, indent, structureInfo.Comment); GenerateCSharpComment(contents, indent, structureInfo.Comment);
// Struct begin // Struct begin
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, true); GenerateCSharpAttributes(buildData, contents, indent, structureInfo, true);
contents.Append(indent).AppendLine("[StructLayout(LayoutKind.Sequential)]"); contents.Append(indent).AppendLine("[StructLayout(LayoutKind.Sequential)]");
#if USE_NETCORE
if (!string.IsNullOrEmpty(structNativeMarshaling))
contents.Append(indent).AppendLine(structNativeMarshaling);
#endif
contents.Append(indent); contents.Append(indent);
GenerateCSharpAccessLevel(contents, structureInfo.Access); GenerateCSharpAccessLevel(contents, structureInfo.Access);
contents.Append("unsafe partial struct ").Append(structureInfo.Name); contents.Append("unsafe partial struct ").Append(structureInfo.Name);
@@ -1142,6 +1597,12 @@ namespace Flax.Build.Bindings
contents.AppendLine(); contents.AppendLine();
GenerateCSharpComment(contents, indent, fieldInfo.Comment); GenerateCSharpComment(contents, indent, fieldInfo.Comment);
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic, fieldInfo.DefaultValue, fieldInfo.Type); GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic, fieldInfo.DefaultValue, fieldInfo.Type);
#if USE_NETCORE
if (fieldInfo.Type.Type == "String")
contents.Append(indent).AppendLine("[MarshalAs(UnmanagedType.LPWStr)]");
else if (fieldInfo.Type.Type == "bool")
contents.Append(indent).AppendLine("[MarshalAs(UnmanagedType.U1)]");
#endif
contents.Append(indent); contents.Append(indent);
GenerateCSharpAccessLevel(contents, fieldInfo.Access); GenerateCSharpAccessLevel(contents, fieldInfo.Access);
if (fieldInfo.IsConstexpr) if (fieldInfo.IsConstexpr)
@@ -1153,21 +1614,32 @@ namespace Flax.Build.Bindings
if (fieldInfo.Type.IsArray && (fieldInfo.NoArray || structureInfo.IsPod)) if (fieldInfo.Type.IsArray && (fieldInfo.NoArray || structureInfo.IsPod))
{ {
// Fixed-size array that needs to be inlined into structure instead of passing it as managed array
fieldInfo.Type.IsArray = false; fieldInfo.Type.IsArray = false;
type = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo); type = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo);
fieldInfo.Type.IsArray = true; fieldInfo.Type.IsArray = true;
contents.Append(type).Append(' ').Append(fieldInfo.Name + "0;").AppendLine(); #if USE_NETCORE
for (int i = 1; i < fieldInfo.Type.ArraySize; i++) // Use fixed statement with primitive types of buffers
if (type == "char")
{ {
contents.AppendLine(); // char's are not blittable, store as short instead
GenerateCSharpComment(contents, indent, fieldInfo.Comment); contents.Append($"fixed short {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {type}*").AppendLine();
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic); }
contents.Append(indent); else
GenerateCSharpAccessLevel(contents, fieldInfo.Access); #endif
if (fieldInfo.IsStatic) {
contents.Append("static "); // Padding in structs for fixed-size array
contents.Append(type).Append(' ').Append(fieldInfo.Name + i).Append(';').AppendLine(); contents.Append(type).Append(' ').Append(fieldInfo.Name + "0;").AppendLine();
for (int i = 1; i < fieldInfo.Type.ArraySize; i++)
{
contents.AppendLine();
GenerateCSharpComment(contents, indent, fieldInfo.Comment);
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic);
contents.Append(indent);
GenerateCSharpAccessLevel(contents, fieldInfo.Access);
if (fieldInfo.IsStatic)
contents.Append("static ");
contents.Append(type).Append(' ').Append(fieldInfo.Name + i).Append(';').AppendLine();
}
} }
continue; continue;
} }
@@ -1393,6 +1865,23 @@ namespace Flax.Build.Bindings
contents.AppendLine(indent + "}"); contents.AppendLine(indent + "}");
if (!string.IsNullOrEmpty(interfaceInfo.Namespace)) if (!string.IsNullOrEmpty(interfaceInfo.Namespace))
contents.AppendLine("}"); contents.AppendLine("}");
#if USE_NETCORE
{
string marshallerName = interfaceInfo.Name + "Marshaller";
contents.AppendLine();
contents.Append(indent).AppendLine("/// <summary>");
contents.Append(indent).AppendLine("/// ");
contents.Append(indent).AppendLine("/// </summary>");
contents.Append(indent).AppendLine($"[CustomMarshaller(typeof({interfaceInfo.Name}), MarshalMode.Default, typeof({marshallerName}))]");
contents.Append(indent).AppendLine($"internal static class {marshallerName}");
contents.Append(indent).AppendLine("{");
contents.Append(indent + " ").AppendLine($"internal static {interfaceInfo.Name} ConvertToManaged(IntPtr unmanaged) => ({interfaceInfo.Name})GCHandleMarshaller.ConvertToManaged(unmanaged);");
contents.Append(indent + " ").AppendLine($"internal static IntPtr ConvertToUnmanaged({interfaceInfo.Name} managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);");
contents.Append(indent + " ").AppendLine("internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);");
contents.Append(indent).AppendLine("}");
}
#endif
} }
private static bool GenerateCSharpType(BuildData buildData, StringBuilder contents, string indent, object type) private static bool GenerateCSharpType(BuildData buildData, StringBuilder contents, string indent, object type)
@@ -1456,6 +1945,9 @@ namespace Flax.Build.Bindings
CSharpUsedNamespaces.Add("System.Globalization"); CSharpUsedNamespaces.Add("System.Globalization");
CSharpUsedNamespaces.Add("System.Runtime.CompilerServices"); CSharpUsedNamespaces.Add("System.Runtime.CompilerServices");
CSharpUsedNamespaces.Add("System.Runtime.InteropServices"); CSharpUsedNamespaces.Add("System.Runtime.InteropServices");
#if USE_NETCORE
CSharpUsedNamespaces.Add("System.Runtime.InteropServices.Marshalling");
#endif
CSharpUsedNamespaces.Add("FlaxEngine"); CSharpUsedNamespaces.Add("FlaxEngine");
// Process all API types from the file // Process all API types from the file

View File

@@ -440,6 +440,13 @@ namespace Flax.Build.Bindings
// Array or Span or DataContainer // Array or Span or DataContainer
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null) if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
{ {
#if USE_NETCORE
if (typeInfo.GenericArgs[0].Type == "bool")
{
type = "bool*";
return "MUtils::ToBoolArray({0})";
}
#endif
type = "MonoArray*"; type = "MonoArray*";
return "MUtils::ToArray({0}, " + GenerateCppGetNativeClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")"; return "MUtils::ToArray({0}, " + GenerateCppGetNativeClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
} }
@@ -472,8 +479,13 @@ namespace Flax.Build.Bindings
if (typeInfo.Type == "BitArray" && typeInfo.GenericArgs != null) if (typeInfo.Type == "BitArray" && typeInfo.GenericArgs != null)
{ {
CppIncludeFiles.Add("Engine/Scripting/InternalCalls/ManagedBitArray.h"); CppIncludeFiles.Add("Engine/Scripting/InternalCalls/ManagedBitArray.h");
#if USE_NETCORE
type = "bool*";
return "MUtils::ToBoolArray({0})";
#else
type = "MonoObject*"; type = "MonoObject*";
return "ManagedBitArray::ToManaged({0})"; return "ManagedBitArray::ToManaged({0})";
#endif
} }
// Function // Function
@@ -817,6 +829,7 @@ namespace Flax.Build.Bindings
return true; return true;
if (typeInfo.IsPtr || typeInfo.IsRef || typeInfo.IsArray || typeInfo.IsBitField || (typeInfo.GenericArgs != null && typeInfo.GenericArgs.Count != 0)) if (typeInfo.IsPtr || typeInfo.IsRef || typeInfo.IsArray || typeInfo.IsBitField || (typeInfo.GenericArgs != null && typeInfo.GenericArgs.Count != 0))
return false; return false;
#if !USE_NETCORE
if (CSharpNativeToManagedBasicTypes.ContainsKey(typeInfo.Type) || CSharpNativeToManagedBasicTypes.ContainsValue(typeInfo.Type)) if (CSharpNativeToManagedBasicTypes.ContainsKey(typeInfo.Type) || CSharpNativeToManagedBasicTypes.ContainsValue(typeInfo.Type))
return true; return true;
var apiType = FindApiTypeInfo(buildData, typeInfo, caller); var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
@@ -825,6 +838,7 @@ namespace Flax.Build.Bindings
if (apiType.IsEnum) if (apiType.IsEnum)
return true; return true;
} }
#endif
return false; return false;
} }
@@ -880,7 +894,38 @@ namespace Flax.Build.Bindings
}, },
IsOut = true, IsOut = true,
}); });
#if USE_NETCORE
if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer")
{
functionInfo.Glue.UseResultReferenceCount = true;
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
{
Name = "resultAsRefCount",
DefaultValue = "var resultAsRefCount",
Type = new TypeInfo
{
Type = "int"
},
IsOut = true,
});
}
#endif
} }
#if USE_NETCORE
else if (functionInfo.ReturnType.Type == "BitArray" || functionInfo.ReturnType.Type == "BytesContainer")//returnValueType == "byte[]")
{
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
{
Name = "returnCount",
DefaultValue = "var returnCount",
Type = new TypeInfo
{
Type = "int"
},
IsOut = true,
});
}
#endif
CppInternalCalls.Add(new KeyValuePair<string, string>(functionInfo.UniqueName, functionInfo.UniqueName)); CppInternalCalls.Add(new KeyValuePair<string, string>(functionInfo.UniqueName, functionInfo.UniqueName));
contents.AppendFormat(" static {0} {1}(", returnValueType, functionInfo.UniqueName); contents.AppendFormat(" static {0} {1}(", returnValueType, functionInfo.UniqueName);
@@ -945,6 +990,23 @@ namespace Flax.Build.Bindings
CppParamsThatNeedConversionWrappers[i] = GenerateCppWrapperNativeToManaged(buildData, parameterInfo.Type, caller, out CppParamsThatNeedConversionTypes[i], functionInfo); CppParamsThatNeedConversionWrappers[i] = GenerateCppWrapperNativeToManaged(buildData, parameterInfo.Type, caller, out CppParamsThatNeedConversionTypes[i], functionInfo);
} }
} }
#if USE_NETCORE
if (parameterInfo.Type.IsArray || parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "BytesContainer" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BitArray")
{
// We need additional output parameters for array sizes
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
{
Name = parameterInfo.Name + "Count",
DefaultValue = parameterInfo.IsOut ? "int _" : parameterInfo.Name + "Count",
Type = new TypeInfo
{
Type = "int"
},
IsOut = parameterInfo.IsOut,
IsRef = isRefOut || parameterInfo.Type.IsRef,
});
}
#endif
} }
for (var i = 0; i < functionInfo.Glue.CustomParameters.Count; i++) for (var i = 0; i < functionInfo.Glue.CustomParameters.Count; i++)
@@ -965,6 +1027,9 @@ namespace Flax.Build.Bindings
contents.Append(')'); contents.Append(')');
contents.AppendLine(); contents.AppendLine();
contents.AppendLine(" {"); contents.AppendLine(" {");
#if USE_NETCORE
contents.AppendLine(String.Format(" SCRIPTING_EXPORT(\"{0}\")", caller.FullNameManaged + "::Internal_" + functionInfo.UniqueName));
#endif
if (!functionInfo.IsStatic) if (!functionInfo.IsStatic)
contents.AppendLine(" if (obj == nullptr) DebugLog::ThrowNullReference();"); contents.AppendLine(" if (obj == nullptr) DebugLog::ThrowNullReference();");
@@ -981,6 +1046,17 @@ namespace Flax.Build.Bindings
callBegin += "auto __result = "; callBegin += "auto __result = ";
} }
#if USE_NETCORE
string callBegin2 = "";
if (functionInfo.Glue.UseResultReferenceCount)
{
callBegin2 = " ";
if (functionInfo.ReturnType.Type == "Span")
callBegin2 += "*resultAsRefCount = {0}.Length();";
else
callBegin2 += "*resultAsRefCount = {0}.Count();";
}
#endif
string call; string call;
if (functionInfo.IsStatic) if (functionInfo.IsStatic)
{ {
@@ -1017,6 +1093,16 @@ namespace Flax.Build.Bindings
} }
else else
{ {
#if USE_NETCORE
// FIXME
if (parameterInfo.Type.Type == "Span" ||
parameterInfo.Type.Type == "Array" ||
parameterInfo.Type.Type == "DataContainer" ||
parameterInfo.Type.Type == "Dictionary")
{
name = '*' + name;
}
#endif
// Convert value // Convert value
param += string.Format(CppParamsWrappersCache[i], name); param += string.Format(CppParamsWrappersCache[i], name);
} }
@@ -1059,8 +1145,20 @@ namespace Flax.Build.Bindings
} }
} }
contents.Append(callBegin); #if USE_NETCORE
call = string.Format(callFormat, call, callParams); if (!string.IsNullOrEmpty(callBegin2))
{
contents.Append(" ").Append("auto& callTemp = ").Append(string.Format(callFormat, call, callParams)).Append(";").AppendLine();
call = "callTemp";
contents.Append(callBegin);
callBegin2 = string.Format(callBegin2, call);
}
else
#endif
{
contents.Append(callBegin);
call = string.Format(callFormat, call, callParams);
}
if (!string.IsNullOrEmpty(returnValueConvert)) if (!string.IsNullOrEmpty(returnValueConvert))
{ {
contents.AppendFormat(returnValueConvert, call); contents.AppendFormat(returnValueConvert, call);
@@ -1072,6 +1170,13 @@ namespace Flax.Build.Bindings
contents.Append(';'); contents.Append(';');
contents.AppendLine(); contents.AppendLine();
#if USE_NETCORE
if (!string.IsNullOrEmpty(callBegin2))
{
contents.Append(callBegin2);
contents.AppendLine();
}
#endif
// Convert special parameters back to managed world // Convert special parameters back to managed world
if (!useInlinedReturn) if (!useInlinedReturn)
@@ -1094,6 +1199,12 @@ namespace Flax.Build.Bindings
if (apiType.IsClass) if (apiType.IsClass)
{ {
contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine(); contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine();
#if USE_NETCORE
if (parameterInfo.Type.Type == "Array")
{
contents.AppendFormat(" *{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
}
#endif
continue; continue;
} }
if (apiType.IsStruct && !apiType.IsPod) if (apiType.IsStruct && !apiType.IsPod)
@@ -1109,9 +1220,10 @@ namespace Flax.Build.Bindings
if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null) if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)
{ {
contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine(); contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine();
contents.AppendFormat(" *{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
continue; continue;
} }
throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'"); throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'");
} }
} }
@@ -1646,6 +1758,9 @@ namespace Flax.Build.Bindings
contents.AppendFormat("{0}* obj, ", classTypeNameNative); contents.AppendFormat("{0}* obj, ", classTypeNameNative);
contents.Append("bool bind)").AppendLine(); contents.Append("bool bind)").AppendLine();
contents.Append(" {").AppendLine(); contents.Append(" {").AppendLine();
#if USE_NETCORE
contents.AppendLine(String.Format(" SCRIPTING_EXPORT(\"{0}\")", classTypeNameManagedInternalCall + "::Internal_" + eventInfo.Name + "_Bind"));
#endif
contents.Append(" Function<void("); contents.Append(" Function<void(");
for (var i = 0; i < paramsCount; i++) for (var i = 0; i < paramsCount; i++)
{ {
@@ -2276,6 +2391,9 @@ namespace Flax.Build.Bindings
contents.AppendLine("#include \"Engine/Scripting/Scripting.h\""); contents.AppendLine("#include \"Engine/Scripting/Scripting.h\"");
contents.AppendLine("#include \"Engine/Scripting/InternalCalls.h\""); contents.AppendLine("#include \"Engine/Scripting/InternalCalls.h\"");
contents.AppendLine("#include \"Engine/Scripting/ManagedCLR/MUtils.h\""); contents.AppendLine("#include \"Engine/Scripting/ManagedCLR/MUtils.h\"");
#if USE_NETCORE
contents.AppendLine("#include \"Engine/Scripting/DotNet/CoreCLR.h\"");
#endif
contents.AppendLine($"#include \"{moduleInfo.Name}.Gen.h\""); contents.AppendLine($"#include \"{moduleInfo.Name}.Gen.h\"");
for (int i = 0; i < moduleInfo.Children.Count; i++) for (int i = 0; i < moduleInfo.Children.Count; i++)
{ {

View File

@@ -60,6 +60,7 @@ namespace Flax.Build.Bindings
public struct GlueInfo public struct GlueInfo
{ {
public bool UseReferenceForResult; public bool UseReferenceForResult;
public bool UseResultReferenceCount;
public List<ParameterInfo> CustomParameters; public List<ParameterInfo> CustomParameters;
} }

View File

@@ -33,6 +33,15 @@ namespace Flax.Build.Bindings
/// </summary> /// </summary>
public bool IsConstRef => IsRef && IsConst; public bool IsConstRef => IsRef && IsConst;
/// <summary>
/// Gets a value indicating whether this type is a reference to another object.
/// </summary>
public bool IsObjectRef => (Type == "ScriptingObjectReference" ||
Type == "AssetReference" ||
Type == "WeakAssetReference" ||
Type == "SoftAssetReference" ||
Type == "SoftObjectReference") && GenericArgs != null;
public TypeInfo() public TypeInfo()
{ {
} }

View File

@@ -9,6 +9,7 @@ using Flax.Build.Graph;
using Flax.Build.Bindings; using Flax.Build.Bindings;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Task = Flax.Build.Graph.Task;
namespace Flax.Build.Plugins namespace Flax.Build.Plugins
{ {

View File

@@ -1,190 +1,39 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C99AAF92-D4AD-4847-9EE0-B11E68E93E1E}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>Flax.Build</RootNamespace> <TargetFramework>net7.0</TargetFramework>
<AssemblyName>Flax.Build</AssemblyName> <ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <Nullable>disable</Nullable>
<LangVersion>7.3</LangVersion> <Configurations>Debug;Release</Configurations>
<FileAlignment>512</FileAlignment> <Platforms>AnyCPU</Platforms>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <BaseOutputPath>..\..\..\Binaries\Tools</BaseOutputPath>
<TargetFrameworkProfile /> <OutDir>..\..\..\Binaries\Tools</OutDir>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
<DefineConstants>USE_NETCORE</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<Prefer32Bit>false</Prefer32Bit>
<OutputPath>..\..\..\Binaries\Tools\</OutputPath>
<DocumentationFile>..\..\..\Binaries\Tools\Flax.Build.xml</DocumentationFile>
<IntermediateOutputPath>..\..\..\Cache\Intermediate\Flax.Build\Debug</IntermediateOutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>true</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>1591</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<Prefer32Bit>false</Prefer32Bit>
<OutputPath>..\..\..\Binaries\Tools\</OutputPath>
<DocumentationFile>..\..\..\Binaries\Tools\Flax.Build.xml</DocumentationFile>
<IntermediateOutputPath>..\..\..\Cache\Intermediate\Flax.Build\Release</IntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>true</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>1591</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Ionic.Zip.Reduced"> <Folder Include="Properties"/>
<HintPath>..\..\..\Source\Platforms\DotNet\Ionic.Zip.Reduced.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil">
<HintPath>..\..\..\Source\Platforms\DotNet\Mono.Cecil.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Setup.Configuration.Interop">
<HintPath>..\..\..\Source\Platforms\DotNet\Microsoft.VisualStudio.Setup.Configuration.Interop.dll</HintPath>
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Source\Platforms\DotNet\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Bindings\ApiTypeInfo.cs" /> <PackageReference Include="DotNetZip" Version="1.16.0"/>
<Compile Include="Bindings\BindingsGenerator.Api.cs" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0-2.final"/>
<Compile Include="Bindings\BindingsGenerator.Cache.cs" /> <PackageReference Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="3.2.2146"/>
<Compile Include="Bindings\BindingsGenerator.Cpp.cs" /> <PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0"/>
<Compile Include="Bindings\BindingsGenerator.cs" /> <PackageReference Include="Mono.Cecil" Version="0.11.4"/>
<Compile Include="Bindings\BindingsGenerator.CSharp.cs" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2-beta1"/>
<Compile Include="Bindings\BindingsGenerator.Parsing.cs" /> <PackageReference Include="System.CodeDom" Version="6.0.2-mauipre.1.22102.15"/>
<Compile Include="Bindings\ClassInfo.cs" />
<Compile Include="Bindings\ClassStructInfo.cs" />
<Compile Include="Bindings\EnumInfo.cs" />
<Compile Include="Bindings\EventInfo.cs" />
<Compile Include="Bindings\FieldInfo.cs" />
<Compile Include="Bindings\FileInfo.cs" />
<Compile Include="Bindings\InheritanceInfo.cs" />
<Compile Include="Bindings\InjectCodeInfo.cs" />
<Compile Include="Bindings\InterfaceInfo.cs" />
<Compile Include="Bindings\LangType.cs" />
<Compile Include="Bindings\MemberInfo.cs" />
<Compile Include="Bindings\FunctionInfo.cs" />
<Compile Include="Bindings\ModuleInfo.cs" />
<Compile Include="Bindings\PropertyInfo.cs" />
<Compile Include="Bindings\StructureInfo.cs" />
<Compile Include="Bindings\TypedefInfo.cs" />
<Compile Include="Bindings\TypeInfo.cs" />
<Compile Include="Build\Assembler.cs" />
<Compile Include="Build\Builder.cs" />
<Compile Include="Build\Builder.Projects.cs" />
<Compile Include="Build\Builder.Rules.cs" />
<Compile Include="Build\DepsModule.cs" />
<Compile Include="Build\DotNet\Builder.DotNet.cs" />
<Compile Include="Build\EditorModule.cs" />
<Compile Include="Build\EngineModule.cs" />
<Compile Include="Build\EngineTarget.cs" />
<Compile Include="Build\GameModule.cs" />
<Compile Include="Build\GameTarget.cs" />
<Compile Include="Build\Graph\CompileTask.cs" />
<Compile Include="Build\Graph\LinkTask.cs" />
<Compile Include="Build\Graph\LocalExecutor.cs" />
<Compile Include="Build\Graph\Task.cs" />
<Compile Include="Build\Graph\TaskExecutor.cs" />
<Compile Include="Build\Graph\TaskGraph.cs" />
<Compile Include="Build\HeaderOnlyModule.cs" />
<Compile Include="Build\InvalidArchitectureException.cs" />
<Compile Include="Build\NativeCpp\Builder.NativeCpp.cs" />
<Compile Include="Build\Module.cs" />
<Compile Include="Build\NativeCpp\BuildOptions.cs" />
<Compile Include="Build\NativeCpp\CompileEnvironment.cs" />
<Compile Include="Build\NativeCpp\CompileOutput.cs" />
<Compile Include="Build\NativeCpp\IncludesCache.cs" />
<Compile Include="Build\NativeCpp\LinkEnvironment.cs" />
<Compile Include="Build\Plugin.cs" />
<Compile Include="Build\Plugins\NetworkingPlugin.cs" />
<Compile Include="Build\Plugins\VisualScriptingPlugin.cs" />
<Compile Include="Build\Profiling.cs" />
<Compile Include="Build\ProjectTarget.cs" />
<Compile Include="Build\Target.cs" />
<Compile Include="Build\ThirdPartyModule.cs" />
<Compile Include="Build\InvalidPlatformException.cs" />
<Compile Include="Build\Platform.cs" />
<Compile Include="Build\Sdk.cs" />
<Compile Include="Build\Toolchain.cs" />
<Compile Include="Build\TargetPlatform.cs" />
<Compile Include="Deploy\Configuration.cs" />
<Compile Include="Deploy\Deployer.cs" />
<Compile Include="Deploy\Deployment.Editor.cs" />
<Compile Include="Deploy\Deployment.Platforms.cs" />
<Compile Include="Deploy\Deployment.Utils.cs" />
<Compile Include="Deploy\FlaxBuild.cs" />
<Compile Include="Deploy\VCEnvironment.cs" />
<Compile Include="Deps\Configuration.cs" />
<Compile Include="Deps\Dependencies\*.cs" />
<Compile Include="Deps\Dependency.cs" />
<Compile Include="Deps\DepsBuilder.cs" />
<Compile Include="Deps\Downloader.cs" />
<Compile Include="Deps\ProgressDisplay.cs" />
<Compile Include="Platforms\Android\*.cs" />
<Compile Include="Platforms\Linux\*.cs" />
<Compile Include="..\..\Platforms\PS4\Flax.Build\*.cs" />
<Compile Include="..\..\Platforms\PS5\Flax.Build\*.cs" />
<Compile Include="Platforms\Mac\*.cs" />
<Compile Include="Platforms\Unix\*.cs" />
<Compile Include="Platforms\UWP\*.cs" />
<Compile Include="Platforms\Windows\*.cs" />
<Compile Include="Platforms\GDK\*.cs" />
<Compile Include="..\..\Platforms\XboxOne\Flax.Build\*.cs" />
<Compile Include="..\..\Platforms\XboxScarlett\Flax.Build\*.cs" />
<Compile Include="..\..\Platforms\Switch\Flax.Build\*.cs" />
<Compile Include="Projects\IProjectCustomizer.cs" />
<Compile Include="Projects\Project.cs" />
<Compile Include="Projects\ProjectFormat.cs" />
<Compile Include="Projects\ProjectGenerator.cs" />
<Compile Include="Projects\Solution.cs" />
<Compile Include="Projects\VisualStudioCode\VisualStudioCodeInstance.cs" />
<Compile Include="Projects\VisualStudioCode\VisualStudioCodeProjectGenerator.cs" />
<Compile Include="Projects\VisualStudio\CSProjectGenerator.cs" />
<Compile Include="Projects\VisualStudio\CSSDKProjectGenerator.cs" />
<Compile Include="Projects\VisualStudio\IVisualStudioProjectCustomizer.cs" />
<Compile Include="Projects\VisualStudio\VCProjectGenerator.cs" />
<Compile Include="Projects\VisualStudio\VisualStudioInstance.cs" />
<Compile Include="Projects\VisualStudio\VisualStudioProject.cs" />
<Compile Include="Projects\VisualStudio\VisualStudioProjectGenerator.cs" />
<Compile Include="Projects\VisualStudio\VisualStudioVersion.cs" />
<Compile Include="Projects\XCodeProjectGenerator.cs" />
<Compile Include="Utilities\MonoCecil.cs" />
<Compile Include="Utilities\StringWriterWithEncoding.cs" />
<Compile Include="Utilities\Tokenizer.cs" />
<Compile Include="Utilities\TwoWayEnumerator.cs" />
<Compile Include="Utilities\Utilities.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Globals.cs" />
<Compile Include="Log.cs" />
<Compile Include="LogIndentScope.cs" />
<Compile Include="CommandLine.cs" />
<Compile Include="CommandLineAttribute.cs" />
<Compile Include="Configuration.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProjectInfo.cs" />
<Compile Include="Utilities\WinAPI.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
</Project>

View File

@@ -41,7 +41,11 @@ namespace Flax.Build
/// <returns>The empty array object.</returns> /// <returns>The empty array object.</returns>
public static T[] GetEmptyArray<T>() public static T[] GetEmptyArray<T>()
{ {
#if USE_NETCORE
return Array.Empty<T>();
#else
return Enumerable.Empty<T>() as T[]; return Enumerable.Empty<T>() as T[];
#endif
} }
/// <summary> /// <summary>