diff --git a/.github/workflows/build_android.yml b/.github/workflows/build_android.yml
index 2c99ad118..f25e6836b 100644
--- a/.github/workflows/build_android.yml
+++ b/.github/workflows/build_android.yml
@@ -5,6 +5,7 @@ jobs:
# Game
game-windows:
+ if: ${{ false }}
name: Game (Android, Release ARM64)
runs-on: "windows-2019"
steps:
diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml
index a860010fd..e04e10a5c 100644
--- a/.github/workflows/build_linux.yml
+++ b/.github/workflows/build_linux.yml
@@ -5,6 +5,7 @@ jobs:
# Editor
editor-linux:
+ if: ${{ false }}
name: Editor (Linux, Development x64)
runs-on: "ubuntu-20.04"
steps:
@@ -28,6 +29,7 @@ jobs:
# Game
game-linux:
+ if: ${{ false }}
name: Game (Linux, Release x64)
runs-on: "ubuntu-20.04"
steps:
diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml
index 33e2668ae..ea658efc3 100644
--- a/.github/workflows/build_mac.yml
+++ b/.github/workflows/build_mac.yml
@@ -5,6 +5,7 @@ jobs:
# Editor
editor-mac:
+ if: ${{ false }}
name: Editor (Mac, Development x64)
runs-on: "macos-latest"
steps:
@@ -22,6 +23,7 @@ jobs:
# Game
game-mac:
+ if: ${{ false }}
name: Game (Mac, Release x64)
runs-on: "macos-latest"
steps:
diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml
index ac88b30f4..d107f074a 100644
--- a/.github/workflows/build_windows.yml
+++ b/.github/workflows/build_windows.yml
@@ -6,12 +6,19 @@ jobs:
# Editor
editor-windows:
name: Editor (Windows, Development x64)
- runs-on: "windows-2019"
+ runs-on: "windows-2022"
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup Vulkan
uses: ./.github/actions/vulkan
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: 7.0.x
+ - name: Check .NET versions
+ run: |
+ dotnet --list-sdks
- name: Checkout LFS
run: |
git lfs version
@@ -23,12 +30,16 @@ jobs:
# Game
game-windows:
name: Game (Windows, Release x64)
- runs-on: "windows-2019"
+ runs-on: "windows-2022"
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup Vulkan
uses: ./.github/actions/vulkan
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: 7.0.x
- name: Checkout LFS
run: |
git lfs version
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index e326fa28d..2a90f9b27 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -5,6 +5,7 @@ jobs:
# Tests
tests-linux:
+ if: ${{ false }}
name: Tests (Linux)
runs-on: "ubuntu-20.04"
steps:
diff --git a/Development/Scripts/Linux/CallBuildTool.sh b/Development/Scripts/Linux/CallBuildTool.sh
index 3052ee241..9aaeca75a 100755
--- a/Development/Scripts/Linux/CallBuildTool.sh
+++ b/Development/Scripts/Linux/CallBuildTool.sh
@@ -10,8 +10,9 @@ if [ $testfilesize -le 1000 ]; then
fi
# Compile the build tool.
-xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
+dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Restore,Clean /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=linux-x64
+dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Build /property:SelfContained=False /property:RuntimeIdentifiers=linux-x64
# Run the build tool using the provided arguments.
#mono --debug --debugger-agent=transport=dt_socket,server=y,address=127.0.0.1:55555 Binaries/Tools/Flax.Build.exe "$@"
-mono Binaries/Tools/Flax.Build.exe "$@"
+Binaries/Tools/Flax.Build "$@"
diff --git a/Development/Scripts/Windows/CallBuildTool.bat b/Development/Scripts/Windows/CallBuildTool.bat
index 396d59da4..a01a7dbcc 100644
--- a/Development/Scripts/Windows/CallBuildTool.bat
+++ b/Development/Scripts/Windows/CallBuildTool.bat
@@ -28,9 +28,9 @@ fc /b Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Fla
if not errorlevel 1 goto SkipClean
copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul
-%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Clean
+%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Restore,Clean /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=win-x64
:SkipClean
-%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Build
+%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Build /property:SelfContained=False /property:RuntimeIdentifiers=win-x64
if errorlevel 1 goto Error_CompilationFailed
Binaries\Tools\Flax.Build.exe %*
diff --git a/Flax.flaxproj b/Flax.flaxproj
index bd64ab7e8..52c466fd7 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -11,6 +11,7 @@
"EditorTarget": "FlaxEditor",
"Configuration": {
"UseCSharp": true,
- "UseLargeWorlds": false
+ "UseLargeWorlds": false,
+ "UseDotNet": true
}
}
\ No newline at end of file
diff --git a/Source/Editor/Content/Import/AudioImportSettings.cs b/Source/Editor/Content/Import/AudioImportSettings.cs
index 19ad1065d..40e715c06 100644
--- a/Source/Editor/Content/Import/AudioImportSettings.cs
+++ b/Source/Editor/Content/Import/AudioImportSettings.cs
@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using FlaxEngine;
namespace FlaxEditor.Content.Import
@@ -93,6 +94,7 @@ namespace FlaxEditor.Content.Import
[StructLayout(LayoutKind.Sequential)]
internal struct InternalOptions
{
+ [MarshalAs(UnmanagedType.I1)]
public AudioFormat Format;
public byte DisableStreaming;
public byte Is3D;
@@ -144,7 +146,7 @@ namespace FlaxEditor.Content.Import
/// Audio asset import entry.
///
///
- public class AudioImportEntry : AssetImportEntry
+ public partial class AudioImportEntry : AssetImportEntry
{
private AudioImportSettings _settings = new AudioImportSettings();
@@ -182,8 +184,9 @@ namespace FlaxEditor.Content.Import
#region Internal Calls
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.AudioImportEntry::Internal_GetAudioImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
#endregion
}
diff --git a/Source/Editor/Content/Import/ModelImportEntry.cs b/Source/Editor/Content/Import/ModelImportEntry.cs
index bded33956..2b959ddb1 100644
--- a/Source/Editor/Content/Import/ModelImportEntry.cs
+++ b/Source/Editor/Content/Import/ModelImportEntry.cs
@@ -1,8 +1,10 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using FlaxEngine;
namespace FlaxEditor.Content.Import
@@ -355,6 +357,7 @@ namespace FlaxEditor.Content.Import
private bool ShowAnimation => Type == ModelType.Animation;
[StructLayout(LayoutKind.Sequential)]
+ [NativeMarshalling(typeof(InternalOptionsMarshaler))]
internal struct InternalOptions
{
public ModelType Type;
@@ -410,6 +413,162 @@ namespace FlaxEditor.Content.Import
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)
{
options = new InternalOptions
@@ -511,7 +670,7 @@ namespace FlaxEditor.Content.Import
/// Model asset import entry.
///
///
- public class ModelImportEntry : AssetImportEntry
+ public partial class ModelImportEntry : AssetImportEntry
{
private ModelImportSettings _settings = new ModelImportSettings();
@@ -548,8 +707,8 @@ namespace FlaxEditor.Content.Import
#region Internal Calls
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.ModelImportEntry::Internal_GetModelImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ internal static partial void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
#endregion
}
diff --git a/Source/Editor/Content/Import/TextureImportEntry.cs b/Source/Editor/Content/Import/TextureImportEntry.cs
index 0ac44ec0b..abffe0ce7 100644
--- a/Source/Editor/Content/Import/TextureImportEntry.cs
+++ b/Source/Editor/Content/Import/TextureImportEntry.cs
@@ -1,10 +1,12 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using FlaxEngine;
// ReSharper disable InconsistentNaming
@@ -297,6 +299,7 @@ namespace FlaxEditor.Content.Import
public List Sprites = new List();
[StructLayout(LayoutKind.Sequential)]
+ [NativeMarshalling(typeof(InternalOptionsMarshaler))]
internal struct InternalOptions
{
public TextureFormatType Type;
@@ -318,6 +321,85 @@ namespace FlaxEditor.Content.Import
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((ManagedArray)GCHandle.FromIntPtr(managed.SpriteAreas).Target) : null,
+ SpriteNames = managed.SpriteNames != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray((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)
{
options = new InternalOptions
@@ -406,7 +488,7 @@ namespace FlaxEditor.Content.Import
/// Texture asset import entry.
///
///
- public class TextureImportEntry : AssetImportEntry
+ public partial class TextureImportEntry : AssetImportEntry
{
private TextureImportSettings _settings = new TextureImportSettings();
@@ -509,8 +591,9 @@ namespace FlaxEditor.Content.Import
#region Internal Calls
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.TextureImportEntry::Internal_GetTextureImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
#endregion
}
diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cs b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
index 4b934cbd6..4df247786 100644
--- a/Source/Editor/CustomEditors/CustomEditorsUtil.cs
+++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
@@ -4,13 +4,15 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.Scripting;
using FlaxEngine;
namespace FlaxEditor.CustomEditors
{
- internal static class CustomEditorsUtil
+ internal static partial class CustomEditorsUtil
{
internal static readonly Dictionary InBuildTypeNames = new Dictionary()
{
@@ -129,7 +131,8 @@ namespace FlaxEditor.CustomEditors
return new GenericEditor();
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Type Internal_GetCustomEditor(Type targetType);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.CustomEditors.CustomEditorsUtil::Internal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalUsing(typeof(SystemTypeMarshaller))]
+ internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
}
}
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index 421512ce0..9eeb4bb35 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using FlaxEditor.Content;
using FlaxEditor.Content.Import;
using FlaxEditor.Content.Settings;
@@ -20,6 +21,8 @@ using FlaxEngine.Assertions;
using FlaxEngine.GUI;
using FlaxEngine.Json;
+#pragma warning disable CS1591
+
namespace FlaxEditor
{
///
@@ -59,17 +62,20 @@ namespace FlaxEditor
///
/// Gets a value indicating whether this Editor is running a dev instance of the engine.
///
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool IsDevInstance();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::IsDevInstance", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool IsDevInstance();
///
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
///
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool IsOfficialBuild();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::IsOfficialBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool IsOfficialBuild();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_IsPlayMode();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_IsPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_IsPlayMode();
///
/// 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)]
+ [NativeMarshalling(typeof(VisualScriptLocalMarshaller))]
internal struct VisualScriptLocal
{
public string Value;
@@ -1214,7 +1221,48 @@ namespace FlaxEditor
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)]
+ [NativeMarshalling(typeof(VisualScriptStackFrameMarshaller))]
internal struct VisualScriptStackFrame
{
public VisualScript Script;
@@ -1222,6 +1270,43 @@ namespace FlaxEditor
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)
{
if (TryBuildCommand(arg))
@@ -1419,116 +1504,133 @@ namespace FlaxEditor
Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode;
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int Internal_ReadOutputLogs(string[] outMessages, byte[] outLogTypes, long[] outLogTimes);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ 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)]
- internal static extern void Internal_SetPlayMode(bool value);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string Internal_GetProjectPath();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial string Internal_GetProjectPath();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_Import(string inputPath, string outputPath, IntPtr arg);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_Import", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_Import(string inputPath, string outputPath, IntPtr arg);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportTexture", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportModel", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportAudio", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetAudioClipMetadata", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CopyCache", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_BakeLightmaps(bool cancel);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_BakeLightmaps", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string Internal_GetShaderAssetSourceCode(IntPtr obj);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [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)]
- internal static extern void Internal_GetCollisionWires(IntPtr collisionData, out Float3[] triangles, out int[] indices);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ 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)]
- internal static extern void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_SetOptions(ref InternalOptions options);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_SetOptions(ref InternalOptions options);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_DrawNavMesh();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_DrawNavMesh", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_DrawNavMesh();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_CloseSplashScreen();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_CloseSplashScreen();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CreateAsset(NewAssetType type, string outputPath);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CreateAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_CreateAsset(NewAssetType type, string outputPath);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string Internal_CanImport(string extension);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial string Internal_CanImport(string extension);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CanExport(string path);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_CanExport(string path);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_Export(string inputPath, string outputFolder);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_Export(string inputPath, string outputFolder);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_GetIsEveryAssemblyLoaded();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetIsEveryAssemblyLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_GetIsEveryAssemblyLoaded();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int Internal_GetLastProjectOpenedEngineBuild();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetLastProjectOpenedEngineBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial int Internal_GetLastProjectOpenedEngineBuild();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_GetIsCSGActive();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetIsCSGActive", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_GetIsCSGActive();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern VisualScriptLocal[] Internal_GetVisualScriptLocals();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)]
+ internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)]
+ internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_EvaluateVisualScriptLocal", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_LoadAsset(ref Guid id);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_LoadAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_LoadAsset(ref Guid id);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanSetToRoot", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern float Internal_GetAnimationTime(IntPtr animatedModel);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_SetAnimationTime(IntPtr animatedModel, float time);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
#endregion
}
diff --git a/Source/Editor/GUI/Timeline/ParticleSystemTimeline.cs b/Source/Editor/GUI/Timeline/ParticleSystemTimeline.cs
index 246c33b4d..cd660daab 100644
--- a/Source/Editor/GUI/Timeline/ParticleSystemTimeline.cs
+++ b/Source/Editor/GUI/Timeline/ParticleSystemTimeline.cs
@@ -10,6 +10,7 @@ using FlaxEditor.GUI.Timeline.Tracks;
using FlaxEditor.Utilities;
using FlaxEditor.Viewport.Previews;
using FlaxEngine;
+using FlaxEngine.Utilities;
namespace FlaxEditor.GUI.Timeline
{
diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp
index 3d236cd49..11844b23c 100644
--- a/Source/Editor/Managed/ManagedEditor.Internal.cpp
+++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp
@@ -323,20 +323,25 @@ namespace CustomEditorsUtilInternal
{
MonoReflectionType* GetCustomEditor(MonoReflectionType* targetType)
{
+ SCRIPTING_EXPORT("FlaxEditor.CustomEditors.CustomEditorsUtil::Internal_GetCustomEditor")
return CustomEditorsUtil::GetCustomEditor(targetType);
}
}
namespace LayersAndTagsSettingsInternal1
{
- MonoArray* GetCurrentTags()
+ MonoArray* GetCurrentTags(int* tagsCount)
{
+ SCRIPTING_EXPORT("FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentTags")
+ *tagsCount = Level::Tags.Count();
return MUtils::ToArray(Level::Tags);
}
- MonoArray* GetCurrentLayers()
+ MonoArray* GetCurrentLayers(int* layersCount)
{
- return MUtils::ToArray(Span(Level::Layers, Math::Max(1, Level::GetNonEmptyLayerNamesCount())));
+ SCRIPTING_EXPORT("FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentLayers")
+ *layersCount = Math::Max(1, Level::GetNonEmptyLayerNamesCount());
+ return MUtils::ToArray(Span(Level::Layers, *layersCount));
}
}
@@ -344,6 +349,7 @@ namespace GameSettingsInternal1
{
void Apply()
{
+ SCRIPTING_EXPORT("FlaxEditor.Content.Settings.GameSettings::Apply")
LOG(Info, "Apply game settings");
GameSettings::Load();
}
@@ -380,6 +386,7 @@ class ManagedEditorInternal
public:
static bool IsDevInstance()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::IsDevInstance")
#if COMPILE_WITH_DEV_ENV
return true;
#else
@@ -389,6 +396,7 @@ public:
static bool IsOfficialBuild()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::IsOfficialBuild")
#if OFFICIAL_BUILD
return true;
#else
@@ -398,18 +406,20 @@ public:
static bool IsPlayMode()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_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);
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
return 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* end = ptr + CachedLogData.Count();
@@ -429,9 +439,9 @@ public:
auto msgObj = MUtils::ToString(StringView(msg, length));
- mono_array_setref(outMessages, count, msgObj);
- mono_array_set(outLogTypes, byte, count, type);
- mono_array_set(outLogTimes, int64, count, time);
+ mono_array_setref(*outMessages, count, msgObj);
+ mono_array_set(*outLogTypes, byte, count, type);
+ mono_array_set(*outLogTimes, int64, count, time);
count++;
}
@@ -445,21 +455,25 @@ public:
static void SetPlayMode(bool value)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetPlayMode")
Editor::IsPlayMode = value;
}
static MonoString* GetProjectPath()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetProjectPath")
return MUtils::ToString(Editor::Project->ProjectPath);
}
static void CloseSplashScreen()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CloseSplashScreen")
Editor::CloseSplashScreen();
}
static bool CloneAssetFile(MonoString* dstPathObj, MonoString* srcPathObj, Guid* dstId)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CloneAssetFile")
// Get normalized paths
String dstPath, srcPath;
MUtils::ToString(dstPathObj, dstPath);
@@ -489,6 +503,7 @@ public:
static bool CreateAsset(NewAssetType type, MonoString* outputPathObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CreateAsset")
String tag;
switch (type)
{
@@ -541,6 +556,7 @@ public:
static bool CreateVisualScript(MonoString* outputPathObj, MonoString* baseTypenameObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CreateVisualScript")
String outputPath;
MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath);
@@ -551,6 +567,7 @@ public:
static MonoString* CanImport(MonoString* extensionObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanImport")
String extension;
MUtils::ToString(extensionObj, extension);
if (extension.Length() > 0 && extension[0] == '.')
@@ -561,6 +578,7 @@ public:
static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_Import")
String inputPath, outputPath;
MUtils::ToString(inputPathObj, inputPath);
MUtils::ToString(outputPathObj, outputPath);
@@ -572,6 +590,7 @@ public:
static bool ImportTexture(MonoString* inputPathObj, MonoString* outputPathObj, InternalTextureOptions* optionsObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportTexture")
ImportTexture::Options options;
InternalTextureOptions::Convert(optionsObj, &options);
@@ -580,6 +599,7 @@ public:
static bool ImportModel(MonoString* inputPathObj, MonoString* outputPathObj, InternalModelOptions* optionsObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportModel")
ImportModelFile::Options options;
InternalModelOptions::Convert(optionsObj, &options);
@@ -588,6 +608,7 @@ public:
static bool ImportAudio(MonoString* inputPathObj, MonoString* outputPathObj, InternalAudioOptions* optionsObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportAudio")
ImportAudio::Options options;
InternalAudioOptions::Convert(optionsObj, &options);
@@ -596,6 +617,7 @@ public:
static void GetAudioClipMetadata(AudioClip* clip, int32* originalSize, int32* importedSize)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetAudioClipMetadata")
INTERNAL_CALL_CHECK(clip);
*originalSize = clip->AudioHeader.OriginalSize;
*importedSize = clip->AudioHeader.ImportedSize;
@@ -603,6 +625,7 @@ public:
static bool SaveJsonAsset(MonoString* outputPathObj, MonoString* dataObj, MonoString* dataTypeNameObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SaveJsonAsset")
String outputPath;
MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath);
@@ -623,6 +646,8 @@ public:
static bool GetTextureImportOptions(MonoString* pathObj, InternalTextureOptions* result)
{
+ SCRIPTING_EXPORT("FlaxEditor.Content.Import.TextureImportEntry::Internal_GetTextureImportOptions")
+
String path;
MUtils::ToString(pathObj, path);
FileSystem::NormalizePath(path);
@@ -641,6 +666,7 @@ public:
static void GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result)
{
+ SCRIPTING_EXPORT("FlaxEditor.Content.Import.ModelImportEntry::Internal_GetModelImportOptions")
// Initialize defaults
ImportModelFile::Options options;
if (const auto* graphicsSettings = GraphicsSettings::Get())
@@ -660,6 +686,7 @@ public:
static bool GetAudioImportOptions(MonoString* pathObj, InternalAudioOptions* result)
{
+ SCRIPTING_EXPORT("FlaxEditor.Content.Import.AudioImportEntry::Internal_GetAudioImportOptions")
String path;
MUtils::ToString(pathObj, path);
FileSystem::NormalizePath(path);
@@ -678,6 +705,7 @@ public:
static bool CanExport(MonoString* pathObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanExport")
#if COMPILE_WITH_ASSETS_EXPORTER
String path;
MUtils::ToString(pathObj, path);
@@ -691,6 +719,7 @@ public:
static bool Export(MonoString* inputPathObj, MonoString* outputFolderObj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_Export")
#if COMPILE_WITH_ASSETS_EXPORTER
String inputPath;
MUtils::ToString(inputPathObj, inputPath);
@@ -708,11 +737,13 @@ public:
static void CopyCache(Guid* dstId, Guid* srcId)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CopyCache")
ShaderCacheManager::CopyCache(*dstId, *srcId);
}
static void BakeLightmaps(bool cancel)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_BakeLightmaps")
auto builder = ShadowsOfMordor::Builder::Instance();
if (cancel)
builder->CancelBuild();
@@ -722,6 +753,7 @@ public:
static MonoString* GetShaderAssetSourceCode(BinaryAsset* obj)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetShaderAssetSourceCode")
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
if (obj->WaitForLoaded())
DebugLog::ThrowNullReference();
@@ -747,6 +779,7 @@ public:
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
CollisionCooking::Argument arg;
String path;
@@ -767,6 +800,7 @@ public:
static void GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetCollisionWires")
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
return;
@@ -792,32 +826,38 @@ public:
static void GetEditorBoxWithChildren(Actor* obj, BoundingBox* result)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetEditorBoxWithChildren")
INTERNAL_CALL_CHECK(obj);
*result = obj->GetEditorBoxChildren();
}
static void SetOptions(ManagedEditor::InternalOptions* options)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetOptions")
ManagedEditor::ManagedEditorOptions = *options;
}
static void DrawNavMesh()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_DrawNavMesh")
Navigation::DrawNavMesh();
}
static bool GetIsEveryAssemblyLoaded()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetIsEveryAssemblyLoaded")
return Scripting::IsEveryAssemblyLoaded();
}
static int32 GetLastProjectOpenedEngineBuild()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetLastProjectOpenedEngineBuild")
return Editor::LastProjectOpenedEngineBuild;
}
static bool GetIsCSGActive()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetIsCSGActive")
#if COMPILE_WITH_CSG_BUILDER
return CSG::Builder::IsActive();
#else
@@ -827,6 +867,7 @@ public:
static void RunVisualScriptBreakpointLoopTick(float deltaTime)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_RunVisualScriptBreakpointLoopTick")
// Update
Platform::Tick();
Engine::HasFocus = (Engine::MainWindow && Engine::MainWindow->IsFocused()) || Platform::GetHasFocus();
@@ -921,6 +962,7 @@ public:
static MonoArray* GetVisualScriptLocals()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptLocals")
MonoArray* result = nullptr;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack && stack->Scope)
@@ -969,6 +1011,7 @@ public:
static MonoArray* GetVisualScriptStackFrames()
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptStackFrames")
MonoArray* result = nullptr;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack)
@@ -1022,6 +1065,7 @@ public:
static bool EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocalManaged* local)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_EvaluateVisualScriptLocal")
Variant 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)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_DeserializeSceneObject")
PROFILE_CPU_NAMED("DeserializeSceneObject");
StringAnsi json;
@@ -1062,11 +1107,13 @@ public:
static void LoadAsset(Guid* id)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_LoadAsset")
Content::LoadAsync(*id);
}
static bool CanSetToRoot(Prefab* prefab, Actor* targetActor)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanSetToRoot")
// Reference: Prefab::ApplyAll(Actor* targetActor)
if (targetActor->GetPrefabID() != prefab->GetID())
return false;
@@ -1089,11 +1136,13 @@ public:
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;
}
static void SetAnimationTime(AnimatedModel* animatedModel, float time)
{
+ SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetAnimationTime")
if (animatedModel && animatedModel->GraphInstance.State.Count() == 1)
animatedModel->GraphInstance.State[0].Animation.TimePosition = time;
}
diff --git a/Source/Editor/Modules/ContentImportingModule.cs b/Source/Editor/Modules/ContentImportingModule.cs
index 4597f8d74..fa990dd7a 100644
--- a/Source/Editor/Modules/ContentImportingModule.cs
+++ b/Source/Editor/Modules/ContentImportingModule.cs
@@ -375,7 +375,9 @@ namespace FlaxEditor.Modules
Thread.Sleep(0);
_workerThread.Join(1000);
- _workerThread.Abort();
+#if !USE_NETCORE
+ _workerThread.Abort(); // Deprecated in .NET 7
+#endif
_workerThread = null;
}
diff --git a/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs b/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs
index 7042dfb92..07e29f506 100644
--- a/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs
+++ b/Source/Editor/Modules/SourceCodeEditing/CodeDocsModule.cs
@@ -257,7 +257,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
{
Profiler.BeginEvent("GetXmlDocs");
- var uri = new UriBuilder(assembly.CodeBase);
+ var uri = new UriBuilder(Utils.GetAssemblyLocation(assembly));
var path = Uri.UnescapeDataString(uri.Path);
var name = assembly.GetName().Name;
var xmlFilePath = Path.Combine(Path.GetDirectoryName(path), name + ".xml");
diff --git a/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs b/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs
index 010cd4942..1e7583dbe 100644
--- a/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs
+++ b/Source/Editor/Modules/SourceCodeEditing/CodeEditingModule.cs
@@ -391,9 +391,27 @@ namespace FlaxEditor.Modules.SourceCodeEditing
private static bool HasAssemblyValidAnyTypes(Assembly assembly)
{
+ var codeBase = Utils.GetAssemblyLocation(assembly);
+#if USE_NETCORE
+ if (assembly.ManifestModule.FullyQualifiedName == "")
+ return false;
+
+ if (string.IsNullOrEmpty(codeBase))
+ return true;
+
+ // Skip runtime related assemblies
+ string repositoryUrl = assembly.GetCustomAttributes().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
- var codeBase = assembly.CodeBase;
- return string.IsNullOrEmpty(codeBase) || !codeBase.Contains("/Mono/lib/mono/");
+ if (!codeBase.Contains("/Mono/lib/mono/"))
+ return true;
+#endif
+ return false;
}
private static bool HasAssemblyValidScriptingTypes(Assembly a)
diff --git a/Source/Editor/Options/InputBinding.cs b/Source/Editor/Options/InputBinding.cs
index e87cb24ae..2ef38ed84 100644
--- a/Source/Editor/Options/InputBinding.cs
+++ b/Source/Editor/Options/InputBinding.cs
@@ -218,6 +218,16 @@ namespace FlaxEditor.Options
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
diff --git a/Source/Editor/Plugins/PluginUtils.cs b/Source/Editor/Plugins/PluginUtils.cs
index 3c9765922..659e66db5 100644
--- a/Source/Editor/Plugins/PluginUtils.cs
+++ b/Source/Editor/Plugins/PluginUtils.cs
@@ -24,7 +24,7 @@ namespace FlaxEditor
var type = plugin.GetType();
var assembly = type.Assembly;
- var assemblyPath = assembly.Location;
+ var assemblyPath = Utils.GetAssemblyLocation(assembly);
var assemblyName = assembly.GetName().Name;
var dotEditorPos = assemblyName.LastIndexOf(".Editor", StringComparison.OrdinalIgnoreCase);
if (dotEditorPos != -1)
diff --git a/Source/Editor/Progress/Handlers/CompileScriptsProgress.cs b/Source/Editor/Progress/Handlers/CompileScriptsProgress.cs
index 339ea60f2..9a4bd608f 100644
--- a/Source/Editor/Progress/Handlers/CompileScriptsProgress.cs
+++ b/Source/Editor/Progress/Handlers/CompileScriptsProgress.cs
@@ -41,8 +41,10 @@ namespace FlaxEditor.Progress.Handlers
private void OnScriptsReload()
{
+#if !USE_NETCORE
// Clear types cache
Newtonsoft.Json.JsonSerializer.ClearCache();
+#endif
}
private void OnScriptsReloadEnd()
diff --git a/Source/Editor/ProjectInfo.cs b/Source/Editor/ProjectInfo.cs
index 0653fe101..64b425681 100644
--- a/Source/Editor/ProjectInfo.cs
+++ b/Source/Editor/ProjectInfo.cs
@@ -8,6 +8,110 @@ using Newtonsoft.Json;
namespace FlaxEditor
{
+ ///
+ ///
+ ///
+ public class FlaxVersionConverter : JsonConverter
+ {
+ // Original implementation is based on Newtonsoft.Json VersionConverter
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ }
+ else if (value is Version)
+ {
+ writer.WriteValue(value.ToString());
+ }
+ else
+ {
+ throw new JsonSerializationException("Expected Version object value");
+ }
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing property value of the JSON that is being converted.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+ else
+ {
+ if (reader.TokenType == JsonToken.StartObject)
+ {
+ try
+ {
+ reader.Read();
+ Dictionary values = new Dictionary();
+ while (reader.TokenType == JsonToken.PropertyName)
+ {
+ var key = reader.Value as string;
+ reader.Read();
+ var val = (long)reader.Value;
+ reader.Read();
+ values.Add(key, (int)val);
+ }
+
+ int major = 0, minor = 0, build = 0;
+ values.TryGetValue("Major", out major);
+ values.TryGetValue("Minor", out minor);
+ values.TryGetValue("Build", out build);
+
+ Version v = new Version(major, minor, build);
+ return v;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
+ }
+ }
+ else if (reader.TokenType == JsonToken.String)
+ {
+ try
+ {
+ Version v = new Version((string)reader.Value!);
+ return v;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
+ }
+ }
+ else
+ {
+ throw new Exception(String.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
+ }
+ }
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false.
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(Version);
+ }
+ }
+
///
/// Contains information about Flax project.
///
@@ -154,7 +258,7 @@ namespace FlaxEditor
{
// Load
var contents = File.ReadAllText(path);
- var project = JsonConvert.DeserializeObject(contents);
+ var project = JsonConvert.DeserializeObject(contents, new JsonSerializerSettings() { Converters = new[] { new FlaxVersionConverter() } });
project.ProjectPath = path;
project.ProjectFolderPath = StringUtils.NormalizePath(Path.GetDirectoryName(path));
diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp
index 25e22eaca..1f119f9af 100644
--- a/Source/Editor/Scripting/ScriptsBuilder.cpp
+++ b/Source/Editor/Scripting/ScriptsBuilder.cpp
@@ -176,6 +176,7 @@ bool ScriptsBuilder::IsReady()
void ScriptsBuilder::MarkWorkspaceDirty()
{
+ SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_MarkWorkspaceDirty")
ScopeLock scopeLock(_locker);
_lastSourceCodeEdited = DateTime::Now();
_wasProjectStructureChanged = true;
@@ -183,6 +184,7 @@ void ScriptsBuilder::MarkWorkspaceDirty()
void ScriptsBuilder::CheckForCompile()
{
+ SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_CheckForCompile")
ScopeLock scopeLock(_locker);
if (IsSourceDirty())
Compile();
@@ -205,6 +207,7 @@ void ScriptsBuilderImpl::onScriptsReloadEnd()
void ScriptsBuilder::Compile()
{
+ SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_Compile")
ScopeLock scopeLock(_locker);
// Request compile job
diff --git a/Source/Editor/States/BuildingScenesState.cs b/Source/Editor/States/BuildingScenesState.cs
index c6d749503..4261cc6d6 100644
--- a/Source/Editor/States/BuildingScenesState.cs
+++ b/Source/Editor/States/BuildingScenesState.cs
@@ -6,7 +6,9 @@ using System.Linq;
using FlaxEditor.Options;
using FlaxEditor.SceneGraph.Actors;
using FlaxEngine;
+using FlaxEditor.Utilities;
using FlaxEngine.Utilities;
+using Utils = FlaxEngine.Utils;
namespace FlaxEditor.States
{
diff --git a/Source/Editor/States/EditingSceneState.cs b/Source/Editor/States/EditingSceneState.cs
index 497b7679c..00bca5a21 100644
--- a/Source/Editor/States/EditingSceneState.cs
+++ b/Source/Editor/States/EditingSceneState.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine;
+using FlaxEditor.Utilities;
using FlaxEngine.Utilities;
namespace FlaxEditor.States
diff --git a/Source/Editor/States/ReloadingScriptsState.cs b/Source/Editor/States/ReloadingScriptsState.cs
index 8676a2af4..d76963734 100644
--- a/Source/Editor/States/ReloadingScriptsState.cs
+++ b/Source/Editor/States/ReloadingScriptsState.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine;
+using FlaxEditor.Utilities;
using FlaxEngine.Utilities;
namespace FlaxEditor.States
diff --git a/Source/Editor/Surface/Archetypes/Function.cs b/Source/Editor/Surface/Archetypes/Function.cs
index 5ff5d35d7..d96155584 100644
--- a/Source/Editor/Surface/Archetypes/Function.cs
+++ b/Source/Editor/Surface/Archetypes/Function.cs
@@ -12,6 +12,7 @@ using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
using FlaxEditor.Windows.Assets;
+using FlaxEngine.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -587,7 +588,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < _parameters.Length; i++)
{
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());
}
@@ -605,7 +606,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < parametersCount; i++)
{
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);
}
}
@@ -788,14 +789,14 @@ namespace FlaxEditor.Surface.Archetypes
{
reader.ReadByte(); // Version
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
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray();
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref signature.Params[i];
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
}
}
@@ -809,14 +810,14 @@ namespace FlaxEditor.Surface.Archetypes
{
reader.ReadByte(); // Version
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
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray();
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref signature.Params[i];
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
}
}
@@ -833,13 +834,13 @@ namespace FlaxEditor.Surface.Archetypes
{
writer.Write((byte)4); // Version
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
for (int i = 0; i < parameters.Length; i++)
{
ref var param = ref parameters[i];
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
}
return stream.ToArray();
@@ -1461,14 +1462,14 @@ namespace FlaxEditor.Surface.Archetypes
if (_signature.IsVirtual)
flags |= Flags.Virtual;
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;
writer.Write(parametersCount); // Parameters count
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref _signature.Parameters[i];
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); // Has default value
}
@@ -1497,13 +1498,13 @@ namespace FlaxEditor.Surface.Archetypes
var flags = (Flags)reader.ReadByte(); // Flags
_signature.IsStatic = (flags & Flags.Static) == Flags.Static;
_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
_signature.Parameters = new Parameter[parametersCount];
for (int i = 0; i < parametersCount; i++)
{
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 hasDefaultValue = reader.ReadByte() != 0; // Has default value
_signature.Parameters[i] = new Parameter
diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs
index cc9d77fa5..e3f79b148 100644
--- a/Source/Editor/Surface/Archetypes/Packing.cs
+++ b/Source/Editor/Surface/Archetypes/Packing.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection;
using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
+using FlaxEngine.Utilities;
using FlaxEngine;
namespace FlaxEditor.Surface.Archetypes
@@ -167,7 +168,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++)
{
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();
}
@@ -184,7 +185,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++)
{
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));
}
}
diff --git a/Source/Editor/Surface/AttributesEditor.cs b/Source/Editor/Surface/AttributesEditor.cs
index 29f540e62..d7d98b2e1 100644
--- a/Source/Editor/Surface/AttributesEditor.cs
+++ b/Source/Editor/Surface/AttributesEditor.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.Loader;
using System.Runtime.Serialization.Formatters.Binary;
using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors;
@@ -118,8 +119,13 @@ namespace FlaxEditor.Surface
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();
+#pragma warning disable SYSLIB0011
formatter.Serialize(stream, attributes);
+#pragma warning restore SYSLIB0011
_oldData = stream.ToArray();
}
editor.Select(new Proxy
@@ -141,8 +147,13 @@ namespace FlaxEditor.Surface
}
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();
+#pragma warning disable SYSLIB0011
formatter.Serialize(stream, newValue);
+#pragma warning restore SYSLIB0011
var newData = stream.ToArray();
if (!_oldData.SequenceEqual(newData))
{
diff --git a/Source/Editor/Surface/SurfaceMeta.cs b/Source/Editor/Surface/SurfaceMeta.cs
index 05003223b..1b07256b1 100644
--- a/Source/Editor/Surface/SurfaceMeta.cs
+++ b/Source/Editor/Surface/SurfaceMeta.cs
@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
using System.Runtime.Serialization.Formatters.Binary;
using FlaxEngine;
@@ -54,8 +56,13 @@ namespace FlaxEditor.Surface
{
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();
+#pragma warning disable SYSLIB0011
return (Attribute[])formatter.Deserialize(stream);
+#pragma warning restore SYSLIB0011
}
catch (Exception ex)
{
@@ -122,8 +129,13 @@ namespace FlaxEditor.Surface
}
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();
+#pragma warning disable SYSLIB0011
formatter.Serialize(stream, attributes);
+#pragma warning restore SYSLIB0011
AddEntry(AttributeMetaTypeID, stream.ToArray());
}
}
diff --git a/Source/Editor/Surface/SurfaceUtils.cs b/Source/Editor/Surface/SurfaceUtils.cs
index 59d90c916..20d80db7a 100644
--- a/Source/Editor/Surface/SurfaceUtils.cs
+++ b/Source/Editor/Surface/SurfaceUtils.cs
@@ -10,6 +10,7 @@ using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.Scripting;
using FlaxEditor.Utilities;
+using FlaxEngine.Utilities;
using FlaxEngine;
namespace FlaxEditor.Surface
diff --git a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs
index 05c77ab3a..1d5977f3c 100644
--- a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs
+++ b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs
@@ -8,6 +8,7 @@ using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
using FlaxEditor.Utilities;
using FlaxEngine;
+using FlaxEngine.Utilities;
using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.Surface
diff --git a/Source/Editor/Tools/Terrain/Sculpt/NoiseMode.cs b/Source/Editor/Tools/Terrain/Sculpt/NoiseMode.cs
index b6c7c160d..7b644623a 100644
--- a/Source/Editor/Tools/Terrain/Sculpt/NoiseMode.cs
+++ b/Source/Editor/Tools/Terrain/Sculpt/NoiseMode.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using FlaxEngine;
+using FlaxEditor.Utilities;
using FlaxEngine.Utilities;
namespace FlaxEditor.Tools.Terrain.Sculpt
diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs
index c9f3ac6e2..9c8a97f95 100644
--- a/Source/Editor/Windows/OutputLogWindow.cs
+++ b/Source/Editor/Windows/OutputLogWindow.cs
@@ -445,7 +445,7 @@ namespace FlaxEditor.Windows
int logCount;
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++)
{
diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs
index 23f74aa94..070b3b9cb 100644
--- a/Source/Editor/Windows/Profiler/CPU.cs
+++ b/Source/Editor/Windows/Profiler/CPU.cs
@@ -19,16 +19,16 @@ namespace FlaxEngine
{
get
{
- fixed (char* name = &Name0)
+ fixed (short* name = Name0)
{
- return new string(name);
+ return new string((char*)name);
}
}
}
internal unsafe bool NameStartsWith(string prefix)
{
- fixed (char* name = &Name0)
+ fixed (short* name = Name0)
{
fixed (char* p = prefix)
{
diff --git a/Source/Engine/Animations/AnimationGraph.cs b/Source/Engine/Animations/AnimationGraph.cs
index c337bcb6d..4bebecab0 100644
--- a/Source/Engine/Animations/AnimationGraph.cs
+++ b/Source/Engine/Animations/AnimationGraph.cs
@@ -3,6 +3,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
namespace FlaxEngine
{
@@ -44,6 +45,7 @@ namespace FlaxEngine
/// The node evaluation context structure.
///
[StructLayout(LayoutKind.Sequential)]
+ [NativeMarshalling(typeof(ContextMarshaler))]
public struct Context
{
///
@@ -92,6 +94,61 @@ namespace FlaxEngine
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)
+ {
+ }
+ }
+
///
/// 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.
@@ -203,14 +260,16 @@ namespace FlaxEngine
#region Internal Calls
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_HasConnection(ref CustomNode.Context context, int boxId);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_HasConnection")]
+ [return: MarshalAs(UnmanagedType.U1)]
+ internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object Internal_GetInputValue(ref CustomNode.Context context, int boxId);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetInputValue")]
+ [return: MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))]
+ internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr Internal_GetOutputImpulseData(ref CustomNode.Context context);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")]
+ internal static partial IntPtr Internal_GetOutputImpulseData(ref AnimationGraph.CustomNode.Context context);
#endregion
}
diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
index 45141bd94..a975736a6 100644
--- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
+++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
@@ -13,8 +13,8 @@
#include "Engine/Content/Assets/SkinnedModel.h"
#if USE_MONO
-
#include
+#endif
struct InternalInitData
{
@@ -52,6 +52,7 @@ namespace AnimGraphInternal
{
bool HasConnection(InternalContext* context, int32 boxId)
{
+ SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_HasConnection")
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -60,6 +61,7 @@ namespace AnimGraphInternal
MonoObject* GetInputValue(InternalContext* context, int32 boxId)
{
+ SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_GetInputValue")
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -77,14 +79,13 @@ namespace AnimGraphInternal
AnimGraphImpulse* GetOutputImpulseData(InternalContext* context)
{
+ SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")
const auto nodes = context->Node->GetNodes(context->GraphExecutor);
context->GraphExecutor->InitNodes(nodes);
return nodes;
}
}
-#endif
-
void AnimGraphExecutor::initRuntime()
{
#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;
// Peek managed object
- const auto obj = mono_gchandle_get_target(data.Handle);
+ const auto obj = MUtils::GetGCHandleTarget(data.Handle);
if (obj == nullptr)
{
LOG(Warning, "Custom node instance is null.");
@@ -166,7 +167,7 @@ void AnimGraph::ClearCustomNode(Node* node)
if (data.Handle)
{
#if USE_MONO
- mono_gchandle_free(data.Handle);
+ MUtils::FreeGCHandle(data.Handle);
#endif
data.Handle = 0;
}
@@ -216,7 +217,7 @@ bool AnimGraph::InitCustomNode(Node* node)
// Allocate managed node object (create GC handle to prevent destruction)
const auto obj = type->CreateInstance();
- const auto handleGC = mono_gchandle_new(obj, false);
+ const auto handleGC = MUtils::NewGCHandle(obj, false);
// Initialize node
InternalInitData initData;
@@ -228,7 +229,7 @@ bool AnimGraph::InitCustomNode(Node* node)
load->Invoke(obj, params, &exception);
if (exception)
{
- mono_gchandle_free(handleGC);
+ MUtils::FreeGCHandle(handleGC);
MException ex(exception);
ex.Log(LogType::Warning, TEXT("AnimGraph"));
diff --git a/Source/Engine/Animations/Graph/AnimGraph.h b/Source/Engine/Animations/Graph/AnimGraph.h
index 74b512303..69855a2ba 100644
--- a/Source/Engine/Animations/Graph/AnimGraph.h
+++ b/Source/Engine/Animations/Graph/AnimGraph.h
@@ -516,7 +516,7 @@ public:
///
/// The GC handle to the managed instance of the node object.
///
- uint32 Handle;
+ gchandle Handle;
};
struct CurveData
diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp
index a7aeeab3d..502228824 100644
--- a/Source/Engine/Content/Asset.cpp
+++ b/Source/Engine/Content/Asset.cpp
@@ -13,6 +13,7 @@
#include "Engine/Threading/MainThreadTask.h"
#include "Engine/Threading/ConcurrentTaskQueue.h"
#if USE_MONO
+#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include
#endif
@@ -270,7 +271,7 @@ void Asset::OnManagedInstanceDeleted()
if (_gcHandle)
{
#if USE_MONO
- mono_gchandle_free(_gcHandle);
+ MUtils::FreeGCHandle(_gcHandle);
#endif
_gcHandle = 0;
}
diff --git a/Source/Engine/Content/JsonAsset.cs b/Source/Engine/Content/JsonAsset.cs
index 26a7d4f28..78c601e7c 100644
--- a/Source/Engine/Content/JsonAsset.cs
+++ b/Source/Engine/Content/JsonAsset.cs
@@ -36,7 +36,10 @@ namespace FlaxEngine
var dataTypeName = DataTypeName;
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
- for (int i = 0; i < assemblies.Length; i++)
+
+ // Going through the assemblies in order will return collected assemblies first,
+ // use reverse order instead to find the type currently loaded assemblies instead.
+ for (int i = assemblies.Length-1; i >= 0; i--)
{
var assembly = assemblies[i];
if (assembly != null)
diff --git a/Source/Engine/Core/Compiler.h b/Source/Engine/Core/Compiler.h
index fa6b77d05..afe545eb5 100644
--- a/Source/Engine/Core/Compiler.h
+++ b/Source/Engine/Core/Compiler.h
@@ -32,6 +32,8 @@
#pragma clang diagnostic ignored "-Wnull-dereference"
#pragma clang diagnostic ignored "-Winvalid-noreturn"
+#define SCRIPTING_EXPORT(name)
+
#elif defined(__GNUC__)
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
@@ -86,6 +88,8 @@
#pragma warning(disable: 4251)
+#define SCRIPTING_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
+
#else
#pragma error "Unknown compiler."
diff --git a/Source/Engine/Core/Config/GameSettings.cs b/Source/Engine/Core/Config/GameSettings.cs
index eeb1d76b6..1145db264 100644
--- a/Source/Engine/Core/Config/GameSettings.cs
+++ b/Source/Engine/Core/Config/GameSettings.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using FlaxEngine;
namespace FlaxEditor.Content.Settings
@@ -562,8 +563,8 @@ namespace FlaxEditor.Content.Settings
///
/// Loads the current game settings asset and applies it to the engine runtime configuration.
///
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern void Apply();
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.GameSettings::Apply")]
+ public static partial void Apply();
#endif
}
}
diff --git a/Source/Engine/Core/Config/LayersAndTagsSettings.cs b/Source/Engine/Core/Config/LayersAndTagsSettings.cs
index 0396b7588..a6003595c 100644
--- a/Source/Engine/Core/Config/LayersAndTagsSettings.cs
+++ b/Source/Engine/Core/Config/LayersAndTagsSettings.cs
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using FlaxEngine;
namespace FlaxEditor.Content.Settings
@@ -24,14 +26,26 @@ namespace FlaxEditor.Content.Settings
/// Gets the current tags collection.
///
/// The tags collection.
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string[] GetCurrentTags();
+ internal static string[] GetCurrentTags()
+ {
+ return GetCurrentTags(out int _);
+ }
///
/// Gets the current layer names (max 32 items but trims last empty items).
///
/// The layers.
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern string[] GetCurrentLayers();
+ public static 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);
}
}
diff --git a/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs b/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs
index 2cf55e03e..4ad7ebfc0 100644
--- a/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs
@@ -18,6 +18,16 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
@@ -25,9 +35,9 @@ namespace FlaxEngine.TypeConverters
{
string[] v = str.Split(',');
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)
- 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.");
}
return base.ConvertFrom(context, culture, value);
@@ -39,7 +49,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs
index bde9d5bd5..3576862c0 100644
--- a/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs
index ccd27261f..33c4748ae 100644
--- a/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs
index ade244eb4..3123ffa42 100644
--- a/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs
index eb7041058..41256852e 100644
--- a/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs
index f6a7a5f73..a6de0b63c 100644
--- a/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs
index dd69a5bea..611e0b499 100644
--- a/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs
index 02b2b9a0c..30d6eac29 100644
--- a/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs
index 78f3fe2e7..2e029adcf 100644
--- a/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs
index 5f837e5ea..a222b6e3f 100644
--- a/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs b/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs
index 8cc95fe20..afdfb83f0 100644
--- a/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs
index 483e7a8ed..84bb24773 100644
--- a/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs
index 70336deb9..e02f620b6 100644
--- a/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs
index 8fcd5ba34..b19b2eaad 100644
--- a/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
return base.CanConvertFrom(context, sourceType);
}
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ {
+ return false;
+ }
+ return base.CanConvertTo(context, destinationType);
+ }
+
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
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);
}
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
if (destinationType == typeof(string))
{
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);
}
diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp
index 5bf8dbf88..3f47dd7a5 100644
--- a/Source/Engine/Core/Types/Variant.cpp
+++ b/Source/Engine/Core/Types/Variant.cpp
@@ -619,7 +619,11 @@ Variant::Variant(Asset* v)
Variant::Variant(_MonoObject* v)
: 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
@@ -957,9 +961,13 @@ Variant::~Variant()
Delete(AsDictionary);
break;
case VariantType::ManagedObject:
-#if USE_MONO
+#if USE_NETCORE
+ if (AsUint64)
+ MUtils::FreeGCHandle(AsUint64);
+ break;
+#elif USE_MONO
if (AsUint)
- mono_gchandle_free(AsUint);
+ MUtils::FreeGCHandle(AsUint);
break;
#endif
default: ;
@@ -1088,8 +1096,10 @@ Variant& Variant::operator=(const Variant& other)
AsDictionary = New>(*other.AsDictionary);
break;
case VariantType::ManagedObject:
-#if USE_MONO
- AsUint = other.AsUint ? mono_gchandle_new(mono_gchandle_get_target(other.AsUint), true) : 0;
+#if USE_NETCORE
+ 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
break;
case VariantType::Null:
@@ -1217,7 +1227,7 @@ bool Variant::operator==(const Variant& other) const
case VariantType::ManagedObject:
#if USE_MONO
// 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
default:
return false;
@@ -1308,8 +1318,10 @@ Variant::operator bool() const
case VariantType::Asset:
return AsAsset != nullptr;
case VariantType::ManagedObject:
-#if USE_MONO
- return AsUint != 0 && mono_gchandle_get_target(AsUint) != nullptr;
+#if USE_NETCORE
+ return AsUint64 != 0 && MUtils::GetGCHandleTarget(AsUint64) != nullptr;
+#elif USE_MONO
+ return AsUint != 0 && MUtils::GetGCHandleTarget(AsUint) != nullptr;
#endif
default:
return false;
@@ -1578,8 +1590,10 @@ Variant::operator void*() const
case VariantType::Blob:
return AsBlob.Data;
case VariantType::ManagedObject:
-#if USE_MONO
- return AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
+#if USE_NETCORE
+ return AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
+#elif USE_MONO
+ return AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
#endif
default:
return nullptr;
@@ -1623,8 +1637,10 @@ Variant::operator ScriptingObject*() const
Variant::operator _MonoObject*() const
{
-#if USE_MONO
- return Type.Type == VariantType::ManagedObject && AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
+#if USE_NETCORE
+ return Type.Type == VariantType::ManagedObject && AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
+#elif USE_MONO
+ return Type.Type == VariantType::ManagedObject && AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
#else
return nullptr;
#endif
@@ -2337,9 +2353,14 @@ void Variant::SetType(const VariantType& type)
Delete(AsDictionary);
break;
case VariantType::ManagedObject:
-#if USE_MONO
+#if USE_NETCORE
+ if (AsUint64)
+ MUtils::FreeGCHandle(AsUint64);
+ break;
+#elif USE_MONO
if (AsUint)
- mono_gchandle_free(AsUint);
+ MUtils::FreeGCHandle(AsUint);
+ break;
#endif
break;
default: ;
@@ -2447,9 +2468,14 @@ void Variant::SetType(VariantType&& type)
Delete(AsDictionary);
break;
case VariantType::ManagedObject:
-#if USE_MONO
+#if USE_NETCORE
+ if (AsUint64)
+ MUtils::FreeGCHandle(AsUint64);
+ break;
+#elif USE_MONO
if (AsUint)
- mono_gchandle_free(AsUint);
+ MUtils::FreeGCHandle(AsUint);
+ break;
#endif
break;
default: ;
@@ -2632,7 +2658,11 @@ void Variant::SetManagedObject(_MonoObject* object)
{
if (Type.Type != VariantType::ManagedObject)
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
{
@@ -2751,8 +2781,10 @@ String Variant::ToString() const
case VariantType::Typename:
return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0);
case VariantType::ManagedObject:
-#if USE_MONO
- return AsUint ? String(MUtils::ToString(mono_object_to_string(mono_gchandle_get_target(AsUint), nullptr))) : TEXT("null");
+#if USE_NETCORE
+ 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
default:
return String::Empty;
@@ -3671,7 +3703,12 @@ void Variant::AllocStructure()
Platform::MemoryCopy(AsBlob.Data, data, AsBlob.Length);
#else
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
}
else
@@ -3763,8 +3800,10 @@ uint32 GetHash(const Variant& key)
case VariantType::Typename:
return GetHash((const char*)key.AsBlob.Data);
case VariantType::ManagedObject:
-#if USE_MONO
- return key.AsUint ? (uint32)mono_object_hash(mono_gchandle_get_target(key.AsUint)) : 0;
+#if USE_NETCORE
+ 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
default:
return 0;
diff --git a/Source/Engine/Engine/DebugLogHandler.cs b/Source/Engine/Engine/DebugLogHandler.cs
index b7bc0d52e..288c5e0d0 100644
--- a/Source/Engine/Engine/DebugLogHandler.cs
+++ b/Source/Engine/Engine/DebugLogHandler.cs
@@ -4,10 +4,12 @@ using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Security;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
namespace FlaxEngine
{
- internal sealed class DebugLogHandler : ILogHandler
+ internal partial class DebugLogHandler : ILogHandler
{
///
/// Occurs on sending a log message.
@@ -64,14 +66,14 @@ namespace FlaxEngine
Debug.Logger.LogException(exception);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_LogWrite(LogType level, string msg);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_LogWrite", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_LogWrite(LogType level, string msg);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_Log(LogType level, string msg, IntPtr obj, string stackTrace);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_Log", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_Log(LogType level, string msg, IntPtr obj, string stackTrace);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void Internal_LogException(Exception exception, IntPtr obj);
+ [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_LogException", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
+ internal static partial void Internal_LogException([MarshalUsing(typeof(FlaxEngine.ExceptionMarshaller))] Exception exception, IntPtr obj);
[SecuritySafeCritical]
public static string Internal_GetStackTrace()
diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs
new file mode 100644
index 000000000..34daf9fcf
--- /dev/null
+++ b/Source/Engine/Engine/NativeInterop.cs
@@ -0,0 +1,2256 @@
+#if USE_NETCORE
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+using System.IO;
+using System.Runtime.CompilerServices;
+using FlaxEngine.Assertions;
+using FlaxEngine.Utilities;
+using System.Runtime.InteropServices.Marshalling;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
+using FlaxEngine.Visject;
+using System.Diagnostics;
+using System.Collections;
+using FlaxEditor.Content;
+
+#pragma warning disable CS1591
+#pragma warning disable CS8632
+
+[assembly: DisableRuntimeMarshalling]
+
+namespace FlaxEngine
+{
+ #region Native structures
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ManagedClass
+ {
+ internal IntPtr typeHandle;
+ internal IntPtr name;
+ internal IntPtr fullname;
+ internal IntPtr @namespace;
+ internal uint typeAttributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ClassMethod
+ {
+ internal IntPtr name;
+ internal int numParameters;
+ internal IntPtr typeHandle;
+ internal uint methodAttributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ClassField
+ {
+ internal IntPtr name;
+ internal IntPtr fieldHandle;
+ internal IntPtr fieldTypeHandle;
+ internal uint fieldAttributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ClassProperty
+ {
+ internal IntPtr name;
+ internal IntPtr getterHandle;
+ internal IntPtr setterHandle;
+ internal uint getterFlags;
+ internal uint setterFlags;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ClassAttribute
+ {
+ internal IntPtr name;
+ internal IntPtr attributeHandle;
+ internal IntPtr attributeTypeHandle;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct VariantNative
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct VariantNativeType
+ {
+ internal VariantUtils.VariantType types;
+ internal IntPtr TypeName; // char*
+ }
+
+ [FieldOffset(0)]
+ VariantNativeType Type;
+
+ [FieldOffset(8)]
+ byte AsBool;
+
+ [FieldOffset(8)]
+ short AsInt16;
+
+ [FieldOffset(8)]
+ ushort AsUint16;
+
+ [FieldOffset(8)]
+ int AsInt;
+
+ [FieldOffset(8)]
+ uint AsUint;
+
+ [FieldOffset(8)]
+ long AsInt64;
+
+ [FieldOffset(8)]
+ ulong AsUint64;
+
+ [FieldOffset(8)]
+ float AsFloat;
+
+ [FieldOffset(8)]
+ double AsDouble;
+
+ [FieldOffset(8)]
+ IntPtr AsPointer;
+
+ [FieldOffset(8)]
+ int AsData0;
+
+ [FieldOffset(12)]
+ int AsData1;
+
+ [FieldOffset(16)]
+ int AsData2;
+
+ [FieldOffset(20)]
+ int AsData3;
+
+ [FieldOffset(24)]
+ int AsData4;
+
+ [FieldOffset(28)]
+ int AsData5;
+ }
+
+#if false
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GuidNative
+ {
+ internal int A;
+ internal short B;
+ internal short C;
+ internal byte D;
+ internal byte E;
+ internal byte F;
+ internal byte G;
+ internal byte H;
+ internal byte I;
+ internal byte J;
+ internal byte K;
+
+ internal GuidNative(Guid guid)
+ {
+ byte[] bytes = guid.ToByteArray();
+ A = MemoryMarshal.Cast(bytes.AsSpan())[0];
+ B = MemoryMarshal.Cast(bytes.AsSpan())[4];
+ C = MemoryMarshal.Cast(bytes.AsSpan())[6];
+ D = bytes[8];
+ E = bytes[9];
+ F = bytes[10];
+ G = bytes[11];
+ H = bytes[12];
+ I = bytes[13];
+ J = bytes[14];
+ K = bytes[15];
+ }
+
+ internal static implicit operator Guid(GuidNative guid) => new Guid(guid.A, guid.B, guid.C, guid.D, guid.E, guid.F, guid.G, guid.H, guid.I, guid.J, guid.K);
+ internal static explicit operator GuidNative(Guid guid) => new GuidNative(guid);
+ }
+#endif
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct VersionNative
+ {
+ internal int _Major;
+ internal int _Minor;
+ internal int _Build;
+ internal int _Revision;
+
+ internal VersionNative(Version ver)
+ {
+ _Major = ver.Major;
+ _Minor = ver.Minor;
+ _Build = ver.Build;
+ _Revision = ver.Revision;
+ }
+
+ internal Version GetVersion()
+ {
+ return new Version(_Major, _Minor, _Build, _Revision);
+ }
+ }
+
+ #endregion
+
+ #region Wrappers
+ ///
+ /// Wrapper for managed arrays that needs to be pinned.
+ ///
+ internal class ManagedArray
+ {
+ internal Array array = null;
+ internal GCHandle handle;
+ internal int elementSize;
+
+ internal ManagedArray(Array arr)
+ {
+ handle = GCHandle.Alloc(arr, GCHandleType.Pinned);
+ elementSize = Marshal.SizeOf(arr.GetType().GetElementType());
+ array = arr;
+ }
+
+ ~ManagedArray()
+ {
+ if (array != null)
+ Release();
+ }
+
+ internal void Release()
+ {
+ handle.Free();
+ array = null;
+ }
+
+ internal IntPtr PointerToPinnedArray => Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
+
+ internal int Length => array.Length;
+
+ internal static ManagedArray Get(ref T[] arr)
+ {
+ return new ManagedArray(arr);
+ }
+
+ internal static ManagedArray Get(Array arr)
+ {
+ ManagedArray managedArray = new ManagedArray(arr);
+ return managedArray;
+ }
+ }
+
+ internal static class ManagedString
+ {
+ internal static GCHandle EmptyStringHandle = GCHandle.Alloc(string.Empty);
+
+ [System.Diagnostics.DebuggerStepThrough]
+ internal static unsafe IntPtr ToNative(string str)
+ {
+ if (str == null)
+ return IntPtr.Zero;
+ else if (str == string.Empty)
+ return GCHandle.ToIntPtr(EmptyStringHandle);
+#if false
+ // HACK: Pin the string and pass the address to it including the length, no marshalling required
+ GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
+ IntPtr ptr = handle.AddrOfPinnedObject() - sizeof(int);
+
+ pinnedStrings.TryAdd(ptr, handle);
+ return ptr;
+#endif
+
+#if false
+ // HACK: Return address to the allocated string structure which includes the string length.
+ // We assume the string content is copied in native side before GC frees it.
+ IntPtr ptr = (Unsafe.Read(Unsafe.AsPointer(ref str)) + sizeof(int) * 2);
+#endif
+ IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(str, GCHandleType.Weak));
+ return ptr;
+ }
+
+ [System.Diagnostics.DebuggerStepThrough]
+ internal static string ToManaged(IntPtr ptr)
+ {
+ if (ptr == IntPtr.Zero)
+ return null;
+
+ return (string)GCHandle.FromIntPtr(ptr).Target;
+ }
+
+ [System.Diagnostics.DebuggerStepThrough]
+ internal static void Free(IntPtr ptr)
+ {
+ if (ptr == IntPtr.Zero)
+ return;
+
+ GCHandle handle = GCHandle.FromIntPtr(ptr);
+ if (handle == EmptyStringHandle)
+ return;
+
+ handle.Free();
+ }
+ }
+
+ #endregion
+
+ #region Marshallers
+
+ [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(GCHandleMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(GCHandleMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(GCHandleMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(GCHandleMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(GCHandleMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(object), MarshalMode.ElementOut, typeof(GCHandleMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedRef, typeof(GCHandleMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(GCHandleMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(object), MarshalMode.ElementRef, typeof(GCHandleMarshaller))]
+ internal static class GCHandleMarshaller
+ {
+ public static class NativeToManaged
+ {
+ public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : GCHandle.FromIntPtr(unmanaged).Target;
+ public static void Free(IntPtr unmanaged)
+ {
+ // This is a permanent handle, do not release it
+ }
+ }
+ public static class ManagedToNative
+ {
+ public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
+ public static void Free(IntPtr unmanaged)
+ {
+ if (unmanaged == IntPtr.Zero)
+ return;
+ GCHandle.FromIntPtr(unmanaged).Free();
+ }
+ }
+ public struct Bidirectional
+ {
+ object managed;
+ IntPtr unmanaged;
+ public void FromManaged(object managed) { this.managed = managed; }
+ public IntPtr ToUnmanaged() { unmanaged = GCHandleMarshaller.ToNative(managed); return unmanaged; }
+ public void FromUnmanaged(IntPtr unmanaged) { this.unmanaged = unmanaged; }
+ public object ToManaged() { managed = GCHandleMarshaller.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; }
+ public void Free()
+ {
+ // FIXME, might be a permanent handle or a temporary one
+ throw new NotImplementedException();
+ /*if (unmanaged == IntPtr.Zero)
+ return;
+ GCHandle.FromIntPtr(unmanaged).Free();*/
+ }
+ }
+ internal static object ConvertToManaged(IntPtr unmanaged) => ToManaged(unmanaged);
+ internal static IntPtr ConvertToUnmanaged(object managed) => ToNative(managed);
+ internal static object ToManaged(IntPtr managed) => managed != IntPtr.Zero ? GCHandle.FromIntPtr(managed).Target : null;
+ internal static IntPtr ToNative(object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
+ internal static void Free(IntPtr unmanaged)
+ {
+ if (unmanaged == IntPtr.Zero)
+ return;
+ GCHandle.FromIntPtr(unmanaged).Free();
+ }
+ }
+
+ [CustomMarshaller(typeof(System.Type), MarshalMode.Default, typeof(SystemTypeMarshaller))]
+ internal static class SystemTypeMarshaller
+ {
+ internal static System.Type ConvertToManaged(IntPtr unmanaged) => (System.Type)GCHandleMarshaller.ConvertToManaged(unmanaged);
+
+ internal static IntPtr ConvertToUnmanaged(System.Type managed)
+ {
+ if (managed == null)
+ return IntPtr.Zero;
+
+ GCHandle handle = NativeInterop.GetOrAddTypeGCHandle(managed);
+ return GCHandle.ToIntPtr(handle);
+ }
+
+ internal static void Free(IntPtr unmanaged)
+ {
+ // Cached handle, do not release
+ }
+ }
+
+ [CustomMarshaller(typeof(Exception), MarshalMode.Default, typeof(ExceptionMarshaller))]
+ internal static class ExceptionMarshaller
+ {
+ internal static Exception ConvertToManaged(IntPtr unmanaged) => (Exception)GCHandleMarshaller.ConvertToManaged(unmanaged);
+ internal static IntPtr ConvertToUnmanaged(Exception managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);
+ internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);
+ }
+
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller.NativeToManaged))]
+ internal static class ObjectMarshaller
+ {
+ public static class NativeToManaged
+ {
+ public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? (FlaxEngine.Object)GCHandle.FromIntPtr(unmanaged).Target : null;
+ }
+ public static class ManagedToNative
+ {
+ public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
+ }
+ }
+
+ [CustomMarshaller(typeof(CultureInfo), MarshalMode.Default, typeof(CultureInfoMarshaller))]
+ internal static class CultureInfoMarshaller
+ {
+ internal static CultureInfo ConvertToManaged(IntPtr unmanaged) => (CultureInfo)GCHandleMarshaller.ConvertToManaged(unmanaged);
+ internal static IntPtr ConvertToUnmanaged(CultureInfo managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);
+ internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);
+ }
+
+ [CustomMarshaller(typeof(Array), MarshalMode.Default, typeof(SystemArrayMarshaller))]
+ internal static class SystemArrayMarshaller
+ {
+ internal static Array ConvertToManaged(IntPtr unmanaged) => (Array)GCHandleMarshaller.ConvertToManaged(unmanaged);
+ internal static IntPtr ConvertToUnmanaged(Array managed) => GCHandleMarshaller.ConvertToUnmanaged(managed);
+ internal static void Free(IntPtr unmanaged) => GCHandleMarshaller.Free(unmanaged);
+ }
+
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedIn, typeof(DictionaryMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.UnmanagedToManagedOut, typeof(DictionaryMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ElementIn, typeof(DictionaryMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedOut, typeof(DictionaryMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.UnmanagedToManagedIn, typeof(DictionaryMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ElementOut, typeof(DictionaryMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedRef, typeof(DictionaryMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.UnmanagedToManagedRef, typeof(DictionaryMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ElementRef, typeof(DictionaryMarshaller<,>))]
+ internal static unsafe class DictionaryMarshaller
+ {
+ public static class NativeToManaged
+ {
+ public static Dictionary ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller.ToManaged(unmanaged);
+ public static void Free(IntPtr unmanaged) => DictionaryMarshaller.Free(unmanaged);
+ }
+ public static class ManagedToNative
+ {
+ public static IntPtr ConvertToUnmanaged(Dictionary managed) => DictionaryMarshaller.ToNative(managed);
+ public static void Free(IntPtr unmanaged) => DictionaryMarshaller.Free(unmanaged);
+ }
+
+ public struct Bidirectional
+ {
+ Dictionary managed;
+ IntPtr unmanaged;
+ public void FromManaged(Dictionary managed) { this.managed = managed; }
+ public IntPtr ToUnmanaged() { unmanaged = DictionaryMarshaller.ToNative(managed); return unmanaged; }
+ public void FromUnmanaged(IntPtr unmanaged) { this.unmanaged = unmanaged; }
+ public Dictionary ToManaged() { managed = DictionaryMarshaller.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; }
+ public void Free() => DictionaryMarshaller.Free(unmanaged);
+ }
+
+ public static Dictionary ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? (Dictionary)GCHandle.FromIntPtr(unmanaged).Target : null;
+ public static IntPtr ConvertToUnmanaged(Dictionary managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
+
+ public static Dictionary ToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? (Dictionary)GCHandle.FromIntPtr(unmanaged).Target : null;
+ public static IntPtr ToNative(Dictionary managed) => managed != null ? GCHandle.ToIntPtr(GCHandle.Alloc(managed)) : IntPtr.Zero;
+ public static void Free(IntPtr unmanaged)
+ {
+ if (unmanaged != IntPtr.Zero)
+ GCHandle.FromIntPtr(unmanaged).Free();
+ }
+ }
+
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(ArrayMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(ArrayMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(ArrayMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(ArrayMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(ArrayMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(ArrayMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(ArrayMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(ArrayMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(ArrayMarshaller<,>))]
+ [ContiguousCollectionMarshaller]
+ internal static unsafe class ArrayMarshaller
+ where TUnmanagedElement : unmanaged
+ {
+ public static class NativeToManaged
+ {
+ internal static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements)
+ {
+ if (unmanaged is null)
+ return null;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target;
+ return new T[numElements];
+ }
+
+ internal static Span GetManagedValuesDestination(T[]? managed)
+ => managed;
+
+ internal static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements)
+ {
+ if (unmanagedValue == null)
+ return ReadOnlySpan.Empty;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanagedValue)).Target;
+ return new ReadOnlySpan(array.array as TUnmanagedElement[]);
+ }
+
+ internal static void Free(TUnmanagedElement* unmanaged)
+ {
+ if (unmanaged == null)
+ return;
+
+ GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged));
+ ((ManagedArray)handle.Target).Release();
+ handle.Free();
+ }
+
+ internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
+ {
+ if (unmanaged == null)
+ return Span.Empty;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target;
+ return new Span(array.array as TUnmanagedElement[]);
+ }
+ }
+ public static class ManagedToNative
+ {
+ internal static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
+ {
+ if (managed is null)
+ {
+ numElements = 0;
+ return null;
+ }
+
+ numElements = managed.Length;
+
+ ManagedArray array = ManagedArray.Get(new TUnmanagedElement[numElements]);
+ var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(array));
+
+ return (TUnmanagedElement*)ptr;
+ }
+
+ internal static ReadOnlySpan GetManagedValuesSource(T[]? managed)
+ => managed;
+
+ internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
+ {
+ if (unmanaged == null)
+ return Span.Empty;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target;
+ return new Span(array.array as TUnmanagedElement[]);
+ }
+
+ internal static void Free(TUnmanagedElement* unmanaged)
+ {
+ if (unmanaged == null)
+ return;
+
+ GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged));
+ ((ManagedArray)handle.Target).Release();
+ handle.Free();
+ }
+ }
+ public struct Bidirectional
+ {
+ T[] managedArray;
+ ManagedArray unmanagedArray;
+ GCHandle handle;
+
+ public void FromManaged(T[]? managed)
+ {
+ if (managed == null)
+ return;
+
+ managedArray = managed;
+ unmanagedArray = ManagedArray.Get(new TUnmanagedElement[managed.Length]);
+ handle = GCHandle.Alloc(unmanagedArray);
+ }
+
+ public ReadOnlySpan GetManagedValuesSource()
+ => managedArray;
+
+ public Span GetUnmanagedValuesDestination()
+ {
+ if (unmanagedArray == null)
+ return Span.Empty;
+
+ return new Span(unmanagedArray.array as TUnmanagedElement[]);
+ }
+
+ public TUnmanagedElement* ToUnmanaged()
+ {
+ return (TUnmanagedElement*)GCHandle.ToIntPtr(handle);
+ }
+
+ public void FromUnmanaged(TUnmanagedElement* value)
+ {
+ ManagedArray arr = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(value)).Target;
+ managedArray = new T[arr.Length];
+ }
+
+ public ReadOnlySpan GetUnmanagedValuesSource(int numElements)
+ {
+ if (unmanagedArray == null)
+ return ReadOnlySpan.Empty;
+
+ return new ReadOnlySpan(unmanagedArray.array as TUnmanagedElement[]);
+ }
+
+ public Span GetManagedValuesDestination(int numElements)
+ => managedArray;
+
+ public T[] ToManaged()
+ => managedArray;
+
+ public void Free()
+ {
+ unmanagedArray.Release();
+ handle.Free();
+ }
+ }
+
+ internal static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
+ {
+ if (managed is null)
+ {
+ numElements = 0;
+ return null;
+ }
+
+ numElements = managed.Length;
+
+ ManagedArray array = ManagedArray.Get(new TUnmanagedElement[numElements]);
+ var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(array));
+
+ return (TUnmanagedElement*)ptr;
+ }
+
+ internal static ReadOnlySpan GetManagedValuesSource(T[]? managed)
+ => managed;
+
+ internal static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements)
+ {
+ if (unmanaged == null)
+ return Span.Empty;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target;
+ return new Span(array.array as TUnmanagedElement[]);
+ }
+
+ internal static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements)
+ {
+ if (unmanaged is null)
+ return null;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanaged)).Target;
+ return new T[numElements];
+ }
+
+ internal static Span GetManagedValuesDestination(T[]? managed)
+ => managed;
+
+ internal static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements)
+ {
+ if (unmanagedValue == null)
+ return ReadOnlySpan.Empty;
+
+ ManagedArray array = (ManagedArray)GCHandle.FromIntPtr(new IntPtr(unmanagedValue)).Target;
+ return new ReadOnlySpan(array.array as TUnmanagedElement[]);
+ }
+
+ internal static void Free(TUnmanagedElement* unmanaged)
+ {
+ if (unmanaged == null)
+ return;
+
+ GCHandle handle = GCHandle.FromIntPtr(new IntPtr(unmanaged));
+ ((ManagedArray)handle.Target).Release();
+ handle.Free();
+ }
+
+ internal static ref T GetPinnableReference(T[]? array)
+ {
+ if (array is null)
+ return ref Unsafe.NullRef();
+
+ ManagedArray managedArray = ManagedArray.Get(array);
+ var ptr = GCHandle.ToIntPtr(GCHandle.Alloc(managedArray));
+ return ref Unsafe.AsRef(ptr.ToPointer());
+ }
+ }
+
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(StringMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(StringMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedRef, typeof(StringMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedRef, typeof(StringMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringMarshaller))]
+ internal static class StringMarshaller
+ {
+ public static class NativeToManaged
+ {
+ public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
+ public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
+ }
+ public static class ManagedToNative
+ {
+ public static unsafe IntPtr ConvertToUnmanaged(string managed)
+ {
+ if (managed == null)
+ return IntPtr.Zero;
+#if false
+ // HACK: Pin the string and pass the address to it including the length, no marshalling required
+ GCHandle handle = GCHandle.Alloc(managed, GCHandleType.Pinned);
+ IntPtr ptr = handle.AddrOfPinnedObject() - sizeof(int);
+
+ pinnedStrings.TryAdd(ptr, handle);
+ return ptr;
+#endif
+
+#if false
+ // HACK: Return address to the allocated string structure which includes the string length.
+ // We assume the string content is copied in native side before GC frees it.
+ IntPtr ptr = (Unsafe.Read(Unsafe.AsPointer(ref managed)) + sizeof(int) * 2);
+#endif
+ IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(managed, GCHandleType.Pinned));
+ return ptr;
+ }
+ public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
+ }
+ public struct Bidirectional
+ {
+ string managed;
+ IntPtr unmanaged;
+ public void FromManaged(string managed) { this.managed = managed; }
+ public IntPtr ToUnmanaged() { unmanaged = ManagedString.ToNative(managed); return unmanaged; }
+ public void FromUnmanaged(IntPtr unmanaged) { this.unmanaged = unmanaged; }
+ public string ToManaged() { managed = ManagedString.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; }
+ public void Free() => ManagedString.Free(unmanaged);
+ }
+ internal static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
+ internal static IntPtr ConvertToUnmanaged(string managed) => ManagedString.ToNative(managed);
+ internal static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
+
+ internal static string ToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
+ internal static IntPtr ToNative(string managed) => ManagedString.ToNative(managed);
+ }
+
+ #endregion
+
+ ///
+ /// Provides a Mono-like API for native code to access managed runtime.
+ ///
+ internal unsafe static partial class NativeInterop
+ {
+ internal static Dictionary AssemblyLocations = new Dictionary();
+
+ private static bool firstAssemblyLoaded = false;
+
+ private static Dictionary typeCache = new Dictionary();
+
+ private static Dictionary marshallableStructCache = new Dictionary();
+
+ private static IntPtr boolTruePtr = GCHandle.ToIntPtr(GCHandle.Alloc((int)1, GCHandleType.Pinned));
+ private static IntPtr boolFalsePtr = GCHandle.ToIntPtr(GCHandle.Alloc((int)0, GCHandleType.Pinned));
+
+ private static List methodHandles = new();
+ private static List methodHandlesCollectible = new();
+ private static Dictionary cachedDelegates = new Dictionary();
+ private static Dictionary cachedDelegatesCollectible = new Dictionary();
+ private static Dictionary typeHandleCache = new Dictionary();
+ private static Dictionary typeHandleCacheCollectible = new Dictionary();
+ private static List fieldHandleCache = new();
+ private static List fieldHandleCacheCollectible = new();
+ private static Dictionary