Merge branch 'GoaLitiuM-dotnet7' into dotnet7
This commit is contained in:
1
.github/workflows/build_android.yml
vendored
1
.github/workflows/build_android.yml
vendored
@@ -5,6 +5,7 @@ jobs:
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
if: ${{ false }}
|
||||
name: Game (Android, Release ARM64)
|
||||
runs-on: "windows-2019"
|
||||
steps:
|
||||
|
||||
2
.github/workflows/build_linux.yml
vendored
2
.github/workflows/build_linux.yml
vendored
@@ -5,6 +5,7 @@ jobs:
|
||||
|
||||
# Editor
|
||||
editor-linux:
|
||||
if: ${{ false }}
|
||||
name: Editor (Linux, Development x64)
|
||||
runs-on: "ubuntu-20.04"
|
||||
steps:
|
||||
@@ -28,6 +29,7 @@ jobs:
|
||||
|
||||
# Game
|
||||
game-linux:
|
||||
if: ${{ false }}
|
||||
name: Game (Linux, Release x64)
|
||||
runs-on: "ubuntu-20.04"
|
||||
steps:
|
||||
|
||||
2
.github/workflows/build_mac.yml
vendored
2
.github/workflows/build_mac.yml
vendored
@@ -5,6 +5,7 @@ jobs:
|
||||
|
||||
# Editor
|
||||
editor-mac:
|
||||
if: ${{ false }}
|
||||
name: Editor (Mac, Development x64)
|
||||
runs-on: "macos-latest"
|
||||
steps:
|
||||
@@ -22,6 +23,7 @@ jobs:
|
||||
|
||||
# Game
|
||||
game-mac:
|
||||
if: ${{ false }}
|
||||
name: Game (Mac, Release x64)
|
||||
runs-on: "macos-latest"
|
||||
steps:
|
||||
|
||||
15
.github/workflows/build_windows.yml
vendored
15
.github/workflows/build_windows.yml
vendored
@@ -6,12 +6,19 @@ jobs:
|
||||
# Editor
|
||||
editor-windows:
|
||||
name: Editor (Windows, Development x64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Check .NET versions
|
||||
run: |
|
||||
dotnet --list-sdks
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
@@ -23,12 +30,16 @@ jobs:
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (Windows, Release x64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
|
||||
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
@@ -5,6 +5,7 @@ jobs:
|
||||
|
||||
# Tests
|
||||
tests-linux:
|
||||
if: ${{ false }}
|
||||
name: Tests (Linux)
|
||||
runs-on: "ubuntu-20.04"
|
||||
steps:
|
||||
|
||||
@@ -10,8 +10,9 @@ if [ $testfilesize -le 1000 ]; then
|
||||
fi
|
||||
|
||||
# Compile the build tool.
|
||||
xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Restore,Clean /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=linux-x64
|
||||
dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Build /property:SelfContained=False /property:RuntimeIdentifiers=linux-x64
|
||||
|
||||
# Run the build tool using the provided arguments.
|
||||
#mono --debug --debugger-agent=transport=dt_socket,server=y,address=127.0.0.1:55555 Binaries/Tools/Flax.Build.exe "$@"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -28,9 +28,9 @@ fc /b Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Fla
|
||||
if not errorlevel 1 goto SkipClean
|
||||
|
||||
copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Clean
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Restore,Clean /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=win-x64
|
||||
:SkipClean
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Build /property:SelfContained=False /property:RuntimeIdentifiers=win-x64
|
||||
if errorlevel 1 goto Error_CompilationFailed
|
||||
|
||||
Binaries\Tools\Flax.Build.exe %*
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"EditorTarget": "FlaxEditor",
|
||||
"Configuration": {
|
||||
"UseCSharp": true,
|
||||
"UseLargeWorlds": false
|
||||
"UseLargeWorlds": false,
|
||||
"UseDotNet": true
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
@@ -93,6 +94,7 @@ namespace FlaxEditor.Content.Import
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public AudioFormat Format;
|
||||
public byte DisableStreaming;
|
||||
public byte Is3D;
|
||||
@@ -144,7 +146,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// Audio asset import entry.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class AudioImportEntry : AssetImportEntry
|
||||
public partial class AudioImportEntry : AssetImportEntry
|
||||
{
|
||||
private AudioImportSettings _settings = new AudioImportSettings();
|
||||
|
||||
@@ -182,8 +184,9 @@ namespace FlaxEditor.Content.Import
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.AudioImportEntry::Internal_GetAudioImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
@@ -355,6 +357,7 @@ namespace FlaxEditor.Content.Import
|
||||
private bool ShowAnimation => Type == ModelType.Animation;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(InternalOptionsMarshaler))]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
public ModelType Type;
|
||||
@@ -410,6 +413,162 @@ namespace FlaxEditor.Content.Import
|
||||
public int ObjectIndex;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(InternalOptions), MarshalMode.Default, typeof(InternalOptionsMarshaler))]
|
||||
internal static class InternalOptionsMarshaler
|
||||
{
|
||||
[Unmanaged]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptionsNative
|
||||
{
|
||||
public int Type;
|
||||
|
||||
// Geometry
|
||||
public byte CalculateNormals;
|
||||
public float SmoothingNormalsAngle;
|
||||
public byte FlipNormals;
|
||||
public float SmoothingTangentsAngle;
|
||||
public byte CalculateTangents;
|
||||
public byte OptimizeMeshes;
|
||||
public byte MergeMeshes;
|
||||
public byte ImportLODs;
|
||||
public byte ImportVertexColors;
|
||||
public byte ImportBlendShapes;
|
||||
public int LightmapUVsSource;
|
||||
//[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public IntPtr CollisionMeshesPrefix;
|
||||
|
||||
// Transform
|
||||
public float Scale;
|
||||
public Quaternion Rotation;
|
||||
public Float3 Translation;
|
||||
public byte CenterGeometry;
|
||||
|
||||
// Animation
|
||||
public int Duration;
|
||||
public float FramesRangeStart;
|
||||
public float FramesRangeEnd;
|
||||
public float DefaultFrameRate;
|
||||
public float SamplingRate;
|
||||
public byte SkipEmptyCurves;
|
||||
public byte OptimizeKeyframes;
|
||||
public byte EnableRootMotion;
|
||||
//[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public IntPtr RootNodeName;
|
||||
|
||||
// Level Of Detail
|
||||
public byte GenerateLODs;
|
||||
public int BaseLOD;
|
||||
public int LODCount;
|
||||
public float TriangleReduction;
|
||||
|
||||
// Misc
|
||||
public byte ImportMaterials;
|
||||
public byte ImportTextures;
|
||||
public byte RestoreMaterialsOnReimport;
|
||||
|
||||
// SDF
|
||||
public byte GenerateSDF;
|
||||
public float SDFResolution;
|
||||
|
||||
// Splitting
|
||||
public byte SplitObjects;
|
||||
public int ObjectIndex;
|
||||
}
|
||||
|
||||
internal static InternalOptions ConvertToManaged(InternalOptionsNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static InternalOptionsNative ConvertToUnmanaged(InternalOptions managed) => ToNative(managed);
|
||||
|
||||
internal static InternalOptions ToManaged(InternalOptionsNative managed)
|
||||
{
|
||||
return new InternalOptions()
|
||||
{
|
||||
Type = (ModelType)managed.Type,
|
||||
CalculateNormals = managed.CalculateNormals,
|
||||
SmoothingNormalsAngle = managed.SmoothingNormalsAngle,
|
||||
FlipNormals = managed.FlipNormals,
|
||||
SmoothingTangentsAngle = managed.SmoothingTangentsAngle,
|
||||
CalculateTangents = managed.CalculateTangents,
|
||||
OptimizeMeshes = managed.OptimizeMeshes,
|
||||
MergeMeshes = managed.MergeMeshes,
|
||||
ImportLODs = managed.ImportLODs,
|
||||
ImportVertexColors = managed.ImportVertexColors,
|
||||
ImportBlendShapes = managed.ImportBlendShapes,
|
||||
LightmapUVsSource = (ModelLightmapUVsSource)managed.LightmapUVsSource,
|
||||
CollisionMeshesPrefix = ManagedString.ToManaged(managed.CollisionMeshesPrefix),
|
||||
Scale = managed.Scale,
|
||||
Rotation = managed.Rotation,
|
||||
Translation = managed.Translation,
|
||||
CenterGeometry = managed.CenterGeometry,
|
||||
Duration = (AnimationDuration)managed.Duration,
|
||||
FramesRangeStart = managed.FramesRangeStart,
|
||||
FramesRangeEnd = managed.FramesRangeEnd,
|
||||
DefaultFrameRate = managed.DefaultFrameRate,
|
||||
SamplingRate = managed.SamplingRate,
|
||||
SkipEmptyCurves = managed.SkipEmptyCurves,
|
||||
OptimizeKeyframes = managed.OptimizeKeyframes,
|
||||
EnableRootMotion = managed.EnableRootMotion,
|
||||
RootNodeName = ManagedString.ToManaged(managed.RootNodeName),
|
||||
GenerateLODs = managed.GenerateLODs,
|
||||
BaseLOD = managed.BaseLOD,
|
||||
LODCount = managed.LODCount,
|
||||
TriangleReduction = managed.TriangleReduction,
|
||||
ImportMaterials = managed.ImportMaterials,
|
||||
ImportTextures = managed.ImportTextures,
|
||||
RestoreMaterialsOnReimport = managed.RestoreMaterialsOnReimport,
|
||||
GenerateSDF = managed.GenerateSDF,
|
||||
SDFResolution = managed.SDFResolution,
|
||||
SplitObjects = managed.SplitObjects,
|
||||
ObjectIndex = managed.ObjectIndex,
|
||||
};
|
||||
}
|
||||
internal static InternalOptionsNative ToNative(InternalOptions managed)
|
||||
{
|
||||
return new InternalOptionsNative()
|
||||
{
|
||||
Type = (int)managed.Type,
|
||||
CalculateNormals = managed.CalculateNormals,
|
||||
SmoothingNormalsAngle = managed.SmoothingNormalsAngle,
|
||||
FlipNormals = managed.FlipNormals,
|
||||
SmoothingTangentsAngle = managed.SmoothingTangentsAngle,
|
||||
CalculateTangents = managed.CalculateTangents,
|
||||
OptimizeMeshes = managed.OptimizeMeshes,
|
||||
MergeMeshes = managed.MergeMeshes,
|
||||
ImportLODs = managed.ImportLODs,
|
||||
ImportVertexColors = managed.ImportVertexColors,
|
||||
ImportBlendShapes = managed.ImportBlendShapes,
|
||||
LightmapUVsSource = (int)managed.LightmapUVsSource,
|
||||
CollisionMeshesPrefix = ManagedString.ToNative(managed.CollisionMeshesPrefix),
|
||||
Scale = managed.Scale,
|
||||
Rotation = managed.Rotation,
|
||||
Translation = managed.Translation,
|
||||
CenterGeometry = managed.CenterGeometry,
|
||||
Duration = (int)managed.Duration,
|
||||
FramesRangeStart = managed.FramesRangeStart,
|
||||
FramesRangeEnd = managed.FramesRangeEnd,
|
||||
DefaultFrameRate = managed.DefaultFrameRate,
|
||||
SamplingRate = managed.SamplingRate,
|
||||
SkipEmptyCurves = managed.SkipEmptyCurves,
|
||||
OptimizeKeyframes = managed.OptimizeKeyframes,
|
||||
EnableRootMotion = managed.EnableRootMotion,
|
||||
RootNodeName = ManagedString.ToNative(managed.RootNodeName),
|
||||
GenerateLODs = managed.GenerateLODs,
|
||||
BaseLOD = managed.BaseLOD,
|
||||
LODCount = managed.LODCount,
|
||||
TriangleReduction = managed.TriangleReduction,
|
||||
ImportMaterials = managed.ImportMaterials,
|
||||
ImportTextures = managed.ImportTextures,
|
||||
RestoreMaterialsOnReimport = managed.RestoreMaterialsOnReimport,
|
||||
GenerateSDF = managed.GenerateSDF,
|
||||
SDFResolution = managed.SDFResolution,
|
||||
SplitObjects = managed.SplitObjects,
|
||||
ObjectIndex = managed.ObjectIndex,
|
||||
};
|
||||
}
|
||||
internal static void Free(InternalOptionsNative unmanaged)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal void ToInternal(out InternalOptions options)
|
||||
{
|
||||
options = new InternalOptions
|
||||
@@ -511,7 +670,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// Model asset import entry.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class ModelImportEntry : AssetImportEntry
|
||||
public partial class ModelImportEntry : AssetImportEntry
|
||||
{
|
||||
private ModelImportSettings _settings = new ModelImportSettings();
|
||||
|
||||
@@ -548,8 +707,8 @@ namespace FlaxEditor.Content.Import
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.ModelImportEntry::Internal_GetModelImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEngine;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
@@ -297,6 +299,7 @@ namespace FlaxEditor.Content.Import
|
||||
public List<SpriteInfo> Sprites = new List<SpriteInfo>();
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(InternalOptionsMarshaler))]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
public TextureFormatType Type;
|
||||
@@ -318,6 +321,85 @@ namespace FlaxEditor.Content.Import
|
||||
public string[] SpriteNames;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(InternalOptions), MarshalMode.Default, typeof(InternalOptionsMarshaler))]
|
||||
internal static class InternalOptionsMarshaler
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptionsNative
|
||||
{
|
||||
public byte Type;
|
||||
public byte IsAtlas;
|
||||
public byte NeverStream;
|
||||
public byte Compress;
|
||||
public byte IndependentChannels;
|
||||
public byte sRGB;
|
||||
public byte GenerateMipMaps;
|
||||
public byte FlipY;
|
||||
public byte Resize;
|
||||
public byte PreserveAlphaCoverage;
|
||||
public float PreserveAlphaCoverageReference;
|
||||
public float Scale;
|
||||
public int MaxSize;
|
||||
public int TextureGroup;
|
||||
public Int2 Size;
|
||||
public IntPtr SpriteAreas;
|
||||
public IntPtr SpriteNames;
|
||||
}
|
||||
|
||||
internal static InternalOptions ConvertToManaged(InternalOptionsNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static InternalOptionsNative ConvertToUnmanaged(InternalOptions managed) => ToNative(managed);
|
||||
|
||||
internal static InternalOptions ToManaged(InternalOptionsNative managed)
|
||||
{
|
||||
return new InternalOptions()
|
||||
{
|
||||
Type = (TextureFormatType)managed.Type,
|
||||
IsAtlas = managed.IsAtlas,
|
||||
NeverStream = managed.NeverStream,
|
||||
Compress = managed.Compress,
|
||||
IndependentChannels = managed.IndependentChannels,
|
||||
sRGB = managed.sRGB,
|
||||
GenerateMipMaps = managed.GenerateMipMaps,
|
||||
FlipY = managed.FlipY,
|
||||
Resize = managed.Resize,
|
||||
PreserveAlphaCoverage = managed.PreserveAlphaCoverage,
|
||||
PreserveAlphaCoverageReference = managed.PreserveAlphaCoverageReference,
|
||||
Scale = managed.Scale,
|
||||
MaxSize = managed.MaxSize,
|
||||
TextureGroup = managed.TextureGroup,
|
||||
Size = managed.Size,
|
||||
SpriteAreas = managed.SpriteAreas != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<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)
|
||||
{
|
||||
options = new InternalOptions
|
||||
@@ -406,7 +488,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// Texture asset import entry.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class TextureImportEntry : AssetImportEntry
|
||||
public partial class TextureImportEntry : AssetImportEntry
|
||||
{
|
||||
private TextureImportSettings _settings = new TextureImportSettings();
|
||||
|
||||
@@ -509,8 +591,9 @@ namespace FlaxEditor.Content.Import
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Import.TextureImportEntry::Internal_GetTextureImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
internal static class CustomEditorsUtil
|
||||
internal static partial class CustomEditorsUtil
|
||||
{
|
||||
internal static readonly Dictionary<Type, string> InBuildTypeNames = new Dictionary<Type, string>()
|
||||
{
|
||||
@@ -129,7 +131,8 @@ namespace FlaxEditor.CustomEditors
|
||||
return new GenericEditor();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Type Internal_GetCustomEditor(Type targetType);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.CustomEditors.CustomEditorsUtil::Internal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(SystemTypeMarshaller))]
|
||||
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.Content.Import;
|
||||
using FlaxEditor.Content.Settings;
|
||||
@@ -20,6 +21,8 @@ using FlaxEngine.Assertions;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace FlaxEditor
|
||||
{
|
||||
/// <summary>
|
||||
@@ -59,17 +62,20 @@ namespace FlaxEditor
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this Editor is running a dev instance of the engine.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool IsDevInstance();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::IsDevInstance", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool IsDevInstance();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool IsOfficialBuild();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::IsOfficialBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool IsOfficialBuild();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_IsPlayMode();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_IsPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_IsPlayMode();
|
||||
|
||||
/// <summary>
|
||||
/// True if the editor is running now in a play mode. Assigned by the managed editor instance.
|
||||
@@ -1206,6 +1212,7 @@ namespace FlaxEditor
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(VisualScriptLocalMarshaller))]
|
||||
internal struct VisualScriptLocal
|
||||
{
|
||||
public string Value;
|
||||
@@ -1214,7 +1221,48 @@ namespace FlaxEditor
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(VisualScriptLocal), MarshalMode.Default, typeof(VisualScriptLocalMarshaller))]
|
||||
internal static class VisualScriptLocalMarshaller
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VisualScriptLocalNative
|
||||
{
|
||||
public IntPtr Value;
|
||||
public IntPtr ValueTypeName;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
internal static VisualScriptLocal ConvertToManaged(VisualScriptLocalNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static VisualScriptLocalNative ConvertToUnmanaged(VisualScriptLocal managed) => ToNative(managed);
|
||||
|
||||
internal static VisualScriptLocal ToManaged(VisualScriptLocalNative managed)
|
||||
{
|
||||
return new VisualScriptLocal()
|
||||
{
|
||||
Value = ManagedString.ToManaged(managed.Value),
|
||||
ValueTypeName = ManagedString.ToManaged(managed.ValueTypeName),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
internal static VisualScriptLocalNative ToNative(VisualScriptLocal managed)
|
||||
{
|
||||
return new VisualScriptLocalNative()
|
||||
{
|
||||
Value = ManagedString.ToNative(managed.Value),
|
||||
ValueTypeName = ManagedString.ToNative(managed.ValueTypeName),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
internal static void Free(VisualScriptLocalNative unmanaged)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(VisualScriptStackFrameMarshaller))]
|
||||
internal struct VisualScriptStackFrame
|
||||
{
|
||||
public VisualScript Script;
|
||||
@@ -1222,6 +1270,43 @@ namespace FlaxEditor
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(VisualScriptStackFrame), MarshalMode.Default, typeof(VisualScriptStackFrameMarshaller))]
|
||||
internal static class VisualScriptStackFrameMarshaller
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VisualScriptStackFrameNative
|
||||
{
|
||||
public IntPtr Script;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
internal static VisualScriptStackFrame ConvertToManaged(VisualScriptStackFrameNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static VisualScriptStackFrameNative ConvertToUnmanaged(VisualScriptStackFrame managed) => ToNative(managed);
|
||||
|
||||
internal static VisualScriptStackFrame ToManaged(VisualScriptStackFrameNative managed)
|
||||
{
|
||||
return new VisualScriptStackFrame()
|
||||
{
|
||||
Script = VisualScriptMarshaller.ConvertToManaged(managed.Script),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
internal static VisualScriptStackFrameNative ToNative(VisualScriptStackFrame managed)
|
||||
{
|
||||
return new VisualScriptStackFrameNative()
|
||||
{
|
||||
Script = VisualScriptMarshaller.ConvertToUnmanaged(managed.Script),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
internal static void Free(VisualScriptStackFrameNative unmanaged)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal void BuildCommand(string arg)
|
||||
{
|
||||
if (TryBuildCommand(arg))
|
||||
@@ -1419,116 +1504,133 @@ namespace FlaxEditor
|
||||
Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern int Internal_ReadOutputLogs(string[] outMessages, byte[] outLogTypes, long[] outLogTimes);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref byte[] outLogTypes, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref long[] outLogTimes, int outCapacity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_SetPlayMode(bool value);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_GetProjectPath();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial string Internal_GetProjectPath();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_Import(string inputPath, string outputPath, IntPtr arg);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_Import", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_Import(string inputPath, string outputPath, IntPtr arg);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportTexture", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportModel", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_ImportAudio", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetAudioClipMetadata", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CopyCache", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_BakeLightmaps(bool cancel);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_BakeLightmaps", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetCollisionWires(IntPtr collisionData, out Float3[] triangles, out int[] indices);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)] out int[] indices);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_SetOptions(ref InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_SetOptions(ref InternalOptions options);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_DrawNavMesh();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_DrawNavMesh", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_DrawNavMesh();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_CloseSplashScreen();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_CloseSplashScreen();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CreateAsset(NewAssetType type, string outputPath);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CreateAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CreateAsset(NewAssetType type, string outputPath);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_CanImport(string extension);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial string Internal_CanImport(string extension);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CanExport(string path);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CanExport(string path);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_Export(string inputPath, string outputFolder);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_Export(string inputPath, string outputFolder);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetIsEveryAssemblyLoaded();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetIsEveryAssemblyLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetIsEveryAssemblyLoaded();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern int Internal_GetLastProjectOpenedEngineBuild();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetLastProjectOpenedEngineBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial int Internal_GetLastProjectOpenedEngineBuild();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetIsCSGActive();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetIsCSGActive", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetIsCSGActive();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern VisualScriptLocal[] Internal_GetVisualScriptLocals();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)]
|
||||
internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), ConstantElementCount = 1)]
|
||||
internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_EvaluateVisualScriptLocal", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_LoadAsset(ref Guid id);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_LoadAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_LoadAsset(ref Guid id);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_CanSetToRoot", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_SetAnimationTime(IntPtr animatedModel, float time);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Editor::Internal_SetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using FlaxEditor.GUI.Timeline.Tracks;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline
|
||||
{
|
||||
|
||||
@@ -323,20 +323,25 @@ namespace CustomEditorsUtilInternal
|
||||
{
|
||||
MonoReflectionType* GetCustomEditor(MonoReflectionType* targetType)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.CustomEditors.CustomEditorsUtil::Internal_GetCustomEditor")
|
||||
return CustomEditorsUtil::GetCustomEditor(targetType);
|
||||
}
|
||||
}
|
||||
|
||||
namespace LayersAndTagsSettingsInternal1
|
||||
{
|
||||
MonoArray* GetCurrentTags()
|
||||
MonoArray* GetCurrentTags(int* tagsCount)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentTags")
|
||||
*tagsCount = Level::Tags.Count();
|
||||
return MUtils::ToArray(Level::Tags);
|
||||
}
|
||||
|
||||
MonoArray* GetCurrentLayers()
|
||||
MonoArray* GetCurrentLayers(int* layersCount)
|
||||
{
|
||||
return MUtils::ToArray(Span<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()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Content.Settings.GameSettings::Apply")
|
||||
LOG(Info, "Apply game settings");
|
||||
GameSettings::Load();
|
||||
}
|
||||
@@ -380,6 +386,7 @@ class ManagedEditorInternal
|
||||
public:
|
||||
static bool IsDevInstance()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::IsDevInstance")
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
return true;
|
||||
#else
|
||||
@@ -389,6 +396,7 @@ public:
|
||||
|
||||
static bool IsOfficialBuild()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::IsOfficialBuild")
|
||||
#if OFFICIAL_BUILD
|
||||
return true;
|
||||
#else
|
||||
@@ -398,18 +406,20 @@ public:
|
||||
|
||||
static bool IsPlayMode()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_IsPlayMode")
|
||||
return Editor::IsPlayMode;
|
||||
}
|
||||
|
||||
static int32 ReadOutputLogs(MonoArray* outMessages, MonoArray* outLogTypes, MonoArray* outLogTimes)
|
||||
static int32 ReadOutputLogs(MonoArray** outMessages, MonoArray** outLogTypes, MonoArray** outLogTimes, int outArraySize)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ReadOutputLogs")
|
||||
ScopeLock lock(CachedLogDataLocker);
|
||||
|
||||
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
|
||||
return 0;
|
||||
|
||||
int32 count = 0;
|
||||
const int32 maxCount = (int32)mono_array_length(outMessages);
|
||||
const int32 maxCount = outArraySize;//(int32)mono_array_length(*outMessages);
|
||||
|
||||
byte* ptr = CachedLogData.Get();
|
||||
byte* end = ptr + CachedLogData.Count();
|
||||
@@ -429,9 +439,9 @@ public:
|
||||
|
||||
auto msgObj = MUtils::ToString(StringView(msg, length));
|
||||
|
||||
mono_array_setref(outMessages, count, msgObj);
|
||||
mono_array_set(outLogTypes, byte, count, type);
|
||||
mono_array_set(outLogTimes, int64, count, time);
|
||||
mono_array_setref(*outMessages, count, msgObj);
|
||||
mono_array_set(*outLogTypes, byte, count, type);
|
||||
mono_array_set(*outLogTimes, int64, count, time);
|
||||
|
||||
count++;
|
||||
}
|
||||
@@ -445,21 +455,25 @@ public:
|
||||
|
||||
static void SetPlayMode(bool value)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetPlayMode")
|
||||
Editor::IsPlayMode = value;
|
||||
}
|
||||
|
||||
static MonoString* GetProjectPath()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetProjectPath")
|
||||
return MUtils::ToString(Editor::Project->ProjectPath);
|
||||
}
|
||||
|
||||
static void CloseSplashScreen()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CloseSplashScreen")
|
||||
Editor::CloseSplashScreen();
|
||||
}
|
||||
|
||||
static bool CloneAssetFile(MonoString* dstPathObj, MonoString* srcPathObj, Guid* dstId)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CloneAssetFile")
|
||||
// Get normalized paths
|
||||
String dstPath, srcPath;
|
||||
MUtils::ToString(dstPathObj, dstPath);
|
||||
@@ -489,6 +503,7 @@ public:
|
||||
|
||||
static bool CreateAsset(NewAssetType type, MonoString* outputPathObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CreateAsset")
|
||||
String tag;
|
||||
switch (type)
|
||||
{
|
||||
@@ -541,6 +556,7 @@ public:
|
||||
|
||||
static bool CreateVisualScript(MonoString* outputPathObj, MonoString* baseTypenameObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CreateVisualScript")
|
||||
String outputPath;
|
||||
MUtils::ToString(outputPathObj, outputPath);
|
||||
FileSystem::NormalizePath(outputPath);
|
||||
@@ -551,6 +567,7 @@ public:
|
||||
|
||||
static MonoString* CanImport(MonoString* extensionObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanImport")
|
||||
String extension;
|
||||
MUtils::ToString(extensionObj, extension);
|
||||
if (extension.Length() > 0 && extension[0] == '.')
|
||||
@@ -561,6 +578,7 @@ public:
|
||||
|
||||
static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_Import")
|
||||
String inputPath, outputPath;
|
||||
MUtils::ToString(inputPathObj, inputPath);
|
||||
MUtils::ToString(outputPathObj, outputPath);
|
||||
@@ -572,6 +590,7 @@ public:
|
||||
|
||||
static bool ImportTexture(MonoString* inputPathObj, MonoString* outputPathObj, InternalTextureOptions* optionsObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportTexture")
|
||||
ImportTexture::Options options;
|
||||
InternalTextureOptions::Convert(optionsObj, &options);
|
||||
|
||||
@@ -580,6 +599,7 @@ public:
|
||||
|
||||
static bool ImportModel(MonoString* inputPathObj, MonoString* outputPathObj, InternalModelOptions* optionsObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportModel")
|
||||
ImportModelFile::Options options;
|
||||
InternalModelOptions::Convert(optionsObj, &options);
|
||||
|
||||
@@ -588,6 +608,7 @@ public:
|
||||
|
||||
static bool ImportAudio(MonoString* inputPathObj, MonoString* outputPathObj, InternalAudioOptions* optionsObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_ImportAudio")
|
||||
ImportAudio::Options options;
|
||||
InternalAudioOptions::Convert(optionsObj, &options);
|
||||
|
||||
@@ -596,6 +617,7 @@ public:
|
||||
|
||||
static void GetAudioClipMetadata(AudioClip* clip, int32* originalSize, int32* importedSize)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetAudioClipMetadata")
|
||||
INTERNAL_CALL_CHECK(clip);
|
||||
*originalSize = clip->AudioHeader.OriginalSize;
|
||||
*importedSize = clip->AudioHeader.ImportedSize;
|
||||
@@ -603,6 +625,7 @@ public:
|
||||
|
||||
static bool SaveJsonAsset(MonoString* outputPathObj, MonoString* dataObj, MonoString* dataTypeNameObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SaveJsonAsset")
|
||||
String outputPath;
|
||||
MUtils::ToString(outputPathObj, outputPath);
|
||||
FileSystem::NormalizePath(outputPath);
|
||||
@@ -623,6 +646,8 @@ public:
|
||||
|
||||
static bool GetTextureImportOptions(MonoString* pathObj, InternalTextureOptions* result)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Content.Import.TextureImportEntry::Internal_GetTextureImportOptions")
|
||||
|
||||
String path;
|
||||
MUtils::ToString(pathObj, path);
|
||||
FileSystem::NormalizePath(path);
|
||||
@@ -641,6 +666,7 @@ public:
|
||||
|
||||
static void GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Content.Import.ModelImportEntry::Internal_GetModelImportOptions")
|
||||
// Initialize defaults
|
||||
ImportModelFile::Options options;
|
||||
if (const auto* graphicsSettings = GraphicsSettings::Get())
|
||||
@@ -660,6 +686,7 @@ public:
|
||||
|
||||
static bool GetAudioImportOptions(MonoString* pathObj, InternalAudioOptions* result)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Content.Import.AudioImportEntry::Internal_GetAudioImportOptions")
|
||||
String path;
|
||||
MUtils::ToString(pathObj, path);
|
||||
FileSystem::NormalizePath(path);
|
||||
@@ -678,6 +705,7 @@ public:
|
||||
|
||||
static bool CanExport(MonoString* pathObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanExport")
|
||||
#if COMPILE_WITH_ASSETS_EXPORTER
|
||||
String path;
|
||||
MUtils::ToString(pathObj, path);
|
||||
@@ -691,6 +719,7 @@ public:
|
||||
|
||||
static bool Export(MonoString* inputPathObj, MonoString* outputFolderObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_Export")
|
||||
#if COMPILE_WITH_ASSETS_EXPORTER
|
||||
String inputPath;
|
||||
MUtils::ToString(inputPathObj, inputPath);
|
||||
@@ -708,11 +737,13 @@ public:
|
||||
|
||||
static void CopyCache(Guid* dstId, Guid* srcId)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CopyCache")
|
||||
ShaderCacheManager::CopyCache(*dstId, *srcId);
|
||||
}
|
||||
|
||||
static void BakeLightmaps(bool cancel)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_BakeLightmaps")
|
||||
auto builder = ShadowsOfMordor::Builder::Instance();
|
||||
if (cancel)
|
||||
builder->CancelBuild();
|
||||
@@ -722,6 +753,7 @@ public:
|
||||
|
||||
static MonoString* GetShaderAssetSourceCode(BinaryAsset* obj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetShaderAssetSourceCode")
|
||||
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
|
||||
if (obj->WaitForLoaded())
|
||||
DebugLog::ThrowNullReference();
|
||||
@@ -747,6 +779,7 @@ public:
|
||||
|
||||
static bool CookMeshCollision(MonoString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CookMeshCollision")
|
||||
#if COMPILE_WITH_PHYSICS_COOKING
|
||||
CollisionCooking::Argument arg;
|
||||
String path;
|
||||
@@ -767,6 +800,7 @@ public:
|
||||
|
||||
static void GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetCollisionWires")
|
||||
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
|
||||
return;
|
||||
|
||||
@@ -792,32 +826,38 @@ public:
|
||||
|
||||
static void GetEditorBoxWithChildren(Actor* obj, BoundingBox* result)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetEditorBoxWithChildren")
|
||||
INTERNAL_CALL_CHECK(obj);
|
||||
*result = obj->GetEditorBoxChildren();
|
||||
}
|
||||
|
||||
static void SetOptions(ManagedEditor::InternalOptions* options)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetOptions")
|
||||
ManagedEditor::ManagedEditorOptions = *options;
|
||||
}
|
||||
|
||||
static void DrawNavMesh()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_DrawNavMesh")
|
||||
Navigation::DrawNavMesh();
|
||||
}
|
||||
|
||||
static bool GetIsEveryAssemblyLoaded()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetIsEveryAssemblyLoaded")
|
||||
return Scripting::IsEveryAssemblyLoaded();
|
||||
}
|
||||
|
||||
static int32 GetLastProjectOpenedEngineBuild()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetLastProjectOpenedEngineBuild")
|
||||
return Editor::LastProjectOpenedEngineBuild;
|
||||
}
|
||||
|
||||
static bool GetIsCSGActive()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetIsCSGActive")
|
||||
#if COMPILE_WITH_CSG_BUILDER
|
||||
return CSG::Builder::IsActive();
|
||||
#else
|
||||
@@ -827,6 +867,7 @@ public:
|
||||
|
||||
static void RunVisualScriptBreakpointLoopTick(float deltaTime)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_RunVisualScriptBreakpointLoopTick")
|
||||
// Update
|
||||
Platform::Tick();
|
||||
Engine::HasFocus = (Engine::MainWindow && Engine::MainWindow->IsFocused()) || Platform::GetHasFocus();
|
||||
@@ -921,6 +962,7 @@ public:
|
||||
|
||||
static MonoArray* GetVisualScriptLocals()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptLocals")
|
||||
MonoArray* result = nullptr;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack && stack->Scope)
|
||||
@@ -969,6 +1011,7 @@ public:
|
||||
|
||||
static MonoArray* GetVisualScriptStackFrames()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetVisualScriptStackFrames")
|
||||
MonoArray* result = nullptr;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack)
|
||||
@@ -1022,6 +1065,7 @@ public:
|
||||
|
||||
static bool EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocalManaged* local)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_EvaluateVisualScriptLocal")
|
||||
Variant v;
|
||||
if (VisualScripting::Evaluate(script, VisualScripting::GetThreadStackTop()->Instance, local->NodeId, local->BoxId, v))
|
||||
{
|
||||
@@ -1034,6 +1078,7 @@ public:
|
||||
|
||||
static void DeserializeSceneObject(SceneObject* sceneObject, MonoString* jsonObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_DeserializeSceneObject")
|
||||
PROFILE_CPU_NAMED("DeserializeSceneObject");
|
||||
|
||||
StringAnsi json;
|
||||
@@ -1062,11 +1107,13 @@ public:
|
||||
|
||||
static void LoadAsset(Guid* id)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_LoadAsset")
|
||||
Content::LoadAsync<Asset>(*id);
|
||||
}
|
||||
|
||||
static bool CanSetToRoot(Prefab* prefab, Actor* targetActor)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_CanSetToRoot")
|
||||
// Reference: Prefab::ApplyAll(Actor* targetActor)
|
||||
if (targetActor->GetPrefabID() != prefab->GetID())
|
||||
return false;
|
||||
@@ -1089,11 +1136,13 @@ public:
|
||||
|
||||
static float GetAnimationTime(AnimatedModel* animatedModel)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_GetAnimationTime")
|
||||
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;
|
||||
}
|
||||
|
||||
static void SetAnimationTime(AnimatedModel* animatedModel, float time)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.Editor::Internal_SetAnimationTime")
|
||||
if (animatedModel && animatedModel->GraphInstance.State.Count() == 1)
|
||||
animatedModel->GraphInstance.State[0].Animation.TimePosition = time;
|
||||
}
|
||||
|
||||
@@ -375,7 +375,9 @@ namespace FlaxEditor.Modules
|
||||
Thread.Sleep(0);
|
||||
|
||||
_workerThread.Join(1000);
|
||||
_workerThread.Abort();
|
||||
#if !USE_NETCORE
|
||||
_workerThread.Abort(); // Deprecated in .NET 7
|
||||
#endif
|
||||
_workerThread = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
{
|
||||
Profiler.BeginEvent("GetXmlDocs");
|
||||
|
||||
var uri = new UriBuilder(assembly.CodeBase);
|
||||
var uri = new UriBuilder(Utils.GetAssemblyLocation(assembly));
|
||||
var path = Uri.UnescapeDataString(uri.Path);
|
||||
var name = assembly.GetName().Name;
|
||||
var xmlFilePath = Path.Combine(Path.GetDirectoryName(path), name + ".xml");
|
||||
|
||||
@@ -391,9 +391,27 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
|
||||
private static bool HasAssemblyValidAnyTypes(Assembly assembly)
|
||||
{
|
||||
var codeBase = Utils.GetAssemblyLocation(assembly);
|
||||
#if USE_NETCORE
|
||||
if (assembly.ManifestModule.FullyQualifiedName == "<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
|
||||
var codeBase = assembly.CodeBase;
|
||||
return string.IsNullOrEmpty(codeBase) || !codeBase.Contains("/Mono/lib/mono/");
|
||||
if (!codeBase.Contains("/Mono/lib/mono/"))
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool HasAssemblyValidScriptingTypes(Assembly a)
|
||||
|
||||
@@ -218,6 +218,16 @@ namespace FlaxEditor.Options
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace FlaxEditor
|
||||
|
||||
var type = plugin.GetType();
|
||||
var assembly = type.Assembly;
|
||||
var assemblyPath = assembly.Location;
|
||||
var assemblyPath = Utils.GetAssemblyLocation(assembly);
|
||||
var assemblyName = assembly.GetName().Name;
|
||||
var dotEditorPos = assemblyName.LastIndexOf(".Editor", StringComparison.OrdinalIgnoreCase);
|
||||
if (dotEditorPos != -1)
|
||||
|
||||
@@ -41,8 +41,10 @@ namespace FlaxEditor.Progress.Handlers
|
||||
|
||||
private void OnScriptsReload()
|
||||
{
|
||||
#if !USE_NETCORE
|
||||
// Clear types cache
|
||||
Newtonsoft.Json.JsonSerializer.ClearCache();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnScriptsReloadEnd()
|
||||
|
||||
@@ -8,6 +8,110 @@ using Newtonsoft.Json;
|
||||
|
||||
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>
|
||||
/// Contains information about Flax project.
|
||||
/// </summary>
|
||||
@@ -154,7 +258,7 @@ namespace FlaxEditor
|
||||
{
|
||||
// Load
|
||||
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.ProjectFolderPath = StringUtils.NormalizePath(Path.GetDirectoryName(path));
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ bool ScriptsBuilder::IsReady()
|
||||
|
||||
void ScriptsBuilder::MarkWorkspaceDirty()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_MarkWorkspaceDirty")
|
||||
ScopeLock scopeLock(_locker);
|
||||
_lastSourceCodeEdited = DateTime::Now();
|
||||
_wasProjectStructureChanged = true;
|
||||
@@ -183,6 +184,7 @@ void ScriptsBuilder::MarkWorkspaceDirty()
|
||||
|
||||
void ScriptsBuilder::CheckForCompile()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_CheckForCompile")
|
||||
ScopeLock scopeLock(_locker);
|
||||
if (IsSourceDirty())
|
||||
Compile();
|
||||
@@ -205,6 +207,7 @@ void ScriptsBuilderImpl::onScriptsReloadEnd()
|
||||
|
||||
void ScriptsBuilder::Compile()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_Compile")
|
||||
ScopeLock scopeLock(_locker);
|
||||
|
||||
// Request compile job
|
||||
|
||||
@@ -6,7 +6,9 @@ using System.Linq;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine.Utilities;
|
||||
using Utils = FlaxEngine.Utils;
|
||||
|
||||
namespace FlaxEditor.States
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.States
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.States
|
||||
|
||||
@@ -12,6 +12,7 @@ using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine.Utilities;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -587,7 +588,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < _parameters.Length; i++)
|
||||
{
|
||||
writer.Write(_parameters[i].Name); // Parameter name
|
||||
Utilities.VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
|
||||
VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
|
||||
}
|
||||
SetValue(2, stream.ToArray());
|
||||
}
|
||||
@@ -605,7 +606,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
var parameterName = reader.ReadString(); // Parameter name
|
||||
var boxType = Utilities.VariantUtils.ReadVariantType(reader); // Box type
|
||||
var boxType = VariantUtils.ReadVariantType(reader); // Box type
|
||||
MakeBox(i + 1, parameterName, boxType);
|
||||
}
|
||||
}
|
||||
@@ -788,14 +789,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
reader.ReadByte(); // Version
|
||||
signature.IsStatic = reader.ReadBoolean(); // Is Static
|
||||
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
|
||||
signature.ReturnType = VariantUtils.ReadVariantScriptType(reader); // Return type
|
||||
var parametersCount = reader.ReadInt32(); // Parameters count
|
||||
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
ref var param = ref signature.Params[i];
|
||||
param.Name = Utilities.Utils.ReadStr(reader, 11); // Parameter name
|
||||
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.Type = VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.IsOut = reader.ReadByte() != 0; // Is parameter out
|
||||
}
|
||||
}
|
||||
@@ -809,14 +810,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
reader.ReadByte(); // Version
|
||||
signature.IsStatic = reader.ReadBoolean(); // Is Static
|
||||
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
|
||||
signature.ReturnType = VariantUtils.ReadVariantScriptType(reader); // Return type
|
||||
var parametersCount = reader.ReadInt32(); // Parameters count
|
||||
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
ref var param = ref signature.Params[i];
|
||||
param.Name = reader.ReadString(); // Parameter name
|
||||
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.Type = VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
param.IsOut = reader.ReadByte() != 0; // Is parameter out
|
||||
}
|
||||
}
|
||||
@@ -833,13 +834,13 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
writer.Write((byte)4); // Version
|
||||
writer.Write(methodInfo.IsStatic); // Is Static
|
||||
Utilities.VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type
|
||||
VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type
|
||||
writer.Write(parameters.Length); // Parameters count
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ref var param = ref parameters[i];
|
||||
Utilities.Utils.WriteStr(writer, param.Name, 11); // Parameter name
|
||||
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
writer.Write((byte)(param.IsOut ? 1 : 0)); // Is parameter out
|
||||
}
|
||||
return stream.ToArray();
|
||||
@@ -1461,14 +1462,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (_signature.IsVirtual)
|
||||
flags |= Flags.Virtual;
|
||||
writer.Write((byte)flags); // Flags
|
||||
Utilities.VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type
|
||||
VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type
|
||||
var parametersCount = _signature.Parameters?.Length ?? 0;
|
||||
writer.Write(parametersCount); // Parameters count
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
ref var param = ref _signature.Parameters[i];
|
||||
Utilities.Utils.WriteStrAnsi(writer, param.Name, 13); // Parameter name
|
||||
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
|
||||
writer.Write((byte)0); // Is parameter out
|
||||
writer.Write((byte)0); // Has default value
|
||||
}
|
||||
@@ -1497,13 +1498,13 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
var flags = (Flags)reader.ReadByte(); // Flags
|
||||
_signature.IsStatic = (flags & Flags.Static) == Flags.Static;
|
||||
_signature.IsVirtual = (flags & Flags.Virtual) == Flags.Virtual;
|
||||
_signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return Type
|
||||
_signature.ReturnType = VariantUtils.ReadVariantScriptType(reader); // Return Type
|
||||
var parametersCount = reader.ReadInt32(); // Parameters count
|
||||
_signature.Parameters = new Parameter[parametersCount];
|
||||
for (int i = 0; i < parametersCount; i++)
|
||||
{
|
||||
var paramName = Utilities.Utils.ReadStrAnsi(reader, 13); // Parameter name
|
||||
var paramType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
var paramType = VariantUtils.ReadVariantScriptType(reader); // Parameter type
|
||||
var isOut = reader.ReadByte() != 0; // Is parameter out
|
||||
var hasDefaultValue = reader.ReadByte() != 0; // Has default value
|
||||
_signature.Parameters[i] = new Parameter
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEngine.Utilities;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface.Archetypes
|
||||
@@ -167,7 +168,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < fieldsLength; i++)
|
||||
{
|
||||
Utilities.Utils.WriteStr(writer, fields[i].Name, 11); // Field type
|
||||
Utilities.VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type
|
||||
VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type
|
||||
}
|
||||
Values[1] = stream.ToArray();
|
||||
}
|
||||
@@ -184,7 +185,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
for (int i = 0; i < fieldsLength; i++)
|
||||
{
|
||||
var fieldName = Utilities.Utils.ReadStr(reader, 11); // Field name
|
||||
var fieldType = Utilities.VariantUtils.ReadVariantType(reader); // Field type
|
||||
var fieldType = VariantUtils.ReadVariantType(reader); // Field type
|
||||
MakeBox(i + 1, fieldName, new ScriptType(fieldType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
@@ -118,8 +119,13 @@ namespace FlaxEditor.Surface
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
|
||||
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
|
||||
|
||||
var formatter = new BinaryFormatter();
|
||||
#pragma warning disable SYSLIB0011
|
||||
formatter.Serialize(stream, attributes);
|
||||
#pragma warning restore SYSLIB0011
|
||||
_oldData = stream.ToArray();
|
||||
}
|
||||
editor.Select(new Proxy
|
||||
@@ -141,8 +147,13 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
|
||||
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
|
||||
|
||||
var formatter = new BinaryFormatter();
|
||||
#pragma warning disable SYSLIB0011
|
||||
formatter.Serialize(stream, newValue);
|
||||
#pragma warning restore SYSLIB0011
|
||||
var newData = stream.ToArray();
|
||||
if (!_oldData.SequenceEqual(newData))
|
||||
{
|
||||
|
||||
@@ -4,6 +4,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using FlaxEngine;
|
||||
|
||||
@@ -54,8 +56,13 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
try
|
||||
{
|
||||
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
|
||||
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
|
||||
|
||||
var formatter = new BinaryFormatter();
|
||||
#pragma warning disable SYSLIB0011
|
||||
return (Attribute[])formatter.Deserialize(stream);
|
||||
#pragma warning restore SYSLIB0011
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -122,8 +129,13 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
// Ensure we are in the correct load context (https://github.com/dotnet/runtime/issues/42041)
|
||||
using var ctx = AssemblyLoadContext.EnterContextualReflection(typeof(Editor).Assembly);
|
||||
|
||||
var formatter = new BinaryFormatter();
|
||||
#pragma warning disable SYSLIB0011
|
||||
formatter.Serialize(stream, attributes);
|
||||
#pragma warning restore SYSLIB0011
|
||||
AddEntry(AttributeMetaTypeID, stream.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine.Utilities;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
|
||||
@@ -8,6 +8,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
using Utils = FlaxEditor.Utilities.Utils;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Tools.Terrain.Sculpt
|
||||
|
||||
@@ -445,7 +445,7 @@ namespace FlaxEditor.Windows
|
||||
int logCount;
|
||||
do
|
||||
{
|
||||
logCount = Editor.Internal_ReadOutputLogs(_outMessages, _outLogTypes, _outLogTimes);
|
||||
logCount = Editor.Internal_ReadOutputLogs(ref _outMessages, ref _outLogTypes, ref _outLogTimes, OutCapacity);
|
||||
|
||||
for (int i = 0; i < logCount; i++)
|
||||
{
|
||||
|
||||
@@ -19,16 +19,16 @@ namespace FlaxEngine
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (char* name = &Name0)
|
||||
fixed (short* name = Name0)
|
||||
{
|
||||
return new string(name);
|
||||
return new string((char*)name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe bool NameStartsWith(string prefix)
|
||||
{
|
||||
fixed (char* name = &Name0)
|
||||
fixed (short* name = Name0)
|
||||
{
|
||||
fixed (char* p = prefix)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
@@ -44,6 +45,7 @@ namespace FlaxEngine
|
||||
/// The node evaluation context structure.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(ContextMarshaler))]
|
||||
public struct Context
|
||||
{
|
||||
/// <summary>
|
||||
@@ -92,6 +94,61 @@ namespace FlaxEngine
|
||||
public AnimatedModel Instance;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(Context), MarshalMode.Default, typeof(ContextMarshaler))]
|
||||
internal static class ContextMarshaler
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ContextNative
|
||||
{
|
||||
public IntPtr Graph;
|
||||
public IntPtr GraphExecutor;
|
||||
public IntPtr Node;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
public float DeltaTime;
|
||||
public ulong CurrentFrameIndex;
|
||||
public IntPtr BaseModel;
|
||||
public IntPtr Instance;
|
||||
}
|
||||
|
||||
internal static Context ConvertToManaged(ContextNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static ContextNative ConvertToUnmanaged(Context managed) => ToNative(managed);
|
||||
|
||||
internal static Context ToManaged(ContextNative managed)
|
||||
{
|
||||
return new Context()
|
||||
{
|
||||
Graph = managed.Graph,
|
||||
GraphExecutor = managed.GraphExecutor,
|
||||
Node = managed.Node,
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
DeltaTime = managed.DeltaTime,
|
||||
CurrentFrameIndex = managed.CurrentFrameIndex,
|
||||
BaseModel = SkinnedModelMarshaller.ConvertToManaged(managed.BaseModel),
|
||||
Instance = AnimatedModelMarshaller.ConvertToManaged(managed.Instance),
|
||||
};
|
||||
}
|
||||
internal static ContextNative ToNative(Context managed)
|
||||
{
|
||||
return new ContextNative()
|
||||
{
|
||||
Graph = managed.Graph,
|
||||
GraphExecutor = managed.GraphExecutor,
|
||||
Node = managed.Node,
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
DeltaTime = managed.DeltaTime,
|
||||
CurrentFrameIndex = managed.CurrentFrameIndex,
|
||||
BaseModel = SkinnedModelMarshaller.ConvertToUnmanaged(managed.BaseModel),
|
||||
Instance = AnimatedModelMarshaller.ConvertToUnmanaged(managed.Instance),
|
||||
};
|
||||
}
|
||||
internal static void Free(ContextNative unmanaged)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The animation graph 'impulse' connections data container (the actual transfer is done via pointer as it gives better performance).
|
||||
/// Container for skeleton nodes transformation hierarchy and any other required data.
|
||||
@@ -203,14 +260,16 @@ namespace FlaxEngine
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_HasConnection(ref CustomNode.Context context, int boxId);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_HasConnection")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern object Internal_GetInputValue(ref CustomNode.Context context, int boxId);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetInputValue")]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))]
|
||||
internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern IntPtr Internal_GetOutputImpulseData(ref CustomNode.Context context);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")]
|
||||
internal static partial IntPtr Internal_GetOutputImpulseData(ref AnimationGraph.CustomNode.Context context);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
#endif
|
||||
|
||||
struct InternalInitData
|
||||
{
|
||||
@@ -52,6 +52,7 @@ namespace AnimGraphInternal
|
||||
{
|
||||
bool HasConnection(InternalContext* context, int32 boxId)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_HasConnection")
|
||||
const auto box = context->Node->TryGetBox(boxId);
|
||||
if (box == nullptr)
|
||||
DebugLog::ThrowArgumentOutOfRange("boxId");
|
||||
@@ -60,6 +61,7 @@ namespace AnimGraphInternal
|
||||
|
||||
MonoObject* GetInputValue(InternalContext* context, int32 boxId)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_GetInputValue")
|
||||
const auto box = context->Node->TryGetBox(boxId);
|
||||
if (box == nullptr)
|
||||
DebugLog::ThrowArgumentOutOfRange("boxId");
|
||||
@@ -77,14 +79,13 @@ namespace AnimGraphInternal
|
||||
|
||||
AnimGraphImpulse* GetOutputImpulseData(InternalContext* context)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")
|
||||
const auto nodes = context->Node->GetNodes(context->GraphExecutor);
|
||||
context->GraphExecutor->InitNodes(nodes);
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void AnimGraphExecutor::initRuntime()
|
||||
{
|
||||
#if USE_MONO
|
||||
@@ -122,7 +123,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
|
||||
internalContext.Instance = context.Data->Object ? context.Data->Object->GetOrCreateManagedInstance() : nullptr;
|
||||
|
||||
// Peek managed object
|
||||
const auto obj = mono_gchandle_get_target(data.Handle);
|
||||
const auto obj = MUtils::GetGCHandleTarget(data.Handle);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Warning, "Custom node instance is null.");
|
||||
@@ -166,7 +167,7 @@ void AnimGraph::ClearCustomNode(Node* node)
|
||||
if (data.Handle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(data.Handle);
|
||||
MUtils::FreeGCHandle(data.Handle);
|
||||
#endif
|
||||
data.Handle = 0;
|
||||
}
|
||||
@@ -216,7 +217,7 @@ bool AnimGraph::InitCustomNode(Node* node)
|
||||
|
||||
// Allocate managed node object (create GC handle to prevent destruction)
|
||||
const auto obj = type->CreateInstance();
|
||||
const auto handleGC = mono_gchandle_new(obj, false);
|
||||
const auto handleGC = MUtils::NewGCHandle(obj, false);
|
||||
|
||||
// Initialize node
|
||||
InternalInitData initData;
|
||||
@@ -228,7 +229,7 @@ bool AnimGraph::InitCustomNode(Node* node)
|
||||
load->Invoke(obj, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
mono_gchandle_free(handleGC);
|
||||
MUtils::FreeGCHandle(handleGC);
|
||||
|
||||
MException ex(exception);
|
||||
ex.Log(LogType::Warning, TEXT("AnimGraph"));
|
||||
|
||||
@@ -516,7 +516,7 @@ public:
|
||||
/// <summary>
|
||||
/// The GC handle to the managed instance of the node object.
|
||||
/// </summary>
|
||||
uint32 Handle;
|
||||
gchandle Handle;
|
||||
};
|
||||
|
||||
struct CurveData
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Engine/Threading/MainThreadTask.h"
|
||||
#include "Engine/Threading/ConcurrentTaskQueue.h"
|
||||
#if USE_MONO
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
|
||||
#endif
|
||||
|
||||
@@ -270,7 +271,7 @@ void Asset::OnManagedInstanceDeleted()
|
||||
if (_gcHandle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(_gcHandle);
|
||||
MUtils::FreeGCHandle(_gcHandle);
|
||||
#endif
|
||||
_gcHandle = 0;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,10 @@ namespace FlaxEngine
|
||||
|
||||
var dataTypeName = DataTypeName;
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
for (int i = 0; i < assemblies.Length; i++)
|
||||
|
||||
// Going through the assemblies in order will return collected assemblies first,
|
||||
// use reverse order instead to find the type currently loaded assemblies instead.
|
||||
for (int i = assemblies.Length-1; i >= 0; i--)
|
||||
{
|
||||
var assembly = assemblies[i];
|
||||
if (assembly != null)
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#pragma clang diagnostic ignored "-Wnull-dereference"
|
||||
#pragma clang diagnostic ignored "-Winvalid-noreturn"
|
||||
|
||||
#define SCRIPTING_EXPORT(name)
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
|
||||
@@ -86,6 +88,8 @@
|
||||
|
||||
#pragma warning(disable: 4251)
|
||||
|
||||
#define SCRIPTING_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
|
||||
|
||||
#else
|
||||
|
||||
#pragma error "Unknown compiler."
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content.Settings
|
||||
@@ -562,8 +563,8 @@ namespace FlaxEditor.Content.Settings
|
||||
/// <summary>
|
||||
/// Loads the current game settings asset and applies it to the engine runtime configuration.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void Apply();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.GameSettings::Apply")]
|
||||
public static partial void Apply();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content.Settings
|
||||
@@ -24,14 +26,26 @@ namespace FlaxEditor.Content.Settings
|
||||
/// Gets the current tags collection.
|
||||
/// </summary>
|
||||
/// <returns>The tags collection.</returns>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string[] GetCurrentTags();
|
||||
internal static string[] GetCurrentTags()
|
||||
{
|
||||
return GetCurrentTags(out int _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current layer names (max 32 items but trims last empty items).
|
||||
/// </summary>
|
||||
/// <returns>The layers.</returns>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern string[] GetCurrentLayers();
|
||||
public static string[] GetCurrentLayers()
|
||||
{
|
||||
return GetCurrentLayers(out int _);
|
||||
}
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentTags", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "tagCount")]
|
||||
internal static partial string[] GetCurrentTags(out int tagCount);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEditor.Content.Settings.LayersAndTagsSettings::GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.ArrayMarshaller<,>), CountElementName = "layerCount")]
|
||||
internal static partial string[] GetCurrentLayers(out int layerCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,16 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
@@ -25,9 +35,9 @@ namespace FlaxEngine.TypeConverters
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
if (v.Length == 4)
|
||||
return new Color(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3]));
|
||||
return new Color(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||
if (v.Length == 3)
|
||||
return new Color(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), 1.0f);
|
||||
return new Color(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), 1.0f);
|
||||
throw new FormatException("Invalid Color value format.");
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
@@ -39,7 +49,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Color)value;
|
||||
return v.R + "," + v.G + "," + v.B + "," + v.A;
|
||||
return v.R.ToString(culture) + "," + v.G.ToString(culture) + "," + v.B.ToString(culture) + "," + v.A.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Double2(double.Parse(v[0]), double.Parse(v[1]));
|
||||
return new Double2(double.Parse(v[0], culture), double.Parse(v[1], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Double2)value;
|
||||
return v.X + "," + v.Y;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Double3(double.Parse(v[0]), double.Parse(v[1]), double.Parse(v[2]));
|
||||
return new Double3(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Double3)value;
|
||||
return v.X + "," + v.Y + "," + v.Z;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Double4(double.Parse(v[0]), double.Parse(v[1]), double.Parse(v[2]), double.Parse(v[3]));
|
||||
return new Double4(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture), double.Parse(v[3], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Double4)value;
|
||||
return v.X + "," + v.Y + "," + v.Z + "," + v.W;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Float2(float.Parse(v[0]), float.Parse(v[1]));
|
||||
return new Float2(float.Parse(v[0], culture), float.Parse(v[1], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Float2)value;
|
||||
return v.X + "," + v.Y;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Float3(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]));
|
||||
return new Float3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Float3)value;
|
||||
return v.X + "," + v.Y + "," + v.Z;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Float4(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3]));
|
||||
return new Float4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Float4)value;
|
||||
return v.X + "," + v.Y + "," + v.Z + "," + v.W;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Int2(int.Parse(v[0]), int.Parse(v[1]));
|
||||
return new Int2(int.Parse(v[0], culture), int.Parse(v[1], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Int2)value;
|
||||
return v.X + "," + v.Y;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Int3(int.Parse(v[0]), int.Parse(v[1]), int.Parse(v[2]));
|
||||
return new Int3(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Int3)value;
|
||||
return v.X + "," + v.Y + "," + v.Z;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Int4(int.Parse(v[0]), int.Parse(v[1]), int.Parse(v[2]), int.Parse(v[3]));
|
||||
return new Int4(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture), int.Parse(v[3], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Int4)value;
|
||||
return v.X + "," + v.Y + "," + v.Z + "," + v.W;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Quaternion(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3]));
|
||||
return new Quaternion(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Quaternion)value;
|
||||
return v.X + "," + v.Y + "," + v.Z + "," + v.W;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Vector2(float.Parse(v[0]), float.Parse(v[1]));
|
||||
return new Vector2(float.Parse(v[0], culture), float.Parse(v[1], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Vector2)value;
|
||||
return v.X + "," + v.Y;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Vector3(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]));
|
||||
return new Vector3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Vector3)value;
|
||||
return v.X + "," + v.Y + "," + v.Z;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,23 @@ namespace FlaxEngine.TypeConverters
|
||||
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 />
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
string[] v = str.Split(',');
|
||||
return new Vector4(float.Parse(v[0]), float.Parse(v[1]), float.Parse(v[2]), float.Parse(v[3]));
|
||||
return new Vector4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
@@ -35,7 +45,7 @@ namespace FlaxEngine.TypeConverters
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var v = (Vector4)value;
|
||||
return v.X + "," + v.Y + "," + v.Z + "," + v.W;
|
||||
return v.X.ToString(culture) + "," + v.Y.ToString(culture) + "," + v.Z.ToString(culture) + "," + v.W.ToString(culture);
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
@@ -619,7 +619,11 @@ Variant::Variant(Asset* v)
|
||||
Variant::Variant(_MonoObject* v)
|
||||
: Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr)
|
||||
{
|
||||
AsUint = v ? mono_gchandle_new(v, true) : 0;
|
||||
#if USE_NETCORE
|
||||
AsUint64 = v ? MUtils::NewGCHandle(v, true) : 0;
|
||||
#else
|
||||
AsUint = v ? MUtils::NewGCHandle(v, true) : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -957,9 +961,13 @@ Variant::~Variant()
|
||||
Delete(AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
#if USE_NETCORE
|
||||
if (AsUint64)
|
||||
MUtils::FreeGCHandle(AsUint64);
|
||||
break;
|
||||
#elif USE_MONO
|
||||
if (AsUint)
|
||||
mono_gchandle_free(AsUint);
|
||||
MUtils::FreeGCHandle(AsUint);
|
||||
break;
|
||||
#endif
|
||||
default: ;
|
||||
@@ -1088,8 +1096,10 @@ Variant& Variant::operator=(const Variant& other)
|
||||
AsDictionary = New<Dictionary<Variant, Variant>>(*other.AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
AsUint = other.AsUint ? mono_gchandle_new(mono_gchandle_get_target(other.AsUint), true) : 0;
|
||||
#if USE_NETCORE
|
||||
AsUint64 = other.AsUint64 ? MUtils::NewGCHandle(MUtils::GetGCHandleTarget(other.AsUint64), true) : 0;
|
||||
#elif USE_MONO
|
||||
AsUint = other.AsUint ? MUtils::NewGCHandle(MUtils::GetGCHandleTarget(other.AsUint), true) : 0;
|
||||
#endif
|
||||
break;
|
||||
case VariantType::Null:
|
||||
@@ -1217,7 +1227,7 @@ bool Variant::operator==(const Variant& other) const
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
// TODO: invoke C# Equality logic?
|
||||
return AsUint == other.AsUint || mono_gchandle_get_target(AsUint) == mono_gchandle_get_target(other.AsUint);
|
||||
return AsUint == other.AsUint || MUtils::GetGCHandleTarget(AsUint) == MUtils::GetGCHandleTarget(other.AsUint);
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
@@ -1308,8 +1318,10 @@ Variant::operator bool() const
|
||||
case VariantType::Asset:
|
||||
return AsAsset != nullptr;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
return AsUint != 0 && mono_gchandle_get_target(AsUint) != nullptr;
|
||||
#if USE_NETCORE
|
||||
return AsUint64 != 0 && MUtils::GetGCHandleTarget(AsUint64) != nullptr;
|
||||
#elif USE_MONO
|
||||
return AsUint != 0 && MUtils::GetGCHandleTarget(AsUint) != nullptr;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
@@ -1578,8 +1590,10 @@ Variant::operator void*() const
|
||||
case VariantType::Blob:
|
||||
return AsBlob.Data;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
return AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
|
||||
#if USE_NETCORE
|
||||
return AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
|
||||
#elif USE_MONO
|
||||
return AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
@@ -1623,8 +1637,10 @@ Variant::operator ScriptingObject*() const
|
||||
|
||||
Variant::operator _MonoObject*() const
|
||||
{
|
||||
#if USE_MONO
|
||||
return Type.Type == VariantType::ManagedObject && AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
|
||||
#if USE_NETCORE
|
||||
return Type.Type == VariantType::ManagedObject && AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
|
||||
#elif USE_MONO
|
||||
return Type.Type == VariantType::ManagedObject && AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
@@ -2337,9 +2353,14 @@ void Variant::SetType(const VariantType& type)
|
||||
Delete(AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
#if USE_NETCORE
|
||||
if (AsUint64)
|
||||
MUtils::FreeGCHandle(AsUint64);
|
||||
break;
|
||||
#elif USE_MONO
|
||||
if (AsUint)
|
||||
mono_gchandle_free(AsUint);
|
||||
MUtils::FreeGCHandle(AsUint);
|
||||
break;
|
||||
#endif
|
||||
break;
|
||||
default: ;
|
||||
@@ -2447,9 +2468,14 @@ void Variant::SetType(VariantType&& type)
|
||||
Delete(AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
#if USE_NETCORE
|
||||
if (AsUint64)
|
||||
MUtils::FreeGCHandle(AsUint64);
|
||||
break;
|
||||
#elif USE_MONO
|
||||
if (AsUint)
|
||||
mono_gchandle_free(AsUint);
|
||||
MUtils::FreeGCHandle(AsUint);
|
||||
break;
|
||||
#endif
|
||||
break;
|
||||
default: ;
|
||||
@@ -2632,7 +2658,11 @@ void Variant::SetManagedObject(_MonoObject* object)
|
||||
{
|
||||
if (Type.Type != VariantType::ManagedObject)
|
||||
SetType(VariantType(VariantType::ManagedObject, mono_object_get_class(object)));
|
||||
AsUint = mono_gchandle_new(object, true);
|
||||
#if USE_NETCORE
|
||||
AsUint64 = MUtils::NewGCHandle(object, true);
|
||||
#else
|
||||
AsUint = MUtils::NewGCHandle(object, true);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2751,8 +2781,10 @@ String Variant::ToString() const
|
||||
case VariantType::Typename:
|
||||
return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0);
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
return AsUint ? String(MUtils::ToString(mono_object_to_string(mono_gchandle_get_target(AsUint), nullptr))) : TEXT("null");
|
||||
#if USE_NETCORE
|
||||
return AsUint64 ? String(MUtils::ToString(mono_object_to_string(MUtils::GetGCHandleTarget(AsUint64), nullptr))) : TEXT("null");
|
||||
#elif USE_MONO
|
||||
return AsUint ? String(MUtils::ToString(mono_object_to_string(MUtils::GetGCHandleTarget(AsUint), nullptr))) : TEXT("null");
|
||||
#endif
|
||||
default:
|
||||
return String::Empty;
|
||||
@@ -3671,7 +3703,12 @@ void Variant::AllocStructure()
|
||||
Platform::MemoryCopy(AsBlob.Data, data, AsBlob.Length);
|
||||
#else
|
||||
Type.Type = VariantType::ManagedObject;
|
||||
AsUint = mono_gchandle_new(instance, true);
|
||||
|
||||
#if USE_NETCORE
|
||||
AsUint64 = MUtils::NewGCHandle(instance, true);
|
||||
#else
|
||||
AsUint = MUtils::NewGCHandle(instance, true);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -3763,8 +3800,10 @@ uint32 GetHash(const Variant& key)
|
||||
case VariantType::Typename:
|
||||
return GetHash((const char*)key.AsBlob.Data);
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
return key.AsUint ? (uint32)mono_object_hash(mono_gchandle_get_target(key.AsUint)) : 0;
|
||||
#if USE_NETCORE
|
||||
return key.AsUint64 ? (uint32)mono_object_hash(MUtils::GetGCHandleTarget(key.AsUint64)) : 0;
|
||||
#elif USE_MONO
|
||||
return key.AsUint ? (uint32)mono_object_hash(MUtils::GetGCHandleTarget(key.AsUint)) : 0;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
|
||||
@@ -4,10 +4,12 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
internal sealed class DebugLogHandler : ILogHandler
|
||||
internal partial class DebugLogHandler : ILogHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs on sending a log message.
|
||||
@@ -64,14 +66,14 @@ namespace FlaxEngine
|
||||
Debug.Logger.LogException(exception);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_LogWrite(LogType level, string msg);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_LogWrite", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_LogWrite(LogType level, string msg);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_Log(LogType level, string msg, IntPtr obj, string stackTrace);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_Log", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_Log(LogType level, string msg, IntPtr obj, string stackTrace);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_LogException(Exception exception, IntPtr obj);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.DebugLogHandler::Internal_LogException", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_LogException([MarshalUsing(typeof(FlaxEngine.ExceptionMarshaller))] Exception exception, IntPtr obj);
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static string Internal_GetStackTrace()
|
||||
|
||||
2256
Source/Engine/Engine/NativeInterop.cs
Normal file
2256
Source/Engine/Engine/NativeInterop.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1277,6 +1277,7 @@ bool Level::SaveAllScenes()
|
||||
|
||||
void Level::SaveAllScenesAsync()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Level::Internal_SaveAllScenesAsync")
|
||||
ScopeLock lock(_sceneActionsLocker);
|
||||
for (int32 i = 0; i < Scenes.Count(); i++)
|
||||
_sceneActions.Enqueue(New<SaveSceneAction>(Scenes[i]));
|
||||
@@ -1381,6 +1382,7 @@ bool Level::UnloadAllScenes()
|
||||
|
||||
void Level::UnloadAllScenesAsync()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Level::Internal_UnloadAllScenesAsync")
|
||||
ScopeLock lock(_sceneActionsLocker);
|
||||
_sceneActions.Enqueue(New<UnloadScenesAction>());
|
||||
}
|
||||
|
||||
@@ -303,6 +303,7 @@ bool NetworkManager::StartHost()
|
||||
|
||||
void NetworkManager::Stop()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Networking.NetworkManager::Internal_Stop");
|
||||
if (Mode == NetworkManagerMode::Offline && State == NetworkConnectionState::Offline)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
@@ -175,6 +175,7 @@ public:
|
||||
/// <param name="size">Size of the memory to copy in bytes</param>
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -196,6 +197,7 @@ public:
|
||||
/// <param name="size">Size of the memory to clear in bytes</param>
|
||||
FORCE_INLINE static void MemoryClear(void* dst, uint64 size)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Utils::MemoryClear")
|
||||
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>
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -1658,6 +1658,7 @@ DragDropEffect LinuxWindow::DoDragDrop(const StringView& data)
|
||||
|
||||
void LinuxClipboard::Clear()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
|
||||
SetText(StringView::Empty);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ Float2 MacUtils::GetScreensOrigin()
|
||||
|
||||
void MacClipboard::Clear()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard clearContents];
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ typedef struct _DROPFILES
|
||||
|
||||
void WindowsClipboard::Clear()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
|
||||
OpenClipboard(nullptr);
|
||||
EmptyClipboard();
|
||||
CloseClipboard();
|
||||
|
||||
@@ -699,6 +699,7 @@ void Render2D::Begin(GPUContext* context, GPUTextureView* output, GPUTextureView
|
||||
|
||||
void Render2D::End()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_End")
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
ASSERT(Context != nullptr && Output != nullptr);
|
||||
ASSERT(GUIShader != nullptr);
|
||||
@@ -814,6 +815,7 @@ void Render2D::PeekTransform(Matrix3x3& transform)
|
||||
|
||||
void Render2D::PopTransform()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopTransform")
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
|
||||
ASSERT(TransformLayersStack.HasItems());
|
||||
@@ -855,6 +857,7 @@ void Render2D::PeekClip(Rectangle& clipRect)
|
||||
|
||||
void Render2D::PopClip()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopClip")
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
|
||||
ClipLayersStack.Pop();
|
||||
@@ -876,6 +879,7 @@ void Render2D::PeekTint(Color& tint)
|
||||
|
||||
void Render2D::PopTint()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopTint")
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
|
||||
TintLayersStack.Pop();
|
||||
|
||||
@@ -64,8 +64,7 @@ namespace FlaxEngine
|
||||
/// <param name="rect">The rectangle to draw.</param>
|
||||
public static void DrawSprite(SpriteHandle spriteHandle, Rectangle rect)
|
||||
{
|
||||
var color = Color.White;
|
||||
Internal_DrawSprite(ref spriteHandle, ref rect, ref color);
|
||||
DrawSprite(spriteHandle, rect, Color.White);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,8 +85,7 @@ namespace FlaxEngine
|
||||
/// <param name="rect">The rectangle to draw.</param>
|
||||
public static void DrawSpritePoint(SpriteHandle spriteHandle, Rectangle rect)
|
||||
{
|
||||
var color = Color.White;
|
||||
Internal_DrawSpritePoint(ref spriteHandle, ref rect, ref color);
|
||||
DrawSpritePoint(spriteHandle, rect, Color.White);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,22 +820,33 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoMethodSignature* sig = mono_method_signature(method->GetNative());
|
||||
if (method->IsStatic() != signature.IsStatic ||
|
||||
/*if (method->IsStatic() != signature.IsStatic ||
|
||||
method->GetName() != signature.Name ||
|
||||
(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;
|
||||
void* sigParams = nullptr;
|
||||
mono_signature_get_params(sig, &sigParams);
|
||||
MonoType* type = mono_signature_get_params(sig, &sigParams);
|
||||
bool isValid = true;
|
||||
for (int32 paramIdx = 0; paramIdx < signature.Params.Count(); paramIdx++)
|
||||
int paramIdx = 0;
|
||||
while (type != nullptr)
|
||||
{
|
||||
auto& param = signature.Params[paramIdx];
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
type = mono_signature_get_params(sig, &sigParams);
|
||||
paramIdx++;
|
||||
}
|
||||
if (isValid && VariantTypeEquals(signature.ReturnType, mono_signature_get_return_type(sig)))
|
||||
return method;
|
||||
@@ -1187,8 +1198,6 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
|
||||
#if USE_MONO
|
||||
const auto mMethod = (MMethod*)method;
|
||||
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);
|
||||
if (paramValues.Length() != parametersCount)
|
||||
{
|
||||
@@ -1222,20 +1231,25 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
|
||||
void** params = (void**)alloca(parametersCount * sizeof(void*));
|
||||
bool failed = 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];
|
||||
const bool isOut = mono_signature_param_is_out(signature, paramIdx) != 0;
|
||||
hasOutParams |= isOut;
|
||||
|
||||
// Marshal parameter for managed method
|
||||
MType paramType(((MonoType**)signatureParams)[paramIdx]);
|
||||
MType paramType(type);
|
||||
params[paramIdx] = MUtils::VariantToManagedArgPtr(paramValue, paramType, 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);
|
||||
return true;
|
||||
}
|
||||
|
||||
type = mono_signature_get_params(signature, &sigParams);
|
||||
paramIdx++;
|
||||
}
|
||||
|
||||
// Invoke the method
|
||||
|
||||
151
Source/Engine/Scripting/DotNet/CoreCLR.cpp
Normal file
151
Source/Engine/Scripting/DotNet/CoreCLR.cpp
Normal 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, ¶ms);
|
||||
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, ¶ms, &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
|
||||
}
|
||||
49
Source/Engine/Scripting/DotNet/CoreCLR.h
Normal file
49
Source/Engine/Scripting/DotNet/CoreCLR.h
Normal 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);
|
||||
};
|
||||
1564
Source/Engine/Scripting/DotNet/MonoApi.cpp
Normal file
1564
Source/Engine/Scripting/DotNet/MonoApi.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,9 @@ extern "C" FLAXENGINE_API void mono_add_internal_call(const char* name, const vo
|
||||
|
||||
#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_EXP(expression)
|
||||
#define INTERNAL_CALL_CHECK_RETURN(obj, defaultValue)
|
||||
|
||||
@@ -6,17 +6,20 @@
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
namespace UtilsInternal
|
||||
{
|
||||
MonoObject* ExtractArrayFromList(MonoObject* obj)
|
||||
{
|
||||
#if USE_MONO
|
||||
auto klass = mono_object_get_class(obj);
|
||||
auto field = mono_class_get_field_from_name(klass, "_items");
|
||||
MonoObject* o;
|
||||
mono_field_get_value(obj, field, &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)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_LogWrite")
|
||||
StringView msg;
|
||||
MUtils::ToString(msgObj, msg);
|
||||
Log::Logger::Write(level, msg);
|
||||
@@ -31,6 +35,8 @@ namespace DebugLogHandlerInternal
|
||||
|
||||
void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_Log")
|
||||
|
||||
if (msgObj == nullptr)
|
||||
return;
|
||||
|
||||
@@ -45,8 +51,11 @@ namespace DebugLogHandlerInternal
|
||||
Log::Logger::Write(level, msg);
|
||||
}
|
||||
|
||||
|
||||
void LogException(MonoException* exception, ScriptingObject* obj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_LogException")
|
||||
#if USE_MONO
|
||||
if (exception == nullptr)
|
||||
return;
|
||||
|
||||
@@ -57,13 +66,16 @@ namespace DebugLogHandlerInternal
|
||||
// Print exception including inner exceptions
|
||||
// TODO: maybe option for build to threat warnings and errors as fatal errors?
|
||||
ex.Log(LogType::Warning, objName.GetText());
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace FlaxLogWriterInternal
|
||||
{
|
||||
void WriteStringToLog(MonoString* msgObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog")
|
||||
if (msgObj == nullptr)
|
||||
return;
|
||||
StringView msg;
|
||||
@@ -72,8 +84,6 @@ namespace FlaxLogWriterInternal
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void registerFlaxEngineInternalCalls()
|
||||
{
|
||||
AnimGraphExecutor::initRuntime();
|
||||
|
||||
@@ -86,7 +86,11 @@ struct FLAXENGINE_API ManagedDictionary
|
||||
CHECK_RETURN(makeGenericMethod, nullptr);
|
||||
|
||||
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);
|
||||
#endif
|
||||
mono_array_set(genericArgs, MonoReflectionType*, 0, mono_type_get_object(domain, keyType));
|
||||
mono_array_set(genericArgs, MonoReflectionType*, 1, mono_type_get_object(domain, valueType));
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "Engine/Platform/Thread.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#if USE_NETCORE
|
||||
#include "Engine/Scripting/DotNet/CoreCLR.h"
|
||||
#endif
|
||||
#if USE_MONO
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
@@ -52,6 +56,9 @@ MDomain* MCore::GetActiveDomain()
|
||||
|
||||
MDomain* MCore::CreateDomain(const MString& domainName)
|
||||
{
|
||||
#if USE_NETCORE
|
||||
return nullptr;
|
||||
#else
|
||||
#if USE_MONO_AOT
|
||||
LOG(Fatal, "Scripts can run only in single domain mode with AOT mode enabled.");
|
||||
return nullptr;
|
||||
@@ -74,10 +81,13 @@ MDomain* MCore::CreateDomain(const MString& domainName)
|
||||
#endif
|
||||
MDomains.Add(domain);
|
||||
return domain;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::UnloadDomain(const MString& domainName)
|
||||
{
|
||||
#if USE_NETCORE
|
||||
#else
|
||||
int32 i = 0;
|
||||
for (; i < MDomains.Count(); i++)
|
||||
{
|
||||
@@ -103,9 +113,48 @@ void MCore::UnloadDomain(const MString& domainName)
|
||||
#endif
|
||||
Delete(domain);
|
||||
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
|
||||
|
||||
@@ -518,7 +567,7 @@ bool MCore::LoadEngine()
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init Mono
|
||||
// Init managed runtime
|
||||
#if PLATFORM_ANDROID
|
||||
const char* monoVersion = "mobile";
|
||||
#else
|
||||
@@ -530,6 +579,7 @@ bool MCore::LoadEngine()
|
||||
MRootDomain->_monoDomain = monoRootDomain;
|
||||
MDomains.Add(MRootDomain);
|
||||
|
||||
#if !USE_NETCORE
|
||||
auto exePath = Platform::GetExecutableFilePath();
|
||||
auto configDir = StringUtils::GetDirectoryName(exePath).ToStringAnsi();
|
||||
auto configFilename = StringUtils::GetFileName(exePath).ToStringAnsi() + ".config";
|
||||
@@ -542,10 +592,11 @@ bool MCore::LoadEngine()
|
||||
#endif
|
||||
mono_domain_set_config(monoRootDomain, configDir.Get(), configFilename.Get());
|
||||
mono_thread_set_main(mono_thread_current());
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
return false;
|
||||
@@ -672,7 +723,7 @@ void MCore::GC::WaitForPendingFinalizers()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB
|
||||
#if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB && !USE_NETCORE
|
||||
|
||||
// Export Mono functions
|
||||
#pragma comment(linker, "/export:mono_add_internal_call")
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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>
|
||||
/// <returns>The method thunk pointer.</returns>
|
||||
void* GetThunk();
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
|
||||
#if USE_NETCORE
|
||||
#include "Engine/Scripting/DotNet/CoreCLR.h"
|
||||
#endif
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
// Inlined mono private types to access MonoType internals
|
||||
@@ -356,11 +360,17 @@ Variant MUtils::UnboxVariant(MonoObject* value)
|
||||
return Variant::Null;
|
||||
const auto& stdTypes = *StdTypesContainer::Instance();
|
||||
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);
|
||||
const MonoType* monoType = mono_class_get_type(klass);
|
||||
#endif
|
||||
|
||||
// Fast type detection for in-built types
|
||||
switch (monoType->type)
|
||||
switch (monoTypeId)
|
||||
{
|
||||
case MONO_TYPE_VOID:
|
||||
return Variant(VariantType(VariantType::Void));
|
||||
@@ -660,7 +670,11 @@ MonoObject* MUtils::BoxVariant(const Variant& value)
|
||||
case VariantType::Guid:
|
||||
return mono_value_box(mono_domain_get(), stdTypes.GuidClass->GetNative(), (void*)&value.AsData);
|
||||
case VariantType::String:
|
||||
#if USE_NETCORE
|
||||
return (MonoObject*)MUtils::ToString((StringView)value);
|
||||
#else
|
||||
return (MonoObject*)MUtils::ToString((StringView)value);
|
||||
#endif
|
||||
case VariantType::Quaternion:
|
||||
return mono_value_box(mono_domain_get(), stdTypes.QuaternionClass->GetNative(), (void*)&value.AsData);
|
||||
case VariantType::BoundingSphere:
|
||||
@@ -844,7 +858,11 @@ MonoObject* MUtils::BoxVariant(const Variant& value)
|
||||
return nullptr;
|
||||
}
|
||||
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:
|
||||
{
|
||||
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)
|
||||
{
|
||||
#if USE_NETCORE
|
||||
fullname = CoreCLR::GetClassFullname(monoClass);
|
||||
#else
|
||||
static MString plusStr("+");
|
||||
static MString dotStr(".");
|
||||
|
||||
@@ -906,6 +927,7 @@ void MUtils::GetClassFullname(MonoClass* monoClass, MString& fullname)
|
||||
}
|
||||
fullname += ']';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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:
|
||||
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);
|
||||
case MONO_TYPE_VALUETYPE:
|
||||
{
|
||||
#if !USE_NETCORE
|
||||
MonoClass* klass = type.GetNative()->data.klass;
|
||||
#else
|
||||
MonoClass* klass = mono_type_get_class(type.GetNative());
|
||||
#endif
|
||||
if (mono_class_is_enum(klass))
|
||||
{
|
||||
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)
|
||||
{
|
||||
#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"));
|
||||
Platform::MemoryCopy((byte*)obj + sizeof(MonoObject), &value, sizeof(Version));
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
Version MUtils::ToNative(MonoObject* 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));
|
||||
#endif
|
||||
return Version();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/object.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;
|
||||
|
||||
namespace MUtils
|
||||
@@ -53,6 +58,19 @@ struct MConverter
|
||||
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).
|
||||
template<typename T>
|
||||
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)
|
||||
{
|
||||
#if USE_NETCORE
|
||||
MonoString* str = MUtils::ToString(data);
|
||||
return mono_value_box(nullptr, klass, str);
|
||||
#else
|
||||
return (MonoObject*)MUtils::ToString(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
#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 MonoObject* ToManaged(const Version& value);
|
||||
extern Version ToNative(MonoObject* value);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
// ReSharper disable UnassignedReadonlyField
|
||||
// ReSharper disable InconsistentNaming
|
||||
@@ -13,13 +15,14 @@ namespace FlaxEngine
|
||||
/// Base class for all objects Flax can reference. Every object has unique identifier.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class Object
|
||||
[NativeMarshalling(typeof(ObjectMarshaller))]
|
||||
public abstract partial class Object
|
||||
{
|
||||
/// <summary>
|
||||
/// The pointer to the unmanaged object (native C++ instance).
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
protected readonly IntPtr __unmanagedPtr;
|
||||
internal readonly IntPtr __unmanagedPtr;
|
||||
|
||||
/// <summary>
|
||||
/// The object unique identifier.
|
||||
@@ -248,35 +251,35 @@ namespace FlaxEngine
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Object Internal_Create1(Type type);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Create1", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial Object Internal_Create1([MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Object Internal_Create2(string typeName);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Create2", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial Object Internal_Create2(string typeName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_ManagedInstanceCreated(Object managedInstance);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_ManagedInstanceCreated(Object managedInstance);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_Destroy(IntPtr obj, float timeLeft);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Destroy", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_Destroy(IntPtr obj, float timeLeft);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_GetTypeName(IntPtr obj);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_GetTypeName", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial string Internal_GetTypeName(IntPtr obj);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Object Internal_FindObject(ref Guid id, Type type);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_FindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial Object Internal_FindObject(ref Guid id, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Object Internal_TryFindObject(ref Guid id, Type type);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_TryFindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial Object Internal_TryFindObject(ref Guid id, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_ChangeID(IntPtr obj, ref Guid id);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ChangeID", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial void Internal_ChangeID(IntPtr obj, ref Guid id);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern IntPtr Internal_GetUnmanagedInterface(IntPtr obj, Type type);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_GetUnmanagedInterface", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
internal static partial IntPtr Internal_GetUnmanagedInterface(IntPtr obj, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ public class Scripting : EngineModule
|
||||
|
||||
if (EngineConfiguration.WithCSharp(options))
|
||||
{
|
||||
options.PublicDependencies.Add("mono");
|
||||
if (EngineConfiguration.UseDotNet)
|
||||
options.PublicDependencies.Add("nethost");
|
||||
else
|
||||
options.PublicDependencies.Add("mono");
|
||||
}
|
||||
|
||||
options.PrivateDependencies.Add("Utilities");
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace ProfilerInternal
|
||||
|
||||
void BeginEvent(MonoString* nameObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Profiler::BeginEvent")
|
||||
#if COMPILE_WITH_PROFILER
|
||||
const StringView name((const Char*)mono_string_chars(nameObj), mono_string_length(nameObj));
|
||||
ProfilerCPU::BeginEvent(*name);
|
||||
@@ -78,6 +79,7 @@ namespace ProfilerInternal
|
||||
|
||||
void EndEvent()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Profiler::EndEvent")
|
||||
#if COMPILE_WITH_PROFILER
|
||||
#if TRACY_ENABLE
|
||||
tracy::ScopedZone::End();
|
||||
@@ -88,6 +90,7 @@ namespace ProfilerInternal
|
||||
|
||||
void BeginEventGPU(MonoString* nameObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Profiler::BeginEventGPU")
|
||||
#if COMPILE_WITH_PROFILER
|
||||
const auto index = ProfilerGPU::BeginEvent((const Char*)mono_string_chars(nameObj));
|
||||
ManagedEventsGPU.Push(index);
|
||||
@@ -96,6 +99,7 @@ namespace ProfilerInternal
|
||||
|
||||
void EndEventGPU()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Profiler::EndEventGPU")
|
||||
#if COMPILE_WITH_PROFILER
|
||||
const auto index = ManagedEventsGPU.Pop();
|
||||
ProfilerGPU::EndEvent(index);
|
||||
@@ -111,16 +115,19 @@ public:
|
||||
#if USE_MONO
|
||||
static bool HasGameModulesLoaded()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Scripting::HasGameModulesLoaded")
|
||||
return Scripting::HasGameModulesLoaded();
|
||||
}
|
||||
|
||||
static bool IsTypeFromGameScripts(MonoReflectionType* type)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Scripting::IsTypeFromGameScripts")
|
||||
return Scripting::IsTypeFromGameScripts(Scripting::FindClass(MUtils::GetClass(type)));
|
||||
}
|
||||
|
||||
static void FlushRemovedObjects()
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Scripting::FlushRemovedObjects")
|
||||
ASSERT(IsInMainThread());
|
||||
ObjectsRemovalService::Flush();
|
||||
}
|
||||
|
||||
@@ -903,6 +903,7 @@ ScriptingObject* Scripting::FindObject(const MObject* managedInstance)
|
||||
|
||||
void Scripting::OnManagedInstanceDeleted(ScriptingObject* obj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_ManagedInstanceDeleted")
|
||||
PROFILE_CPU();
|
||||
ASSERT(obj);
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -65,7 +67,7 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// C# scripting service.
|
||||
/// </summary>
|
||||
public static class Scripting
|
||||
public static partial class Scripting
|
||||
{
|
||||
private static readonly List<Action> UpdateActions = new List<Action>();
|
||||
private static readonly MainThreadTaskScheduler MainThreadTaskScheduler = new MainThreadTaskScheduler();
|
||||
@@ -207,6 +209,21 @@ namespace FlaxEngine
|
||||
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()
|
||||
{
|
||||
var style = new Style
|
||||
@@ -283,21 +300,23 @@ namespace FlaxEngine
|
||||
/// Returns true if game scripts assembly has been loaded.
|
||||
/// </summary>
|
||||
/// <returns>True if game scripts assembly is loaded, otherwise false.</returns>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern bool HasGameModulesLoaded();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Scripting::HasGameModulesLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static partial bool HasGameModulesLoaded();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if given type is from one of the game scripts assemblies.
|
||||
/// </summary>
|
||||
/// <returns>True if the type is from game assembly, otherwise false.</returns>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern bool IsTypeFromGameScripts(Type type);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Scripting::IsTypeFromGameScripts", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static partial bool IsTypeFromGameScripts([MarshalUsing(typeof(SystemTypeMarshaller))] Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the removed objects (disposed objects using Object.Destroy).
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void FlushRemovedObjects();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Scripting::FlushRemovedObjects", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
public static partial void FlushRemovedObjects();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,32 +325,32 @@ namespace FlaxEngine
|
||||
/// <remarks>
|
||||
/// Profiler is available in the editor and Debug/Development builds. Release builds don't have profiling tools.
|
||||
/// </remarks>
|
||||
public static class Profiler
|
||||
public static partial class Profiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Begins profiling a piece of code with a custom label.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the event.</param>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void BeginEvent(string name);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::BeginEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
public static partial void BeginEvent(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Ends profiling an event.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void EndEvent();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::EndEvent", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
public static partial void EndEvent();
|
||||
|
||||
/// <summary>
|
||||
/// Begins GPU profiling a piece of code with a custom label.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the event.</param>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void BeginEventGPU(string name);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::BeginEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
public static partial void BeginEventGPU(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Ends GPU profiling an event.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void EndEventGPU();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Profiler::EndEventGPU", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]
|
||||
public static partial void EndEventGPU();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,13 @@ ScriptingObject* ScriptingObject::NewObject(const ScriptingTypeHandle& typeHandl
|
||||
|
||||
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
|
||||
const int32 handle = Platform::AtomicRead((int32*)&_gcHandle);
|
||||
return handle ? mono_gchandle_get_target(handle) : nullptr;
|
||||
return handle ? MUtils::GetGCHandleTarget(handle) : nullptr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
@@ -211,7 +215,7 @@ void ScriptingObject::OnManagedInstanceDeleted()
|
||||
if (_gcHandle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(_gcHandle);
|
||||
MUtils::FreeGCHandle(_gcHandle);
|
||||
#endif
|
||||
_gcHandle = 0;
|
||||
}
|
||||
@@ -236,10 +240,16 @@ bool ScriptingObject::CreateManaged()
|
||||
if (!managedInstance)
|
||||
return true;
|
||||
|
||||
// Prevent form object GC destruction
|
||||
auto handle = mono_gchandle_new(managedInstance, false);
|
||||
// Prevent from object GC destruction
|
||||
#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);
|
||||
if (*(uint32*)&oldHandle != 0)
|
||||
#endif
|
||||
{
|
||||
// Other thread already created the object before
|
||||
if (const auto monoClass = GetClass())
|
||||
@@ -252,7 +262,7 @@ bool ScriptingObject::CreateManaged()
|
||||
monoUnmanagedPtrField->SetValue(managedInstance, ¶m);
|
||||
}
|
||||
}
|
||||
mono_gchandle_free(handle);
|
||||
MUtils::FreeGCHandle(handle);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -337,7 +347,7 @@ void ScriptingObject::DestroyManaged()
|
||||
// Clear the handle
|
||||
if (_gcHandle)
|
||||
{
|
||||
mono_gchandle_free(_gcHandle);
|
||||
MUtils::FreeGCHandle(_gcHandle);
|
||||
_gcHandle = 0;
|
||||
}
|
||||
#else
|
||||
@@ -448,9 +458,15 @@ bool ManagedScriptingObject::CreateManaged()
|
||||
return true;
|
||||
|
||||
// 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);
|
||||
if (*(uint32*)&oldHandle != 0)
|
||||
#endif
|
||||
{
|
||||
// Other thread already created the object before
|
||||
if (const auto monoClass = GetClass())
|
||||
@@ -463,7 +479,7 @@ bool ManagedScriptingObject::CreateManaged()
|
||||
monoUnmanagedPtrField->SetValue(managedInstance, ¶m);
|
||||
}
|
||||
}
|
||||
mono_gchandle_free(handle);
|
||||
MUtils::FreeGCHandle(handle);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -487,6 +503,7 @@ public:
|
||||
|
||||
static MonoObject* Create1(MonoReflectionType* type)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_Create1")
|
||||
// Peek class for that type (handle generic class cases)
|
||||
if (!type)
|
||||
DebugLog::ThrowArgumentNull("type");
|
||||
@@ -550,6 +567,7 @@ public:
|
||||
|
||||
static MonoObject* Create2(MonoString* typeNameObj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_Create2")
|
||||
// Get typename
|
||||
if (typeNameObj == nullptr)
|
||||
DebugLog::ThrowArgumentNull("typeName");
|
||||
@@ -587,6 +605,7 @@ public:
|
||||
|
||||
static void ManagedInstanceCreated(MonoObject* managedInstance)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_ManagedInstanceCreated")
|
||||
MonoClass* typeClass = mono_object_get_class(managedInstance);
|
||||
|
||||
// Get the assembly with that class
|
||||
@@ -625,12 +644,20 @@ public:
|
||||
if (auto* managedScriptingObject = dynamic_cast<ManagedScriptingObject*>(obj))
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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();
|
||||
@@ -657,6 +684,7 @@ public:
|
||||
|
||||
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?)
|
||||
const bool useGameTime = timeLeft > ZeroTolerance;
|
||||
|
||||
@@ -666,12 +694,14 @@ public:
|
||||
|
||||
static MonoString* GetTypeName(ScriptingObject* obj)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_GetTypeName")
|
||||
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
|
||||
return MUtils::ToString(obj->GetType().Fullname);
|
||||
}
|
||||
|
||||
static MonoObject* FindObject(Guid* id, MonoReflectionType* type)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_FindObject")
|
||||
if (!id->IsValid())
|
||||
return nullptr;
|
||||
auto klass = MUtils::GetClass(type);
|
||||
@@ -701,6 +731,7 @@ public:
|
||||
|
||||
static MonoObject* TryFindObject(Guid* id, MonoReflectionType* type)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_TryFindObject")
|
||||
ScriptingObject* obj = Scripting::TryFindObject(*id);
|
||||
if (obj && !obj->Is(MUtils::GetClass(type)))
|
||||
obj = nullptr;
|
||||
@@ -709,12 +740,14 @@ public:
|
||||
|
||||
static void ChangeID(ScriptingObject* obj, Guid* id)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_ChangeID")
|
||||
INTERNAL_CALL_CHECK(obj);
|
||||
obj->ChangeID(*id);
|
||||
}
|
||||
|
||||
static void* GetUnmanagedInterface(ScriptingObject* obj, MonoReflectionType* type)
|
||||
{
|
||||
SCRIPTING_EXPORT("FlaxEngine.Object::Internal_GetUnmanagedInterface")
|
||||
if (obj && type)
|
||||
{
|
||||
auto typeClass = MUtils::GetClass(type);
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
uint32 _gcHandle;
|
||||
gchandle _gcHandle;
|
||||
ScriptingTypeHandle _type;
|
||||
Guid _id;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ typedef void MObject;
|
||||
#else
|
||||
|
||||
#define USE_MONO 1
|
||||
#define USE_NETCORE 0
|
||||
#define USE_NETCORE 1
|
||||
|
||||
// Enables using single (root) app domain for the user scripts
|
||||
#define USE_SCRIPTING_SINGLE_DOMAIN 1
|
||||
@@ -49,6 +49,17 @@ typedef void MObject;
|
||||
#define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE
|
||||
#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
|
||||
typedef struct _MonoClass MonoClass;
|
||||
typedef struct _MonoDomain MonoDomain;
|
||||
|
||||
@@ -37,7 +37,11 @@ namespace FlaxEngine.Json
|
||||
{
|
||||
// Skip serialization as reference id for the root object serialization (eg. Script)
|
||||
var cache = JsonSerializer.Current.Value;
|
||||
#if !USE_NETCORE
|
||||
if (cache != null && cache.IsDuringSerialization && cache.SerializerWriter.SerializeStackSize == 0)
|
||||
#else
|
||||
if (cache != null && cache.IsDuringSerialization)
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -142,6 +146,7 @@ namespace FlaxEngine.Json
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
#if !USE_NETCORE
|
||||
/// <inheritdoc />
|
||||
public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer)
|
||||
{
|
||||
@@ -170,6 +175,7 @@ namespace FlaxEngine.Json
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
|
||||
@@ -232,8 +238,10 @@ namespace FlaxEngine.Json
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite => true;
|
||||
|
||||
#if !USE_NETCORE
|
||||
/// <inheritdoc />
|
||||
public override bool CanWriteDiff => true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -11,7 +12,7 @@ using FlaxEngine.Json.JsonCustomSerializers;
|
||||
using FlaxEngine.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace FlaxEngine.Json
|
||||
{
|
||||
@@ -23,7 +24,11 @@ namespace FlaxEngine.Json
|
||||
public StringBuilder StringBuilder;
|
||||
public StringWriter StringWriter;
|
||||
public JsonTextWriter JsonWriter;
|
||||
#if !USE_NETCORE
|
||||
public JsonSerializerInternalWriter SerializerWriter;
|
||||
#else
|
||||
public /*JsonSerializerInternalWriter*/ object SerializerWriter;
|
||||
#endif
|
||||
public UnmanagedMemoryStream MemoryStream;
|
||||
public StreamReader Reader;
|
||||
public bool IsDuringSerialization;
|
||||
@@ -32,9 +37,18 @@ namespace FlaxEngine.Json
|
||||
{
|
||||
JsonSerializer = Newtonsoft.Json.JsonSerializer.CreateDefault(settings);
|
||||
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);
|
||||
StringWriter = new StringWriter(StringBuilder, CultureInfo.InvariantCulture);
|
||||
SerializerWriter = new JsonSerializerInternalWriter(JsonSerializer);
|
||||
MemoryStream = new UnmanagedMemoryStream((byte*)0, 0);
|
||||
Reader = new StreamReader(MemoryStream, Encoding.UTF8, false);
|
||||
JsonWriter = new JsonTextWriter(StringWriter)
|
||||
@@ -107,7 +121,72 @@ namespace FlaxEngine.Json
|
||||
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>
|
||||
@@ -124,7 +203,17 @@ namespace FlaxEngine.Json
|
||||
|
||||
cache.StringBuilder.Clear();
|
||||
cache.IsDuringSerialization = true;
|
||||
#if !USE_NETCORE
|
||||
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();
|
||||
}
|
||||
@@ -143,7 +232,17 @@ namespace FlaxEngine.Json
|
||||
|
||||
cache.StringBuilder.Clear();
|
||||
cache.IsDuringSerialization = true;
|
||||
#if !USE_NETCORE
|
||||
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();
|
||||
}
|
||||
@@ -157,15 +256,25 @@ namespace FlaxEngine.Json
|
||||
/// <returns>The output json string.</returns>
|
||||
public static string SerializeDiff(object obj, object other, bool isManagedOnly = false)
|
||||
{
|
||||
Type type = obj.GetType();
|
||||
var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value;
|
||||
Current.Value = cache;
|
||||
|
||||
cache.StringBuilder.Clear();
|
||||
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>
|
||||
|
||||
@@ -6,7 +6,9 @@ using System.IO;
|
||||
using System.Text;
|
||||
using FlaxEngine.GUI;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
@@ -340,10 +342,22 @@ namespace FlaxEngine
|
||||
jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling;
|
||||
jsonWriter.Culture = jsonSerializer.Culture;
|
||||
jsonWriter.DateFormatString = jsonSerializer.DateFormatString;
|
||||
|
||||
#if !USE_NETCORE
|
||||
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer);
|
||||
|
||||
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;
|
||||
@@ -380,10 +394,25 @@ namespace FlaxEngine
|
||||
jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling;
|
||||
jsonWriter.Culture = jsonSerializer.Culture;
|
||||
jsonWriter.DateFormatString = jsonSerializer.DateFormatString;
|
||||
|
||||
#if !USE_NETCORE
|
||||
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer);
|
||||
|
||||
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;
|
||||
|
||||
@@ -6,13 +6,15 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Class with helper functions.
|
||||
/// </summary>
|
||||
public static class Utils
|
||||
public static partial class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 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="destination">The destination location.</param>
|
||||
/// <param name="length">The length (amount of bytes to copy).</param>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void MemoryCopy(IntPtr destination, IntPtr source, ulong length);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::MemoryCopy")]
|
||||
public static partial void MemoryCopy(IntPtr destination, IntPtr source, ulong length);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the memory region with zeros.
|
||||
@@ -44,8 +46,8 @@ namespace FlaxEngine
|
||||
/// <remarks>Uses low-level platform impl.</remarks>
|
||||
/// <param name="dst">Destination memory address</param>
|
||||
/// <param name="size">Size of the memory to clear in bytes</param>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void MemoryClear(IntPtr dst, ulong size);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::MemoryClear")]
|
||||
public static partial void MemoryClear(IntPtr dst, ulong size);
|
||||
|
||||
/// <summary>
|
||||
/// Compares two blocks of the memory.
|
||||
@@ -54,8 +56,8 @@ namespace FlaxEngine
|
||||
/// <param name="buf1">The first buffer address.</param>
|
||||
/// <param name="buf2">The second buffer address.</param>
|
||||
/// <param name="size">Size of the memory to compare in bytes.</param>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern int MemoryCompare(IntPtr buf1, IntPtr buf2, ulong size);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::MemoryCompare")]
|
||||
public static partial int MemoryCompare(IntPtr buf1, IntPtr buf2, ulong size);
|
||||
|
||||
/// <summary>
|
||||
/// Rounds the floating point value up to 1 decimal place.
|
||||
@@ -94,7 +96,11 @@ namespace FlaxEngine
|
||||
/// <returns>The empty array object.</returns>
|
||||
public static T[] GetEmptyArray<T>()
|
||||
{
|
||||
#if USE_NETCORE
|
||||
return Array.Empty<T>();
|
||||
#else
|
||||
return Enumerable.Empty<T>() as T[];
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,10 +215,50 @@ namespace FlaxEngine
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -295,8 +341,9 @@ namespace FlaxEngine
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Array Internal_ExtractArrayFromList(object list);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Utils::Internal_ExtractArrayFromList")]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.SystemArrayMarshaller))]
|
||||
internal static partial Array Internal_ExtractArrayFromList([MarshalUsing(typeof(FlaxEngine.GCHandleMarshaller))] object list);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the color from the binary stream.
|
||||
|
||||
@@ -4,11 +4,14 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if FLAX_EDITOR
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Utilities;
|
||||
#endif
|
||||
using FlaxEngine;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace FlaxEditor.Utilities
|
||||
namespace FlaxEngine.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Editor utilities and helper functions for Variant type.
|
||||
@@ -76,6 +79,7 @@ namespace FlaxEditor.Utilities
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
internal static VariantType ToVariantType(this Type type)
|
||||
{
|
||||
VariantType variantType;
|
||||
@@ -107,7 +111,9 @@ namespace FlaxEditor.Utilities
|
||||
variantType = VariantType.Pointer;
|
||||
else if (type == typeof(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;
|
||||
else if (typeof(Asset).IsAssignableFrom(type))
|
||||
variantType = VariantType.Asset;
|
||||
@@ -1286,5 +1292,6 @@ namespace FlaxEditor.Utilities
|
||||
|
||||
stream.WriteEndObject();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
6
Source/Engine/Visject/VisjectScript.cpp
Normal file
6
Source/Engine/Visject/VisjectScript.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "VisjectScript.h"
|
||||
|
||||
VisjectScript::VisjectScript(const SpawnParams& params)
|
||||
: Script(params)
|
||||
{
|
||||
}
|
||||
14
Source/Engine/Visject/VisjectScript.h
Normal file
14
Source/Engine/Visject/VisjectScript.h
Normal 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);
|
||||
};
|
||||
9
Source/ThirdParty/nethost/FlaxEngine.CSharp.runtimeconfig.json
vendored
Normal file
9
Source/ThirdParty/nethost/FlaxEngine.CSharp.runtimeconfig.json
vendored
Normal 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
23
Source/ThirdParty/nethost/LICENSE.TXT
vendored
Normal 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.
|
||||
112
Source/ThirdParty/nethost/nethost.Build.cs
vendored
Normal file
112
Source/ThirdParty/nethost/nethost.Build.cs
vendored
Normal 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"));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BuildData = Flax.Build.Builder.BuildData;
|
||||
|
||||
namespace Flax.Build.Bindings
|
||||
@@ -171,7 +172,11 @@ namespace Flax.Build.Bindings
|
||||
|
||||
// Skip for collections
|
||||
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer" || typeInfo.Type == "Dictionary" || typeInfo.Type == "HashSet") && typeInfo.GenericArgs != null)
|
||||
#if !USE_NETCORE
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
// Skip for special types
|
||||
if (typeInfo.GenericArgs == null)
|
||||
@@ -219,6 +224,40 @@ namespace Flax.Build.Bindings
|
||||
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>
|
||||
/// Finds the API type information.
|
||||
/// </summary>
|
||||
|
||||
@@ -278,15 +278,15 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
if (typeInfo.IsObjectRef)
|
||||
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller);
|
||||
|
||||
// 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)
|
||||
#endif
|
||||
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller) + "[]";
|
||||
|
||||
// Dictionary
|
||||
@@ -361,11 +361,7 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
if (typeInfo.IsObjectRef)
|
||||
return "IntPtr";
|
||||
|
||||
// Function
|
||||
@@ -419,11 +415,7 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
if (typeInfo.IsObjectRef)
|
||||
return "FlaxEngine.Object.GetUnmanagedPtr({0})";
|
||||
|
||||
// Default
|
||||
@@ -443,8 +435,38 @@ namespace Flax.Build.Bindings
|
||||
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("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('(');
|
||||
|
||||
var separator = false;
|
||||
@@ -461,6 +483,30 @@ namespace Flax.Build.Bindings
|
||||
separator = true;
|
||||
|
||||
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)
|
||||
contents.Append("out ");
|
||||
else if (parameterInfo.IsRef || UsePassByReference(buildData, parameterInfo.Type, caller))
|
||||
@@ -484,6 +530,21 @@ namespace Flax.Build.Bindings
|
||||
separator = true;
|
||||
|
||||
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)
|
||||
contents.Append("out ");
|
||||
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)
|
||||
{
|
||||
#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)
|
||||
{
|
||||
}
|
||||
@@ -613,6 +685,9 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
// Write attribute for C++ calling code
|
||||
contents.Append(indent).AppendLine("[Unmanaged]");
|
||||
|
||||
// Skip boilerplate code when using debugger
|
||||
//contents.Append(indent).AppendLine("[System.Diagnostics.DebuggerStepThrough]");
|
||||
}
|
||||
if (isDeprecated || apiTypeInfo.IsDeprecated)
|
||||
{
|
||||
@@ -698,6 +773,15 @@ namespace Flax.Build.Bindings
|
||||
|
||||
// Class begin
|
||||
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);
|
||||
GenerateCSharpAccessLevel(contents, classInfo.Access);
|
||||
if (classInfo.IsStatic)
|
||||
@@ -862,11 +946,19 @@ namespace Flax.Build.Bindings
|
||||
contents.Append(indent).Append('}').AppendLine();
|
||||
|
||||
contents.AppendLine();
|
||||
#if !USE_NETCORE
|
||||
contents.Append(indent).Append("[MethodImpl(MethodImplOptions.InternalCall)]").AppendLine();
|
||||
contents.Append(indent).Append($"internal static extern void Internal_{eventInfo.Name}_Bind(");
|
||||
if (!eventInfo.IsStatic)
|
||||
contents.Append("IntPtr obj, ");
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -1100,6 +1192,51 @@ namespace Flax.Build.Bindings
|
||||
indent = indent.Substring(0, indent.Length - 4);
|
||||
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
|
||||
if (!string.IsNullOrEmpty(classInfo.Namespace))
|
||||
{
|
||||
@@ -1119,13 +1256,330 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine("{");
|
||||
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
|
||||
GenerateCSharpComment(contents, indent, structureInfo.Comment);
|
||||
|
||||
// Struct begin
|
||||
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, true);
|
||||
contents.Append(indent).AppendLine("[StructLayout(LayoutKind.Sequential)]");
|
||||
#if USE_NETCORE
|
||||
if (!string.IsNullOrEmpty(structNativeMarshaling))
|
||||
contents.Append(indent).AppendLine(structNativeMarshaling);
|
||||
#endif
|
||||
contents.Append(indent);
|
||||
GenerateCSharpAccessLevel(contents, structureInfo.Access);
|
||||
contents.Append("unsafe partial struct ").Append(structureInfo.Name);
|
||||
@@ -1142,6 +1596,12 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine();
|
||||
GenerateCSharpComment(contents, indent, fieldInfo.Comment);
|
||||
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);
|
||||
GenerateCSharpAccessLevel(contents, fieldInfo.Access);
|
||||
if (fieldInfo.IsConstexpr)
|
||||
@@ -1153,21 +1613,32 @@ namespace Flax.Build.Bindings
|
||||
|
||||
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;
|
||||
type = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo);
|
||||
fieldInfo.Type.IsArray = true;
|
||||
contents.Append(type).Append(' ').Append(fieldInfo.Name + "0;").AppendLine();
|
||||
for (int i = 1; i < fieldInfo.Type.ArraySize; i++)
|
||||
#if USE_NETCORE
|
||||
// Use fixed statement with primitive types of buffers
|
||||
if (type == "char")
|
||||
{
|
||||
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();
|
||||
// char's are not blittable, store as short instead
|
||||
contents.Append($"fixed short {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {type}*").AppendLine();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Padding in structs for fixed-size array
|
||||
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;
|
||||
}
|
||||
@@ -1393,6 +1864,23 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine(indent + "}");
|
||||
if (!string.IsNullOrEmpty(interfaceInfo.Namespace))
|
||||
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)
|
||||
@@ -1456,6 +1944,9 @@ namespace Flax.Build.Bindings
|
||||
CSharpUsedNamespaces.Add("System.Globalization");
|
||||
CSharpUsedNamespaces.Add("System.Runtime.CompilerServices");
|
||||
CSharpUsedNamespaces.Add("System.Runtime.InteropServices");
|
||||
#if USE_NETCORE
|
||||
CSharpUsedNamespaces.Add("System.Runtime.InteropServices.Marshalling");
|
||||
#endif
|
||||
CSharpUsedNamespaces.Add("FlaxEngine");
|
||||
|
||||
// Process all API types from the file
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user