Refactor CoreCLR runtime into explicit dotnet api instead of mocking mono api

Required by platforms that will use mono under the hood for .Net 7
New `USE_CSHARP` define for C# ability
Engine doesn't use `mono_*` apis directly but via MCore/MClass/MMethod/ apis
This commit is contained in:
Wojtek Figat
2023-03-27 17:29:42 +02:00
parent eed2cdfe04
commit 510fc443e8
111 changed files with 17048 additions and 8765 deletions

View File

@@ -391,8 +391,8 @@ namespace FlaxEditor.Content.Import
MaxSize = managed.MaxSize,
TextureGroup = managed.TextureGroup,
Size = managed.Size,
SpriteAreas = managed.SpriteAreas?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas)))) : IntPtr.Zero,
SpriteNames = managed.SpriteNames?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames)))) : IntPtr.Zero,
SpriteAreas = managed.SpriteAreas?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteAreas))) : IntPtr.Zero,
SpriteNames = managed.SpriteNames?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(NativeInterop.ManagedArrayToGCHandleArray(managed.SpriteNames))) : IntPtr.Zero,
};
}
internal static void Free(InternalOptionsNative unmanaged)

View File

@@ -134,7 +134,7 @@ namespace FlaxEditor.Content
_index = index;
type.Asset.GetMethodSignature(index, out _name, out _flags, out var returnTypeName, out var paramNames, out var paramTypeNames, out var paramOuts);
_returnType = TypeUtils.GetType(returnTypeName);
if (paramNames.Length != 0)
if (paramNames != null && paramNames.Length != 0)
{
_parameters = new ScriptMemberInfo.Parameter[paramNames.Length];
for (int i = 0; i < _parameters.Length; i++)

View File

@@ -3,9 +3,10 @@
#include "GameCooker.h"
#include "PlatformTools.h"
#include "FlaxEngine.Gen.h"
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/ManagedCLR/MTypes.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/BinaryModule.h"
@@ -29,7 +30,6 @@
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Content/JsonAsset.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Scripting/MException.h"
#if PLATFORM_TOOLS_WINDOWS
#include "Platform/Windows/WindowsPlatformTools.h"
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
@@ -596,9 +596,9 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
ASSERT(GameCookerImpl::Internal_OnCollectAssets);
}
MCore::AttachThread();
MCore::Thread::Attach();
MObject* exception = nullptr;
auto list = (MonoArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
auto list = (MArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
if (exception)
{
MException ex(exception);
@@ -632,7 +632,7 @@ bool GameCookerImpl::Build()
Steps.Add(New<PostProcessStep>());
}
MCore::AttachThread();
MCore::Thread::Attach();
// Build Started
CallEvent(GameCooker::EventType::BuildStarted);
@@ -760,7 +760,7 @@ void GameCookerService::Update()
}
MainThreadManagedInvokeAction::ParamsBuilder params;
params.AddParam(ProgressMsg, Scripting::GetScriptsDomain()->GetNative());
params.AddParam(ProgressMsg, Scripting::GetScriptsDomain());
params.AddParam(ProgressValue);
MainThreadManagedInvokeAction::Invoke(Internal_OnProgress, params);
GameCooker::OnProgress(ProgressMsg, ProgressValue);

View File

@@ -13,7 +13,6 @@
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "FlaxEngine.Gen.h"
#include <mono/metadata/reflection.h>
#define TRACK_ASSEMBLY(assembly) \
if (assembly->IsLoaded()) \
@@ -49,24 +48,24 @@ struct Entry
}
};
Dictionary<MonoType*, Entry> Cache(512);
Dictionary<MType*, Entry> Cache(512);
void OnAssemblyLoaded(MAssembly* assembly);
void OnAssemblyUnloading(MAssembly* assembly);
void OnBinaryModuleLoaded(BinaryModule* module);
MonoReflectionType* CustomEditorsUtil::GetCustomEditor(MonoReflectionType* refType)
MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
{
if (!refType)
return nullptr;
MonoType* type = mono_reflection_type_get_type(refType);
MType* type = INTERNAL_TYPE_OBJECT_GET(refType);
Entry result;
if (Cache.TryGet(type, result))
{
const auto editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
MClass* editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
if (editor)
{
return MUtils::GetType(editor->GetNative());
return MUtils::GetType(editor);
}
}
return nullptr;
@@ -123,19 +122,19 @@ void OnAssemblyLoaded(MAssembly* assembly)
continue;
const auto attribute = mclass->GetAttribute(customEditorAttribute);
if (attribute == nullptr || mono_object_get_class(attribute) != customEditorAttribute->GetNative())
if (attribute == nullptr || MCore::Object::GetClass(attribute) != customEditorAttribute)
continue;
// Check if attribute references a valid class
MonoReflectionType* refType = nullptr;
MTypeObject* refType = nullptr;
customEditorTypeField->GetValue(attribute, &refType);
if (refType == nullptr)
continue;
MonoType* type = mono_reflection_type_get_type(refType);
MType* type = INTERNAL_TYPE_OBJECT_GET(refType);
if (type == nullptr)
continue;
MonoClass* typeClass = mono_type_get_class(type);
MClass* typeClass = MCore::Type::GetClass(type);
// Check if it's a custom editor class
if (mclass->IsSubClassOf(customEditor))
@@ -152,18 +151,14 @@ void OnAssemblyLoaded(MAssembly* assembly)
entry.CustomEditor = mclass;
}
//LOG(Info, "Custom Editor {0} for type {1} (default: {2})", String(mclass->GetFullName()), String(mono_type_get_name(type)), isDefault);
//LOG(Info, "Custom Editor {0} for type {1} (default: {2})", String(mclass->GetFullName()), MCore::Type::ToString(type), isDefault);
}
else if (typeClass)
{
MClass* referencedClass = Scripting::FindClass(typeClass);
if (referencedClass)
{
auto& entry = Cache[mono_class_get_type(mclass->GetNative())];
entry.CustomEditor = referencedClass;
auto& entry = Cache[mclass->GetType()];
entry.CustomEditor = typeClass;
//LOG(Info, "Custom Editor {0} for type {1}", String(referencedClass->GetFullName()), String(mclass->GetFullName()));
}
//LOG(Info, "Custom Editor {0} for type {1}", String(typeClass->GetFullName()), String(mclass->GetFullName()));
}
}
@@ -183,21 +178,16 @@ void OnAssemblyUnloading(MAssembly* assembly)
// Remove entries with user classes
for (auto i = Cache.Begin(); i.IsNotEnd(); ++i)
{
#if USE_NETCORE
MonoClass* monoClass = mono_type_get_class(i->Key);
#else
MonoClass* monoClass = (MonoClass*)(void*)i->Key;
#endif
if (assembly->GetClass(monoClass))
MClass* mClass = MCore::Type::GetClass(i->Key);
if (mClass && mClass->GetAssembly() == assembly)
{
Cache.Remove(i);
}
else
{
if (i->Value.DefaultEditor && assembly->GetClass(i->Value.DefaultEditor->GetNative()))
if (i->Value.DefaultEditor && i->Value.DefaultEditor->GetAssembly() == assembly)
i->Value.DefaultEditor = nullptr;
if (i->Value.CustomEditor && assembly->GetClass(i->Value.CustomEditor->GetNative()))
if (i->Value.CustomEditor && i->Value.CustomEditor->GetAssembly() == assembly)
i->Value.CustomEditor = nullptr;
}
}

View File

@@ -11,7 +11,7 @@ class CustomEditorsUtil
{
public:
#if USE_MONO
static MonoReflectionType* GetCustomEditor(MonoReflectionType* refType);
#if USE_CSHARP
static MTypeObject* GetCustomEditor(MTypeObject* refType);
#endif
};

View File

@@ -9,11 +9,11 @@
#include "Engine/ContentExporters/AssetsExportingManager.h"
#include "Editor/CustomEditors/CustomEditorsUtil.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/InternalCalls.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/StdTypesContainer.h"
#include "Engine/Scripting/Internal/InternalCalls.h"
#include "Engine/Scripting/Internal/StdTypesContainer.h"
#include "Engine/Graphics/Shaders/Cache/ShaderCacheManager.h"
#include "Engine/ShadowsOfMordor/Builder.h"
#include "Engine/Physics/CollisionData.h"
@@ -47,7 +47,6 @@
#include "FlaxEngine.Gen.h"
#include "Engine/Level/Actors/AnimatedModel.h"
#include "Engine/Serialization/JsonTools.h"
#include <mono/metadata/appdomain.h>
Guid ManagedEditor::ObjectID(0x91970b4e, 0x99634f61, 0x84723632, 0x54c776af);
@@ -75,8 +74,8 @@ struct InternalTextureOptions
int32 TextureGroup;
int32 SizeX;
int32 SizeY;
MonoArray* SpriteAreas;
MonoArray* SpriteNames;
MArray* SpriteAreas;
MArray* SpriteNames;
static void Convert(InternalTextureOptions* from, ImportTexture::Options* to)
{
@@ -99,14 +98,16 @@ struct InternalTextureOptions
to->Sprites.Clear();
if (from->SpriteNames != nullptr)
{
int32 count = (int32)mono_array_length(from->SpriteNames);
ASSERT(count == (int32)mono_array_length(from->SpriteAreas));
to->Sprites.EnsureCapacity(count);
int32 count = MCore::Array::GetLength(from->SpriteNames);
ASSERT(count == MCore::Array::GetLength(from->SpriteAreas));
to->Sprites.Resize(count);
MString** spriteNamesPtr = MCore::Array::GetAddress<MString*>(from->SpriteNames);
Rectangle* spriteAreasPtr = MCore::Array::GetAddress<Rectangle>(from->SpriteAreas);
for (int32 i = 0; i < count; i++)
{
Sprite& sprite = to->Sprites.AddOne();
sprite.Area = mono_array_get(from->SpriteAreas, Rectangle, i);
sprite.Name = MUtils::ToString(mono_array_get(from->SpriteNames, MonoString*, i));
Sprite& sprite = to->Sprites[i];
sprite.Area = spriteAreasPtr[i];
sprite.Name = MUtils::ToString(spriteNamesPtr[i]);
}
}
}
@@ -131,16 +132,14 @@ struct InternalTextureOptions
to->SizeY = from->SizeY;
if (from->Sprites.HasItems())
{
const auto domain = mono_domain_get();
int32 count = from->Sprites.Count();
auto rectClass = Rectangle::TypeInitializer.GetType().ManagedClass;
ASSERT(rectClass != nullptr);
to->SpriteAreas = mono_array_new(domain, rectClass->GetNative(), count);
to->SpriteNames = mono_array_new(domain, mono_get_string_class(), count);
const int32 count = from->Sprites.Count();
to->SpriteAreas = MCore::Array::New(Rectangle::TypeInitializer.GetClass(), count);
to->SpriteNames = MCore::Array::New( MCore::TypeCache::String, count);
Rectangle* spriteAreasPtr = MCore::Array::GetAddress<Rectangle>(to->SpriteAreas);
for (int32 i = 0; i < count; i++)
{
mono_array_set(to->SpriteAreas, Rectangle, i, from->Sprites[i].Area);
mono_array_setref(to->SpriteNames, i, MUtils::ToString(from->Sprites[i].Name, domain));
spriteAreasPtr[i] = from->Sprites[i].Area;
MCore::GC::WriteArrayRef(to->SpriteNames, (MObject*)MUtils::ToString(from->Sprites[i].Name), i);
}
}
else
@@ -167,7 +166,7 @@ struct InternalModelOptions
byte ImportVertexColors;
byte ImportBlendShapes;
ModelLightmapUVsSource LightmapUVsSource;
MonoString* CollisionMeshesPrefix;
MString* CollisionMeshesPrefix;
// Transform
float Scale;
@@ -185,7 +184,7 @@ struct InternalModelOptions
byte OptimizeKeyframes;
byte ImportScaleTracks;
byte EnableRootMotion;
MonoString* RootNodeName;
MString* RootNodeName;
// Level Of Detail
byte GenerateLODs;
@@ -371,7 +370,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_IsPlayMode()
return Editor::IsPlayMode;
}
DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MonoArray** outMessages, MonoArray** outLogTypes, MonoArray** outLogTimes, int outArraySize)
DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MArray** outMessages, MArray** outLogTypes, MArray** outLogTimes, int outArraySize)
{
ScopeLock lock(CachedLogDataLocker);
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
@@ -382,6 +381,8 @@ DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MonoArray** outMessage
byte* ptr = CachedLogData.Get();
byte* end = ptr + CachedLogData.Count();
byte* outLogTypesPtr = MCore::Array::GetAddress<byte>(*outLogTypes);
int64* outLogTimesPtr = MCore::Array::GetAddress<int64>(*outLogTimes);
while (count < maxCount && ptr != end)
{
auto type = (byte)*(int32*)ptr;
@@ -398,9 +399,9 @@ DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MonoArray** outMessage
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);
MCore::GC::WriteArrayRef(*outMessages, (MObject*)msgObj, count);
outLogTypesPtr[count] = type;
outLogTimesPtr[count] = time;
count++;
}
@@ -417,7 +418,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_SetPlayMode(bool value)
Editor::IsPlayMode = value;
}
DEFINE_INTERNAL_CALL(MonoString*) EditorInternal_GetProjectPath()
DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetProjectPath()
{
return MUtils::ToString(Editor::Project->ProjectPath);
}
@@ -427,7 +428,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_CloseSplashScreen()
Editor::CloseSplashScreen();
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MonoString* dstPathObj, MonoString* srcPathObj, Guid* dstId)
DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MString* srcPathObj, Guid* dstId)
{
// Get normalized paths
String dstPath, srcPath;
@@ -456,7 +457,7 @@ enum class NewAssetType
Animation = 11,
};
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateAsset(NewAssetType type, MonoString* outputPathObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateAsset(NewAssetType type, MString* outputPathObj)
{
String tag;
switch (type)
@@ -508,7 +509,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateAsset(NewAssetType type, MonoStr
return AssetsImportingManager::Create(tag, outputPath);
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MonoString* outputPathObj, MonoString* baseTypenameObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPathObj, MString* baseTypenameObj)
{
String outputPath;
MUtils::ToString(outputPathObj, outputPath);
@@ -518,7 +519,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MonoString* outputP
return AssetsImportingManager::Create(AssetsImportingManager::CreateVisualScriptTag, outputPath, &baseTypename);
}
DEFINE_INTERNAL_CALL(MonoString*) EditorInternal_CanImport(MonoString* extensionObj)
DEFINE_INTERNAL_CALL(MString*) EditorInternal_CanImport(MString* extensionObj)
{
String extension;
MUtils::ToString(extensionObj, extension);
@@ -528,7 +529,7 @@ DEFINE_INTERNAL_CALL(MonoString*) EditorInternal_CanImport(MonoString* extension
return importer ? MUtils::ToString(importer->ResultExtension) : nullptr;
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)
DEFINE_INTERNAL_CALL(bool) EditorInternal_Import(MString* inputPathObj, MString* outputPathObj, void* arg)
{
String inputPath, outputPath;
MUtils::ToString(inputPathObj, inputPath);
@@ -538,21 +539,21 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_Import(MonoString* inputPathObj, MonoS
return AssetsImportingManager::Import(inputPath, outputPath, arg);
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_ImportTexture(MonoString* inputPathObj, MonoString* outputPathObj, InternalTextureOptions* optionsObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_ImportTexture(MString* inputPathObj, MString* outputPathObj, InternalTextureOptions* optionsObj)
{
ImportTexture::Options options;
InternalTextureOptions::Convert(optionsObj, &options);
return EditorInternal_Import(inputPathObj, outputPathObj, &options);
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_ImportModel(MonoString* inputPathObj, MonoString* outputPathObj, InternalModelOptions* optionsObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_ImportModel(MString* inputPathObj, MString* outputPathObj, InternalModelOptions* optionsObj)
{
ImportModelFile::Options options;
InternalModelOptions::Convert(optionsObj, &options);
return EditorInternal_Import(inputPathObj, outputPathObj, &options);
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_ImportAudio(MonoString* inputPathObj, MonoString* outputPathObj, InternalAudioOptions* optionsObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_ImportAudio(MString* inputPathObj, MString* outputPathObj, InternalAudioOptions* optionsObj)
{
ImportAudio::Options options;
InternalAudioOptions::Convert(optionsObj, &options);
@@ -566,27 +567,24 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetAudioClipMetadata(AudioClip* clip,
*importedSize = clip->AudioHeader.ImportedSize;
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MonoString* outputPathObj, MonoString* dataObj, MonoString* dataTypeNameObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj, MString* dataObj, MString* dataTypeNameObj)
{
String outputPath;
MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath);
const auto dataObjPtr = mono_string_to_utf8(dataObj);
StringAnsiView data(dataObjPtr);
const StringView dataObjChars = MCore::String::GetChars(dataObj);
const StringAsANSI<> data(dataObjChars.Get(), dataObjChars.Length());
const StringAnsiView dataAnsi(data.Get(), data.Length());
const StringView dataTypeNameObjChars = MCore::String::GetChars(dataTypeNameObj);
const StringAsANSI<> dataTypeName(dataTypeNameObjChars.Get(), dataTypeNameObjChars.Length());
const StringAnsiView dataTypeNameAnsi(dataTypeName.Get(), dataTypeName.Length());
const auto dataTypeNameObjPtr = mono_string_to_utf8(dataTypeNameObj);
StringAnsiView dataTypeName(dataTypeNameObjPtr);
const bool result = CreateJson::Create(outputPath, data, dataTypeName);
mono_free(dataObjPtr);
mono_free(dataTypeNameObjPtr);
return result;
return CreateJson::Create(outputPath, dataAnsi, dataTypeNameAnsi);
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MonoString* pathObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj)
{
#if COMPILE_WITH_ASSETS_EXPORTER
String path;
@@ -599,7 +597,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MonoString* pathObj)
#endif
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MonoString* inputPathObj, MonoString* outputFolderObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString* outputFolderObj)
{
#if COMPILE_WITH_ASSETS_EXPORTER
String inputPath;
@@ -630,7 +628,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_BakeLightmaps(bool cancel)
builder->Build();
}
DEFINE_INTERNAL_CALL(MonoString*) EditorInternal_GetShaderAssetSourceCode(BinaryAsset* obj)
DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAsset* obj)
{
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
if (obj->WaitForLoaded())
@@ -655,7 +653,7 @@ DEFINE_INTERNAL_CALL(MonoString*) EditorInternal_GetShaderAssetSourceCode(Binary
return str;
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MonoString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
{
#if COMPILE_WITH_PHYSICS_COOKING
CollisionCooking::Argument arg;
@@ -675,7 +673,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MonoString* pathObj,
#endif
}
DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* collisionData, MonoArray** triangles, MonoArray** indices, int* trianglesCount, int* indicesCount)
DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* collisionData, MArray** triangles, MArray** indices, int* trianglesCount, int* indicesCount)
{
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
return;
@@ -683,20 +681,18 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* colli
const auto& debugLines = collisionData->GetDebugLines();
const int32 linesCount = debugLines.Count() / 2;
mono_gc_wbarrier_generic_store(triangles, (MonoObject*)mono_array_new(mono_domain_get(), Float3::TypeInitializer.GetMonoClass(), debugLines.Count()));
mono_gc_wbarrier_generic_store(indices, (MonoObject*)mono_array_new(mono_domain_get(), mono_get_int32_class(), linesCount * 3));
MCore::GC::WriteRef(triangles, (MObject*)MCore::Array::New(Float3::TypeInitializer.GetClass(), debugLines.Count()));
MCore::GC::WriteRef(indices, (MObject*)MCore::Array::New( MCore::TypeCache::Int32, linesCount * 3));
// Use one triangle per debug line
for (int32 i = 0; i < debugLines.Count(); i++)
{
mono_array_set(*triangles, Float3, i, debugLines[i]);
}
Platform::MemoryCopy(MCore::Array::GetAddress<Float3>(*triangles), debugLines.Get(), debugLines.Count() * sizeof(Float3));
int32 iI = 0;
int32* indicesPtr = MCore::Array::GetAddress<int32>(*indices);
for (int32 i = 0; i < debugLines.Count(); i += 2)
{
mono_array_set(*indices, int32, iI++, i);
mono_array_set(*indices, int32, iI++, i + 1);
mono_array_set(*indices, int32, iI++, i);
indicesPtr[iI++] = i;
indicesPtr[iI++] = i + 1;
indicesPtr[iI++] = i;
}
*trianglesCount = debugLines.Count();
*indicesCount = linesCount * 3;
@@ -828,23 +824,23 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
struct VisualScriptLocalManaged
{
MonoString* Value;
MonoString* ValueTypeName;
MString* Value;
MString* ValueTypeName;
uint32 NodeId;
int32 BoxId;
};
DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptLocals(int* localsCount)
DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptLocals(int* localsCount)
{
MonoArray* result = nullptr;
MArray* result = nullptr;
*localsCount = 0;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack && stack->Scope)
{
const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count();
const auto mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal");
const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal");
ASSERT(mclass);
result = mono_array_new(mono_domain_get(), mclass->GetNative(), count);
result = MCore::Array::New( mclass, count);
VisualScriptLocalManaged local;
local.NodeId = MAX_uint32;
if (stack->Scope->Parameters.Length() != 0)
@@ -855,13 +851,14 @@ DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptLocals(int* local
if (s)
local.NodeId = s->Node->ID;
}
VisualScriptLocalManaged* resultPtr = MCore::Array::GetAddress<VisualScriptLocalManaged>(result);
for (int32 i = 0; i < stack->Scope->Parameters.Length(); i++)
{
auto& v = stack->Scope->Parameters[i];
local.BoxId = i + 1;
local.Value = MUtils::ToString(v.ToString());
local.ValueTypeName = MUtils::ToString(v.Type.GetTypeName());
mono_array_set(result, VisualScriptLocalManaged, i, local);
resultPtr[i] = local;
}
for (int32 i = 0; i < stack->Scope->ReturnedValues.Count(); i++)
{
@@ -870,7 +867,7 @@ DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptLocals(int* local
local.BoxId = v.BoxId;
local.Value = MUtils::ToString(v.Value.ToString());
local.ValueTypeName = MUtils::ToString(v.Value.Type.GetTypeName());
mono_array_set(result, VisualScriptLocalManaged, stack->Scope->Parameters.Length() + i, local);
resultPtr[stack->Scope->Parameters.Length() + i] = local;
}
*localsCount = count;
}
@@ -879,14 +876,14 @@ DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptLocals(int* local
struct VisualScriptStackFrameManaged
{
MonoObject* Script;
MObject* Script;
uint32 NodeId;
int32 BoxId;
};
DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptStackFrames(int* stackFramesCount)
DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptStackFrames(int* stackFramesCount)
{
MonoArray* result = nullptr;
MArray* result = nullptr;
*stackFramesCount = 0;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack)
@@ -898,9 +895,10 @@ DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptStackFrames(int*
s = s->PreviousFrame;
count++;
}
const auto mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame");
const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame");
ASSERT(mclass);
result = mono_array_new(mono_domain_get(), mclass->GetNative(), count);
result = MCore::Array::New( mclass, count);
VisualScriptStackFrameManaged* resultPtr = MCore::Array::GetAddress<VisualScriptStackFrameManaged>(result);
s = stack;
count = 0;
while (s)
@@ -909,7 +907,7 @@ DEFINE_INTERNAL_CALL(MonoArray*) EditorInternal_GetVisualScriptStackFrames(int*
frame.Script = s->Script->GetOrCreateManagedInstance();
frame.NodeId = s->Node->ID;
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
mono_array_set(result, VisualScriptStackFrameManaged, count, frame);
resultPtr[count] = frame;
s = s->PreviousFrame;
count++;
}
@@ -951,7 +949,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_EvaluateVisualScriptLocal(VisualScript
return false;
}
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MonoString* jsonObj)
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MString* jsonObj)
{
PROFILE_CPU_NAMED("DeserializeSceneObject");
@@ -1017,12 +1015,12 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_SetAnimationTime(AnimatedModel* animat
animatedModel->GraphInstance.State[0].Animation.TimePosition = time;
}
DEFINE_INTERNAL_CALL(MonoReflectionType*) CustomEditorsUtilInternal_GetCustomEditor(MonoReflectionType* targetType)
DEFINE_INTERNAL_CALL(MTypeObject*) CustomEditorsUtilInternal_GetCustomEditor(MTypeObject* targetType)
{
return CustomEditorsUtil::GetCustomEditor(targetType);
}
DEFINE_INTERNAL_CALL(bool) TextureImportEntryInternal_GetTextureImportOptions(MonoString* pathObj, InternalTextureOptions* result)
DEFINE_INTERNAL_CALL(bool) TextureImportEntryInternal_GetTextureImportOptions(MString* pathObj, InternalTextureOptions* result)
{
String path;
MUtils::ToString(pathObj, path);
@@ -1037,7 +1035,7 @@ DEFINE_INTERNAL_CALL(bool) TextureImportEntryInternal_GetTextureImportOptions(Mo
return false;
}
DEFINE_INTERNAL_CALL(void) ModelImportEntryInternal_GetModelImportOptions(MonoString* pathObj, InternalModelOptions* result)
DEFINE_INTERNAL_CALL(void) ModelImportEntryInternal_GetModelImportOptions(MString* pathObj, InternalModelOptions* result)
{
// Initialize defaults
ImportModelFile::Options options;
@@ -1056,7 +1054,7 @@ DEFINE_INTERNAL_CALL(void) ModelImportEntryInternal_GetModelImportOptions(MonoSt
InternalModelOptions::Convert(&options, result);
}
DEFINE_INTERNAL_CALL(bool) AudioImportEntryInternal_GetAudioImportOptions(MonoString* pathObj, InternalAudioOptions* result)
DEFINE_INTERNAL_CALL(bool) AudioImportEntryInternal_GetAudioImportOptions(MString* pathObj, InternalAudioOptions* result)
{
String path;
MUtils::ToString(pathObj, path);
@@ -1074,7 +1072,7 @@ DEFINE_INTERNAL_CALL(bool) AudioImportEntryInternal_GetAudioImportOptions(MonoSt
return false;
}
DEFINE_INTERNAL_CALL(MonoArray*) LayersAndTagsSettingsInternal_GetCurrentLayers(int* layersCount)
DEFINE_INTERNAL_CALL(MArray*) LayersAndTagsSettingsInternal_GetCurrentLayers(int* layersCount)
{
*layersCount = Math::Max(1, Level::GetNonEmptyLayerNamesCount());
return MUtils::ToArray(Span<String>(Level::Layers, *layersCount));

View File

@@ -3,20 +3,19 @@
#include "ManagedEditor.h"
#include "Editor/Editor.h"
#include "FlaxEngine.Gen.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/ShadowsOfMordor/Builder.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Content/Assets/VisualScript.h"
#include "Engine/CSG/CSGBuilder.h"
#include "Engine/Engine/CommandLine.h"
#include "Engine/Renderer/ProbesRenderer.h"
#include "Engine/Animations/Graph/AnimGraph.h"
#include <mono/metadata/threads.h>
ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions;
@@ -79,7 +78,7 @@ void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
ASSERT(Internal_EnvProbeBake);
}
MonoObject* probeObj = e.Actor ? e.Actor->GetManagedInstance() : nullptr;
MObject* probeObj = e.Actor ? e.Actor->GetManagedInstance() : nullptr;
MainThreadManagedInvokeAction::ParamsBuilder params;
params.AddParam(started);
@@ -107,8 +106,8 @@ void OnBrushModified(CSG::Brush* brush)
struct VisualScriptingDebugFlowInfo
{
MonoObject* Script;
MonoObject* ScriptInstance;
MObject* Script;
MObject* ScriptInstance;
uint32 NodeId;
int32 BoxId;
};
@@ -187,7 +186,7 @@ void ManagedEditor::Init()
{
LOG(Fatal, "Invalid Editor assembly! Missing initialization method.");
}
MonoObject* instance = GetOrCreateManagedInstance();
MObject* instance = GetOrCreateManagedInstance();
if (instance == nullptr)
{
LOG(Fatal, "Failed to create editor instance.");
@@ -325,7 +324,7 @@ bool ManagedEditor::CanReloadScripts()
bool ManagedEditor::CanAutoBuildCSG()
{
// Skip calls from non-managed thread (eg. physics worker)
if (!mono_domain_get() || !mono_thread_current())
if (!MCore::Thread::IsAttached())
return false;
if (!HasManagedInstance())
@@ -343,7 +342,7 @@ bool ManagedEditor::CanAutoBuildCSG()
bool ManagedEditor::CanAutoBuildNavMesh()
{
// Skip calls from non-managed thread (eg. physics worker)
if (!mono_domain_get() || !mono_thread_current())
if (!MCore::Thread::IsAttached())
return false;
if (!HasManagedInstance())

View File

@@ -15,7 +15,7 @@
#include "Engine/Platform/FileSystemWatcher.h"
#include "Engine/Platform/CreateProcessSettings.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
@@ -77,7 +77,7 @@ namespace ScriptsBuilderImpl
void onScriptsReloadEnd();
void onScriptsLoaded();
void GetClassName(const MString& fullname, MString& className);
void GetClassName(const StringAnsi& fullname, StringAnsi& className);
void onCodeEditorAsyncOpenBegin()
{
@@ -245,12 +245,12 @@ bool ScriptsBuilder::RunBuildTool(const StringView& args, const StringView& work
cmdLine.Append(TEXT("\""));
cmdLine.Append(monoPath);
cmdLine.Append(TEXT("\" "));
// TODO: Set env var for the mono MONO_GC_PARAMS=nursery-size64m to boost build performance -> profile it
#endif
cmdLine.Append(TEXT("\""));
cmdLine.Append(buildToolPath);
cmdLine.Append(TEXT("\" "));
cmdLine.Append(args.Get(), args.Length());
// TODO: Set env var for the mono MONO_GC_PARAMS=nursery-size64m to boost build performance -> profile it
// Call build tool
CreateProcessSettings procSettings;
@@ -270,7 +270,7 @@ bool ScriptsBuilder::GenerateProject(const StringView& customArgs)
return RunBuildTool(args);
}
void ScriptsBuilderImpl::GetClassName(const MString& fullname, MString& className)
void ScriptsBuilderImpl::GetClassName(const StringAnsi& fullname, StringAnsi& className)
{
const auto lastDotIndex = fullname.FindLast('.');
if (lastDotIndex != -1)
@@ -287,7 +287,7 @@ void ScriptsBuilderImpl::GetClassName(const MString& fullname, MString& classNam
MClass* ScriptsBuilder::FindScript(const StringView& scriptName)
{
PROFILE_CPU();
const MString scriptNameStd = scriptName.ToStringAnsi();
const StringAnsi scriptNameStd = scriptName.ToStringAnsi();
const ScriptingTypeHandle scriptingType = Scripting::FindScriptingType(scriptNameStd);
if (scriptingType)
@@ -301,7 +301,7 @@ MClass* ScriptsBuilder::FindScript(const StringView& scriptName)
// Check all assemblies (ignoring the typename namespace)
auto& modules = BinaryModule::GetModules();
MString className;
StringAnsi className;
GetClassName(scriptNameStd, className);
MClass* scriptClass = Script::GetStaticClass();
for (int32 j = 0; j < modules.Count(); j++)
@@ -318,7 +318,7 @@ MClass* ScriptsBuilder::FindScript(const StringView& scriptName)
// Managed scripts
if (mclass->IsSubClassOf(scriptClass) && !mclass->IsStatic() && !mclass->IsAbstract() && !mclass->IsInterface())
{
MString mclassName;
StringAnsi mclassName;
GetClassName(mclass->GetFullName(), mclassName);
if (className == mclassName)
{

View File

@@ -125,6 +125,9 @@ namespace FlaxEditor.Windows
"Used third party software:",
"",
"Mono Project - www.mono-project.com",
#if USE_NETCORE
".NET - www.dotnet.microsoft.com",
#endif
"FreeType Project - www.freetype.org",
"Assimp - www.assimp.sourceforge.net",
"DirectXMesh - Copyright (c) Microsoft Corporation. All rights reserved.",

View File

@@ -2,7 +2,7 @@
#include "AnimEvent.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedSerialization.h"
#include "Engine/Scripting/Internal/ManagedSerialization.h"
#include "Engine/Serialization/SerializationFwd.h"
#include "Engine/Serialization/Serialization.h"

View File

@@ -2,25 +2,23 @@
#include "AnimGraph.h"
#include "Engine/Debug/DebugLog.h"
#include "Engine/Scripting/InternalCalls.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Internal/InternalCalls.h"
#include "Engine/Content/Assets/SkinnedModel.h"
#if !COMPILE_WITHOUT_CSHARP
#if USE_MONO
#include <mono/metadata/appdomain.h>
#endif
#if USE_CSHARP
struct InternalInitData
{
MonoArray* Values;
MonoObject* BaseModel;
MArray* Values;
MObject* BaseModel;
};
struct InternalContext
@@ -32,8 +30,8 @@ struct InternalContext
int32 BoxId;
float DeltaTime;
uint64 CurrentFrameIndex;
MonoObject* BaseModel;
MonoObject* Instance;
MObject* BaseModel;
MObject* Instance;
};
struct InternalImpulse
@@ -57,7 +55,7 @@ DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* cont
return box->HasConnection();
}
DEFINE_INTERNAL_CALL(MonoObject*) AnimGraphInternal_GetInputValue(InternalContext* context, int32 boxId)
DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext* context, int32 boxId)
{
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
@@ -85,16 +83,14 @@ DEFINE_INTERNAL_CALL(AnimGraphImpulse*) AnimGraphInternal_GetOutputImpulseData(I
void AnimGraphExecutor::initRuntime()
{
#if USE_MONO
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_HasConnection", &AnimGraphInternal_HasConnection);
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetInputValue", &AnimGraphInternal_GetInputValue);
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData", &AnimGraphInternal_GetOutputImpulseData);
#endif
}
void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value& value)
{
#if USE_MONO
#if USE_CSHARP
auto& context = Context.Get();
if (context.ValueCache.TryGet(boxBase, value))
return;
@@ -120,7 +116,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 = MUtils::GetGCHandleTarget(data.Handle);
const auto obj = MCore::GCHandle::GetTarget(data.Handle);
if (obj == nullptr)
{
LOG(Warning, "Custom node instance is null.");
@@ -131,7 +127,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
void* params[1];
params[0] = &internalContext;
MObject* exception = nullptr;
MonoObject* result = data.Evaluate->Invoke(obj, params, &exception);
MObject* result = data.Evaluate->Invoke(obj, params, &exception);
if (exception)
{
MException ex(exception);
@@ -163,16 +159,14 @@ void AnimGraph::ClearCustomNode(Node* node)
data.Evaluate = nullptr;
if (data.Handle)
{
#if USE_MONO
MUtils::FreeGCHandle(data.Handle);
#endif
MCore::GCHandle::Free(data.Handle);
data.Handle = 0;
}
}
bool AnimGraph::InitCustomNode(Node* node)
{
#if USE_MONO
#if USE_CSHARP
// Fetch the node logic controller type
if (node->Values.Count() < 2 || node->Values[0].Type.Type != ValueType::String)
{
@@ -180,7 +174,7 @@ bool AnimGraph::InitCustomNode(Node* node)
return false;
}
const StringView typeName(node->Values[0]);
const MString typeNameStd = typeName.ToStringAnsi();
const StringAnsi typeNameStd = typeName.ToStringAnsi();
MClass* type = Scripting::FindClass(typeNameStd);
if (type == nullptr)
{
@@ -203,18 +197,15 @@ bool AnimGraph::InitCustomNode(Node* node)
}
// Create node values managed array
if (mono_domain_get() == nullptr)
Scripting::GetScriptsDomain()->Dispatch();
const auto values = mono_array_new(mono_domain_get(), mono_get_object_class(), node->Values.Count());
MCore::Thread::Attach();
MArray* values = MCore::Array::New( MCore::TypeCache::Object, node->Values.Count());
MObject** valuesPtr = MCore::Array::GetAddress<MObject*>(values);
for (int32 i = 0; i < node->Values.Count(); i++)
{
const auto v = MUtils::BoxVariant(node->Values[i]);
mono_array_set(values, MonoObject*, i, v);
}
valuesPtr[i] = MUtils::BoxVariant(node->Values[i]);
// Allocate managed node object (create GC handle to prevent destruction)
const auto obj = type->CreateInstance();
const auto handleGC = MUtils::NewGCHandle(obj, false);
MObject* obj = type->CreateInstance();
const MGCHandle handleGC = MCore::GCHandle::New(obj, false);
// Initialize node
InternalInitData initData;
@@ -226,7 +217,7 @@ bool AnimGraph::InitCustomNode(Node* node)
load->Invoke(obj, params, &exception);
if (exception)
{
MUtils::FreeGCHandle(handleGC);
MCore::GCHandle::Free(handleGC);
MException ex(exception);
ex.Log(LogType::Warning, TEXT("AnimGraph"));

View File

@@ -13,12 +13,12 @@
#include "Engine/Renderer/RenderList.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/Script.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/ManagedCLR/MProperty.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MType.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
// This could be Update, LateUpdate or FixedUpdate
#define UPDATE_POINT Update
@@ -260,7 +260,7 @@ void SceneAnimationPlayer::MapTrack(const StringView& from, const Guid& to)
void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
{
#if USE_MONO
#if USE_CSHARP
// Restore all tracks
for (int32 j = 0; j < anim->Tracks.Count(); j++)
{
@@ -364,7 +364,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexOffset, SceneAnimation* anim, float time, const SceneAnimation::Track& track, TrackInstance& state, void* target)
{
#if USE_MONO
#if USE_CSHARP
switch (track.Type)
{
case SceneAnimation::Track::Types::KeyframesProperty:
@@ -511,7 +511,7 @@ bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexO
// Return the value
StringView str(keyframesValues[leftKey], keyframesLengths[leftKey]);
*(MonoString**)target = MUtils::ToString(str);
*(MString**)target = MUtils::ToString(str);
break;
}
case SceneAnimation::Track::Types::StructProperty:
@@ -528,10 +528,10 @@ bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexO
// Cache field
if (!childTrackState.Field)
{
MType type = state.Property ? state.Property->GetType() : (state.Field ? state.Field->GetType() : MType());
MType* type = state.Property ? state.Property->GetType() : (state.Field ? state.Field->GetType() : nullptr);
if (!type)
continue;
MClass* mclass = Scripting::FindClass(mono_type_get_class(type.GetNative()));
MClass* mclass = MCore::Type::GetClass(type);
childTrackState.Field = mclass->GetField(childTrackRuntimeData->PropertyName);
if (!childTrackState.Field)
continue;
@@ -556,7 +556,7 @@ bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexO
void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset, CallStack& callStack)
{
#if USE_MONO
#if USE_CSHARP
const float fps = anim->FramesPerSecond;
#if !BUILD_RELEASE || USE_EDITOR
callStack.Add(anim);
@@ -873,7 +873,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
// Cache property or field
if (!state.Property && !state.Field)
{
MClass* mclass = Scripting::FindClass(mono_object_get_class(instance));
MClass* mclass = MCore::Object::GetClass(instance);
state.Property = mclass->GetProperty(runtimeData->PropertyName);
if (!state.Property)
{
@@ -886,9 +886,8 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
}
// Get stack memory for data value
MType valueType = state.Property ? state.Property->GetType() : state.Field->GetType();
int32 valueAlignment;
int32 valueSize = mono_type_stack_size(valueType.GetNative(), &valueAlignment);
MType* valueType = state.Property ? state.Property->GetType() : state.Field->GetType();
int32 valueSize = MCore::Type::GetSize(valueType);
_tracksDataStack.AddDefault(valueSize);
void* value = &_tracksDataStack[_tracksDataStack.Count() - valueSize];
@@ -906,10 +905,10 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
MException ex(exception);
ex.Log(LogType::Error, TEXT("Property"));
}
else if (!valueType.IsPointer())
else if (!MCore::Type::IsPointer(valueType))
{
if (boxed)
Platform::MemoryCopy(value, mono_object_unbox(boxed), valueSize);
Platform::MemoryCopy(value, MCore::Object::Unbox(boxed), valueSize);
else
Platform::MemoryClear(value, valueSize);
}
@@ -932,7 +931,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
case SceneAnimation::Track::Types::StringProperty:
{
StringView str;
MUtils::ToString(*(MonoString**)value, str);
MUtils::ToString(*(MString**)value, str);
_restoreData.Add((byte*)str.Get(), str.Length());
_restoreData.Add('\0');
break;
@@ -957,7 +956,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
if (TickPropertyTrack(j, stateIndexOffset, anim, time, track, state, value))
{
// Set the value
if (valueType.IsPointer())
if (MCore::Type::IsPointer(valueType))
value = (void*)*(intptr*)value;
if (state.Property)
{
@@ -1027,7 +1026,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
// Cache method
if (!state.Method)
{
state.Method = mono_class_get_method_from_name(mono_object_get_class(instance), runtimeData->EventName, runtimeData->EventParamsCount);
state.Method = MCore::Object::GetClass(instance)->FindMethod(runtimeData->EventName, runtimeData->EventParamsCount);
if (!state.Method)
break;
}
@@ -1035,7 +1034,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
// Invoke the method
Variant result;
MObject* exception = nullptr;
mono_runtime_invoke((MonoMethod*)state.Method, instance, paramsData, &exception);
state.Method->Invoke(instance, paramsData, &exception);
if (exception)
{
MException ex(exception);

View File

@@ -46,7 +46,7 @@ private:
MObject* ManagedObject = nullptr;
MProperty* Property = nullptr;
MField* Field = nullptr;
void* Method = nullptr;
MMethod* Method = nullptr;
int32 RestoreStateIndex = -1;
bool Warn = true;

View File

@@ -12,10 +12,7 @@
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/MainThreadTask.h"
#include "Engine/Threading/ConcurrentTaskQueue.h"
#if USE_MONO
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include <mono/metadata/mono-gc.h>
#endif
#include "Engine/Scripting/ManagedCLR/MCore.h"
AssetReferenceBase::~AssetReferenceBase()
{
@@ -270,9 +267,7 @@ void Asset::OnManagedInstanceDeleted()
// Cleanup
if (_gcHandle)
{
#if USE_MONO
MUtils::FreeGCHandle(_gcHandle);
#endif
MCore::GCHandle::Free(_gcHandle);
_gcHandle = 0;
}

View File

@@ -7,7 +7,7 @@
#include "Engine/Platform/FileSystem.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Tools/TextureTool/TextureTool.h"
REGISTER_BINARY_ASSET_WITH_UPGRADER(Texture, "FlaxEngine.Texture", TextureAssetUpgrader, true);

View File

@@ -5,14 +5,13 @@
#include "Engine/Core/Types/DataContainer.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/Events.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MType.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Serialization/MemoryWriteStream.h"
#include "Engine/Serialization/Serialization.h"
@@ -310,15 +309,15 @@ void VisualScriptExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
const StringAsANSI<100> typeNameAnsi(typeName.Get(), typeName.Length());
if (StringUtils::Compare(typeNameAnsi.Get(), obj.Type.GetTypeName()) != 0)
{
#if USE_MONO
MonoClass* klass = Scripting::FindClassNative(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
MonoClass* objKlass = MUtils::GetClass(obj);
if (!klass || !objKlass || mono_class_is_subclass_of(objKlass, klass, false) == 0)
#if USE_CSHARP
MClass* klass = Scripting::FindClass(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
MClass* objKlass = MUtils::GetClass(obj);
if (!klass || !objKlass || !objKlass->IsSubClassOf(klass))
obj = Value::Null;
#else
const ScriptingTypeHandle type = Scripting::FindScriptingType(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
const ScriptingTypeHandle objType = Scripting::FindScriptingType(obj.Type.GetTypeName());
if (!type || !objType || objType.IsSubclassOf(type))
if (!type || !objType || !objType.IsSubclassOf(type))
obj = Value::Null;
#endif
}

View File

@@ -30,7 +30,7 @@ bool CreateJson::Create(const StringView& path, rapidjson_flax::StringBuffer& da
return Create(path, data1, data2);
}
bool CreateJson::Create(const StringView& path, StringAnsiView& data, StringAnsiView& dataTypename)
bool CreateJson::Create(const StringView& path, const StringAnsiView& data, const StringAnsiView& dataTypename)
{
Guid id = Guid::New();

View File

@@ -16,7 +16,7 @@ class CreateJson
public:
static bool Create(const StringView& path, rapidjson_flax::StringBuffer& data, const String& dataTypename);
static bool Create(const StringView& path, rapidjson_flax::StringBuffer& data, const char* dataTypename);
static bool Create(const StringView& path, StringAnsiView& data, StringAnsiView& dataTypename);
static bool Create(const StringView& path, const StringAnsiView& data, const StringAnsiView& dataTypename);
static CreateAssetResult ImportPo(CreateAssetContext& context);
};

View File

@@ -17,6 +17,8 @@ protected:
int32 _length = 0;
public:
typedef T CharType;
/// <summary>
/// Finalizes an instance of the <see cref="StringBase"/> class.
/// </summary>

View File

@@ -29,6 +29,8 @@ protected:
}
public:
typedef T CharType;
/// <summary>
/// Gets the specific const character from this string.
/// </summary>

View File

@@ -23,12 +23,10 @@
#include "Engine/Scripting/ScriptingObject.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Utilities/Crc.h"
#include "Engine/Utilities/StringConverter.h"
#if USE_MONO
#include <mono/metadata/object.h>
#endif
namespace
{
@@ -108,15 +106,14 @@ VariantType::VariantType(Types type, const StringAnsiView& typeName)
}
}
VariantType::VariantType(Types type, _MonoClass* klass)
VariantType::VariantType(Types type, MClass* klass)
{
Type = type;
TypeName = nullptr;
#if USE_MONO
#if USE_CSHARP
if (klass)
{
MString typeName;
MUtils::GetClassFullname(klass, typeName);
const StringAnsi& typeName = klass->GetFullName();
const int32 length = typeName.Length();
TypeName = static_cast<char*>(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, typeName.Get(), length);
@@ -166,7 +163,7 @@ VariantType::VariantType(const StringAnsiView& typeName)
}
// Try using managed class
#if USE_MONO
#if USE_CSHARP
if (const auto mclass = Scripting::FindClass(typeName))
{
new(this) VariantType(ManagedObject, typeName);
@@ -615,21 +612,21 @@ Variant::Variant(Asset* v)
}
}
#if USE_MONO
#if USE_CSHARP
Variant::Variant(_MonoObject* v)
: Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr)
Variant::Variant(MObject* v)
: Type(VariantType::ManagedObject, v ? MCore::Object::GetClass(v) : nullptr)
{
#if USE_NETCORE
AsUint64 = v ? MUtils::NewGCHandle(v, true) : 0;
AsUint64 = v ? MCore::GCHandle::New(v, true) : 0;
#else
AsUint = v ? MUtils::NewGCHandle(v, true) : 0;
AsUint = v ? MCore::GCHandle::New(v, true) : 0;
#endif
}
#else
Variant::Variant(_MonoObject* v)
Variant::Variant(MObject* v)
: Type(VariantType::ManagedObject, nullptr)
{
AsUint = 0;
@@ -964,13 +961,12 @@ Variant::~Variant()
case VariantType::ManagedObject:
#if USE_NETCORE
if (AsUint64)
MUtils::FreeGCHandle(AsUint64);
break;
MCore::GCHandle::Free(AsUint64);
#elif USE_MONO
if (AsUint)
MUtils::FreeGCHandle(AsUint);
break;
MCore::GCHandle::Free(AsUint);
#endif
break;
default: ;
}
}
@@ -1098,9 +1094,9 @@ Variant& Variant::operator=(const Variant& other)
break;
case VariantType::ManagedObject:
#if USE_NETCORE
AsUint64 = other.AsUint64 ? MUtils::NewGCHandle(MUtils::GetGCHandleTarget(other.AsUint64), true) : 0;
AsUint64 = other.AsUint64 ? MCore::GCHandle::New(MCore::GCHandle::GetTarget(other.AsUint64), true) : 0;
#elif USE_MONO
AsUint = other.AsUint ? MUtils::NewGCHandle(MUtils::GetGCHandleTarget(other.AsUint), true) : 0;
AsUint = other.AsUint ? MCore::GCHandle::New(MCore::GCHandle::GetTarget(other.AsUint), true) : 0;
#endif
break;
case VariantType::Null:
@@ -1226,9 +1222,13 @@ bool Variant::operator==(const Variant& other) const
return false;
return AsBlob.Length == other.AsBlob.Length && StringUtils::Compare(static_cast<const char*>(AsBlob.Data), static_cast<const char*>(other.AsBlob.Data), AsBlob.Length - 1) == 0;
case VariantType::ManagedObject:
#if USE_MONO
#if USE_NETCORE
// TODO: invoke C# Equality logic?
return AsUint == other.AsUint || MUtils::GetGCHandleTarget(AsUint) == MUtils::GetGCHandleTarget(other.AsUint);
return AsUint64 == other.AsUint64 || MCore::GCHandle::GetTarget(AsUint64) == MCore::GCHandle::GetTarget(other.AsUint64);
#elif USE_MONO
return AsUint == other.AsUint || MCore::GCHandle::GetTarget(AsUint) == MCore::GCHandle::GetTarget(other.AsUint);
#else
return nullptr;
#endif
default:
return false;
@@ -1320,9 +1320,11 @@ Variant::operator bool() const
return AsAsset != nullptr;
case VariantType::ManagedObject:
#if USE_NETCORE
return AsUint64 != 0 && MUtils::GetGCHandleTarget(AsUint64) != nullptr;
return AsUint64 != 0 && MCore::GCHandle::GetTarget(AsUint64) != nullptr;
#elif USE_MONO
return AsUint != 0 && MUtils::GetGCHandleTarget(AsUint) != nullptr;
return AsUint != 0 && MCore::GCHandle::GetTarget(AsUint) != nullptr;
#else
return nullptr;
#endif
default:
return false;
@@ -1592,9 +1594,11 @@ Variant::operator void*() const
return AsBlob.Data;
case VariantType::ManagedObject:
#if USE_NETCORE
return AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
return AsUint64 ? MCore::GCHandle::GetTarget(AsUint64) : nullptr;
#elif USE_MONO
return AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
return AsUint ? MCore::GCHandle::GetTarget(AsUint) : nullptr;
#else
return nullptr;
#endif
default:
return nullptr;
@@ -1636,12 +1640,12 @@ Variant::operator ScriptingObject*() const
}
}
Variant::operator _MonoObject*() const
Variant::operator MObject*() const
{
#if USE_NETCORE
return Type.Type == VariantType::ManagedObject && AsUint64 ? MUtils::GetGCHandleTarget(AsUint64) : nullptr;
return Type.Type == VariantType::ManagedObject && AsUint64 ? MCore::GCHandle::GetTarget(AsUint64) : nullptr;
#elif USE_MONO
return Type.Type == VariantType::ManagedObject && AsUint ? MUtils::GetGCHandleTarget(AsUint) : nullptr;
return Type.Type == VariantType::ManagedObject && AsUint ? MCore::GCHandle::GetTarget(AsUint) : nullptr;
#else
return nullptr;
#endif
@@ -2356,12 +2360,10 @@ void Variant::SetType(const VariantType& type)
case VariantType::ManagedObject:
#if USE_NETCORE
if (AsUint64)
MUtils::FreeGCHandle(AsUint64);
break;
MCore::GCHandle::Free(AsUint64);
#elif USE_MONO
if (AsUint)
MUtils::FreeGCHandle(AsUint);
break;
MCore::GCHandle::Free(AsUint);
#endif
break;
default: ;
@@ -2471,12 +2473,10 @@ void Variant::SetType(VariantType&& type)
case VariantType::ManagedObject:
#if USE_NETCORE
if (AsUint64)
MUtils::FreeGCHandle(AsUint64);
break;
MCore::GCHandle::Free(AsUint64);
#elif USE_MONO
if (AsUint)
MUtils::FreeGCHandle(AsUint);
break;
MCore::GCHandle::Free(AsUint);
#endif
break;
default: ;
@@ -2652,17 +2652,17 @@ void Variant::SetObject(ScriptingObject* object)
object->Deleted.Bind<Variant, &Variant::OnObjectDeleted>(this);
}
void Variant::SetManagedObject(_MonoObject* object)
void Variant::SetManagedObject(MObject* object)
{
#if USE_MONO
#if USE_CSHARP
if (object)
{
if (Type.Type != VariantType::ManagedObject)
SetType(VariantType(VariantType::ManagedObject, mono_object_get_class(object)));
SetType(VariantType(VariantType::ManagedObject, MCore::Object::GetClass(object)));
#if USE_NETCORE
AsUint64 = MUtils::NewGCHandle(object, true);
AsUint64 = MCore::GCHandle::New(object, true);
#else
AsUint = MUtils::NewGCHandle(object, true);
AsUint = MCore::GCHandle::New(object, true);
#endif
}
else
@@ -2783,9 +2783,11 @@ String Variant::ToString() const
return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0);
case VariantType::ManagedObject:
#if USE_NETCORE
return AsUint64 ? String(MUtils::ToString(mono_object_to_string(MUtils::GetGCHandleTarget(AsUint64), nullptr))) : TEXT("null");
return AsUint64 ? String(MUtils::ToString(MCore::Object::ToString(MCore::GCHandle::GetTarget(AsUint64)))) : TEXT("null");
#elif USE_MONO
return AsUint ? String(MUtils::ToString(mono_object_to_string(MUtils::GetGCHandleTarget(AsUint), nullptr))) : TEXT("null");
return AsUint ? String(MUtils::ToString(MCore::Object::ToString(MCore::GCHandle::GetTarget(AsUint)))) : TEXT("null");
#else
return String::Empty;
#endif
default:
return String::Empty;
@@ -3688,17 +3690,17 @@ void Variant::AllocStructure()
AsBlob.Data = Allocator::Allocate(AsBlob.Length);
*((int16*)AsBlob.Data) = 0;
}
#if USE_MONO
#if USE_CSHARP
else if (const auto mclass = Scripting::FindClass(typeName))
{
// Fallback to C#-only types
MCore::AttachThread();
auto instance = mclass->CreateInstance();
MCore::Thread::Attach();
MObject* instance = mclass->CreateInstance();
if (instance)
{
#if 0
void* data = mono_object_unbox(instance);
int32 instanceSize = mono_class_instance_size(mclass->GetNative());
void* data = MCore::Object::Unbox(instance);
int32 instanceSize = mclass->GetInstanceSize();
AsBlob.Length = instanceSize - (int32)((uintptr)data - (uintptr)instance);
AsBlob.Data = Allocator::Allocate(AsBlob.Length);
Platform::MemoryCopy(AsBlob.Data, data, AsBlob.Length);
@@ -3706,9 +3708,9 @@ void Variant::AllocStructure()
Type.Type = VariantType::ManagedObject;
#if USE_NETCORE
AsUint64 = MUtils::NewGCHandle(instance, true);
AsUint64 = MCore::GCHandle::New(instance, true);
#else
AsUint = MUtils::NewGCHandle(instance, true);
AsUint = MCore::GCHandle::New(instance, true);
#endif
#endif
}
@@ -3802,9 +3804,11 @@ uint32 GetHash(const Variant& key)
return GetHash((const char*)key.AsBlob.Data);
case VariantType::ManagedObject:
#if USE_NETCORE
return key.AsUint64 ? (uint32)mono_object_hash(MUtils::GetGCHandleTarget(key.AsUint64)) : 0;
return key.AsUint64 ? (uint32)MCore::Object::GetHashCode(MCore::GCHandle::GetTarget(key.AsUint64)) : 0;
#elif USE_MONO
return key.AsUint ? (uint32)mono_object_hash(MUtils::GetGCHandleTarget(key.AsUint)) : 0;
return key.AsUint ? (uint32)MCore::Object::GetHashCode(MCore::GCHandle::GetTarget(key.AsUint)) : 0;
#else
return 0;
#endif
default:
return 0;

View File

@@ -3,10 +3,9 @@
#pragma once
#include "Engine/Core/Types/String.h"
#include "Engine/Scripting/Types.h"
class Asset;
class ScriptingObject;
struct ScriptingType;
struct Transform;
struct CommonValue;
template<typename T>
@@ -105,7 +104,7 @@ public:
explicit VariantType(Types type, const StringView& typeName);
explicit VariantType(Types type, const StringAnsiView& typeName);
explicit VariantType(Types type, struct _MonoClass* klass);
explicit VariantType(Types type, MClass* klass);
explicit VariantType(const StringAnsiView& typeName);
VariantType(const VariantType& other);
VariantType(VariantType&& other) noexcept;
@@ -215,7 +214,7 @@ public:
Variant(void* v);
Variant(ScriptingObject* v);
Variant(Asset* v);
Variant(struct _MonoObject* v);
Variant(MObject* v);
Variant(const StringView& v);
Variant(const StringAnsiView& v);
Variant(const Char* v);
@@ -296,7 +295,7 @@ public:
explicit operator StringView() const; // Returned StringView, if not empty, is guaranteed to point to a null terminated buffer.
explicit operator StringAnsiView() const; // Returned StringView, if not empty, is guaranteed to point to a null terminated buffer.
explicit operator ScriptingObject*() const;
explicit operator struct _MonoObject*() const;
explicit operator MObject*() const;
explicit operator Asset*() const;
explicit operator Float2() const;
explicit operator Float3() const;
@@ -356,7 +355,7 @@ public:
void SetBlob(int32 length);
void SetBlob(const void* data, int32 length);
void SetObject(ScriptingObject* object);
void SetManagedObject(struct _MonoObject* object);
void SetManagedObject(MObject* object);
void SetAsset(Asset* asset);
String ToString() const;

View File

@@ -3,17 +3,15 @@
#include "DebugLog.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Threading/Threading.h"
#include "FlaxEngine.Gen.h"
#if USE_MONO
#include <mono/metadata/exception.h>
#include <mono/metadata/appdomain.h>
#if USE_CSHARP
namespace Impl
{
@@ -68,19 +66,19 @@ bool CacheMethods()
void DebugLog::Log(LogType type, const StringView& message)
{
#if USE_MONO
#if USE_CSHARP
if (CacheMethods())
return;
auto scriptsDomain = Scripting::GetScriptsDomain();
MainThreadManagedInvokeAction::ParamsBuilder params;
params.AddParam(type);
params.AddParam(message, scriptsDomain->GetNative());
params.AddParam(message, scriptsDomain);
#if BUILD_RELEASE
params.AddParam(StringView::Empty, scriptsDomain->GetNative());
params.AddParam(StringView::Empty, scriptsDomain);
#else
const String stackTrace = Platform::GetStackTrace(1);
params.AddParam(stackTrace, scriptsDomain->GetNative());
params.AddParam(stackTrace, scriptsDomain);
#endif
MainThreadManagedInvokeAction::Invoke(Internal_SendLog, params);
#endif
@@ -88,7 +86,7 @@ void DebugLog::Log(LogType type, const StringView& message)
void DebugLog::LogException(MObject* exceptionObject)
{
#if USE_MONO
#if USE_CSHARP
if (exceptionObject == nullptr || CacheMethods())
return;
@@ -101,11 +99,11 @@ void DebugLog::LogException(MObject* exceptionObject)
String DebugLog::GetStackTrace()
{
String result;
#if USE_MONO
#if USE_CSHARP
if (!CacheMethods())
{
auto stackTraceObj = Internal_GetStackTrace->Invoke(nullptr, nullptr, nullptr);
MUtils::ToString((MonoString*)stackTraceObj, result);
MUtils::ToString((MString*)stackTraceObj, result);
}
#endif
return result;
@@ -113,10 +111,9 @@ String DebugLog::GetStackTrace()
void DebugLog::ThrowException(const char* msg)
{
#if USE_MONO
// Throw exception to the C# world
auto ex = mono_exception_from_name_msg(mono_get_corlib(), "System", "Exception", msg);
mono_raise_exception(ex);
#if USE_CSHARP
auto ex = MCore::Exception::Get(msg);
MCore::Exception::Throw(ex);
#endif
}
@@ -125,45 +122,40 @@ void DebugLog::ThrowNullReference()
//LOG(Warning, "Invalid null reference.");
//LOG_STR(Warning, DebugLog::GetStackTrace());
#if USE_MONO
// Throw exception to the C# world
auto ex = mono_get_exception_null_reference();
mono_raise_exception(ex);
#if USE_CSHARP
auto ex = MCore::Exception::GetNullReference();
MCore::Exception::Throw(ex);
#endif
}
void DebugLog::ThrowArgument(const char* arg, const char* msg)
{
#if USE_MONO
// Throw exception to the C# world
auto ex = mono_get_exception_argument(arg, msg);
mono_raise_exception(ex);
#if USE_CSHARP
auto ex = MCore::Exception::GetArgument(arg, msg);
MCore::Exception::Throw(ex);
#endif
}
void DebugLog::ThrowArgumentNull(const char* arg)
{
#if USE_MONO
// Throw exception to the C# world
auto ex = mono_get_exception_argument_null(arg);
mono_raise_exception(ex);
#if USE_CSHARP
auto ex = MCore::Exception::GetArgumentNull(arg);
MCore::Exception::Throw(ex);
#endif
}
void DebugLog::ThrowArgumentOutOfRange(const char* arg)
{
#if USE_MONO
// Throw exception to the C# world
auto ex = mono_get_exception_argument_out_of_range(arg);
mono_raise_exception(ex);
#if USE_CSHARP
auto ex = MCore::Exception::GetArgumentOutOfRange(arg);
MCore::Exception::Throw(ex);
#endif
}
void DebugLog::ThrowNotSupported(const char* msg)
{
#if USE_MONO
// Throw exception to the C# world
auto ex = mono_get_exception_not_supported(msg);
mono_raise_exception(ex);
#if USE_CSHARP
auto ex = MCore::Exception::GetNotSupported(msg);
MCore::Exception::Throw(ex);
#endif
}

View File

@@ -24,15 +24,15 @@ namespace Log
/// <summary>
/// Creates default exception with additional data
/// </summary>
/// <param name="message">Additional information that help describe error</param>
/// <param name="additionalInfo">Additional information that help describe error</param>
CLRInnerException(const String& additionalInfo)
: Exception(String::Format(TEXT("Current {0} CLR method has thrown an inner exception"),
#if USE_MONO
TEXT("Mono")
TEXT("Mono")
#elif USE_CORECLR
TEXT(".NET Core")
TEXT(".NET Core")
#else
TEXT("Unknown engine")
TEXT("Unknown engine")
#endif
), additionalInfo)
{

View File

@@ -39,7 +39,7 @@
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Core/Config/PlatformSettings.h"
#endif
@@ -547,7 +547,7 @@ void EngineImpl::InitPaths()
#endif
#if USE_EDITOR
Globals::EngineContentFolder = Globals::StartupFolder / TEXT("Content");
#if USE_MONO && !USE_NETCORE
#if USE_MONO
#if PLATFORM_WINDOWS
Globals::MonoPath = Globals::StartupFolder / TEXT("Source/Platforms/Editor/Windows/Mono");
#elif PLATFORM_LINUX
@@ -559,7 +559,7 @@ void EngineImpl::InitPaths()
#endif
#endif
#else
#if USE_MONO && !USE_NETCORE
#if USE_MONO
Globals::MonoPath = Globals::StartupFolder / TEXT("Mono");
#endif
#endif

View File

@@ -15,7 +15,7 @@ String Globals::EngineContentFolder;
String Globals::ProjectSourceFolder;
#endif
String Globals::ProjectContentFolder;
#if USE_MONO && !USE_NETCORE
#if USE_MONO
String Globals::MonoPath;
#endif
bool Globals::FatalErrorOccurred;

View File

@@ -49,7 +49,7 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
// Project content directory path
API_FIELD(ReadOnly) static String ProjectContentFolder;
#if USE_MONO && !USE_NETCORE
#if USE_MONO
// Mono library folder path
API_FIELD(ReadOnly) static String MonoPath;
#endif

View File

@@ -64,14 +64,6 @@ namespace FlaxEngine
internal uint setterAttributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeAttributeDefinitions
{
internal IntPtr name;
internal ManagedHandle attributeHandle;
internal ManagedHandle attributeTypeHandle;
}
[StructLayout(LayoutKind.Explicit)]
public struct VariantNative
{
@@ -245,7 +237,9 @@ namespace FlaxEngine
elementSize = Marshal.SizeOf(elementType);
}
private ManagedArray() { }
private ManagedArray()
{
}
private ManagedArray(IntPtr ptr, int length, Type elementType) => Allocate(ptr, length, elementType);
@@ -294,7 +288,9 @@ namespace FlaxEngine
private static class ArrayCast
{
delegate Array GetDelegate(Span<byte> span);
[ThreadStatic] private static Dictionary<Type, GetDelegate> delegates;
[ThreadStatic]
private static Dictionary<Type, GetDelegate> delegates;
internal static Array ToArray(Span<byte> span, Type type)
{
@@ -322,7 +318,8 @@ namespace FlaxEngine
/// </summary>
private static class ManagedArrayPool
{
[ThreadStatic] private static List<ValueTuple<bool, ManagedArray>> pool;
[ThreadStatic]
private static List<ValueTuple<bool, ManagedArray>> pool;
internal static ManagedArray Get()
{
@@ -374,7 +371,7 @@ namespace FlaxEngine
else if (str == string.Empty)
return ManagedHandle.ToIntPtr(EmptyStringHandle);
Assert.IsTrue(str.Length > 0);
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(str));
return ManagedHandle.ToIntPtr(str);
}
[System.Diagnostics.DebuggerStepThrough]
@@ -385,7 +382,7 @@ namespace FlaxEngine
else if (str == string.Empty)
return ManagedHandle.ToIntPtr(EmptyStringHandle);
Assert.IsTrue(str.Length > 0);
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(str, GCHandleType.Weak));
return ManagedHandle.ToIntPtr(str, GCHandleType.Weak);
}
[System.Diagnostics.DebuggerStepThrough]
@@ -459,6 +456,12 @@ namespace FlaxEngine
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator IntPtr(ManagedHandle value) => ToIntPtr(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IntPtr ToIntPtr(object value) => ManagedHandlePool.AllocateHandle(value, GCHandleType.Normal);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IntPtr ToIntPtr(object value, GCHandleType type) => ManagedHandlePool.AllocateHandle(value, type);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IntPtr ToIntPtr(ManagedHandle value) => value.handle;
@@ -624,14 +627,17 @@ namespace FlaxEngine
public static class NativeToManaged
{
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
public static void Free(IntPtr unmanaged)
{
// This is a permanent handle, do not release it
}
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero;
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
if (unmanaged == IntPtr.Zero)
@@ -639,14 +645,35 @@ namespace FlaxEngine
ManagedHandle.FromIntPtr(unmanaged).Free();
}
}
public struct Bidirectional
{
object managed;
IntPtr unmanaged;
public void FromManaged(object managed) { this.managed = managed; }
public IntPtr ToUnmanaged() { unmanaged = ManagedHandleMarshaller.ToNative(managed); return unmanaged; }
public void FromUnmanaged(IntPtr unmanaged) { this.unmanaged = unmanaged; }
public object ToManaged() { managed = ManagedHandleMarshaller.ToManaged(unmanaged); unmanaged = IntPtr.Zero; return managed; }
public void FromManaged(object managed)
{
this.managed = managed;
}
public IntPtr ToUnmanaged()
{
unmanaged = ManagedHandleMarshaller.ToNative(managed);
return unmanaged;
}
public void FromUnmanaged(IntPtr unmanaged)
{
this.unmanaged = unmanaged;
}
public object ToManaged()
{
managed = ManagedHandleMarshaller.ToManaged(unmanaged);
unmanaged = IntPtr.Zero;
return managed;
}
public void Free()
{
// FIXME, might be a permanent handle or a temporary one
@@ -656,10 +683,12 @@ namespace FlaxEngine
unmanaged.Free();*/
}
}
public static object ConvertToManaged(IntPtr unmanaged) => ToManaged(unmanaged);
public static IntPtr ConvertToUnmanaged(object managed) => ToNative(managed);
public static object ToManaged(IntPtr managed) => managed != IntPtr.Zero ? ManagedHandle.FromIntPtr(managed).Target : null;
public static IntPtr ToNative(object managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero;
public static IntPtr ToNative(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
if (unmanaged == IntPtr.Zero)
@@ -707,9 +736,10 @@ namespace FlaxEngine
{
public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero;
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
}
}
@@ -801,6 +831,7 @@ namespace FlaxEngine
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
public static void Free(IntPtr unmanaged) => DictionaryMarshaller<T, U>.Free(unmanaged);
}
public static class ManagedToNative
{
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed);
@@ -833,10 +864,11 @@ namespace FlaxEngine
}
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<Dictionary<T, U>>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero;
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
public static Dictionary<T, U> ToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<Dictionary<T, U>>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
public static IntPtr ToNative(Dictionary<T, U> managed) => managed != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed)) : IntPtr.Zero;
public static IntPtr ToNative(Dictionary<T, U> managed) => managed != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
if (unmanaged != IntPtr.Zero)
@@ -904,7 +936,7 @@ namespace FlaxEngine
}
numElements = managed.Length;
ManagedArray managedArray = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
var ptr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray));
var ptr = ManagedHandle.ToIntPtr(managedArray);
return (TUnmanagedElement*)ptr;
}
@@ -988,7 +1020,7 @@ namespace FlaxEngine
}
numElements = managed.Length;
ManagedArray managedArray = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
IntPtr handle = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray));
IntPtr handle = ManagedHandle.ToIntPtr(managedArray);
return (TUnmanagedElement*)handle;
}
@@ -1045,9 +1077,7 @@ namespace FlaxEngine
{
public static unsafe IntPtr ConvertToUnmanaged(string managed)
{
if (managed == null)
return IntPtr.Zero;
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managed));
return managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed);
}
public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
@@ -1091,7 +1121,7 @@ namespace FlaxEngine
/// <summary>
/// Provides a Mono-like API for native code to access managed runtime.
/// </summary>
internal unsafe static partial class NativeInterop
internal static unsafe partial class NativeInterop
{
internal static Dictionary<string, string> AssemblyLocations = new();
@@ -1164,15 +1194,21 @@ namespace FlaxEngine
}
[UnmanagedCallersOnly]
internal static void* AllocMemory(int size)
internal static void* AllocMemory(int size, bool coTaskMem)
{
return NativeMemory.AlignedAlloc((UIntPtr)size, 16);
if (coTaskMem)
return Marshal.AllocCoTaskMem(size).ToPointer();
else
return NativeMemory.AlignedAlloc((UIntPtr)size, 16);
}
[UnmanagedCallersOnly]
internal static void FreeMemory(void* ptr)
internal static void FreeMemory(void* ptr, bool coTaskMem)
{
NativeMemory.AlignedFree(ptr);
if (coTaskMem)
Marshal.FreeCoTaskMem(new IntPtr(ptr));
else
NativeMemory.AlignedFree(ptr);
}
internal static void* NativeAlloc(int byteCount)
@@ -1220,7 +1256,7 @@ namespace FlaxEngine
{
var obj = array.GetValue(i);
if (obj != null)
pointerArray.SetValue(ManagedHandle.ToIntPtr(ManagedHandle.Alloc(obj)), i);
pointerArray.SetValue(ManagedHandle.ToIntPtr(obj), i);
}
return pointerArray;
}
@@ -1320,11 +1356,18 @@ namespace FlaxEngine
return FindType(internalAssemblyQualifiedName);
}
internal class ReferenceTypePlaceholder { }
internal struct ValueTypePlaceholder { }
internal class ReferenceTypePlaceholder
{
}
internal struct ValueTypePlaceholder
{
}
internal delegate object MarshalToManagedDelegate(IntPtr nativePtr, bool byRef);
internal delegate void MarshalToNativeDelegate(object managedObject, IntPtr nativePtr);
internal delegate void MarshalToNativeFieldDelegate(FieldInfo field, object fieldOwner, IntPtr nativePtr, out int fieldOffset);
internal static ConcurrentDictionary<Type, MarshalToManagedDelegate> toManagedMarshallers = new ConcurrentDictionary<Type, MarshalToManagedDelegate>(1, 3);
@@ -1395,7 +1438,9 @@ namespace FlaxEngine
internal static class MarshalHelper<T>
{
private delegate void MarshalToNativeTypedDelegate(ref T managedValue, IntPtr nativePtr);
private delegate void MarshalToManagedTypedDelegate(ref T managedValue, IntPtr nativePtr, bool byRef);
internal delegate void MarshalFieldTypedDelegate(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset);
internal static FieldInfo[] marshallableFields;
@@ -1604,7 +1649,8 @@ namespace FlaxEngine
fieldType = typeof(byte);
if (fieldType.IsValueType && !fieldType.IsEnum && !fieldType.IsPrimitive) // Is it a structure?
{ }
{
}
else if (fieldType.IsClass || fieldType.IsPointer)
fieldAlignment = IntPtr.Size;
else
@@ -1816,7 +1862,7 @@ namespace FlaxEngine
else if (managedValue is FlaxEngine.Object flaxObj)
managedPtr = FlaxEngine.Object.GetUnmanagedPtr(flaxObj);
else
managedPtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedValue, GCHandleType.Weak));
managedPtr = ManagedHandle.ToIntPtr(managedValue, GCHandleType.Weak);
}
else if (type == typeof(Type))
managedPtr = managedValue != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle((Type)(object)managedValue)) : IntPtr.Zero;
@@ -1845,11 +1891,11 @@ namespace FlaxEngine
}
else
managedArray = ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(arr));
managedPtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray, GCHandleType.Weak));
managedPtr = ManagedHandle.ToIntPtr(managedArray, GCHandleType.Weak);
}
}
else
managedPtr = managedValue != null ? ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedValue, GCHandleType.Weak)) : IntPtr.Zero;
managedPtr = managedValue != null ? ManagedHandle.ToIntPtr(managedValue, GCHandleType.Weak) : IntPtr.Zero;
Unsafe.Write<IntPtr>(nativePtr.ToPointer(), managedPtr);
}
@@ -1859,12 +1905,14 @@ namespace FlaxEngine
{
internal Type[] parameterTypes;
internal MethodInfo method;
internal Type returnType;
private Invoker.MarshalAndInvokeDelegate invokeDelegate;
private object delegInvoke;
internal MethodHolder(MethodInfo method)
{
this.method = method;
returnType = method.ReturnType;
parameterTypes = method.GetParameterTypes();
}
@@ -1875,8 +1923,8 @@ namespace FlaxEngine
List<Type> methodTypes = new List<Type>();
if (!method.IsStatic)
methodTypes.Add(method.DeclaringType);
if (method.ReturnType != typeof(void))
methodTypes.Add(method.ReturnType);
if (returnType != typeof(void))
methodTypes.Add(returnType);
methodTypes.AddRange(parameterTypes);
List<Type> genericParamTypes = new List<Type>();
@@ -1890,7 +1938,7 @@ namespace FlaxEngine
genericParamTypes.Add(type);
}
string invokerTypeName = $"FlaxEngine.NativeInterop+Invoker+Invoker{(method.IsStatic ? "Static" : "")}{(method.ReturnType != typeof(void) ? "Ret" : "NoRet")}{parameterTypes.Length}{(genericParamTypes.Count > 0 ? "`" + genericParamTypes.Count : "")}";
string invokerTypeName = $"FlaxEngine.NativeInterop+Invoker+Invoker{(method.IsStatic ? "Static" : "")}{(returnType != typeof(void) ? "Ret" : "NoRet")}{parameterTypes.Length}{(genericParamTypes.Count > 0 ? "`" + genericParamTypes.Count : "")}";
Type invokerType = Type.GetType(invokerTypeName);
if (invokerType != null)
{
@@ -1903,7 +1951,6 @@ namespace FlaxEngine
outDeleg = invokeDelegate;
outDelegInvoke = delegInvoke;
return outDeleg != null;
}
}
@@ -1986,10 +2033,8 @@ namespace FlaxEngine
var methods = new List<MethodInfo>();
var staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
var instanceMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (MethodInfo method in staticMethods)
methods.Add(method);
foreach (MethodInfo method in instanceMethods)
methods.Add(method);
methods.AddRange(staticMethods);
methods.AddRange(instanceMethods);
var arr = (NativeMethodDefinitions*)NativeAlloc(methods.Count, Unsafe.SizeOf<NativeMethodDefinitions>());
for (int i = 0; i < methods.Count; i++)
@@ -2085,42 +2130,42 @@ namespace FlaxEngine
}
[UnmanagedCallersOnly]
internal static void GetClassAttributes(ManagedHandle typeHandle, NativeAttributeDefinitions** classAttributes, int* classAttributesCount)
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
object[] attributeValues = type.GetCustomAttributes(false);
Type[] attributeTypes = type.GetCustomAttributes(false).Select(x => x.GetType()).ToArray();
NativeAttributeDefinitions* arr = (NativeAttributeDefinitions*)NativeAlloc(attributeTypes.Length, Unsafe.SizeOf<NativeAttributeDefinitions>());
for (int i = 0; i < attributeTypes.Length; i++)
ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf<ManagedHandle>());
for (int i = 0; i < attributeValues.Length; i++)
{
IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativeAttributeDefinitions>() * i);
if (!classAttributesCacheCollectible.TryGetValue(attributeValues[i], out ManagedHandle attributeHandle))
{
attributeHandle = ManagedHandle.Alloc(attributeValues[i]);
classAttributesCacheCollectible.Add(attributeValues[i], attributeHandle);
}
ManagedHandle attributeTypeHandle = GetTypeGCHandle(attributeTypes[i]);
NativeAttributeDefinitions classAttribute = new NativeAttributeDefinitions()
{
name = NativeAllocStringAnsi(attributeTypes[i].Name),
attributeTypeHandle = attributeTypeHandle,
attributeHandle = attributeHandle,
};
Unsafe.Write(ptr.ToPointer(), classAttribute);
arr[i] = attributeHandle;
}
*classAttributes = arr;
*classAttributesCount = attributeTypes.Length;
*classAttributesCount = attributeValues.Length;
}
[UnmanagedCallersOnly]
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attribHandle)
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
Type attribType = Unsafe.As<Type>(attribHandle.Target);
object attrib = type.GetCustomAttributes(false).FirstOrDefault(x => x.GetType() == attribType);
var attributes = type.GetCustomAttributes(false);
object attrib;
if (attributeHandle.IsAllocated)
{
// Check for certain attribute type
Type attributeType = Unsafe.As<Type>(attributeHandle.Target);
attrib = attributes.FirstOrDefault(x => x.GetType() == attributeType);
}
else
{
// Check if has any attribute
attrib = attributes.FirstOrDefault();
}
if (attrib != null)
return ManagedHandle.Alloc(attrib, GCHandleType.Weak);
return new ManagedHandle();
@@ -2192,7 +2237,7 @@ namespace FlaxEngine
internal static ManagedHandle GetMethodReturnType(ManagedHandle methodHandle)
{
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
Type returnType = methodHolder.method.ReturnType;
Type returnType = methodHolder.returnType;
return GetTypeGCHandle(returnType);
}
@@ -2201,7 +2246,7 @@ namespace FlaxEngine
internal static void GetMethodParameterTypes(ManagedHandle methodHandle, IntPtr* typeHandles)
{
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
Type returnType = methodHolder.method.ReturnType;
Type returnType = methodHolder.returnType;
IntPtr arr = (IntPtr)NativeAlloc(methodHolder.parameterTypes.Length, IntPtr.Size);
for (int i = 0; i < methodHolder.parameterTypes.Length; i++)
{
@@ -2292,26 +2337,25 @@ namespace FlaxEngine
if (marshalledType.IsValueType)
{
ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, marshalledType);
return ManagedHandle.Alloc(managedArray/*, GCHandleType.Weak*/);
return ManagedHandle.Alloc(managedArray);
}
else
{
Array arr = ArrayFactory.CreateArray(type, size);
ManagedArray managedArray = ManagedArray.WrapNewArray(arr);
return ManagedHandle.Alloc(managedArray/*, GCHandleType.Weak*/);
return ManagedHandle.Alloc(managedArray);
}
}
[UnmanagedCallersOnly]
internal static unsafe IntPtr GetArrayPointerToElement(ManagedHandle arrayHandle, int size, int index)
internal static unsafe IntPtr GetArrayPointer(ManagedHandle arrayHandle)
{
if (!arrayHandle.IsAllocated)
return IntPtr.Zero;
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
if (managedArray.Length == 0)
return IntPtr.Zero;
Assert.IsTrue(index >= 0 && index < managedArray.Length);
return IntPtr.Add(managedArray.Pointer, size * index);
return managedArray.Pointer;
}
[UnmanagedCallersOnly]
@@ -2335,12 +2379,6 @@ namespace FlaxEngine
return ManagedString.ToNativeWeak(new string(new ReadOnlySpan<char>(text, length)));
}
[UnmanagedCallersOnly]
internal static IntPtr NewString(sbyte* text)
{
return ManagedString.ToNativeWeak(new string(text));
}
[UnmanagedCallersOnly]
internal static IntPtr NewStringLength(sbyte* text, int length)
{
@@ -2370,6 +2408,7 @@ namespace FlaxEngine
{
private static ConcurrentDictionary<Type, UnboxerDelegate> unboxers = new ConcurrentDictionary<Type, UnboxerDelegate>(1, 3);
private static MethodInfo unboxerMethod = typeof(ValueTypeUnboxer).GetMethod(nameof(ValueTypeUnboxer.UnboxPointer), BindingFlags.Static | BindingFlags.NonPublic);
private delegate IntPtr UnboxerDelegate(object value);
private static UnboxerDelegate UnboxerDelegateFactory(Type type)
@@ -2395,7 +2434,7 @@ namespace FlaxEngine
/// Returns the address of the boxed value type.
/// </summary>
[UnmanagedCallersOnly]
internal unsafe static IntPtr UnboxValue(ManagedHandle handle)
internal static unsafe IntPtr UnboxValue(ManagedHandle handle)
{
object value = handle.Target;
Type type = value.GetType();
@@ -2418,7 +2457,6 @@ namespace FlaxEngine
{
object obj = objectHandle.Target;
Type type = obj.GetType();
ConstructorInfo ctor = type.GetMember(".ctor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).First() as ConstructorInfo;
ctor.Invoke(obj, null);
}
@@ -2438,7 +2476,7 @@ namespace FlaxEngine
catch (Exception exception)
{
if (exceptionPtr != IntPtr.Zero)
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(exception, GCHandleType.Weak)));
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
return IntPtr.Zero;
}
return returnValue;
@@ -2468,7 +2506,7 @@ namespace FlaxEngine
realException = exception.InnerException;
if (exceptionPtr != IntPtr.Zero)
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(realException, GCHandleType.Weak)));
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
else
throw realException;
return IntPtr.Zero;
@@ -2486,7 +2524,7 @@ namespace FlaxEngine
}
// Return value
return Invoker.MarshalReturnValueGeneric(methodHolder.method.ReturnType, returnObject);
return Invoker.MarshalReturnValueGeneric(methodHolder.returnType, returnObject);
}
}
@@ -2498,7 +2536,7 @@ namespace FlaxEngine
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
// Wrap the method call, this is needed to get the object instance from ManagedHandle and to pass the exception back to native side
ThunkContext context = new ThunkContext(methodHolder.method);
ThunkContext context = new ThunkContext((MethodInfo)methodHolder.method);
Delegate methodDelegate = typeof(ThunkContext).GetMethod(nameof(ThunkContext.InvokeThunk)).CreateDelegate<InvokeThunkDelegate>(context);
IntPtr functionPtr = Marshal.GetFunctionPointerForDelegate(methodDelegate);
@@ -2533,36 +2571,12 @@ namespace FlaxEngine
}
[UnmanagedCallersOnly]
internal static void SetArrayValueReference(ManagedHandle arrayHandle, IntPtr elementPtr, IntPtr valueHandle)
internal static void SetArrayValueReference(ManagedHandle arrayHandle, IntPtr valueHandle, int index)
{
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
int index = (int)(elementPtr.ToInt64() - managedArray.Pointer.ToInt64()) / managedArray.ElementSize;
managedArray.ToSpan<IntPtr>()[index] = valueHandle;
}
[UnmanagedCallersOnly]
internal static ManagedHandle LoadAssemblyFromPath(IntPtr assemblyPath_, IntPtr* assemblyName, IntPtr* assemblyFullName)
{
if (!firstAssemblyLoaded)
{
// This assembly was already loaded when initializing the host context
firstAssemblyLoaded = true;
Assembly flaxEngineAssembly = AssemblyLoadContext.Default.Assemblies.First(x => x.GetName().Name == "FlaxEngine.CSharp");
*assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name);
*assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName);
return GetAssemblyHandle(flaxEngineAssembly);
}
string assemblyPath = Marshal.PtrToStringAnsi(assemblyPath_);
Assembly assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
return GetAssemblyHandle(assembly);
}
[UnmanagedCallersOnly]
internal static ManagedHandle LoadAssemblyImage(IntPtr data, int len, IntPtr assemblyPath_, IntPtr* assemblyName, IntPtr* assemblyFullName)
{
@@ -2680,16 +2694,6 @@ namespace FlaxEngine
DelegateHelpers.InitMethods();
}
[UnmanagedCallersOnly]
internal static ManagedHandle GetAssemblyObject(IntPtr assemblyName_)
{
string assemblyName = Marshal.PtrToStringAnsi(assemblyName_);
Assembly assembly = Utils.GetAssemblies().FirstOrDefault(x => x.FullName == assemblyName);
if (assembly == null)
return new ManagedHandle();
return ManagedHandle.Alloc(assembly);
}
[UnmanagedCallersOnly]
internal static unsafe int NativeSizeOf(ManagedHandle typeHandle, uint* align)
{
@@ -2753,6 +2757,13 @@ namespace FlaxEngine
return GetTypeGCHandle(type.BaseType);
}
[UnmanagedCallersOnly]
internal static ManagedHandle GetElementClass(ManagedHandle typeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
return GetTypeGCHandle(type.GetElementType());
}
[UnmanagedCallersOnly]
internal static byte GetMethodParameterIsOut(ManagedHandle methodHandle, int parameterNum)
{
@@ -2805,10 +2816,10 @@ namespace FlaxEngine
}
[UnmanagedCallersOnly]
internal static ManagedHandle NewGCHandleWeakref(ManagedHandle valueHandle, byte track_resurrection)
internal static ManagedHandle NewGCHandleWeak(ManagedHandle valueHandle, byte trackResurrection)
{
object value = valueHandle.Target;
ManagedHandle handle = ManagedHandle.Alloc(value, track_resurrection != 0 ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
ManagedHandle handle = ManagedHandle.Alloc(value, trackResurrection != 0 ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
return handle;
}
@@ -2818,122 +2829,125 @@ namespace FlaxEngine
valueHandle.Free();
}
internal enum MonoType
internal enum MTypes : uint
{
MONO_TYPE_END = 0x00,
MONO_TYPE_VOID = 0x01,
MONO_TYPE_BOOLEAN = 0x02,
MONO_TYPE_CHAR = 0x03,
MONO_TYPE_I1 = 0x04,
MONO_TYPE_U1 = 0x05,
MONO_TYPE_I2 = 0x06,
MONO_TYPE_U2 = 0x07,
MONO_TYPE_I4 = 0x08,
MONO_TYPE_U4 = 0x09,
MONO_TYPE_I8 = 0x0a,
MONO_TYPE_U8 = 0x0b,
MONO_TYPE_R4 = 0x0c,
MONO_TYPE_R8 = 0x0d,
MONO_TYPE_STRING = 0x0e,
MONO_TYPE_PTR = 0x0f,
MONO_TYPE_BYREF = 0x10,
MONO_TYPE_VALUETYPE = 0x11,
MONO_TYPE_CLASS = 0x12,
MONO_TYPE_VAR = 0x13,
MONO_TYPE_ARRAY = 0x14,
MONO_TYPE_GENERICINST = 0x15,
MONO_TYPE_TYPEDBYREF = 0x16,
MONO_TYPE_I = 0x18,
MONO_TYPE_U = 0x19,
MONO_TYPE_FNPTR = 0x1b,
MONO_TYPE_OBJECT = 0x1c,
MONO_TYPE_SZARRAY = 0x1d,
MONO_TYPE_MVAR = 0x1e,
MONO_TYPE_CMOD_REQD = 0x1f,
MONO_TYPE_CMOD_OPT = 0x20,
MONO_TYPE_INTERNAL = 0x21,
MONO_TYPE_MODIFIER = 0x40,
MONO_TYPE_SENTINEL = 0x41,
MONO_TYPE_PINNED = 0x45,
MONO_TYPE_ENUM = 0x55,
End = 0x00,
Void = 0x01,
Boolean = 0x02,
Char = 0x03,
I1 = 0x04,
U1 = 0x05,
I2 = 0x06,
U2 = 0x07,
I4 = 0x08,
U4 = 0x09,
I8 = 0x0a,
U8 = 0x0b,
R4 = 0x0c,
R8 = 0x0d,
String = 0x0e,
Ptr = 0x0f,
ByRef = 0x10,
ValueType = 0x11,
Class = 0x12,
Var = 0x13,
Array = 0x14,
GenericInst = 0x15,
TypeByRef = 0x16,
I = 0x18,
U = 0x19,
Fnptr = 0x1b,
Object = 0x1c,
SzArray = 0x1d,
MVar = 0x1e,
CmodReqd = 0x1f,
CmodOpt = 0x20,
Internal = 0x21,
Modifier = 0x40,
Sentinel = 0x41,
Pinned = 0x45,
Enum = 0x55,
};
[UnmanagedCallersOnly]
internal static int GetTypeMonoTypeEnum(ManagedHandle typeHandle)
internal static uint GetTypeMTypesEnum(ManagedHandle typeHandle)
{
Type type = Unsafe.As<Type>(typeHandle.Target);
MonoType monoType;
MTypes monoType;
switch (type)
{
case Type _ when type == typeof(bool):
monoType = MonoType.MONO_TYPE_BOOLEAN;
break;
case Type _ when type == typeof(sbyte):
case Type _ when type == typeof(short):
monoType = MonoType.MONO_TYPE_I2;
break;
case Type _ when type == typeof(byte):
case Type _ when type == typeof(ushort):
monoType = MonoType.MONO_TYPE_U2;
break;
case Type _ when type == typeof(int):
monoType = MonoType.MONO_TYPE_I4;
break;
case Type _ when type == typeof(uint):
monoType = MonoType.MONO_TYPE_U4;
break;
case Type _ when type == typeof(long):
monoType = MonoType.MONO_TYPE_I8;
break;
case Type _ when type == typeof(ulong):
monoType = MonoType.MONO_TYPE_U8;
break;
case Type _ when type == typeof(float):
monoType = MonoType.MONO_TYPE_R4;
break;
case Type _ when type == typeof(double):
monoType = MonoType.MONO_TYPE_R8;
break;
case Type _ when type == typeof(string):
monoType = MonoType.MONO_TYPE_STRING;
break;
case Type _ when type == typeof(IntPtr):
monoType = MonoType.MONO_TYPE_PTR;
break;
case Type _ when type.IsEnum:
{
var elementType = type.GetEnumUnderlyingType();
if (elementType == typeof(sbyte) || elementType == typeof(short))
monoType = MonoType.MONO_TYPE_I2;
else if (elementType == typeof(byte) || elementType == typeof(ushort))
monoType = MonoType.MONO_TYPE_U2;
else if (elementType == typeof(int))
monoType = MonoType.MONO_TYPE_I4;
else if (elementType == typeof(uint))
monoType = MonoType.MONO_TYPE_U4;
else if (elementType == typeof(long))
monoType = MonoType.MONO_TYPE_I8;
else if (elementType == typeof(ulong))
monoType = MonoType.MONO_TYPE_U8;
else
throw new Exception($"GetTypeMonoTypeEnum: Unsupported type '{type.FullName}'");
break;
}
case Type _ when type.IsValueType && !type.IsEnum && !type.IsPrimitive:
monoType = MonoType.MONO_TYPE_VALUETYPE;
break;
case Type _ when type.IsClass:
monoType = MonoType.MONO_TYPE_OBJECT;
break;
case Type _ when type.IsGenericType:
monoType = MonoType.MONO_TYPE_GENERICINST;
break;
default: throw new Exception($"GetTypeMonoTypeEnum: Unsupported type '{type.FullName}'");
case Type _ when type == typeof(void):
monoType = MTypes.Void;
break;
case Type _ when type == typeof(bool):
monoType = MTypes.Boolean;
break;
case Type _ when type == typeof(sbyte):
case Type _ when type == typeof(short):
monoType = MTypes.I2;
break;
case Type _ when type == typeof(byte):
case Type _ when type == typeof(ushort):
monoType = MTypes.U2;
break;
case Type _ when type == typeof(int):
monoType = MTypes.I4;
break;
case Type _ when type == typeof(uint):
monoType = MTypes.U4;
break;
case Type _ when type == typeof(long):
monoType = MTypes.I8;
break;
case Type _ when type == typeof(ulong):
monoType = MTypes.U8;
break;
case Type _ when type == typeof(float):
monoType = MTypes.R4;
break;
case Type _ when type == typeof(double):
monoType = MTypes.R8;
break;
case Type _ when type == typeof(string):
monoType = MTypes.String;
break;
case Type _ when type == typeof(IntPtr):
monoType = MTypes.Ptr;
break;
case Type _ when type.IsEnum:
{
var elementType = type.GetEnumUnderlyingType();
if (elementType == typeof(sbyte) || elementType == typeof(short))
monoType = MTypes.I2;
else if (elementType == typeof(byte) || elementType == typeof(ushort))
monoType = MTypes.U2;
else if (elementType == typeof(int))
monoType = MTypes.I4;
else if (elementType == typeof(uint))
monoType = MTypes.U4;
else if (elementType == typeof(long))
monoType = MTypes.I8;
else if (elementType == typeof(ulong))
monoType = MTypes.U8;
else
throw new Exception($"Unsupported type '{type.FullName}'");
break;
}
return (int)monoType;
case Type _ when type.IsArray:
monoType = MTypes.Array;
break;
case Type _ when type.IsValueType && !type.IsEnum && !type.IsPrimitive:
monoType = MTypes.ValueType;
break;
case Type _ when type.IsGenericType:
monoType = MTypes.GenericInst;
break;
case Type _ when type.IsClass:
monoType = MTypes.Object;
break;
default: throw new Exception($"Unsupported type '{type.FullName}'");
}
return (uint)monoType;
}
/// <summary>
@@ -2958,7 +2972,7 @@ namespace FlaxEngine
// We need private types of this assembly too, DefinedTypes contains a lot of types from other assemblies...
var types = referencedTypes.Any() ? assembly.DefinedTypes.Where(x => !referencedTypes.Contains(x.FullName)).ToArray() : assembly.DefinedTypes.ToArray();
Assert.IsTrue(Utils.GetAssemblies().Where(x => x.GetName().Name == "FlaxEngine.CSharp").Count() == 1);
Assert.IsTrue(Utils.GetAssemblies().Count(x => x.GetName().Name == "FlaxEngine.CSharp") == 1);
return types;
}
@@ -3086,7 +3100,7 @@ namespace FlaxEngine
// Returned exception is the last parameter
IntPtr exceptionPtr = nativePtrs[parameterTypes.Length];
if (exceptionPtr != IntPtr.Zero)
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(exception, GCHandleType.Weak)));
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
return IntPtr.Zero;
}
return returnValue;
@@ -3127,7 +3141,7 @@ namespace FlaxEngine
// Returned exception is the last parameter
IntPtr exceptionPtr = nativePtrs[numParams];
if (exceptionPtr != IntPtr.Zero)
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(ManagedHandle.Alloc(exception, GCHandleType.Weak)));
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
return IntPtr.Zero;
}

View File

@@ -19,6 +19,7 @@ namespace FlaxEngine
internal static class Invoker
{
internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr);
internal delegate IntPtr InvokeThunkDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs);
/// <summary>
@@ -29,6 +30,7 @@ namespace FlaxEngine
{
return (T*)ptr.ToPointer();
}
internal static MethodInfo ToPointerMethod = typeof(Invoker).GetMethod(nameof(Invoker.ToPointer), BindingFlags.Static | BindingFlags.NonPublic);
/// <summary>
@@ -43,22 +45,18 @@ namespace FlaxEngine
methodParameters = method.GetParameters().Select(x => x.ParameterType).Prepend(method.DeclaringType).ToArray();
// Pass delegate parameters by reference
Type[] delegateParameters = methodParameters.Select(x => x.IsPointer ? typeof(IntPtr) : x)
.Select(x => passParametersByRef && !x.IsByRef ? x.MakeByRefType() : x).ToArray();
Type[] delegateParameters = methodParameters.Select(x => x.IsPointer ? typeof(IntPtr) : x).Select(x => passParametersByRef && !x.IsByRef ? x.MakeByRefType() : x).ToArray();
if (!method.IsStatic && passParametersByRef)
delegateParameters[0] = method.DeclaringType;
// Convert unmanaged pointer parameters to IntPtr
ParameterExpression[] parameterExpressions = delegateParameters.Select(x => Expression.Parameter(x)).ToArray();
ParameterExpression[] parameterExpressions = delegateParameters.Select(Expression.Parameter).ToArray();
Expression[] callExpressions = new Expression[methodParameters.Length];
for (int i = 0; i < methodParameters.Length; i++)
{
Type parameterType = methodParameters[i];
if (parameterType.IsPointer)
{
callExpressions[i] =
Expression.Call(null, ToPointerMethod.MakeGenericMethod(parameterType.GetElementType()), parameterExpressions[i]);
}
callExpressions[i] = Expression.Call(null, ToPointerMethod.MakeGenericMethod(parameterType.GetElementType()), parameterExpressions[i]);
else
callExpressions[i] = parameterExpressions[i];
}
@@ -70,7 +68,7 @@ namespace FlaxEngine
else
callDelegExp = Expression.Call(parameterExpressions[0], method, callExpressions.Skip(1).ToArray());
Type delegateType = DelegateHelpers.MakeNewCustomDelegate(delegateParameters.Append(method.ReturnType).ToArray());
return Expression.Lambda(delegateType, callDelegExp, parameterExpressions.ToArray()).Compile();
return Expression.Lambda(delegateType, callDelegExp, parameterExpressions).Compile();
}
internal static IntPtr MarshalReturnValue<TRet>(ref TRet returnValue)
@@ -79,8 +77,6 @@ namespace FlaxEngine
return IntPtr.Zero;
if (typeof(TRet) == typeof(string))
return ManagedString.ToNativeWeak(Unsafe.As<string>(returnValue));
if (typeof(TRet) == typeof(IntPtr))
return (IntPtr)(object)returnValue;
if (typeof(TRet) == typeof(ManagedHandle))
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnValue);
if (typeof(TRet) == typeof(bool))
@@ -91,10 +87,10 @@ namespace FlaxEngine
{
var elementType = typeof(TRet).GetElementType();
if (ArrayFactory.GetMarshalledType(elementType) == elementType)
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnValue)), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnValue))), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnValue)), GCHandleType.Weak);
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnValue))), GCHandleType.Weak);
}
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnValue, GCHandleType.Weak));
return ManagedHandle.ToIntPtr(returnValue, GCHandleType.Weak);
}
internal static IntPtr MarshalReturnValueGeneric(Type returnType, object returnObject)
@@ -103,8 +99,6 @@ namespace FlaxEngine
return IntPtr.Zero;
if (returnType == typeof(string))
return ManagedString.ToNativeWeak(Unsafe.As<string>(returnObject));
if (returnType == typeof(IntPtr))
return (IntPtr)returnObject;
if (returnType == typeof(ManagedHandle))
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
if (returnType == typeof(bool))
@@ -112,10 +106,10 @@ namespace FlaxEngine
if (returnType == typeof(Type))
return ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As<Type>(returnObject)));
if (returnType.IsArray && ArrayFactory.GetMarshalledType(returnType.GetElementType()) == returnType.GetElementType())
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnObject)), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnObject)), GCHandleType.Weak);
if (returnType.IsArray)
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnObject))), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnObject, GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnObject))), GCHandleType.Weak);
return ManagedHandle.ToIntPtr(returnObject, GCHandleType.Weak);
}
internal static IntPtr MarshalReturnValueThunk<TRet>(ref TRet returnValue)
@@ -134,8 +128,8 @@ namespace FlaxEngine
{
var elementType = typeof(TRet).GetElementType();
if (ArrayFactory.GetMarshalledType(elementType) == elementType)
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnValue)), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnValue))), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnValue)), GCHandleType.Weak);
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnValue))), GCHandleType.Weak);
}
// Match Mono bindings and pass value as pointer to prevent boxing it
if (typeof(TRet) == typeof(System.Boolean))
@@ -152,7 +146,7 @@ namespace FlaxEngine
return (IntPtr)new UIntPtr((ulong)(System.UInt32)(object)returnValue);
if (typeof(TRet) == typeof(System.UInt64))
return (IntPtr)new UIntPtr((ulong)(System.UInt64)(object)returnValue);
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnValue, GCHandleType.Weak));
return ManagedHandle.ToIntPtr(returnValue, GCHandleType.Weak);
}
internal static IntPtr MarshalReturnValueThunkGeneric(Type returnType, object returnObject)
@@ -171,8 +165,8 @@ namespace FlaxEngine
{
var elementType = returnType.GetElementType();
if (ArrayFactory.GetMarshalledType(elementType) == elementType)
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnObject)), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnObject))), GCHandleType.Weak));
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(returnObject)), GCHandleType.Weak);
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(ManagedArrayToGCHandleArray(Unsafe.As<Array>(returnObject))), GCHandleType.Weak);
}
// Match Mono bindings and pass value as pointer to prevent boxing it
if (returnType == typeof(System.Boolean))
@@ -189,7 +183,7 @@ namespace FlaxEngine
return (IntPtr)new UIntPtr((ulong)(System.UInt32)(object)returnObject);
if (returnType == typeof(System.UInt64))
return (IntPtr)new UIntPtr((ulong)(System.UInt64)(object)returnObject);
return ManagedHandle.ToIntPtr(ManagedHandle.Alloc(returnObject, GCHandleType.Weak));
return ManagedHandle.ToIntPtr(returnObject, GCHandleType.Weak);
}
internal static class InvokerNoRet0<TInstance>

View File

@@ -11,15 +11,13 @@
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Threading/Task.h"
#include "Engine/Threading/Threading.h"
#if USE_EDITOR
#include "Engine/Renderer/GBufferPass.h"
#endif
#if USE_MONO
#include <mono/metadata/appdomain.h>
#endif
namespace
{
@@ -117,28 +115,28 @@ namespace
#if !COMPILE_WITHOUT_CSHARP
template<typename IndexType>
bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MArray* verticesObj, MArray* trianglesObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj, MArray* colorsObj)
{
ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount);
ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount);
auto vertices = (Float3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Float3), 0);
auto triangles = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
const auto normals = normalsObj ? (Float3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Float3), 0) : nullptr;
const auto tangents = tangentsObj ? (Float3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Float3), 0) : nullptr;
const auto uvs = uvObj ? (Float2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Float2), 0) : nullptr;
const auto colors = colorsObj ? (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0) : nullptr;
ASSERT((uint32)MCore::Array::GetLength(verticesObj) >= vertexCount);
ASSERT((uint32)MCore::Array::GetLength(trianglesObj) / 3 >= triangleCount);
auto vertices = MCore::Array::GetAddress<Float3>(verticesObj);
auto triangles = MCore::Array::GetAddress<IndexType>(trianglesObj);
const auto normals = normalsObj ? MCore::Array::GetAddress<Float3>(normalsObj) : nullptr;
const auto tangents = tangentsObj ? MCore::Array::GetAddress<Float3>(tangentsObj) : nullptr;
const auto uvs = uvObj ? MCore::Array::GetAddress<Float2>(uvObj) : nullptr;
const auto colors = colorsObj ? MCore::Array::GetAddress<Color32>(colorsObj) : nullptr;
return UpdateMesh<IndexType>(mesh, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
}
template<typename IndexType>
bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj)
bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MArray* trianglesObj)
{
const auto model = mesh->GetModel();
ASSERT(model && model->IsVirtual() && trianglesObj);
// Get buffer data
ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount);
auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
ASSERT(MCore::Array::GetLength(trianglesObj) / 3 >= triangleCount);
auto ib = MCore::Array::GetAddress<IndexType>(trianglesObj);
return mesh->UpdateTriangles(triangleCount, ib);
}
@@ -717,22 +715,22 @@ ScriptingObject* Mesh::GetParentModel()
#if !COMPILE_WITHOUT_CSHARP
bool Mesh::UpdateMeshUInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
bool Mesh::UpdateMeshUInt(int32 vertexCount, int32 triangleCount, MArray* verticesObj, MArray* trianglesObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj, MArray* colorsObj)
{
return ::UpdateMesh<uint32>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
}
bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MArray* verticesObj, MArray* trianglesObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj, MArray* colorsObj)
{
return ::UpdateMesh<uint16>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
}
bool Mesh::UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj)
bool Mesh::UpdateTrianglesUInt(int32 triangleCount, MArray* trianglesObj)
{
return ::UpdateTriangles<uint32>(this, triangleCount, trianglesObj);
}
bool Mesh::UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj)
bool Mesh::UpdateTrianglesUShort(int32 triangleCount, MArray* trianglesObj)
{
return ::UpdateTriangles<uint16>(this, triangleCount, trianglesObj);
}
@@ -746,7 +744,7 @@ enum class InternalBufferType
IB32 = 4,
};
MonoArray* Mesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
MArray* Mesh::DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI)
{
auto mesh = this;
auto type = (InternalBufferType)typeI;
@@ -824,8 +822,8 @@ MonoArray* Mesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, i
}
// Convert into managed array
MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
MArray* result = MCore::Array::New(MCore::Type::GetClass(INTERNAL_TYPE_OBJECT_GET(resultType)), dataCount);
void* managedArrayPtr = MCore::Array::GetAddress(result);
const int32 elementSize = data.Length() / dataCount;
switch (type)
{

View File

@@ -317,10 +317,10 @@ private:
// Internal bindings
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
#if !COMPILE_WITHOUT_CSHARP
API_FUNCTION(NoProxy) bool UpdateMeshUInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
API_FUNCTION(NoProxy) bool UpdateMeshUInt(int32 vertexCount, int32 triangleCount, MArray* verticesObj, MArray* trianglesObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj, MArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MArray* verticesObj, MArray* trianglesObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj, MArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MArray* trianglesObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MArray* trianglesObj);
API_FUNCTION(NoProxy) MArray* DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI);
#endif
};

View File

@@ -12,11 +12,9 @@
#include "Engine/Renderer/RenderList.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Threading/Task.h"
#include "Engine/Threading/Threading.h"
#if USE_MONO
#include <mono/metadata/appdomain.h>
#endif
void SkinnedMesh::Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere)
{
@@ -398,18 +396,18 @@ ScriptingObject* SkinnedMesh::GetParentModel()
#if !COMPILE_WITHOUT_CSHARP
template<typename IndexType>
bool UpdateMesh(SkinnedMesh* mesh, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj)
bool UpdateMesh(SkinnedMesh* mesh, MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj)
{
auto model = mesh->GetSkinnedModel();
ASSERT(model && model->IsVirtual() && verticesObj && trianglesObj && blendIndicesObj && blendWeightsObj);
// Get buffers data
const auto vertexCount = (uint32)mono_array_length(verticesObj);
const auto triangleCount = (uint32)mono_array_length(trianglesObj) / 3;
auto vertices = (Float3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Float3), 0);
auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(int32), 0);
auto blendIndices = (Int4*)(void*)mono_array_addr_with_size(blendIndicesObj, sizeof(Int4), 0);
auto blendWeights = (Float4*)(void*)mono_array_addr_with_size(blendWeightsObj, sizeof(Float4), 0);
const auto vertexCount = (uint32)MCore::Array::GetLength(verticesObj);
const auto triangleCount = (uint32)MCore::Array::GetLength(trianglesObj) / 3;
auto vertices = MCore::Array::GetAddress<Float3>(verticesObj);
auto ib = MCore::Array::GetAddress<IndexType>(trianglesObj);
auto blendIndices = MCore::Array::GetAddress<Int4>(blendIndicesObj);
auto blendWeights = MCore::Array::GetAddress<Float4>(blendWeightsObj);
Array<VB0SkinnedElementType> vb;
vb.Resize(vertexCount);
for (uint32 i = 0; i < vertexCount; i++)
@@ -418,10 +416,10 @@ bool UpdateMesh(SkinnedMesh* mesh, MonoArray* verticesObj, MonoArray* trianglesO
}
if (normalsObj)
{
const auto normals = (Float3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Float3), 0);
const auto normals = MCore::Array::GetAddress<Float3>(normalsObj);
if (tangentsObj)
{
const auto tangents = (Float3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Float3), 0);
const auto tangents = MCore::Array::GetAddress<Float3>(tangentsObj);
for (uint32 i = 0; i < vertexCount; i++)
{
// Peek normal and tangent
@@ -475,7 +473,7 @@ bool UpdateMesh(SkinnedMesh* mesh, MonoArray* verticesObj, MonoArray* trianglesO
}
if (uvObj)
{
const auto uvs = (Float2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Float2), 0);
const auto uvs = MCore::Array::GetAddress<Float2>(uvObj);
for (uint32 i = 0; i < vertexCount; i++)
vb[i].TexCoord = Half2(uvs[i]);
}
@@ -499,12 +497,12 @@ bool UpdateMesh(SkinnedMesh* mesh, MonoArray* verticesObj, MonoArray* trianglesO
return mesh->UpdateMesh(vertexCount, triangleCount, vb.Get(), ib);
}
bool SkinnedMesh::UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj)
bool SkinnedMesh::UpdateMeshUInt(MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj)
{
return ::UpdateMesh<uint32>(this, verticesObj, trianglesObj, blendIndicesObj, blendWeightsObj, normalsObj, tangentsObj, uvObj);
}
bool SkinnedMesh::UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj)
bool SkinnedMesh::UpdateMeshUShort(MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj)
{
return ::UpdateMesh<uint16>(this, verticesObj, trianglesObj, blendIndicesObj, blendWeightsObj, normalsObj, tangentsObj, uvObj);
}
@@ -516,7 +514,7 @@ enum class InternalBufferType
IB32 = 4,
};
MonoArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
MArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI)
{
SkinnedMesh* mesh = this;
InternalBufferType type = (InternalBufferType)typeI;
@@ -582,8 +580,8 @@ MonoArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MonoReflectionType* result
}
// Convert into managed array
MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
MArray* result = MCore::Array::New(MCore::Type::GetClass(INTERNAL_TYPE_OBJECT_GET(resultType)), dataCount);
void* managedArrayPtr = MCore::Array::GetAddress(result);
const int32 elementSize = data.Length() / dataCount;
switch (type)
{

View File

@@ -197,8 +197,8 @@ private:
// Internal bindings
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
#if !COMPILE_WITHOUT_CSHARP
API_FUNCTION(NoProxy) bool UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
API_FUNCTION(NoProxy) bool UpdateMeshUInt(MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj);
API_FUNCTION(NoProxy) MArray* DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI);
#endif
};

View File

@@ -4,9 +4,7 @@
#include "Engine/Serialization/Serialization.h"
#include "Engine/Animations/CurveSerialization.h"
#include "Engine/Core/Math/Matrix.h"
#if USE_MONO
#include <mono/metadata/object.h>
#endif
#include "Engine/Scripting/ManagedCLR/MCore.h"
Spline::Spline(const SpawnParams& params)
: Actor(params)
@@ -441,16 +439,17 @@ void Spline::UpdateSpline()
#if !COMPILE_WITHOUT_CSHARP
void Spline::GetKeyframes(MonoArray* data)
void Spline::GetKeyframes(MArray* data)
{
Platform::MemoryCopy(mono_array_addr_with_size(data, sizeof(Keyframe), 0), Curve.GetKeyframes().Get(), sizeof(Keyframe) * Curve.GetKeyframes().Count());
ASSERT(MCore::Array::GetLength(data) >= Curve.GetKeyframes().Count());
Platform::MemoryCopy(MCore::Array::GetAddress(data), Curve.GetKeyframes().Get(), sizeof(Keyframe) * Curve.GetKeyframes().Count());
}
void Spline::SetKeyframes(MonoArray* data)
void Spline::SetKeyframes(MArray* data)
{
const auto count = (int32)mono_array_length(data);
const int32 count = MCore::Array::GetLength(data);
Curve.GetKeyframes().Resize(count, false);
Platform::MemoryCopy(Curve.GetKeyframes().Get(), mono_array_addr_with_size(data, sizeof(Keyframe), 0), sizeof(Keyframe) * count);
Platform::MemoryCopy(Curve.GetKeyframes().Get(), MCore::Array::GetAddress(data), sizeof(Keyframe) * count);
UpdateSpline();
}

View File

@@ -363,8 +363,8 @@ protected:
private:
// Internal bindings
#if !COMPILE_WITHOUT_CSHARP
API_FUNCTION(NoProxy) void GetKeyframes(MonoArray* data);
API_FUNCTION(NoProxy) void SetKeyframes(MonoArray* data);
API_FUNCTION(NoProxy) void GetKeyframes(MArray* data);
API_FUNCTION(NoProxy) void SetKeyframes(MArray* data);
#endif
public:

View File

@@ -26,7 +26,7 @@
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Serialization/JsonTools.h"

View File

@@ -6,7 +6,7 @@
#include "Engine/Content/Content.h"
#include "Engine/Level/Prefabs/Prefab.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedSerialization.h"
#include "Engine/Scripting/Internal/ManagedSerialization.h"
#include "Engine/Serialization/ISerializeModifier.h"
#include "Engine/Serialization/Serialization.h"

File diff suppressed because it is too large Load Diff

View File

@@ -2,13 +2,25 @@
#include "CultureInfo.h"
#include "Engine/Core/Log.h"
#include "Engine/Scripting/ManagedCLR/MType.h"
#include "Engine/Core/Types/StringView.h"
#include "Engine/Utilities/StringConverter.h"
#if USE_MONO
#include <mono/metadata/appdomain.h>
#include <mono/metadata/culture-info.h>
#include <mono/metadata/culture-info-tables.h>
#include "Engine/Scripting/Types.h"
#include "Engine/Scripting/ManagedCLR/MProperty.h"
#if USE_CSHARP
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#endif
// Use in-built cultures info tables from mono
#include "CultureInfo.Tables.h"
#if USE_MONO
typedef struct
{
MonoObject obj;
@@ -30,7 +42,6 @@ CultureInfo::CultureInfo(int32 lcid)
_englishName = TEXT("Invariant Culture");
return;
}
#if USE_MONO
for (int32 i = 0; i < NUM_CULTURE_ENTRIES; i++)
{
auto& e = culture_entries[i];
@@ -47,7 +58,6 @@ CultureInfo::CultureInfo(int32 lcid)
break;
}
}
#endif
if (!_data)
{
_englishName = TEXT("Invariant Culture");
@@ -70,7 +80,6 @@ CultureInfo::CultureInfo(const StringAnsiView& name)
_englishName = TEXT("Invariant Culture");
return;
}
#if USE_MONO
for (int32 i = 0; i < NUM_CULTURE_ENTRIES; i++)
{
auto& e = culture_entries[i];
@@ -87,7 +96,6 @@ CultureInfo::CultureInfo(const StringAnsiView& name)
break;
}
}
#endif
if (!_data)
{
_lcid = 127;
@@ -122,16 +130,6 @@ const String& CultureInfo::GetEnglishName() const
return _englishName;
}
bool CultureInfo::IsRightToLeft() const
{
#if USE_MONO
const auto data = static_cast<CultureInfoEntry*>(_data);
if (data)
return data->text_info.is_right_to_left ? true : false;
#endif
return false;
}
String CultureInfo::ToString() const
{
return _name;
@@ -144,31 +142,18 @@ bool CultureInfo::operator==(const CultureInfo& other) const
void* MUtils::ToManaged(const CultureInfo& value)
{
#if USE_MONO
const auto klass = mono_class_from_name(mono_get_corlib(), "System.Globalization", "CultureInfo");
if (klass)
{
void* iter = nullptr;
MonoMethod* method;
while ((method = mono_class_get_methods(klass, &iter)))
{
if (StringUtils::Compare(mono_method_get_name(method), ".ctor") == 0)
{
const auto sig = mono_method_signature(method);
void* sigParams = nullptr;
mono_signature_get_params(sig, &sigParams);
if (mono_signature_get_param_count(sig) == 1 && mono_type_get_class(((MonoType**)sigParams)[0]) != mono_get_string_class())
{
MonoObject* obj = mono_object_new(mono_domain_get(), klass);
int32 lcid = value.GetLCID();
void* params[1];
params[0] = &lcid;
mono_runtime_invoke(method, obj, params, nullptr);
return obj;
}
}
}
}
#if USE_CSHARP
auto scriptingClass = Scripting::GetStaticClass();
CHECK_RETURN(scriptingClass, nullptr);
auto cultureInfoToManaged = scriptingClass->GetMethod("CultureInfoToManaged", 1);
CHECK_RETURN(cultureInfoToManaged, nullptr);
int32 lcid = value.GetLCID();
void* params[1];
params[0] = &lcid;
MObject* obj = cultureInfoToManaged->Invoke(nullptr, params, nullptr);
return obj;
#endif
return nullptr;
}
@@ -179,6 +164,17 @@ CultureInfo MUtils::ToNative(void* value)
#if USE_MONO
if (value)
lcid = static_cast<MonoCultureInfo*>(value)->lcid;
#elif USE_CSHARP
const MClass* klass = GetBinaryModuleCorlib()->Assembly->GetClass("System.Globalization.CultureInfo");
if (value && klass)
{
MProperty* lcidProperty = klass->GetProperty("LCID");
if (lcidProperty && lcidProperty->GetGetMethod())
{
MObject* lcidObj = lcidProperty->GetGetMethod()->Invoke(value, nullptr, nullptr);
lcid = *(int32*)MCore::Object::Unbox(lcidObj);
}
}
#endif
return CultureInfo(lcid);
}

View File

@@ -11,6 +11,7 @@
API_CLASS(InBuild, Namespace="System.Globalization") class FLAXENGINE_API CultureInfo
{
DECLARE_SCRIPTING_TYPE_MINIMAL(CultureInfo);
private:
void* _data;
int32 _lcid;
@@ -64,11 +65,6 @@ public:
/// </summary>
const String& GetEnglishName() const;
/// <summary>
/// Returns true if culture uses right-to-left (RTL) text layout. Otherwise it's more common left-to-right.
/// </summary>
bool IsRightToLeft() const;
String ToString() const;
bool operator==(const CultureInfo& other) const;
};

View File

@@ -111,7 +111,7 @@ int32 ThreadBase::Run()
_isRunning = false;
ThreadExiting(thread, exitCode);
ThreadRegistry::Remove(thread);
MCore::ExitThread(); // TODO: use mono_thread_detach instead of ext and unlink mono runtime from thread in ThreadExiting delegate
MCore::Thread::Exit(); // TODO: use mono_thread_detach instead of ext and unlink mono runtime from thread in ThreadExiting delegate
// mono terminates the native thread..
return exitCode;

View File

@@ -10,15 +10,12 @@
#include "Engine/Platform/IGuiData.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#if USE_MONO
#include <mono/metadata/appdomain.h>
#endif
#if USE_MONO
#if USE_CSHARP
// Helper macros for calling C# events
#define BEGIN_INVOKE_EVENT(name, paramsCount) \
auto managedInstance = GetManagedInstance(); \
@@ -68,10 +65,11 @@
isText = false; data->GetAsFiles(&outputData); \
} \
params[1] = (void*)&isText; \
MonoArray* outputDataMono = mono_array_new(mono_domain_get(), mono_get_string_class(), outputData.Count()); \
MArray* outputDataManaged = MCore::Array::New(MCore::TypeCache::String, outputData.Count()); \
MString** outputDataManagedPtr = MCore::Array::GetAddress<MString*>(outputDataManaged); \
for (int32 i = 0; i < outputData.Count(); i++) \
*(MonoString**)mono_array_addr_with_size(outputDataMono, sizeof(MonoString*), i) = MUtils::ToString(outputData[i]); \
params[2] = outputDataMono; \
outputDataManagedPtr[i] = MUtils::ToString(outputData[i]); \
params[2] = outputDataManaged; \
MObject* exception = nullptr; \
auto resultObj = _method_##name->Invoke(GetManagedInstance(), params, &exception); \
if (resultObj) \

View File

@@ -7,15 +7,14 @@
#include "Engine/Profiler/ProfilerCPU.h"
#include "ManagedCLR/MAssembly.h"
#include "ManagedCLR/MClass.h"
#include "ManagedCLR/MType.h"
#include "ManagedCLR/MMethod.h"
#include "ManagedCLR/MField.h"
#include "ManagedCLR/MUtils.h"
#include "ManagedCLR/MException.h"
#include "FlaxEngine.Gen.h"
#include "MException.h"
#include "Scripting.h"
#include "Events.h"
#include "StdTypesContainer.h"
#include "Internal/StdTypesContainer.h"
Dictionary<Pair<ScriptingTypeHandle, StringView>, void(*)(ScriptingObject*, void*, bool)> ScriptingEvents::EventsTable;
Delegate<ScriptingObject*, Span<Variant>, ScriptingTypeHandle, StringView> ScriptingEvents::Event;
@@ -25,7 +24,7 @@ ManagedBinaryModule* GetBinaryModuleCorlib()
#if COMPILE_WITHOUT_CSHARP
return nullptr;
#else
static ManagedBinaryModule assembly("corlib", MAssemblyOptions(false)); // Don't precache all corlib classes
static ManagedBinaryModule assembly("corlib");
return &assembly;
#endif
}
@@ -54,12 +53,12 @@ const ScriptingType& ScriptingTypeHandle::GetType() const
return Module->Types[TypeIndex];
}
#if USE_MONO
#if USE_CSHARP
MonoClass* ScriptingTypeHandle::GetMonoClass() const
MClass* ScriptingTypeHandle::GetClass() const
{
ASSERT_LOW_LAYER(Module && Module->Types[TypeIndex].ManagedClass);
return Module->Types[TypeIndex].ManagedClass->GetNative();
return Module->Types[TypeIndex].ManagedClass;
}
#endif
@@ -695,8 +694,8 @@ void BinaryModule::Destroy(bool isReloading)
GetModules().RemoveKeepOrder(this);
}
ManagedBinaryModule::ManagedBinaryModule(const StringAnsiView& name, const MAssemblyOptions& options)
: ManagedBinaryModule(New<MAssembly>(nullptr, name, options))
ManagedBinaryModule::ManagedBinaryModule(const StringAnsiView& name)
: ManagedBinaryModule(New<MAssembly>(nullptr, name))
{
}
@@ -799,18 +798,18 @@ namespace
return nullptr;
}
bool VariantTypeEquals(const VariantType& type, MonoType* monoType)
bool VariantTypeEquals(const VariantType& type, MType* mType)
{
MonoClass* monoClass = mono_class_from_mono_type(monoType);
if (MUtils::GetClass(type) != monoClass)
MClass* mClass = MCore::Type::GetClass(mType);
if (MUtils::GetClass(type) != mClass)
{
// Hack for Vector2/3/4 which alias with Float2/3/4 or Double2/3/4 (depending on USE_LARGE_WORLDS)
const auto& stdTypes = *StdTypesContainer::Instance();
if (monoClass == stdTypes.Vector2Class->GetNative() && (type.Type == VariantType::Float2 || type.Type == VariantType::Double2))
if (mClass == stdTypes.Vector2Class && (type.Type == VariantType::Float2 || type.Type == VariantType::Double2))
return true;
if (monoClass == stdTypes.Vector3Class->GetNative() && (type.Type == VariantType::Float3 || type.Type == VariantType::Double3))
if (mClass == stdTypes.Vector3Class && (type.Type == VariantType::Float3 || type.Type == VariantType::Double3))
return true;
if (monoClass == stdTypes.Vector4Class->GetNative() && (type.Type == VariantType::Float4 || type.Type == VariantType::Double4))
if (mClass == stdTypes.Vector4Class && (type.Type == VariantType::Float4 || type.Type == VariantType::Double4))
return true;
return false;
@@ -828,64 +827,54 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
const auto& methods = mclass->GetMethods();
for (MMethod* method : methods)
{
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(method->GetNative());
/*if (method->IsStatic() != signature.IsStatic ||
method->GetName() != signature.Name ||
(int32)mono_signature_get_param_count(sig) != signature.Params.Count())
continue;*/
#if USE_CSHARP
if (method->IsStatic() != signature.IsStatic)
continue;
if (method->GetName() != signature.Name)
continue;
if ((int32)mono_signature_get_param_count(sig) != signature.Params.Count())
if (method->GetParametersCount() != signature.Params.Count())
continue;
void* sigParams = nullptr;
MonoType* type = mono_signature_get_params(sig, &sigParams);
bool isValid = true;
int paramIdx = 0;
while (type != nullptr)
for (int32 paramIdx = 0; paramIdx < signature.Params.Count(); paramIdx++)
{
auto& param = signature.Params[paramIdx];
if (param.IsOut != (mono_signature_param_is_out(sig, paramIdx) != 0) ||
MType* type = method->GetParameterType(paramIdx);
if (param.IsOut != method->GetParameterIsOut(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)))
if (isValid && VariantTypeEquals(signature.ReturnType, method->GetReturnType()))
return method;
#endif
}
return nullptr;
}
#if USE_MONO
#if USE_CSHARP
ManagedBinaryModule* ManagedBinaryModule::FindModule(MonoClass* klass)
ManagedBinaryModule* ManagedBinaryModule::FindModule(const MClass* klass)
{
// TODO: consider caching lookup table MonoImage* -> ManagedBinaryModule*
ManagedBinaryModule* module = nullptr;
MonoImage* mImage = mono_class_get_image(klass);
auto& modules = BinaryModule::GetModules();
for (auto e : modules)
if (klass && klass->GetAssembly())
{
auto managedModule = dynamic_cast<ManagedBinaryModule*>(e);
if (managedModule && managedModule->Assembly->GetMonoImage() == mImage)
auto& modules = BinaryModule::GetModules();
for (auto e : modules)
{
module = managedModule;
break;
auto managedModule = dynamic_cast<ManagedBinaryModule*>(e);
if (managedModule && managedModule->Assembly == klass->GetAssembly())
{
module = managedModule;
break;
}
}
}
return module;
}
ScriptingTypeHandle ManagedBinaryModule::FindType(MonoClass* klass)
ScriptingTypeHandle ManagedBinaryModule::FindType(const MClass* klass)
{
auto typeModule = FindModule(klass);
if (typeModule)
@@ -924,7 +913,7 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
ASSERT(type.ManagedClass == nullptr);
// Cache class
const MString typeName(type.Fullname.Get(), type.Fullname.Length());
const StringAnsi typeName(type.Fullname.Get(), type.Fullname.Length());
classes.TryGet(typeName, type.ManagedClass);
if (type.ManagedClass == nullptr)
{
@@ -933,7 +922,7 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
}
// Cache klass -> type index lookup
MonoClass* klass = type.ManagedClass->GetNative();
MClass* klass = type.ManagedClass;
#if !BUILD_RELEASE
if (ClassToTypeIndex.ContainsKey(klass))
{
@@ -1004,26 +993,14 @@ void ManagedBinaryModule::InitType(MClass* mclass)
{
#if !COMPILE_WITHOUT_CSHARP
// Skip if already initialized
const MString& typeName = mclass->GetFullName();
const StringAnsi& typeName = mclass->GetFullName();
if (TypeNameToTypeIndex.ContainsKey(typeName))
return;
// Find first native base C++ class of this C# class
MClass* baseClass = nullptr;
MonoClass* baseKlass = mono_class_get_parent(mclass->GetNative());
MonoImage* baseKlassImage = mono_class_get_image(baseKlass);
MClass* baseClass = mclass->GetBaseClass();
ScriptingTypeHandle baseType;
auto& modules = GetModules();
for (int32 i = 0; i < modules.Count(); i++)
{
auto e = dynamic_cast<ManagedBinaryModule*>(modules[i]);
if (e && e->Assembly->GetMonoImage() == baseKlassImage)
{
baseType.Module = e;
baseClass = e->Assembly->GetClass(baseKlass);
break;
}
}
baseType.Module = FindModule(baseClass);
if (!baseClass)
{
LOG(Error, "Missing base class for managed class {0} from assembly {1}.", String(typeName), Assembly->ToString());
@@ -1058,13 +1035,12 @@ void ManagedBinaryModule::InitType(MClass* mclass)
_managedMemoryBlocks.Add(typeNameData);
// Initialize scripting interfaces implemented in C#
MonoClass* interfaceKlass;
void* interfaceIt = nullptr;
int32 interfacesCount = 0;
MonoClass* klass = mclass->GetNative();
while ((interfaceKlass = mono_class_get_interfaces(klass, &interfaceIt)))
MClass* klass = mclass;
const Array<MClass*>& interfaceClasses = klass->GetInterfaces();
for (const MClass* interfaceClass : interfaceClasses)
{
const ScriptingTypeHandle interfaceType = FindType(interfaceKlass);
const ScriptingTypeHandle interfaceType = FindType(interfaceClass);
if (interfaceType)
interfacesCount++;
}
@@ -1073,10 +1049,9 @@ void ManagedBinaryModule::InitType(MClass* mclass)
{
interfaces = (ScriptingType::InterfaceImplementation*)Allocator::Allocate((interfacesCount + 1) * sizeof(ScriptingType::InterfaceImplementation));
interfacesCount = 0;
interfaceIt = nullptr;
while ((interfaceKlass = mono_class_get_interfaces(klass, &interfaceIt)))
for (const MClass* interfaceClass : interfaceClasses)
{
const ScriptingTypeHandle interfaceTypeHandle = FindType(interfaceKlass);
const ScriptingTypeHandle interfaceTypeHandle = FindType(interfaceClass);
if (!interfaceTypeHandle)
continue;
auto& interface = interfaces[interfacesCount++];
@@ -1100,7 +1075,7 @@ void ManagedBinaryModule::InitType(MClass* mclass)
auto& type = Types[typeIndex];
type.ManagedClass = mclass;
// Register Mono class
// Register C# class
ASSERT(!ClassToTypeIndex.ContainsKey(klass));
ClassToTypeIndex[klass] = typeIndex;
@@ -1125,11 +1100,9 @@ void ManagedBinaryModule::InitType(MClass* mclass)
// Special case if method was found but the base class uses generic arguments
if (method && baseClass->IsGeneric())
{
// TODO: encapsulate it into MClass to support inflated methods
auto parentClass = mono_class_get_parent(mclass->GetNative());
auto parentMethod = mono_class_get_method_from_name(parentClass, referenceMethod->GetName().Get(), 0);
auto inflatedMethod = mono_class_inflate_generic_method(parentMethod, nullptr);
method = New<MMethod>(inflatedMethod, baseClass);
MClass* parentClass = mclass->GetBaseClass();
MMethod* parentMethod = parentClass->GetMethod(referenceMethod->GetName().Get(), 0);
method = parentMethod->InflateGeneric();
}
baseClass = baseClass->GetBaseClass();
@@ -1153,7 +1126,7 @@ void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
for (int32 i = _firstManagedTypeIndex; i < Types.Count(); i++)
{
const ScriptingType& type = Types[i];
const MString typeName(type.Fullname.Get(), type.Fullname.Length());
const StringAnsi typeName(type.Fullname.Get(), type.Fullname.Length());
TypeNameToTypeIndex.Remove(typeName);
}
}
@@ -1211,10 +1184,9 @@ void* ManagedBinaryModule::FindMethod(const ScriptingTypeHandle& typeHandle, con
bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Span<Variant> paramValues, Variant& result)
{
#if USE_MONO
#if USE_CSHARP
const auto mMethod = (MMethod*)method;
MonoMethodSignature* signature = mono_method_signature(mMethod->GetNative());
const int32 parametersCount = mono_signature_get_param_count(signature);
const int32 parametersCount = mMethod->GetParametersCount();;
if (paramValues.Length() != parametersCount)
{
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) with invalid parameters amount ({3})", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount, paramValues.Length());
@@ -1227,10 +1199,10 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
if (!mMethod->IsStatic())
{
// Box instance into C# object
MonoObject* instanceObject = MUtils::BoxVariant(instance);
MObject* instanceObject = MUtils::BoxVariant(instance);
// Validate instance
if (!instanceObject || !mono_class_is_subclass_of(mono_object_get_class(instanceObject), mMethod->GetParentClass()->GetNative(), withInterfaces))
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(mMethod->GetParentClass(), withInterfaces))
{
if (!instanceObject)
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) without object instance", String(mMethod->GetParentClass()->GetFullName()), String(mMethod->GetName()), parametersCount);
@@ -1240,37 +1212,32 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
}
// For value-types instance is the actual boxed object data, not te object itself
mInstance = mono_class_is_valuetype(mono_object_get_class(instanceObject)) ? mono_object_unbox(instanceObject) : instanceObject;
mInstance = MCore::Object::GetClass(instanceObject)->IsValueType() ? MCore::Object::Unbox(instanceObject) : instanceObject;
}
// Marshal parameters
void** params = (void**)alloca(parametersCount * sizeof(void*));
bool failed = false;
bool hasOutParams = false;
void* sigParams = nullptr;
MonoType* type = mono_signature_get_params(signature, &sigParams);
for (int paramIdx = 0; type != nullptr;)
for (int32 paramIdx = 0; paramIdx < parametersCount; paramIdx++)
{
auto& paramValue = paramValues[paramIdx];
const bool isOut = mono_signature_param_is_out(signature, paramIdx) != 0;
Variant& paramValue = paramValues[paramIdx];
const bool isOut = mMethod->GetParameterIsOut(paramIdx);
hasOutParams |= isOut;
// Marshal parameter for managed method
MType paramType(type);
MType* paramType = mMethod->GetParameterType(paramIdx);
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);
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, MCore::Type::ToString(paramType), paramIdx, paramValue.Type);
return true;
}
type = mono_signature_get_params(signature, &sigParams);
paramIdx++;
}
// Invoke the method
MObject* exception = nullptr;
MonoObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MonoObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
MObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
if (exception)
{
MException ex(exception);
@@ -1303,18 +1270,17 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
{
for (int32 paramIdx = 0; paramIdx < parametersCount; paramIdx++)
{
const bool isOut = mono_signature_param_is_out(signature, paramIdx) != 0;
if (isOut)
if (mMethod->GetParameterIsOut(paramIdx))
{
auto& paramValue = paramValues[paramIdx];
auto param = params[paramIdx];
switch (paramValue.Type.Type)
{
case VariantType::String:
paramValue.SetString(MUtils::ToString((MonoString*)param));
paramValue.SetString(MUtils::ToString((MString*)param));
break;
case VariantType::Object:
paramValue = MUtils::UnboxVariant((MonoObject*)param);
paramValue = MUtils::UnboxVariant((MObject*)param);
break;
case VariantType::Structure:
{
@@ -1322,7 +1288,8 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
if (paramTypeHandle)
{
auto& valueType = paramTypeHandle.GetType();
valueType.Struct.Unbox(paramValue.AsBlob.Data, (MonoObject*)((byte*)param - sizeof(MonoObject)));
MISSING_CODE("TODO: reimplement unpacking managed structure out parameter from C# call");
//valueType.Struct.Unbox(paramValue.AsBlob.Data, (MObject*)((byte*)param - sizeof(MonoObject))); // TODO: fix this for dotnet7
}
break;
}
@@ -1339,21 +1306,18 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSignature& signature)
{
#if USE_MONO
#if USE_CSHARP
const auto mMethod = (MMethod*)method;
signature.Name = mMethod->GetName();
signature.IsStatic = mMethod->IsStatic();
MonoMethodSignature* sig = mono_method_signature(mMethod->GetNative());
signature.ReturnType = MoveTemp(MUtils::UnboxVariantType(mono_signature_get_return_type(sig)));
void* signatureParams = nullptr;
mono_signature_get_params(sig, &signatureParams);
const int32 paramsCount = (int32)mono_signature_get_param_count(sig);
signature.ReturnType = MoveTemp(MUtils::UnboxVariantType(mMethod->GetReturnType()));
const int32 paramsCount = mMethod->GetParametersCount();
signature.Params.Resize(paramsCount);
for (int32 paramIdx = 0; paramIdx < paramsCount; paramIdx++)
{
auto& param = signature.Params[paramIdx];
param.Type = MoveTemp(MUtils::UnboxVariantType(((MonoType**)signatureParams)[paramIdx]));
param.IsOut = mono_signature_param_is_out(sig, paramIdx) != 0;
param.Type = MoveTemp(MUtils::UnboxVariantType(mMethod->GetParameterType(paramIdx)));
param.IsOut = mMethod->GetParameterIsOut(paramIdx);
}
#endif
}
@@ -1366,28 +1330,28 @@ void* ManagedBinaryModule::FindField(const ScriptingTypeHandle& typeHandle, cons
void ManagedBinaryModule::GetFieldSignature(void* field, ScriptingTypeFieldSignature& fieldSignature)
{
#if USE_MONO
#if USE_CSHARP
const auto mField = (MField*)field;
fieldSignature.Name = mField->GetName();
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType().GetNative()));
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType()));
fieldSignature.IsStatic = mField->IsStatic();
#endif
}
bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Variant& result)
{
#if USE_MONO
#if USE_CSHARP
const auto mField = (MField*)field;
// Get instance object
MonoObject* instanceObject = nullptr;
MObject* instanceObject = nullptr;
if (!mField->IsStatic())
{
// Box instance into C# object
instanceObject = MUtils::BoxVariant(instance);
// Validate instance
if (!instanceObject || !mono_class_is_subclass_of(mono_object_get_class(instanceObject), mField->GetParentClass()->GetNative(), false))
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(mField->GetParentClass()))
{
if (!instanceObject)
LOG(Error, "Failed to get field '{0}.{1}' without object instance", String(mField->GetParentClass()->GetFullName()), String(mField->GetName()));
@@ -1398,7 +1362,7 @@ bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Va
}
// Get the value
MonoObject* resultObject = mField->GetValueBoxed(instanceObject);
MObject* resultObject = mField->GetValueBoxed(instanceObject);
result = MUtils::UnboxVariant(resultObject);
return false;
#else
@@ -1408,18 +1372,18 @@ bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Va
bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value)
{
#if USE_MONO
#if USE_CSHARP
const auto mField = (MField*)field;
// Get instance object
MonoObject* instanceObject = nullptr;
MObject* instanceObject = nullptr;
if (!mField->IsStatic())
{
// Box instance into C# object
instanceObject = MUtils::BoxVariant(instance);
// Validate instance
if (!instanceObject || !mono_class_is_subclass_of(mono_object_get_class(instanceObject), mField->GetParentClass()->GetNative(), false))
if (!instanceObject || !MCore::Object::GetClass(instanceObject)->IsSubClassOf(mField->GetParentClass()))
{
if (!instanceObject)
LOG(Error, "Failed to set field '{0}.{1}' without object instance", String(mField->GetParentClass()->GetFullName()), String(mField->GetName()));
@@ -1446,8 +1410,8 @@ void ManagedBinaryModule::Destroy(bool isReloading)
Assembly->Unload(isReloading);
}
NativeBinaryModule::NativeBinaryModule(const StringAnsiView& name, const MAssemblyOptions& options)
: NativeBinaryModule(New<MAssembly>(nullptr, name, options))
NativeBinaryModule::NativeBinaryModule(const StringAnsiView& name)
: NativeBinaryModule(New<MAssembly>(nullptr, name))
{
}

View File

@@ -9,7 +9,6 @@
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/ISerializable.h"
#include "ManagedCLR/MAssemblyOptions.h"
/// <summary>
/// The scripting type method metadata for code reflection.
@@ -269,8 +268,7 @@ public:
/// Initializes a new instance of the <see cref="ManagedBinaryModule" /> class.
/// </summary>
/// <param name="name">The module name.</param>
/// <param name="options">The assembly options.</param>
ManagedBinaryModule(const StringAnsiView& name, const MAssemblyOptions& options);
ManagedBinaryModule(const StringAnsiView& name);
/// <summary>
/// Initializes a new instance of the <see cref="ManagedBinaryModule" /> class.
@@ -290,18 +288,18 @@ public:
/// </summary>
MAssembly* Assembly;
#if !COMPILE_WITHOUT_CSHARP
#if USE_CSHARP
/// <summary>
/// The scripting types cache that maps the managed class to the scripting type index. Build after assembly is loaded and scripting types get the managed classes information.
/// </summary>
Dictionary<MonoClass*, int32, HeapAllocation> ClassToTypeIndex;
Dictionary<MClass*, int32, HeapAllocation> ClassToTypeIndex;
#endif
static ScriptingObject* ManagedObjectSpawn(const ScriptingObjectSpawnParams& params);
static MMethod* FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature);
#if USE_MONO
static ManagedBinaryModule* FindModule(MonoClass* klass);
static ScriptingTypeHandle FindType(MonoClass* klass);
#if USE_CSHARP
static ManagedBinaryModule* FindModule(const MClass* klass);
static ScriptingTypeHandle FindType(const MClass* klass);
#endif
private:
@@ -339,8 +337,7 @@ public:
/// Initializes a new instance of the <see cref="NativeBinaryModule" /> class.
/// </summary>
/// <param name="name">The module name.</param>
/// <param name="options">The assembly options.</param>
NativeBinaryModule(const StringAnsiView& name, const MAssemblyOptions& options);
NativeBinaryModule(const StringAnsiView& name);
/// <summary>
/// Initializes a new instance of the <see cref="NativeBinaryModule" /> class.

View File

@@ -1,386 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "CoreCLR.h"
#if USE_NETCORE
#include "Engine/Core/Log.h"
#include "Engine/Platform/Platform.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Debug/DebugLog.h"
#include "Engine/Engine/Globals.h"
#if DOTNET_HOST_CORECRL
#include <nethost.h>
#include <coreclr_delegates.h>
#include <hostfxr.h>
#elif DOTNET_HOST_MONO
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Debug/Exceptions/CLRInnerException.h"
#include <mono/jit/jit.h>
#include <mono/jit/mono-private-unstable.h>
#include <mono/utils/mono-logger.h>
typedef char char_t;
#else
#error "Unknown .NET runtime host."
#endif
#if PLATFORM_WINDOWS
#include <combaseapi.h>
#undef SetEnvironmentVariable
#undef LoadLibrary
#endif
static Dictionary<String, void*> CachedFunctions;
static const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp");
#if DOTNET_HOST_CORECRL
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::InitHostfxr(const String& configPath, const String& libraryPath)
{
const FLAX_CORECLR_STRING& library_path = FLAX_CORECLR_STRING(libraryPath);
// Get path to hostfxr library
get_hostfxr_parameters get_hostfxr_params;
get_hostfxr_params.size = sizeof(hostfxr_initialize_parameters);
get_hostfxr_params.assembly_path = library_path.Get();
FLAX_CORECLR_STRING dotnetRoot;
// TODO: implement proper lookup for dotnet instalation folder and handle standalone build of FlaxGame
#if PLATFORM_MAC
get_hostfxr_params.dotnet_root = "/usr/local/share/dotnet";
#else
get_hostfxr_params.dotnet_root = nullptr;
#endif
#if !USE_EDITOR
const String& bundledDotnetPath = Globals::ProjectFolder / TEXT("Dotnet");
if (FileSystem::DirectoryExists(bundledDotnetPath))
{
dotnetRoot = FLAX_CORECLR_STRING(bundledDotnetPath);
#if PLATFORM_WINDOWS_FAMILY
dotnetRoot.Replace('/', '\\');
#endif
get_hostfxr_params.dotnet_root = dotnetRoot.Get();
}
#endif
char_t hostfxrPath[1024];
size_t hostfxrPathSize = sizeof(hostfxrPath) / sizeof(char_t);
int rc = get_hostfxr_path(hostfxrPath, &hostfxrPathSize, &get_hostfxr_params);
if (rc != 0)
{
LOG(Error, "Failed to find hostfxr: {0:x} ({1})", (unsigned int)rc, String(get_hostfxr_params.dotnet_root));
// Warn user about missing .Net
#if PLATFORM_DESKTOP
Platform::OpenUrl(TEXT("https://dotnet.microsoft.com/en-us/download/dotnet/7.0"));
#endif
#if USE_EDITOR
LOG(Fatal, "Missing .NET 7 SDK installation requried to run Flax Editor.");
#else
LOG(Fatal, "Missing .NET 7 Runtime installation requried to run this application.");
#endif
return true;
}
String path(hostfxrPath);
LOG(Info, "Found hostfxr in {0}", path);
// Get API from hostfxr library
void* hostfxr = Platform::LoadLibrary(path.Get());
if (hostfxr == nullptr)
{
LOG(Fatal, "Failed to load hostfxr library ({0})", path);
return true;
}
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");
if (!hostfxr_get_runtime_delegate || !hostfxr_run_app)
{
LOG(Fatal, "Failed to setup hostfxr API ({0})", path);
return true;
}
// Initialize hosting component
const char_t* argv[1] = { library_path.Get() };
hostfxr_initialize_parameters init_params;
init_params.size = sizeof(hostfxr_initialize_parameters);
init_params.host_path = library_path.Get();
path = String(StringUtils::GetDirectoryName(path)) / TEXT("/../../../");
StringUtils::PathRemoveRelativeParts(path);
dotnetRoot = FLAX_CORECLR_STRING(path);
init_params.dotnet_root = dotnetRoot.Get();
hostfxr_handle handle = nullptr;
rc = hostfxr_initialize_for_dotnet_command_line(ARRAY_COUNT(argv), argv, &init_params, &handle);
if (rc != 0 || handle == nullptr)
{
hostfxr_close(handle);
LOG(Fatal, "Failed to initialize hostfxr: {0:x} ({1})", (unsigned int)rc, String(init_params.dotnet_root));
return true;
}
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)
{
hostfxr_close(handle);
LOG(Fatal, "Failed to get runtime delegate hdt_get_function_pointer: 0x{0:x}", (unsigned int)rc);
return true;
}
hostfxr_close(handle);
get_function_pointer = (get_function_pointer_fn)pget_function_pointer;
return false;
}
void CoreCLR::ShutdownHostfxr()
{
}
void* CoreCLR::GetStaticMethodPointer(const String& methodName)
{
void* fun;
if (CachedFunctions.TryGet(methodName, fun))
return fun;
int rc = get_function_pointer(NativeInteropTypeName, 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(methodName, fun);
return fun;
}
#elif DOTNET_HOST_MONO
#ifdef USE_MONO_AOT_MODULE
void* MonoAotModuleHandle = nullptr;
#endif
MonoDomain* MonoDomainHandle = nullptr;
void OnLogCallback(const char* logDomain, const char* logLevel, const char* message, mono_bool fatal, void* userData)
{
String currentDomain(logDomain);
String msg(message);
msg.Replace('\n', ' ');
static const char* monoErrorLevels[] =
{
nullptr,
"error",
"critical",
"warning",
"message",
"info",
"debug"
};
uint32 errorLevel = 0;
if (logLevel != nullptr)
{
for (uint32 i = 1; i < 7; i++)
{
if (strcmp(monoErrorLevels[i], logLevel) == 0)
{
errorLevel = i;
break;
}
}
}
if (currentDomain.IsEmpty())
{
auto domain = MCore::GetActiveDomain();
if (domain != nullptr)
{
currentDomain = domain->GetName().Get();
}
else
{
currentDomain = "null";
}
}
#if 0
// Print C# stack trace (crash may be caused by the managed code)
if (mono_domain_get() && Assemblies::FlaxEngine.Assembly->IsLoaded())
{
const auto managedStackTrace = DebugLog::GetStackTrace();
if (managedStackTrace.HasChars())
{
LOG(Warning, "Managed stack trace:");
LOG_STR(Warning, managedStackTrace);
}
}
#endif
if (errorLevel == 0)
{
Log::CLRInnerException(String::Format(TEXT("Message: {0} | Domain: {1}"), msg, currentDomain)).SetLevel(LogType::Error);
}
else if (errorLevel <= 2)
{
Log::CLRInnerException(String::Format(TEXT("Message: {0} | Domain: {1}"), msg, currentDomain)).SetLevel(LogType::Error);
}
else if (errorLevel <= 3)
{
LOG(Warning, "Message: {0} | Domain: {1}", msg, currentDomain);
}
else
{
LOG(Info, "Message: {0} | Domain: {1}", msg, currentDomain);
}
}
void OnPrintCallback(const char* string, mono_bool isStdout)
{
LOG_STR(Warning, String(string));
}
void OnPrintErrorCallback(const char* string, mono_bool isStdout)
{
// HACK: ignore this message
if (string && Platform::MemoryCompare(string, "debugger-agent: Unable to listen on ", 36) == 0)
return;
LOG_STR(Error, String(string));
}
bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath)
{
#if 1
// Enable detailed Mono logging
Platform::SetEnvironmentVariable(TEXT("MONO_LOG_LEVEL"), TEXT("debug"));
Platform::SetEnvironmentVariable(TEXT("MONO_LOG_MASK"), TEXT("all"));
//Platform::SetEnvironmentVariable(TEXT("MONO_GC_DEBUG"), TEXT("6:gc-log.txt,check-remset-consistency,nursery-canaries"));
#endif
#if defined(USE_MONO_AOT_MODE)
// Enable AOT mode (per-platform)
mono_jit_set_aot_mode(USE_MONO_AOT_MODE);
#endif
#ifdef USE_MONO_AOT_MODULE
// Load AOT module
const DateTime aotModuleLoadStartTime = DateTime::Now();
LOG(Info, "Loading Mono AOT module...");
void* libAotModule = Platform::LoadLibrary(TEXT(USE_MONO_AOT_MODULE));
if (libAotModule == nullptr)
{
LOG(Error, "Failed to laod Mono AOT module (" TEXT(USE_MONO_AOT_MODULE) ")");
return true;
}
MonoAotModuleHandle = libAotModule;
void* getModulesPtr = Platform::GetProcAddress(libAotModule, "GetMonoModules");
if (getModulesPtr == nullptr)
{
LOG(Error, "Failed to get Mono AOT modules getter.");
return true;
}
typedef int (*GetMonoModulesFunc)(void** buffer, int bufferSize);
const auto getModules = (GetMonoModulesFunc)getModulesPtr;
const int32 moduelsCount = getModules(nullptr, 0);
void** modules = (void**)Allocator::Allocate(moduelsCount * sizeof(void*));
getModules(modules, moduelsCount);
for (int32 i = 0; i < moduelsCount; i++)
{
mono_aot_register_module((void**)modules[i]);
}
Allocator::Free(modules);
LOG(Info, "Mono AOT module loaded in {0}ms", (int32)(DateTime::Now() - aotModuleLoadStartTime).GetTotalMilliseconds());
#endif
// TODO: setup C# debugger
// Connect to mono engine callback system
mono_trace_set_log_handler(OnLogCallback, nullptr);
mono_trace_set_print_handler(OnPrintCallback);
mono_trace_set_printerr_handler(OnPrintErrorCallback);
// Initialize Mono VM
StringAnsi baseDirectory(Globals::ProjectFolder);
const char* appctxKeys[] =
{
"RUNTIME_IDENTIFIER",
"APP_CONTEXT_BASE_DIRECTORY",
};
const char* appctxValues[] =
{
MACRO_TO_STR(DOTNET_HOST_RUNTIME_IDENTIFIER),
baseDirectory.Get(),
};
static_assert(ARRAY_COUNT(appctxKeys) == ARRAY_COUNT(appctxValues), "Invalid appctx setup");
monovm_initialize(ARRAY_COUNT(appctxKeys), appctxKeys, appctxValues);
// Init managed runtime
#if PLATFORM_ANDROID || PLATFORM_IOS
const char* monoVersion = "mobile";
#else
const char* monoVersion = ""; // ignored
#endif
MonoDomainHandle = mono_jit_init_version("Flax", monoVersion);
if (!MonoDomainHandle)
{
LOG(Fatal, "Failed to initialize Mono.");
return true;
}
// Log info
char* buildInfo = mono_get_runtime_build_info();
LOG(Info, "Mono runtime version: {0}", String(buildInfo));
mono_free(buildInfo);
return false;
}
void CoreCLR::ShutdownHostfxr()
{
mono_jit_cleanup(MonoDomainHandle);
MonoDomainHandle = nullptr;
#ifdef USE_MONO_AOT_MODULE
Platform::FreeLibrary(MonoAotModuleHandle);
#endif
}
void* CoreCLR::GetStaticMethodPointer(const String& methodName)
{
MISSING_CODE("TODO: CoreCLR::GetStaticMethodPointer for Mono host runtime");
return nullptr;
}
#endif
void CoreCLR::RegisterNativeLibrary(const char* moduleName, const char* modulePath)
{
static void* RegisterNativeLibraryPtr = CoreCLR::GetStaticMethodPointer(TEXT("RegisterNativeLibrary"));
CoreCLR::CallStaticMethod<void, const char*, const char*>(RegisterNativeLibraryPtr, moduleName, modulePath);
}
void* CoreCLR::Allocate(int32 size)
{
static void* AllocMemoryPtr = CoreCLR::GetStaticMethodPointer(TEXT("AllocMemory"));
return CoreCLR::CallStaticMethod<void*, int32>(AllocMemoryPtr, size);
}
void CoreCLR::Free(void* ptr)
{
if (!ptr)
return;
static void* FreeMemoryPtr = CoreCLR::GetStaticMethodPointer(TEXT("FreeMemory"));
CoreCLR::CallStaticMethod<void, void*>(FreeMemoryPtr, ptr);
}
#endif

View File

@@ -1,71 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Scripting/Types.h"
#if USE_NETCORE
#if defined(_WIN32)
#define CORECLR_DELEGATE_CALLTYPE __stdcall
#define FLAX_CORECLR_STRING String
#define FLAX_CORECLR_TEXT(x) TEXT(x)
#else
#define CORECLR_DELEGATE_CALLTYPE
#define FLAX_CORECLR_STRING StringAnsi
#define FLAX_CORECLR_TEXT(x) x
#endif
/// <summary>
/// .NET Runtime hosting library that uses Hostfxr (https://github.com/dotnet/runtime).
/// </summary>
class CoreCLR
{
public:
static bool InitHostfxr(const String& configPath, const String& libraryPath);
static void ShutdownHostfxr();
/// <summary>
/// Returns the function pointer to the managed static method in NativeInterop class.
/// </summary>
static void* GetStaticMethodPointer(const String& methodName);
/// <summary>
/// Calls the managed static method in NativeInterop class with given parameters.
/// </summary>
template<typename RetType, typename ...Args>
static inline RetType CallStaticMethodByName(const String& methodName, Args... args)
{
typedef RetType(CORECLR_DELEGATE_CALLTYPE* fun)(Args...);
return ((fun)GetStaticMethodPointer(methodName))(args...);
}
/// <summary>
/// Calls the managed static method with given parameters.
/// </summary>
template<typename RetType, typename ...Args>
static inline RetType CallStaticMethod(void* methodPtr, Args... args)
{
typedef RetType(CORECLR_DELEGATE_CALLTYPE* fun)(Args...);
return ((fun)methodPtr)(args...);
}
static void RegisterNativeLibrary(const char* moduleName, const char* modulePath);
static const char* GetClassFullname(void* klass);
static void* Allocate(int32 size);
static void Free(void* ptr);
static MGCHandle NewGCHandle(void* obj, bool pinned);
static MGCHandle NewGCHandleWeakref(void* obj, bool track_resurrection);
static void* GetGCHandleTarget(const MGCHandle& handle);
static void FreeGCHandle(const MGCHandle& handle);
static bool HasCustomAttribute(void* klass, void* attribClass);
static bool HasCustomAttribute(void* klass);
static void* GetCustomAttribute(void* klass, void* attribClass);
static Array<MObject*> GetCustomAttributes(void* klass);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,97 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "Scripting.h"
#include "ScriptingType.h"
#include "FlaxEngine.Gen.h"
#include "Engine/Scripting/InternalCalls.h"
#include "Engine/Platform/Platform.h"
#include "Engine/Animations/Graph/AnimGraph.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#if USE_MONO
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#endif
#include "Engine/Scripting/Internal/InternalCalls.h"
#include "Engine/Core/ObjectsRemovalService.h"
#include "Engine/Profiler/Profiler.h"
#include "FlaxEngine.Gen.h"
#if TRACY_ENABLE && !PROFILE_CPU_USE_TRANSIENT_DATA
#include "Engine/Core/Collections/ChunkedArray.h"
#endif
#include "Engine/Core/Types/Pair.h"
#include "Engine/Threading/Threading.h"
#if USE_MONO
#include <mono/metadata/mono-gc.h>
#endif
#if !COMPILE_WITHOUT_CSHARP
#if USE_MONO
DEFINE_INTERNAL_CALL(MObject*) UtilsInternal_ExtractArrayFromList(MObject* obj)
{
MClass* klass = MCore::Object::GetClass(obj);
MField* field = klass->GetField("_items");
MObject* o;
field->GetValue(obj, &o);
return o;
}
#endif
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryCopy(void* dst, const void* src, uint64 size)
{
Platform::MemoryCopy(dst, src, size);
}
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryClear(void* dst, uint64 size)
{
Platform::MemoryClear(dst, size);
}
DEFINE_INTERNAL_CALL(int32) PlatformInternal_MemoryCompare(const void* buf1, const void* buf2, uint64 size)
{
return Platform::MemoryCompare(buf1, buf2, size);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogWrite(LogType level, MString* msgObj)
{
StringView msg;
MUtils::ToString(msgObj, msg);
Log::Logger::Write(level, msg);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_Log(LogType level, MString* msgObj, ScriptingObject* obj, MString* stackTrace)
{
if (msgObj == nullptr)
return;
// Get info
StringView msg;
MUtils::ToString(msgObj, msg);
//const String objName = obj ? obj->ToString() : String::Empty;
// Send event
// TODO: maybe option for build to threat warnings and errors as fatal errors?
//const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg);
Log::Logger::Write(level, msg);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogException(MObject* exception, ScriptingObject* obj)
{
#if USE_CSHARP
if (exception == nullptr)
return;
// Get info
MException ex(exception);
const String objName = obj ? obj->ToString() : String::Empty;
// 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
}
#endif
#if USE_CSHARP
namespace
{
@@ -39,10 +112,11 @@ namespace
#endif
}
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEvent(MonoString* nameObj)
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEvent(MString* nameObj)
{
#if COMPILE_WITH_PROFILER
const StringView name((const Char*)mono_string_chars(nameObj), mono_string_length(nameObj));
StringView name;
MUtils::ToString(nameObj, name);
ProfilerCPU::BeginEvent(*name);
#if TRACY_ENABLE
#if PROFILE_CPU_USE_TRANSIENT_DATA
@@ -87,10 +161,11 @@ DEFINE_INTERNAL_CALL(void) ProfilerInternal_EndEvent()
#endif
}
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEventGPU(MonoString* nameObj)
DEFINE_INTERNAL_CALL(void) ProfilerInternal_BeginEventGPU(MString* nameObj)
{
#if COMPILE_WITH_PROFILER
const auto index = ProfilerGPU::BeginEvent((const Char*)mono_string_chars(nameObj));
const StringView nameChars = MCore::String::GetChars(nameObj);
const auto index = ProfilerGPU::BeginEvent(nameChars.Get());
ManagedEventsGPU.Push(index);
#endif
}
@@ -108,9 +183,9 @@ DEFINE_INTERNAL_CALL(bool) ScriptingInternal_HasGameModulesLoaded()
return Scripting::HasGameModulesLoaded();
}
DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MonoReflectionType* type)
DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MTypeObject* type)
{
return Scripting::IsTypeFromGameScripts(Scripting::FindClass(MUtils::GetClass(type)));
return Scripting::IsTypeFromGameScripts(MUtils::GetClass(INTERNAL_TYPE_OBJECT_GET(type)));
}
DEFINE_INTERNAL_CALL(void) ScriptingInternal_FlushRemovedObjects()
@@ -121,6 +196,22 @@ DEFINE_INTERNAL_CALL(void) ScriptingInternal_FlushRemovedObjects()
#endif
void registerFlaxEngineInternalCalls()
{
AnimGraphExecutor::initRuntime();
#if USE_CSHARP
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &PlatformInternal_MemoryCopy);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &PlatformInternal_MemoryClear);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCompare", &PlatformInternal_MemoryCompare);
#if USE_MONO
ADD_INTERNAL_CALL("FlaxEngine.Utils::Internal_ExtractArrayFromList", &UtilsInternal_ExtractArrayFromList);
#endif
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal_LogWrite);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal_Log);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal_LogException);
#endif
}
class ScriptingInternal
{
public:

View File

@@ -2,10 +2,10 @@
#pragma once
#include "Engine/Debug/DebugLog.h"
#include "Engine/Core/Log.h"
#include "ScriptingType.h"
#include "Types.h"
#include "Engine/Debug/DebugLog.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/Types.h"
#if defined(__clang__)
// Helper utility to override vtable entry with automatic restore
@@ -33,7 +33,7 @@ struct FLAXENGINE_API VTableFunctionInjector
#define MSVC_FUNC_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
#endif
#if USE_MONO
#if USE_CSHARP
#if USE_NETCORE
#define ADD_INTERNAL_CALL(fullName, method)

View File

@@ -3,7 +3,7 @@
#include "MainThreadManagedInvokeAction.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Scripting/ScriptingCalls.h"
#include "MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(MMethod* method, MObject* instance, LogType exceptionLevel)
{

View File

@@ -4,8 +4,8 @@
#include "Engine/Threading/MainThreadTask.h"
#include "Engine/Core/Log.h"
#include "ManagedCLR/MMethod.h"
#include "ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
/// <summary>
/// Helper class for easy invoking managed code on main thread before all game systems update.
@@ -71,28 +71,28 @@ public:
AddParam(val);
}
#if USE_MONO
#if USE_CSHARP
FORCE_INLINE void AddParam(const String& value)
{
MonoString* val = MUtils::ToString(value);
MString* val = MUtils::ToString(value);
AddParam(val);
}
FORCE_INLINE void AddParam(const StringView& value)
{
MonoString* val = MUtils::ToString(value);
MString* val = MUtils::ToString(value);
AddParam(val);
}
FORCE_INLINE void AddParam(const String& value, MonoDomain* domain)
FORCE_INLINE void AddParam(const String& value, MDomain* domain)
{
MonoString* val = MUtils::ToString(value, domain);
MString* val = MUtils::ToString(value, domain);
AddParam(val);
}
FORCE_INLINE void AddParam(const StringView& value, MonoDomain* domain)
FORCE_INLINE void AddParam(const StringView& value, MDomain* domain)
{
MonoString* val = MUtils::ToString(value, domain);
MString* val = MUtils::ToString(value, domain);
AddParam(val);
}
#endif

View File

@@ -2,16 +2,9 @@
#pragma once
#include "Engine/Core/Log.h"
#include "Engine/Core/Collections/BitArray.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/BinaryModule.h"
#if USE_MONO
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/object.h>
#include "Engine/Scripting/ManagedCLR/MCore.h"
#if USE_CSHARP
struct ManagedBitArray
{
@@ -26,7 +19,7 @@ struct ManagedBitArray
MonoMethod* bitArrayCtor = mono_method_desc_search_in_class(desc, bitArrayClass->GetNative());
mono_method_desc_free(desc);
CHECK_RETURN(bitArrayCtor, nullptr);
MonoObject* instance = mono_object_new(mono_domain_get(), bitArrayClass->GetNative());
MObject* instance = MCore::Object::New(bitArrayClass);
CHECK_RETURN(instance, nullptr);
int32 length = data.Count();
void* params[1];
@@ -34,10 +27,10 @@ struct ManagedBitArray
mono_runtime_invoke(bitArrayCtor, instance, params, nullptr);
const MField* arrayField = bitArrayClass->GetField("m_array");
CHECK_RETURN(arrayField, nullptr);
MonoArray* array = nullptr;
MArray* array = nullptr;
arrayField->GetValue(instance, &array);
CHECK_RETURN(array, nullptr);
const int32 arrayLength = mono_array_length(array);
const int32 arrayLength = MCore::Array::GetLength(array);
//mono_value_copy_array(array, 0, (void*)data.Get(), arrayLength);
int32* arrayPtr = mono_array_addr(array, int32, 0);
//Platform::MemoryCopy(mono_array_addr_with_size(array, sizeof(int32), 0), data.Get(), data.Count() / sizeof(byte));
@@ -45,12 +38,11 @@ struct ManagedBitArray
return instance;
#else
// Convert into bool[]
MonoArray* array = mono_array_new(mono_domain_get(), mono_get_boolean_class(), data.Count());
MArray* array = MCore::Array::New(MCore::TypeCache::Boolean, data.Count());
bool* arrayPtr = MCore::Array::GetAddress<bool>(array);
for (int32 i = 0; i < data.Count(); i++)
{
mono_array_set(array, bool, i, data[i]);
}
return (MonoObject*)array;
arrayPtr[i] = data[i];
return (MObject*)array;
#endif
}
};

View File

@@ -4,40 +4,39 @@
#include "Engine/Core/Log.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/StdTypesContainer.h"
#if USE_CSHARP
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/MException.h"
#if USE_MONO
#include <mono/metadata/appdomain.h>
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Internal/StdTypesContainer.h"
/// <summary>
/// Utility interop between C++ and C# for Dictionary collection.
/// </summary>
struct FLAXENGINE_API ManagedDictionary
{
MonoObject* Instance;
MObject* Instance;
ManagedDictionary(MonoObject* instance = nullptr)
ManagedDictionary(MObject* instance = nullptr)
{
Instance = instance;
}
template<typename KeyType, typename ValueType>
static MonoObject* ToManaged(const Dictionary<KeyType, ValueType>& data, MonoType* keyType, MonoType* valueType)
static MObject* ToManaged(const Dictionary<KeyType, ValueType>& data, MType* keyType, MType* valueType)
{
MConverter<KeyType> keysConverter;
MConverter<ValueType> valueConverter;
ManagedDictionary result = New(keyType, valueType);
MonoClass* keyClass = mono_type_get_class(keyType);
MonoClass* valueClass = mono_type_get_class(valueType);
MClass* keyClass = MCore::Type::GetClass(keyType);
MClass* valueClass = MCore::Type::GetClass(valueType);
for (auto i = data.Begin(); i.IsNotEnd(); ++i)
{
MonoObject* keyManaged = keysConverter.Box(i->Key, keyClass);
MonoObject* valueManaged = valueConverter.Box(i->Value, valueClass);
MObject* keyManaged = keysConverter.Box(i->Key, keyClass);
MObject* valueManaged = valueConverter.Box(i->Value, valueClass);
result.Add(keyManaged, valueManaged);
}
return result.Instance;
@@ -49,82 +48,78 @@ struct FLAXENGINE_API ManagedDictionary
/// <param name="managed">The managed dictionary object.</param>
/// <returns>The output array.</returns>
template<typename KeyType, typename ValueType>
static Dictionary<KeyType, ValueType> ToNative(MonoObject* managed)
static Dictionary<KeyType, ValueType> ToNative(MObject* managed)
{
Dictionary<KeyType, ValueType> result;
const ManagedDictionary wrapper(managed);
MonoArray* managedKeys = wrapper.GetKeys();
auto length = managedKeys ? (int32)mono_array_length(managedKeys) : 0;
MArray* managedKeys = wrapper.GetKeys();
int32 length = managedKeys ? MCore::Array::GetLength(managedKeys) : 0;
Array<KeyType> keys;
keys.Resize(length);
result.EnsureCapacity(length);
MConverter<KeyType> keysConverter;
for (int32 i = 0; i < keys.Count(); i++)
{
auto& key = keys[i];
MonoObject* keyManaged = mono_array_get(managedKeys, MonoObject*, i);
keysConverter.Unbox(key, keyManaged);
}
MConverter<ValueType> valueConverter;
MObject** managedKeysPtr = MCore::Array::GetAddress<MObject*>(managedKeys);
for (int32 i = 0; i < keys.Count(); i++)
{
auto& key = keys[i];
MonoObject* keyManaged = mono_array_get(managedKeys, MonoObject*, i);
MonoObject* valueManaged = wrapper.GetValue(keyManaged);
auto& value = result[key];
KeyType& key = keys[i];
MObject* keyManaged = managedKeysPtr[i];
keysConverter.Unbox(key, keyManaged);
MObject* valueManaged = wrapper.GetValue(keyManaged);
ValueType& value = result[key];
valueConverter.Unbox(value, valueManaged);
}
return result;
}
static MonoReflectionType* GetClass(MonoType* keyType, MonoType* valueType)
static MTypeObject* GetClass(MType* keyType, MType* valueType)
{
auto domain = mono_domain_get();
auto scriptingClass = Scripting::GetStaticClass();
MClass* scriptingClass = Scripting::GetStaticClass();
CHECK_RETURN(scriptingClass, nullptr);
auto makeGenericMethod = scriptingClass->GetMethod("MakeGenericType", 2);
MMethod* makeGenericMethod = scriptingClass->GetMethod("MakeGenericType", 2);
CHECK_RETURN(makeGenericMethod, nullptr);
auto genericType = MUtils::GetType(StdTypesContainer::Instance()->DictionaryClass->GetNative());
MTypeObject* genericType = MUtils::GetType(StdTypesContainer::Instance()->DictionaryClass);
#if USE_NETCORE
auto genericArgs = mono_array_new(domain, mono_get_intptr_class(), 2);
MArray* genericArgs = MCore::Array::New(MCore::TypeCache::IntPtr, 2);
#else
auto genericArgs = mono_array_new(domain, mono_get_object_class(), 2);
MArray* genericArgs = MCore::Array::New(MCore::TypeCache::Object, 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));
MTypeObject** genericArgsPtr = MCore::Array::GetAddress<MTypeObject*>(genericArgs);
genericArgsPtr[0] = INTERNAL_TYPE_GET_OBJECT(keyType);
genericArgsPtr[1] = INTERNAL_TYPE_GET_OBJECT(valueType);
void* params[2];
params[0] = genericType;
params[1] = genericArgs;
MObject* exception = nullptr;
auto dictionaryType = makeGenericMethod->Invoke(nullptr, params, &exception);
MObject* dictionaryType = makeGenericMethod->Invoke(nullptr, params, &exception);
if (exception)
{
MException ex(exception);
ex.Log(LogType::Error, TEXT(""));
return nullptr;
}
return (MonoReflectionType*)dictionaryType;
return (MTypeObject*)dictionaryType;
}
static ManagedDictionary New(MonoType* keyType, MonoType* valueType)
static ManagedDictionary New(MType* keyType, MType* valueType)
{
ManagedDictionary result;
auto dictionaryType = GetClass(keyType, valueType);
MTypeObject* dictionaryType = GetClass(keyType, valueType);
if (!dictionaryType)
return result;
auto scriptingClass = Scripting::GetStaticClass();
MClass* scriptingClass = Scripting::GetStaticClass();
CHECK_RETURN(scriptingClass, result);
auto createMethod = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2);
MMethod* createMethod = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2);
CHECK_RETURN(createMethod, result);
MObject* exception = nullptr;
void* params[2];
params[0] = dictionaryType;
params[1] = nullptr;
auto instance = createMethod->Invoke(nullptr, params, &exception);
MObject* instance = createMethod->Invoke(nullptr, params, &exception);
if (exception)
{
MException ex(exception);
@@ -136,19 +131,19 @@ struct FLAXENGINE_API ManagedDictionary
return result;
}
void Add(MonoObject* key, MonoObject* value)
void Add(MObject* key, MObject* value)
{
CHECK(Instance);
auto scriptingClass = Scripting::GetStaticClass();
MClass* scriptingClass = Scripting::GetStaticClass();
CHECK(scriptingClass);
auto addDictionaryItemMethod = scriptingClass->GetMethod("AddDictionaryItem", 3);
MMethod* addDictionaryItemMethod = scriptingClass->GetMethod("AddDictionaryItem", 3);
CHECK(addDictionaryItemMethod);
void* params[3];
params[0] = Instance;
params[1] = key;
params[2] = value;
MObject* exception = nullptr;
mono_runtime_invoke(addDictionaryItemMethod->GetNative(), Instance, params, &exception);
addDictionaryItemMethod->Invoke(Instance, params, &exception);
if (exception)
{
MException ex(exception);
@@ -156,27 +151,27 @@ struct FLAXENGINE_API ManagedDictionary
}
}
MonoArray* GetKeys() const
MArray* GetKeys() const
{
CHECK_RETURN(Instance, nullptr);
auto scriptingClass = Scripting::GetStaticClass();
MClass* scriptingClass = Scripting::GetStaticClass();
CHECK_RETURN(scriptingClass, nullptr);
auto getDictionaryKeysMethod = scriptingClass->GetMethod("GetDictionaryKeys", 1);
MMethod* getDictionaryKeysMethod = scriptingClass->GetMethod("GetDictionaryKeys", 1);
CHECK_RETURN(getDictionaryKeysMethod, nullptr);
void* params[1];
params[0] = Instance;
return (MonoArray*)mono_runtime_invoke(getDictionaryKeysMethod->GetNative(), nullptr, params, nullptr);
return (MArray*)getDictionaryKeysMethod->Invoke( nullptr, params, nullptr);
}
MonoObject* GetValue(MonoObject* key) const
MObject* GetValue(MObject* key) const
{
CHECK_RETURN(Instance, nullptr);
auto klass = mono_object_get_class(Instance);
auto getItemMethod = mono_class_get_method_from_name(klass, "System.Collections.IDictionary.get_Item", 1);
MClass* klass = MCore::Object::GetClass(Instance);
MMethod* getItemMethod = klass->GetMethod("System.Collections.IDictionary.get_Item", 1);
CHECK_RETURN(getItemMethod, nullptr);
void* params[1];
params[0] = key;
return mono_runtime_invoke(getItemMethod, Instance, params, nullptr);
return getItemMethod->Invoke(Instance, params, nullptr);
}
};

View File

@@ -1,14 +1,14 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "ManagedSerialization.h"
#if USE_MONO
#if USE_CSHARP
#include "Engine/Core/Log.h"
#include "Engine/Serialization/Json.h"
#include "Engine/Serialization/JsonWriter.h"
#include "StdTypesContainer.h"
#include "MException.h"
#include "ManagedCLR/MMethod.h"
#include <mono/metadata/mono-debug.h>
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/Internal/StdTypesContainer.h"
void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MObject* object)
{
@@ -29,7 +29,7 @@ void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MOb
// Call serialization tool
MObject* exception = nullptr;
// TODO: use method thunk
auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_Serialize->Invoke(nullptr, params, &exception);
auto invokeResultStr = (MString*)StdTypesContainer::Instance()->Json_Serialize->Invoke(nullptr, params, &exception);
if (exception)
{
MException ex(exception);
@@ -42,9 +42,7 @@ void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MOb
}
// Write result data
const auto invokeResultChars = mono_string_to_utf8(invokeResultStr);
stream.RawValue(invokeResultChars);
mono_free(invokeResultChars);
stream.RawValue(MCore::String::GetChars(invokeResultStr));
}
void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream, MObject* object, MObject* other)
@@ -67,7 +65,7 @@ void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream,
// Call serialization tool
MObject* exception = nullptr;
// TODO: use method thunk
auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_SerializeDiff->Invoke(nullptr, params, &exception);
auto invokeResultStr = (MString*)StdTypesContainer::Instance()->Json_SerializeDiff->Invoke(nullptr, params, &exception);
if (exception)
{
MException ex(exception);
@@ -80,9 +78,7 @@ void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream,
}
// Write result data
auto invokeResultChars = mono_string_to_utf8(invokeResultStr);
stream.RawValue(invokeResultChars);
mono_free(invokeResultChars);
stream.RawValue(MCore::String::GetChars(invokeResultStr));
}
void ManagedSerialization::Deserialize(ISerializable::DeserializeStream& stream, MObject* object)

View File

@@ -3,7 +3,7 @@
#pragma once
#include "Engine/Core/ISerializable.h"
#include "ManagedCLR/MTypes.h"
#include "Engine/Scripting/ManagedCLR/MTypes.h"
/// <summary>
/// Managed objects serialization utilities. Helps with C# scripts saving to JSON or loading.
@@ -11,8 +11,7 @@
class FLAXENGINE_API ManagedSerialization
{
public:
#if USE_MONO
#if USE_CSHARP
/// <summary>
/// Serializes managed object to JSON.
/// </summary>

View File

@@ -1,11 +1,11 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "StdTypesContainer.h"
#include "Scripting.h"
#include "ScriptingType.h"
#include "BinaryModule.h"
#include "ManagedCLR/MAssembly.h"
#include "ManagedCLR/MClass.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Scripting/BinaryModule.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Core/Log.h"
#include "FlaxEngine.Gen.h"
@@ -47,7 +47,7 @@ void StdTypesContainer::Clear()
bool StdTypesContainer::Gather()
{
#if !COMPILE_WITHOUT_CSHARP
#if USE_CSHARP
#define GET_CLASS(assembly, type, typeName) \
type = ((ManagedBinaryModule*)CONCAT_MACROS(GetBinaryModule, assembly)())->Assembly->GetClass(typeName); \
if (type == nullptr) \

View File

@@ -1,92 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "Engine/Platform/Platform.h"
#include "Engine/Animations/Graph/AnimGraph.h"
#include "Engine/Scripting/InternalCalls.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#if !COMPILE_WITHOUT_CSHARP
#if USE_MONO && !USE_NETCORE
DEFINE_INTERNAL_CALL(MonoObject*) UtilsInternal_ExtractArrayFromList(MonoObject* obj)
{
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;
}
#endif
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryCopy(void* dst, const void* src, uint64 size)
{
Platform::MemoryCopy(dst, src, size);
}
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryClear(void* dst, uint64 size)
{
Platform::MemoryClear(dst, size);
}
DEFINE_INTERNAL_CALL(int32) PlatformInternal_MemoryCompare(const void* buf1, const void* buf2, uint64 size)
{
return Platform::MemoryCompare(buf1, buf2, size);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogWrite(LogType level, MonoString* msgObj)
{
StringView msg;
MUtils::ToString(msgObj, msg);
Log::Logger::Write(level, msg);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace)
{
if (msgObj == nullptr)
return;
// Get info
StringView msg;
MUtils::ToString(msgObj, msg);
//const String objName = obj ? obj->ToString() : String::Empty;
// Send event
// TODO: maybe option for build to threat warnings and errors as fatal errors?
//const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg);
Log::Logger::Write(level, msg);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogException(MonoException* exception, ScriptingObject* obj)
{
#if USE_MONO
if (exception == nullptr)
return;
// Get info
MException ex(exception);
const String objName = obj ? obj->ToString() : String::Empty;
// 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
}
#endif
void registerFlaxEngineInternalCalls()
{
AnimGraphExecutor::initRuntime();
#if USE_MONO
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &PlatformInternal_MemoryCopy);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &PlatformInternal_MemoryClear);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCompare", &PlatformInternal_MemoryCompare);
#if USE_MONO && !USE_NETCORE
ADD_INTERNAL_CALL("FlaxEngine.Utils::Internal_ExtractArrayFromList", &UtilsInternal::ExtractArrayFromList);
#endif
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal_LogWrite);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal_Log);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal_LogException);
#endif
}

View File

@@ -1,38 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MException.h"
#include "ManagedCLR/MUtils.h"
#if USE_MONO
#include <mono/metadata/object.h>
#endif
MException::MException(MObject* exception)
: InnerException(nullptr)
{
#if USE_MONO
ASSERT(exception);
MonoClass* exceptionClass = mono_object_get_class(exception);
MonoProperty* exceptionMsgProp = mono_class_get_property_from_name(exceptionClass, "Message");
MonoMethod* exceptionMsgGetter = mono_property_get_get_method(exceptionMsgProp);
MonoString* exceptionMsg = (MonoString*)mono_runtime_invoke(exceptionMsgGetter, exception, nullptr, nullptr);
Message = MUtils::ToString(exceptionMsg);
MonoProperty* exceptionStackProp = mono_class_get_property_from_name(exceptionClass, "StackTrace");
MonoMethod* exceptionStackGetter = mono_property_get_get_method(exceptionStackProp);
MonoString* exceptionStackTrace = (MonoString*)mono_runtime_invoke(exceptionStackGetter, exception, nullptr, nullptr);
StackTrace = MUtils::ToString(exceptionStackTrace);
MonoProperty* innerExceptionProp = mono_class_get_property_from_name(exceptionClass, "InnerException");
MonoMethod* innerExceptionGetter = mono_property_get_get_method(innerExceptionProp);
MonoObject* innerException = (MonoObject*)mono_runtime_invoke(innerExceptionGetter, exception, nullptr, nullptr);
if (innerException)
InnerException = New<MException>(innerException);
#endif
}
MException::~MException()
{
if (InnerException)
Delete(InnerException);
}

View File

@@ -1,420 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MAssembly.h"
#include "MClass.h"
#include "MDomain.h"
#include "MUtils.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Debug/Exceptions/InvalidOperationException.h"
#include "Engine/Debug/Exceptions/FileNotFoundException.h"
#include "Engine/Debug/Exceptions/CLRInnerException.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Platform/StringUtils.h"
#include "Engine/Platform/File.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/Threading.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/tokentype.h>
#endif
MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options)
: _domain(domain)
, _isLoaded(false)
, _isLoading(false)
, _isDependency(false)
, _isFileLocked(false)
, _hasCachedClasses(false)
, _reloadCount(0)
, _name(name)
, _options(options)
{
}
MAssembly::~MAssembly()
{
Unload();
}
String MAssembly::ToString() const
{
return _name.ToString();
}
bool MAssembly::Load(const String& assemblyPath)
{
if (IsLoaded())
return false;
PROFILE_CPU();
ZoneText(*assemblyPath, assemblyPath.Length());
// Check file path
if (!FileSystem::FileExists(assemblyPath))
{
Log::FileNotFoundException ex(assemblyPath);
return true;
}
// Start
const auto startTime = DateTime::NowUTC();
OnLoading();
// Load
bool failed;
if (_options.KeepManagedFileLocked)
failed = LoadDefault(assemblyPath);
else
failed = LoadWithImage(assemblyPath);
if (failed)
{
OnLoadFailed();
return true;
}
// End
OnLoaded(startTime);
return false;
}
#if USE_MONO
bool MAssembly::Load(MonoImage* monoImage)
{
if (IsLoaded())
return false;
PROFILE_CPU();
#if TRACY_ENABLE
const StringAnsiView monoImageName(mono_image_get_name(monoImage));
ZoneText(*monoImageName, monoImageName.Length());
#endif
// Ensure to be unloaded
Unload();
// Start
const auto startTime = DateTime::NowUTC();
OnLoading();
// Load
_monoAssembly = mono_image_get_assembly(monoImage);
if (_monoAssembly == nullptr)
{
OnLoadFailed();
return true;
}
_monoImage = monoImage;
_isDependency = true;
_hasCachedClasses = false;
// End
OnLoaded(startTime);
return false;
}
#endif
void MAssembly::Unload(bool isReloading)
{
if (!IsLoaded())
return;
PROFILE_CPU();
Unloading(this);
// Close runtime
#if USE_MONO
if (_monoImage)
{
if (isReloading)
{
LOG(Info, "Unloading managed assembly \'{0}\' (is reloading)", String(_name));
mono_assembly_close(_monoAssembly);
}
else
{
// NOTE: do not try to close all the opened images
// that will cause the domain unload to crash because
// the images have already been closed (double free)
}
_monoAssembly = nullptr;
_monoImage = nullptr;
}
#endif
// Cleanup
_debugData.Resize(0);
_assemblyPath.Clear();
_isFileLocked = false;
_isDependency = false;
_isLoading = false;
_isLoaded = false;
_hasCachedClasses = false;
_classes.ClearDelete();
Unloaded(this);
}
MClass* MAssembly::GetClass(const StringAnsiView& fullname) const
{
// Check state
if (!IsLoaded())
{
Log::InvalidOperationException(TEXT("MAssembly was not yet loaded or loading was in progress"));
return nullptr;
}
StringAnsiView key(fullname);
// Special case for reference
if (fullname[fullname.Length() - 1] == '&')
key = StringAnsiView(key.Get(), key.Length() - 1);
// Find class by name
const auto& classes = GetClasses();
MClass* result = nullptr;
classes.TryGet(key, result);
#if 0
if (!result)
{
LOG(Warning, "Failed to find class {0} in assembly {1}. Classes:", String(fullname), ToString());
for (auto i = classes.Begin(); i.IsNotEnd(); ++i)
{
LOG(Warning, " - {0}", String(i->Key));
}
}
#endif
return result;
}
#if USE_MONO
MClass* MAssembly::GetClass(MonoClass* monoClass) const
{
if (monoClass == nullptr || !IsLoaded() || mono_class_get_image(monoClass) != _monoImage)
return nullptr;
// Find class by native pointer
const auto& classes = GetClasses();
const auto typeToken = mono_class_get_type_token(monoClass);
for (auto i = classes.Begin(); i.IsNotEnd(); ++i)
{
MonoClass* e = i->Value->GetNative();
if (e == monoClass || mono_class_get_type_token(e) == typeToken)
{
return i->Value;
}
}
#if 0
{
LOG(Warning, "Failed to find class {0}.{1} in assembly {2}. Classes:", String(mono_class_get_namespace(monoClass)), String(mono_class_get_name(monoClass)), ToString());
for (auto i = classes.Begin(); i.IsNotEnd(); ++i)
{
LOG(Warning, " - {0}", String(i->Key));
}
}
#endif
return nullptr;
}
MonoReflectionAssembly* MAssembly::GetNative() const
{
if (!_monoAssembly)
return nullptr;
return mono_assembly_get_object(mono_domain_get(), _monoAssembly);
}
#endif
const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
{
if (_hasCachedClasses || !IsLoaded())
return _classes;
PROFILE_CPU();
const auto startTime = DateTime::NowUTC();
#if USE_MONO
#if TRACY_ENABLE
const StringAnsiView monoImageName(mono_image_get_name(_monoImage));
ZoneText(*monoImageName, monoImageName.Length());
#endif
ScopeLock lock(_locker);
if (_hasCachedClasses)
return _classes;
ASSERT(_classes.IsEmpty());
const int32 numRows = mono_image_get_table_rows(_monoImage, MONO_TABLE_TYPEDEF);
_classes.EnsureCapacity(numRows * 4);
for (int32 i = 1; i < numRows; i++) // Skip <Module> class
{
MonoClass* klass = mono_class_get(_monoImage, (i + 1) | MONO_TOKEN_TYPE_DEF);
// Peek the typename
MString fullname;
MUtils::GetClassFullname(klass, fullname);
// Create class object
auto mclass = New<MClass>(this, klass, fullname);
_classes.Add(fullname, mclass);
}
#endif
const auto endTime = DateTime::NowUTC();
LOG(Info, "Caching classes for assembly {0} took {1}ms", String(_name), (int32)(endTime - startTime).GetTotalMilliseconds());
#if 0
for (auto i = _classes.Begin(); i.IsNotEnd(); ++i)
LOG(Info, "Class: {0}", String(i->Value->GetFullName()));
#endif
_hasCachedClasses = true;
return _classes;
}
bool MAssembly::LoadDefault(const String& assemblyPath)
{
#if USE_MONO
// With this method of loading we need to make sure, we won't try to load assembly again if its loaded somewhere.
auto assembly = mono_domain_assembly_open(_domain->GetNative(), assemblyPath.ToStringAnsi().Get());
if (!assembly)
{
return true;
}
auto assemblyImage = mono_assembly_get_image(assembly);
if (!assembly)
{
mono_assembly_close(assembly);
return true;
}
_monoAssembly = assembly;
_monoImage = assemblyImage;
#endif
// Set state
_isDependency = false;
_hasCachedClasses = false;
_isFileLocked = true;
_assemblyPath = assemblyPath;
// Register in domain
_domain->_assemblies[_name] = this;
return false;
}
bool MAssembly::LoadWithImage(const String& assemblyPath)
{
// Lock file only for loading operation
_isFileLocked = true;
// Load assembly file data
Array<byte> data;
File::ReadAllBytes(assemblyPath, data);
#if USE_MONO
// Init Mono image
MonoImageOpenStatus status;
const auto name = assemblyPath.ToStringAnsi();
const auto assemblyImage = mono_image_open_from_data_with_name(reinterpret_cast<char*>(data.Get()), data.Count(), true, &status, false, name.Get());
if (status != MONO_IMAGE_OK || assemblyImage == nullptr)
{
Log::CLRInnerException(TEXT("Mono assembly image is invalid at ") + assemblyPath);
return true;
}
// Setup assembly
const auto assembly = mono_assembly_load_from_full(assemblyImage, name.Substring(0, name.Length() - 3).Get(), &status, false);
mono_image_close(assemblyImage);
if (status != MONO_IMAGE_OK || assembly == nullptr)
{
Log::CLRInnerException(TEXT("Mono assembly image is corrupted at ") + assemblyPath);
return true;
}
#if MONO_DEBUG_ENABLE
// Try to load debug symbols (use portable PDB format)
const auto pdbPath = String(StringUtils::GetPathWithoutExtension(assemblyPath)) + TEXT(".pdb");
if (FileSystem::FileExists(pdbPath))
{
// Load .pdb file
File::ReadAllBytes(pdbPath, _debugData);
// Attach debugging symbols to image
if (_debugData.HasItems())
{
mono_debug_open_image_from_memory(assemblyImage, _debugData.Get(), _debugData.Count());
}
}
// TODO: load pdbs for custom third-party libs referenced by game assemblies for debugging
#if 0
// Hack to load debug information for Newtonsoft.Json (enable it to debug C# code of json lib)
if (assemblyPath.EndsWith(TEXT("FlaxEngine.CSharp.dll")))
{
static Array<byte> NewtonsoftJsonDebugData;
File::ReadAllBytes(String(StringUtils::GetDirectoryName(assemblyPath)) / TEXT("Newtonsoft.Json.pdb"), NewtonsoftJsonDebugData);
if (NewtonsoftJsonDebugData.HasItems())
{
StringAnsi tmp(String(StringUtils::GetDirectoryName(assemblyPath)) / TEXT("Newtonsoft.Json.dll"));
MonoAssembly* a = mono_assembly_open(tmp.Get(), &status);
if (a)
{
mono_debug_open_image_from_memory(mono_assembly_get_image(a), NewtonsoftJsonDebugData.Get(), NewtonsoftJsonDebugData.Count());
}
}
}
#endif
#endif
_monoAssembly = assembly;
_monoImage = assemblyImage;
#endif
// Set state
_isDependency = false;
_hasCachedClasses = false;
_isFileLocked = false;
_assemblyPath = assemblyPath;
return false;
}
void MAssembly::OnLoading()
{
Loading(this);
_isLoading = true;
// Pick a domain
if (_domain == nullptr)
_domain = MCore::GetActiveDomain();
}
void MAssembly::OnLoaded(const DateTime& startTime)
{
// Register in domain
_domain->_assemblies[_name] = this;
_isLoaded = true;
_isLoading = false;
if (_options.PreCacheOnLoad)
GetClasses();
const auto endTime = DateTime::NowUTC();
LOG(Info, "Assembly {0} loaded in {1}ms", String(_name), (int32)(endTime - startTime).GetTotalMilliseconds());
Loaded(this);
}
void MAssembly::OnLoadFailed()
{
_isLoading = false;
LoadFailed(this);
}

View File

@@ -3,7 +3,6 @@
#pragma once
#include "MTypes.h"
#include "MAssemblyOptions.h"
#include "Engine/Core/Delegate.h"
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Array.h"
@@ -16,44 +15,41 @@
class FLAXENGINE_API MAssembly
{
friend MDomain;
public:
friend Scripting;
typedef Dictionary<MString, MClass*> ClassesDictionary;
public:
typedef Dictionary<StringAnsi, MClass*> ClassesDictionary;
private:
#if USE_MONO
MonoAssembly* _monoAssembly = nullptr;
MonoImage* _monoImage = nullptr;
#elif USE_NETCORE
StringAnsi _fullname;
void* _handle = nullptr;
#endif
MDomain* _domain;
int32 _isLoaded : 1;
int32 _isLoading : 1;
int32 _isDependency : 1;
int32 _isFileLocked : 1;
mutable int32 _hasCachedClasses : 1;
mutable ClassesDictionary _classes;
CriticalSection _locker;
int32 _reloadCount;
MString _name;
StringAnsi _name;
String _assemblyPath;
Array<byte> _debugData;
const MAssemblyOptions _options;
public:
/// <summary>
/// Initializes a new instance of the <see cref="MAssembly"/> class.
/// </summary>
/// <param name="domain">The assembly domain.</param>
/// <param name="name">The assembly name.</param>
/// <param name="options">The assembly options.</param>
MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options);
MAssembly(MDomain* domain, const StringAnsiView& name);
/// <summary>
/// Finalizes an instance of the <see cref="MAssembly"/> class.
@@ -61,7 +57,6 @@ public:
~MAssembly();
public:
/// <summary>
/// Managed assembly actions delegate type.
/// </summary>
@@ -93,7 +88,6 @@ public:
AssemblyDelegate Unloaded;
public:
/// <summary>
/// Returns true if assembly is during loading state.
/// </summary>
@@ -113,7 +107,7 @@ public:
/// <summary>
/// Gets the assembly name.
/// </summary>
FORCE_INLINE const MString& GetName() const
FORCE_INLINE const StringAnsi& GetName() const
{
return _name;
}
@@ -143,39 +137,30 @@ public:
}
#if USE_MONO
/// <summary>
/// Gets the Mono assembly.
/// </summary>
FORCE_INLINE MonoAssembly* GetMonoAssembly() const
{
return _monoAssembly;
}
/// <summary>
/// Gets the Mono image.
/// </summary>
FORCE_INLINE MonoImage* GetMonoImage() const
{
return _monoImage;
}
#elif USE_NETCORE
FORCE_INLINE void* GetHandle() const
{
return _handle;
}
#endif
/// <summary>
/// Gets the options that assembly was created with.
/// </summary>
FORCE_INLINE const MAssemblyOptions& GetOptions() const
{
return _options;
}
public:
/// <summary>
/// Loads assembly for domain.
/// </summary>
/// <param name="assemblyPath">The assembly path.</param>
/// <param name="nativePath">The optional path to the native code assembly (eg. if C# assembly contains bindings).</param>
/// <returns>True if cannot load, otherwise false</returns>
bool Load(const String& assemblyPath);
bool Load(const String& assemblyPath, const StringView& nativePath = StringView::Empty);
#if USE_MONO
/// <summary>
@@ -193,7 +178,6 @@ public:
void Unload(bool isReloading = false);
public:
/// <summary>
/// Attempts to find a managed class with the specified namespace and name in this assembly. Returns null if one cannot be found.
/// </summary>
@@ -212,30 +196,18 @@ public:
/// <summary>
/// Gets the native of the assembly (for the current domain). Can be used to pass to the scripting backend as a parameter.
/// </summary>
/// <returns>The native assembly object.</returns>
MonoReflectionAssembly* GetNative() const;
#endif
/// <summary>
/// Gets the classes lookup cache. Performs full initialization if not cached. The result cache contains all classes from the assembly.
/// </summary>
/// <returns>The cache.</returns>
const ClassesDictionary& GetClasses() const;
private:
/// <summary>
/// Loads the assembly for domain.
/// </summary>
/// <returns>True if failed, otherwise false.</returns>
bool LoadDefault(const String& assemblyPath);
/// <summary>
/// Loads the assembly for domain from non-blocking image.
/// </summary>
/// <returns>True if failed, otherwise false.</returns>
bool LoadWithImage(const String& assemblyPath);
bool LoadCorlib();
bool LoadImage(const String& assemblyPath, const StringView& nativePath);
bool UnloadImage(bool isReloading);
void OnLoading();
void OnLoaded(const struct DateTime& startTime);
void OnLoadFailed();

View File

@@ -1,32 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Types/BaseTypes.h"
/// <summary>
/// The options for creation of the managed assembly.
/// </summary>
struct MAssemblyOptions
{
/// <summary>
/// Should assembly cache classes on Load method.
/// </summary>
int32 PreCacheOnLoad : 1;
/// <summary>
/// Locks DLL/exe file with managed code.
/// </summary>
int32 KeepManagedFileLocked : 1;
/// <summary>
/// Initializes a new instance of the <see cref="MAssemblyOptions"/> struct.
/// </summary>
/// <param name="preCacheOnLoad">if set to <c>true</c> to precache assembly metadata on load.</param>
/// <param name="keepManagedFileLocked">if set to <c>true</c> keep managed file locked after load.</param>
MAssemblyOptions(bool preCacheOnLoad = true, bool keepManagedFileLocked = false)
: PreCacheOnLoad(preCacheOnLoad)
, KeepManagedFileLocked(keepManagedFileLocked)
{
}
};

View File

@@ -1,442 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MClass.h"
#include "MType.h"
#include "MTypes.h"
#include "MField.h"
#include "MProperty.h"
#include "MMethod.h"
#include "MEvent.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Core/Log.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attrdefs.h>
#define GET_CUSTOM_ATTR() (MonoCustomAttrInfo*)(_attrInfo ? _attrInfo : _attrInfo = mono_custom_attrs_from_class(_monoClass))
#endif
#if USE_NETCORE
#include "Engine/Scripting/DotNet/CoreCLR.h"
#endif
#if USE_MONO
MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname)
: _assembly(parentAssembly)
, _fullname(fullname)
, _visibility(MVisibility::Private)
, _hasCachedProperties(false)
, _hasCachedFields(false)
, _hasCachedMethods(false)
, _hasCachedAttributes(false)
, _hasCachedEvents(false)
, _isStatic(false)
, _isSealed(false)
, _isAbstract(false)
, _isInterface(false)
{
_monoClass = monoClass;
ASSERT(monoClass);
const uint32_t flags = mono_class_get_flags(monoClass);
switch (flags & MONO_TYPE_ATTR_VISIBILITY_MASK)
{
case MONO_TYPE_ATTR_NOT_PUBLIC:
case MONO_TYPE_ATTR_NESTED_PRIVATE:
_visibility = MVisibility::Private;
break;
case MONO_TYPE_ATTR_PUBLIC:
case MONO_TYPE_ATTR_NESTED_PUBLIC:
_visibility = MVisibility::Public;
break;
case MONO_TYPE_ATTR_NESTED_FAMILY:
case MONO_TYPE_ATTR_NESTED_ASSEMBLY:
_visibility = MVisibility::Internal;
break;
case MONO_TYPE_ATTR_NESTED_FAM_OR_ASSEM:
_visibility = MVisibility::ProtectedInternal;
break;
case MONO_TYPE_ATTR_NESTED_FAM_AND_ASSEM:
_visibility = MVisibility::PrivateProtected;
break;
default:
CRASH;
}
const uint32_t staticClassFlags = MONO_TYPE_ATTR_ABSTRACT | MONO_TYPE_ATTR_SEALED;
_isStatic = (flags & staticClassFlags) == staticClassFlags;
_isSealed = !_isStatic && (flags & MONO_TYPE_ATTR_SEALED) == MONO_TYPE_ATTR_SEALED;
_isAbstract = !_isStatic && (flags & MONO_TYPE_ATTR_ABSTRACT) == MONO_TYPE_ATTR_ABSTRACT;
_isInterface = (flags & MONO_TYPE_ATTR_CLASS_SEMANTIC_MASK) == MONO_TYPE_ATTR_INTERFACE;
}
#endif
MClass::~MClass()
{
#if !COMPILE_WITHOUT_CSHARP
#if USE_MONO
if (_attrInfo)
mono_custom_attrs_free((MonoCustomAttrInfo*)_attrInfo);
#endif
_fields.ClearDelete();
_properties.ClearDelete();
_methods.ClearDelete();
_attributes.ClearDelete();
_events.ClearDelete();
#endif
}
bool MClass::IsGeneric() const
{
return _fullname.FindLast('`') != -1;
}
MType MClass::GetType() const
{
#if USE_MONO
return MType(mono_class_get_type(_monoClass));
#else
return MType();
#endif
}
MClass* MClass::GetBaseClass() const
{
#if USE_MONO
MonoClass* monoBase = mono_class_get_parent(_monoClass);
if (monoBase == nullptr)
return nullptr;
return Scripting::FindClass(monoBase);
#else
return nullptr;
#endif
}
bool MClass::IsSubClassOf(const MClass* klass) const
{
#if USE_MONO
return klass && mono_class_is_subclass_of(_monoClass, klass->GetNative(), false) != 0;
#else
return false;
#endif
}
#if USE_MONO
bool MClass::IsSubClassOf(const MonoClass* monoClass) const
{
return monoClass && mono_class_is_subclass_of(_monoClass, (MonoClass*)monoClass, true) != 0;
}
#endif
bool MClass::HasInterface(const MClass* klass) const
{
#if USE_MONO
return klass && mono_class_is_assignable_from(klass->GetNative(), _monoClass) != 0;
#else
return false;
#endif
}
bool MClass::IsInstanceOfType(MObject* object) const
{
if (object == nullptr)
return false;
#if USE_MONO
MonoClass* monoClass = mono_object_get_class(object);
return mono_class_is_subclass_of(monoClass, _monoClass, false) != 0;
#else
return false;
#endif
}
uint32 MClass::GetInstanceSize() const
{
#if USE_MONO
uint32 dummy = 0;
if (mono_class_is_valuetype(_monoClass))
return mono_class_value_size(_monoClass, &dummy);
return mono_class_instance_size(_monoClass);
#else
return 0;
#endif
}
MMethod* MClass::FindMethod(const char* name, int32 numParams, bool checkBaseClasses)
{
auto method = GetMethod(name, numParams);
if (!method && checkBaseClasses)
{
auto base = GetBaseClass();
if (base)
method = base->FindMethod(name, numParams, true);
}
return method;
}
MMethod* MClass::GetMethod(const char* name, int32 numParams)
{
// Lookup for cached method
for (int32 i = 0; i < _methods.Count(); i++)
{
if (_methods[i]->GetName() == name && _methods[i]->GetParametersCount() == numParams)
return _methods[i];
}
#if USE_MONO
// Find Mono method
MonoMethod* monoMethod = mono_class_get_method_from_name(_monoClass, name, numParams);
if (monoMethod == nullptr)
return nullptr;
// Create method
auto method = New<MMethod>(monoMethod, name, this);
_methods.Add(method);
return method;
#else
return nullptr;
#endif
}
const Array<MMethod*>& MClass::GetMethods()
{
if (_hasCachedMethods)
return _methods;
#if USE_MONO
void* iter = nullptr;
MonoMethod* curClassMethod;
while ((curClassMethod = mono_class_get_methods(_monoClass, &iter)))
{
// Check if has not been added
bool isMissing = true;
for (int32 i = 0; i < _methods.Count(); i++)
{
if (_methods[i]->GetNative() == curClassMethod)
{
isMissing = false;
break;
}
}
if (isMissing)
{
// Create method
auto method = New<MMethod>(curClassMethod, this);
_methods.Add(method);
}
}
#endif
_hasCachedMethods = true;
return _methods;
}
MField* MClass::GetField(const char* name)
{
// Lookup for cached field
for (int32 i = 0; i < _fields.Count(); i++)
{
if (_fields[i]->GetName() == name)
return _fields[i];
}
#if USE_MONO
// Find mono field
MonoClassField* field = mono_class_get_field_from_name(_monoClass, name);
if (field == nullptr)
return nullptr;
// Create field
auto mfield = New<MField>(field, name, this);
_fields.Add(mfield);
return mfield;
#else
return nullptr;
#endif
}
const Array<MField*>& MClass::GetFields()
{
if (_hasCachedFields)
return _fields;
#if USE_MONO
void* iter = nullptr;
MonoClassField* curClassField;
while ((curClassField = mono_class_get_fields(_monoClass, &iter)))
{
const char* fieldName = mono_field_get_name(curClassField);
GetField(fieldName);
}
#endif
_hasCachedFields = true;
return _fields;
}
MEvent* MClass::GetEvent(const char* name)
{
GetEvents();
for (int32 i = 0; i < _events.Count(); i++)
{
if (_events[i]->GetName() == name)
return _events[i];
}
return nullptr;
}
const Array<MEvent*>& MClass::GetEvents()
{
if (_hasCachedEvents)
return _events;
#if USE_MONO
void* iter = nullptr;
MonoEvent* curEvent;
while ((curEvent = mono_class_get_events(_monoClass, &iter)))
{
const char* name = mono_event_get_name(curEvent);
bool missing = true;
for (int32 i = 0; i < _events.Count(); i++)
{
if (_events[i]->GetName() == name)
{
missing = false;
break;
}
}
if (missing)
{
auto result = New<MEvent>(curEvent, name, this);
_events.Add(result);
}
}
#endif
_hasCachedEvents = true;
return _events;
}
MProperty* MClass::GetProperty(const char* name)
{
// Lookup for cached property
for (int32 i = 0; i < _properties.Count(); i++)
{
if (_properties[i]->GetName() == name)
return _properties[i];
}
#if USE_MONO
// Find mono property
MonoProperty* monoProperty = mono_class_get_property_from_name(_monoClass, name);
if (monoProperty == nullptr)
return nullptr;
// Create method
auto mproperty = New<MProperty>(monoProperty, name, this);
_properties.Add(mproperty);
return mproperty;
#else
return nullptr;
#endif
}
const Array<MProperty*>& MClass::GetProperties()
{
if (_hasCachedProperties)
return _properties;
#if USE_MONO
void* iter = nullptr;
MonoProperty* curClassProperty;
while ((curClassProperty = mono_class_get_properties(_monoClass, &iter)))
{
const char* propertyName = mono_property_get_name(curClassProperty);
GetProperty(propertyName);
}
#endif
_hasCachedProperties = true;
return _properties;
}
MObject* MClass::CreateInstance() const
{
#if USE_MONO
MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass);
if (!mono_class_is_valuetype(_monoClass))
mono_runtime_object_init(obj);
return obj;
#else
return nullptr;
#endif
}
MObject* MClass::CreateInstance(void** params, uint32 numParams)
{
#if USE_MONO
MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass);
const auto constructor = GetMethod(".ctor", numParams);
ASSERT(constructor);
constructor->Invoke(obj, params, nullptr);
return obj;
#else
return nullptr;
#endif
}
bool MClass::HasAttribute(const MClass* monoClass) const
{
#if USE_NETCORE
return CoreCLR::HasCustomAttribute(_monoClass, monoClass->GetNative());
#elif USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
#else
return false;
#endif
}
bool MClass::HasAttribute() const
{
#if USE_NETCORE
return CoreCLR::HasCustomAttribute(_monoClass);
#elif USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo && attrInfo->num_attrs > 0;
#else
return false;
#endif
}
MObject* MClass::GetAttribute(const MClass* monoClass) const
{
#if USE_NETCORE
return (MObject*)CoreCLR::GetCustomAttribute(_monoClass, monoClass->GetNative());
#elif USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo ? mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()) : nullptr;
#else
return nullptr;
#endif
}
const Array<MObject*>& MClass::GetAttributes()
{
if (_hasCachedAttributes)
return _attributes;
_hasCachedAttributes = true;
#if USE_NETCORE
_attributes = MoveTemp(CoreCLR::GetCustomAttributes(_monoClass));
#elif USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
if (attrInfo == nullptr)
return _attributes;
MonoArray* monoAttributesArray = mono_custom_attrs_construct(attrInfo);
const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length);
for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
mono_custom_attrs_free(attrInfo);
#endif
return _attributes;
}

View File

@@ -10,44 +10,49 @@
/// </summary>
class FLAXENGINE_API MClass
{
friend MCore;
private:
#if USE_MONO
MonoClass* _monoClass;
mutable void* _attrInfo = nullptr;
#elif USE_NETCORE
void* _handle;
StringAnsi _name;
StringAnsi _namespace_;
uint32 _types = 0;
mutable uint32 _size = 0;
#endif
const MAssembly* _assembly;
MString _fullname;
StringAnsi _fullname;
Array<MMethod*> _methods;
Array<MField*> _fields;
Array<MProperty*> _properties;
Array<MObject*> _attributes;
Array<MEvent*> _events;
mutable Array<MMethod*> _methods;
mutable Array<MField*> _fields;
mutable Array<MProperty*> _properties;
mutable Array<MObject*> _attributes;
mutable Array<MEvent*> _events;
mutable Array<MClass*> _interfaces;
MVisibility _visibility;
int32 _hasCachedProperties : 1;
int32 _hasCachedFields : 1;
int32 _hasCachedMethods : 1;
int32 _hasCachedAttributes : 1;
int32 _hasCachedEvents : 1;
mutable int32 _hasCachedProperties : 1;
mutable int32 _hasCachedFields : 1;
mutable int32 _hasCachedMethods : 1;
mutable int32 _hasCachedAttributes : 1;
mutable int32 _hasCachedEvents : 1;
mutable int32 _hasCachedInterfaces : 1;
int32 _isStatic : 1;
int32 _isSealed : 1;
int32 _isAbstract : 1;
int32 _isInterface : 1;
int32 _isValueType : 1;
int32 _isEnum : 1;
public:
#if USE_MONO
/// <summary>
/// Initializes a new instance of the <see cref="MClass"/> class.
/// </summary>
/// <param name="parentAssembly">The parent assembly.</param>
/// <param name="monoClass">The Mono class.</param>
/// <param name="fullname">The fullname.</param>
MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname);
MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const StringAnsi& fullname);
#elif USE_NETCORE
MClass(const MAssembly* parentAssembly, void* handle, const char* name, const char* fullname, const char* namespace_, MTypeAttributes typeAttributes);
#endif
/// <summary>
@@ -56,7 +61,6 @@ public:
~MClass();
public:
/// <summary>
/// Gets the parent assembly.
/// </summary>
@@ -68,11 +72,21 @@ public:
/// <summary>
/// Gets the full name of the class (namespace and typename).
/// </summary>
FORCE_INLINE const MString& GetFullName() const
FORCE_INLINE const StringAnsi& GetFullName() const
{
return _fullname;
}
/// <summary>
/// Gets the name of the class.
/// </summary>
StringAnsiView GetName() const;
/// <summary>
/// Gets the namespace of the class.
/// </summary>
StringAnsiView GetNamespace() const;
#if USE_MONO
/// <summary>
/// Gets the Mono class handle.
@@ -81,6 +95,11 @@ public:
{
return _monoClass;
}
#elif USE_NETCORE
FORCE_INLINE void* GetNative() const
{
return _handle;
}
#endif
/// <summary>
@@ -123,15 +142,34 @@ public:
return _isInterface != 0;
}
/// <summary>
/// Gets if class is value type (eg. enum or structure) but not reference type (eg. class, string, array, interface)
/// </summary>
FORCE_INLINE bool IsValueType() const
{
return _isValueType != 0;
}
/// <summary>
/// Gets if class is enumeration
/// </summary>
FORCE_INLINE bool IsEnum() const
{
return _isEnum != 0;
}
/// <summary>
/// Gets if class is generic
/// </summary>
bool IsGeneric() const;
bool IsGeneric() const
{
return _fullname.FindLast('`') != -1;
}
/// <summary>
/// Gets the class type.
/// </summary>
MType GetType() const;
MType* GetType() const;
/// <summary>
/// Returns the base class of this class. Null if this class has no base.
@@ -142,17 +180,9 @@ public:
/// Checks if this class is a sub class of the specified class (including any derived types).
/// </summary>
/// <param name="klass">The class.</param>
/// <param name="checkInterfaces">True if check interfaces, otherwise just base class.</param>
/// <returns>True if this class is a sub class of the specified class.</returns>
bool IsSubClassOf(const MClass* klass) const;
#if USE_MONO
/// <summary>
/// Checks if this class is a sub class of the specified class (including any derived types).
/// </summary>
/// <param name="monoClass">The Mono class.</param>
/// <returns>True if this class is a sub class of the specified class.</returns>
bool IsSubClassOf(const MonoClass* monoClass) const;
#endif
bool IsSubClassOf(const MClass* klass, bool checkInterfaces = false) const;
/// <summary>
/// Checks if this class implements the specified interface (including any base types).
@@ -173,8 +203,12 @@ public:
/// </summary>
uint32 GetInstanceSize() const;
public:
/// <summary>
/// Returns the class of the array type elements.
/// </summary>
MClass* GetElementClass() const;
public:
/// <summary>
/// Returns an object referencing a method with the specified name and number of parameters. Optionally checks the base classes.
/// </summary>
@@ -182,7 +216,17 @@ public:
/// <param name="numParams">The method parameters count.</param>
/// <param name="checkBaseClasses">True if check base classes when searching for the given method.</param>
/// <returns>The method or null if failed to find it.</returns>
MMethod* FindMethod(const char* name, int32 numParams, bool checkBaseClasses);
MMethod* FindMethod(const char* name, int32 numParams, bool checkBaseClasses = true) const
{
MMethod* method = GetMethod(name, numParams);
if (!method && checkBaseClasses)
{
MClass* base = GetBaseClass();
if (base)
method = base->FindMethod(name, numParams, true);
}
return method;
}
/// <summary>
/// Returns an object referencing a method with the specified name and number of parameters.
@@ -191,88 +235,73 @@ public:
/// <param name="name">The method name.</param>
/// <param name="numParams">The method parameters count.</param>
/// <returns>The method or null if failed to get it.</returns>
MMethod* GetMethod(const char* name, int32 numParams = 0);
MMethod* GetMethod(const char* name, int32 numParams = 0) const;
/// <summary>
/// Returns all methods belonging to this class.
/// </summary>
/// <remarks>
/// Be aware this will not include the methods of any base classes.
/// </remarks>
/// <remarks>Be aware this will not include the methods of any base classes.</remarks>
/// <returns>The list of methods.</returns>
const Array<MMethod*>& GetMethods();
const Array<MMethod*>& GetMethods() const;
/// <summary>
/// Returns an object referencing a field with the specified name.
/// </summary>
/// <remarks>
/// Does not query base class fields.
/// Returns null if field cannot be found.
/// </remarks>
/// <remarks>Does not query base class fields. Returns null if field cannot be found.</remarks>
/// <param name="name">The field name.</param>
/// <returns>The field or null if failed.</returns>
MField* GetField(const char* name);
MField* GetField(const char* name) const;
/// <summary>
/// Returns all fields belonging to this class.
/// </summary>
/// <remarks>
/// Be aware this will not include the fields of any base classes.
/// </remarks>
/// <remarks>Be aware this will not include the fields of any base classes.</remarks>
/// <returns>The list of fields.</returns>
const Array<MField*>& GetFields();
const Array<MField*>& GetFields() const;
/// <summary>
/// Returns an object referencing a event with the specified name.
/// </summary>
/// <param name="name">The event name.</param>
/// <returns>The event object.</returns>
MEvent* GetEvent(const char* name);
MEvent* GetEvent(const char* name) const;
/// <summary>
/// Returns all events belonging to this class.
/// </summary>
/// <returns>The list of events.</returns>
const Array<MEvent*>& GetEvents();
const Array<MEvent*>& GetEvents() const;
/// <summary>
/// Returns an object referencing a property with the specified name.
/// </summary>
/// <remarks>
/// Does not query base class properties.
/// Returns null if property cannot be found.
/// </remarks>
/// <remarks>Does not query base class properties. Returns null if property cannot be found.</remarks>
/// <param name="name">The property name.</param>
/// <returns>The property.</returns>
MProperty* GetProperty(const char* name);
MProperty* GetProperty(const char* name) const;
/// <summary>
/// Returns all properties belonging to this class.
/// </summary>
/// <remarks>
/// Be aware this will not include the properties of any base classes.
/// </remarks>
/// <remarks>Be aware this will not include the properties of any base classes.</remarks>
/// <returns>The list of properties.</returns>
const Array<MProperty*>& GetProperties();
const Array<MProperty*>& GetProperties() const;
/// <summary>
/// Returns all interfaces implemented by this class (excluding interfaces from base classes).
/// </summary>
/// <remarks>Be aware this will not include the interfaces of any base classes.</remarks>
/// <returns>The list of interfaces.</returns>
const Array<MClass*>& GetInterfaces() const;
public:
/// <summary>
/// Creates a new instance of this class and constructs it.
/// </summary>
/// <returns>The created managed object.</returns>
MObject* CreateInstance() const;
/// <summary>
/// Creates a new instance of this class and then constructs it using the constructor with the specified number of parameters.
/// </summary>
/// <param name="params">The array containing pointers to constructor parameters. Array length must be equal to number of parameters.</param>
/// <param name="numParams">The number of parameters the constructor accepts.</param>
/// <returns>The created managed object.</returns>
MObject* CreateInstance(void** params, uint32 numParams);
public:
/// <summary>
/// Checks if class has an attribute of the specified type.
/// </summary>
@@ -297,5 +326,5 @@ public:
/// Returns an instance of all attributes connected with given class. Returns null if the class doesn't have any attributes.
/// </summary>
/// <returns>The array of attribute objects.</returns>
const Array<MObject*>& GetAttributes();
const Array<MObject*>& GetAttributes() const;
};

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,6 @@
class FLAXENGINE_API MCore
{
public:
/// <summary>
/// Gets the root domain.
/// </summary>
@@ -26,16 +25,15 @@ public:
/// </summary>
/// <param name="domainName">The domain name to create.</param>
/// <returns>The domain object.</returns>
static MDomain* CreateDomain(const MString& domainName);
static MDomain* CreateDomain(const StringAnsi& domainName);
/// <summary>
/// Unloads the domain.
/// </summary>
/// <param name="domainName">The domain name to remove.</param>
static void UnloadDomain(const MString& domainName);
static void UnloadDomain(const StringAnsi& domainName);
public:
/// <summary>
/// Initialize CLR Engine
/// </summary>
@@ -47,39 +45,139 @@ public:
/// </summary>
static void UnloadEngine();
/// <summary>
/// Attaches CLR runtime to the current thread. Use it to allow invoking managed runtime from native threads.
/// </summary>
static void AttachThread();
/// <summary>
/// Exits the managed runtime thread. Clears the thread data and sets its exit code to 0. Use it before ending the native thread that uses AttachThread.
/// </summary>
static void ExitThread();
public:
/// <summary>
/// Utilities for C# object management.
/// </summary>
struct FLAXENGINE_API Object
{
static MObject* Box(void* value, const MClass* klass);
static void* Unbox(MObject* obj);
static MObject* New(const MClass* klass);
static void Init(MObject* obj);
static MClass* GetClass(MObject* obj);
static MString* ToString(MObject* obj);
static int32 GetHashCode(MObject* obj);
};
/// <summary>
/// Utilities for C# string management.
/// </summary>
struct FLAXENGINE_API String
{
static MString* GetEmpty(MDomain* domain = nullptr);
static MString* New(const char* str, int32 length, MDomain* domain = nullptr);
static MString* New(const Char* str, int32 length, MDomain* domain = nullptr);
static StringView GetChars(MString* obj);
};
/// <summary>
/// Utilities for C# array management.
/// </summary>
struct FLAXENGINE_API Array
{
static MArray* New(const MClass* elementKlass, int32 length);
static MClass* GetClass(MClass* elementKlass);
static int32 GetLength(const MArray* obj);
static void* GetAddress(const MArray* obj);
template<typename T>
FORCE_INLINE static T* GetAddress(const MArray* obj)
{
return (T*)GetAddress(obj);
}
};
/// <summary>
/// Utilities for GC Handle management.
/// </summary>
struct FLAXENGINE_API GCHandle
{
static MGCHandle New(MObject* obj, bool pinned);
static MGCHandle NewWeak(MObject* obj, bool trackResurrection);
static MObject* GetTarget(const MGCHandle& handle);
static void Free(const MGCHandle& handle);
};
/// <summary>
/// Helper utilities for C# garbage collector.
/// </summary>
class GC
struct FLAXENGINE_API GC
{
public:
/// <summary>
/// Forces an immediate garbage collection of all generations.
/// </summary>
static void Collect();
/// <summary>
/// Forces an immediate garbage collection of the given generation.
/// </summary>
/// <param name="generation">The target generation</param>
static void Collect(int32 generation);
/// <summary>
/// Suspends the current thread until the thread that is processing the queue of finalizers has emptied that queue.
/// </summary>
static void WaitForPendingFinalizers();
static void WriteRef(void* ptr, MObject* ref);
static void WriteValue(void* dst, void* src, int32 count, const MClass* klass);
static void WriteArrayRef(MArray* dst, MObject* ref, int32 index);
#if USE_NETCORE
static void* AllocateMemory(int32 size, bool coTaskMem = false);
static void FreeMemory(void* ptr, bool coTaskMem = false);
#endif
};
/// <summary>
/// Utilities for C# threads management.
/// </summary>
struct FLAXENGINE_API Thread
{
static void Attach();
static void Exit();
static bool IsAttached();
};
/// <summary>
/// Helper utilities for C# exceptions throwing.
/// </summary>
struct FLAXENGINE_API Exception
{
static void Throw(MObject* exception);
static MObject* GetNullReference();
static MObject* Get(const char* msg);
static MObject* GetArgument(const char* arg, const char* msg);
static MObject* GetArgumentNull(const char* arg);
static MObject* GetArgumentOutOfRange(const char* arg);
static MObject* GetNotSupported(const char* msg);
};
/// <summary>
/// Helper utilities for C# types information.
/// </summary>
struct FLAXENGINE_API Type
{
static ::String ToString(MType* type);
static MClass* GetClass(MType* type);
static int32 GetSize(MType* type);
static MTypes GetType(MType* type);
static bool IsPointer(MType* type);
static bool IsReference(MType* type);
#if USE_MONO
static MTypeObject* GetObject(MType* type);
static MType* Get(MTypeObject* type);
#endif
};
/// <summary>
/// Helper types cache from C# corlib and engine.
/// </summary>
struct FLAXENGINE_API TypeCache
{
static MClass* Void;
static MClass* Object;
static MClass* Byte;
static MClass* Boolean;
static MClass* SByte;
static MClass* Char;
static MClass* Int16;
static MClass* UInt16;
static MClass* Int32;
static MClass* UInt32;
static MClass* Int64;
static MClass* UInt64;
static MClass* IntPtr;
static MClass* UIntPtr;
static MClass* Single;
static MClass* Double;
static MClass* String;
};
};

View File

@@ -1,87 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MDomain.h"
#include "MCore.h"
#include "MAssembly.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Core/Log.h"
#include "Engine/Debug/Exceptions/ArgumentException.h"
#include "Engine/Debug/Exceptions/Exceptions.h"
#if USE_MONO
#include <mono/metadata/threads.h>
#endif
extern MDomain* MActiveDomain;
MDomain::MDomain(const MString& domainName)
: _domainName(domainName)
{
}
bool MDomain::SetCurrentDomain(bool force)
{
#if USE_MONO
if (mono_domain_set(_monoDomain, force) == 0)
return false;
#endif
MActiveDomain = this;
return true;
}
MAssembly* MDomain::CreateEmptyAssembly(const MString& assemblyName, const MAssemblyOptions options)
{
// Validates if assembly is already open
if (_assemblies.ContainsKey(assemblyName))
{
Log::ArgumentException(String::Format(TEXT("{0} assembly has already been added"), String(assemblyName)));
return _assemblies.At(assemblyName);
}
// Create shared pointer to the assembly
const auto assembly = New<MAssembly>(this, assemblyName, options);
// Add assembly instance to dictionary
_assemblies.Add(assemblyName, assembly);
return assembly;
}
void MDomain::RemoveAssembly(const MString& assemblyName)
{
auto assembly = _assemblies[assemblyName];
_assemblies.Remove(assemblyName);
Delete(assembly);
}
MAssembly* MDomain::GetAssembly(const MString& assemblyName) const
{
MAssembly* result = nullptr;
if (!_assemblies.TryGet(assemblyName, result))
{
Log::ArgumentOutOfRangeException(TEXT("Current assembly was not found in given domain"));
}
return result;
}
void MDomain::Dispatch() const
{
#if USE_MONO
if (!IsInMainThread())
{
mono_thread_attach(_monoDomain);
}
#endif
}
MClass* MDomain::FindClass(const StringAnsiView& fullname) const
{
for (auto assembly = _assemblies.Begin(); assembly != _assemblies.End(); ++assembly)
{
const auto currentClass = assembly->Value->GetClass(fullname);
if (!currentClass)
{
return currentClass;
}
}
return nullptr;
}

View File

@@ -4,7 +4,6 @@
#include "Engine/Core/Collections/Dictionary.h"
#include "MTypes.h"
#include "MAssemblyOptions.h"
/// <summary>
/// Domain separates multiple processes within one executed CLR environment.
@@ -17,24 +16,24 @@ class FLAXENGINE_API MDomain
{
friend MCore;
friend MAssembly;
public:
typedef Dictionary<MString, MAssembly*> AssembliesDictionary;
public:
typedef Dictionary<StringAnsi, MAssembly*> AssembliesDictionary;
private:
#if USE_MONO
MonoDomain* _monoDomain;
#endif
MString _domainName;
StringAnsi _domainName;
AssembliesDictionary _assemblies;
public:
MDomain(const MString& domainName);
MDomain(const StringAnsi& domainName)
: _domainName(domainName)
{
}
public:
#if USE_MONO
/// <summary>
/// Gets native domain class.
@@ -48,7 +47,7 @@ public:
/// <summary>
/// Gets current domain name
/// </summary>
FORCE_INLINE const MString& GetName() const
FORCE_INLINE const StringAnsi& GetName() const
{
return _domainName;
}
@@ -62,27 +61,6 @@ public:
}
public:
/// <summary>
/// Create assembly container from current domain
/// </summary>
/// <param name="assemblyName">Assembly name to later receive from assemblies dictionary</param>
/// <param name="options">The assembly options container.</param>
/// <returns>MAssembly object ready to Load</returns>
MAssembly* CreateEmptyAssembly(const MString& assemblyName, const MAssemblyOptions options);
/// <summary>
/// Removes assembly from current domain and request unloading.
/// </summary>
/// <param name="assemblyName">Assembly name</param>
void RemoveAssembly(const MString& assemblyName);
/// <summary>
/// Gets current domain assembly.
/// </summary>
/// <returns>The managed assembly or null if not found.</returns>
MAssembly* GetAssembly(const MString& assemblyName) const;
/// <summary>
/// Attaches current CLR domain calls to the current thread.
/// </summary>
@@ -93,9 +71,4 @@ public:
/// </summary>
/// <returns>True if succeed in settings, false if failed.</returns>
bool SetCurrentDomain(bool force = false);
/// <summary>
/// Returns class from current domain.
/// </summary>
MClass* FindClass(const StringAnsiView& fullname) const;
};

View File

@@ -1,144 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MEvent.h"
#include "MType.h"
#include "MClass.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass)
: _monoEvent(monoEvent)
, _addMethod(nullptr)
, _removeMethod(nullptr)
, _parentClass(parentClass)
, _name(name)
, _hasCachedAttributes(false)
, _hasAddMonoMethod(true)
, _hasRemoveMonoMethod(true)
{
#if BUILD_DEBUG
// Validate input name
ASSERT(StringUtils::Compare(name, mono_event_get_name(monoEvent)) == 0);
#endif
}
#endif
MType MEvent::GetType()
{
if (GetAddMethod() != nullptr)
return GetAddMethod()->GetReturnType();
if (GetRemoveMethod() != nullptr)
return GetRemoveMethod()->GetReturnType();
return MType();
}
MMethod* MEvent::GetAddMethod()
{
if (!_hasAddMonoMethod)
return nullptr;
if (_addMethod == nullptr)
{
#if USE_MONO
auto addMonoMethod = mono_event_get_add_method(_monoEvent);
if (addMonoMethod != nullptr)
{
_hasAddMonoMethod = true;
return _addMethod = New<MMethod>(addMonoMethod, _parentClass);
}
#endif
}
return _addMethod;
}
MMethod* MEvent::GetRemoveMethod()
{
if (!_hasRemoveMonoMethod)
return nullptr;
if (_removeMethod == nullptr)
{
#if USE_MONO
auto removeMonoMethod = mono_event_get_remove_method(_monoEvent);
if (removeMonoMethod)
{
_hasRemoveMonoMethod = true;
return _removeMethod = New<MMethod>(removeMonoMethod, _parentClass);
}
#endif
}
return _removeMethod;
}
bool MEvent::HasAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
#else
return false;
#endif
}
bool MEvent::HasAttribute() const
{
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr)
return false;
if (attrInfo->num_attrs > 0)
{
mono_custom_attrs_free(attrInfo);
return true;
}
mono_custom_attrs_free(attrInfo);
return false;
#else
return false;
#endif
}
MObject* MEvent::GetAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
#else
return nullptr;
#endif
}
const Array<MObject*>& MEvent::GetAttributes()
{
if (_hasCachedAttributes)
return _attributes;
_hasCachedAttributes = true;
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr)
return _attributes;
MonoArray* monoAttributesArray = mono_custom_attrs_construct(attrInfo);
const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length);
for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
mono_custom_attrs_free(attrInfo);
#endif
return _attributes;
}

View File

@@ -12,35 +12,36 @@ class FLAXENGINE_API MEvent
friend MClass;
protected:
#if USE_MONO
MonoEvent* _monoEvent;
#elif USE_NETCORE
void* _handle;
#endif
MMethod* _addMethod;
MMethod* _removeMethod;
mutable MMethod* _addMethod;
mutable MMethod* _removeMethod;
MClass* _parentClass;
MString _name;
StringAnsi _name;
int32 _hasCachedAttributes : 1;
int32 _hasAddMonoMethod : 1;
int32 _hasRemoveMonoMethod : 1;
mutable int32 _hasCachedAttributes : 1;
mutable int32 _hasAddMonoMethod : 1;
mutable int32 _hasRemoveMonoMethod : 1;
Array<MObject*> _attributes;
mutable Array<MObject*> _attributes;
public:
#if USE_MONO
explicit MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass);
#elif USE_NETCORE
MEvent(MClass* parentClass, void* handle, const char* name);
#endif
public:
/// <summary>
/// Gets the event name.
/// </summary>
FORCE_INLINE const MString& GetName() const
FORCE_INLINE const StringAnsi& GetName() const
{
return _name;
}
@@ -56,22 +57,22 @@ public:
/// <summary>
/// Gets the event type class.
/// </summary>
MType GetType();
MType* GetType() const;
/// <summary>
/// Gets the event add method.
/// </summary>
MMethod* GetAddMethod();
MMethod* GetAddMethod() const;
/// <summary>
/// Gets the event remove method.
/// </summary>
MMethod* GetRemoveMethod();
MMethod* GetRemoveMethod() const;
/// <summary>
/// Gets event visibility in the class.
/// </summary>
FORCE_INLINE MVisibility GetVisibility()
FORCE_INLINE MVisibility GetVisibility() const
{
return GetAddMethod()->GetVisibility();
}
@@ -79,7 +80,7 @@ public:
/// <summary>
/// Returns true if event is static.
/// </summary>
FORCE_INLINE bool IsStatic()
FORCE_INLINE bool IsStatic() const
{
return GetAddMethod()->IsStatic();
}
@@ -95,7 +96,6 @@ public:
#endif
public:
/// <summary>
/// Checks if event has an attribute of the specified type.
/// </summary>
@@ -120,5 +120,5 @@ public:
/// Returns an instance of all attributes connected with given event. Returns null if the event doesn't have any attributes.
/// </summary>
/// <returns>The array of attribute objects.</returns>
const Array<MObject*>& GetAttributes();
const Array<MObject*>& GetAttributes() const;
};

View File

@@ -3,8 +3,8 @@
#pragma once
#include "Engine/Core/Types/String.h"
#include "ManagedCLR/MTypes.h"
#include "Engine/Core/Log.h"
#include "MTypes.h"
/// <summary>
/// Represents errors that occur during script execution.
@@ -12,7 +12,6 @@
class FLAXENGINE_API MException
{
public:
/// <summary>
/// Gets a message that describes the current exception.
/// </summary>
@@ -29,18 +28,6 @@ public:
MException* InnerException;
public:
#if USE_MONO
/// <summary>
/// Initializes a new instance of the <see cref="MException"/> class.
/// </summary>
/// <param name="exception">The exception.</param>
explicit MException(MonoException* exception)
: MException((MonoObject*)exception)
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="MException"/> class.
/// </summary>
@@ -53,26 +40,10 @@ public:
~MException();
public:
/// <summary>
/// Sends exception to the log.
/// </summary>
/// <param name="type">The log message type.</param>
/// <param name="target">Execution target name.</param>
void Log(const LogType type, const Char* target)
{
// Log inner exceptions chain
auto inner = InnerException;
while (inner)
{
auto stackTrace = inner->StackTrace.HasChars() ? *inner->StackTrace : TEXT("<empty>");
Log::Logger::Write(LogType::Warning, String::Format(TEXT("Inner exception. {0}\nStack strace:\n{1}\n"), inner->Message, stackTrace));
inner = inner->InnerException;
}
// Send stack trace only to log file
auto stackTrace = StackTrace.HasChars() ? *StackTrace : TEXT("<empty>");
Log::Logger::Write(LogType::Warning, String::Format(TEXT("Exception has been thrown during {0}. {1}\nStack strace:\n{2}"), target, Message, stackTrace));
Log::Logger::Write(type, String::Format(TEXT("Exception has been thrown during {0}.\n{1}"), target, Message));
}
void Log(const LogType type, const Char* target);
};

View File

@@ -1,162 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MField.h"
#include "MType.h"
#include "MClass.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attrdefs.h>
MField::MField(MonoClassField* monoField, const char* name, MClass* parentClass)
: _monoField(monoField)
, _monoType(mono_field_get_type(monoField))
, _parentClass(parentClass)
, _name(name)
, _hasCachedAttributes(false)
{
#if BUILD_DEBUG
// Validate input name
ASSERT(StringUtils::Compare(name, mono_field_get_name(monoField)) == 0);
#endif
const uint32_t flags = mono_field_get_flags(monoField);
switch (flags & MONO_FIELD_ATTR_FIELD_ACCESS_MASK)
{
case MONO_FIELD_ATTR_PRIVATE:
_visibility = MVisibility::Private;
break;
case MONO_FIELD_ATTR_FAM_AND_ASSEM:
_visibility = MVisibility::PrivateProtected;
break;
case MONO_FIELD_ATTR_ASSEMBLY:
_visibility = MVisibility::Internal;
break;
case MONO_FIELD_ATTR_FAMILY:
_visibility = MVisibility::Protected;
break;
case MONO_FIELD_ATTR_FAM_OR_ASSEM:
_visibility = MVisibility::ProtectedInternal;
break;
case MONO_FIELD_ATTR_PUBLIC:
_visibility = MVisibility::Public;
break;
default:
CRASH;
}
_isStatic = (flags & MONO_FIELD_ATTR_STATIC) != 0;
}
#endif
MType MField::GetType() const
{
#if USE_MONO
return MType(_monoType);
#else
return MType();
#endif
}
int32 MField::GetOffset() const
{
#if USE_MONO
return mono_field_get_offset(_monoField) - sizeof(MonoObject);
#else
return 0;
#endif
}
void MField::GetValue(MObject* instance, void* result) const
{
#if USE_MONO
mono_field_get_value(instance, _monoField, result);
#endif
}
MObject* MField::GetValueBoxed(MObject* instance) const
{
#if USE_MONO
return mono_field_get_value_object(mono_domain_get(), _monoField, instance);
#else
return nullptr;
#endif
}
void MField::SetValue(MObject* instance, void* value) const
{
#if USE_MONO
mono_field_set_value(instance, _monoField, value);
#endif
}
bool MField::HasAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
#else
return false;
#endif
}
bool MField::HasAttribute() const
{
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr)
return false;
if (attrInfo->num_attrs > 0)
{
mono_custom_attrs_free(attrInfo);
return true;
}
mono_custom_attrs_free(attrInfo);
#endif
return false;
}
MObject* MField::GetAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
#else
return nullptr;
#endif
}
const Array<MObject*>& MField::GetAttributes()
{
if (_hasCachedAttributes)
return _attributes;
_hasCachedAttributes = true;
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr)
return _attributes;
MonoArray* monoAttributesArray = mono_custom_attrs_construct(attrInfo);
const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length);
for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
mono_custom_attrs_free(attrInfo);
#endif
return _attributes;
}

View File

@@ -13,34 +13,36 @@ class FLAXENGINE_API MField
friend MClass;
protected:
#if USE_MONO
MonoClassField* _monoField;
MonoType* _monoType;
#elif USE_NETCORE
void* _handle;
void* _type;
#endif
MClass* _parentClass;
MString _name;
StringAnsi _name;
MVisibility _visibility;
int32 _hasCachedAttributes : 1;
mutable int32 _hasCachedAttributes : 1;
int32 _isStatic : 1;
Array<MObject*> _attributes;
mutable Array<MObject*> _attributes;
public:
#if USE_MONO
explicit MField(MonoClassField* monoField, const char* name, MClass* parentClass);
#elif USE_NETCORE
MField(MClass* parentClass, void* handle, const char* name, void* type, MFieldAttributes attributes);
#endif
public:
/// <summary>
/// Gets field name.
/// </summary>
FORCE_INLINE const MString& GetName() const
FORCE_INLINE const StringAnsi& GetName() const
{
return _name;
}
@@ -56,7 +58,7 @@ public:
/// <summary>
/// Gets field type class.
/// </summary>
MType GetType() const;
MType* GetType() const;
/// <summary>
/// Gets the field offset (in bytes) from the start of the parent object.
@@ -90,7 +92,6 @@ public:
#endif
public:
/// <summary>
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null.
/// </summary>
@@ -119,7 +120,6 @@ public:
void SetValue(MObject* instance, void* value) const;
public:
/// <summary>
/// Checks if field has an attribute of the specified type.
/// </summary>
@@ -144,5 +144,5 @@ public:
/// Returns an instance of all attributes connected with given field. Returns null if the field doesn't have any attributes.
/// </summary>
/// <returns>The array of attribute objects.</returns>
const Array<MObject*>& GetAttributes();
const Array<MObject*>& GetAttributes() const;
};

View File

@@ -1,217 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MMethod.h"
#include "MType.h"
#include "MClass.h"
#include "Engine/Profiler/ProfilerCPU.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attrdefs.h>
MMethod::MMethod(MonoMethod* monoMethod, MClass* parentClass)
: MMethod(monoMethod, mono_method_get_name(monoMethod), parentClass)
{
}
MMethod::MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass)
: _monoMethod(monoMethod)
, _parentClass(parentClass)
, _name(name)
, _hasCachedAttributes(false)
{
#if BUILD_DEBUG
// Validate input name
ASSERT(StringUtils::Compare(name, mono_method_get_name(monoMethod)) == 0);
#endif
const uint32_t flags = mono_method_get_flags(monoMethod, nullptr);
_isStatic = (flags & MONO_METHOD_ATTR_STATIC) != 0;
switch (flags & MONO_METHOD_ATTR_ACCESS_MASK)
{
case MONO_METHOD_ATTR_PRIVATE:
_visibility = MVisibility::Private;
break;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
_visibility = MVisibility::PrivateProtected;
break;
case MONO_METHOD_ATTR_ASSEM:
_visibility = MVisibility::Internal;
break;
case MONO_METHOD_ATTR_FAMILY:
_visibility = MVisibility::Protected;
break;
case MONO_METHOD_ATTR_FAM_OR_ASSEM:
_visibility = MVisibility::ProtectedInternal;
break;
case MONO_METHOD_ATTR_PUBLIC:
_visibility = MVisibility::Public;
break;
default:
CRASH;
}
#if COMPILE_WITH_PROFILER
const MString& className = parentClass->GetFullName();
ProfilerName.Resize(className.Length() + 2 + _name.Length());
Platform::MemoryCopy(ProfilerName.Get(), className.Get(), className.Length());
ProfilerName.Get()[className.Length()] = ':';
ProfilerName.Get()[className.Length() + 1] = ':';
Platform::MemoryCopy(ProfilerName.Get() + className.Length() + 2, _name.Get(), _name.Length());
ProfilerData.name = ProfilerName.Get();
ProfilerData.function = _name.Get();
ProfilerData.file = nullptr;
ProfilerData.line = 0;
ProfilerData.color = 0;
#endif
}
#endif
MObject* MMethod::Invoke(void* instance, void** params, MObject** exception) const
{
#if USE_MONO
PROFILE_CPU_SRC_LOC(ProfilerData);
return mono_runtime_invoke(_monoMethod, instance, params, exception);
#else
return nullptr;
#endif
}
MObject* MMethod::InvokeVirtual(MObject* instance, void** params, MObject** exception) const
{
#if USE_MONO
PROFILE_CPU_SRC_LOC(ProfilerData);
MonoMethod* virtualMethod = mono_object_get_virtual_method(instance, _monoMethod);
return mono_runtime_invoke(virtualMethod, instance, params, exception);
#else
return nullptr;
#endif
}
#if !USE_MONO_AOT
void* MMethod::GetThunk()
{
if (!_cachedThunk)
{
#if USE_MONO
_cachedThunk = mono_method_get_unmanaged_thunk(_monoMethod);
#endif
}
return _cachedThunk;
}
#endif
MType MMethod::GetReturnType() const
{
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
MonoType* returnType = mono_signature_get_return_type(sig);
return MType(returnType);
#else
return MType();
#endif
}
int32 MMethod::GetParametersCount() const
{
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
return mono_signature_get_param_count(sig);
#else
return 0;
#endif
}
MType MMethod::GetParameterType(int32 paramIdx) const
{
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig));
void* it = nullptr;
mono_signature_get_params(sig, &it);
return MType(((MonoType**)it)[paramIdx]);
#else
return MType();
#endif
}
bool MMethod::GetParameterIsOut(int32 paramIdx) const
{
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig));
return mono_signature_param_is_out(sig, paramIdx) != 0;
#else
return false;
#endif
}
bool MMethod::HasAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
#else
return false;
#endif
}
bool MMethod::HasAttribute() const
{
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr)
return false;
if (attrInfo->num_attrs > 0)
{
mono_custom_attrs_free(attrInfo);
return true;
}
mono_custom_attrs_free(attrInfo);
#endif
return false;
}
MObject* MMethod::GetAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
#else
return nullptr;
#endif
}
const Array<MObject*>& MMethod::GetAttributes()
{
if (_hasCachedAttributes)
return _attributes;
_hasCachedAttributes = true;
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr)
return _attributes;
MonoArray* monoAttributesArray = mono_custom_attrs_construct(attrInfo);
const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length);
for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
mono_custom_attrs_free(attrInfo);
#endif
return _attributes;
}

View File

@@ -18,33 +18,41 @@ class FLAXENGINE_API MMethod
friend MEvent;
protected:
#if USE_MONO
MonoMethod* _monoMethod;
#elif USE_NETCORE
void* _handle;
int32 _paramsCount;
mutable void* _returnType;
mutable Array<void*, InlinedAllocation<8>> _parameterTypes;
void CacheSignature() const;
#endif
MClass* _parentClass;
MString _name;
StringAnsi _name;
MVisibility _visibility;
#if !USE_MONO_AOT
void* _cachedThunk = nullptr;
#endif
int32 _hasCachedAttributes : 1;
mutable int32 _hasCachedAttributes : 1;
#if USE_NETCORE
mutable int32 _hasCachedSignature : 1;
#endif
int32 _isStatic : 1;
Array<MObject*> _attributes;
mutable Array<MObject*> _attributes;
public:
#if USE_MONO
explicit MMethod(MonoMethod* monoMethod, MClass* parentClass);
explicit MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass);
#elif USE_NETCORE
MMethod(MClass* parentClass, StringAnsi&& name, void* handle, int32 paramsCount, MMethodAttributes attributes);
#endif
public:
#if COMPILE_WITH_PROFILER
MString ProfilerName;
StringAnsi ProfilerName;
SourceLocationData ProfilerData;
#endif
@@ -85,15 +93,22 @@ public:
/// <remarks>
/// This is the fastest way of calling managed code.
/// 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.
/// Thunks return boxed value but for some smaller types (eg. bool, int, float) the return is inlined into pointer.
/// </remarks>
/// <returns>The method thunk pointer.</returns>
void* GetThunk();
#endif
/// <summary>
/// Creates a method that is inflated out of generic method.
/// </summary>
/// <returns>The inflated generic method.</returns>
MMethod* InflateGeneric() const;
/// <summary>
/// Gets the method name.
/// </summary>
FORCE_INLINE const MString& GetName() const
FORCE_INLINE const StringAnsi& GetName() const
{
return _name;
}
@@ -109,7 +124,7 @@ public:
/// <summary>
/// Returns the type of the return value. Returns null if method has no return value.
/// </summary>
MType GetReturnType() const;
MType* GetReturnType() const;
/// <summary>
/// Returns the number of parameters the method expects.
@@ -121,7 +136,7 @@ public:
/// </summary>
/// <param name="paramIdx">The parameter type.</param>
/// <returns>The parameter type.</returns>
MType GetParameterType(int32 paramIdx) const;
MType* GetParameterType(int32 paramIdx) const;
/// <summary>
/// Returns the value indicating whenever the method parameter at the specified index is marked as output parameter.
@@ -157,7 +172,6 @@ public:
#endif
public:
/// <summary>
/// Checks if method has an attribute of the specified type.
/// </summary>
@@ -182,5 +196,5 @@ public:
/// Returns an instance of all attributes connected with given method. Returns null if the method doesn't have any attributes.
/// </summary>
/// <returns>The array of attribute objects.</returns>
const Array<MObject*>& GetAttributes();
const Array<MObject*>& GetAttributes() const;
};

View File

@@ -1,203 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MProperty.h"
#include "Engine/Core/Math/Math.h"
#include "MMethod.h"
#include "MClass.h"
#include "MType.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass)
: _monoProperty(monoProperty)
, _getMethod(nullptr)
, _setMethod(nullptr)
, _parentClass(parentClass)
, _name(name)
, _hasCachedAttributes(false)
, _hasSetMethod(true)
, _hasGetMethod(true)
{
#if BUILD_DEBUG
// Validate input name
ASSERT(StringUtils::Compare(name, mono_property_get_name(monoProperty)) == 0);
#endif
GetGetMethod();
GetSetMethod();
}
#endif
MProperty::~MProperty()
{
if (_getMethod)
Delete(_getMethod);
if (_setMethod)
Delete(_setMethod);
}
MType MProperty::GetType()
{
if (GetGetMethod() != nullptr)
return GetGetMethod()->GetReturnType();
return GetSetMethod()->GetReturnType();
}
MMethod* MProperty::GetGetMethod()
{
if (!_hasGetMethod)
return nullptr;
if (_getMethod == nullptr)
{
#if USE_MONO
auto method = mono_property_get_get_method(_monoProperty);
if (method != nullptr)
{
_hasGetMethod = true;
return _getMethod = New<MMethod>(method, _parentClass);
}
#endif
}
return _getMethod;
}
MMethod* MProperty::GetSetMethod()
{
if (!_hasSetMethod)
return nullptr;
if (_setMethod == nullptr)
{
#if USE_MONO
auto method = mono_property_get_set_method(_monoProperty);
if (method != nullptr)
{
_hasSetMethod = true;
return _setMethod = New<MMethod>(method, _parentClass);
}
#endif
}
return _setMethod;
}
MVisibility MProperty::GetVisibility()
{
if (GetGetMethod() && GetSetMethod())
{
return static_cast<MVisibility>(
Math::Max(
static_cast<int>(GetGetMethod()->GetVisibility()),
static_cast<int>(GetSetMethod()->GetVisibility())
));
}
if (GetGetMethod())
{
return GetGetMethod()->GetVisibility();
}
return GetSetMethod()->GetVisibility();
}
bool MProperty::IsStatic()
{
if (GetGetMethod())
{
return GetGetMethod()->IsStatic();
}
if (GetSetMethod())
{
return GetSetMethod()->IsStatic();
}
return false;
}
MObject* MProperty::GetValue(MObject* instance, MObject** exception)
{
#if USE_MONO
return mono_property_get_value(_monoProperty, instance, nullptr, exception);
#else
return nullptr;
#endif
}
void MProperty::SetValue(MObject* instance, void* value, MObject** exception)
{
#if USE_MONO
void* params[1];
params[0] = value;
mono_property_set_value(_monoProperty, instance, params, exception);
#endif
}
bool MProperty::HasAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr)
return false;
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo);
return hasAttr;
#else
return false;
#endif
}
bool MProperty::HasAttribute() const
{
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr)
return false;
if (attrInfo->num_attrs > 0)
{
mono_custom_attrs_free(attrInfo);
return true;
}
mono_custom_attrs_free(attrInfo);
return false;
#else
return false;
#endif
}
MObject* MProperty::GetAttribute(MClass* monoClass) const
{
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr)
return nullptr;
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo);
return foundAttr;
#else
return nullptr;
#endif
}
const Array<MObject*>& MProperty::GetAttributes()
{
if (_hasCachedAttributes)
return _attributes;
_hasCachedAttributes = true;
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr)
return _attributes;
MonoArray* monoAttributesArray = mono_custom_attrs_construct(attrInfo);
const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length);
for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
mono_custom_attrs_free(attrInfo);
#endif
return _attributes;
}

View File

@@ -14,27 +14,27 @@ class FLAXENGINE_API MProperty
friend MClass;
protected:
#if USE_MONO
MonoProperty* _monoProperty;
#endif
MMethod* _getMethod;
MMethod* _setMethod;
mutable MMethod* _getMethod;
mutable MMethod* _setMethod;
MClass* _parentClass;
MString _name;
StringAnsi _name;
int32 _hasCachedAttributes : 1;
int32 _hasSetMethod : 1;
int32 _hasGetMethod : 1;
mutable int32 _hasCachedAttributes : 1;
mutable int32 _hasSetMethod : 1;
mutable int32 _hasGetMethod : 1;
Array<MObject*> _attributes;
mutable Array<MObject*> _attributes;
public:
#if USE_MONO
explicit MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass);
#elif USE_NETCORE
MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes);
#endif
/// <summary>
@@ -43,11 +43,10 @@ public:
~MProperty();
public:
/// <summary>
/// Gets the property name.
/// </summary>
FORCE_INLINE const MString& GetName() const
FORCE_INLINE const StringAnsi& GetName() const
{
return _name;
}
@@ -63,30 +62,29 @@ public:
/// <summary>
/// Gets property type class.
/// </summary>
MType GetType();
MType* GetType() const;
/// <summary>
/// Gets property get method.
/// </summary>
MMethod* GetGetMethod();
MMethod* GetGetMethod() const;
/// <summary>
/// Gets property set method.
/// </summary>
MMethod* GetSetMethod();
MMethod* GetSetMethod() const;
/// <summary>
/// Gets property visibility in the class.
/// </summary>
MVisibility GetVisibility();
MVisibility GetVisibility() const;
/// <summary>
/// Returns true if property is static.
/// </summary>
bool IsStatic();
bool IsStatic() const;
public:
/// <summary>
/// Retrieves value currently set in the property on the specified object instance. If property is static object instance can be null.
/// </summary>
@@ -96,7 +94,7 @@ public:
/// <param name="instance">The object of given type to get value from.</param>
/// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
/// <returns>The returned boxed value object.</returns>
MObject* GetValue(MObject* instance, MObject** exception);
MObject* GetValue(MObject* instance, MObject** exception) const;
/// <summary>
/// Sets a value for the property on the specified object instance. If property is static object instance can be null.
@@ -107,11 +105,9 @@ public:
/// <param name="instance">Object of given type to set value to.</param>
/// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
/// <param name="value">The value to set of undefined type.</param>
void SetValue(MObject* instance, void* value, MObject** exception);
void SetValue(MObject* instance, void* value, MObject** exception) const;
public:
/// <summary>
/// Checks if property has an attribute of the specified type.
/// </summary>
@@ -136,5 +132,5 @@ public:
/// Returns an instance of all attributes connected with given property. Returns null if the property doesn't have any attributes.
/// </summary>
/// <returns>The array of attribute objects.</returns>
const Array<MObject*>& GetAttributes();
const Array<MObject*>& GetAttributes() const;
};

View File

@@ -1,70 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Types/String.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#endif
/// <summary>
/// Class for converting mono classes and methods into usable form without instancing a class.
/// Mainly used for reflection where full object are not necessary.
/// </summary>
class MStaticConverter
{
public:
#if USE_MONO
static MonoClass* GetMonoClassFromObject(MonoObject* monoObject)
{
ASSERT(monoObject);
return mono_object_get_class(monoObject);
}
static Array<MonoClass*> GetMonoClassArrayFromObjects(Array<MonoObject*> monoObjectArray)
{
ASSERT(monoObjectArray.Count() > 0);
Array<MonoClass*> array = Array<MonoClass*>(monoObjectArray.Count());
for (auto i = 0; i < monoObjectArray.Count(); i++)
{
array.Add(GetMonoClassFromObject(monoObjectArray[i]));
}
return array;
}
static String GetClassName(MonoClass* monoClass)
{
ASSERT(monoClass);
return String(mono_class_get_name(monoClass));
}
static Array<String> GetClassNames(Array<MonoClass*> monoClassArray)
{
ASSERT(monoClassArray.Count() > 0);
Array<String> array = Array<String>(monoClassArray.Count());
for (auto i = 0; i < monoClassArray.Count(); i++)
{
array.Add(GetClassName(monoClassArray[i]));
}
return array;
}
static String GetClassNamespace(MonoClass* monoClass)
{
ASSERT(monoClass);
return String(mono_class_get_namespace(monoClass));
}
static Array<String> GetClassNamespaces(Array<MonoClass*> monoClassArray)
{
ASSERT(monoClassArray.Count() > 0);
Array<String> array = Array<String>(monoClassArray.Count());
for (auto i = 0; i < monoClassArray.Count(); i++)
{
array.Add(GetClassName(monoClassArray[i]));
}
return array;
}
#endif
};

View File

@@ -1,50 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "MType.h"
#include "MUtils.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
String MType::ToString() const
{
return _monoType ? String(mono_type_get_name(_monoType)) : String::Empty;
}
bool MType::IsStruct() const
{
ASSERT(_monoType);
return mono_type_is_struct(_monoType) != 0;
}
bool MType::IsVoid() const
{
ASSERT(_monoType);
return mono_type_is_void(_monoType) != 0;
}
bool MType::IsPointer() const
{
ASSERT(_monoType);
return mono_type_is_pointer(_monoType) != 0;
}
bool MType::IsReference() const
{
ASSERT(_monoType);
return mono_type_is_reference(_monoType) != 0;
}
bool MType::IsByRef() const
{
ASSERT(_monoType);
return mono_type_is_byref(_monoType) != 0;
}
#else
String MType::ToString() const
{
return String::Empty;
}
#endif

View File

@@ -1,78 +0,0 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "MTypes.h"
/// <summary>
/// Contains information about managed type.
/// </summary>
class MType
{
public:
#if USE_MONO
MonoType* _monoType;
/// <summary>
/// Initializes a new instance of the <see cref="MType"/> class.
/// </summary>
/// <param name="monoType">The Mono type.</param>
MType(MonoType* monoType)
: _monoType(monoType)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MType"/> class.
/// </summary>
MType()
: _monoType(nullptr)
{
}
#endif
/// <summary>
/// Finalizes an instance of the <see cref="MType"/> class.
/// </summary>
~MType()
{
}
public:
String ToString() const;
#if USE_MONO
/// <summary>
/// Gets mono type handle
/// </summary>
MonoType* GetNative() const
{
return _monoType;
}
bool IsStruct() const;
bool IsVoid() const;
bool IsPointer() const;
bool IsReference() const;
bool IsByRef() const;
public:
FORCE_INLINE bool operator==(const MType& other) const
{
return _monoType == other._monoType;
}
FORCE_INLINE bool operator!=(const MType& other) const
{
return _monoType != other._monoType;
}
FORCE_INLINE operator bool() const
{
return _monoType != nullptr;
}
#endif
};

View File

@@ -6,11 +6,6 @@
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Types/StringView.h"
/// <summary>
/// String container for names and typenames used by the managed runtime backend (8-bit chars).
/// </summary>
typedef StringAnsi MString;
enum class MVisibility
{
Private,
@@ -20,3 +15,51 @@ enum class MVisibility
ProtectedInternal,
Public,
};
enum class MTypes : uint32
{
End = 0x00,
Void = 0x01,
Boolean = 0x02,
Char = 0x03,
I1 = 0x04,
U1 = 0x05,
I2 = 0x06,
U2 = 0x07,
I4 = 0x08,
U4 = 0x09,
I8 = 0x0a,
U8 = 0x0b,
R4 = 0x0c,
R8 = 0x0d,
String = 0x0e,
Ptr = 0x0f,
ByRef = 0x10,
ValueType = 0x11,
Class = 0x12,
Var = 0x13,
Array = 0x14,
GenericInst = 0x15,
TypeByRef = 0x16,
I = 0x18,
U = 0x19,
Fnptr = 0x1b,
Object = 0x1c,
SzArray = 0x1d,
MVar = 0x1e,
CmodReqd = 0x1f,
CmodOpt = 0x20,
Internal = 0x21,
Modifier = 0x40,
Sentinel = 0x41,
Pinned = 0x45,
Enum = 0x55,
};
#if USE_NETCORE
enum class MTypeAttributes : uint32;
enum class MMethodAttributes : uint32;
enum class MFieldAttributes : uint32;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -3,99 +3,78 @@
#pragma once
#include "MTypes.h"
#include "MCore.h"
#include "Engine/Core/Types/StringView.h"
#include "Engine/Core/Types/DataContainer.h"
#include "Engine/Core/Types/Variant.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Scripting/ScriptingObject.h"
#if USE_MONO
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
#if USE_NETCORE
#include "Engine/Scripting/DotNet/CoreCLR.h"
#endif
#if USE_CSHARP
struct Version;
class CultureInfo;
template<typename AllocationType>
class BitArray;
namespace MUtils
{
extern FLAXENGINE_API StringView ToString(MonoString* str);
extern FLAXENGINE_API StringAnsi ToStringAnsi(MonoString* str);
extern FLAXENGINE_API void ToString(MonoString* str, String& result);
extern FLAXENGINE_API void ToString(MonoString* str, StringView& result);
extern FLAXENGINE_API void ToString(MonoString* str, Variant& result);
extern FLAXENGINE_API void ToString(MonoString* str, MString& result);
extern FLAXENGINE_API StringView ToString(MString* str);
extern FLAXENGINE_API StringAnsi ToStringAnsi(MString* str);
extern FLAXENGINE_API void ToString(MString* str, String& result);
extern FLAXENGINE_API void ToString(MString* str, StringView& result);
extern FLAXENGINE_API void ToString(MString* str, Variant& result);
extern FLAXENGINE_API void ToString(MString* str, StringAnsi& result);
extern FLAXENGINE_API MonoString* ToString(const char* str);
extern FLAXENGINE_API MonoString* ToString(const StringAnsi& str);
extern FLAXENGINE_API MonoString* ToString(const String& str);
extern FLAXENGINE_API MonoString* ToString(const String& str, MonoDomain* domain);
extern FLAXENGINE_API MonoString* ToString(const StringAnsiView& str);
extern FLAXENGINE_API MonoString* ToString(const StringView& str);
extern FLAXENGINE_API MonoString* ToString(const StringView& str, MonoDomain* domain);
extern FLAXENGINE_API MString* ToString(const char* str);
extern FLAXENGINE_API MString* ToString(const StringAnsi& str);
extern FLAXENGINE_API MString* ToString(const String& str);
extern FLAXENGINE_API MString* ToString(const String& str, MDomain* domain);
extern FLAXENGINE_API MString* ToString(const StringAnsiView& str);
extern FLAXENGINE_API MString* ToString(const StringView& str);
extern FLAXENGINE_API MString* ToString(const StringView& str, MDomain* domain);
extern FLAXENGINE_API ScriptingTypeHandle UnboxScriptingTypeHandle(MonoReflectionType* value);
extern FLAXENGINE_API MonoReflectionType* BoxScriptingTypeHandle(const ScriptingTypeHandle& value);
extern FLAXENGINE_API VariantType UnboxVariantType(MonoReflectionType* value);
extern FLAXENGINE_API VariantType UnboxVariantType(MonoType* monoType);
extern FLAXENGINE_API MonoReflectionType* BoxVariantType(const VariantType& value);
extern FLAXENGINE_API Variant UnboxVariant(MonoObject* value);
extern FLAXENGINE_API MonoObject* BoxVariant(const Variant& value);
extern FLAXENGINE_API ScriptingTypeHandle UnboxScriptingTypeHandle(MTypeObject* value);
extern FLAXENGINE_API MTypeObject* BoxScriptingTypeHandle(const ScriptingTypeHandle& value);
extern FLAXENGINE_API VariantType UnboxVariantType(MType* type);
extern FLAXENGINE_API MTypeObject* BoxVariantType(const VariantType& value);
extern FLAXENGINE_API Variant UnboxVariant(MObject* value);
extern FLAXENGINE_API MObject* BoxVariant(const Variant& value);
}
// Converter for data of type T between managed and unmanaged world
template<typename T, typename Enable = void>
struct MConverter
{
MonoObject* Box(const T& data, MonoClass* klass);
void Unbox(T& result, MonoObject* data);
void ToManagedArray(MonoArray* result, const Span<T>& data);
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<T, AllocationType>& result, MonoArray* data, int32 length);
MObject* Box(const T& data, const MClass* klass);
void Unbox(T& result, MObject* data);
void ToManagedArray(MArray* result, const Span<T>& data);
void ToNativeArray(Span<T>& result, const MArray* data);
};
#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>
{
MonoObject* Box(const T& data, MonoClass* klass)
MObject* Box(const T& data, const MClass* klass)
{
return mono_value_box(mono_domain_get(), klass, (void*)&data);
return MCore::Object::Box((void*)&data, klass);
}
void Unbox(T& result, MonoObject* data)
void Unbox(T& result, MObject* data)
{
CHECK(data);
Platform::MemoryCopy(&result, mono_object_unbox(data), sizeof(T));
Platform::MemoryCopy(&result, MCore::Object::Unbox(data), sizeof(T));
}
void ToManagedArray(MonoArray* result, const Span<T>& data)
void ToManagedArray(MArray* result, const Span<T>& data)
{
Platform::MemoryCopy(mono_array_addr(result, T, 0), data.Get(), data.Length() * sizeof(T));
Platform::MemoryCopy(MCore::Array::GetAddress(result), data.Get(), data.Length() * sizeof(T));
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<T, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<T>& result, const MArray* data)
{
result.Add(mono_array_addr(data, T, 0), length);
Platform::MemoryCopy(result.Get(), MCore::Array::GetAddress(data), result.Length() * sizeof(T));
}
};
@@ -103,38 +82,37 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
template<>
struct MConverter<String>
{
MonoObject* Box(const String& data, MonoClass* klass)
MObject* Box(const String& data, const MClass* klass)
{
#if USE_NETCORE
MonoString* str = MUtils::ToString(data);
return mono_value_box(nullptr, klass, str);
MString* str = MUtils::ToString(data);
return MCore::Object::Box(str, klass);
#else
return (MonoObject*)MUtils::ToString(data);
return (MObject*)MUtils::ToString(data);
#endif
}
void Unbox(String& result, MonoObject* data)
void Unbox(String& result, MObject* data)
{
#if USE_NETCORE
MonoString* str = (MonoString*)mono_object_unbox(data);
MString* str = (MString*)MCore::Object::Unbox(data);
result = MUtils::ToString(str);
#else
result = MUtils::ToString((MonoString*)data);
result = MUtils::ToString((MString*)data);
#endif
}
void ToManagedArray(MonoArray* result, const Span<String>& data)
void ToManagedArray(MArray* result, const Span<String>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, MUtils::ToString(data[i]));
MCore::GC::WriteArrayRef(result, (MObject*)MUtils::ToString(data[i]), i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<String, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<String>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
MUtils::ToString(mono_array_get(data, MonoString*, i), result[i]);
MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result[i]);
}
};
@@ -142,28 +120,27 @@ struct MConverter<String>
template<>
struct MConverter<StringAnsi>
{
MonoObject* Box(const StringAnsi& data, MonoClass* klass)
MObject* Box(const StringAnsi& data, const MClass* klass)
{
return (MonoObject*)MUtils::ToString(data);
return (MObject*)MUtils::ToString(data);
}
void Unbox(StringAnsi& result, MonoObject* data)
void Unbox(StringAnsi& result, MObject* data)
{
result = MUtils::ToStringAnsi((MonoString*)data);
result = MUtils::ToStringAnsi((MString*)data);
}
void ToManagedArray(MonoArray* result, const Span<StringAnsi>& data)
void ToManagedArray(MArray* result, const Span<StringAnsi>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, MUtils::ToString(data[i]));
MCore::GC::WriteArrayRef(result, (MObject*)MUtils::ToString(data[i]), i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<StringAnsi, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<StringAnsi>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
MUtils::ToString(mono_array_get(data, MonoString*, i), result[i]);
MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result[i]);
}
};
@@ -171,28 +148,27 @@ struct MConverter<StringAnsi>
template<>
struct MConverter<StringView>
{
MonoObject* Box(const StringView& data, MonoClass* klass)
MObject* Box(const StringView& data, const MClass* klass)
{
return (MonoObject*)MUtils::ToString(data);
return (MObject*)MUtils::ToString(data);
}
void Unbox(StringView& result, MonoObject* data)
void Unbox(StringView& result, MObject* data)
{
result = MUtils::ToString((MonoString*)data);
result = MUtils::ToString((MString*)data);
}
void ToManagedArray(MonoArray* result, const Span<StringView>& data)
void ToManagedArray(MArray* result, const Span<StringView>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, MUtils::ToString(data[i]));
MCore::GC::WriteArrayRef(result, (MObject*)MUtils::ToString(data[i]), i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<StringView, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<StringView>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
MUtils::ToString(mono_array_get(data, MonoString*, i), result[i]);
MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result[i]);
}
};
@@ -200,28 +176,27 @@ struct MConverter<StringView>
template<>
struct MConverter<Variant>
{
MonoObject* Box(const Variant& data, MonoClass* klass)
MObject* Box(const Variant& data, const MClass* klass)
{
return MUtils::BoxVariant(data);
}
void Unbox(Variant& result, MonoObject* data)
void Unbox(Variant& result, MObject* data)
{
result = MUtils::UnboxVariant(data);
}
void ToManagedArray(MonoArray* result, const Span<Variant>& data)
void ToManagedArray(MArray* result, const Span<Variant>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, MUtils::BoxVariant(data[i]));
MCore::GC::WriteArrayRef(result, MUtils::BoxVariant(data[i]), i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<Variant, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<Variant>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
result[i] = MUtils::UnboxVariant(mono_array_get(data, MonoObject*, i));
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = MUtils::UnboxVariant(dataPtr[i]);
}
};
@@ -229,31 +204,27 @@ struct MConverter<Variant>
template<typename T>
struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Value>::Type>
{
MonoObject* Box(T* data, MonoClass* klass)
MObject* Box(T* data, const MClass* klass)
{
return data ? data->GetOrCreateManagedInstance() : nullptr;
}
void Unbox(T*& result, MonoObject* data)
void Unbox(T*& result, MObject* data)
{
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MonoArray* result, const Span<T*>& data)
void ToManagedArray(MArray* result, const Span<T*>& data)
{
for (int32 i = 0; i < data.Length(); i++)
{
auto obj = data[i];
mono_array_setref(result, i, obj ? obj->GetOrCreateManagedInstance() : nullptr);
}
MCore::GC::WriteArrayRef(result, data[i] ? data[i]->GetOrCreateManagedInstance() : nullptr, i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<T*, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<T*>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
result[i] = (T*)ScriptingObject::ToNative(mono_array_get(data, MonoObject*, i));
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
}
};
@@ -261,28 +232,15 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
template<typename T>
struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Value>::Type>
{
MonoObject* Box(const T& data, MonoClass* klass)
MObject* Box(const T& data, const MClass* klass)
{
return data.GetOrCreateManagedInstance();
}
void Unbox(T& result, MonoObject* data)
{
// Not Supported
CRASH;
}
void ToManagedArray(MonoArray* result, const Span<T>& data)
void ToManagedArray(MArray* result, const Span<T>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, data[i].GetOrCreateManagedInstance());
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<T, AllocationType>& result, MonoArray* data, int32 length)
{
// Not Supported
CRASH;
MCore::GC::WriteArrayRef(result, data[i].GetOrCreateManagedInstance(), i);
}
};
@@ -293,28 +251,27 @@ class ScriptingObjectReference;
template<typename T>
struct MConverter<ScriptingObjectReference<T>>
{
MonoObject* Box(const ScriptingObjectReference<T>& data, MonoClass* klass)
MObject* Box(const ScriptingObjectReference<T>& data, const MClass* klass)
{
return data.GetManagedInstance();
}
void Unbox(ScriptingObjectReference<T>& result, MonoObject* data)
void Unbox(ScriptingObjectReference<T>& result, MObject* data)
{
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MonoArray* result, const Span<ScriptingObjectReference<T>>& data)
void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, data[i].GetManagedInstance());
MCore::GC::WriteArrayRef(result, data[i].GetManagedInstance(), i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<ScriptingObjectReference<T>, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<ScriptingObjectReference<T>>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
result[i] = (T*)ScriptingObject::ToNative(mono_array_get(data, MonoObject*, i));
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
}
};
@@ -325,28 +282,27 @@ class AssetReference;
template<typename T>
struct MConverter<AssetReference<T>>
{
MonoObject* Box(const AssetReference<T>& data, MonoClass* klass)
MObject* Box(const AssetReference<T>& data, const MClass* klass)
{
return data.GetManagedInstance();
}
void Unbox(AssetReference<T>& result, MonoObject* data)
void Unbox(AssetReference<T>& result, MObject* data)
{
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MonoArray* result, const Span<AssetReference<T>>& data)
void ToManagedArray(MArray* result, const Span<AssetReference<T>>& data)
{
for (int32 i = 0; i < data.Length(); i++)
mono_array_setref(result, i, data[i].GetManagedInstance());
MCore::GC::WriteArrayRef(result, data[i].GetManagedInstance(), i);
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<AssetReference<T>, AllocationType>& result, MonoArray* data, int32 length)
void ToNativeArray(Span<AssetReference<T>>& result, const MArray* data)
{
result.Resize(length);
for (int32 i = 0; i < length; i++)
result[i] = (T*)ScriptingObject::ToNative(mono_array_get(data, MonoObject*, i));
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++)
result[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
}
};
@@ -354,102 +310,66 @@ struct MConverter<AssetReference<T>>
template<typename T>
struct MConverter<Array<T>>
{
MonoObject* Box(const Array<T>& data, MonoClass* klass)
MObject* Box(const Array<T>& data, const MClass* klass)
{
if (!klass)
return nullptr;
// TODO: use shared empty arrays cache
auto result = mono_array_new(mono_domain_get(), klass, data.Count());
MArray* result = MCore::Array::New(klass, data.Count());
MConverter<T> converter;
converter.ToManagedArray(result, Span<T>(data.Get(), data.Count()));
return (MonoObject*)result;
return (MObject*)result;
}
void Unbox(Array<T>& result, MonoObject* data)
void Unbox(Array<T>& result, MObject* data)
{
auto length = data ? (int32)mono_array_length((MonoArray*)data) : 0;
result.EnsureCapacity(length);
const int32 length = data ? MCore::Array::GetLength((MArray*)data) : 0;
result.Resize(length);
MConverter<T> converter;
converter.ToNativeArray(result, (MonoArray*)data, length);
}
void ToManagedArray(MonoArray* result, const Span<Array<T>>& data)
{
CRASH; // Not implemented
}
template<typename AllocationType = HeapAllocation>
void ToNativeArray(Array<Array<T>, AllocationType>& result, MonoArray* data, int32 length)
{
CRASH; // Not implemented
Span<T> resultSpan(result.Get(), length);
converter.ToNativeArray(resultSpan, (MArray*)data);
}
};
namespace MUtils
{
// Outputs the full typename for the type of the specified object.
extern FLAXENGINE_API void GetClassFullname(MonoObject* obj, MString& fullname);
// Outputs the full typename for the specified type.
extern FLAXENGINE_API void GetClassFullname(MonoClass* monoClass, MString& fullname);
// Outputs the full typename for the specified type.
extern FLAXENGINE_API void GetClassFullname(MonoReflectionType* type, MString& fullname);
// Outputs the full typename for the type of the specified object.
inline MString GetClassFullname(MonoObject* obj)
{
MString fullname;
GetClassFullname(obj, fullname);
return fullname;
}
// Outputs the full typename for the type of the specified object.
inline MString GetClassFullname(MonoClass* monoClass)
{
MString fullname;
GetClassFullname(monoClass, fullname);
return fullname;
}
extern FLAXENGINE_API const StringAnsi& GetClassFullname(MObject* obj);
// Returns the class of the provided object.
extern FLAXENGINE_API MonoClass* GetClass(MonoObject* object);
extern FLAXENGINE_API MClass* GetClass(MObject* object);
// Returns the class of the provided type.
extern FLAXENGINE_API MonoClass* GetClass(MonoReflectionType* type);
extern FLAXENGINE_API MClass* GetClass(MTypeObject* type);
// Returns the class of the provided VariantType value.
extern FLAXENGINE_API MonoClass* GetClass(const VariantType& value);
extern FLAXENGINE_API MClass* GetClass(const VariantType& value);
// Returns the class of the provided Variant value.
extern FLAXENGINE_API MonoClass* GetClass(const Variant& value);
extern FLAXENGINE_API MClass* GetClass(const Variant& value);
// Returns the type of the provided object.
extern FLAXENGINE_API MonoReflectionType* GetType(MonoObject* object);
extern FLAXENGINE_API MTypeObject* GetType(MObject* object);
// Returns the type of the provided class.
extern FLAXENGINE_API MonoReflectionType* GetType(MonoClass* klass);
// Returns the type of the provided class.
extern FLAXENGINE_API MonoReflectionType* GetType(MClass* mclass);
extern FLAXENGINE_API MTypeObject* GetType(MClass* klass);
/// <summary>
/// Boxes the native value into the MonoObject.
/// Boxes the native value into the managed object.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="valueClass">The value type class.</param>
template<class T>
MonoObject* Box(const T& value, MonoClass* valueClass)
MObject* Box(const T& value, const MClass* valueClass)
{
MConverter<T> converter;
return converter.Box(value, valueClass);
}
/// <summary>
/// Unboxes MonoObject to the native value of the given type.
/// Unboxes MObject to the native value of the given type.
/// </summary>
template<class T>
T Unbox(MonoObject* object)
T Unbox(MObject* object)
{
MConverter<T> converter;
T result;
@@ -462,7 +382,7 @@ namespace MUtils
/// </summary>
/// <param name="arrayObj">The array object.</param>
/// <returns>The result data container with linked array data bytes (not copied).</returns>
extern FLAXENGINE_API BytesContainer LinkArray(MonoArray* arrayObj);
extern FLAXENGINE_API BytesContainer LinkArray(MArray* arrayObj);
/// <summary>
/// Allocates new managed array of data and copies contents from given native array.
@@ -471,12 +391,11 @@ namespace MUtils
/// <param name="valueClass">The array values type class.</param>
/// <returns>The output array.</returns>
template<typename T>
MonoArray* ToArray(const Span<T>& data, MonoClass* valueClass)
MArray* ToArray(const Span<T>& data, const MClass* valueClass)
{
if (!valueClass)
return nullptr;
// TODO: use shared empty arrays cache
auto result = mono_array_new(mono_domain_get(), valueClass, data.Length());
MArray* result = MCore::Array::New(valueClass, data.Length());
MConverter<T> converter;
converter.ToManagedArray(result, data);
return result;
@@ -489,7 +408,7 @@ namespace MUtils
/// <param name="valueClass">The array values type class.</param>
/// <returns>The output array.</returns>
template<typename T, typename AllocationType>
FORCE_INLINE MonoArray* ToArray(const Array<T, AllocationType>& data, MonoClass* valueClass)
FORCE_INLINE MArray* ToArray(const Array<T, AllocationType>& data, const MClass* valueClass)
{
return MUtils::ToArray(Span<T>(data.Get(), data.Count()), valueClass);
}
@@ -500,13 +419,14 @@ namespace MUtils
/// <param name="arrayObj">The managed array object.</param>
/// <returns>The output array.</returns>
template<typename T, typename AllocationType = HeapAllocation>
Array<T, AllocationType> ToArray(MonoArray* arrayObj)
Array<T, AllocationType> ToArray(MArray* arrayObj)
{
Array<T, AllocationType> result;
auto length = arrayObj ? (int32)mono_array_length(arrayObj) : 0;
result.EnsureCapacity(length);
const int32 length = arrayObj ? MCore::Array::GetLength(arrayObj) : 0;
result.Resize(length);
MConverter<T> converter;
converter.ToNativeArray(result, arrayObj, length);
Span<T> resultSpan(result.Get(), length);
converter.ToNativeArray(resultSpan, arrayObj);
return result;
}
@@ -516,10 +436,10 @@ namespace MUtils
/// <param name="arrayObj">The managed array object.</param>
/// <returns>The output array pointer and size.</returns>
template<typename T>
Span<T> ToSpan(MonoArray* arrayObj)
Span<T> ToSpan(MArray* arrayObj)
{
auto ptr = (T*)(void*)mono_array_addr_with_size(arrayObj, sizeof(T), 0);
auto length = arrayObj ? (int32)mono_array_length(arrayObj) : 0;
T* ptr = (T*)MCore::Array::GetAddress(arrayObj);
const int32 length = arrayObj ? MCore::Array::GetLength(arrayObj) : 0;
return Span<T>(ptr, length);
}
@@ -540,16 +460,15 @@ namespace MUtils
/// <param name="arrayObj">The array object.</param>
/// <param name="result">The result data (linked not copied).</param>
template<typename T>
void ToArray(MonoArray* arrayObj, DataContainer<T>& result)
void ToArray(MArray* arrayObj, DataContainer<T>& result)
{
auto length = arrayObj ? (int32)mono_array_length(arrayObj) : 0;
const int32 length = arrayObj ? MCore::Array::GetLength(arrayObj) : 0;
if (length == 0)
{
result.Release();
return;
}
auto bytesRaw = (T*)(void*)mono_array_addr_with_size(arrayObj, sizeof(T), 0);
T* bytesRaw = (T*)MCore::Array::GetAddress(arrayObj);
result.Link(bytesRaw, length);
}
@@ -558,9 +477,9 @@ namespace MUtils
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
FORCE_INLINE MonoArray* ToArray(const Span<byte>& data)
FORCE_INLINE MArray* ToArray(const Span<byte>& data)
{
return ToArray(data, mono_get_byte_class());
return ToArray(data, MCore::TypeCache::Byte);
}
/// <summary>
@@ -568,9 +487,9 @@ namespace MUtils
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
FORCE_INLINE MonoArray* ToArray(Array<byte>& data)
FORCE_INLINE MArray* ToArray(Array<byte>& data)
{
return ToArray(Span<byte>(data.Get(), data.Count()), mono_get_byte_class());
return ToArray(Span<byte>(data.Get(), data.Count()), MCore::TypeCache::Byte);
}
/// <summary>
@@ -578,9 +497,9 @@ namespace MUtils
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
FORCE_INLINE MonoArray* ToArray(const Span<String>& data)
FORCE_INLINE MArray* ToArray(const Span<String>& data)
{
return ToArray(data, mono_get_string_class());
return ToArray(data, MCore::TypeCache::String);
}
/// <summary>
@@ -588,35 +507,35 @@ namespace MUtils
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
FORCE_INLINE MonoArray* ToArray(const Array<String>& data)
FORCE_INLINE MArray* ToArray(const Array<String>& data)
{
return ToArray(Span<String>(data.Get(), data.Count()), mono_get_string_class());
return ToArray(Span<String>(data.Get(), data.Count()), MCore::TypeCache::String);
}
#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.
/// 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));
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
bool* arr = (bool*)MCore::GC::AllocateMemory(data.Count() * sizeof(bool), true);
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.
/// 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>
template<typename AllocationType = HeapAllocation>
FORCE_INLINE bool* ToBoolArray(const BitArray<AllocationType>& data)
{
bool* arr = (bool*)CoreCLR::Allocate(data.Count() * sizeof(bool));
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
bool* arr = (bool*)MCore::GC::AllocateMemory(data.Count() * sizeof(bool), true);
for (int i = 0; i < data.Count(); i++)
arr[i] = data[i];
return arr;
@@ -634,45 +553,10 @@ namespace MUtils
}
#endif
FORCE_INLINE MGCHandle NewGCHandle(MonoObject* obj, bool pinned)
{
#if USE_NETCORE
return CoreCLR::NewGCHandle(obj, pinned);
#else
return mono_gchandle_new(obj, pinned);
#endif
}
extern void* VariantToManagedArgPtr(Variant& value, MType* type, bool& failed);
FORCE_INLINE MGCHandle NewGCHandleWeakref(MonoObject* obj, bool track_resurrection)
{
#if USE_NETCORE
return CoreCLR::NewGCHandleWeakref(obj, track_resurrection);
#else
return mono_gchandle_new_weakref(obj, track_resurrection);
#endif
}
FORCE_INLINE MonoObject* GetGCHandleTarget(const MGCHandle& handle)
{
#if USE_NETCORE
return (MonoObject*)CoreCLR::GetGCHandleTarget(handle);
#else
return mono_gchandle_get_target(handle);
#endif
}
FORCE_INLINE void FreeGCHandle(const MGCHandle& 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);
extern MObject* ToManaged(const Version& value);
extern Version ToNative(MObject* value);
};
#endif

View File

@@ -30,7 +30,7 @@ GamePlugin::GamePlugin(const SpawnParams& params)
#if USE_EDITOR
#include "EditorPlugin.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
EditorPlugin::EditorPlugin(const SpawnParams& params)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,537 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "Engine/Scripting/Types.h"
#if !USE_CSHARP
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Scripting/ManagedCLR/MEvent.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MProperty.h"
extern MDomain* MRootDomain;
extern Array<MDomain*, FixedAllocation<4>> MDomains;
MDomain* MCore::CreateDomain(const StringAnsi& domainName)
{
for (int32 i = 0; i < MDomains.Count(); i++)
{
if (MDomains[i]->GetName() == domainName)
return MDomains[i];
}
auto domain = New<MDomain>(domainName);
MDomains.Add(domain);
return domain;
}
void MCore::UnloadDomain(const StringAnsi& domainName)
{
int32 i = 0;
for (; i < MDomains.Count(); i++)
{
if (MDomains[i]->GetName() == domainName)
break;
}
if (i == MDomains.Count())
return;
auto domain = MDomains[i];
Delete(domain);
MDomains.RemoveAtKeepOrder(i);
}
bool MCore::LoadEngine()
{
MRootDomain = New<MDomain>("Root");
MDomains.Add(MRootDomain);
return false;
}
void MCore::UnloadEngine()
{
MDomains.ClearDelete();
MRootDomain = nullptr;
}
MObject* MCore::Object::Box(void* value, const MClass* klass)
{
return nullptr;
}
void* MCore::Object::Unbox(MObject* obj)
{
return nullptr;
}
MObject* MCore::Object::New(const MClass* klass)
{
return nullptr;
}
void MCore::Object::Init(MObject* obj)
{
}
MClass* MCore::Object::GetClass(MObject* obj)
{
return nullptr;
}
MString* MCore::Object::ToString(MObject* obj)
{
return nullptr;
}
int32 MCore::Object::GetHashCode(MObject* obj)
{
return 0;
}
MString* MCore::String::GetEmpty(MDomain* domain)
{
return nullptr;
}
MString* MCore::String::New(const char* str, int32 length, MDomain* domain)
{
return nullptr;
}
MString* MCore::String::New(const Char* str, int32 length, MDomain* domain)
{
return nullptr;
}
StringView MCore::String::GetChars(MString* obj)
{
return StringView::Empty;
}
MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
{
return nullptr;
}
MClass* MCore::Array::GetClass(MClass* elementKlass)
{
return nullptr;
}
int32 MCore::Array::GetLength(const MArray* obj)
{
return 0;
}
void* MCore::Array::GetAddress(const MArray* obj)
{
return nullptr;
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
return (MGCHandle)(uintptr)obj;
}
MGCHandle MCore::GCHandle::NewWeak(MObject* obj, bool trackResurrection)
{
return (MGCHandle)(uintptr)obj;
}
MObject* MCore::GCHandle::GetTarget(const MGCHandle& handle)
{
return (MObject*)(uintptr)handle;
}
void MCore::GCHandle::Free(const MGCHandle& handle)
{
}
void MCore::GC::Collect()
{
}
void MCore::GC::Collect(int32 generation)
{
}
void MCore::GC::WaitForPendingFinalizers()
{
}
void MCore::GC::WriteRef(void* ptr, MObject* ref)
{
}
void MCore::GC::WriteValue(void* dst, void* src, int32 count, const MClass* klass)
{
}
void MCore::GC::WriteArrayRef(MArray* dst, MObject* ref, int32 index)
{
}
void MCore::Thread::Attach()
{
}
void MCore::Thread::Exit()
{
}
bool MCore::Thread::IsAttached()
{
return true;
}
void MCore::Exception::Throw(MObject* exception)
{
}
MObject* MCore::Exception::GetNullReference()
{
return nullptr;
}
MObject* MCore::Exception::Get(const char* msg)
{
return nullptr;
}
MObject* MCore::Exception::GetArgument(const char* arg, const char* msg)
{
return nullptr;
}
MObject* MCore::Exception::GetArgumentNull(const char* arg)
{
return nullptr;
}
MObject* MCore::Exception::GetArgumentOutOfRange(const char* arg)
{
return nullptr;
}
MObject* MCore::Exception::GetNotSupported(const char* msg)
{
return nullptr;
}
const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
{
_hasCachedClasses = true;
return _classes;
}
bool MAssembly::LoadCorlib()
{
return false;
}
bool MAssembly::LoadImage(const String& assemblyPath)
{
_hasCachedClasses = false;
_assemblyPath = assemblyPath;
return false;
}
bool MAssembly::UnloadImage(bool isReloading)
{
return false;
}
MClass::~MClass()
{
_fields.ClearDelete();
_properties.ClearDelete();
_methods.ClearDelete();
_events.ClearDelete();
}
MClass* MClass::GetBaseClass() const
{
return nullptr;
}
bool MClass::IsSubClassOf(const MClass* klass, bool checkInterfaces) const
{
return false;
}
bool MClass::HasInterface(const MClass* klass) const
{
return false;
}
bool MClass::IsInstanceOfType(MObject* object) const
{
return false;
}
uint32 MClass::GetInstanceSize() const
{
return 0;
}
MMethod* MClass::GetMethod(const char* name, int32 numParams) const
{
return nullptr;
}
const Array<MMethod*>& MClass::GetMethods() const
{
_hasCachedMethods = true;
return _methods;
}
MField* MClass::GetField(const char* name) const
{
return nullptr;
}
const Array<MField*>& MClass::GetFields() const
{
_hasCachedFields = true;
return _fields;
}
const Array<MEvent*>& MClass::GetEvents() const
{
_hasCachedEvents = true;
return _events;
}
MProperty* MClass::GetProperty(const char* name) const
{
return nullptr;
}
const Array<MProperty*>& MClass::GetProperties() const
{
_hasCachedProperties = true;
return _properties;
}
bool MClass::HasAttribute(const MClass* monoClass) const
{
return false;
}
bool MClass::HasAttribute() const
{
return false;
}
MObject* MClass::GetAttribute(const MClass* monoClass) const
{
return nullptr;
}
const Array<MObject*>& MClass::GetAttributes() const
{
_hasCachedAttributes = true;
return _attributes;
}
bool MDomain::SetCurrentDomain(bool force)
{
extern MDomain* MActiveDomain;
MActiveDomain = this;
return true;
}
void MDomain::Dispatch() const
{
}
MMethod* MEvent::GetAddMethod() const
{
return _addMethod;
}
MMethod* MEvent::GetRemoveMethod() const
{
return _removeMethod;
}
bool MEvent::HasAttribute(MClass* monoClass) const
{
return false;
}
bool MEvent::HasAttribute() const
{
return false;
}
MObject* MEvent::GetAttribute(MClass* monoClass) const
{
return nullptr;
}
const Array<MObject*>& MEvent::GetAttributes() const
{
return _attributes;
}
MException::MException(MObject* exception)
: InnerException(nullptr)
{
}
MException::~MException()
{
}
MType* MField::GetType() const
{
return nullptr;
}
int32 MField::GetOffset() const
{
return 0;
}
void MField::GetValue(MObject* instance, void* result) const
{
}
MObject* MField::GetValueBoxed(MObject* instance) const
{
return nullptr;
}
void MField::SetValue(MObject* instance, void* value) const
{
}
bool MField::HasAttribute(MClass* monoClass) const
{
return false;
}
bool MField::HasAttribute() const
{
return false;
}
MObject* MField::GetAttribute(MClass* monoClass) const
{
return nullptr;
}
const Array<MObject*>& MField::GetAttributes() const
{
return _attributes;
}
MObject* MMethod::Invoke(void* instance, void** params, MObject** exception) const
{
return nullptr;
}
MObject* MMethod::InvokeVirtual(MObject* instance, void** params, MObject** exception) const
{
return nullptr;
}
MMethod* MMethod::InflateGeneric() const
{
return nullptr;
}
MType* MMethod::GetReturnType() const
{
return nullptr;
}
int32 MMethod::GetParametersCount() const
{
return 0;
}
MType* MMethod::GetParameterType(int32 paramIdx) const
{
return nullptr;
}
bool MMethod::GetParameterIsOut(int32 paramIdx) const
{
return false;
}
bool MMethod::HasAttribute(MClass* monoClass) const
{
return false;
}
bool MMethod::HasAttribute() const
{
return false;
}
MObject* MMethod::GetAttribute(MClass* monoClass) const
{
return nullptr;
}
const Array<MObject*>& MMethod::GetAttributes() const
{
return _attributes;
}
MProperty::~MProperty()
{
if (_getMethod)
Delete(_getMethod);
if (_setMethod)
Delete(_setMethod);
}
MMethod* MProperty::GetGetMethod() const
{
return _getMethod;
}
MMethod* MProperty::GetSetMethod() const
{
return _setMethod;
}
MObject* MProperty::GetValue(MObject* instance, MObject** exception) const
{
return nullptr;
}
void MProperty::SetValue(MObject* instance, void* value, MObject** exception) const
{
}
bool MProperty::HasAttribute(MClass* monoClass) const
{
return false;
}
bool MProperty::HasAttribute() const
{
return false;
}
MObject* MProperty::GetAttribute(MClass* monoClass) const
{
return nullptr;
}
const Array<MObject*>& MProperty::GetAttributes() const
{
return _attributes;
}
#endif

View File

@@ -3,7 +3,7 @@
#include "Script.h"
#include "Engine/Core/Log.h"
#if USE_EDITOR
#include "StdTypesContainer.h"
#include "Internal/StdTypesContainer.h"
#include "ManagedCLR/MClass.h"
#include "Editor/Editor.h"
#endif

View File

@@ -17,9 +17,9 @@ public class Scripting : EngineModule
{
if (EngineConfiguration.WithDotNet(options))
{
// .NET
options.PrivateDependencies.Add("nethost");
options.ScriptingAPI.Defines.Add("USE_NETCORE");
options.PublicDefinitions.Add("USE_NETCORE");
if (options.Target is EngineTarget engineTarget && engineTarget.UseSeparateMainExecutable(options))
{
@@ -30,7 +30,9 @@ public class Scripting : EngineModule
}
else
{
options.PublicDependencies.Add("mono");
// Mono
options.PrivateDependencies.Add("mono");
options.ScriptingAPI.Defines.Add("USE_MONO");
}
}

View File

@@ -2,7 +2,6 @@
#include "BinaryModule.h"
#include "Scripting.h"
#include "StdTypesContainer.h"
#include "ScriptingType.h"
#include "FlaxEngine.Gen.h"
#include "Engine/Threading/Threading.h"
@@ -20,7 +19,8 @@
#include "ManagedCLR/MMethod.h"
#include "ManagedCLR/MDomain.h"
#include "ManagedCLR/MCore.h"
#include "MException.h"
#include "ManagedCLR/MException.h"
#include "Internal/StdTypesContainer.h"
#include "Engine/Core/ObjectsRemovalService.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Profiler/ProfilerCPU.h"
@@ -29,14 +29,8 @@
#include "Engine/Engine/EngineService.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Platform/MemoryStats.h"
#include "Engine/Serialization/JsonTools.h"
#if USE_MONO
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/object.h>
#endif
#if USE_NETCORE
#include "DotNet/CoreCLR.h"
#endif
extern void registerFlaxEngineInternalCalls();
@@ -392,7 +386,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
else
{
// Create module if native library is not used
module = New<ManagedBinaryModule>(nameAnsi, MAssemblyOptions());
module = New<ManagedBinaryModule>(nameAnsi);
_nonNativeModules.Add(module);
}
}
@@ -401,18 +395,11 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
// C#
if (managedPath.HasChars() && !((ManagedBinaryModule*)module)->Assembly->IsLoaded())
{
if (((ManagedBinaryModule*)module)->Assembly->Load(managedPath))
if (((ManagedBinaryModule*)module)->Assembly->Load(managedPath, nativePath))
{
LOG(Error, "Failed to load C# assembly '{0}' for binary module {1}.", managedPath, name);
return true;
}
#if USE_NETCORE
// Provide new path of hot-reloaded native library path for managed DllImport
if (nativePath.HasChars())
{
CoreCLR::RegisterNativeLibrary(nameAnsi.Get(), StringAnsi(nativePath).Get());
}
#endif
}
#endif
@@ -429,13 +416,46 @@ bool Scripting::Load()
// Note: this action can be called from main thread (due to Mono problems with assemblies actions from other threads)
ASSERT(IsInMainThread());
#if !COMPILE_WITHOUT_CSHARP
#if USE_CSHARP
// Load C# core assembly
if (GetBinaryModuleCorlib()->Assembly->Load(mono_get_corlib()))
ManagedBinaryModule* corlib = GetBinaryModuleCorlib();
if (corlib->Assembly->LoadCorlib())
{
LOG(Error, "Failed to load corlib C# assembly.");
return true;
}
// Initialize C# corelib types
{
const auto& corlibClasses = corlib->Assembly->GetClasses();
bool gotAll = true;
#define CACHE_CORLIB_CLASS(var, name) gotAll &= corlibClasses.TryGet(StringAnsiView(name), MCore::TypeCache::var)
CACHE_CORLIB_CLASS(Void, "System.Void");
CACHE_CORLIB_CLASS(Object, "System.Object");
CACHE_CORLIB_CLASS(Byte, "System.Byte");
CACHE_CORLIB_CLASS(Boolean, "System.Boolean");
CACHE_CORLIB_CLASS(SByte, "System.SByte");
CACHE_CORLIB_CLASS(Char, "System.Char");
CACHE_CORLIB_CLASS(Int16, "System.Int16");
CACHE_CORLIB_CLASS(UInt16, "System.UInt16");
CACHE_CORLIB_CLASS(Int32, "System.Int32");
CACHE_CORLIB_CLASS(UInt32, "System.UInt32");
CACHE_CORLIB_CLASS(Int64, "System.Int64");
CACHE_CORLIB_CLASS(UInt64, "System.UInt64");
CACHE_CORLIB_CLASS(IntPtr, "System.IntPtr");
CACHE_CORLIB_CLASS(UIntPtr, "System.UIntPtr");
CACHE_CORLIB_CLASS(Single, "System.Single");
CACHE_CORLIB_CLASS(Double, "System.Double");
CACHE_CORLIB_CLASS(String, "System.String");
#undef CACHE_CORLIB_CLASS
if (!gotAll)
{
LOG(Error, "Failed to load corlib C# assembly.");
for (const auto& e : corlibClasses)
LOG(Info, "Class: {0}", String(e.Value->GetFullName()));
return true;
}
}
#endif
// Load FlaxEngine
@@ -671,48 +691,6 @@ MClass* Scripting::FindClass(const StringAnsiView& fullname)
return nullptr;
}
#if USE_MONO
MClass* Scripting::FindClass(MonoClass* monoClass)
{
if (monoClass == nullptr)
return nullptr;
PROFILE_CPU();
auto& modules = BinaryModule::GetModules();
for (auto module : modules)
{
auto managedModule = dynamic_cast<ManagedBinaryModule*>(module);
if (managedModule && managedModule->Assembly->IsLoaded())
{
MClass* result = managedModule->Assembly->GetClass(monoClass);
if (result != nullptr)
return result;
}
}
return nullptr;
}
MonoClass* Scripting::FindClassNative(const StringAnsiView& fullname)
{
if (fullname.IsEmpty())
return nullptr;
PROFILE_CPU();
auto& modules = BinaryModule::GetModules();
for (auto module : modules)
{
auto managedModule = dynamic_cast<ManagedBinaryModule*>(module);
if (managedModule && managedModule->Assembly->IsLoaded())
{
MClass* result = managedModule->Assembly->GetClass(fullname);
if (result != nullptr)
return result->GetNative();
}
}
return nullptr;
}
#endif
ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname)
{
if (fullname.IsEmpty())
@@ -754,21 +732,20 @@ ScriptingObject* Scripting::NewObject(const MClass* type)
LOG(Error, "Invalid type.");
return nullptr;
}
#if USE_MONO
#if USE_CSHARP
// Get the assembly with that class
MonoClass* typeClass = type->GetNative();
auto module = ManagedBinaryModule::FindModule(typeClass);
auto module = ManagedBinaryModule::FindModule(type);
if (module == nullptr)
{
LOG(Error, "Cannot find scripting assembly for type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot find scripting assembly for type \'{0}\'.", String(type->GetFullName()));
return nullptr;
}
// Try to find the scripting type for this class
int32 typeIndex;
if (!module->ClassToTypeIndex.TryGet(typeClass, typeIndex))
if (!module->ClassToTypeIndex.TryGet(type, typeIndex))
{
LOG(Error, "Cannot spawn objects of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot spawn objects of type \'{0}\'.", String(type->GetFullName()));
return nullptr;
}
const ScriptingType& scriptingType = module->Types[typeIndex];

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
@@ -215,6 +216,11 @@ namespace FlaxEngine
return ManagedHandle.Alloc(version);
}
internal static ManagedHandle CultureInfoToManaged(int lcid)
{
return ManagedHandle.Alloc(new CultureInfo(lcid));
}
internal static void VersionToNative(ManagedHandle versionHandle, IntPtr nativePtr)
{
Version version = Unsafe.As<Version>(versionHandle.Target);

View File

@@ -86,22 +86,6 @@ public:
/// <returns>The MClass object or null if missing.</returns>
static MClass* FindClass(const StringAnsiView& fullname);
#if USE_MONO
/// <summary>
/// Finds the class from the given Mono class object within whole assembly.
/// </summary>
/// <param name="monoClass">The Mono class.</param>
/// <returns>The MClass object or null if missing.</returns>
static MClass* FindClass(MonoClass* monoClass);
/// <summary>
/// Finds the native class with given fully qualified name within whole assembly.
/// </summary>
/// <param name="fullname">The full name of the type eg: System.Int64.</param>
/// <returns>The MClass object or null if missing.</returns>
static MonoClass* FindClassNative(const StringAnsiView& fullname);
#endif
/// <summary>
/// Finds the scripting type of the given fullname by searching loaded scripting assemblies.
/// </summary>

View File

@@ -3,7 +3,6 @@
#include "ScriptingObject.h"
#include "Scripting.h"
#include "BinaryModule.h"
#include "InternalCalls.h"
#include "Engine/Level/Actor.h"
#include "Engine/Core/Log.h"
#include "Engine/Utilities/StringConverter.h"
@@ -15,11 +14,8 @@
#include "ManagedCLR/MUtils.h"
#include "ManagedCLR/MField.h"
#include "ManagedCLR/MCore.h"
#include "Internal/InternalCalls.h"
#include "FlaxEngine.Gen.h"
#if USE_MONO
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
#endif
#define ScriptingObject_unmanagedPtr "__unmanagedPtr"
#define ScriptingObject_id "__internalId"
@@ -73,8 +69,8 @@ MObject* ScriptingObject::GetManagedInstance() const
#elif USE_MONO
const MGCHandle handle = Platform::AtomicRead((int32*)&_gcHandle);
#endif
#if USE_MONO
return handle ? MUtils::GetGCHandleTarget(handle) : nullptr;
#if USE_CSHARP
return handle ? MCore::GCHandle::GetTarget(handle) : nullptr;
#else
return nullptr;
#endif
@@ -180,13 +176,13 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
ScriptingObject* ScriptingObject::ToNative(MObject* obj)
{
ScriptingObject* ptr = nullptr;
#if USE_MONO
#if USE_CSHARP
if (obj)
{
// TODO: cache the field offset from object and read directly from object pointer
const auto ptrField = mono_class_get_field_from_name(mono_object_get_class(obj), ScriptingObject_unmanagedPtr);
const auto ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr);
CHECK_RETURN(ptrField, nullptr);
mono_field_get_value(obj, ptrField, &ptr);
ptrField->GetValue(obj, &ptr);
}
#endif
return ptr;
@@ -227,7 +223,7 @@ void ScriptingObject::SetManagedInstance(MObject* instance)
#if USE_NETCORE
_gcHandle = (MGCHandle)instance;
#elif !COMPILE_WITHOUT_CSHARP
_gcHandle = MUtils::NewGCHandle(instance, false);
_gcHandle = MCore::GCHandle::New(instance, false);
#endif
}
@@ -236,8 +232,8 @@ void ScriptingObject::OnManagedInstanceDeleted()
// Release the handle
if (_gcHandle)
{
#if USE_MONO
MUtils::FreeGCHandle(_gcHandle);
#if USE_CSHARP
MCore::GCHandle::Free(_gcHandle);
#endif
_gcHandle = 0;
}
@@ -257,8 +253,8 @@ void ScriptingObject::OnScriptingDispose()
bool ScriptingObject::CreateManaged()
{
#if USE_MONO
MonoObject* managedInstance = CreateManagedInternal();
#if USE_CSHARP
MObject* managedInstance = CreateManagedInternal();
if (!managedInstance)
return true;
@@ -268,7 +264,7 @@ bool ScriptingObject::CreateManaged()
auto oldHandle = Platform::InterlockedCompareExchange((int64*)&_gcHandle, *(int64*)&handle, 0);
if (*(uint64*)&oldHandle != 0)
#else
auto handle = MUtils::NewGCHandle(managedInstance, false);
auto handle = MCore::GCHandle::New(managedInstance, false);
auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0);
if (*(uint32*)&oldHandle != 0)
#endif
@@ -284,7 +280,7 @@ bool ScriptingObject::CreateManaged()
monoUnmanagedPtrField->SetValue(managedInstance, &param);
}
}
MUtils::FreeGCHandle(handle);
MCore::GCHandle::Free(handle);
return true;
}
#endif
@@ -296,9 +292,9 @@ bool ScriptingObject::CreateManaged()
return false;
}
#if USE_MONO
#if USE_CSHARP
MonoObject* ScriptingObject::CreateManagedInternal()
MObject* ScriptingObject::CreateManagedInternal()
{
// Get class
MClass* monoClass = GetClass();
@@ -309,15 +305,10 @@ MonoObject* ScriptingObject::CreateManagedInternal()
}
// Ensure to have managed domain attached (this can be called from custom native thread, eg. content loader)
auto domain = mono_domain_get();
if (!domain)
{
MCore::AttachThread();
domain = mono_domain_get();
}
MCore::Thread::Attach();
// Allocate managed instance
MonoObject* managedInstance = mono_object_new(domain, monoClass->GetNative());
MObject* managedInstance = MCore::Object::New(monoClass);
if (managedInstance == nullptr)
{
LOG(Warning, "Failed to create new instance of the object of type {0}", String(monoClass->GetFullName()));
@@ -339,7 +330,7 @@ MonoObject* ScriptingObject::CreateManagedInternal()
}
// Initialize managed instance (calls constructor)
mono_runtime_object_init(managedInstance);
MCore::Object::Init(managedInstance);
return managedInstance;
}
@@ -348,7 +339,7 @@ MonoObject* ScriptingObject::CreateManagedInternal()
void ScriptingObject::DestroyManaged()
{
#if USE_MONO
#if USE_CSHARP
// Get managed instance
const auto managedInstance = GetManagedInstance();
@@ -369,7 +360,7 @@ void ScriptingObject::DestroyManaged()
// Clear the handle
if (_gcHandle)
{
MUtils::FreeGCHandle(_gcHandle);
MCore::GCHandle::Free(_gcHandle);
_gcHandle = 0;
}
#else
@@ -407,30 +398,12 @@ bool ScriptingObject::CanCast(const MClass* from, const MClass* to)
#if PLATFORM_LINUX || PLATFORM_MAC
// Cannot enter GC unsafe region if the thread is not attached
MCore::AttachThread();
MCore::Thread::Attach();
#endif
return from->IsSubClassOf(to);
}
#if USE_MONO
bool ScriptingObject::CanCast(const MClass* from, const MonoClass* to)
{
if (!from && !to)
return true;
CHECK_RETURN(from && to, false);
#if PLATFORM_LINUX
// Cannot enter GC unsafe region if the thread is not attached
MCore::AttachThread();
#endif
return from->IsSubClassOf(to);
}
#endif
void ScriptingObject::OnDeleteObject()
{
// Cleanup managed object
@@ -460,7 +433,7 @@ void ManagedScriptingObject::SetManagedInstance(MObject* instance)
#if USE_NETCORE
_gcHandle = (MGCHandle)instance;
#elif !COMPILE_WITHOUT_CSHARP
_gcHandle = MUtils::NewGCHandleWeakref(instance, false);
_gcHandle = MCore::GCHandle::NewWeak(instance, false);
#endif
}
@@ -484,8 +457,8 @@ void ManagedScriptingObject::OnScriptingDispose()
bool ManagedScriptingObject::CreateManaged()
{
#if USE_MONO
MonoObject* managedInstance = CreateManagedInternal();
#if USE_CSHARP
MObject* managedInstance = CreateManagedInternal();
if (!managedInstance)
return true;
@@ -495,7 +468,7 @@ bool ManagedScriptingObject::CreateManaged()
auto oldHandle = Platform::InterlockedCompareExchange((int64*)&_gcHandle, *(int64*)&handle, 0);
if (*(uint64*)&oldHandle != 0)
#else
auto handle = MUtils::NewGCHandleWeakref(managedInstance, false);
auto handle = MCore::GCHandle::NewWeak(managedInstance, false);
auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0);
if (*(uint32*)&oldHandle != 0)
#endif
@@ -511,7 +484,7 @@ bool ManagedScriptingObject::CreateManaged()
monoUnmanagedPtrField->SetValue(managedInstance, &param);
}
}
MUtils::FreeGCHandle(handle);
MCore::GCHandle::Free(handle);
return true;
}
#endif
@@ -528,21 +501,21 @@ PersistentScriptingObject::PersistentScriptingObject(const SpawnParams& params)
{
}
#if !COMPILE_WITHOUT_CSHARP
#if USE_CSHARP
DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create1(MonoReflectionType* type)
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create1(MTypeObject* type)
{
// Peek class for that type (handle generic class cases)
if (!type)
DebugLog::ThrowArgumentNull("type");
MonoType* monoType = mono_reflection_type_get_type(type);
const int32 monoTypeType = mono_type_get_type(monoType);
if (monoTypeType == MONO_TYPE_GENERICINST)
MType* mType = INTERNAL_TYPE_OBJECT_GET(type);
const MTypes mTypeType = MCore::Type::GetType(mType);
if (mTypeType == MTypes::GenericInst)
{
LOG(Error, "Generic scripts are not supported.");
return nullptr;
}
MonoClass* typeClass = mono_type_get_class(monoType);
MClass* typeClass = MCore::Type::GetClass(mType);
if (typeClass == nullptr)
{
LOG(Error, "Invalid type.");
@@ -553,7 +526,7 @@ DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create1(MonoReflectionType* typ
auto module = ManagedBinaryModule::FindModule(typeClass);
if (module == nullptr)
{
LOG(Error, "Cannot find scripting assembly for type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot find scripting assembly for type \'{0}\'.", String(typeClass->GetFullName()));
return nullptr;
}
@@ -561,7 +534,7 @@ DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create1(MonoReflectionType* typ
int32 typeIndex;
if (!module->ClassToTypeIndex.TryGet(typeClass, typeIndex))
{
LOG(Error, "Cannot spawn objects of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot spawn objects of type \'{0}\'.", String(typeClass->GetFullName()));
return nullptr;
}
const ScriptingType& scriptingType = module->Types[typeIndex];
@@ -571,35 +544,36 @@ DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create1(MonoReflectionType* typ
ScriptingObject* obj = scriptingType.Script.Spawn(params);
if (obj == nullptr)
{
LOG(Error, "Failed to spawn object of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Failed to spawn object of type \'{0}\'.", String(typeClass->GetFullName()));
return nullptr;
}
// Set default name for actors
if (auto* actor = dynamic_cast<Actor*>(obj))
{
actor->SetName(String(mono_class_get_name(typeClass)));
actor->SetName(String(typeClass->GetName()));
}
// Create managed object
obj->CreateManaged();
MonoObject* managedInstance = obj->GetManagedInstance();
MObject* managedInstance = obj->GetManagedInstance();
if (managedInstance == nullptr)
{
LOG(Error, "Cannot create managed instance for type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot create managed instance for type \'{0}\'.", String(typeClass->GetFullName()));
Delete(obj);
}
return managedInstance;
}
DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create2(MonoString* typeNameObj)
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create2(MString* typeNameObj)
{
// Get typename
if (typeNameObj == nullptr)
DebugLog::ThrowArgumentNull("typeName");
const StringAsANSI<> typeNameData((const Char*)mono_string_chars(typeNameObj), (int32)mono_string_length(typeNameObj));
const StringAnsiView typeName(typeNameData.Get(), (int32)mono_string_length(typeNameObj));
const StringView typeNameChars = MCore::String::GetChars(typeNameObj);
const StringAsANSI<100> typeNameData(typeNameChars.Get(), typeNameChars.Length());
const StringAnsiView typeName(typeNameData.Get(), typeNameChars.Length());
// Try to find the scripting type for this typename
const ScriptingTypeHandle type = Scripting::FindScriptingType(typeName);
@@ -620,7 +594,7 @@ DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create2(MonoString* typeNameObj
// Create managed object
obj->CreateManaged();
MonoObject* managedInstance = obj->GetManagedInstance();
MObject* managedInstance = obj->GetManagedInstance();
if (managedInstance == nullptr)
{
LOG(Error, "Cannot create managed instance for type \'{0}\'.", String(typeName));
@@ -630,15 +604,15 @@ DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_Create2(MonoString* typeNameObj
return managedInstance;
}
DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MonoObject* managedInstance)
DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* managedInstance)
{
MonoClass* typeClass = mono_object_get_class(managedInstance);
MClass* typeClass = MCore::Object::GetClass(managedInstance);
// Get the assembly with that class
auto module = ManagedBinaryModule::FindModule(typeClass);
if (module == nullptr)
{
LOG(Error, "Cannot find scripting assembly for type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot find scripting assembly for type \'{0}\'.", String(typeClass->GetFullName()));
return;
}
@@ -646,7 +620,7 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MonoObject* man
int32 typeIndex;
if (!module->ClassToTypeIndex.TryGet(typeClass, typeIndex))
{
LOG(Error, "Cannot spawn objects of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Cannot spawn objects of type \'{0}\'.", String(typeClass->GetFullName()));
return;
}
const ScriptingType& scriptingType = module->Types[typeIndex];
@@ -656,14 +630,14 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MonoObject* man
ScriptingObject* obj = scriptingType.Script.Spawn(params);
if (obj == nullptr)
{
LOG(Error, "Failed to spawn object of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
LOG(Error, "Failed to spawn object of type \'{0}\'.", String(typeClass->GetFullName()));
return;
}
// Set default name for actors
if (auto* actor = dynamic_cast<Actor*>(obj))
{
actor->SetName(String(mono_class_get_name(typeClass)));
actor->SetName(String(typeClass->GetName()));
}
// Link created managed instance to the unmanaged object
@@ -706,21 +680,21 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_Destroy(ScriptingObject* obj, float ti
obj->DeleteObject(timeLeft, useGameTime);
}
DEFINE_INTERNAL_CALL(MonoString*) ObjectInternal_GetTypeName(ScriptingObject* obj)
DEFINE_INTERNAL_CALL(MString*) ObjectInternal_GetTypeName(ScriptingObject* obj)
{
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
return MUtils::ToString(obj->GetType().Fullname);
}
DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_FindObject(Guid* id, MonoReflectionType* type)
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_FindObject(Guid* id, MTypeObject* type)
{
if (!id->IsValid())
return nullptr;
auto klass = MUtils::GetClass(type);
MClass* klass = MUtils::GetClass(type);
ScriptingObject* obj = Scripting::TryFindObject(*id);
if (!obj)
{
if (!klass || klass == ScriptingObject::GetStaticClass()->GetNative() || mono_class_is_subclass_of(klass, Asset::GetStaticClass()->GetNative(), false) != 0)
if (!klass || klass == ScriptingObject::GetStaticClass() || klass->IsSubClassOf(Asset::GetStaticClass()))
{
obj = Content::LoadAsync<Asset>(*id);
}
@@ -729,19 +703,19 @@ DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_FindObject(Guid* id, MonoReflec
{
if (klass && !obj->Is(klass))
{
LOG(Warning, "Found scripting object with ID={0} of type {1} that doesn't match type {2}.", *id, String(obj->GetType().Fullname), String(MUtils::GetClassFullname(klass)));
LOG(Warning, "Found scripting object with ID={0} of type {1} that doesn't match type {2}.", *id, String(obj->GetType().Fullname), String(klass->GetFullName()));
return nullptr;
}
return obj->GetOrCreateManagedInstance();
}
if (klass)
LOG(Warning, "Unable to find scripting object with ID={0}. Required type {1}.", *id, String(MUtils::GetClassFullname(klass)));
LOG(Warning, "Unable to find scripting object with ID={0}. Required type {1}.", *id, String(klass->GetFullName()));
else
LOG(Warning, "Unable to find scripting object with ID={0}", *id);
return nullptr;
}
DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_TryFindObject(Guid* id, MonoReflectionType* type)
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_TryFindObject(Guid* id, MTypeObject* type)
{
ScriptingObject* obj = Scripting::TryFindObject(*id);
if (obj && !obj->Is(MUtils::GetClass(type)))
@@ -755,11 +729,11 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ChangeID(ScriptingObject* obj, Guid* i
obj->ChangeID(*id);
}
DEFINE_INTERNAL_CALL(void*) ObjectInternal_GetUnmanagedInterface(ScriptingObject* obj, MonoReflectionType* type)
DEFINE_INTERNAL_CALL(void*) ObjectInternal_GetUnmanagedInterface(ScriptingObject* obj, MTypeObject* type)
{
if (obj && type)
{
auto typeClass = MUtils::GetClass(type);
MClass* typeClass = MUtils::GetClass(type);
const ScriptingTypeHandle interfaceType = ManagedBinaryModule::FindType(typeClass);
if (interfaceType)
{
@@ -769,9 +743,9 @@ DEFINE_INTERNAL_CALL(void*) ObjectInternal_GetUnmanagedInterface(ScriptingObject
return nullptr;
}
DEFINE_INTERNAL_CALL(MonoObject*) ObjectInternal_FromUnmanagedPtr(ScriptingObject* obj)
DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_FromUnmanagedPtr(ScriptingObject* obj)
{
MonoObject* result = nullptr;
MObject* result = nullptr;
if (obj)
result = obj->GetOrCreateManagedInstance();
return result;

View File

@@ -152,9 +152,6 @@ public:
/// <param name="to">The destination class to the cast.</param>
/// <returns>True if can, otherwise false.</returns>
static bool CanCast(const MClass* from, const MClass* to);
#if USE_MONO
static bool CanCast(const MClass* from, const MonoClass* to);
#endif
template<typename T>
static T* Cast(ScriptingObject* obj)
@@ -169,13 +166,6 @@ public:
return CanCast(GetClass(), type);
}
#if USE_MONO
bool Is(MonoClass* klass) const
{
return CanCast(GetClass(), klass);
}
#endif
template<typename T>
bool Is() const
{
@@ -217,11 +207,11 @@ public:
void UnregisterObject();
protected:
#if USE_MONO
#if USE_CSHARP
/// <summary>
/// Create a new managed object.
/// </summary>
MonoObject* CreateManagedInternal();
MObject* CreateManagedInternal();
#endif
public:

View File

@@ -65,8 +65,8 @@ struct FLAXENGINE_API ScriptingTypeHandle
String ToString(bool withAssembly = false) const;
const ScriptingType& GetType() const;
#if USE_MONO
MonoClass* GetMonoClass() const;
#if USE_CSHARP
MClass* GetClass() const;
#endif
bool IsSubclassOf(ScriptingTypeHandle c) const;
bool IsAssignableFrom(ScriptingTypeHandle c) const;

View File

@@ -19,51 +19,43 @@ class MMethod;
class MProperty;
class MEvent;
class MDomain;
class MType;
#if COMPILE_WITHOUT_CSHARP
// No Scripting
#define USE_CSHARP 0
#define USE_MONO 0
#define USE_NETCORE 0
typedef void MObject;
// Dummy types declarations
typedef struct CSharpObject MObject;
typedef struct CSharpArray MArray;
typedef struct CSharpString MString;
typedef struct CSharpType MType;
typedef MType MTypeObject;
typedef unsigned int MGCHandle;
#define INTERNAL_TYPE_GET_OBJECT(type) (type)
#define INTERNAL_TYPE_OBJECT_GET(type) (type)
#else
#define USE_MONO 1
#if COMPILE_WITH_MONO
#define USE_NETCORE 0
#else
#define USE_NETCORE 1
#endif
// Enables using single (root) app domain for the user scripts
#define USE_SCRIPTING_SINGLE_DOMAIN 1
#if USE_MONO
// Enables/disables profiling managed world via Mono
#define USE_MONO_PROFILER (COMPILE_WITH_PROFILER)
// Enable/disable mono debugging
#define MONO_DEBUG_ENABLE (!BUILD_RELEASE && !USE_NETCORE)
#ifndef USE_MONO_AOT
#define USE_MONO_AOT 0
#define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE
#endif
#if USE_NETCORE
struct _MonoDomain {};
struct _MonoThread {};
#endif
#if COMPILE_WITH_MONO
#if USE_NETCORE
typedef unsigned long long MGCHandle;
#else
typedef unsigned int MGCHandle;
#endif
// Mono scripting
#define USE_CSHARP 1
#define USE_MONO 1
#define USE_NETCORE 0
// Enables/disables profiling managed world via Mono
#define USE_MONO_PROFILER (COMPILE_WITH_PROFILER)
// Enable/disable mono debugging
#define MONO_DEBUG_ENABLE (!BUILD_RELEASE)
// Mono types declarations
typedef struct _MonoClass MonoClass;
@@ -82,7 +74,34 @@ typedef struct _MonoReflectionAssembly MonoReflectionAssembly;
typedef struct _MonoException MonoException;
typedef struct _MonoClassField MonoClassField;
typedef MonoObject MObject;
typedef MonoArray MArray;
typedef MonoString MString;
typedef MonoType MType;
typedef MonoReflectionType MTypeObject;
typedef unsigned int MGCHandle;
#define INTERNAL_TYPE_GET_OBJECT(type) MCore::Type::GetObject(type)
#define INTERNAL_TYPE_OBJECT_GET(type) MCore::Type::Get(type)
#else
// .NET scripting
#define USE_CSHARP 1
#define USE_MONO 0
#define USE_NETCORE 1
// Dotnet types declarations
typedef struct DotNetObject MObject;
typedef struct DotNetArray MArray;
typedef struct DotNetString MString;
typedef struct DotNetType MType;
typedef MType MTypeObject;
typedef unsigned long long MGCHandle;
#define INTERNAL_TYPE_GET_OBJECT(type) (type)
#define INTERNAL_TYPE_OBJECT_GET(type) (type)
#endif
// Enables using single (root) app domain for the user scripts
#define USE_SCRIPTING_SINGLE_DOMAIN 1
#endif

View File

@@ -78,6 +78,12 @@ public:
String(buf.Get());
}
void String(const StringView& value)
{
const StringAsUTF8<256> buf(*value, value.Length());
String(buf.Get());
}
void String(const StringAnsi& value)
{
String(value.Get(), static_cast<unsigned>(value.Length()));
@@ -85,7 +91,13 @@ public:
FORCE_INLINE void RawValue(const StringAnsi& str)
{
RawValue(str.Get(), static_cast<int32>(str.Length()));
RawValue(str.Get(), str.Length());
}
void RawValue(const StringView& str)
{
const StringAsUTF8<256> buf(*str, str.Length());
RawValue(buf.Get(), buf.Length());
}
FORCE_INLINE void RawValue(const CharType* json)

View File

@@ -18,14 +18,12 @@
#include "Engine/Core/Math/Color.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Scripting/ManagedSerialization.h"
#include "Engine/Scripting/Internal/ManagedSerialization.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
#include "Engine/Content/Asset.h"
#include "Engine/Utilities/Encryption.h"
#if USE_MONO
#include <mono/metadata/object.h>
#endif
void ISerializable::DeserializeIfExists(DeserializeStream& stream, const char* memberName, ISerializeModifier* modifier)
{
@@ -216,12 +214,12 @@ void Serialization::Serialize(ISerializable::SerializeStream& stream, const Vari
case VariantType::ManagedObject:
case VariantType::Structure:
{
#if USE_MONO
MonoObject* obj;
#if USE_CSHARP
MObject* obj;
if (v.Type.Type == VariantType::Structure)
obj = MUtils::BoxVariant(v);
else
obj = (MonoObject*)v;
obj = (MObject*)v;
ManagedSerialization::Serialize(stream, obj);
#endif
break;
@@ -365,24 +363,24 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
case VariantType::ManagedObject:
case VariantType::Structure:
{
#if USE_MONO
auto obj = (MonoObject*)v;
#if USE_CSHARP
auto obj = (MObject*)v;
if (!obj && v.Type.TypeName)
{
MonoClass* klass = MUtils::GetClass(v.Type);
MClass* klass = MUtils::GetClass(v.Type);
if (!klass)
{
LOG(Error, "Invalid variant type {0}", v.Type);
return;
}
obj = mono_object_new(mono_domain_get(), klass);
obj = MCore::Object::New(klass);
if (!obj)
{
LOG(Error, "Failed to managed instance of the variant type {0}", v.Type);
return;
}
if (!mono_class_is_valuetype(klass))
mono_runtime_object_init(obj);
if (!klass->IsValueType())
MCore::Object::Init(obj);
if (v.Type.Type == VariantType::ManagedObject)
v.SetManagedObject(obj);
}

View File

@@ -12,9 +12,10 @@
#include "Engine/Core/Cache.h"
#include "Engine/Debug/Exceptions/JsonParseException.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/ManagedSerialization.h"
#include "Engine/Scripting/Internal/ManagedSerialization.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingObject.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
@@ -359,22 +360,22 @@ void ReadStream::Read(Variant& data)
// Json
StringAnsi json;
ReadStringAnsi(&json, -71);
#if USE_MONO
MCore::AttachThread();
MonoClass* klass = MUtils::GetClass(data.Type);
#if USE_CSHARP
MCore::Thread::Attach();
MClass* klass = MUtils::GetClass(data.Type);
if (!klass)
{
LOG(Error, "Invalid variant type {0}", data.Type);
return;
}
MonoObject* obj = mono_object_new(mono_domain_get(), klass);
MObject* obj = MCore::Object::New(klass);
if (!obj)
{
LOG(Error, "Failed to managed instance of the variant type {0}", data.Type);
return;
}
if (!mono_class_is_valuetype(klass))
mono_runtime_object_init(obj);
if (!klass->IsValueType())
MCore::Object::Init(obj);
ManagedSerialization::Deserialize(json, obj);
if (data.Type.Type == VariantType::ManagedObject)
data.SetManagedObject(obj);
@@ -900,18 +901,18 @@ void WriteStream::Write(const Variant& data)
case VariantType::ManagedObject:
case VariantType::Structure:
{
#if USE_MONO
MonoObject* obj;
#if USE_CSHARP
MObject* obj;
if (data.Type.Type == VariantType::Structure)
obj = MUtils::BoxVariant(data);
else
obj = (MonoObject*)data;
obj = (MObject*)data;
if (obj)
{
WriteByte(1);
rapidjson_flax::StringBuffer json;
CompactJsonWriter writerObj(json);
MCore::AttachThread();
MCore::Thread::Attach();
ManagedSerialization::Serialize(writerObj, obj);
WriteStringAnsi(StringAnsiView(json.GetString(), (int32)json.GetSize()), -71);
}

View File

@@ -8,11 +8,8 @@
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Profiler/ProfilerCPU.h"
#if USE_CSHARP
#include "Engine/Scripting/ManagedCLR/MCore.h"
#if USE_MONO
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include <mono/metadata/appdomain.h>
#include <mono/metadata/threads.h>
#endif
// Jobs storage perf info:
@@ -161,7 +158,7 @@ int32 JobSystemThread::Run()
Platform::SetThreadAffinityMask(1ull << Index);
JobData data;
bool attachMonoThread = true;
bool attachCSharpThread = true;
#if !JOB_SYSTEM_USE_MUTEX
moodycamel::ConsumerToken consumerToken(Jobs);
#endif
@@ -190,13 +187,12 @@ int32 JobSystemThread::Run()
if (data.Job.IsBinded())
{
#if USE_MONO
#if USE_CSHARP
// Ensure to have C# thread attached to this thead (late init due to MCore being initialized after Job System)
if (attachMonoThread && !mono_domain_get())
if (attachCSharpThread)
{
const auto domain = MCore::GetActiveDomain();
mono_thread_attach(domain->GetNative());
attachMonoThread = false;
MCore::Thread::Attach();
attachCSharpThread = false;
}
#endif

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