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:
@@ -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)
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class CustomEditorsUtil
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
static MonoReflectionType* GetCustomEditor(MonoReflectionType* refType);
|
||||
#if USE_CSHARP
|
||||
static MTypeObject* GetCustomEditor(MTypeObject* refType);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ protected:
|
||||
int32 _length = 0;
|
||||
|
||||
public:
|
||||
typedef T CharType;
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="StringBase"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -29,6 +29,8 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
typedef T CharType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specific const character from this string.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
8634
Source/Engine/Localization/CultureInfo.Tables.h
Normal file
8634
Source/Engine/Localization/CultureInfo.Tables.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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:
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
@@ -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>
|
||||
@@ -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) \
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
1827
Source/Engine/Scripting/Runtime/DotNet.cpp
Normal file
1827
Source/Engine/Scripting/Runtime/DotNet.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3564
Source/Engine/Scripting/Runtime/Mono.cpp
Normal file
3564
Source/Engine/Scripting/Runtime/Mono.cpp
Normal file
File diff suppressed because it is too large
Load Diff
537
Source/Engine/Scripting/Runtime/None.cpp
Normal file
537
Source/Engine/Scripting/Runtime/None.cpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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, ¶m);
|
||||
}
|
||||
}
|
||||
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, ¶m);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user