Merge branch 'GoaLitiuM-dotnet7' into dotnet7

This commit is contained in:
Wojciech Figat
2022-12-16 13:12:27 +01:00
134 changed files with 7253 additions and 596 deletions

View File

@@ -5,6 +5,7 @@ jobs:
# Game # Game
game-windows: game-windows:
if: ${{ false }}
name: Game (Android, Release ARM64) name: Game (Android, Release ARM64)
runs-on: "windows-2019" runs-on: "windows-2019"
steps: steps:

View File

@@ -5,6 +5,7 @@ jobs:
# Editor # Editor
editor-linux: editor-linux:
if: ${{ false }}
name: Editor (Linux, Development x64) name: Editor (Linux, Development x64)
runs-on: "ubuntu-20.04" runs-on: "ubuntu-20.04"
steps: steps:
@@ -28,6 +29,7 @@ jobs:
# Game # Game
game-linux: game-linux:
if: ${{ false }}
name: Game (Linux, Release x64) name: Game (Linux, Release x64)
runs-on: "ubuntu-20.04" runs-on: "ubuntu-20.04"
steps: steps:

View File

@@ -5,6 +5,7 @@ jobs:
# Editor # Editor
editor-mac: editor-mac:
if: ${{ false }}
name: Editor (Mac, Development x64) name: Editor (Mac, Development x64)
runs-on: "macos-latest" runs-on: "macos-latest"
steps: steps:
@@ -22,6 +23,7 @@ jobs:
# Game # Game
game-mac: game-mac:
if: ${{ false }}
name: Game (Mac, Release x64) name: Game (Mac, Release x64)
runs-on: "macos-latest" runs-on: "macos-latest"
steps: steps:

View File

@@ -6,12 +6,19 @@ jobs:
# Editor # Editor
editor-windows: editor-windows:
name: Editor (Windows, Development x64) name: Editor (Windows, Development x64)
runs-on: "windows-2019" runs-on: "windows-2022"
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup Vulkan - name: Setup Vulkan
uses: ./.github/actions/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 - name: Checkout LFS
run: | run: |
git lfs version git lfs version
@@ -23,12 +30,16 @@ jobs:
# Game # Game
game-windows: game-windows:
name: Game (Windows, Release x64) name: Game (Windows, Release x64)
runs-on: "windows-2019" runs-on: "windows-2022"
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup Vulkan - name: Setup Vulkan
uses: ./.github/actions/vulkan uses: ./.github/actions/vulkan
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Checkout LFS - name: Checkout LFS
run: | run: |
git lfs version git lfs version

View File

@@ -5,6 +5,7 @@ jobs:
# Tests # Tests
tests-linux: tests-linux:
if: ${{ false }}
name: Tests (Linux) name: Tests (Linux)
runs-on: "ubuntu-20.04" runs-on: "ubuntu-20.04"
steps: steps:

View File

@@ -10,8 +10,9 @@ if [ $testfilesize -le 1000 ]; then
fi fi
# Compile the build tool. # 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. # 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 --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 "$@"

View File

@@ -28,9 +28,9 @@ fc /b Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Fla
if not errorlevel 1 goto SkipClean if not errorlevel 1 goto SkipClean
copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul 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 :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 if errorlevel 1 goto Error_CompilationFailed
Binaries\Tools\Flax.Build.exe %* Binaries\Tools\Flax.Build.exe %*

View File

@@ -11,6 +11,7 @@
"EditorTarget": "FlaxEditor", "EditorTarget": "FlaxEditor",
"Configuration": { "Configuration": {
"UseCSharp": true, "UseCSharp": true,
"UseLargeWorlds": false "UseLargeWorlds": false,
"UseDotNet": true
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -218,6 +218,16 @@ namespace FlaxEditor.Options
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {

View File

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

View File

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

View File

@@ -8,6 +8,110 @@ using Newtonsoft.Json;
namespace FlaxEditor namespace FlaxEditor
{ {
/// <summary>
///
/// </summary>
public class FlaxVersionConverter : JsonConverter
{
// Original implementation is based on Newtonsoft.Json VersionConverter
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
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");
}
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
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<string, int> values = new Dictionary<string, int>();
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));
}
}
}
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Version);
}
}
/// <summary> /// <summary>
/// Contains information about Flax project. /// Contains information about Flax project.
/// </summary> /// </summary>
@@ -154,7 +258,7 @@ namespace FlaxEditor
{ {
// Load // Load
var contents = File.ReadAllText(path); var contents = File.ReadAllText(path);
var project = JsonConvert.DeserializeObject<ProjectInfo>(contents); var project = JsonConvert.DeserializeObject<ProjectInfo>(contents, new JsonSerializerSettings() { Converters = new[] { new FlaxVersionConverter() } });
project.ProjectPath = path; project.ProjectPath = path;
project.ProjectFolderPath = StringUtils.NormalizePath(Path.GetDirectoryName(path)); project.ProjectFolderPath = StringUtils.NormalizePath(Path.GetDirectoryName(path));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -36,7 +36,10 @@ namespace FlaxEngine
var dataTypeName = DataTypeName; var dataTypeName = DataTypeName;
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 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]; var assembly = assemblies[i];
if (assembly != null) if (assembly != null)

View File

@@ -32,6 +32,8 @@
#pragma clang diagnostic ignored "-Wnull-dereference" #pragma clang diagnostic ignored "-Wnull-dereference"
#pragma clang diagnostic ignored "-Winvalid-noreturn" #pragma clang diagnostic ignored "-Winvalid-noreturn"
#define SCRIPTING_EXPORT(name)
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define DLLEXPORT __attribute__ ((__visibility__ ("default"))) #define DLLEXPORT __attribute__ ((__visibility__ ("default")))
@@ -86,6 +88,8 @@
#pragma warning(disable: 4251) #pragma warning(disable: 4251)
#define SCRIPTING_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
#else #else
#pragma error "Unknown compiler." #pragma error "Unknown compiler."

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,7 +15,10 @@ public class Scripting : EngineModule
if (EngineConfiguration.WithCSharp(options)) if (EngineConfiguration.WithCSharp(options))
{ {
options.PublicDependencies.Add("mono"); if (EngineConfiguration.UseDotNet)
options.PublicDependencies.Add("nethost");
else
options.PublicDependencies.Add("mono");
} }
options.PrivateDependencies.Add("Utilities"); options.PrivateDependencies.Add("Utilities");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -37,7 +37,11 @@ namespace FlaxEngine.Json
{ {
// Skip serialization as reference id for the root object serialization (eg. Script) // Skip serialization as reference id for the root object serialization (eg. Script)
var cache = JsonSerializer.Current.Value; var cache = JsonSerializer.Current.Value;
#if !USE_NETCORE
if (cache != null && cache.IsDuringSerialization && cache.SerializerWriter.SerializeStackSize == 0) if (cache != null && cache.IsDuringSerialization && cache.SerializerWriter.SerializeStackSize == 0)
#else
if (cache != null && cache.IsDuringSerialization)
#endif
{ {
return false; return false;
} }
@@ -142,6 +146,7 @@ namespace FlaxEngine.Json
writer.WriteEndObject(); writer.WriteEndObject();
} }
#if !USE_NETCORE
/// <inheritdoc /> /// <inheritdoc />
public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer) public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer)
{ {
@@ -170,6 +175,7 @@ namespace FlaxEngine.Json
} }
writer.WriteEndObject(); writer.WriteEndObject();
} }
#endif
/// <inheritdoc /> /// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
@@ -232,8 +238,10 @@ namespace FlaxEngine.Json
/// <inheritdoc /> /// <inheritdoc />
public override bool CanWrite => true; public override bool CanWrite => true;
#if !USE_NETCORE
/// <inheritdoc /> /// <inheritdoc />
public override bool CanWriteDiff => true; public override bool CanWriteDiff => true;
#endif
} }
/// <summary> /// <summary>

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -11,7 +12,7 @@ using FlaxEngine.Json.JsonCustomSerializers;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Linq;
namespace FlaxEngine.Json namespace FlaxEngine.Json
{ {
@@ -23,7 +24,11 @@ namespace FlaxEngine.Json
public StringBuilder StringBuilder; public StringBuilder StringBuilder;
public StringWriter StringWriter; public StringWriter StringWriter;
public JsonTextWriter JsonWriter; public JsonTextWriter JsonWriter;
#if !USE_NETCORE
public JsonSerializerInternalWriter SerializerWriter; public JsonSerializerInternalWriter SerializerWriter;
#else
public /*JsonSerializerInternalWriter*/ object SerializerWriter;
#endif
public UnmanagedMemoryStream MemoryStream; public UnmanagedMemoryStream MemoryStream;
public StreamReader Reader; public StreamReader Reader;
public bool IsDuringSerialization; public bool IsDuringSerialization;
@@ -32,9 +37,18 @@ namespace FlaxEngine.Json
{ {
JsonSerializer = Newtonsoft.Json.JsonSerializer.CreateDefault(settings); JsonSerializer = Newtonsoft.Json.JsonSerializer.CreateDefault(settings);
JsonSerializer.Formatting = Formatting.Indented; JsonSerializer.Formatting = Formatting.Indented;
#if USE_NETCORE
Type jsonSerializerInternalWriterType =
typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
"Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
System.Reflection.ConstructorInfo ctor = jsonSerializerInternalWriterType.GetConstructors
(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)[0];
SerializerWriter = ctor.Invoke(new object[] { JsonSerializer });
#else
SerializerWriter = new JsonSerializerInternalWriter(JsonSerializer);
#endif
StringBuilder = new StringBuilder(256); StringBuilder = new StringBuilder(256);
StringWriter = new StringWriter(StringBuilder, CultureInfo.InvariantCulture); StringWriter = new StringWriter(StringBuilder, CultureInfo.InvariantCulture);
SerializerWriter = new JsonSerializerInternalWriter(JsonSerializer);
MemoryStream = new UnmanagedMemoryStream((byte*)0, 0); MemoryStream = new UnmanagedMemoryStream((byte*)0, 0);
Reader = new StreamReader(MemoryStream, Encoding.UTF8, false); Reader = new StreamReader(MemoryStream, Encoding.UTF8, false);
JsonWriter = new JsonTextWriter(StringWriter) JsonWriter = new JsonTextWriter(StringWriter)
@@ -107,7 +121,72 @@ namespace FlaxEngine.Json
return sceneObjA.PrefabObjectID == sceneObjB.PrefabObjectID; return sceneObjA.PrefabObjectID == sceneObjB.PrefabObjectID;
}*/ }*/
return Newtonsoft.Json.Utilities.MiscellaneousUtils.DefaultValueEquals(objA, objB); // Based on Newtonsoft.Json MiscellaneousUtils-class ValueEquals-method
bool DefaultValueEquals(object objA_, object objB_)
{
bool IsInteger(object value)
{
var type = value.GetType();
return type == typeof(SByte) ||
type == typeof(Byte) ||
type == typeof(Int16) ||
type == typeof(UInt16) ||
type == typeof(Int32) ||
type == typeof(UInt32) ||
type == typeof(Int64) ||
type == typeof(SByte) ||
type == typeof(UInt64);
}
if (objA_ == objB_)
{
return true;
}
if (objA_ == null || objB_ == null)
{
return false;
}
// comparing an Int32 and Int64 both of the same value returns false
// make types the same then compare
if (objA_.GetType() != objB_.GetType())
{
if (IsInteger(objA_) && IsInteger(objB_))
{
return Convert.ToDecimal(objA_, CultureInfo.CurrentCulture).Equals(Convert.ToDecimal(objB_, CultureInfo.CurrentCulture));
}
else if ((objA_ is double || objA_ is float || objA_ is decimal) && (objB_ is double || objB_ is float || objB_ is decimal))
{
return Mathd.NearEqual(Convert.ToDouble(objA_, CultureInfo.CurrentCulture), Convert.ToDouble(objB_, CultureInfo.CurrentCulture));
}
else
{
return false;
}
}
// Diff on collections
if (objA_ is System.Collections.IList aList && objB_ is System.Collections.IList bList)
{
if (aList.Count != bList.Count)
return false;
}
if (objA_ is System.Collections.IEnumerable aEnumerable && objB_ is System.Collections.IEnumerable bEnumerable)
{
var aEnumerator = aEnumerable.GetEnumerator();
var bEnumerator = bEnumerable.GetEnumerator();
while (aEnumerator.MoveNext())
{
if (!bEnumerator.MoveNext() || !ValueEquals(aEnumerator.Current, bEnumerator.Current))
return false;
}
return !bEnumerator.MoveNext();
}
return objA_.Equals(objB_);
}
return /*Newtonsoft.Json.Utilities.MiscellaneousUtils.*/DefaultValueEquals(objA, objB);
} }
/// <summary> /// <summary>
@@ -124,7 +203,17 @@ namespace FlaxEngine.Json
cache.StringBuilder.Clear(); cache.StringBuilder.Clear();
cache.IsDuringSerialization = true; cache.IsDuringSerialization = true;
#if !USE_NETCORE
cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type); cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type);
#else
Type jsonSerializerInternalWriterType =
typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
"Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
System.Reflection.MethodInfo Serialize = jsonSerializerInternalWriterType.GetMethod("Serialize",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
Serialize.Invoke(cache.SerializerWriter, new object[] { cache.JsonWriter, obj, type });
#endif
return cache.StringBuilder.ToString(); return cache.StringBuilder.ToString();
} }
@@ -143,7 +232,17 @@ namespace FlaxEngine.Json
cache.StringBuilder.Clear(); cache.StringBuilder.Clear();
cache.IsDuringSerialization = true; cache.IsDuringSerialization = true;
#if !USE_NETCORE
cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type); cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type);
#else
Type jsonSerializerInternalWriterType =
typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
"Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
System.Reflection.MethodInfo Serialize = jsonSerializerInternalWriterType.GetMethod("Serialize",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
Serialize.Invoke(cache.SerializerWriter, new object[] { cache.JsonWriter, obj, type });
#endif
return cache.StringBuilder.ToString(); return cache.StringBuilder.ToString();
} }
@@ -157,15 +256,25 @@ namespace FlaxEngine.Json
/// <returns>The output json string.</returns> /// <returns>The output json string.</returns>
public static string SerializeDiff(object obj, object other, bool isManagedOnly = false) public static string SerializeDiff(object obj, object other, bool isManagedOnly = false)
{ {
Type type = obj.GetType();
var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value; var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value;
Current.Value = cache; Current.Value = cache;
cache.StringBuilder.Clear(); cache.StringBuilder.Clear();
cache.IsDuringSerialization = true; cache.IsDuringSerialization = true;
cache.SerializerWriter.SerializeDiff(cache.JsonWriter, obj, type, other);
return cache.StringBuilder.ToString(); JObject jObj = JObject.FromObject(obj, cache.JsonSerializer);
JObject jOther = JObject.FromObject(other, cache.JsonSerializer);
JObject diff = new JObject();
foreach (KeyValuePair<string, JToken> prop in jObj)
{
JProperty otherProp = jOther.Property(prop.Key);
if (JToken.DeepEquals(prop.Value, otherProp.Value))
continue;
diff.Add(prop.Key, prop.Value);
}
return diff.ToString();
} }
/// <summary> /// <summary>

View File

@@ -6,7 +6,9 @@ using System.IO;
using System.Text; using System.Text;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
namespace FlaxEngine namespace FlaxEngine
{ {
@@ -340,10 +342,22 @@ namespace FlaxEngine
jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling; jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling;
jsonWriter.Culture = jsonSerializer.Culture; jsonWriter.Culture = jsonSerializer.Culture;
jsonWriter.DateFormatString = jsonSerializer.DateFormatString; jsonWriter.DateFormatString = jsonSerializer.DateFormatString;
#if !USE_NETCORE
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer); JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer);
serializerWriter.Serialize(jsonWriter, _control, type); serializerWriter.Serialize(jsonWriter, _control, type);
#else
Type jsonSerializerInternalWriterType =
typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
"Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
System.Reflection.ConstructorInfo ctor = jsonSerializerInternalWriterType.GetConstructors
(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)[0];
object serializerWriter = ctor.Invoke(new object[] { jsonSerializer });
System.Reflection.MethodInfo Serialize = jsonSerializerInternalWriterType.GetMethod("Serialize",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
Serialize.Invoke(serializerWriter, new object[] { jsonWriter, _control, type });
#endif
} }
controlType = type.FullName; controlType = type.FullName;
@@ -380,10 +394,25 @@ namespace FlaxEngine
jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling; jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling;
jsonWriter.Culture = jsonSerializer.Culture; jsonWriter.Culture = jsonSerializer.Culture;
jsonWriter.DateFormatString = jsonSerializer.DateFormatString; jsonWriter.DateFormatString = jsonSerializer.DateFormatString;
#if !USE_NETCORE
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer); JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer);
serializerWriter.SerializeDiff(jsonWriter, _control, type, other._control); serializerWriter.SerializeDiff(jsonWriter, _control, type, other._control);
#else
JObject jObj = JObject.FromObject(_control, jsonSerializer);
JObject jOther = JObject.FromObject(other._control, jsonSerializer);
JObject diff = new JObject();
foreach (KeyValuePair<string, JToken> prop in jObj)
{
JProperty otherProp = jOther.Property(prop.Key);
if (JToken.DeepEquals(prop.Value, otherProp.Value))
continue;
diff.Add(prop.Key, prop.Value);
}
diff.WriteTo(jsonWriter);
#endif
} }
controlType = string.Empty; controlType = string.Empty;

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
{
"runtimeOptions": {
"tfm": "net7.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "7.0.0-rc.2.22472.3"
}
}
}

23
Source/ThirdParty/nethost/LICENSE.TXT vendored Normal file
View File

@@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) .NET Foundation and Contributors
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,112 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using System.IO;
using System;
using Flax.Build;
using Flax.Build.NativeCpp;
using Flax.Build.Platforms;
using Microsoft.Win32;
using System.Linq;
/// <summary>
/// Module for nethost (.NET runtime host library)
/// </summary>
public class nethost : ThirdPartyModule
{
/// <inheritdoc />
public override void Init()
{
base.Init();
LicenseType = LicenseTypes.MIT;
LicenseFilePath = "LICENSE.TXT";
// Merge third-party modules into engine binary
BinaryModuleName = "FlaxEngine";
}
/// <inheritdoc />
private static Version ParseVersion(string version)
{
// Give precedence to final releases over release candidate / beta releases
int rev = 9999;
if (version.Contains("-")) // e.g. 7.0.0-rc.2.22472.3
{
version = version.Substring(0, version.IndexOf("-"));
rev = 0;
}
Version ver = new Version(version);
return new Version(ver.Major, ver.Minor, ver.Build, rev);
}
/// <inheritdoc />
public override void Setup(BuildOptions options)
{
base.Setup(options);
options.SourceFiles.Clear();
string arch = "x64"; //options.Architecture == TargetArchitecture.x64 ? "x64" : "x86";
string dotnetVersion;
string appHostRuntimePath;
// NOTE: nethost is bundled with SDK, not runtime. Should C# scripting have a hard requirement for SDK to be installed?
if (options.Platform.Target == TargetPlatform.Windows)
{
string os = $"win-{arch}";
using RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
using RegistryKey hostKey = baseKey.OpenSubKey(@$"SOFTWARE\dotnet\Setup\InstalledVersions\{arch}\sharedhost");
string dotnetPath = (string)hostKey.GetValue("Path");
using RegistryKey runtimeKey = baseKey.OpenSubKey(@$"SOFTWARE\WOW6432Node\dotnet\Setup\InstalledVersions\{arch}\sharedfx\Microsoft.NETCore.App");
string[] versions = runtimeKey.GetValueNames();
dotnetVersion = versions.OrderByDescending(x => ParseVersion(x)).FirstOrDefault();
if (string.IsNullOrEmpty(dotnetPath))
dotnetPath = Environment.GetEnvironmentVariable("DOTNET_ROOT");
if (string.IsNullOrEmpty(dotnetPath) || string.IsNullOrEmpty(dotnetVersion))
throw new Exception("Failed to find dotnet installation");
int majorVersion = int.Parse(dotnetVersion.Substring(0, dotnetVersion.IndexOf(".")));
if (majorVersion < 7)
throw new Exception($"Unsupported dotnet version found, minimum version required is .NET 7 (found {dotnetVersion})");
appHostRuntimePath = String.Format("{0}packs\\Microsoft.NETCore.App.Host.{1}\\{2}\\runtimes\\{1}\\native", dotnetPath, os, dotnetVersion);
options.OutputFiles.Add(Path.Combine(appHostRuntimePath, "nethost.lib"));
options.DependencyFiles.Add(Path.Combine(appHostRuntimePath, "nethost.dll"));
options.PublicIncludePaths.Add(appHostRuntimePath);
}
else if (options.Platform.Target == TargetPlatform.Linux)
{
// TODO: Support /etc/dotnet/install_location
string dotnetPath = "/usr/share/dotnet/";
string os = $"linux-{arch}";
string[] versions = Directory.GetDirectories($"{dotnetPath}host/fxr/").Select(x => Path.GetFileName(x)).ToArray();
dotnetVersion = versions.OrderByDescending(x => ParseVersion(x)).FirstOrDefault();
int majorVersion = int.Parse(dotnetVersion.Substring(0, dotnetVersion.IndexOf(".")));
if (majorVersion < 7)
throw new Exception($"Unsupported dotnet version found, minimum version required is .NET 7 (found {dotnetVersion})");
appHostRuntimePath = String.Format("{0}packs/Microsoft.NETCore.App.Host.{1}/{2}/runtimes/{1}/native", dotnetPath, os, dotnetVersion);
options.OutputFiles.Add(Path.Combine(appHostRuntimePath, "libnethost.a"));
options.DependencyFiles.Add(Path.Combine(appHostRuntimePath, "libnethost.so"));
options.PublicIncludePaths.Add(appHostRuntimePath);
}
else
throw new InvalidPlatformException(options.Platform.Target);
options.PublicIncludePaths.Add(appHostRuntimePath);
options.ScriptingAPI.Defines.Add("USE_NETCORE");
options.DependencyFiles.Add(Path.Combine(FolderPath, "FlaxEngine.CSharp.runtimeconfig.json"));
}
}

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More