Add support for compiling and running engine without C# scripting

(configurable via `EngineConfiguration.UseCSharp` in Flax.Build)
This commit is contained in:
Wojtek Figat
2021-10-23 16:41:57 +02:00
parent 0b3d6b03ac
commit 8938f13a0b
86 changed files with 1244 additions and 688 deletions

View File

@@ -3,6 +3,7 @@
#include "GameCooker.h" #include "GameCooker.h"
#include "FlaxEngine.Gen.h" #include "FlaxEngine.Gen.h"
#include "Engine/Scripting/MainThreadManagedInvokeAction.h" #include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/Scripting/ManagedCLR/MTypes.h"
#include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/Scripting.h" #include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingType.h" #include "Engine/Scripting/ScriptingType.h"
@@ -450,7 +451,7 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
} }
MCore::AttachThread(); MCore::AttachThread();
MonoObject* exception = nullptr; MObject* exception = nullptr;
auto list = (MonoArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception); auto list = (MonoArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
if (exception) if (exception)
{ {
@@ -486,7 +487,7 @@ bool GameCookerImpl::Build()
Steps.Add(New<PostProcessStep>()); Steps.Add(New<PostProcessStep>());
} }
MCore::Instance()->AttachThread(); MCore::AttachThread();
// Build Started // Build Started
CallEvent(GameCooker::EventType::BuildStarted); CallEvent(GameCooker::EventType::BuildStarted);

View File

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

View File

@@ -126,7 +126,7 @@ void OnVisualScriptingDebugFlow()
flowInfo.ScriptInstance = stack->Instance ? stack->Instance->GetOrCreateManagedInstance() : nullptr; flowInfo.ScriptInstance = stack->Instance ? stack->Instance->GetOrCreateManagedInstance() : nullptr;
flowInfo.NodeId = stack->Node->ID; flowInfo.NodeId = stack->Node->ID;
flowInfo.BoxId = stack->Box->ID; flowInfo.BoxId = stack->Box->ID;
MonoObject* exception = nullptr; MObject* exception = nullptr;
void* params[1]; void* params[1];
params[0] = &flowInfo; params[0] = &flowInfo;
Internal_OnVisualScriptingDebugFlow->Invoke(nullptr, params, &exception); Internal_OnVisualScriptingDebugFlow->Invoke(nullptr, params, &exception);
@@ -191,7 +191,7 @@ void ManagedEditor::Init()
{ {
LOG(Fatal, "Failed to create editor instance."); LOG(Fatal, "Failed to create editor instance.");
} }
MonoObject* exception = nullptr; MObject* exception = nullptr;
bool isHeadless = CommandLine::Options.Headless.IsTrue(); bool isHeadless = CommandLine::Options.Headless.IsTrue();
bool skipCompile = CommandLine::Options.SkipCompile.IsTrue(); bool skipCompile = CommandLine::Options.SkipCompile.IsTrue();
bool newProject = CommandLine::Options.NewProject.IsTrue(); bool newProject = CommandLine::Options.NewProject.IsTrue();
@@ -259,7 +259,7 @@ void ManagedEditor::Update()
} }
// Call update // Call update
MonoObject* exception = nullptr; MObject* exception = nullptr;
UpdateMethod->Invoke(instance, nullptr, &exception); UpdateMethod->Invoke(instance, nullptr, &exception);
if (exception) if (exception)
{ {
@@ -291,7 +291,7 @@ void ManagedEditor::Exit()
{ {
LOG(Fatal, "Invalid Editor assembly!"); LOG(Fatal, "Invalid Editor assembly!");
} }
MonoObject* exception = nullptr; MObject* exception = nullptr;
exitMethod->Invoke(instance, nullptr, &exception); exitMethod->Invoke(instance, nullptr, &exception);
if (exception) if (exception)
{ {

View File

@@ -456,7 +456,7 @@ void ScriptsBuilderImpl::CallCompileEvent(EventData& data)
LOG(Fatal, "Invalid Editor assembly!"); LOG(Fatal, "Invalid Editor assembly!");
} }
} }
/*MonoObject* exception = nullptr; /*MObject* exception = nullptr;
void* args[1]; void* args[1];
args[0] = &data.Type; args[0] = &data.Type;
Internal_OnEvent->Invoke(nullptr, args, &exception); Internal_OnEvent->Invoke(nullptr, args, &exception);

View File

@@ -11,6 +11,9 @@
#include "Engine/Scripting/Scripting.h" #include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/MException.h" #include "Engine/Scripting/MException.h"
#include "Engine/Content/Assets/SkinnedModel.h" #include "Engine/Content/Assets/SkinnedModel.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
struct InternalInitData struct InternalInitData
@@ -80,15 +83,20 @@ namespace AnimGraphInternal
} }
} }
#endif
void AnimGraphExecutor::initRuntime() void AnimGraphExecutor::initRuntime()
{ {
#if USE_MONO
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_HasConnection", &AnimGraphInternal::HasConnection); ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_HasConnection", &AnimGraphInternal::HasConnection);
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetInputValue", &AnimGraphInternal::GetInputValue); ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetInputValue", &AnimGraphInternal::GetInputValue);
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData", &AnimGraphInternal::GetOutputImpulseData); ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData", &AnimGraphInternal::GetOutputImpulseData);
#endif
} }
void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value& value) void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value& value)
{ {
#if USE_MONO
auto& context = Context.Get(); auto& context = Context.Get();
if (context.ValueCache.TryGet(boxBase, value)) if (context.ValueCache.TryGet(boxBase, value))
return; return;
@@ -124,7 +132,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
// Evaluate node // Evaluate node
void* params[1]; void* params[1];
params[0] = &internalContext; params[0] = &internalContext;
MonoObject* exception = nullptr; MObject* exception = nullptr;
MonoObject* result = data.Evaluate->Invoke(obj, params, &exception); MonoObject* result = data.Evaluate->Invoke(obj, params, &exception);
if (exception) if (exception)
{ {
@@ -136,6 +144,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
// Extract result // Extract result
value = MUtils::UnboxVariant(result); value = MUtils::UnboxVariant(result);
context.ValueCache.Add(boxBase, value); context.ValueCache.Add(boxBase, value);
#endif
} }
bool AnimGraph::IsReady() const bool AnimGraph::IsReady() const
@@ -156,13 +165,16 @@ void AnimGraph::ClearCustomNode(Node* node)
data.Evaluate = nullptr; data.Evaluate = nullptr;
if (data.Handle) if (data.Handle)
{ {
#if USE_MONO
mono_gchandle_free(data.Handle); mono_gchandle_free(data.Handle);
#endif
data.Handle = 0; data.Handle = 0;
} }
} }
bool AnimGraph::InitCustomNode(Node* node) bool AnimGraph::InitCustomNode(Node* node)
{ {
#if USE_MONO
// Fetch the node logic controller type // Fetch the node logic controller type
if (node->Values.Count() < 2 || node->Values[0].Type.Type != ValueType::String) if (node->Values.Count() < 2 || node->Values[0].Type.Type != ValueType::String)
{ {
@@ -212,7 +224,7 @@ bool AnimGraph::InitCustomNode(Node* node)
initData.BaseModel = BaseModel.GetManagedInstance(); initData.BaseModel = BaseModel.GetManagedInstance();
void* params[1]; void* params[1];
params[0] = &initData; params[0] = &initData;
MonoObject* exception = nullptr; MObject* exception = nullptr;
load->Invoke(obj, params, &exception); load->Invoke(obj, params, &exception);
if (exception) if (exception)
{ {
@@ -227,7 +239,7 @@ bool AnimGraph::InitCustomNode(Node* node)
auto& data = node->Data.Custom; auto& data = node->Data.Custom;
data.Evaluate = evaluate; data.Evaluate = evaluate;
data.Handle = handleGC; data.Handle = handleGC;
#endif
return false; return false;
} }

View File

@@ -260,6 +260,7 @@ void SceneAnimationPlayer::MapTrack(const StringView& from, const Guid& to)
void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset) void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
{ {
#if USE_MONO
// Restore all tracks // Restore all tracks
for (int32 j = 0; j < anim->Tracks.Count(); j++) for (int32 j = 0; j < anim->Tracks.Count(); j++)
{ {
@@ -293,7 +294,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|| state.RestoreStateIndex == -1 || state.RestoreStateIndex == -1
|| (state.Field == nullptr && state.Property == nullptr)) || (state.Field == nullptr && state.Property == nullptr))
break; break;
MonoObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject; MObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject;
if (!instance) if (!instance)
break; break;
@@ -318,7 +319,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
{ {
if (state.Property) if (state.Property)
{ {
MonoObject* exception = nullptr; MObject* exception = nullptr;
state.ManagedObject = state.Property->GetValue(instance, &exception); state.ManagedObject = state.Property->GetValue(instance, &exception);
if (exception) if (exception)
{ {
@@ -341,7 +342,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
// Set the value // Set the value
if (state.Property) if (state.Property)
{ {
MonoObject* exception = nullptr; MObject* exception = nullptr;
state.Property->SetValue(instance, value, &exception); state.Property->SetValue(instance, value, &exception);
if (exception) if (exception)
{ {
@@ -353,16 +354,17 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
{ {
state.Field->SetValue(instance, value); state.Field->SetValue(instance, value);
} }
break; break;
} }
default: ; default: ;
} }
} }
#endif
} }
bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexOffset, SceneAnimation* anim, float time, const SceneAnimation::Track& track, TrackInstance& state, void* target) bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexOffset, SceneAnimation* anim, float time, const SceneAnimation::Track& track, TrackInstance& state, void* target)
{ {
#if USE_MONO
switch (track.Type) switch (track.Type)
{ {
case SceneAnimation::Track::Types::KeyframesProperty: case SceneAnimation::Track::Types::KeyframesProperty:
@@ -511,17 +513,18 @@ bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexO
case SceneAnimation::Track::Types::ObjectProperty: case SceneAnimation::Track::Types::ObjectProperty:
{ {
// Cache the sub-object pointer for the sub-tracks // Cache the sub-object pointer for the sub-tracks
state.ManagedObject = *(MonoObject**)target; state.ManagedObject = *(MObject**)target;
return false; return false;
} }
default: ; default: ;
} }
#endif
return true; return true;
} }
void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset, CallStack& callStack) void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset, CallStack& callStack)
{ {
#if USE_MONO
const float fps = anim->FramesPerSecond; const float fps = anim->FramesPerSecond;
#if !BUILD_RELEASE || USE_EDITOR #if !BUILD_RELEASE || USE_EDITOR
callStack.Add(anim); callStack.Add(anim);
@@ -827,7 +830,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
break; break;
// Skip if parent object is missing // Skip if parent object is missing
MonoObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject; MObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject;
if (!instance) if (!instance)
break; break;
@@ -860,7 +863,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
{ {
if (state.Property) if (state.Property)
{ {
MonoObject* exception = nullptr; MObject* exception = nullptr;
auto boxed = state.Property->GetValue(instance, &exception); auto boxed = state.Property->GetValue(instance, &exception);
if (exception) if (exception)
{ {
@@ -876,7 +879,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
} }
else else
{ {
*(MonoObject**)value = boxed; *(MObject**)value = boxed;
} }
} }
else else
@@ -900,7 +903,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
} }
case SceneAnimation::Track::Types::ObjectReferenceProperty: case SceneAnimation::Track::Types::ObjectReferenceProperty:
{ {
auto obj = Scripting::FindObject(*(MonoObject**)value); auto obj = Scripting::FindObject(*(MObject**)value);
auto id = obj ? obj->GetID() : Guid::Empty; auto id = obj ? obj->GetID() : Guid::Empty;
_restoreData.Add((byte*)&id, sizeof(Guid)); _restoreData.Add((byte*)&id, sizeof(Guid));
break; break;
@@ -922,7 +925,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
value = (void*)*(intptr*)value; value = (void*)*(intptr*)value;
if (state.Property) if (state.Property)
{ {
MonoObject* exception = nullptr; MObject* exception = nullptr;
state.Property->SetValue(instance, value, &exception); state.Property->SetValue(instance, value, &exception);
if (exception) if (exception)
{ {
@@ -995,7 +998,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
// Invoke the method // Invoke the method
Variant result; Variant result;
MonoObject* exception = nullptr; MObject* exception = nullptr;
mono_runtime_invoke((MonoMethod*)state.Method, instance, paramsData, &exception); mono_runtime_invoke((MonoMethod*)state.Method, instance, paramsData, &exception);
if (exception) if (exception)
{ {
@@ -1064,6 +1067,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
default: ; default: ;
} }
} }
#endif
} }
void SceneAnimationPlayer::Tick() void SceneAnimationPlayer::Tick()

View File

@@ -43,7 +43,7 @@ private:
struct TrackInstance struct TrackInstance
{ {
ScriptingObjectReference<ScriptingObject> Object; ScriptingObjectReference<ScriptingObject> Object;
MonoObject* ManagedObject = nullptr; MObject* ManagedObject = nullptr;
MProperty* Property = nullptr; MProperty* Property = nullptr;
MField* Field = nullptr; MField* Field = nullptr;
void* Method = nullptr; void* Method = nullptr;

View File

@@ -11,7 +11,9 @@
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/MainThreadTask.h" #include "Engine/Threading/MainThreadTask.h"
#include "Engine/Threading/ConcurrentTaskQueue.h" #include "Engine/Threading/ConcurrentTaskQueue.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
#endif
AssetReferenceBase::~AssetReferenceBase() AssetReferenceBase::~AssetReferenceBase()
{ {
@@ -202,7 +204,9 @@ void Asset::OnManagedInstanceDeleted()
// Cleanup // Cleanup
if (_gcHandle) if (_gcHandle)
{ {
#if USE_MONO
mono_gchandle_free(_gcHandle); mono_gchandle_free(_gcHandle);
#endif
_gcHandle = 0; _gcHandle = 0;
} }

View File

@@ -60,7 +60,7 @@ public:
/// <summary> /// <summary>
/// Gets managed instance object (or null if no asset set). /// Gets managed instance object (or null if no asset set).
/// </summary> /// </summary>
FORCE_INLINE MonoObject* GetManagedInstance() const FORCE_INLINE MObject* GetManagedInstance() const
{ {
return _asset ? _asset->GetOrCreateManagedInstance() : nullptr; return _asset ? _asset->GetOrCreateManagedInstance() : nullptr;
} }

View File

@@ -310,10 +310,17 @@ void VisualScriptExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
const StringAsANSI<100> typeNameAnsi(typeName.Get(), typeName.Length()); const StringAsANSI<100> typeNameAnsi(typeName.Get(), typeName.Length());
if (StringUtils::Compare(typeNameAnsi.Get(), obj.Type.GetTypeName()) != 0) if (StringUtils::Compare(typeNameAnsi.Get(), obj.Type.GetTypeName()) != 0)
{ {
#if USE_MONO
MonoClass* klass = Scripting::FindClassNative(StringAnsiView(typeNameAnsi.Get(), typeName.Length())); MonoClass* klass = Scripting::FindClassNative(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
MonoClass* objKlass = MUtils::GetClass(obj); MonoClass* objKlass = MUtils::GetClass(obj);
if (!klass || !objKlass || mono_class_is_subclass_of(objKlass, klass, false) == 0) if (!klass || !objKlass || mono_class_is_subclass_of(objKlass, klass, false) == 0)
obj = Value::Null; 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))
obj = Value::Null;
#endif
} }
} }
@@ -448,6 +455,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value&
} }
else else
{ {
#if !COMPILE_WITHOUT_CSHARP
// Fallback to C#-only types // Fallback to C#-only types
const auto mclass = Scripting::FindClass(StringAnsiView(typeNameAnsi.Get(), typeName.Length())); const auto mclass = Scripting::FindClass(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
if (mclass) if (mclass)
@@ -461,6 +469,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value&
} }
} }
else else
#endif
{ {
if (typeName.HasChars()) if (typeName.HasChars())
{ {

View File

@@ -50,7 +50,7 @@ public:
/// <summary> /// <summary>
/// Gets managed instance object (or null if no asset set). /// Gets managed instance object (or null if no asset set).
/// </summary> /// </summary>
FORCE_INLINE MonoObject* GetManagedInstance() const FORCE_INLINE MObject* GetManagedInstance() const
{ {
return _asset ? _asset->GetOrCreateManagedInstance() : nullptr; return _asset ? _asset->GetOrCreateManagedInstance() : nullptr;
} }

View File

@@ -64,6 +64,7 @@ VariantType::VariantType(Types type, _MonoClass* klass)
{ {
Type = type; Type = type;
TypeName = nullptr; TypeName = nullptr;
#if USE_MONO
if (klass) if (klass)
{ {
MString typeName; MString typeName;
@@ -72,6 +73,7 @@ VariantType::VariantType(Types type, _MonoClass* klass)
TypeName = static_cast<char*>(Allocator::Allocate(length)); TypeName = static_cast<char*>(Allocator::Allocate(length));
Platform::MemoryCopy(TypeName, typeName.Get(), length); Platform::MemoryCopy(TypeName, typeName.Get(), length);
} }
#endif
} }
VariantType::VariantType(const VariantType& other) VariantType::VariantType(const VariantType& other)
@@ -517,12 +519,24 @@ Variant::Variant(Asset* v)
} }
} }
#if USE_MONO
Variant::Variant(_MonoObject* v) Variant::Variant(_MonoObject* v)
: Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr) : Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr)
{ {
AsUint = v ? mono_gchandle_new(v, true) : 0; AsUint = v ? mono_gchandle_new(v, true) : 0;
} }
#else
Variant::Variant(_MonoObject* v)
: Type(VariantType::ManagedObject, nullptr)
{
AsUint = 0;
}
#endif
Variant::Variant(const StringView& v) Variant::Variant(const StringView& v)
: Type(VariantType::String) : Type(VariantType::String)
{ {
@@ -788,8 +802,8 @@ Variant::~Variant()
case VariantType::Dictionary: case VariantType::Dictionary:
Delete(AsDictionary); Delete(AsDictionary);
break; break;
#if USE_MONO
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO
if (AsUint) if (AsUint)
mono_gchandle_free(AsUint); mono_gchandle_free(AsUint);
break; break;
@@ -912,7 +926,9 @@ Variant& Variant::operator=(const Variant& other)
AsDictionary = New<Dictionary<Variant, Variant>>(*other.AsDictionary); AsDictionary = New<Dictionary<Variant, Variant>>(*other.AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO
AsUint = other.AsUint ? mono_gchandle_new(mono_gchandle_get_target(other.AsUint), true) : 0; AsUint = other.AsUint ? mono_gchandle_new(mono_gchandle_get_target(other.AsUint), true) : 0;
#endif
break; break;
case VariantType::Null: case VariantType::Null:
case VariantType::Void: case VariantType::Void:
@@ -1015,9 +1031,6 @@ bool Variant::operator==(const Variant& other) const
return false; return false;
} }
return true; return true;
case VariantType::ManagedObject:
// TODO: invoke C# Equality logic?
return AsUint == other.AsUint || mono_gchandle_get_target(AsUint) == mono_gchandle_get_target(other.AsUint);
case VariantType::Typename: case VariantType::Typename:
if (AsBlob.Data == nullptr && other.AsBlob.Data == nullptr) if (AsBlob.Data == nullptr && other.AsBlob.Data == nullptr)
return true; return true;
@@ -1026,6 +1039,11 @@ bool Variant::operator==(const Variant& other) const
if (other.AsBlob.Data == nullptr) if (other.AsBlob.Data == nullptr)
return false; 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; 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
// TODO: invoke C# Equality logic?
return AsUint == other.AsUint || mono_gchandle_get_target(AsUint) == mono_gchandle_get_target(other.AsUint);
#endif
default: default:
return false; return false;
} }
@@ -1115,7 +1133,9 @@ Variant::operator bool() const
case VariantType::Asset: case VariantType::Asset:
return AsAsset != nullptr; return AsAsset != nullptr;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO
return AsUint != 0 && mono_gchandle_get_target(AsUint) != nullptr; return AsUint != 0 && mono_gchandle_get_target(AsUint) != nullptr;
#endif
default: default:
return false; return false;
} }
@@ -1461,7 +1481,9 @@ Variant::operator void*() const
case VariantType::Blob: case VariantType::Blob:
return AsBlob.Data; return AsBlob.Data;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO
return AsUint ? mono_gchandle_get_target(AsUint) : nullptr; return AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
#endif
default: default:
return nullptr; return nullptr;
} }
@@ -1504,7 +1526,11 @@ Variant::operator ScriptingObject*() const
Variant::operator _MonoObject*() const Variant::operator _MonoObject*() const
{ {
#if USE_MONO
return Type.Type == VariantType::ManagedObject && AsUint ? mono_gchandle_get_target(AsUint) : nullptr; return Type.Type == VariantType::ManagedObject && AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
#else
return nullptr;
#endif
} }
Variant::operator Asset*() const Variant::operator Asset*() const
@@ -2011,8 +2037,10 @@ void Variant::SetType(const VariantType& type)
Delete(AsDictionary); Delete(AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO
if (AsUint) if (AsUint)
mono_gchandle_free(AsUint); mono_gchandle_free(AsUint);
#endif
break; break;
default: ; default: ;
} }
@@ -2105,8 +2133,10 @@ void Variant::SetType(VariantType&& type)
Delete(AsDictionary); Delete(AsDictionary);
break; break;
case VariantType::ManagedObject: case VariantType::ManagedObject:
#if USE_MONO
if (AsUint) if (AsUint)
mono_gchandle_free(AsUint); mono_gchandle_free(AsUint);
#endif
break; break;
default: ; default: ;
} }
@@ -2245,6 +2275,7 @@ void Variant::SetObject(ScriptingObject* object)
void Variant::SetManagedObject(_MonoObject* object) void Variant::SetManagedObject(_MonoObject* object)
{ {
#if USE_MONO
if (object) if (object)
{ {
if (Type.Type != VariantType::ManagedObject) if (Type.Type != VariantType::ManagedObject)
@@ -2257,6 +2288,7 @@ void Variant::SetManagedObject(_MonoObject* object)
SetType(VariantType(VariantType::ManagedObject)); SetType(VariantType(VariantType::ManagedObject));
AsUint = 0; AsUint = 0;
} }
#endif
} }
void Variant::SetAsset(Asset* asset) void Variant::SetAsset(Asset* asset)
@@ -2338,10 +2370,12 @@ String Variant::ToString() const
return (*(Ray*)AsBlob.Data).ToString(); return (*(Ray*)AsBlob.Data).ToString();
case VariantType::Matrix: case VariantType::Matrix:
return (*(Matrix*)AsBlob.Data).ToString(); return (*(Matrix*)AsBlob.Data).ToString();
case VariantType::ManagedObject:
return AsUint ? String(MUtils::ToString(mono_object_to_string(mono_gchandle_get_target(AsUint), nullptr))) : TEXT("null");
case VariantType::Typename: case VariantType::Typename:
return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0); return String((const char*)AsBlob.Data, AsBlob.Length ? AsBlob.Length - 1 : 0);
case VariantType::ManagedObject:
#if USE_MONO
return AsUint ? String(MUtils::ToString(mono_object_to_string(mono_gchandle_get_target(AsUint), nullptr))) : TEXT("null");
#endif
default: default:
return String::Empty; return String::Empty;
} }
@@ -3110,6 +3144,7 @@ void Variant::AllocStructure()
AsBlob.Data = Allocator::Allocate(AsBlob.Length); AsBlob.Data = Allocator::Allocate(AsBlob.Length);
*((int16*)AsBlob.Data) = 0; *((int16*)AsBlob.Data) = 0;
} }
#if USE_MONO
else if (const auto mclass = Scripting::FindClass(typeName)) else if (const auto mclass = Scripting::FindClass(typeName))
{ {
// Fallback to C#-only types // Fallback to C#-only types
@@ -3134,6 +3169,7 @@ void Variant::AllocStructure()
AsBlob.Length = 0; AsBlob.Length = 0;
} }
} }
#endif
else else
{ {
if (typeName.Length() != 0) if (typeName.Length() != 0)
@@ -3213,10 +3249,12 @@ uint32 GetHash(const Variant& key)
return GetHash(*(Color*)key.AsData); return GetHash(*(Color*)key.AsData);
case VariantType::Guid: case VariantType::Guid:
return GetHash(*(Guid*)key.AsData); return GetHash(*(Guid*)key.AsData);
case VariantType::ManagedObject:
return key.AsUint ? (uint32)mono_object_hash(mono_gchandle_get_target(key.AsUint)) : 0;
case VariantType::Typename: case VariantType::Typename:
return GetHash((const char*)key.AsBlob.Data); return GetHash((const char*)key.AsBlob.Data);
case VariantType::ManagedObject:
#if USE_MONO
return key.AsUint ? (uint32)mono_object_hash(mono_gchandle_get_target(key.AsUint)) : 0;
#endif
default: default:
return 0; return 0;
} }

View File

@@ -9,6 +9,9 @@
#include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#include "FlaxEngine.Gen.h" #include "FlaxEngine.Gen.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/exception.h> #include <ThirdParty/mono-2.0/mono/metadata/exception.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
@@ -61,8 +64,11 @@ bool CacheMethods()
return false; return false;
} }
#endif
void DebugLog::Log(LogType type, const StringView& message) void DebugLog::Log(LogType type, const StringView& message)
{ {
#if USE_MONO
if (CacheMethods()) if (CacheMethods())
return; return;
@@ -77,34 +83,41 @@ void DebugLog::Log(LogType type, const StringView& message)
params.AddParam(stackTrace, scriptsDomain->GetNative()); params.AddParam(stackTrace, scriptsDomain->GetNative());
#endif #endif
MainThreadManagedInvokeAction::Invoke(Internal_SendLog, params); MainThreadManagedInvokeAction::Invoke(Internal_SendLog, params);
#endif
} }
void DebugLog::LogException(MonoObject* exceptionObject) void DebugLog::LogException(MObject* exceptionObject)
{ {
#if USE_MONO
if (exceptionObject == nullptr || CacheMethods()) if (exceptionObject == nullptr || CacheMethods())
return; return;
MainThreadManagedInvokeAction::ParamsBuilder params; MainThreadManagedInvokeAction::ParamsBuilder params;
params.AddParam(exceptionObject); params.AddParam(exceptionObject);
MainThreadManagedInvokeAction::Invoke(Internal_SendLogException, params); MainThreadManagedInvokeAction::Invoke(Internal_SendLogException, params);
#endif
} }
String DebugLog::GetStackTrace() String DebugLog::GetStackTrace()
{ {
String result; String result;
#if USE_MONO
if (!CacheMethods()) if (!CacheMethods())
{ {
auto stackTraceObj = Internal_GetStackTrace->Invoke(nullptr, nullptr, nullptr); auto stackTraceObj = Internal_GetStackTrace->Invoke(nullptr, nullptr, nullptr);
MUtils::ToString((MonoString*)stackTraceObj, result); MUtils::ToString((MonoString*)stackTraceObj, result);
} }
#endif
return result; return result;
} }
void DebugLog::ThrowException(const char* msg) void DebugLog::ThrowException(const char* msg)
{ {
#if USE_MONO
// Throw exception to the C# world // Throw exception to the C# world
auto ex = mono_exception_from_name_msg(mono_get_corlib(), "System", "Exception", msg); auto ex = mono_exception_from_name_msg(mono_get_corlib(), "System", "Exception", msg);
mono_raise_exception(ex); mono_raise_exception(ex);
#endif
} }
void DebugLog::ThrowNullReference() void DebugLog::ThrowNullReference()
@@ -112,35 +125,45 @@ void DebugLog::ThrowNullReference()
//LOG(Warning, "Invalid null reference."); //LOG(Warning, "Invalid null reference.");
//LOG_STR(Warning, DebugLog::GetStackTrace()); //LOG_STR(Warning, DebugLog::GetStackTrace());
#if USE_MONO
// Throw exception to the C# world // Throw exception to the C# world
auto ex = mono_get_exception_null_reference(); auto ex = mono_get_exception_null_reference();
mono_raise_exception(ex); mono_raise_exception(ex);
#endif
} }
void DebugLog::ThrowArgument(const char* arg, const char* msg) void DebugLog::ThrowArgument(const char* arg, const char* msg)
{ {
#if USE_MONO
// Throw exception to the C# world // Throw exception to the C# world
auto ex = mono_get_exception_argument(arg, msg); auto ex = mono_get_exception_argument(arg, msg);
mono_raise_exception(ex); mono_raise_exception(ex);
#endif
} }
void DebugLog::ThrowArgumentNull(const char* arg) void DebugLog::ThrowArgumentNull(const char* arg)
{ {
#if USE_MONO
// Throw exception to the C# world // Throw exception to the C# world
auto ex = mono_get_exception_argument_null(arg); auto ex = mono_get_exception_argument_null(arg);
mono_raise_exception(ex); mono_raise_exception(ex);
#endif
} }
void DebugLog::ThrowArgumentOutOfRange(const char* arg) void DebugLog::ThrowArgumentOutOfRange(const char* arg)
{ {
#if USE_MONO
// Throw exception to the C# world // Throw exception to the C# world
auto ex = mono_get_exception_argument_out_of_range(arg); auto ex = mono_get_exception_argument_out_of_range(arg);
mono_raise_exception(ex); mono_raise_exception(ex);
#endif
} }
void DebugLog::ThrowNotSupported(const char* msg) void DebugLog::ThrowNotSupported(const char* msg)
{ {
#if USE_MONO
// Throw exception to the C# world // Throw exception to the C# world
auto ex = mono_get_exception_not_supported(msg); auto ex = mono_get_exception_not_supported(msg);
mono_raise_exception(ex); mono_raise_exception(ex);
#endif
} }

View File

@@ -50,7 +50,7 @@ public:
/// Logs a formatted exception message to the Flax Console. /// Logs a formatted exception message to the Flax Console.
/// </summary> /// </summary>
/// <param name="exceptionObject">Runtime Exception.</param> /// <param name="exceptionObject">Runtime Exception.</param>
static void LogException(MonoObject* exceptionObject); static void LogException(MObject* exceptionObject);
public: public:

View File

@@ -605,7 +605,7 @@ void EngineImpl::InitMainWindow()
return; return;
} }
#if !USE_EDITOR #if !USE_EDITOR && !COMPILE_WITHOUT_CSHARP
// Inform the managed runtime about the window (game can link GUI to it) // Inform the managed runtime about the window (game can link GUI to it)
auto scriptingClass = Scripting::GetStaticClass(); auto scriptingClass = Scripting::GetStaticClass();
ASSERT(scriptingClass); ASSERT(scriptingClass);
@@ -613,7 +613,7 @@ void EngineImpl::InitMainWindow()
ASSERT(setWindowMethod); ASSERT(setWindowMethod);
void* params[1]; void* params[1];
params[0] = Engine::MainWindow->GetOrCreateManagedInstance(); params[0] = Engine::MainWindow->GetOrCreateManagedInstance();
MonoObject* exception = nullptr; MObject* exception = nullptr;
setWindowMethod->Invoke(nullptr, params, &exception); setWindowMethod->Invoke(nullptr, params, &exception);
if (exception) if (exception)
{ {

View File

@@ -11,7 +11,9 @@
#include "Engine/Renderer/RenderList.h" #include "Engine/Renderer/RenderList.h"
#include "Engine/Serialization/MemoryReadStream.h" #include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
namespace namespace
{ {
@@ -106,6 +108,8 @@ namespace
return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vertices, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, triangles); return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vertices, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, triangles);
} }
#if !COMPILE_WITHOUT_CSHARP
template<typename IndexType> 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, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
{ {
@@ -132,6 +136,8 @@ namespace
return mesh->UpdateTriangles(triangleCount, ib); return mesh->UpdateTriangles(triangleCount, ib);
} }
#endif
} }
bool Mesh::HasVertexColors() const bool Mesh::HasVertexColors() const
@@ -591,6 +597,8 @@ ScriptingObject* Mesh::GetParentModel()
return _model; return _model;
} }
#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, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
{ {
return ::UpdateMesh<uint32>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj); return ::UpdateMesh<uint32>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
@@ -763,3 +771,5 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
ConvertMeshData(mesh, type, resultObj, data.Get()); ConvertMeshData(mesh, type, resultObj, data.Get());
return false; return false;
} }
#endif

View File

@@ -404,9 +404,11 @@ private:
// Internal bindings // Internal bindings
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel(); 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 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 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 UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj); API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI); API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
#endif
}; };

View File

@@ -11,7 +11,9 @@
#include "Engine/Serialization/MemoryReadStream.h" #include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
void SkinnedMesh::Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere) void SkinnedMesh::Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere)
{ {
@@ -316,6 +318,8 @@ ScriptingObject* SkinnedMesh::GetParentModel()
return _model; return _model;
} }
#if !COMPILE_WITHOUT_CSHARP
template<typename IndexType> 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, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj)
{ {
@@ -561,3 +565,5 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
ConvertMeshData(mesh, type, resultObj, data.Get()); ConvertMeshData(mesh, type, resultObj, data.Get());
return false; return false;
} }
#endif

View File

@@ -258,7 +258,9 @@ private:
// Internal bindings // Internal bindings
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel(); 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 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) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI); API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
#endif
}; };

View File

@@ -20,13 +20,17 @@
#include "Engine/Scripting/Script.h" #include "Engine/Scripting/Script.h"
#include "Engine/Scripting/BinaryModule.h" #include "Engine/Scripting/BinaryModule.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Renderer/Lightmaps.h" #include "Engine/Renderer/Lightmaps.h"
#else #else
#include "Engine/Engine/Screen.h" #include "Engine/Engine/Screen.h"
#endif #endif
#if USE_MONO
// TODO: use API for events and remove this manual wrapper code // TODO: use API for events and remove this manual wrapper code
class RenderContextInternal class RenderContextInternal
{ {
@@ -53,6 +57,8 @@ namespace
} }
} }
#endif
Array<RenderTask*> RenderTask::Tasks; Array<RenderTask*> RenderTask::Tasks;
CriticalSection RenderTask::TasksLocker; CriticalSection RenderTask::TasksLocker;
int32 RenderTask::TasksDoneLastFrame; int32 RenderTask::TasksDoneLastFrame;
@@ -174,7 +180,7 @@ void ManagedPostProcessEffect::FetchInfo()
args[0] = Target->GetOrCreateManagedInstance(); args[0] = Target->GetOrCreateManagedInstance();
args[1] = &_location; args[1] = &_location;
args[2] = &_useSingleTarget; args[2] = &_useSingleTarget;
MonoObject* exception = nullptr; MObject* exception = nullptr;
FetchInfoManaged->Invoke(nullptr, args, &exception); FetchInfoManaged->Invoke(nullptr, args, &exception);
if (exception) if (exception)
DebugLog::LogException(exception); DebugLog::LogException(exception);
@@ -187,6 +193,7 @@ bool ManagedPostProcessEffect::IsLoaded() const
void ManagedPostProcessEffect::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output) void ManagedPostProcessEffect::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output)
{ {
#if USE_MONO
const auto context = GPUDevice::Instance->GetMainContext(); const auto context = GPUDevice::Instance->GetMainContext();
auto inputObj = ScriptingObject::ToManaged(input); auto inputObj = ScriptingObject::ToManaged(input);
auto outputObj = ScriptingObject::ToManaged(output); auto outputObj = ScriptingObject::ToManaged(output);
@@ -203,10 +210,11 @@ void ManagedPostProcessEffect::Render(RenderContext& renderContext, GPUTexture*
params[1] = &tmp; params[1] = &tmp;
params[2] = inputObj; params[2] = inputObj;
params[3] = outputObj; params[3] = outputObj;
MonoObject* exception = nullptr; MObject* exception = nullptr;
renderMethod->InvokeVirtual(Target->GetOrCreateManagedInstance(), params, &exception); renderMethod->InvokeVirtual(Target->GetOrCreateManagedInstance(), params, &exception);
if (exception) if (exception)
DebugLog::LogException(exception); DebugLog::LogException(exception);
#endif
} }
SceneRenderTask::SceneRenderTask(const SpawnParams& params) SceneRenderTask::SceneRenderTask(const SpawnParams& params)
@@ -340,6 +348,8 @@ void SceneRenderTask::OnBegin(GPUContext* context)
} }
// Get custom and global PostFx // Get custom and global PostFx
CustomPostFx.Clear();
#if !COMPILE_WITHOUT_CSHARP
// TODO: move postFx in SceneRenderTask from C# to C++ // TODO: move postFx in SceneRenderTask from C# to C++
static MMethod* GetPostFxManaged = GetStaticClass()->GetMethod("GetPostFx", 1); static MMethod* GetPostFxManaged = GetStaticClass()->GetMethod("GetPostFx", 1);
if (GetPostFxManaged) if (GetPostFxManaged)
@@ -347,7 +357,8 @@ void SceneRenderTask::OnBegin(GPUContext* context)
int32 count = 0; int32 count = 0;
void* params[1]; void* params[1];
params[0] = &count; params[0] = &count;
MonoObject* exception = nullptr; MObject* exception = nullptr;
#if USE_MONO
const auto objects = (MonoArray*)GetPostFxManaged->Invoke(GetOrCreateManagedInstance(), params, &exception); const auto objects = (MonoArray*)GetPostFxManaged->Invoke(GetOrCreateManagedInstance(), params, &exception);
if (exception) if (exception)
DebugLog::LogException(exception); DebugLog::LogException(exception);
@@ -359,9 +370,9 @@ void SceneRenderTask::OnBegin(GPUContext* context)
if (postFx.Target) if (postFx.Target)
postFx.FetchInfo(); postFx.FetchInfo();
} }
#endif
} }
else #endif
CustomPostFx.Clear();
// Setup render buffers for the output rendering resolution // Setup render buffers for the output rendering resolution
if (Output) if (Output)

View File

@@ -4,7 +4,9 @@
#include "Engine/Serialization/Serialization.h" #include "Engine/Serialization/Serialization.h"
#include "Engine/Animations/CurveSerialization.h" #include "Engine/Animations/CurveSerialization.h"
#include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/Matrix.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#endif
Spline::Spline(const SpawnParams& params) Spline::Spline(const SpawnParams& params)
: Actor(params) : Actor(params)
@@ -437,6 +439,8 @@ void Spline::UpdateSpline()
SplineUpdated(); SplineUpdated();
} }
#if !COMPILE_WITHOUT_CSHARP
void Spline::GetKeyframes(MonoArray* data) void Spline::GetKeyframes(MonoArray* data)
{ {
Platform::MemoryCopy(mono_array_addr_with_size(data, sizeof(Keyframe), 0), Curve.GetKeyframes().Get(), sizeof(Keyframe) * Curve.GetKeyframes().Count()); Platform::MemoryCopy(mono_array_addr_with_size(data, sizeof(Keyframe), 0), Curve.GetKeyframes().Get(), sizeof(Keyframe) * Curve.GetKeyframes().Count());
@@ -450,6 +454,8 @@ void Spline::SetKeyframes(MonoArray* data)
UpdateSpline(); UpdateSpline();
} }
#endif
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Debug/DebugDraw.h" #include "Engine/Debug/DebugDraw.h"

View File

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

View File

@@ -117,6 +117,7 @@ void SceneObject::Serialize(SerializeStream& stream, const void* otherObj)
stream.Guid(_parent->GetID()); stream.Guid(_parent->GetID());
} }
#if !COMPILE_WITHOUT_CSHARP
// Handle C# objects data serialization // Handle C# objects data serialization
if (Flags & ObjectFlags::IsManagedType) if (Flags & ObjectFlags::IsManagedType)
{ {
@@ -130,6 +131,7 @@ void SceneObject::Serialize(SerializeStream& stream, const void* otherObj)
ManagedSerialization::Serialize(stream, GetOrCreateManagedInstance()); ManagedSerialization::Serialize(stream, GetOrCreateManagedInstance());
} }
} }
#endif
// Handle custom scripting objects data serialization // Handle custom scripting objects data serialization
if (Flags & ObjectFlags::IsCustomScriptingType) if (Flags & ObjectFlags::IsCustomScriptingType)
@@ -146,6 +148,7 @@ void SceneObject::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
// _prefabID is deserialized by Actor/Script impl // _prefabID is deserialized by Actor/Script impl
DESERIALIZE_MEMBER(PrefabObjectID, _prefabObjectID); DESERIALIZE_MEMBER(PrefabObjectID, _prefabObjectID);
#if !COMPILE_WITHOUT_CSHARP
// Handle C# objects data serialization // Handle C# objects data serialization
if (Flags & ObjectFlags::IsManagedType) if (Flags & ObjectFlags::IsManagedType)
{ {
@@ -155,6 +158,7 @@ void SceneObject::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
ManagedSerialization::Deserialize(v->value, GetOrCreateManagedInstance()); ManagedSerialization::Deserialize(v->value, GetOrCreateManagedInstance());
} }
} }
#endif
// Handle custom scripting objects data serialization // Handle custom scripting objects data serialization
if (Flags & ObjectFlags::IsCustomScriptingType) if (Flags & ObjectFlags::IsCustomScriptingType)

View File

@@ -47,8 +47,6 @@ CultureInfo::CultureInfo(int32 lcid)
break; break;
} }
} }
#else
#error "Missing CultureInfo implementation."
#endif #endif
if (!_data) if (!_data)
{ {
@@ -89,8 +87,6 @@ CultureInfo::CultureInfo(const StringAnsiView& name)
break; break;
} }
} }
#else
#error "Missing CultureInfo implementation."
#endif #endif
if (!_data) if (!_data)
{ {
@@ -132,8 +128,6 @@ bool CultureInfo::IsRightToLeft() const
const auto data = static_cast<CultureInfoEntry*>(_data); const auto data = static_cast<CultureInfoEntry*>(_data);
if (data) if (data)
return data->text_info.is_right_to_left ? true : false; return data->text_info.is_right_to_left ? true : false;
#else
#error "Missing CultureInfo implementation."
#endif #endif
return false; return false;
} }

View File

@@ -14,8 +14,11 @@
#include "Engine/Scripting/ManagedCLR/MUtils.h" #include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h" #include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MClass.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
#if USE_MONO
// Helper macros for calling C# events // Helper macros for calling C# events
#define BEGIN_INVOKE_EVENT(name, paramsCount) \ #define BEGIN_INVOKE_EVENT(name, paramsCount) \
auto managedInstance = GetManagedInstance(); \ auto managedInstance = GetManagedInstance(); \
@@ -42,7 +45,7 @@
params[0] = param0; \ params[0] = param0; \
params[1] = param1; \ params[1] = param1; \
params[2] = param2; \ params[2] = param2; \
MonoObject* exception = nullptr; \ MObject* exception = nullptr; \
_method_##name->Invoke(managedInstance, params, &exception); \ _method_##name->Invoke(managedInstance, params, &exception); \
END_INVOKE_EVENT(name) END_INVOKE_EVENT(name)
#define INVOKE_EVENT_PARAMS_3(name, param0, param1, param2) INVOKE_EVENT(name, 3, param0, param1, param2) #define INVOKE_EVENT_PARAMS_3(name, param0, param1, param2) INVOKE_EVENT(name, 3, param0, param1, param2)
@@ -69,11 +72,19 @@
for (int32 i = 0; i < outputData.Count(); i++) \ for (int32 i = 0; i < outputData.Count(); i++) \
*(MonoString**)mono_array_addr_with_size(outputDataMono, sizeof(MonoString*), i) = MUtils::ToString(outputData[i]); \ *(MonoString**)mono_array_addr_with_size(outputDataMono, sizeof(MonoString*), i) = MUtils::ToString(outputData[i]); \
params[2] = outputDataMono; \ params[2] = outputDataMono; \
MonoObject* exception = nullptr; \ MObject* exception = nullptr; \
auto resultObj = _method_##name->Invoke(GetManagedInstance(), params, &exception); \ auto resultObj = _method_##name->Invoke(GetManagedInstance(), params, &exception); \
if (resultObj) \ if (resultObj) \
result = (DragDropEffect)MUtils::Unbox<int32>(resultObj); \ result = (DragDropEffect)MUtils::Unbox<int32>(resultObj); \
END_INVOKE_EVENT(name) END_INVOKE_EVENT(name)
#else
#define INVOKE_EVENT(name, paramsCount, param0, param1, param2)
#define INVOKE_EVENT_PARAMS_3(name, param0, param1, param2) INVOKE_EVENT(name, 3, param0, param1, param2)
#define INVOKE_EVENT_PARAMS_2(name, param0, param1) INVOKE_EVENT(name, 2, param0, param1, nullptr)
#define INVOKE_EVENT_PARAMS_1(name, param0) INVOKE_EVENT(name, 1, param0, nullptr, nullptr)
#define INVOKE_EVENT_PARAMS_0(name) INVOKE_EVENT(name, 0, nullptr, nullptr, nullptr)
#define INVOKE_DRAG_EVENT(name)
#endif
WindowBase::WindowBase(const CreateWindowSettings& settings) WindowBase::WindowBase(const CreateWindowSettings& settings)
: PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer)) : PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer))

View File

@@ -21,8 +21,12 @@ Delegate<ScriptingObject*, Span<Variant>, ScriptingTypeHandle, StringView> Scrip
ManagedBinaryModule* GetBinaryModuleCorlib() 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", MAssemblyOptions(false)); // Don't precache all corlib classes
return &assembly; return &assembly;
#endif
} }
ScriptingTypeHandle::ScriptingTypeHandle(const ScriptingTypeInitializer& initializer) ScriptingTypeHandle::ScriptingTypeHandle(const ScriptingTypeInitializer& initializer)
@@ -698,6 +702,8 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
return object; return object;
} }
#if !COMPILE_WITHOUT_CSHARP
namespace namespace
{ {
MMethod* FindMethod(MClass* mclass, const MMethod* referenceMethod) MMethod* FindMethod(MClass* mclass, const MMethod* referenceMethod)
@@ -719,6 +725,8 @@ namespace
} }
} }
#endif
MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature) MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature)
{ {
if (!mclass) if (!mclass)
@@ -726,6 +734,7 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
const auto& methods = mclass->GetMethods(); const auto& methods = mclass->GetMethods();
for (MMethod* method : methods) for (MMethod* method : methods)
{ {
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(method->GetNative()); MonoMethodSignature* sig = mono_method_signature(method->GetNative());
if (method->IsStatic() != signature.IsStatic || if (method->IsStatic() != signature.IsStatic ||
method->GetName() != signature.Name || method->GetName() != signature.Name ||
@@ -746,10 +755,13 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
} }
if (isValid && MUtils::GetClass(signature.ReturnType) == mono_class_from_mono_type(mono_signature_get_return_type(sig))) if (isValid && MUtils::GetClass(signature.ReturnType) == mono_class_from_mono_type(mono_signature_get_return_type(sig)))
return method; return method;
#endif
} }
return nullptr; return nullptr;
} }
#if USE_MONO
ManagedBinaryModule* ManagedBinaryModule::FindModule(MonoClass* klass) ManagedBinaryModule* ManagedBinaryModule::FindModule(MonoClass* klass)
{ {
// TODO: consider caching lookup table MonoImage* -> ManagedBinaryModule* // TODO: consider caching lookup table MonoImage* -> ManagedBinaryModule*
@@ -782,6 +794,8 @@ ScriptingTypeHandle ManagedBinaryModule::FindType(MonoClass* klass)
return ScriptingTypeHandle(); return ScriptingTypeHandle();
} }
#endif
void ManagedBinaryModule::OnLoading(MAssembly* assembly) void ManagedBinaryModule::OnLoading(MAssembly* assembly)
{ {
PROFILE_CPU(); PROFILE_CPU();
@@ -793,6 +807,7 @@ void ManagedBinaryModule::OnLoading(MAssembly* assembly)
void ManagedBinaryModule::OnLoaded(MAssembly* assembly) void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
{ {
#if !COMPILE_WITHOUT_CSHARP
PROFILE_CPU(); PROFILE_CPU();
ASSERT(ClassToTypeIndex.IsEmpty()); ASSERT(ClassToTypeIndex.IsEmpty());
@@ -849,10 +864,12 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
InitType(mclass); InitType(mclass);
} }
} }
#endif
} }
void ManagedBinaryModule::InitType(MClass* mclass) void ManagedBinaryModule::InitType(MClass* mclass)
{ {
#if !COMPILE_WITHOUT_CSHARP
// Skip if already initialized // Skip if already initialized
const MString& typeName = mclass->GetFullName(); const MString& typeName = mclass->GetFullName();
if (TypeNameToTypeIndex.ContainsKey(typeName)) if (TypeNameToTypeIndex.ContainsKey(typeName))
@@ -992,6 +1009,7 @@ void ManagedBinaryModule::InitType(MClass* mclass)
// Move to the next entry (table is null terminated) // Move to the next entry (table is null terminated)
scriptVTable++; scriptVTable++;
} }
#endif
} }
void ManagedBinaryModule::OnUnloading(MAssembly* assembly) void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
@@ -1020,7 +1038,9 @@ void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
type.Script.ScriptVTable = nullptr; type.Script.ScriptVTable = nullptr;
} }
} }
#if !COMPILE_WITHOUT_CSHARP
ClassToTypeIndex.Clear(); ClassToTypeIndex.Clear();
#endif
} }
const StringAnsi& ManagedBinaryModule::GetName() const const StringAnsi& ManagedBinaryModule::GetName() const
@@ -1030,7 +1050,11 @@ const StringAnsi& ManagedBinaryModule::GetName() const
bool ManagedBinaryModule::IsLoaded() const bool ManagedBinaryModule::IsLoaded() const
{ {
#if COMPILE_WITHOUT_CSHARP
return true;
#else
return Assembly->IsLoaded(); return Assembly->IsLoaded();
#endif
} }
void* ManagedBinaryModule::FindMethod(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name, int32 numParams) void* ManagedBinaryModule::FindMethod(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name, int32 numParams)
@@ -1047,6 +1071,7 @@ void* ManagedBinaryModule::FindMethod(const ScriptingTypeHandle& typeHandle, con
bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Span<Variant> paramValues, Variant& result) bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Span<Variant> paramValues, Variant& result)
{ {
#if USE_MONO
const auto mMethod = (MMethod*)method; const auto mMethod = (MMethod*)method;
MonoMethodSignature* signature = mono_method_signature(mMethod->GetNative()); MonoMethodSignature* signature = mono_method_signature(mMethod->GetNative());
void* signatureParams = nullptr; void* signatureParams = nullptr;
@@ -1101,7 +1126,7 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
} }
// Invoke the method // Invoke the method
MonoObject* exception = nullptr; MObject* exception = nullptr;
MonoObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MonoObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception); MonoObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MonoObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
if (exception) if (exception)
{ {
@@ -1164,10 +1189,14 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
} }
return false; return false;
#else
return true;
#endif
} }
void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSignature& signature) void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSignature& signature)
{ {
#if USE_MONO
const auto mMethod = (MMethod*)method; const auto mMethod = (MMethod*)method;
signature.Name = mMethod->GetName(); signature.Name = mMethod->GetName();
signature.IsStatic = mMethod->IsStatic(); signature.IsStatic = mMethod->IsStatic();
@@ -1183,6 +1212,7 @@ void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSi
param.Type = MoveTemp(MUtils::UnboxVariantType(((MonoType**)signatureParams)[paramIdx])); param.Type = MoveTemp(MUtils::UnboxVariantType(((MonoType**)signatureParams)[paramIdx]));
param.IsOut = mono_signature_param_is_out(sig, paramIdx) != 0; param.IsOut = mono_signature_param_is_out(sig, paramIdx) != 0;
} }
#endif
} }
void* ManagedBinaryModule::FindField(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name) void* ManagedBinaryModule::FindField(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name)
@@ -1193,14 +1223,17 @@ void* ManagedBinaryModule::FindField(const ScriptingTypeHandle& typeHandle, cons
void ManagedBinaryModule::GetFieldSignature(void* field, ScriptingTypeFieldSignature& fieldSignature) void ManagedBinaryModule::GetFieldSignature(void* field, ScriptingTypeFieldSignature& fieldSignature)
{ {
#if USE_MONO
const auto mField = (MField*)field; const auto mField = (MField*)field;
fieldSignature.Name = mField->GetName(); fieldSignature.Name = mField->GetName();
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType().GetNative())); fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType().GetNative()));
fieldSignature.IsStatic = mField->IsStatic(); fieldSignature.IsStatic = mField->IsStatic();
#endif
} }
bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Variant& result) bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Variant& result)
{ {
#if USE_MONO
const auto mField = (MField*)field; const auto mField = (MField*)field;
// Get instance object // Get instance object
@@ -1225,10 +1258,14 @@ bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Va
MonoObject* resultObject = mField->GetValueBoxed(instanceObject); MonoObject* resultObject = mField->GetValueBoxed(instanceObject);
result = MUtils::UnboxVariant(resultObject); result = MUtils::UnboxVariant(resultObject);
return false; return false;
#else
return true;
#endif
} }
bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value) bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value)
{ {
#if USE_MONO
const auto mField = (MField*)field; const auto mField = (MField*)field;
// Get instance object // Get instance object
@@ -1253,6 +1290,9 @@ bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Va
bool failed = false; bool failed = false;
mField->SetValue(instanceObject, MUtils::VariantToManagedArgPtr(value, mField->GetType(), failed)); mField->SetValue(instanceObject, MUtils::VariantToManagedArgPtr(value, mField->GetType(), failed));
return failed; return failed;
#else
return true;
#endif
} }
void ManagedBinaryModule::Destroy(bool isReloading) void ManagedBinaryModule::Destroy(bool isReloading)

View File

@@ -290,15 +290,19 @@ public:
/// </summary> /// </summary>
MAssembly* Assembly; MAssembly* Assembly;
#if !COMPILE_WITHOUT_CSHARP
/// <summary> /// <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. /// 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> /// </summary>
Dictionary<MonoClass*, int32, HeapAllocation> ClassToTypeIndex; Dictionary<MonoClass*, int32, HeapAllocation> ClassToTypeIndex;
#endif
static ScriptingObject* ManagedObjectSpawn(const ScriptingObjectSpawnParams& params); static ScriptingObject* ManagedObjectSpawn(const ScriptingObjectSpawnParams& params);
static MMethod* FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature); static MMethod* FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature);
#if USE_MONO
static ManagedBinaryModule* FindModule(MonoClass* klass); static ManagedBinaryModule* FindModule(MonoClass* klass);
static ScriptingTypeHandle FindType(MonoClass* klass); static ScriptingTypeHandle FindType(MonoClass* klass);
#endif
private: private:

View File

@@ -5,6 +5,9 @@
#include "Engine/Debug/DebugLog.h" #include "Engine/Debug/DebugLog.h"
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
#include "ScriptingType.h" #include "ScriptingType.h"
#include "Types.h"
#if USE_MONO
extern "C" FLAXENGINE_API void mono_add_internal_call(const char* name, const void* method); extern "C" FLAXENGINE_API void mono_add_internal_call(const char* name, const void* method);
#define ADD_INTERNAL_CALL(fullName, method) mono_add_internal_call(fullName, (const void*)method) #define ADD_INTERNAL_CALL(fullName, method) mono_add_internal_call(fullName, (const void*)method)
@@ -46,3 +49,13 @@ extern "C" FLAXENGINE_API void mono_add_internal_call(const char* name, const vo
} }
#endif #endif
#else
#define ADD_INTERNAL_CALL(fullName, method)
#define INTERNAL_CALL_CHECK(obj)
#define INTERNAL_CALL_CHECK_EXP(expression)
#define INTERNAL_CALL_CHECK_RETURN(obj, defaultValue)
#define INTERNAL_CALL_CHECK_EXP_RETURN(expression, defaultValue)
#endif

View File

@@ -6,6 +6,8 @@
#include "Engine/Scripting/MException.h" #include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h" #include "Engine/Scripting/ManagedCLR/MUtils.h"
#if USE_MONO
namespace UtilsInternal namespace UtilsInternal
{ {
MonoObject* ExtractArrayFromList(MonoObject* obj) MonoObject* ExtractArrayFromList(MonoObject* obj)
@@ -70,9 +72,12 @@ namespace FlaxLogWriterInternal
} }
} }
#endif
void registerFlaxEngineInternalCalls() void registerFlaxEngineInternalCalls()
{ {
AnimGraphExecutor::initRuntime(); AnimGraphExecutor::initRuntime();
#if USE_MONO
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &Platform::MemoryCopy); ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &Platform::MemoryCopy);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &Platform::MemoryClear); ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &Platform::MemoryClear);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCompare", &Platform::MemoryCompare); ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCompare", &Platform::MemoryCompare);
@@ -81,4 +86,5 @@ void registerFlaxEngineInternalCalls()
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal::Log); ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal::Log);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal::LogException); ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal::LogException);
ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog); ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog);
#endif
} }

View File

@@ -8,6 +8,7 @@
#include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MField.h" #include "Engine/Scripting/ManagedCLR/MField.h"
#include "Engine/Scripting/BinaryModule.h" #include "Engine/Scripting/BinaryModule.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/debug-helpers.h> #include <ThirdParty/mono-2.0/mono/metadata/debug-helpers.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
@@ -15,7 +16,7 @@
struct ManagedBitArray struct ManagedBitArray
{ {
template<typename AllocationType = HeapAllocation> template<typename AllocationType = HeapAllocation>
static MonoObject* ToManaged(const BitArray<AllocationType>& data) static MObject* ToManaged(const BitArray<AllocationType>& data)
{ {
#if 0 #if 0
// TODO: use actual System.Collections.BitArray for BitArray interop // TODO: use actual System.Collections.BitArray for BitArray interop
@@ -53,3 +54,5 @@ struct ManagedBitArray
#endif #endif
} }
}; };
#endif

View File

@@ -11,6 +11,7 @@
#include "Engine/Scripting/ManagedCLR/MMethod.h" #include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h" #include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/MException.h" #include "Engine/Scripting/MException.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
struct FLAXENGINE_API ManagedDictionary struct FLAXENGINE_API ManagedDictionary
@@ -93,7 +94,7 @@ struct FLAXENGINE_API ManagedDictionary
void* params[2]; void* params[2];
params[0] = genericType; params[0] = genericType;
params[1] = genericArgs; params[1] = genericArgs;
MonoObject* exception = nullptr; MObject* exception = nullptr;
auto dictionaryType = makeGenericMethod->Invoke(nullptr, params, &exception); auto dictionaryType = makeGenericMethod->Invoke(nullptr, params, &exception);
if (exception) if (exception)
{ {
@@ -127,7 +128,7 @@ struct FLAXENGINE_API ManagedDictionary
params[0] = Instance; params[0] = Instance;
params[1] = key; params[1] = key;
params[2] = value; params[2] = value;
MonoObject* exception = nullptr; MObject* exception = nullptr;
mono_runtime_invoke(addDictionaryItemMethod->GetNative(), Instance, params, &exception); mono_runtime_invoke(addDictionaryItemMethod->GetNative(), Instance, params, &exception);
if (exception) if (exception)
{ {
@@ -159,3 +160,5 @@ struct FLAXENGINE_API ManagedDictionary
return mono_runtime_invoke(getItemMethod, Instance, params, nullptr); return mono_runtime_invoke(getItemMethod, Instance, params, nullptr);
} }
}; };
#endif

View File

@@ -2,11 +2,14 @@
#include "MException.h" #include "MException.h"
#include "ManagedCLR/MUtils.h" #include "ManagedCLR/MUtils.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#endif
MException::MException(MonoObject* exception) MException::MException(MObject* exception)
: InnerException(nullptr) : InnerException(nullptr)
{ {
#if USE_MONO
ASSERT(exception); ASSERT(exception);
MonoClass* exceptionClass = mono_object_get_class(exception); MonoClass* exceptionClass = mono_object_get_class(exception);
@@ -25,6 +28,7 @@ MException::MException(MonoObject* exception)
MonoObject* innerException = (MonoObject*)mono_runtime_invoke(innerExceptionGetter, exception, nullptr, nullptr); MonoObject* innerException = (MonoObject*)mono_runtime_invoke(innerExceptionGetter, exception, nullptr, nullptr);
if (innerException) if (innerException)
InnerException = New<MException>(innerException); InnerException = New<MException>(innerException);
#endif
} }
MException::~MException() MException::~MException()

View File

@@ -30,6 +30,7 @@ public:
public: public:
#if USE_MONO
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MException"/> class. /// Initializes a new instance of the <see cref="MException"/> class.
/// </summary> /// </summary>
@@ -38,12 +39,13 @@ public:
: MException((MonoObject*)exception) : MException((MonoObject*)exception)
{ {
} }
#endif
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MException"/> class. /// Initializes a new instance of the <see cref="MException"/> class.
/// </summary> /// </summary>
/// <param name="exception">The exception object.</param> /// <param name="exception">The exception object.</param>
explicit MException(MonoObject* exception); explicit MException(MObject* exception);
/// <summary> /// <summary>
/// Disposes a instance of the <see cref="MException"/> class. /// Disposes a instance of the <see cref="MException"/> class.

View File

@@ -5,7 +5,7 @@
#include "Engine/Scripting/ScriptingCalls.h" #include "Engine/Scripting/ScriptingCalls.h"
#include "MException.h" #include "MException.h"
MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(MMethod* method, MonoObject* instance, LogType exceptionLevel) MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(MMethod* method, MObject* instance, LogType exceptionLevel)
{ {
ASSERT_LOW_LAYER(method != nullptr); ASSERT_LOW_LAYER(method != nullptr);
@@ -23,7 +23,7 @@ MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(MMethod* me
} }
} }
MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(MMethod* method, ParamsBuilder& params, MonoObject* instance, LogType exceptionLevel) MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(MMethod* method, ParamsBuilder& params, MObject* instance, LogType exceptionLevel)
{ {
ASSERT_LOW_LAYER(method != nullptr); ASSERT_LOW_LAYER(method != nullptr);
@@ -59,14 +59,14 @@ MainThreadManagedInvokeAction* MainThreadManagedInvokeAction::Invoke(void* metho
} }
} }
void MainThreadManagedInvokeAction::InvokeNow(MMethod* method, ParamsBuilder& params, MonoObject* instance, LogType exceptionLevel) void MainThreadManagedInvokeAction::InvokeNow(MMethod* method, ParamsBuilder& params, MObject* instance, LogType exceptionLevel)
{ {
ASSERT_LOW_LAYER(method != nullptr); ASSERT_LOW_LAYER(method != nullptr);
void* paramsData[8]; void* paramsData[8];
params.GetParams(paramsData); params.GetParams(paramsData);
MonoObject* exception = nullptr; MObject* exception = nullptr;
method->Invoke(instance, paramsData, &exception); method->Invoke(instance, paramsData, &exception);
if (exception) if (exception)
{ {
@@ -82,14 +82,13 @@ bool MainThreadManagedInvokeAction::Run()
void* paramsData[8]; void* paramsData[8];
_params.GetParams(paramsData); _params.GetParams(paramsData);
MonoObject* exception = nullptr; MObject* exception = nullptr;
if (_method) if (_method)
{ {
_method->Invoke(_instance, paramsData, &exception); _method->Invoke(_instance, paramsData, &exception);
} }
else else if (_methodThunk)
{ {
ASSERT(_methodThunk);
switch (_params.Count) switch (_params.Count)
{ {
case 0: case 0:

View File

@@ -71,6 +71,7 @@ public:
AddParam(val); AddParam(val);
} }
#if USE_MONO
FORCE_INLINE void AddParam(const String& value) FORCE_INLINE void AddParam(const String& value)
{ {
MonoString* val = MUtils::ToString(value); MonoString* val = MUtils::ToString(value);
@@ -94,6 +95,7 @@ public:
MonoString* val = MUtils::ToString(value, domain); MonoString* val = MUtils::ToString(value, domain);
AddParam(val); AddParam(val);
} }
#endif
void GetParams(void* params[8]) void GetParams(void* params[8])
{ {
@@ -109,7 +111,7 @@ public:
private: private:
MonoObject* _instance; MObject* _instance;
MMethod* _method; MMethod* _method;
void* _methodThunk; void* _methodThunk;
LogType _exceptionLevel; LogType _exceptionLevel;
@@ -117,7 +119,7 @@ private:
public: public:
MainThreadManagedInvokeAction(MonoObject* instance, MMethod* method, LogType exceptionLevel) MainThreadManagedInvokeAction(MObject* instance, MMethod* method, LogType exceptionLevel)
: _instance(instance) : _instance(instance)
, _method(method) , _method(method)
, _methodThunk(nullptr) , _methodThunk(nullptr)
@@ -126,7 +128,7 @@ public:
{ {
} }
MainThreadManagedInvokeAction(MonoObject* instance, MMethod* method, LogType exceptionLevel, const ParamsBuilder& params) MainThreadManagedInvokeAction(MObject* instance, MMethod* method, LogType exceptionLevel, const ParamsBuilder& params)
: _instance(instance) : _instance(instance)
, _method(method) , _method(method)
, _methodThunk(nullptr) , _methodThunk(nullptr)
@@ -153,7 +155,7 @@ public:
/// <param name="instance">The managed instance object.</param> /// <param name="instance">The managed instance object.</param>
/// <param name="exceptionLevel">The exception logging error level.</param> /// <param name="exceptionLevel">The exception logging error level.</param>
/// <returns>The created task.</returns> /// <returns>The created task.</returns>
static MainThreadManagedInvokeAction* Invoke(MMethod* method, MonoObject* instance = nullptr, LogType exceptionLevel = LogType::Error); static MainThreadManagedInvokeAction* Invoke(MMethod* method, MObject* instance = nullptr, LogType exceptionLevel = LogType::Error);
/// <summary> /// <summary>
/// Starts the new task or invokes this action now if already running on a main thread. /// Starts the new task or invokes this action now if already running on a main thread.
@@ -163,7 +165,7 @@ public:
/// <param name="instance">The managed instance object.</param> /// <param name="instance">The managed instance object.</param>
/// <param name="exceptionLevel">The exception logging error level.</param> /// <param name="exceptionLevel">The exception logging error level.</param>
/// <returns>The created task.</returns> /// <returns>The created task.</returns>
static MainThreadManagedInvokeAction* Invoke(MMethod* method, ParamsBuilder& params, MonoObject* instance = nullptr, LogType exceptionLevel = LogType::Error); static MainThreadManagedInvokeAction* Invoke(MMethod* method, ParamsBuilder& params, MObject* instance = nullptr, LogType exceptionLevel = LogType::Error);
/// <summary> /// <summary>
/// Starts the new task or invokes this action now if already running on a main thread. /// Starts the new task or invokes this action now if already running on a main thread.
@@ -181,7 +183,7 @@ public:
/// <param name="params">The method parameters.</param> /// <param name="params">The method parameters.</param>
/// <param name="instance">The managed instance object.</param> /// <param name="instance">The managed instance object.</param>
/// <param name="exceptionLevel">The exception logging error level.</param> /// <param name="exceptionLevel">The exception logging error level.</param>
static void InvokeNow(MMethod* method, ParamsBuilder& params, MonoObject* instance = nullptr, LogType exceptionLevel = LogType::Error); static void InvokeNow(MMethod* method, ParamsBuilder& params, MObject* instance = nullptr, LogType exceptionLevel = LogType::Error);
protected: protected:

View File

@@ -1,9 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MAssembly.h" #include "MAssembly.h"
#if USE_MONO
#include "MClass.h" #include "MClass.h"
#include "MDomain.h" #include "MDomain.h"
#include "MUtils.h" #include "MUtils.h"
@@ -19,14 +16,14 @@
#include "Engine/Platform/File.h" #include "Engine/Platform/File.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/assembly.h> #include <ThirdParty/mono-2.0/mono/metadata/assembly.h>
#include <ThirdParty/mono-2.0/mono/metadata/tokentype.h> #include <ThirdParty/mono-2.0/mono/metadata/tokentype.h>
#endif
MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options) MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options)
: _monoAssembly(nullptr) : _domain(domain)
, _monoImage(nullptr)
, _domain(domain)
, _isLoaded(false) , _isLoaded(false)
, _isLoading(false) , _isLoading(false)
, _isDependency(false) , _isDependency(false)
@@ -83,6 +80,8 @@ bool MAssembly::Load(const String& assemblyPath)
return false; return false;
} }
#if USE_MONO
bool MAssembly::Load(MonoImage* monoImage) bool MAssembly::Load(MonoImage* monoImage)
{ {
if (IsLoaded()) if (IsLoaded())
@@ -116,6 +115,8 @@ bool MAssembly::Load(MonoImage* monoImage)
return false; return false;
} }
#endif
void MAssembly::Unload(bool isReloading) void MAssembly::Unload(bool isReloading)
{ {
if (!IsLoaded()) if (!IsLoaded())
@@ -125,6 +126,7 @@ void MAssembly::Unload(bool isReloading)
Unloading(this); Unloading(this);
// Close runtime // Close runtime
#if USE_MONO
if (_monoImage) if (_monoImage)
{ {
if (isReloading) if (isReloading)
@@ -143,6 +145,7 @@ void MAssembly::Unload(bool isReloading)
_monoAssembly = nullptr; _monoAssembly = nullptr;
_monoImage = nullptr; _monoImage = nullptr;
} }
#endif
// Cleanup // Cleanup
_debugData.Resize(0); _debugData.Resize(0);
@@ -190,6 +193,8 @@ MClass* MAssembly::GetClass(const StringAnsiView& fullname) const
return result; return result;
} }
#if USE_MONO
MClass* MAssembly::GetClass(MonoClass* monoClass) const MClass* MAssembly::GetClass(MonoClass* monoClass) const
{ {
if (monoClass == nullptr || !IsLoaded() || mono_class_get_image(monoClass) != _monoImage) if (monoClass == nullptr || !IsLoaded() || mono_class_get_image(monoClass) != _monoImage)
@@ -226,11 +231,16 @@ MonoReflectionAssembly* MAssembly::GetNative() const
return mono_assembly_get_object(mono_domain_get(), _monoAssembly); return mono_assembly_get_object(mono_domain_get(), _monoAssembly);
} }
#endif
const MAssembly::ClassesDictionary& MAssembly::GetClasses() const const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
{ {
if (_hasCachedClasses || !IsLoaded()) if (_hasCachedClasses || !IsLoaded())
return _classes; return _classes;
PROFILE_CPU(); PROFILE_CPU();
const auto startTime = DateTime::NowUTC();
#if USE_MONO
#if TRACY_ENABLE #if TRACY_ENABLE
const StringAnsiView monoImageName(mono_image_get_name(_monoImage)); const StringAnsiView monoImageName(mono_image_get_name(_monoImage));
ZoneText(*monoImageName, monoImageName.Length()); ZoneText(*monoImageName, monoImageName.Length());
@@ -239,9 +249,6 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
if (_hasCachedClasses) if (_hasCachedClasses)
return _classes; return _classes;
ASSERT(_classes.IsEmpty()); ASSERT(_classes.IsEmpty());
const auto startTime = DateTime::NowUTC();
const int32 numRows = mono_image_get_table_rows(_monoImage, MONO_TABLE_TYPEDEF); const int32 numRows = mono_image_get_table_rows(_monoImage, MONO_TABLE_TYPEDEF);
_classes.EnsureCapacity(numRows * 4); _classes.EnsureCapacity(numRows * 4);
for (int32 i = 1; i < numRows; i++) // Skip <Module> class for (int32 i = 1; i < numRows; i++) // Skip <Module> class
@@ -256,6 +263,7 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
auto mclass = New<MClass>(this, klass, fullname); auto mclass = New<MClass>(this, klass, fullname);
_classes.Add(fullname, mclass); _classes.Add(fullname, mclass);
} }
#endif
const auto endTime = DateTime::NowUTC(); const auto endTime = DateTime::NowUTC();
LOG(Info, "Caching classes for assembly {0} took {1}ms", String(_name), (int32)(endTime - startTime).GetTotalMilliseconds()); LOG(Info, "Caching classes for assembly {0} took {1}ms", String(_name), (int32)(endTime - startTime).GetTotalMilliseconds());
@@ -271,6 +279,7 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
bool MAssembly::LoadDefault(const String& assemblyPath) 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. // 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()); auto assembly = mono_domain_assembly_open(_domain->GetNative(), assemblyPath.ToStringAnsi().Get());
if (!assembly) if (!assembly)
@@ -283,17 +292,18 @@ bool MAssembly::LoadDefault(const String& assemblyPath)
mono_assembly_close(assembly); mono_assembly_close(assembly);
return true; return true;
} }
// Register in domain
_domain->_assemblies[_name] = this;
// Set state
_monoAssembly = assembly; _monoAssembly = assembly;
_monoImage = assemblyImage; _monoImage = assemblyImage;
#endif
// Set state
_isDependency = false; _isDependency = false;
_hasCachedClasses = false; _hasCachedClasses = false;
_isFileLocked = true; _isFileLocked = true;
_assemblyPath = assemblyPath; _assemblyPath = assemblyPath;
// Register in domain
_domain->_assemblies[_name] = this;
return false; return false;
} }
@@ -307,6 +317,7 @@ bool MAssembly::LoadWithImage(const String& assemblyPath)
Array<byte> data; Array<byte> data;
File::ReadAllBytes(assemblyPath, data); File::ReadAllBytes(assemblyPath, data);
#if USE_MONO
// Init Mono image // Init Mono image
MonoImageOpenStatus status; MonoImageOpenStatus status;
const auto name = assemblyPath.ToStringAnsi(); const auto name = assemblyPath.ToStringAnsi();
@@ -359,10 +370,11 @@ bool MAssembly::LoadWithImage(const String& assemblyPath)
} }
#endif #endif
#endif #endif
// Set state
_monoAssembly = assembly; _monoAssembly = assembly;
_monoImage = assemblyImage; _monoImage = assemblyImage;
#endif
// Set state
_isDependency = false; _isDependency = false;
_hasCachedClasses = false; _hasCachedClasses = false;
_isFileLocked = false; _isFileLocked = false;
@@ -379,7 +391,7 @@ void MAssembly::OnLoading()
// Pick a domain // Pick a domain
if (_domain == nullptr) if (_domain == nullptr)
_domain = MCore::Instance()->GetActiveDomain(); _domain = MCore::GetActiveDomain();
} }
void MAssembly::OnLoaded(const DateTime& startTime) void MAssembly::OnLoaded(const DateTime& startTime)
@@ -405,5 +417,3 @@ void MAssembly::OnLoadFailed()
LoadFailed(this); LoadFailed(this);
} }
#endif

View File

@@ -16,7 +16,6 @@
class FLAXENGINE_API MAssembly class FLAXENGINE_API MAssembly
{ {
friend MDomain; friend MDomain;
public: public:
typedef Dictionary<MString, MClass*> ClassesDictionary; typedef Dictionary<MString, MClass*> ClassesDictionary;
@@ -24,8 +23,8 @@ public:
private: private:
#if USE_MONO #if USE_MONO
MonoAssembly* _monoAssembly; MonoAssembly* _monoAssembly = nullptr;
MonoImage* _monoImage; MonoImage* _monoImage = nullptr;
#endif #endif
MDomain* _domain; MDomain* _domain;
@@ -98,7 +97,6 @@ public:
/// <summary> /// <summary>
/// Returns true if assembly is during loading state. /// Returns true if assembly is during loading state.
/// </summary> /// </summary>
/// <returns>True if is loading, otherwise false.</returns>
FORCE_INLINE bool IsLoading() const FORCE_INLINE bool IsLoading() const
{ {
return _isLoading != 0; return _isLoading != 0;
@@ -107,7 +105,6 @@ public:
/// <summary> /// <summary>
/// Returns true if assembly has been loaded. /// Returns true if assembly has been loaded.
/// </summary> /// </summary>
/// <returns>True if is loaded, otherwise false.</returns>
FORCE_INLINE bool IsLoaded() const FORCE_INLINE bool IsLoaded() const
{ {
return _isLoaded != 0; return _isLoaded != 0;
@@ -116,7 +113,6 @@ public:
/// <summary> /// <summary>
/// Gets the assembly name. /// Gets the assembly name.
/// </summary> /// </summary>
/// <returns>The assembly name.</returns>
FORCE_INLINE const MString& GetName() const FORCE_INLINE const MString& GetName() const
{ {
return _name; return _name;
@@ -125,7 +121,6 @@ public:
/// <summary> /// <summary>
/// Gets the assembly name as string. /// Gets the assembly name as string.
/// </summary> /// </summary>
/// <returns>The assembly name.</returns>
String ToString() const; String ToString() const;
/// <summary> /// <summary>
@@ -134,7 +129,6 @@ public:
/// <remarks> /// <remarks>
/// If assembly was made from scratch (empty), path will return null. /// If assembly was made from scratch (empty), path will return null.
/// </remarks> /// </remarks>
/// <returns>The assembly path.</returns>
FORCE_INLINE const String& GetAssemblyPath() const FORCE_INLINE const String& GetAssemblyPath() const
{ {
return _assemblyPath; return _assemblyPath;
@@ -143,20 +137,15 @@ public:
/// <summary> /// <summary>
/// Gets the parent domain. /// Gets the parent domain.
/// </summary> /// </summary>
/// <returns>The domain object.</returns>
FORCE_INLINE MDomain* GetDomain() const FORCE_INLINE MDomain* GetDomain() const
{ {
return _domain; return _domain;
} }
public:
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Gets the Mono assembly. /// Gets the Mono assembly.
/// </summary> /// </summary>
/// <returns>The Mono assembly.</returns>
FORCE_INLINE MonoAssembly* GetMonoAssembly() const FORCE_INLINE MonoAssembly* GetMonoAssembly() const
{ {
return _monoAssembly; return _monoAssembly;
@@ -165,25 +154,22 @@ public:
/// <summary> /// <summary>
/// Gets the Mono image. /// Gets the Mono image.
/// </summary> /// </summary>
/// <returns>The Mono image.</returns>
FORCE_INLINE MonoImage* GetMonoImage() const FORCE_INLINE MonoImage* GetMonoImage() const
{ {
return _monoImage; return _monoImage;
} }
#endif #endif
public:
/// <summary> /// <summary>
/// Gets the options that assembly was created with. /// Gets the options that assembly was created with.
/// </summary> /// </summary>
/// <returns>The options.</returns>
FORCE_INLINE const MAssemblyOptions& GetOptions() const FORCE_INLINE const MAssemblyOptions& GetOptions() const
{ {
return _options; return _options;
} }
public:
/// <summary> /// <summary>
/// Loads assembly for domain. /// Loads assembly for domain.
/// </summary> /// </summary>
@@ -192,14 +178,12 @@ public:
bool Load(const String& assemblyPath); bool Load(const String& assemblyPath);
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Loads assembly for domain. /// Loads assembly for domain.
/// </summary> /// </summary>
/// <param name="monoImage">The assembly image.</param> /// <param name="monoImage">The assembly image.</param>
/// <returns>True if cannot load, otherwise false.</returns> /// <returns>True if cannot load, otherwise false.</returns>
bool Load(MonoImage* monoImage); bool Load(MonoImage* monoImage);
#endif #endif
/// <summary> /// <summary>
@@ -218,7 +202,6 @@ public:
MClass* GetClass(const StringAnsiView& typeName) const; MClass* GetClass(const StringAnsiView& typeName) const;
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Converts an internal mono representation of a class into engine class. /// Converts an internal mono representation of a class into engine class.
/// </summary> /// </summary>
@@ -231,7 +214,6 @@ public:
/// </summary> /// </summary>
/// <returns>The native assembly object.</returns> /// <returns>The native assembly object.</returns>
MonoReflectionAssembly* GetNative() const; MonoReflectionAssembly* GetNative() const;
#endif #endif
/// <summary> /// <summary>
@@ -242,8 +224,6 @@ public:
private: private:
#if USE_MONO
/// <summary> /// <summary>
/// Loads the assembly for domain. /// Loads the assembly for domain.
/// </summary> /// </summary>
@@ -256,8 +236,6 @@ private:
/// <returns>True if failed, otherwise false.</returns> /// <returns>True if failed, otherwise false.</returns>
bool LoadWithImage(const String& assemblyPath); bool LoadWithImage(const String& assemblyPath);
#endif
void OnLoading(); void OnLoading();
void OnLoaded(const struct DateTime& startTime); void OnLoaded(const struct DateTime& startTime);
void OnLoadFailed(); void OnLoadFailed();

View File

@@ -1,9 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MClass.h" #include "MClass.h"
#if USE_MONO
#include "MType.h" #include "MType.h"
#include "MTypes.h" #include "MTypes.h"
#include "MField.h" #include "MField.h"
@@ -11,16 +8,16 @@
#include "MMethod.h" #include "MMethod.h"
#include "MEvent.h" #include "MEvent.h"
#include "Engine/Scripting/Scripting.h" #include "Engine/Scripting/Scripting.h"
#include "Engine/Core/Log.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h> #include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h>
#define GET_CUSTOM_ATTR() (MonoCustomAttrInfo*)(_attrInfo ? _attrInfo : _attrInfo = mono_custom_attrs_from_class(_monoClass)) #define GET_CUSTOM_ATTR() (MonoCustomAttrInfo*)(_attrInfo ? _attrInfo : _attrInfo = mono_custom_attrs_from_class(_monoClass))
#include "Engine/Core/Log.h" #endif
#if USE_MONO
MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname) MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname)
: _monoClass(monoClass) : _assembly(parentAssembly)
, _attrInfo(nullptr)
, _assembly(parentAssembly)
, _fullname(fullname) , _fullname(fullname)
, _visibility(MVisibility::Private) , _visibility(MVisibility::Private)
, _hasCachedProperties(false) , _hasCachedProperties(false)
@@ -33,9 +30,10 @@ MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MStr
, _isAbstract(false) , _isAbstract(false)
, _isInterface(false) , _isInterface(false)
{ {
ASSERT(_monoClass); _monoClass = monoClass;
ASSERT(monoClass);
const uint32_t flags = mono_class_get_flags(_monoClass); const uint32_t flags = mono_class_get_flags(monoClass);
switch (flags & MONO_TYPE_ATTR_VISIBILITY_MASK) switch (flags & MONO_TYPE_ATTR_VISIBILITY_MASK)
{ {
@@ -67,12 +65,14 @@ MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MStr
_isAbstract = !_isStatic && (flags & MONO_TYPE_ATTR_ABSTRACT) == MONO_TYPE_ATTR_ABSTRACT; _isAbstract = !_isStatic && (flags & MONO_TYPE_ATTR_ABSTRACT) == MONO_TYPE_ATTR_ABSTRACT;
_isInterface = (flags & MONO_TYPE_ATTR_CLASS_SEMANTIC_MASK) == MONO_TYPE_ATTR_INTERFACE; _isInterface = (flags & MONO_TYPE_ATTR_CLASS_SEMANTIC_MASK) == MONO_TYPE_ATTR_INTERFACE;
} }
#endif
MClass::~MClass() MClass::~MClass()
{ {
#if USE_MONO
if (_attrInfo) if (_attrInfo)
mono_custom_attrs_free((MonoCustomAttrInfo*)_attrInfo); mono_custom_attrs_free((MonoCustomAttrInfo*)_attrInfo);
#endif
_fields.ClearDelete(); _fields.ClearDelete();
_properties.ClearDelete(); _properties.ClearDelete();
_methods.ClearDelete(); _methods.ClearDelete();
@@ -80,11 +80,6 @@ MClass::~MClass()
_events.ClearDelete(); _events.ClearDelete();
} }
MonoClass* MClass::GetNative() const
{
return _monoClass;
}
bool MClass::IsGeneric() const bool MClass::IsGeneric() const
{ {
return _fullname.FindLast('`') != -1; return _fullname.FindLast('`') != -1;
@@ -92,45 +87,63 @@ bool MClass::IsGeneric() const
MType MClass::GetType() const MType MClass::GetType() const
{ {
#if USE_MONO
return MType(mono_class_get_type(_monoClass)); return MType(mono_class_get_type(_monoClass));
#else
return MType();
#endif
} }
MClass* MClass::GetBaseClass() const MClass* MClass::GetBaseClass() const
{ {
#if USE_MONO
MonoClass* monoBase = mono_class_get_parent(_monoClass); MonoClass* monoBase = mono_class_get_parent(_monoClass);
if (monoBase == nullptr) if (monoBase == nullptr)
return nullptr; return nullptr;
return Scripting::FindClass(monoBase); return Scripting::FindClass(monoBase);
#else
return nullptr;
#endif
} }
bool MClass::IsSubClassOf(const MClass* klass) const bool MClass::IsSubClassOf(const MClass* klass) const
{ {
#if USE_MONO
return klass && mono_class_is_subclass_of(_monoClass, klass->GetNative(), false) != 0; return klass && mono_class_is_subclass_of(_monoClass, klass->GetNative(), false) != 0;
#else
return false;
#endif
} }
#if USE_MONO
bool MClass::IsSubClassOf(MonoClass* monoClass) const bool MClass::IsSubClassOf(MonoClass* monoClass) const
{ {
return monoClass && mono_class_is_subclass_of(_monoClass, monoClass, true) != 0; return monoClass && mono_class_is_subclass_of(_monoClass, monoClass, true) != 0;
} }
#endif
bool MClass::IsInstanceOfType(MonoObject* object) const bool MClass::IsInstanceOfType(MObject* object) const
{ {
if (object == nullptr) if (object == nullptr)
return false; return false;
#if USE_MONO
MonoClass* monoClass = mono_object_get_class(object); MonoClass* monoClass = mono_object_get_class(object);
return mono_class_is_subclass_of(monoClass, _monoClass, false) != 0; return mono_class_is_subclass_of(monoClass, _monoClass, false) != 0;
#else
return false;
#endif
} }
uint32 MClass::GetInstanceSize() const uint32 MClass::GetInstanceSize() const
{ {
#if USE_MONO
uint32 dummy = 0; uint32 dummy = 0;
if (mono_class_is_valuetype(_monoClass)) if (mono_class_is_valuetype(_monoClass))
return mono_class_value_size(_monoClass, &dummy); return mono_class_value_size(_monoClass, &dummy);
return mono_class_instance_size(_monoClass); return mono_class_instance_size(_monoClass);
#else
return 0;
#endif
} }
MMethod* MClass::FindMethod(const char* name, int32 numParams, bool checkBaseClasses) MMethod* MClass::FindMethod(const char* name, int32 numParams, bool checkBaseClasses)
@@ -154,6 +167,7 @@ MMethod* MClass::GetMethod(const char* name, int32 numParams)
return _methods[i]; return _methods[i];
} }
#if USE_MONO
// Find Mono method // Find Mono method
MonoMethod* monoMethod = mono_class_get_method_from_name(_monoClass, name, numParams); MonoMethod* monoMethod = mono_class_get_method_from_name(_monoClass, name, numParams);
if (monoMethod == nullptr) if (monoMethod == nullptr)
@@ -162,8 +176,10 @@ MMethod* MClass::GetMethod(const char* name, int32 numParams)
// Create method // Create method
auto method = New<MMethod>(monoMethod, name, this); auto method = New<MMethod>(monoMethod, name, this);
_methods.Add(method); _methods.Add(method);
return method; return method;
#else
return nullptr;
#endif
} }
const Array<MMethod*>& MClass::GetMethods() const Array<MMethod*>& MClass::GetMethods()
@@ -171,6 +187,7 @@ const Array<MMethod*>& MClass::GetMethods()
if (_hasCachedMethods) if (_hasCachedMethods)
return _methods; return _methods;
#if USE_MONO
void* iter = nullptr; void* iter = nullptr;
MonoMethod* curClassMethod; MonoMethod* curClassMethod;
while ((curClassMethod = mono_class_get_methods(_monoClass, &iter))) while ((curClassMethod = mono_class_get_methods(_monoClass, &iter)))
@@ -193,6 +210,7 @@ const Array<MMethod*>& MClass::GetMethods()
_methods.Add(method); _methods.Add(method);
} }
} }
#endif
_hasCachedMethods = true; _hasCachedMethods = true;
return _methods; return _methods;
@@ -207,6 +225,7 @@ MField* MClass::GetField(const char* name)
return _fields[i]; return _fields[i];
} }
#if USE_MONO
// Find mono field // Find mono field
MonoClassField* field = mono_class_get_field_from_name(_monoClass, name); MonoClassField* field = mono_class_get_field_from_name(_monoClass, name);
if (field == nullptr) if (field == nullptr)
@@ -216,6 +235,9 @@ MField* MClass::GetField(const char* name)
auto mfield = New<MField>(field, name, this); auto mfield = New<MField>(field, name, this);
_fields.Add(mfield); _fields.Add(mfield);
return mfield; return mfield;
#else
return nullptr;
#endif
} }
const Array<MField*>& MClass::GetFields() const Array<MField*>& MClass::GetFields()
@@ -223,6 +245,7 @@ const Array<MField*>& MClass::GetFields()
if (_hasCachedFields) if (_hasCachedFields)
return _fields; return _fields;
#if USE_MONO
void* iter = nullptr; void* iter = nullptr;
MonoClassField* curClassField; MonoClassField* curClassField;
while ((curClassField = mono_class_get_fields(_monoClass, &iter))) while ((curClassField = mono_class_get_fields(_monoClass, &iter)))
@@ -230,6 +253,7 @@ const Array<MField*>& MClass::GetFields()
const char* fieldName = mono_field_get_name(curClassField); const char* fieldName = mono_field_get_name(curClassField);
GetField(fieldName); GetField(fieldName);
} }
#endif
_hasCachedFields = true; _hasCachedFields = true;
return _fields; return _fields;
@@ -246,34 +270,33 @@ MEvent* MClass::GetEvent(const char* name)
return nullptr; return nullptr;
} }
MEvent* MClass::AddEvent(const char* name, MonoEvent* event)
{
// Lookup for cached event
for (int32 i = 0; i < _events.Count(); i++)
{
if (_events[i]->GetName() == name)
return _events[i];
}
// Create field
auto result = New<MEvent>(event, name, this);
_events.Add(result);
return result;
}
const Array<MEvent*>& MClass::GetEvents() const Array<MEvent*>& MClass::GetEvents()
{ {
if (_hasCachedEvents) if (_hasCachedEvents)
return _events; return _events;
#if USE_MONO
void* iter = nullptr; void* iter = nullptr;
MonoEvent* curEvent; MonoEvent* curEvent;
while ((curEvent = mono_class_get_events(_monoClass, &iter))) while ((curEvent = mono_class_get_events(_monoClass, &iter)))
{ {
const char* fieldName = mono_event_get_name(curEvent); const char* name = mono_event_get_name(curEvent);
AddEvent(fieldName, 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; _hasCachedEvents = true;
return _events; return _events;
@@ -288,6 +311,7 @@ MProperty* MClass::GetProperty(const char* name)
return _properties[i]; return _properties[i];
} }
#if USE_MONO
// Find mono property // Find mono property
MonoProperty* monoProperty = mono_class_get_property_from_name(_monoClass, name); MonoProperty* monoProperty = mono_class_get_property_from_name(_monoClass, name);
if (monoProperty == nullptr) if (monoProperty == nullptr)
@@ -298,6 +322,9 @@ MProperty* MClass::GetProperty(const char* name)
_properties.Add(mproperty); _properties.Add(mproperty);
return mproperty; return mproperty;
#else
return nullptr;
#endif
} }
const Array<MProperty*>& MClass::GetProperties() const Array<MProperty*>& MClass::GetProperties()
@@ -305,6 +332,7 @@ const Array<MProperty*>& MClass::GetProperties()
if (_hasCachedProperties) if (_hasCachedProperties)
return _properties; return _properties;
#if USE_MONO
void* iter = nullptr; void* iter = nullptr;
MonoProperty* curClassProperty; MonoProperty* curClassProperty;
while ((curClassProperty = mono_class_get_properties(_monoClass, &iter))) while ((curClassProperty = mono_class_get_properties(_monoClass, &iter)))
@@ -312,52 +340,74 @@ const Array<MProperty*>& MClass::GetProperties()
const char* propertyName = mono_property_get_name(curClassProperty); const char* propertyName = mono_property_get_name(curClassProperty);
GetProperty(propertyName); GetProperty(propertyName);
} }
#endif
_hasCachedProperties = true; _hasCachedProperties = true;
return _properties; return _properties;
} }
MonoObject* MClass::CreateInstance() const MObject* MClass::CreateInstance() const
{ {
#if USE_MONO
MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass); MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass);
if (!mono_class_is_valuetype(_monoClass)) if (!mono_class_is_valuetype(_monoClass))
mono_runtime_object_init(obj); mono_runtime_object_init(obj);
return obj; return obj;
#else
return nullptr;
#endif
} }
MonoObject* MClass::CreateInstance(void** params, uint32 numParams) MObject* MClass::CreateInstance(void** params, uint32 numParams)
{ {
#if USE_MONO
MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass); MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass);
const auto constructor = GetMethod(".ctor", numParams); const auto constructor = GetMethod(".ctor", numParams);
ASSERT(constructor); ASSERT(constructor);
constructor->Invoke(obj, params, nullptr); constructor->Invoke(obj, params, nullptr);
return obj; return obj;
#else
return nullptr;
#endif
} }
bool MClass::HasAttribute(MClass* monoClass) bool MClass::HasAttribute(MClass* monoClass)
{ {
#if USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0; return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
#else
return false;
#endif
} }
bool MClass::HasAttribute() bool MClass::HasAttribute()
{ {
#if USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo && attrInfo->num_attrs > 0; return attrInfo && attrInfo->num_attrs > 0;
#else
return false;
#endif
} }
MonoObject* MClass::GetAttribute(MClass* monoClass) MObject* MClass::GetAttribute(MClass* monoClass)
{ {
#if USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
return attrInfo ? mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()) : nullptr; return attrInfo ? mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()) : nullptr;
#else
return false;
#endif
} }
const Array<MonoObject*>& MClass::GetAttributes() const Array<MObject*>& MClass::GetAttributes()
{ {
if (_hasCachedAttributes) if (_hasCachedAttributes)
return _attributes; return _attributes;
_hasCachedAttributes = true; _hasCachedAttributes = true;
#if USE_MONO
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR(); MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
if (attrInfo == nullptr) if (attrInfo == nullptr)
return _attributes; return _attributes;
@@ -366,9 +416,8 @@ const Array<MonoObject*>& MClass::GetAttributes()
const auto length = (uint32)mono_array_length(monoAttributesArray); const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length); _attributes.Resize(length);
for (uint32 i = 0; i < length; i++) for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i); _attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return _attributes; return _attributes;
} }
#endif

View File

@@ -14,7 +14,7 @@ private:
#if USE_MONO #if USE_MONO
MonoClass* _monoClass; MonoClass* _monoClass;
void* _attrInfo; void* _attrInfo = nullptr;
#endif #endif
const MAssembly* _assembly; const MAssembly* _assembly;
@@ -23,7 +23,7 @@ private:
Array<MMethod*> _methods; Array<MMethod*> _methods;
Array<MField*> _fields; Array<MField*> _fields;
Array<MProperty*> _properties; Array<MProperty*> _properties;
Array<MonoObject*> _attributes; Array<MObject*> _attributes;
Array<MEvent*> _events; Array<MEvent*> _events;
MVisibility _visibility; MVisibility _visibility;
@@ -40,6 +40,7 @@ private:
public: public:
#if USE_MONO
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MClass"/> class. /// Initializes a new instance of the <see cref="MClass"/> class.
/// </summary> /// </summary>
@@ -47,6 +48,7 @@ public:
/// <param name="monoClass">The Mono class.</param> /// <param name="monoClass">The Mono class.</param>
/// <param name="fullname">The fullname.</param> /// <param name="fullname">The fullname.</param>
MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname); MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname);
#endif
/// <summary> /// <summary>
/// Finalizes an instance of the <see cref="MClass"/> class. /// Finalizes an instance of the <see cref="MClass"/> class.
@@ -72,12 +74,13 @@ public:
} }
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Gets the Mono class handle. /// Gets the Mono class handle.
/// </summary> /// </summary>
MonoClass* GetNative() const; FORCE_INLINE MonoClass* GetNative() const
{
return _monoClass;
}
#endif #endif
/// <summary> /// <summary>
@@ -142,19 +145,21 @@ public:
/// <returns>True if this class is a sub class of the specified class.</returns> /// <returns>True if this class is a sub class of the specified class.</returns>
bool IsSubClassOf(const MClass* klass) const; bool IsSubClassOf(const MClass* klass) const;
#if USE_MONO
/// <summary> /// <summary>
/// Checks if this class is a sub class of the specified class (including any derived types). /// Checks if this class is a sub class of the specified class (including any derived types).
/// </summary> /// </summary>
/// <param name="monoClass">The Mono class.</param> /// <param name="monoClass">The Mono class.</param>
/// <returns>True if this class is a sub class of the specified class.</returns> /// <returns>True if this class is a sub class of the specified class.</returns>
bool IsSubClassOf(MonoClass* monoClass) const; bool IsSubClassOf(MonoClass* monoClass) const;
#endif
/// <summary> /// <summary>
/// Checks is the provided object instance of this class' type. /// Checks is the provided object instance of this class' type.
/// </summary> /// </summary>
/// <param name="object">The object to check.</param> /// <param name="object">The object to check.</param>
/// <returns>True if object is an instance the this class.</returns> /// <returns>True if object is an instance the this class.</returns>
bool IsInstanceOfType(MonoObject* object) const; bool IsInstanceOfType(MObject* object) const;
/// <summary> /// <summary>
/// Returns the size of an instance of this class, in bytes. /// Returns the size of an instance of this class, in bytes.
@@ -217,14 +222,6 @@ public:
/// <returns>The event object.</returns> /// <returns>The event object.</returns>
MEvent* GetEvent(const char* name); MEvent* GetEvent(const char* name);
/// <summary>
/// Adds event with the specified name to the cache.
/// </summary>
/// <param name="name">The event name.</param>
/// <param name="event">The event Mono object.</param>
/// <returns>The event.</returns>
MEvent* AddEvent(const char* name, MonoEvent* event);
/// <summary> /// <summary>
/// Returns all events belonging to this class. /// Returns all events belonging to this class.
/// </summary> /// </summary>
@@ -257,7 +254,7 @@ public:
/// Creates a new instance of this class and constructs it. /// Creates a new instance of this class and constructs it.
/// </summary> /// </summary>
/// <returns>The created managed object.</returns> /// <returns>The created managed object.</returns>
MonoObject* CreateInstance() const; MObject* CreateInstance() const;
/// <summary> /// <summary>
/// Creates a new instance of this class and then constructs it using the constructor with the specified number of parameters. /// Creates a new instance of this class and then constructs it using the constructor with the specified number of parameters.
@@ -265,7 +262,7 @@ public:
/// <param name="params">The array containing pointers to constructor parameters. Array length must be equal to number of parameters.</param> /// <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> /// <param name="numParams">The number of parameters the constructor accepts.</param>
/// <returns>The created managed object.</returns> /// <returns>The created managed object.</returns>
MonoObject* CreateInstance(void** params, uint32 numParams); MObject* CreateInstance(void** params, uint32 numParams);
public: public:
@@ -287,11 +284,11 @@ public:
/// </summary> /// </summary>
/// <param name="monoClass">The attribute class to take.</param> /// <param name="monoClass">The attribute class to take.</param>
/// <returns>The attribute object.</returns> /// <returns>The attribute object.</returns>
MonoObject* GetAttribute(MClass* monoClass); MObject* GetAttribute(MClass* monoClass);
/// <summary> /// <summary>
/// Returns an instance of all attributes connected with given class. Returns null if the class doesn't have any attributes. /// Returns an instance of all attributes connected with given class. Returns null if the class doesn't have any attributes.
/// </summary> /// </summary>
/// <returns>The array of attribute objects.</returns> /// <returns>The array of attribute objects.</returns>
const Array<MonoObject*>& GetAttributes(); const Array<MObject*>& GetAttributes();
}; };

View File

@@ -1,9 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MCore.h" #include "MCore.h"
#if USE_MONO
#include "MDomain.h" #include "MDomain.h"
#include "MClass.h" #include "MClass.h"
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
@@ -16,6 +13,7 @@
#include "Engine/Platform/Thread.h" #include "Engine/Platform/Thread.h"
#include "Engine/Scripting/MException.h" #include "Engine/Scripting/MException.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#if USE_MONO
#ifdef USE_MONO_AOT_MODULE #ifdef USE_MONO_AOT_MODULE
#include "Engine/Core/Types/TimeSpan.h" #include "Engine/Core/Types/TimeSpan.h"
#endif #endif
@@ -33,15 +31,24 @@
#if !USE_MONO_DYNAMIC_LIB #if !USE_MONO_DYNAMIC_LIB
#include <ThirdParty/mono-2.0/mono/utils/mono-dl-fallback.h> #include <ThirdParty/mono-2.0/mono/utils/mono-dl-fallback.h>
#endif #endif
#endif
#ifdef USE_MONO_AOT_MODULE #ifdef USE_MONO_AOT_MODULE
void* MonoAotModuleHandle = nullptr; void* MonoAotModuleHandle = nullptr;
#endif #endif
MCore::MCore() MDomain* MRootDomain = nullptr;
: _rootDomain(nullptr) MDomain* MActiveDomain = nullptr;
, _activeDomain(nullptr) Array<MDomain*, InlinedAllocation<4>> MDomains;
MDomain* MCore::GetRootDomain()
{ {
return MRootDomain;
}
MDomain* MCore::GetActiveDomain()
{
return MActiveDomain;
} }
MDomain* MCore::CreateDomain(const MString& domainName) MDomain* MCore::CreateDomain(const MString& domainName)
@@ -51,50 +58,56 @@ MDomain* MCore::CreateDomain(const MString& domainName)
return nullptr; return nullptr;
#endif #endif
for (int32 i = 0; i < _domains.Count(); i++) for (int32 i = 0; i < MDomains.Count(); i++)
{ {
if (_domains[i]->GetName() == domainName) if (MDomains[i]->GetName() == domainName)
return _domains[i]; return MDomains[i];
} }
auto domain = New<MDomain>(domainName);
#if USE_MONO
const auto monoDomain = mono_domain_create_appdomain((char*)domainName.Get(), nullptr); const auto monoDomain = mono_domain_create_appdomain((char*)domainName.Get(), nullptr);
#if MONO_DEBUG_ENABLE #if MONO_DEBUG_ENABLE
mono_debug_domain_create(monoDomain); mono_debug_domain_create(monoDomain);
#endif #endif
ASSERT(monoDomain); ASSERT(monoDomain);
auto domain = New<MDomain>(domainName, monoDomain); domain->_monoDomain = monoDomain;
_domains.Add(domain); #endif
MDomains.Add(domain);
return domain; return domain;
} }
void MCore::UnloadDomain(const MString& domainName) void MCore::UnloadDomain(const MString& domainName)
{ {
int32 i = 0; int32 i = 0;
for (; i < _domains.Count(); i++) for (; i < MDomains.Count(); i++)
{ {
if (_domains[i]->GetName() == domainName) if (MDomains[i]->GetName() == domainName)
break; break;
} }
if (i == _domains.Count()) if (i == MDomains.Count())
return; return;
auto domain = _domains[i]; auto domain = MDomains[i];
#if USE_MONO
#if MONO_DEBUG_ENABLE #if MONO_DEBUG_ENABLE
//mono_debug_domain_unload(domain->GetNative()); //mono_debug_domain_unload(domain->GetNative());
#endif #endif
//mono_domain_finalize(_monoScriptsDomain, 2000); //mono_domain_finalize(domain->GetNative(), 2000);
MObject* exception = nullptr;
MonoObject* exception = nullptr;
mono_domain_try_unload(domain->GetNative(), &exception); mono_domain_try_unload(domain->GetNative(), &exception);
if (exception) if (exception)
{ {
MException ex(exception); MException ex(exception);
ex.Log(LogType::Fatal, TEXT("Scripting::Release")); ex.Log(LogType::Fatal, TEXT("Scripting::Release"));
} }
#endif
Delete(domain); Delete(domain);
_domains.RemoveAtKeepOrder(i); MDomains.RemoveAtKeepOrder(i);
} }
#if USE_MONO
#if 0 #if 0
void* MonoMalloc(size_t size) void* MonoMalloc(size_t size)
@@ -254,7 +267,7 @@ void OnLogCallback(const char* logDomain, const char* logLevel, const char* mess
if (currentDomain.IsEmpty()) if (currentDomain.IsEmpty())
{ {
auto domain = MCore::Instance()->GetActiveDomain(); auto domain = MCore::GetActiveDomain();
if (domain != nullptr) if (domain != nullptr)
{ {
currentDomain = domain->GetName().Get(); currentDomain = domain->GetName().Get();
@@ -443,7 +456,7 @@ bool MCore::LoadEngine()
#endif #endif
// Connects to mono engine callback system // Connects to mono engine callback system
mono_trace_set_log_handler(OnLogCallback, this); mono_trace_set_log_handler(OnLogCallback, nullptr);
mono_trace_set_print_handler(OnPrintCallback); mono_trace_set_print_handler(OnPrintCallback);
mono_trace_set_printerr_handler(OnPrintErrorCallback); mono_trace_set_printerr_handler(OnPrintErrorCallback);
} }
@@ -505,7 +518,7 @@ bool MCore::LoadEngine()
} }
#endif #endif
// Init Mono // Init Mono
#if PLATFORM_ANDROID #if PLATFORM_ANDROID
const char* monoVersion = "mobile"; const char* monoVersion = "mobile";
#else #else
@@ -513,8 +526,9 @@ bool MCore::LoadEngine()
#endif #endif
auto monoRootDomain = mono_jit_init_version("Flax", monoVersion); auto monoRootDomain = mono_jit_init_version("Flax", monoVersion);
ASSERT(monoRootDomain); ASSERT(monoRootDomain);
_rootDomain = New<MDomain>("Root", monoRootDomain); MRootDomain = New<MDomain>("Root");
_domains.Add(_rootDomain); MRootDomain->_monoDomain = monoRootDomain;
MDomains.Add(MRootDomain);
auto exePath = Platform::GetExecutableFilePath(); auto exePath = Platform::GetExecutableFilePath();
auto configDir = StringUtils::GetDirectoryName(exePath).ToStringAnsi(); auto configDir = StringUtils::GetDirectoryName(exePath).ToStringAnsi();
@@ -553,29 +567,29 @@ void MCore::UnloadEngine()
Thread::ThreadExiting.Unbind<OnThreadExiting>(); Thread::ThreadExiting.Unbind<OnThreadExiting>();
// Only root domain should be alive at this point // Only root domain should be alive at this point
for (auto domain : _domains) for (auto domain : MDomains)
{ {
if (domain != _rootDomain) if (domain != MRootDomain)
Delete(domain); Delete(domain);
} }
_domains.Clear(); MDomains.Clear();
if (_rootDomain) if (MRootDomain)
{ {
#if PLATFORM_WINDOWS && USE_EDITOR #if PLATFORM_WINDOWS && USE_EDITOR
// TODO: reduce issues with hot-reloading C# DLLs because sometimes it crashes on exit // TODO: reduce issues with hot-reloading C# DLLs because sometimes it crashes on exit
__try __try
#endif #endif
{ {
mono_jit_cleanup(_rootDomain->GetNative()); mono_jit_cleanup(MRootDomain->GetNative());
} }
#if PLATFORM_WINDOWS && USE_EDITOR #if PLATFORM_WINDOWS && USE_EDITOR
__except (MonoHackSehExceptionHandler(nullptr)) __except (MonoHackSehExceptionHandler(nullptr))
{ {
} }
#endif #endif
Delete(_rootDomain); Delete(MRootDomain);
_rootDomain = nullptr; MRootDomain = nullptr;
} }
#ifdef USE_MONO_AOT_MODULE #ifdef USE_MONO_AOT_MODULE
@@ -591,39 +605,65 @@ void MCore::UnloadEngine()
#endif #endif
} }
#else
bool MCore::LoadEngine()
{
MRootDomain = New<MDomain>("Root");
MDomains.Add(MRootDomain);
return false;
}
void MCore::UnloadEngine()
{
MDomains.ClearDelete();
MRootDomain = nullptr;
}
#endif
void MCore::AttachThread() void MCore::AttachThread()
{ {
#if USE_MONO
if (!IsInMainThread() && !mono_domain_get()) if (!IsInMainThread() && !mono_domain_get())
{ {
const auto domain = Instance()->GetActiveDomain(); const auto domain = GetActiveDomain();
ASSERT(domain); ASSERT(domain);
mono_thread_attach(domain->GetNative()); mono_thread_attach(domain->GetNative());
} }
#endif
} }
void MCore::ExitThread() void MCore::ExitThread()
{ {
#if USE_MONO
if (!IsInMainThread() && mono_domain_get()) if (!IsInMainThread() && mono_domain_get())
{ {
LOG(Info, "Thread 0x{0:x} exits the managed runtime", Platform::GetCurrentThreadID()); LOG(Info, "Thread 0x{0:x} exits the managed runtime", Platform::GetCurrentThreadID());
mono_thread_exit(); mono_thread_exit();
} }
#endif
} }
void MCore::GC::Collect() void MCore::GC::Collect()
{ {
#if USE_MONO
PROFILE_CPU(); PROFILE_CPU();
mono_gc_collect(mono_gc_max_generation()); mono_gc_collect(mono_gc_max_generation());
#endif
} }
void MCore::GC::Collect(int32 generation) void MCore::GC::Collect(int32 generation)
{ {
#if USE_MONO
PROFILE_CPU(); PROFILE_CPU();
mono_gc_collect(generation); mono_gc_collect(generation);
#endif
} }
void MCore::GC::WaitForPendingFinalizers() void MCore::GC::WaitForPendingFinalizers()
{ {
#if USE_MONO
PROFILE_CPU(); PROFILE_CPU();
if (mono_gc_pending_finalizers()) if (mono_gc_pending_finalizers())
{ {
@@ -633,9 +673,10 @@ void MCore::GC::WaitForPendingFinalizers()
Platform::Sleep(1); Platform::Sleep(1);
} while (mono_gc_pending_finalizers()); } while (mono_gc_pending_finalizers());
} }
#endif
} }
#if PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB #if USE_MONO && PLATFORM_WIN32 && !USE_MONO_DYNAMIC_LIB
// Export Mono functions // Export Mono functions
#pragma comment(linker, "/export:mono_add_internal_call") #pragma comment(linker, "/export:mono_add_internal_call")
@@ -2109,5 +2150,3 @@ void MCore::GC::WaitForPendingFinalizers()
#pragma comment(linker, "/export:mono_jit_info_get_code_size") #pragma comment(linker, "/export:mono_jit_info_get_code_size")
#endif #endif
#endif

View File

@@ -2,63 +2,37 @@
#pragma once #pragma once
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Singleton.h"
#include "MTypes.h" #include "MTypes.h"
/// <summary> /// <summary>
/// Main handler for CLR Engine. /// Main handler for CLR Engine.
/// </summary> /// </summary>
class FLAXENGINE_API MCore : public Singleton<MCore> class FLAXENGINE_API MCore
{ {
friend MDomain;
private:
MDomain* _rootDomain;
MDomain* _activeDomain;
Array<MDomain*, InlinedAllocation<4>> _domains;
public: public:
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MCore"/> class. /// Gets the root domain.
/// </summary> /// </summary>
MCore(); static MDomain* GetRootDomain();
public: /// <summary>
/// Gets the currently active domain.
/// </summary>
static MDomain* GetActiveDomain();
/// <summary> /// <summary>
/// Creates an new empty domain. /// Creates an new empty domain.
/// </summary> /// </summary>
/// <param name="domainName">The domain name to create.</param> /// <param name="domainName">The domain name to create.</param>
/// <returns>The domain object.</returns> /// <returns>The domain object.</returns>
MDomain* CreateDomain(const MString& domainName); static MDomain* CreateDomain(const MString& domainName);
/// <summary> /// <summary>
/// Unloads the domain. /// Unloads the domain.
/// </summary> /// </summary>
/// <param name="domainName">The domain name to remove.</param> /// <param name="domainName">The domain name to remove.</param>
void UnloadDomain(const MString& domainName); static void UnloadDomain(const MString& domainName);
/// <summary>
/// Gets the root domain.
/// </summary>
/// <returns>The root domain.</returns>
FORCE_INLINE MDomain* GetRootDomain() const
{
return _rootDomain;
}
/// <summary>
/// Gets the currently active domain.
/// </summary>
/// <returns>The current domain.</returns>
FORCE_INLINE MDomain* GetActiveDomain() const
{
return _activeDomain;
}
public: public:
@@ -66,12 +40,12 @@ public:
/// Initialize CLR Engine /// Initialize CLR Engine
/// </summary> /// </summary>
/// <returns>True if failed, otherwise false.</returns> /// <returns>True if failed, otherwise false.</returns>
bool LoadEngine(); static bool LoadEngine();
/// <summary> /// <summary>
/// Unload CLR Engine /// Unload CLR Engine
/// </summary> /// </summary>
void UnloadEngine(); static void UnloadEngine();
/// <summary> /// <summary>
/// Attaches CLR runtime to the current thread. Use it to allow invoking managed runtime from native threads. /// Attaches CLR runtime to the current thread. Use it to allow invoking managed runtime from native threads.

View File

@@ -1,38 +1,31 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MDomain.h" #include "MDomain.h"
#if USE_MONO
#include "MCore.h" #include "MCore.h"
#include "MAssembly.h" #include "MAssembly.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
#include "Engine/Debug/Exceptions/ArgumentException.h" #include "Engine/Debug/Exceptions/ArgumentException.h"
#include "Engine/Debug/Exceptions/Exceptions.h" #include "Engine/Debug/Exceptions/Exceptions.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/threads.h> #include <ThirdParty/mono-2.0/mono/metadata/threads.h>
#endif
MDomain::MDomain(const MString& domainName, MonoDomain* monoDomain) extern MDomain* MActiveDomain;
: _monoDomain(monoDomain)
, _domainName(domainName)
, _coreInstance(MCore::Instance())
{
}
MonoDomain* MDomain::GetNative() const MDomain::MDomain(const MString& domainName)
: _domainName(domainName)
{ {
return _monoDomain;
} }
bool MDomain::SetCurrentDomain(bool force) bool MDomain::SetCurrentDomain(bool force)
{ {
ASSERT(_monoDomain); #if USE_MONO
const auto monoBool = mono_domain_set(_monoDomain, force) != 0; if (mono_domain_set(_monoDomain, force) == 0)
if (monoBool) return false;
{ #endif
_coreInstance->_activeDomain = this; MActiveDomain = this;
} return true;
return monoBool;
} }
MAssembly* MDomain::CreateEmptyAssembly(const MString& assemblyName, const MAssemblyOptions options) MAssembly* MDomain::CreateEmptyAssembly(const MString& assemblyName, const MAssemblyOptions options)
@@ -72,10 +65,12 @@ MAssembly* MDomain::GetAssembly(const MString& assemblyName) const
void MDomain::Dispatch() const void MDomain::Dispatch() const
{ {
#if USE_MONO
if (!IsInMainThread()) if (!IsInMainThread())
{ {
mono_thread_attach(_monoDomain); mono_thread_attach(_monoDomain);
} }
#endif
} }
MClass* MDomain::FindClass(const StringAnsiView& fullname) const MClass* MDomain::FindClass(const StringAnsiView& fullname) const
@@ -90,5 +85,3 @@ MClass* MDomain::FindClass(const StringAnsiView& fullname) const
} }
return nullptr; return nullptr;
} }
#endif

View File

@@ -17,7 +17,6 @@ class FLAXENGINE_API MDomain
{ {
friend MCore; friend MCore;
friend MAssembly; friend MAssembly;
public: public:
typedef Dictionary<MString, MAssembly*> AssembliesDictionary; typedef Dictionary<MString, MAssembly*> AssembliesDictionary;
@@ -27,38 +26,43 @@ private:
#if USE_MONO #if USE_MONO
MonoDomain* _monoDomain; MonoDomain* _monoDomain;
#endif #endif
MString _domainName; MString _domainName;
AssembliesDictionary _assemblies; AssembliesDictionary _assemblies;
MCore* _coreInstance;
public:
MDomain(const MString& domainName);
public: public:
#if USE_MONO #if USE_MONO
MDomain(const MString& domainName, MonoDomain* monoDomain);
#endif
public:
#if USE_MONO
/// <summary> /// <summary>
/// Gets native domain class /// Gets native domain class.
/// </summary> /// </summary>
/// <returns>The native domain.</returns> FORCE_INLINE MonoDomain* GetNative() const
MonoDomain* GetNative() const; {
return _monoDomain;
}
#endif #endif
/// <summary> /// <summary>
/// Gets current domain name /// Gets current domain name
/// </summary> /// </summary>
/// <returns>The name.</returns>
FORCE_INLINE const MString& GetName() const FORCE_INLINE const MString& GetName() const
{ {
return _domainName; return _domainName;
} }
/// <summary>
/// Gets the current domain assemblies.
/// </summary>
FORCE_INLINE const AssembliesDictionary& GetAssemblies() const
{
return _assemblies;
}
public:
/// <summary> /// <summary>
/// Create assembly container from current domain /// Create assembly container from current domain
/// </summary> /// </summary>
@@ -73,15 +77,6 @@ public:
/// <param name="assemblyName">Assembly name</param> /// <param name="assemblyName">Assembly name</param>
void RemoveAssembly(const MString& assemblyName); void RemoveAssembly(const MString& assemblyName);
/// <summary>
/// Gets the current domain assemblies.
/// </summary>
/// <returns>The assemblies.</returns>
FORCE_INLINE const AssembliesDictionary& GetAssemblies() const
{
return _assemblies;
}
/// <summary> /// <summary>
/// Gets current domain assembly. /// Gets current domain assembly.
/// </summary> /// </summary>

View File

@@ -1,11 +1,9 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MEvent.h" #include "MEvent.h"
#if USE_MONO
#include "MType.h" #include "MType.h"
#include "MClass.h" #include "MClass.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass) MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass)
@@ -24,13 +22,14 @@ MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass)
#endif #endif
} }
#endif
MType MEvent::GetType() MType MEvent::GetType()
{ {
if (GetAddMethod() != nullptr) if (GetAddMethod() != nullptr)
return GetAddMethod()->GetReturnType(); return GetAddMethod()->GetReturnType();
if (GetRemoveMethod() != nullptr) if (GetRemoveMethod() != nullptr)
return GetRemoveMethod()->GetReturnType(); return GetRemoveMethod()->GetReturnType();
CRASH;
return MType(); return MType();
} }
@@ -40,12 +39,14 @@ MMethod* MEvent::GetAddMethod()
return nullptr; return nullptr;
if (_addMethod == nullptr) if (_addMethod == nullptr)
{ {
#if USE_MONO
auto addMonoMethod = mono_event_get_add_method(_monoEvent); auto addMonoMethod = mono_event_get_add_method(_monoEvent);
if (addMonoMethod != nullptr) if (addMonoMethod != nullptr)
{ {
_hasAddMonoMethod = true; _hasAddMonoMethod = true;
return _addMethod = New<MMethod>(addMonoMethod, _parentClass); return _addMethod = New<MMethod>(addMonoMethod, _parentClass);
} }
#endif
} }
return _addMethod; return _addMethod;
} }
@@ -56,19 +57,21 @@ MMethod* MEvent::GetRemoveMethod()
return nullptr; return nullptr;
if (_removeMethod == nullptr) if (_removeMethod == nullptr)
{ {
#if USE_MONO
auto removeMonoMethod = mono_event_get_remove_method(_monoEvent); auto removeMonoMethod = mono_event_get_remove_method(_monoEvent);
if (removeMonoMethod) if (removeMonoMethod)
{ {
_hasRemoveMonoMethod = true; _hasRemoveMonoMethod = true;
return _removeMethod = New<MMethod>(removeMonoMethod, _parentClass); return _removeMethod = New<MMethod>(removeMonoMethod, _parentClass);
} }
return nullptr; #endif
} }
return _removeMethod; return _removeMethod;
} }
bool MEvent::HasAttribute(MClass* monoClass) const bool MEvent::HasAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent); MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -77,10 +80,14 @@ bool MEvent::HasAttribute(MClass* monoClass) const
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0; const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return hasAttr; return hasAttr;
#else
return false;
#endif
} }
bool MEvent::HasAttribute() const bool MEvent::HasAttribute() const
{ {
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent); MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -93,10 +100,14 @@ bool MEvent::HasAttribute() const
} }
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return false; return false;
#else
return false;
#endif
} }
MonoObject* MEvent::GetAttribute(MClass* monoClass) const MObject* MEvent::GetAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent); MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -105,14 +116,18 @@ MonoObject* MEvent::GetAttribute(MClass* monoClass) const
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()); MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return foundAttr; return foundAttr;
#else
return false;
#endif
} }
const Array<MonoObject*>& MEvent::GetAttributes() const Array<MObject*>& MEvent::GetAttributes()
{ {
if (_hasCachedAttributes) if (_hasCachedAttributes)
return _attributes; return _attributes;
_hasCachedAttributes = true; _hasCachedAttributes = true;
#if USE_MONO
MonoClass* parentClass = mono_event_get_parent(_monoEvent); MonoClass* parentClass = mono_event_get_parent(_monoEvent);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -122,9 +137,8 @@ const Array<MonoObject*>& MEvent::GetAttributes()
const auto length = (uint32)mono_array_length(monoAttributesArray); const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length); _attributes.Resize(length);
for (uint32 i = 0; i < length; i++) for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i); _attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return _attributes; return _attributes;
} }
#endif

View File

@@ -23,12 +23,12 @@ protected:
MString _name; MString _name;
Array<MonoObject*> _attributes;
int32 _hasCachedAttributes : 1; int32 _hasCachedAttributes : 1;
int32 _hasAddMonoMethod : 1; int32 _hasAddMonoMethod : 1;
int32 _hasRemoveMonoMethod : 1; int32 _hasRemoveMonoMethod : 1;
Array<MObject*> _attributes;
public: public:
#if USE_MONO #if USE_MONO
@@ -40,7 +40,6 @@ public:
/// <summary> /// <summary>
/// Gets the event name. /// Gets the event name.
/// </summary> /// </summary>
/// <returns>The name.</returns>
FORCE_INLINE const MString& GetName() const FORCE_INLINE const MString& GetName() const
{ {
return _name; return _name;
@@ -49,7 +48,6 @@ public:
/// <summary> /// <summary>
/// Returns the parent class that this method is contained with. /// Returns the parent class that this method is contained with.
/// </summary> /// </summary>
/// <returns>The parent class.</returns>
FORCE_INLINE MClass* GetParentClass() const FORCE_INLINE MClass* GetParentClass() const
{ {
return _parentClass; return _parentClass;
@@ -58,25 +56,21 @@ public:
/// <summary> /// <summary>
/// Gets the event type class. /// Gets the event type class.
/// </summary> /// </summary>
/// <returns>The type class.</returns>
MType GetType(); MType GetType();
/// <summary> /// <summary>
/// Gets the event add method. /// Gets the event add method.
/// </summary> /// </summary>
/// <returns>The method object.</returns>
MMethod* GetAddMethod(); MMethod* GetAddMethod();
/// <summary> /// <summary>
/// Gets the event remove method. /// Gets the event remove method.
/// </summary> /// </summary>
/// <returns>The method object.</returns>
MMethod* GetRemoveMethod(); MMethod* GetRemoveMethod();
/// <summary> /// <summary>
/// Gets event visibility in the class. /// Gets event visibility in the class.
/// </summary> /// </summary>
/// <returns>The event visibility.</returns>
FORCE_INLINE MVisibility GetVisibility() FORCE_INLINE MVisibility GetVisibility()
{ {
return GetAddMethod()->GetVisibility(); return GetAddMethod()->GetVisibility();
@@ -85,23 +79,19 @@ public:
/// <summary> /// <summary>
/// Returns true if event is static. /// Returns true if event is static.
/// </summary> /// </summary>
/// <returns>True if is static, otherwise false.</returns>
FORCE_INLINE bool IsStatic() FORCE_INLINE bool IsStatic()
{ {
return GetAddMethod()->IsStatic(); return GetAddMethod()->IsStatic();
} }
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Gets the Mono event handle. /// Gets the Mono event handle.
/// </summary> /// </summary>
/// <returns>The Mono event.</returns>
FORCE_INLINE MonoEvent* GetNative() const FORCE_INLINE MonoEvent* GetNative() const
{ {
return _monoEvent; return _monoEvent;
} }
#endif #endif
public: public:
@@ -124,11 +114,11 @@ public:
/// </summary> /// </summary>
/// <param name="monoClass">The attribute class to take.</param> /// <param name="monoClass">The attribute class to take.</param>
/// <returns>The attribute object.</returns> /// <returns>The attribute object.</returns>
MonoObject* GetAttribute(MClass* monoClass) const; MObject* GetAttribute(MClass* monoClass) const;
/// <summary> /// <summary>
/// Returns an instance of all attributes connected with given event. Returns null if the event doesn't have any attributes. /// Returns an instance of all attributes connected with given event. Returns null if the event doesn't have any attributes.
/// </summary> /// </summary>
/// <returns>The array of attribute objects.</returns> /// <returns>The array of attribute objects.</returns>
const Array<MonoObject*>& GetAttributes(); const Array<MObject*>& GetAttributes();
}; };

View File

@@ -1,11 +1,9 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MField.h" #include "MField.h"
#if USE_MONO
#include "MType.h" #include "MType.h"
#include "MClass.h" #include "MClass.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h> #include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h>
@@ -48,33 +46,52 @@ MField::MField(MonoClassField* monoField, const char* name, MClass* parentClass)
_isStatic = (flags & MONO_FIELD_ATTR_STATIC) != 0; _isStatic = (flags & MONO_FIELD_ATTR_STATIC) != 0;
} }
#endif
MType MField::GetType() const MType MField::GetType() const
{ {
#if USE_MONO
return MType(_monoType); return MType(_monoType);
#else
return MType();
#endif
} }
int32 MField::GetOffset() const int32 MField::GetOffset() const
{ {
#if USE_MONO
return mono_field_get_offset(_monoField) - sizeof(MonoObject); return mono_field_get_offset(_monoField) - sizeof(MonoObject);
#else
return 0;
#endif
} }
void MField::GetValue(MonoObject* instance, void* result) const void MField::GetValue(MObject* instance, void* result) const
{ {
#if USE_MONO
mono_field_get_value(instance, _monoField, result); mono_field_get_value(instance, _monoField, result);
#endif
} }
MonoObject* MField::GetValueBoxed(MonoObject* instance) const MObject* MField::GetValueBoxed(MObject* instance) const
{ {
#if USE_MONO
return mono_field_get_value_object(mono_domain_get(), _monoField, instance); return mono_field_get_value_object(mono_domain_get(), _monoField, instance);
#else
return nullptr;
#endif
} }
void MField::SetValue(MonoObject* instance, void* value) const void MField::SetValue(MObject* instance, void* value) const
{ {
#if USE_MONO
mono_field_set_value(instance, _monoField, value); mono_field_set_value(instance, _monoField, value);
#endif
} }
bool MField::HasAttribute(MClass* monoClass) const bool MField::HasAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField); MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -83,10 +100,14 @@ bool MField::HasAttribute(MClass* monoClass) const
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0; const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return hasAttr; return hasAttr;
#else
return false;
#endif
} }
bool MField::HasAttribute() const bool MField::HasAttribute() const
{ {
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField); MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -98,11 +119,13 @@ bool MField::HasAttribute() const
return true; return true;
} }
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return false; return false;
} }
MonoObject* MField::GetAttribute(MClass* monoClass) const MObject* MField::GetAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField); MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -111,14 +134,18 @@ MonoObject* MField::GetAttribute(MClass* monoClass) const
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()); MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return foundAttr; return foundAttr;
#else
return nullptr;
#endif
} }
const Array<MonoObject*>& MField::GetAttributes() const Array<MObject*>& MField::GetAttributes()
{ {
if (_hasCachedAttributes) if (_hasCachedAttributes)
return _attributes; return _attributes;
_hasCachedAttributes = true; _hasCachedAttributes = true;
#if USE_MONO
MonoClass* parentClass = mono_field_get_parent(_monoField); MonoClass* parentClass = mono_field_get_parent(_monoField);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -130,7 +157,6 @@ const Array<MonoObject*>& MField::GetAttributes()
for (uint32 i = 0; i < length; i++) for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i); _attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return _attributes; return _attributes;
} }
#endif

View File

@@ -20,15 +20,15 @@ protected:
#endif #endif
MClass* _parentClass; MClass* _parentClass;
MString _name; MString _name;
MVisibility _visibility;
Array<MonoObject*> _attributes; MVisibility _visibility;
int32 _hasCachedAttributes : 1; int32 _hasCachedAttributes : 1;
int32 _isStatic : 1; int32 _isStatic : 1;
Array<MObject*> _attributes;
public: public:
#if USE_MONO #if USE_MONO
@@ -40,7 +40,6 @@ public:
/// <summary> /// <summary>
/// Gets field name. /// Gets field name.
/// </summary> /// </summary>
/// <returns>The field name.</returns>
FORCE_INLINE const MString& GetName() const FORCE_INLINE const MString& GetName() const
{ {
return _name; return _name;
@@ -49,7 +48,6 @@ public:
/// <summary> /// <summary>
/// Returns the parent class that this method is contained with. /// Returns the parent class that this method is contained with.
/// </summary> /// </summary>
/// <returns>The parent class.</returns>
FORCE_INLINE MClass* GetParentClass() const FORCE_INLINE MClass* GetParentClass() const
{ {
return _parentClass; return _parentClass;
@@ -58,19 +56,16 @@ public:
/// <summary> /// <summary>
/// Gets field type class. /// Gets field type class.
/// </summary> /// </summary>
/// <returns>The field type.</returns>
MType GetType() const; MType GetType() const;
/// <summary> /// <summary>
/// Gets the field offset (in bytes) from the start of the parent object. /// Gets the field offset (in bytes) from the start of the parent object.
/// </summary> /// </summary>
/// <returns>The field offset in bytes.</returns>
int32 GetOffset() const; int32 GetOffset() const;
/// <summary> /// <summary>
/// Gets field visibility in the class. /// Gets field visibility in the class.
/// </summary> /// </summary>
/// <returns>The field visibility.</returns>
FORCE_INLINE MVisibility GetVisibility() const FORCE_INLINE MVisibility GetVisibility() const
{ {
return _visibility; return _visibility;
@@ -79,23 +74,19 @@ public:
/// <summary> /// <summary>
/// Returns true if field is static. /// Returns true if field is static.
/// </summary> /// </summary>
/// <returns>True if is static, otherwise false.</returns>
FORCE_INLINE bool IsStatic() const FORCE_INLINE bool IsStatic() const
{ {
return _isStatic != 0; return _isStatic != 0;
} }
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Gets mono field handle. /// Gets mono field handle.
/// </summary> /// </summary>
/// <returns>The Mono field object.</returns>
FORCE_INLINE MonoClassField* GetNative() const FORCE_INLINE MonoClassField* GetNative() const
{ {
return _monoField; return _monoField;
} }
#endif #endif
public: public:
@@ -104,28 +95,28 @@ public:
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. /// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Value will be a pointer to raw data type for value types (for example int, float), and a MonoObject* for reference types. /// Value will be a pointer to raw data type for value types (for example int, float), and a MObject* for reference types.
/// </remarks> /// </remarks>
/// <param name="instance">The object of given type to get value from.</param> /// <param name="instance">The object of given type to get value from.</param>
/// <param name="result">The return value of undefined type.</param> /// <param name="result">The return value of undefined type.</param>
void GetValue(MonoObject* instance, void* result) const; void GetValue(MObject* instance, void* result) const;
/// <summary> /// <summary>
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed. /// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed.
/// </summary> /// </summary>
/// <param name="instance">The object of given type to get value from.</param> /// <param name="instance">The object of given type to get value from.</param>
/// <returns>The boxed value object.</returns> /// <returns>The boxed value object.</returns>
MonoObject* GetValueBoxed(MonoObject* instance) const; MObject* GetValueBoxed(MObject* instance) const;
/// <summary> /// <summary>
/// Sets a value for the field on the specified object instance. If field is static object instance can be null. /// Sets a value for the field on the specified object instance. If field is static object instance can be null.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Value should be a pointer to raw data type for value types (for example int, float), and a MonoObject* for reference types. /// Value should be a pointer to raw data type for value types (for example int, float), and a MObject* for reference types.
/// </remarks> /// </remarks>
/// <param name="instance">The object of given type to set value to.</param> /// <param name="instance">The object of given type to set value to.</param>
/// <param name="value">Th value of undefined type.</param> /// <param name="value">Th value of undefined type.</param>
void SetValue(MonoObject* instance, void* value) const; void SetValue(MObject* instance, void* value) const;
public: public:
@@ -147,11 +138,11 @@ public:
/// </summary> /// </summary>
/// <param name="monoClass">The attribute class to take.</param> /// <param name="monoClass">The attribute class to take.</param>
/// <returns>The attribute object.</returns> /// <returns>The attribute object.</returns>
MonoObject* GetAttribute(MClass* monoClass) const; MObject* GetAttribute(MClass* monoClass) const;
/// <summary> /// <summary>
/// Returns an instance of all attributes connected with given field. Returns null if the field doesn't have any attributes. /// Returns an instance of all attributes connected with given field. Returns null if the field doesn't have any attributes.
/// </summary> /// </summary>
/// <returns>The array of attribute objects.</returns> /// <returns>The array of attribute objects.</returns>
const Array<MonoObject*>& GetAttributes(); const Array<MObject*>& GetAttributes();
}; };

View File

@@ -1,12 +1,10 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MMethod.h" #include "MMethod.h"
#if USE_MONO
#include "MType.h" #include "MType.h"
#include "MClass.h" #include "MClass.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h> #include <ThirdParty/mono-2.0/mono/metadata/attrdefs.h>
@@ -68,17 +66,27 @@ MMethod::MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass)
#endif #endif
} }
MonoObject* MMethod::Invoke(void* instance, void** params, MonoObject** exception) const #endif
MObject* MMethod::Invoke(void* instance, void** params, MObject** exception) const
{ {
#if USE_MONO
PROFILE_CPU_SRC_LOC(ProfilerData); PROFILE_CPU_SRC_LOC(ProfilerData);
return mono_runtime_invoke(_monoMethod, instance, params, exception); return mono_runtime_invoke(_monoMethod, instance, params, exception);
#else
return nullptr;
#endif
} }
MonoObject* MMethod::InvokeVirtual(MonoObject* instance, void** params, MonoObject** exception) const MObject* MMethod::InvokeVirtual(MObject* instance, void** params, MObject** exception) const
{ {
#if USE_MONO
PROFILE_CPU_SRC_LOC(ProfilerData); PROFILE_CPU_SRC_LOC(ProfilerData);
MonoMethod* virtualMethod = mono_object_get_virtual_method(instance, _monoMethod); MonoMethod* virtualMethod = mono_object_get_virtual_method(instance, _monoMethod);
return mono_runtime_invoke(virtualMethod, instance, params, exception); return mono_runtime_invoke(virtualMethod, instance, params, exception);
#else
return nullptr;
#endif
} }
#if !USE_MONO_AOT #if !USE_MONO_AOT
@@ -87,7 +95,9 @@ void* MMethod::GetThunk()
{ {
if (!_cachedThunk) if (!_cachedThunk)
{ {
#if USE_MONO
_cachedThunk = mono_method_get_unmanaged_thunk(_monoMethod); _cachedThunk = mono_method_get_unmanaged_thunk(_monoMethod);
#endif
} }
return _cachedThunk; return _cachedThunk;
} }
@@ -96,35 +106,52 @@ void* MMethod::GetThunk()
MType MMethod::GetReturnType() const MType MMethod::GetReturnType() const
{ {
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod); MonoMethodSignature* sig = mono_method_signature(_monoMethod);
MonoType* returnType = mono_signature_get_return_type(sig); MonoType* returnType = mono_signature_get_return_type(sig);
return MType(returnType); return MType(returnType);
#else
return MType();
#endif
} }
int32 MMethod::GetParametersCount() const int32 MMethod::GetParametersCount() const
{ {
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod); MonoMethodSignature* sig = mono_method_signature(_monoMethod);
return mono_signature_get_param_count(sig); return mono_signature_get_param_count(sig);
#else
return 0;
#endif
} }
MType MMethod::GetParameterType(int32 paramIdx) const MType MMethod::GetParameterType(int32 paramIdx) const
{ {
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod); MonoMethodSignature* sig = mono_method_signature(_monoMethod);
ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig)); ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig));
void* it = nullptr; void* it = nullptr;
mono_signature_get_params(sig, &it); mono_signature_get_params(sig, &it);
return MType(((MonoType**)it)[paramIdx]); return MType(((MonoType**)it)[paramIdx]);
#else
return MType();
#endif
} }
bool MMethod::GetParameterIsOut(int32 paramIdx) const bool MMethod::GetParameterIsOut(int32 paramIdx) const
{ {
#if USE_MONO
MonoMethodSignature* sig = mono_method_signature(_monoMethod); MonoMethodSignature* sig = mono_method_signature(_monoMethod);
ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig)); ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig));
return mono_signature_param_is_out(sig, paramIdx) != 0; return mono_signature_param_is_out(sig, paramIdx) != 0;
#else
return false;
#endif
} }
bool MMethod::HasAttribute(MClass* monoClass) const bool MMethod::HasAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr) if (attrInfo == nullptr)
return false; return false;
@@ -132,10 +159,14 @@ bool MMethod::HasAttribute(MClass* monoClass) const
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0; const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return hasAttr; return hasAttr;
#else
return false;
#endif
} }
bool MMethod::HasAttribute() const bool MMethod::HasAttribute() const
{ {
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr) if (attrInfo == nullptr)
return false; return false;
@@ -146,11 +177,13 @@ bool MMethod::HasAttribute() const
return true; return true;
} }
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return false; return false;
} }
MonoObject* MMethod::GetAttribute(MClass* monoClass) const MObject* MMethod::GetAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr) if (attrInfo == nullptr)
return nullptr; return nullptr;
@@ -158,14 +191,18 @@ MonoObject* MMethod::GetAttribute(MClass* monoClass) const
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()); MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return foundAttr; return foundAttr;
#else
return false;
#endif
} }
const Array<MonoObject*>& MMethod::GetAttributes() const Array<MObject*>& MMethod::GetAttributes()
{ {
if (_hasCachedAttributes) if (_hasCachedAttributes)
return _attributes; return _attributes;
_hasCachedAttributes = true; _hasCachedAttributes = true;
#if USE_MONO
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
if (attrInfo == nullptr) if (attrInfo == nullptr)
return _attributes; return _attributes;
@@ -176,7 +213,6 @@ const Array<MonoObject*>& MMethod::GetAttributes()
for (uint32 i = 0; i < length; i++) for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i); _attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return _attributes; return _attributes;
} }
#endif

View File

@@ -29,11 +29,11 @@ protected:
void* _cachedThunk = nullptr; void* _cachedThunk = nullptr;
#endif #endif
Array<MonoObject*> _attributes;
int32 _hasCachedAttributes : 1; int32 _hasCachedAttributes : 1;
int32 _isStatic : 1; int32 _isStatic : 1;
Array<MObject*> _attributes;
public: public:
#if USE_MONO #if USE_MONO
@@ -48,8 +48,6 @@ public:
SourceLocationData ProfilerData; SourceLocationData ProfilerData;
#endif #endif
#if USE_MONO
/// <summary> /// <summary>
/// Invokes the method on the provided object instance. This does not respect polymorphism and will invoke the exact method of the class this object was retrieved from.Use invokeVirtual() if you need polymorphism. /// Invokes the method on the provided object instance. This does not respect polymorphism and will invoke the exact method of the class this object was retrieved from.Use invokeVirtual() if you need polymorphism.
/// </summary> /// </summary>
@@ -59,10 +57,10 @@ public:
/// <param name="instance">Instance of the object to invoke the method on. Can be null for static methods.</param> /// <param name="instance">Instance of the object to invoke the method on. Can be null for static methods.</param>
/// <param name="params">Array of parameters to pass to the method. Caller must ensure they match method /// <param name="params">Array of parameters to pass to the method. Caller must ensure they match method
/// parameter count and type.For value types parameters should be pointers to the /// parameter count and type.For value types parameters should be pointers to the
/// values and for reference types they should be pointers to MonoObject.</param> /// values and for reference types they should be pointers to MObject.</param>
/// <param name="exception">An optional pointer to the exception value to store exception object reference.</param> /// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
/// <returns>A boxed return value, or null if method has no return value.</returns> /// <returns>A boxed return value, or null if method has no return value.</returns>
MonoObject* Invoke(void* instance, void** params, MonoObject** exception) const; MObject* Invoke(void* instance, void** params, MObject** exception) const;
/// <summary> /// <summary>
/// Invokes the method on the provided object instance. If the instance has an override of this method it will be called. /// Invokes the method on the provided object instance. If the instance has an override of this method it will be called.
@@ -74,16 +72,13 @@ public:
/// <param name="params"> /// <param name="params">
/// Array of parameters to pass to the method. Caller must ensure they match method /// Array of parameters to pass to the method. Caller must ensure they match method
/// parameter count and type. For value types parameters should be pointers to the /// parameter count and type. For value types parameters should be pointers to the
/// values and for reference types they should be pointers to MonoObject. /// values and for reference types they should be pointers to MObject.
/// </param> /// </param>
/// <param name="exception">An optional pointer to the exception value to store exception object reference.</param> /// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
/// <returns>A boxed return value, or null if method has no return value.</returns> /// <returns>A boxed return value, or null if method has no return value.</returns>
MonoObject* InvokeVirtual(MonoObject* instance, void** params, MonoObject** exception) const; MObject* InvokeVirtual(MObject* instance, void** params, MObject** exception) const;
#endif
#if !USE_MONO_AOT #if !USE_MONO_AOT
/// <summary> /// <summary>
/// Gets a thunk for this method. A thunk is a C++ like function pointer that you can use for calling the method. /// Gets a thunk for this method. A thunk is a C++ like function pointer that you can use for calling the method.
/// </summary> /// </summary>
@@ -93,7 +88,6 @@ public:
/// </remarks> /// </remarks>
/// <returns>The method thunk pointer.</returns> /// <returns>The method thunk pointer.</returns>
void* GetThunk(); void* GetThunk();
#endif #endif
/// <summary> /// <summary>
@@ -153,7 +147,6 @@ public:
} }
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Gets the Mono method handle. /// Gets the Mono method handle.
/// </summary> /// </summary>
@@ -161,7 +154,6 @@ public:
{ {
return _monoMethod; return _monoMethod;
} }
#endif #endif
public: public:
@@ -184,11 +176,11 @@ public:
/// </summary> /// </summary>
/// <param name="monoClass">The attribute Class to take.</param> /// <param name="monoClass">The attribute Class to take.</param>
/// <returns>The attribute object.</returns> /// <returns>The attribute object.</returns>
MonoObject* GetAttribute(MClass* monoClass) const; MObject* GetAttribute(MClass* monoClass) const;
/// <summary> /// <summary>
/// Returns an instance of all attributes connected with given method. Returns null if the method doesn't have any attributes. /// Returns an instance of all attributes connected with given method. Returns null if the method doesn't have any attributes.
/// </summary> /// </summary>
/// <returns>The array of attribute objects.</returns> /// <returns>The array of attribute objects.</returns>
const Array<MonoObject*>& GetAttributes(); const Array<MObject*>& GetAttributes();
}; };

View File

@@ -1,13 +1,11 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "MProperty.h" #include "MProperty.h"
#if USE_MONO
#include "Engine/Core/Math/Math.h" #include "Engine/Core/Math/Math.h"
#include "MMethod.h" #include "MMethod.h"
#include "MClass.h" #include "MClass.h"
#include "MType.h" #include "MType.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass) MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass)
@@ -29,6 +27,8 @@ MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* paren
GetSetMethod(); GetSetMethod();
} }
#endif
MProperty::~MProperty() MProperty::~MProperty()
{ {
if (_getMethod) if (_getMethod)
@@ -48,18 +48,17 @@ MMethod* MProperty::GetGetMethod()
{ {
if (!_hasGetMethod) if (!_hasGetMethod)
return nullptr; return nullptr;
if (_getMethod == nullptr) if (_getMethod == nullptr)
{ {
#if USE_MONO
auto method = mono_property_get_get_method(_monoProperty); auto method = mono_property_get_get_method(_monoProperty);
if (method != nullptr) if (method != nullptr)
{ {
_hasGetMethod = true; _hasGetMethod = true;
return _getMethod = New<MMethod>(method, _parentClass); return _getMethod = New<MMethod>(method, _parentClass);
} }
return nullptr; #endif
} }
return _getMethod; return _getMethod;
} }
@@ -67,18 +66,17 @@ MMethod* MProperty::GetSetMethod()
{ {
if (!_hasSetMethod) if (!_hasSetMethod)
return nullptr; return nullptr;
if (_setMethod == nullptr) if (_setMethod == nullptr)
{ {
#if USE_MONO
auto method = mono_property_get_set_method(_monoProperty); auto method = mono_property_get_set_method(_monoProperty);
if (method != nullptr) if (method != nullptr)
{ {
_hasSetMethod = true; _hasSetMethod = true;
return _setMethod = New<MMethod>(method, _parentClass); return _setMethod = New<MMethod>(method, _parentClass);
} }
return nullptr; #endif
} }
return _setMethod; return _setMethod;
} }
@@ -112,20 +110,27 @@ bool MProperty::IsStatic()
return false; return false;
} }
MonoObject* MProperty::GetValue(MonoObject* instance, MonoObject** exception) MObject* MProperty::GetValue(MObject* instance, MObject** exception)
{ {
#if USE_MONO
return mono_property_get_value(_monoProperty, instance, nullptr, exception); return mono_property_get_value(_monoProperty, instance, nullptr, exception);
#else
return nullptr;
#endif
} }
void MProperty::SetValue(MonoObject* instance, void* value, MonoObject** exception) void MProperty::SetValue(MObject* instance, void* value, MObject** exception)
{ {
#if USE_MONO
void* params[1]; void* params[1];
params[0] = value; params[0] = value;
mono_property_set_value(_monoProperty, instance, params, exception); mono_property_set_value(_monoProperty, instance, params, exception);
#endif
} }
bool MProperty::HasAttribute(MClass* monoClass) const bool MProperty::HasAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty); MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -134,10 +139,14 @@ bool MProperty::HasAttribute(MClass* monoClass) const
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0; const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return hasAttr; return hasAttr;
#else
return false;
#endif
} }
bool MProperty::HasAttribute() const bool MProperty::HasAttribute() const
{ {
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty); MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -150,10 +159,14 @@ bool MProperty::HasAttribute() const
} }
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return false; return false;
#else
return false;
#endif
} }
MonoObject* MProperty::GetAttribute(MClass* monoClass) const MObject* MProperty::GetAttribute(MClass* monoClass) const
{ {
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty); MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -162,14 +175,18 @@ MonoObject* MProperty::GetAttribute(MClass* monoClass) const
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative()); MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
return foundAttr; return foundAttr;
#else
return nullptr;
#endif
} }
const Array<MonoObject*>& MProperty::GetAttributes() const Array<MObject*>& MProperty::GetAttributes()
{ {
if (_hasCachedAttributes) if (_hasCachedAttributes)
return _attributes; return _attributes;
_hasCachedAttributes = true; _hasCachedAttributes = true;
#if USE_MONO
MonoClass* parentClass = mono_property_get_parent(_monoProperty); MonoClass* parentClass = mono_property_get_parent(_monoProperty);
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty); MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
if (attrInfo == nullptr) if (attrInfo == nullptr)
@@ -179,9 +196,8 @@ const Array<MonoObject*>& MProperty::GetAttributes()
const auto length = (uint32)mono_array_length(monoAttributesArray); const auto length = (uint32)mono_array_length(monoAttributesArray);
_attributes.Resize(length); _attributes.Resize(length);
for (uint32 i = 0; i < length; i++) for (uint32 i = 0; i < length; i++)
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i); _attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
mono_custom_attrs_free(attrInfo); mono_custom_attrs_free(attrInfo);
#endif
return _attributes; return _attributes;
} }
#endif

View File

@@ -25,12 +25,12 @@ protected:
MString _name; MString _name;
Array<MonoObject*> _attributes;
int32 _hasCachedAttributes : 1; int32 _hasCachedAttributes : 1;
int32 _hasSetMethod : 1; int32 _hasSetMethod : 1;
int32 _hasGetMethod : 1; int32 _hasGetMethod : 1;
Array<MObject*> _attributes;
public: public:
#if USE_MONO #if USE_MONO
@@ -47,7 +47,6 @@ public:
/// <summary> /// <summary>
/// Gets the property name. /// Gets the property name.
/// </summary> /// </summary>
/// <returns>The property name.</returns>
FORCE_INLINE const MString& GetName() const FORCE_INLINE const MString& GetName() const
{ {
return _name; return _name;
@@ -56,7 +55,6 @@ public:
/// <summary> /// <summary>
/// Returns the parent class that this method is contained with. /// Returns the parent class that this method is contained with.
/// </summary> /// </summary>
/// <returns>The parent class.</returns>
FORCE_INLINE MClass* GetParentClass() const FORCE_INLINE MClass* GetParentClass() const
{ {
return _parentClass; return _parentClass;
@@ -65,31 +63,26 @@ public:
/// <summary> /// <summary>
/// Gets property type class. /// Gets property type class.
/// </summary> /// </summary>
/// <returns>The property type.</returns>
MType GetType(); MType GetType();
/// <summary> /// <summary>
/// Gets property get method. /// Gets property get method.
/// </summary> /// </summary>
/// <returns>The getter method.</returns>
MMethod* GetGetMethod(); MMethod* GetGetMethod();
/// <summary> /// <summary>
/// Gets property set method. /// Gets property set method.
/// </summary> /// </summary>
/// <returns>The setter method.</returns>
MMethod* GetSetMethod(); MMethod* GetSetMethod();
/// <summary> /// <summary>
/// Gets property visibility in the class. /// Gets property visibility in the class.
/// </summary> /// </summary>
/// <returns>The property visibility.</returns>
MVisibility GetVisibility(); MVisibility GetVisibility();
/// <summary> /// <summary>
/// Returns true if property is static. /// Returns true if property is static.
/// </summary> /// </summary>
/// <returns>True if is static, otherwise false.</returns>
bool IsStatic(); bool IsStatic();
public: public:
@@ -98,23 +91,24 @@ public:
/// Retrieves value currently set in the property on the specified object instance. If property is static object instance can be null. /// Retrieves value currently set in the property on the specified object instance. If property is static object instance can be null.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Value will be a pointer to raw data type for value types (for example int, float), and a MonoObject* for reference types. /// Value will be a pointer to raw data type for value types (for example int, float), and a MObject* for reference types.
/// </remarks> /// </remarks>
/// <param name="instance">The object of given type to get value from.</param> /// <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> /// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
/// <returns>The returned boxed value object.</returns> /// <returns>The returned boxed value object.</returns>
MonoObject* GetValue(MonoObject* instance, MonoObject** exception); MObject* GetValue(MObject* instance, MObject** exception);
/// <summary> /// <summary>
/// Sets a value for the property on the specified object instance. If property is static object instance can be null. /// Sets a value for the property on the specified object instance. If property is static object instance can be null.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Value should be a pointer to raw data type for value types (for example int, float), and a MonoObject* for reference types. /// Value should be a pointer to raw data type for value types (for example int, float), and a MObject* for reference types.
/// </remarks> /// </remarks>
/// <param name="instance">Object of given type to set value to.</param> /// <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="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> /// <param name="value">The value to set of undefined type.</param>
void SetValue(MonoObject* instance, void* value, MonoObject** exception); void SetValue(MObject* instance, void* value, MObject** exception);
public: public:
@@ -136,11 +130,11 @@ public:
/// </summary> /// </summary>
/// <param name="monoClass">The attribute class to take.</param> /// <param name="monoClass">The attribute class to take.</param>
/// <returns>The attribute object.</returns> /// <returns>The attribute object.</returns>
MonoObject* GetAttribute(MClass* monoClass) const; MObject* GetAttribute(MClass* monoClass) const;
/// <summary> /// <summary>
/// Returns an instance of all attributes connected with given property. Returns null if the property doesn't have any attributes. /// Returns an instance of all attributes connected with given property. Returns null if the property doesn't have any attributes.
/// </summary> /// </summary>
/// <returns>The array of attribute objects.</returns> /// <returns>The array of attribute objects.</returns>
const Array<MonoObject*>& GetAttributes(); const Array<MObject*>& GetAttributes();
}; };

View File

@@ -3,7 +3,9 @@
#pragma once #pragma once
#include "Engine/Core/Types/String.h" #include "Engine/Core/Types/String.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#endif
/// <summary> /// <summary>
/// Class for converting mono classes and methods into usable form without instancing a class. /// Class for converting mono classes and methods into usable form without instancing a class.
@@ -13,6 +15,7 @@ class MStaticConverter
{ {
public: public:
#if USE_MONO
static MonoClass* GetMonoClassFromObject(MonoObject* monoObject) static MonoClass* GetMonoClassFromObject(MonoObject* monoObject)
{ {
ASSERT(monoObject); ASSERT(monoObject);
@@ -63,4 +66,5 @@ public:
} }
return array; return array;
} }
#endif
}; };

View File

@@ -2,9 +2,7 @@
#include "MType.h" #include "MType.h"
#include "MUtils.h" #include "MUtils.h"
#if USE_MONO #if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
String MType::ToString() const String MType::ToString() const
@@ -42,4 +40,11 @@ bool MType::IsByRef() const
return mono_type_is_byref(_monoType) != 0; return mono_type_is_byref(_monoType) != 0;
} }
#else
String MType::ToString() const
{
return String::Empty;
}
#endif #endif

View File

@@ -5,14 +5,13 @@
#include "MTypes.h" #include "MTypes.h"
/// <summary> /// <summary>
/// Contains information about managed type /// Contains information about managed type.
/// </summary> /// </summary>
class MType class MType
{ {
public: public:
#if USE_MONO #if USE_MONO
MonoType* _monoType; MonoType* _monoType;
/// <summary> /// <summary>
@@ -31,7 +30,6 @@ public:
: _monoType(nullptr) : _monoType(nullptr)
{ {
} }
#endif #endif
/// <summary> /// <summary>
@@ -46,11 +44,9 @@ public:
String ToString() const; String ToString() const;
#if USE_MONO #if USE_MONO
/// <summary> /// <summary>
/// Gets mono type handle /// Gets mono type handle
/// </summary> /// </summary>
/// <returns>Mono type</returns>
MonoType* GetNative() const MonoType* GetNative() const
{ {
return _monoType; return _monoType;
@@ -78,6 +74,5 @@ public:
{ {
return _monoType != nullptr; return _monoType != nullptr;
} }
#endif #endif
}; };

View File

@@ -2,63 +2,15 @@
#pragma once #pragma once
#include "../Types.h"
#include "Engine/Core/Types/String.h" #include "Engine/Core/Types/String.h"
#include "Engine/Core/Types/StringView.h" #include "Engine/Core/Types/StringView.h"
// Enable/disable mono debugging
#define MONO_DEBUG_ENABLE (!BUILD_RELEASE)
#define USE_MONO (1)
#define USE_NETCORE (0)
#ifndef USE_MONO_AOT
#define USE_MONO_AOT 0
#define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE
#endif
// Enables/disables profiling managed world via Mono
#define USE_MONO_PROFILER (COMPILE_WITH_PROFILER)
// Enables using single (root) app domain for the user scripts
#define USE_SINGLE_DOMAIN 1
#if USE_MONO
/// <summary> /// <summary>
/// String container for names and typenames used by the managed runtime backend. /// String container for names and typenames used by the managed runtime backend (8-bit chars).
/// </summary> /// </summary>
typedef StringAnsi MString; typedef StringAnsi MString;
// Mono types declarations
typedef struct _MonoClass MonoClass;
typedef struct _MonoDomain MonoDomain;
typedef struct _MonoImage MonoImage;
typedef struct _MonoAssembly MonoAssembly;
typedef struct _MonoMethod MonoMethod;
typedef struct _MonoProperty MonoProperty;
typedef struct _MonoObject MonoObject;
typedef struct _MonoEvent MonoEvent;
typedef struct _MonoType MonoType;
typedef struct _MonoString MonoString;
typedef struct _MonoArray MonoArray;
typedef struct _MonoReflectionType MonoReflectionType;
typedef struct _MonoReflectionAssembly MonoReflectionAssembly;
typedef struct _MonoException MonoException;
typedef struct _MonoClassField MonoClassField;
typedef MonoObject MObject;
#endif
// Forward declarations
class MCore;
class MAssembly;
class MClass;
class MField;
class MMethod;
class MProperty;
class MEvent;
class MDomain;
class MType;
enum class MVisibility enum class MVisibility
{ {
Private, Private,

View File

@@ -22,6 +22,8 @@
#include "Engine/Utilities/StringConverter.h" #include "Engine/Utilities/StringConverter.h"
#include "Engine/Content/Asset.h" #include "Engine/Content/Asset.h"
#if USE_MONO
struct _MonoType struct _MonoType
{ {
union union
@@ -846,3 +848,5 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
failed = true; failed = true;
return nullptr; return nullptr;
} }
#endif

View File

@@ -8,6 +8,9 @@
#include "Engine/Core/Types/Variant.h" #include "Engine/Core/Types/Variant.h"
#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Array.h"
#include "Engine/Scripting/ScriptingObject.h" #include "Engine/Scripting/ScriptingObject.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
@@ -498,3 +501,5 @@ namespace MUtils
extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed); extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed);
}; };
#endif

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "ManagedSerialization.h" #include "ManagedSerialization.h"
#if USE_MONO
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
#include "Engine/Serialization/Json.h" #include "Engine/Serialization/Json.h"
#include "Engine/Serialization/JsonWriter.h" #include "Engine/Serialization/JsonWriter.h"
@@ -26,7 +27,7 @@ void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, Mon
params[1] = &isManagedOnly; params[1] = &isManagedOnly;
// Call serialization tool // Call serialization tool
MonoObject* exception = nullptr; MObject* exception = nullptr;
// TODO: use method thunk // TODO: use method thunk
auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_Serialize->Invoke(nullptr, params, &exception); auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_Serialize->Invoke(nullptr, params, &exception);
if (exception) if (exception)
@@ -64,7 +65,7 @@ void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream,
params[2] = &isManagedOnly; params[2] = &isManagedOnly;
// Call serialization tool // Call serialization tool
MonoObject* exception = nullptr; MObject* exception = nullptr;
// TODO: use method thunk // TODO: use method thunk
auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_SerializeDiff->Invoke(nullptr, params, &exception); auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_SerializeDiff->Invoke(nullptr, params, &exception);
if (exception) if (exception)
@@ -115,7 +116,7 @@ void ManagedSerialization::Deserialize(const StringAnsiView& data, MonoObject* o
args[2] = (void*)&len; args[2] = (void*)&len;
// Call serialization tool // Call serialization tool
MonoObject* exception = nullptr; MObject* exception = nullptr;
// TODO: use method thunk // TODO: use method thunk
StdTypesContainer::Instance()->Json_Deserialize->Invoke(nullptr, args, &exception); StdTypesContainer::Instance()->Json_Deserialize->Invoke(nullptr, args, &exception);
if (exception) if (exception)
@@ -124,3 +125,5 @@ void ManagedSerialization::Deserialize(const StringAnsiView& data, MonoObject* o
ex.Log(LogType::Error, TEXT("ManagedSerialization::Deserialize")); ex.Log(LogType::Error, TEXT("ManagedSerialization::Deserialize"));
} }
} }
#endif

View File

@@ -12,6 +12,7 @@ class FLAXENGINE_API ManagedSerialization
{ {
public: public:
#if USE_MONO
/// <summary> /// <summary>
/// Serializes managed object to JSON. /// Serializes managed object to JSON.
/// </summary> /// </summary>
@@ -40,4 +41,5 @@ public:
/// <param name="data">The input data.</param> /// <param name="data">The input data.</param>
/// <param name="object">The object to deserialize.</param> /// <param name="object">The object to deserialize.</param>
static void Deserialize(const StringAnsiView& data, MonoObject* object); static void Deserialize(const StringAnsiView& data, MonoObject* object);
#endif
}; };

View File

@@ -44,13 +44,14 @@ PluginManagerService PluginManagerServiceInstance;
void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor) void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor)
{ {
#if !COMPILE_WITHOUT_CSHARP
if (Internal_LoadPlugin == nullptr) if (Internal_LoadPlugin == nullptr)
{ {
Internal_LoadPlugin = PluginManager::GetStaticClass()->GetMethod("Internal_LoadPlugin", 2); Internal_LoadPlugin = PluginManager::GetStaticClass()->GetMethod("Internal_LoadPlugin", 2);
ASSERT(Internal_LoadPlugin); ASSERT(Internal_LoadPlugin);
} }
MonoObject* exception = nullptr; MObject* exception = nullptr;
void* params[2]; void* params[2];
params[0] = MUtils::GetType(klass->GetNative()); params[0] = MUtils::GetType(klass->GetNative());
params[1] = &isEditor; params[1] = &isEditor;
@@ -59,6 +60,7 @@ void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor)
{ {
DebugLog::LogException(exception); DebugLog::LogException(exception);
} }
#endif
} }
void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly) void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
@@ -113,10 +115,11 @@ void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly) void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly)
{ {
#if !COMPILE_WITHOUT_CSHARP
// Cleanup plugins from this assembly // Cleanup plugins from this assembly
const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose", 1); const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose", 1);
ASSERT(disposeMethod); ASSERT(disposeMethod);
MonoObject* exception = nullptr; MObject* exception = nullptr;
void* params[1]; void* params[1];
params[0] = assembly->GetNative(); params[0] = assembly->GetNative();
disposeMethod->Invoke(nullptr, params, &exception); disposeMethod->Invoke(nullptr, params, &exception);
@@ -124,6 +127,7 @@ void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly)
{ {
DebugLog::LogException(exception); DebugLog::LogException(exception);
} }
#endif
} }
void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module) void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module)
@@ -169,13 +173,15 @@ void PluginManagerService::Dispose()
PROFILE_CPU_NAMED("Dispose Plugins"); PROFILE_CPU_NAMED("Dispose Plugins");
#if !COMPILE_WITHOUT_CSHARP
// Cleanup all plugins // Cleanup all plugins
const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose"); const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose");
ASSERT(disposeMethod); ASSERT(disposeMethod);
MonoObject* exception = nullptr; MObject* exception = nullptr;
disposeMethod->Invoke(nullptr, nullptr, &exception); disposeMethod->Invoke(nullptr, nullptr, &exception);
if (exception) if (exception)
{ {
DebugLog::LogException(exception); DebugLog::LogException(exception);
} }
#endif
} }

View File

@@ -13,7 +13,11 @@ public class Scripting : EngineModule
{ {
base.Setup(options); base.Setup(options);
options.PublicDependencies.Add("mono"); if (EngineConfiguration.WithCSharp(options))
{
options.PublicDependencies.Add("mono");
}
options.PrivateDependencies.Add("Utilities"); options.PrivateDependencies.Add("Utilities");
} }
} }

View File

@@ -14,7 +14,11 @@
#endif #endif
#include "Engine/Core/Types/Pair.h" #include "Engine/Core/Types/Pair.h"
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
#endif
#if USE_MONO
namespace ProfilerInternal namespace ProfilerInternal
{ {
@@ -99,9 +103,12 @@ namespace ProfilerInternal
} }
} }
#endif
class ScriptingInternal class ScriptingInternal
{ {
public: public:
#if USE_MONO
static bool HasGameModulesLoaded() static bool HasGameModulesLoaded()
{ {
return Scripting::HasGameModulesLoaded(); return Scripting::HasGameModulesLoaded();
@@ -117,9 +124,11 @@ public:
ASSERT(IsInMainThread()); ASSERT(IsInMainThread());
ObjectsRemovalService::Flush(); ObjectsRemovalService::Flush();
} }
#endif
static void InitRuntime() static void InitRuntime()
{ {
#if USE_MONO
// Scripting API // Scripting API
ADD_INTERNAL_CALL("FlaxEngine.Scripting::HasGameModulesLoaded", &HasGameModulesLoaded); ADD_INTERNAL_CALL("FlaxEngine.Scripting::HasGameModulesLoaded", &HasGameModulesLoaded);
ADD_INTERNAL_CALL("FlaxEngine.Scripting::IsTypeFromGameScripts", &IsTypeFromGameScripts); ADD_INTERNAL_CALL("FlaxEngine.Scripting::IsTypeFromGameScripts", &IsTypeFromGameScripts);
@@ -130,6 +139,7 @@ public:
ADD_INTERNAL_CALL("FlaxEngine.Profiler::EndEvent", &ProfilerInternal::EndEvent); ADD_INTERNAL_CALL("FlaxEngine.Profiler::EndEvent", &ProfilerInternal::EndEvent);
ADD_INTERNAL_CALL("FlaxEngine.Profiler::BeginEventGPU", &ProfilerInternal::BeginEventGPU); ADD_INTERNAL_CALL("FlaxEngine.Profiler::BeginEventGPU", &ProfilerInternal::BeginEventGPU);
ADD_INTERNAL_CALL("FlaxEngine.Profiler::EndEventGPU", &ProfilerInternal::EndEventGPU); ADD_INTERNAL_CALL("FlaxEngine.Profiler::EndEventGPU", &ProfilerInternal::EndEventGPU);
#endif
} }
}; };

View File

@@ -30,8 +30,10 @@
#include "Engine/Engine/Globals.h" #include "Engine/Engine/Globals.h"
#include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/RenderTask.h"
#include "Engine/Serialization/JsonTools.h" #include "Engine/Serialization/JsonTools.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h> #include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#endif
extern void registerFlaxEngineInternalCalls(); extern void registerFlaxEngineInternalCalls();
@@ -55,8 +57,8 @@ public:
namespace namespace
{ {
MDomain* _monoRootDomain = nullptr; MDomain* _rootDomain = nullptr;
MDomain* _monoScriptsDomain = nullptr; MDomain* _scriptsDomain = nullptr;
CriticalSection _objectsLocker; CriticalSection _objectsLocker;
#define USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING 0 #define USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING 0
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING #if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
@@ -134,24 +136,24 @@ bool ScriptingService::Init()
engineAssembly->Unloading.Bind(onEngineUnloading); engineAssembly->Unloading.Bind(onEngineUnloading);
// Initialize managed runtime // Initialize managed runtime
if (MCore::Instance()->LoadEngine()) if (MCore::LoadEngine())
{ {
LOG(Fatal, "Mono initialization failed."); LOG(Fatal, "Mono initialization failed.");
return true; return true;
} }
// Cache root domain // Cache root domain
_monoRootDomain = MCore::Instance()->GetRootDomain(); _rootDomain = MCore::GetRootDomain();
#if USE_SINGLE_DOMAIN #if USE_SCRIPTING_SINGLE_DOMAIN
// Use single root domain // Use single root domain
auto domain = _monoRootDomain; auto domain = _rootDomain;
#else #else
// Create Mono domain for scripts // Create Mono domain for scripts
auto domain = MCore::Instance()->CreateDomain(TEXT("Scripts Domain")); auto domain = MCore::CreateDomain("Scripts Domain");
#endif #endif
domain->SetCurrentDomain(true); domain->SetCurrentDomain(true);
_monoScriptsDomain = domain; _scriptsDomain = domain;
// Add internal calls // Add internal calls
registerFlaxEngineInternalCalls(); registerFlaxEngineInternalCalls();
@@ -169,6 +171,9 @@ bool ScriptingService::Init()
return false; return false;
} }
#if COMPILE_WITHOUT_CSHARP
#define INVOKE_EVENT(name)
#else
#define INVOKE_EVENT(name) \ #define INVOKE_EVENT(name) \
if (!_isEngineAssemblyLoaded) return; \ if (!_isEngineAssemblyLoaded) return; \
if (_method_##name == nullptr) \ if (_method_##name == nullptr) \
@@ -186,9 +191,10 @@ bool ScriptingService::Init()
return; \ return; \
} \ } \
} \ } \
MonoObject* exception = nullptr; \ MObject* exception = nullptr; \
_method_##name->Invoke(nullptr, nullptr, &exception); \ _method_##name->Invoke(nullptr, nullptr, &exception); \
DebugLog::LogException(exception) DebugLog::LogException(exception)
#endif
void ScriptingService::Update() void ScriptingService::Update()
{ {
@@ -227,12 +233,12 @@ void ScriptingService::BeforeExit()
MDomain* Scripting::GetRootDomain() MDomain* Scripting::GetRootDomain()
{ {
return _monoRootDomain; return _rootDomain;
} }
MDomain* Scripting::GetScriptsDomain() MDomain* Scripting::GetScriptsDomain()
{ {
return _monoScriptsDomain; return _scriptsDomain;
} }
void Scripting::ProcessBuildInfoPath(String& path, const String& projectFolderPath) void Scripting::ProcessBuildInfoPath(String& path, const String& projectFolderPath)
@@ -276,10 +282,9 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
// Load all references // Load all references
auto referencesMember = document.FindMember("References"); auto referencesMember = document.FindMember("References");
if (referencesMember != document.MemberEnd()) if (referencesMember != document.MemberEnd() && referencesMember->value.IsArray())
{ {
auto& referencesArray = referencesMember->value; auto& referencesArray = referencesMember->value;
ASSERT(referencesArray.IsArray());
for (rapidjson::SizeType i = 0; i < referencesArray.Size(); i++) for (rapidjson::SizeType i = 0; i < referencesArray.Size(); i++)
{ {
auto& reference = referencesArray[i]; auto& reference = referencesArray[i];
@@ -308,10 +313,9 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
// Load all binary modules // Load all binary modules
auto binaryModulesMember = document.FindMember("BinaryModules"); auto binaryModulesMember = document.FindMember("BinaryModules");
if (binaryModulesMember != document.MemberEnd()) if (binaryModulesMember != document.MemberEnd() && binaryModulesMember->value.IsArray())
{ {
auto& binaryModulesArray = binaryModulesMember->value; auto& binaryModulesArray = binaryModulesMember->value;
ASSERT(binaryModulesArray.IsArray());
for (rapidjson::SizeType i = 0; i < binaryModulesArray.Size(); i++) for (rapidjson::SizeType i = 0; i < binaryModulesArray.Size(); i++)
{ {
auto& binaryModule = binaryModulesArray[i]; auto& binaryModule = binaryModulesArray[i];
@@ -396,6 +400,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
} }
} }
#if !COMPILE_WITHOUT_CSHARP
// C# // C#
if (managedPath.HasChars() && !((ManagedBinaryModule*)module)->Assembly->IsLoaded()) if (managedPath.HasChars() && !((ManagedBinaryModule*)module)->Assembly->IsLoaded())
{ {
@@ -405,6 +410,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
return true; return true;
} }
} }
#endif
BinaryModuleLoaded(module); BinaryModuleLoaded(module);
} }
@@ -419,12 +425,14 @@ bool Scripting::Load()
// Note: this action can be called from main thread (due to Mono problems with assemblies actions from other threads) // Note: this action can be called from main thread (due to Mono problems with assemblies actions from other threads)
ASSERT(IsInMainThread()); ASSERT(IsInMainThread());
#if !COMPILE_WITHOUT_CSHARP
// Load C# core assembly // Load C# core assembly
if (GetBinaryModuleCorlib()->Assembly->Load(mono_get_corlib())) if (GetBinaryModuleCorlib()->Assembly->Load(mono_get_corlib()))
{ {
LOG(Error, "Failed to load corlib C# assembly."); LOG(Error, "Failed to load corlib C# assembly.");
return true; return true;
} }
#endif
// Load FlaxEngine // Load FlaxEngine
const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll"); const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
@@ -539,7 +547,7 @@ void Scripting::Release()
ObjectsRemovalService::Flush(); ObjectsRemovalService::Flush();
// Switch domain // Switch domain
auto rootDomain = MCore::Instance()->GetRootDomain(); auto rootDomain = MCore::GetRootDomain();
if (rootDomain) if (rootDomain)
{ {
if (!rootDomain->SetCurrentDomain(false)) if (!rootDomain->SetCurrentDomain(false))
@@ -548,8 +556,8 @@ void Scripting::Release()
} }
} }
#if !USE_SINGLE_DOMAIN #if !USE_SCRIPTING_SINGLE_DOMAIN
MCore::Instance()->UnloadDomain("Scripts Domain"); MCore::UnloadDomain("Scripts Domain");
#endif #endif
} }
@@ -647,25 +655,6 @@ void Scripting::Reload(bool canTriggerSceneReload)
#endif #endif
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;
}
MClass* Scripting::FindClass(const StringAnsiView& fullname) MClass* Scripting::FindClass(const StringAnsiView& fullname)
{ {
if (fullname.IsEmpty()) if (fullname.IsEmpty())
@@ -685,6 +674,27 @@ MClass* Scripting::FindClass(const StringAnsiView& fullname)
return nullptr; 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) MonoClass* Scripting::FindClassNative(const StringAnsiView& fullname)
{ {
if (fullname.IsEmpty()) if (fullname.IsEmpty())
@@ -704,6 +714,8 @@ MonoClass* Scripting::FindClassNative(const StringAnsiView& fullname)
return nullptr; return nullptr;
} }
#endif
ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname) ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname)
{ {
if (fullname.IsEmpty()) if (fullname.IsEmpty())
@@ -816,7 +828,7 @@ ScriptingObject* Scripting::TryFindObject(Guid id, MClass* type)
return result; return result;
} }
ScriptingObject* Scripting::FindObject(const MonoObject* managedInstance) ScriptingObject* Scripting::FindObject(const MObject* managedInstance)
{ {
if (managedInstance == nullptr) if (managedInstance == nullptr)
return nullptr; return nullptr;
@@ -938,13 +950,14 @@ bool initFlaxEngine()
if (StdTypesContainer::Instance()->Gather()) if (StdTypesContainer::Instance()->Gather())
return true; return true;
#if !COMPILE_WITHOUT_CSHARP
// Init C# class library // Init C# class library
{ {
auto scriptingClass = Scripting::GetStaticClass(); auto scriptingClass = Scripting::GetStaticClass();
ASSERT(scriptingClass); ASSERT(scriptingClass);
const auto initMethod = scriptingClass->GetMethod("Init"); const auto initMethod = scriptingClass->GetMethod("Init");
ASSERT(initMethod); ASSERT(initMethod);
MonoObject* exception = nullptr; MObject* exception = nullptr;
initMethod->Invoke(nullptr, nullptr, &exception); initMethod->Invoke(nullptr, nullptr, &exception);
if (exception) if (exception)
{ {
@@ -952,10 +965,11 @@ bool initFlaxEngine()
ex.Log(LogType::Fatal, TEXT("FlaxEngine.Scripting.Init")); ex.Log(LogType::Fatal, TEXT("FlaxEngine.Scripting.Init"));
return true; return true;
} }
// TODO: move it somewhere to game instance class or similar
MainRenderTask::Instance = New<MainRenderTask>();
} }
#endif
// TODO: move it somewhere to game instance class or similar
MainRenderTask::Instance = New<MainRenderTask>();
return false; return false;
} }
@@ -989,5 +1003,5 @@ void ScriptingService::Dispose()
{ {
Scripting::Release(); Scripting::Release();
MCore::Instance()->UnloadEngine(); MCore::UnloadEngine();
} }

View File

@@ -47,12 +47,12 @@ public:
public: public:
/// <summary> /// <summary>
/// Gets mono root domain /// Gets the root domain.
/// </summary> /// </summary>
static MDomain* GetRootDomain(); static MDomain* GetRootDomain();
/// <summary> /// <summary>
/// Gets scripts domain /// Gets the scripts domain (it can be the root domain if not using separate domain for scripting).
/// </summary> /// </summary>
static MDomain* GetScriptsDomain(); static MDomain* GetScriptsDomain();
@@ -70,17 +70,23 @@ public:
static void Release(); static void Release();
#if USE_EDITOR #if USE_EDITOR
/// <summary> /// <summary>
/// Reloads scripts. /// Reloads scripts.
/// </summary> /// </summary>
/// <param name="canTriggerSceneReload">True if allow to scene scripts reload callback, otherwise it won't be possible.</param> /// <param name="canTriggerSceneReload">True if allow to scene scripts reload callback, otherwise it won't be possible.</param>
static void Reload(bool canTriggerSceneReload = true); static void Reload(bool canTriggerSceneReload = true);
#endif #endif
public: public:
/// <summary>
/// Finds the 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 MClass* FindClass(const StringAnsiView& fullname);
#if USE_MONO
/// <summary> /// <summary>
/// Finds the class from the given Mono class object within whole assembly. /// Finds the class from the given Mono class object within whole assembly.
/// </summary> /// </summary>
@@ -88,19 +94,13 @@ public:
/// <returns>The MClass object or null if missing.</returns> /// <returns>The MClass object or null if missing.</returns>
static MClass* FindClass(MonoClass* monoClass); static MClass* FindClass(MonoClass* monoClass);
/// <summary>
/// Finds the 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 MClass* FindClass(const StringAnsiView& fullname);
/// <summary> /// <summary>
/// Finds the native class with given fully qualified name within whole assembly. /// Finds the native class with given fully qualified name within whole assembly.
/// </summary> /// </summary>
/// <param name="fullname">The full name of the type eg: System.Int64.</param> /// <param name="fullname">The full name of the type eg: System.Int64.</param>
/// <returns>The MClass object or null if missing.</returns> /// <returns>The MClass object or null if missing.</returns>
static MonoClass* FindClassNative(const StringAnsiView& fullname); static MonoClass* FindClassNative(const StringAnsiView& fullname);
#endif
/// <summary> /// <summary>
/// Finds the scripting type of the given fullname by searching loaded scripting assemblies. /// Finds the scripting type of the given fullname by searching loaded scripting assemblies.
@@ -161,7 +161,7 @@ public:
/// </summary> /// </summary>
/// <param name="managedInstance">The managed instance pointer.</param> /// <param name="managedInstance">The managed instance pointer.</param>
/// <returns>The found object or null if missing.</returns> /// <returns>The found object or null if missing.</returns>
static ScriptingObject* FindObject(const MonoObject* managedInstance); static ScriptingObject* FindObject(const MObject* managedInstance);
/// <summary> /// <summary>
/// Event called by the internal call on a finalizer thread when the managed objects gets deleted by the GC. /// Event called by the internal call on a finalizer thread when the managed objects gets deleted by the GC.

View File

@@ -4,14 +4,14 @@
#include "Engine/Scripting/ManagedCLR/MTypes.h" #include "Engine/Scripting/ManagedCLR/MTypes.h"
typedef void (*Thunk_Void_0)(MonoObject** exception); typedef void (*Thunk_Void_0)(MObject** exception);
typedef void (*Thunk_Void_1)(void* param_1, MonoObject** exception); typedef void (*Thunk_Void_1)(void* param_1, MObject** exception);
typedef void (*Thunk_Void_2)(void* param_1, void* param_2, MonoObject** exception); typedef void (*Thunk_Void_2)(void* param_1, void* param_2, MObject** exception);
typedef void (*Thunk_Void_3)(void* param_1, void* param_2, void* param_3, MonoObject** exception); typedef void (*Thunk_Void_3)(void* param_1, void* param_2, void* param_3, MObject** exception);
typedef void (*Thunk_Void_4)(void* param_1, void* param_2, void* param_3, void* param_4, MonoObject** exception); typedef void (*Thunk_Void_4)(void* param_1, void* param_2, void* param_3, void* param_4, MObject** exception);
typedef MonoObject* (*Thunk_Object_0)(MonoObject** exception); typedef MObject* (*Thunk_Object_0)(MObject** exception);
typedef MonoObject* (*Thunk_Object_1)(void* param_1, MonoObject** exception); typedef MObject* (*Thunk_Object_1)(void* param_1, MObject** exception);
typedef MonoObject* (*Thunk_Object_2)(void* param_1, void* param_2, MonoObject** exception); typedef MObject* (*Thunk_Object_2)(void* param_1, void* param_2, MObject** exception);
typedef MonoObject* (*Thunk_Object_3)(void* param_1, void* param_2, void* param_3, MonoObject** exception); typedef MObject* (*Thunk_Object_3)(void* param_1, void* param_2, void* param_3, MObject** exception);
typedef MonoObject* (*Thunk_Object_4)(void* param_1, void* param_2, void* param_3, void* param_4, MonoObject** exception); typedef MObject* (*Thunk_Object_4)(void* param_1, void* param_2, void* param_3, void* param_4, MObject** exception);

View File

@@ -18,8 +18,10 @@
#include "ManagedCLR/MCore.h" #include "ManagedCLR/MCore.h"
#endif #endif
#include "FlaxEngine.Gen.h" #include "FlaxEngine.Gen.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
#define ScriptingObject_unmanagedPtr "__unmanagedPtr" #define ScriptingObject_unmanagedPtr "__unmanagedPtr"
#define ScriptingObject_id "__internalId" #define ScriptingObject_id "__internalId"
@@ -54,14 +56,18 @@ ScriptingObject::~ScriptingObject()
} }
} }
MonoObject* ScriptingObject::GetManagedInstance() const MObject* ScriptingObject::GetManagedInstance() const
{ {
#if USE_MONO
return _gcHandle ? mono_gchandle_get_target(_gcHandle) : nullptr; return _gcHandle ? mono_gchandle_get_target(_gcHandle) : nullptr;
#else
return nullptr;
#endif
} }
MonoObject* ScriptingObject::GetOrCreateManagedInstance() const MObject* ScriptingObject::GetOrCreateManagedInstance() const
{ {
MonoObject* managedInstance = GetManagedInstance(); MObject* managedInstance = GetManagedInstance();
if (!managedInstance) if (!managedInstance)
{ {
const_cast<ScriptingObject*>(this)->CreateManaged(); const_cast<ScriptingObject*>(this)->CreateManaged();
@@ -144,9 +150,10 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
return result; return result;
} }
ScriptingObject* ScriptingObject::ToNative(MonoObject* obj) ScriptingObject* ScriptingObject::ToNative(MObject* obj)
{ {
ScriptingObject* ptr = nullptr; ScriptingObject* ptr = nullptr;
#if USE_MONO
if (obj) if (obj)
{ {
// TODO: cache the field offset from object and read directly from object pointer // TODO: cache the field offset from object and read directly from object pointer
@@ -154,6 +161,7 @@ ScriptingObject* ScriptingObject::ToNative(MonoObject* obj)
CHECK_RETURN(ptrField, nullptr); CHECK_RETURN(ptrField, nullptr);
mono_field_get_value(obj, ptrField, &ptr); mono_field_get_value(obj, ptrField, &ptr);
} }
#endif
return ptr; return ptr;
} }
@@ -191,7 +199,9 @@ void ScriptingObject::OnManagedInstanceDeleted()
// Release the handle // Release the handle
if (_gcHandle) if (_gcHandle)
{ {
#if USE_MONO
mono_gchandle_free(_gcHandle); mono_gchandle_free(_gcHandle);
#endif
_gcHandle = 0; _gcHandle = 0;
} }
@@ -212,6 +222,8 @@ void ScriptingObject::OnScriptingDispose()
DeleteObject(); DeleteObject();
} }
#if USE_MONO
MonoObject* ScriptingObject::CreateManagedInternal() MonoObject* ScriptingObject::CreateManagedInternal()
{ {
#if BUILD_DEBUG #if BUILD_DEBUG
@@ -254,8 +266,11 @@ MonoObject* ScriptingObject::CreateManagedInternal()
return managedInstance; return managedInstance;
} }
#endif
void ScriptingObject::DestroyManaged() void ScriptingObject::DestroyManaged()
{ {
#if USE_MONO
// Get managed instance // Get managed instance
const auto managedInstance = GetManagedInstance(); const auto managedInstance = GetManagedInstance();
@@ -279,6 +294,9 @@ void ScriptingObject::DestroyManaged()
mono_gchandle_free(_gcHandle); mono_gchandle_free(_gcHandle);
_gcHandle = 0; _gcHandle = 0;
} }
#else
_gcHandle = 0;
#endif
} }
void ScriptingObject::RegisterObject() void ScriptingObject::RegisterObject()
@@ -319,6 +337,8 @@ bool ScriptingObject::CanCast(MClass* from, MClass* to)
return from->IsSubClassOf(to); return from->IsSubClassOf(to);
} }
#if USE_MONO
bool ScriptingObject::CanCast(MClass* from, MonoClass* to) bool ScriptingObject::CanCast(MClass* from, MonoClass* to)
{ {
if (!from && !to) if (!from && !to)
@@ -333,6 +353,8 @@ bool ScriptingObject::CanCast(MClass* from, MonoClass* to)
return from->IsSubClassOf(to); return from->IsSubClassOf(to);
} }
#endif
void ScriptingObject::OnDeleteObject() void ScriptingObject::OnDeleteObject()
{ {
// Cleanup managed object // Cleanup managed object
@@ -358,6 +380,7 @@ ManagedScriptingObject::ManagedScriptingObject(const SpawnParams& params)
void ManagedScriptingObject::CreateManaged() void ManagedScriptingObject::CreateManaged()
{ {
#if USE_MONO
MonoObject* managedInstance = CreateManagedInternal(); MonoObject* managedInstance = CreateManagedInternal();
if (managedInstance) if (managedInstance)
{ {
@@ -368,6 +391,11 @@ void ManagedScriptingObject::CreateManaged()
if (!IsRegistered()) if (!IsRegistered())
RegisterObject(); RegisterObject();
} }
#else
// Ensure to be registered
if (!IsRegistered())
RegisterObject();
#endif
} }
PersistentScriptingObject::PersistentScriptingObject(const SpawnParams& params) PersistentScriptingObject::PersistentScriptingObject(const SpawnParams& params)
@@ -385,7 +413,9 @@ void PersistentScriptingObject::OnManagedInstanceDeleted()
// Cleanup // Cleanup
if (_gcHandle) if (_gcHandle)
{ {
#if USE_MONO
mono_gchandle_free(_gcHandle); mono_gchandle_free(_gcHandle);
#endif
_gcHandle = 0; _gcHandle = 0;
} }
@@ -404,6 +434,7 @@ void PersistentScriptingObject::OnScriptingDispose()
void PersistentScriptingObject::CreateManaged() void PersistentScriptingObject::CreateManaged()
{ {
#if USE_MONO
MonoObject* managedInstance = CreateManagedInternal(); MonoObject* managedInstance = CreateManagedInternal();
if (managedInstance) if (managedInstance)
{ {
@@ -414,11 +445,18 @@ void PersistentScriptingObject::CreateManaged()
if (!IsRegistered()) if (!IsRegistered())
RegisterObject(); RegisterObject();
} }
#else
// Ensure to be registered
if (!IsRegistered())
RegisterObject();
#endif
} }
class ScriptingObjectInternal class ScriptingObjectInternal
{ {
public: public:
#if !COMPILE_WITHOUT_CSHARP
static MonoObject* Create1(MonoReflectionType* type) static MonoObject* Create1(MonoReflectionType* type)
{ {
@@ -676,6 +714,14 @@ public:
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_GetUnmanagedInterface", &GetUnmanagedInterface); ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_GetUnmanagedInterface", &GetUnmanagedInterface);
} }
#else
static void InitRuntime()
{
}
#endif
static ScriptingObject* Spawn(const ScriptingObjectSpawnParams& params) static ScriptingObject* Spawn(const ScriptingObjectSpawnParams& params)
{ {
return New<PersistentScriptingObject>(params); return New<PersistentScriptingObject>(params);

View File

@@ -62,12 +62,12 @@ public:
/// <summary> /// <summary>
/// Gets the managed instance object. /// Gets the managed instance object.
/// </summary> /// </summary>
MonoObject* GetManagedInstance() const; MObject* GetManagedInstance() const;
/// <summary> /// <summary>
/// Gets the managed instance object or creates it if missing. /// Gets the managed instance object or creates it if missing.
/// </summary> /// </summary>
MonoObject* GetOrCreateManagedInstance() const; MObject* GetOrCreateManagedInstance() const;
/// <summary> /// <summary>
/// Determines whether managed instance is alive. /// Determines whether managed instance is alive.
@@ -117,9 +117,9 @@ public:
return (T*)ToInterface(obj, T::TypeInitializer); return (T*)ToInterface(obj, T::TypeInitializer);
} }
static ScriptingObject* ToNative(MonoObject* obj); static ScriptingObject* ToNative(MObject* obj);
static MonoObject* ToManaged(ScriptingObject* obj) static MObject* ToManaged(ScriptingObject* obj)
{ {
return obj ? obj->GetOrCreateManagedInstance() : nullptr; return obj ? obj->GetOrCreateManagedInstance() : nullptr;
} }
@@ -139,7 +139,9 @@ public:
/// <param name="to">The destination class to the cast.</param> /// <param name="to">The destination class to the cast.</param>
/// <returns>True if can, otherwise false.</returns> /// <returns>True if can, otherwise false.</returns>
static bool CanCast(MClass* from, MClass* to); static bool CanCast(MClass* from, MClass* to);
#if USE_MONO
static bool CanCast(MClass* from, MonoClass* to); static bool CanCast(MClass* from, MonoClass* to);
#endif
template<typename T> template<typename T>
static T* Cast(ScriptingObject* obj) static T* Cast(ScriptingObject* obj)
@@ -154,10 +156,12 @@ public:
return CanCast(GetClass(), type); return CanCast(GetClass(), type);
} }
#if USE_MONO
bool Is(MonoClass* klass) const bool Is(MonoClass* klass) const
{ {
return CanCast(GetClass(), klass); return CanCast(GetClass(), klass);
} }
#endif
template<typename T> template<typename T>
bool Is() const bool Is() const
@@ -186,7 +190,6 @@ public:
/// <summary> /// <summary>
/// Determines whether this object is registered or not (can be found by the queries and used in a game). /// Determines whether this object is registered or not (can be found by the queries and used in a game).
/// </summary> /// </summary>
/// <returns><c>true</c> if this instance is registered; otherwise, <c>false</c>.</returns>
FORCE_INLINE bool IsRegistered() const FORCE_INLINE bool IsRegistered() const
{ {
return (Flags & ObjectFlags::IsRegistered) != 0; return (Flags & ObjectFlags::IsRegistered) != 0;
@@ -204,10 +207,12 @@ public:
protected: protected:
#if USE_MONO
/// <summary> /// <summary>
/// Create a new managed object. /// Create a new managed object.
/// </summary> /// </summary>
MonoObject* CreateManagedInternal(); MonoObject* CreateManagedInternal();
#endif
public: public:

View File

@@ -68,7 +68,7 @@ public:
/// <summary> /// <summary>
/// Gets managed instance object (or null if no object linked). /// Gets managed instance object (or null if no object linked).
/// </summary> /// </summary>
FORCE_INLINE MonoObject* GetManagedInstance() const FORCE_INLINE MObject* GetManagedInstance() const
{ {
return _object ? _object->GetOrCreateManagedInstance() : nullptr; return _object ? _object->GetOrCreateManagedInstance() : nullptr;
} }
@@ -84,7 +84,7 @@ public:
/// <summary> /// <summary>
/// Gets the managed instance object or creates it if missing or null if not assigned. /// Gets the managed instance object or creates it if missing or null if not assigned.
/// </summary> /// </summary>
FORCE_INLINE MonoObject* GetOrCreateManagedInstance() const FORCE_INLINE MObject* GetOrCreateManagedInstance() const
{ {
return _object ? _object->GetOrCreateManagedInstance() : nullptr; return _object ? _object->GetOrCreateManagedInstance() : nullptr;
} }

View File

@@ -13,9 +13,6 @@ class NativeBinaryModule;
struct ScriptingTypeHandle; struct ScriptingTypeHandle;
struct ScriptingTypeInitializer; struct ScriptingTypeInitializer;
struct ScriptingObjectSpawnParams; struct ScriptingObjectSpawnParams;
typedef struct _MonoClass MonoClass;
typedef struct _MonoObject MonoObject;
typedef struct _MonoType MonoType;
/// <summary> /// <summary>
/// The safe handle to the scripting type contained in the scripting assembly. /// The safe handle to the scripting type contained in the scripting assembly.
@@ -113,8 +110,8 @@ struct FLAXENGINE_API ScriptingType
typedef void (*Ctor)(void* ptr); typedef void (*Ctor)(void* ptr);
typedef void (*Dtor)(void* ptr); typedef void (*Dtor)(void* ptr);
typedef void (*Copy)(void* dst, void* src); typedef void (*Copy)(void* dst, void* src);
typedef MonoObject* (*Box)(void* ptr); typedef MObject* (*Box)(void* ptr);
typedef void (*Unbox)(void* ptr, MonoObject* managed); typedef void (*Unbox)(void* ptr, MObject* managed);
typedef void (*GetField)(void* ptr, const String& name, Variant& value); typedef void (*GetField)(void* ptr, const String& name, Variant& value);
typedef void (*SetField)(void* ptr, const String& name, const Variant& value); typedef void (*SetField)(void* ptr, const String& name, const Variant& value);
typedef void* (*GetInterfaceWrapper)(ScriptingObject* obj); typedef void* (*GetInterfaceWrapper)(ScriptingObject* obj);

View File

@@ -281,7 +281,7 @@ public:
/// Gets managed instance object (or null if no object linked). /// Gets managed instance object (or null if no object linked).
/// </summary> /// </summary>
/// <returns>The managed object instance.</returns> /// <returns>The managed object instance.</returns>
MonoObject* GetManagedInstance() const MObject* GetManagedInstance() const
{ {
auto object = Get(); auto object = Get();
return object ? object->GetOrCreateManagedInstance() : nullptr; return object ? object->GetOrCreateManagedInstance() : nullptr;
@@ -301,7 +301,7 @@ public:
/// Gets the managed instance object or creates it if missing or null if not assigned. /// Gets the managed instance object or creates it if missing or null if not assigned.
/// </summary> /// </summary>
/// <returns>The Mono managed object.</returns> /// <returns>The Mono managed object.</returns>
MonoObject* GetOrCreateManagedInstance() const MObject* GetOrCreateManagedInstance() const
{ {
auto object = Get(); auto object = Get();
return object ? object->GetOrCreateManagedInstance() : nullptr; return object ? object->GetOrCreateManagedInstance() : nullptr;

View File

@@ -47,6 +47,7 @@ void StdTypesContainer::Clear()
bool StdTypesContainer::Gather() bool StdTypesContainer::Gather()
{ {
#if !COMPILE_WITHOUT_CSHARP
#define GET_CLASS(assembly, type, typeName) \ #define GET_CLASS(assembly, type, typeName) \
type = ((ManagedBinaryModule*)CONCAT_MACROS(GetBinaryModule, assembly)())->Assembly->GetClass(typeName); \ type = ((ManagedBinaryModule*)CONCAT_MACROS(GetBinaryModule, assembly)())->Assembly->GetClass(typeName); \
if (type == nullptr) \ if (type == nullptr) \
@@ -93,5 +94,6 @@ bool StdTypesContainer::Gather()
#undef GET_CLASS #undef GET_CLASS
#undef GET_METHOD #undef GET_METHOD
#endif
return false; return false;
} }

View File

@@ -2,14 +2,69 @@
#pragma once #pragma once
// Forward declarations
class Scripting; class Scripting;
struct ScriptingType; struct ScriptingType;
class BinaryModule; class BinaryModule;
class ScriptingObject; class ScriptingObject;
class MCore;
class MDomain; class MDomain;
class MException; class MException;
class MAssembly; class MAssembly;
class MClass; class MClass;
class MField; class MField;
class MMethod;
class MProperty; class MProperty;
class MEvent; class MEvent;
class MDomain;
class MType;
#if COMPILE_WITHOUT_CSHARP
// No Scripting
#define USE_MONO 0
#define USE_NETCORE 0
typedef void MObject;
#else
#define USE_MONO 1
#define USE_NETCORE 0
// 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)
#ifndef USE_MONO_AOT
#define USE_MONO_AOT 0
#define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE
#endif
// Mono types declarations
typedef struct _MonoClass MonoClass;
typedef struct _MonoDomain MonoDomain;
typedef struct _MonoImage MonoImage;
typedef struct _MonoAssembly MonoAssembly;
typedef struct _MonoMethod MonoMethod;
typedef struct _MonoProperty MonoProperty;
typedef struct _MonoObject MonoObject;
typedef struct _MonoEvent MonoEvent;
typedef struct _MonoType MonoType;
typedef struct _MonoString MonoString;
typedef struct _MonoArray MonoArray;
typedef struct _MonoReflectionType MonoReflectionType;
typedef struct _MonoReflectionAssembly MonoReflectionAssembly;
typedef struct _MonoException MonoException;
typedef struct _MonoClassField MonoClassField;
typedef MonoObject MObject;
#endif
#endif

View File

@@ -208,12 +208,14 @@ void Serialization::Serialize(ISerializable::SerializeStream& stream, const Vari
case VariantType::ManagedObject: case VariantType::ManagedObject:
case VariantType::Structure: case VariantType::Structure:
{ {
#if USE_MONO
MonoObject* obj; MonoObject* obj;
if (v.Type.Type == VariantType::Structure) if (v.Type.Type == VariantType::Structure)
obj = MUtils::BoxVariant(v); obj = MUtils::BoxVariant(v);
else else
obj = (MonoObject*)v; obj = (MonoObject*)v;
ManagedSerialization::Serialize(stream, obj); ManagedSerialization::Serialize(stream, obj);
#endif
break; break;
} }
default: default:
@@ -346,6 +348,7 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
case VariantType::ManagedObject: case VariantType::ManagedObject:
case VariantType::Structure: case VariantType::Structure:
{ {
#if USE_MONO
auto obj = (MonoObject*)v; auto obj = (MonoObject*)v;
if (!obj && v.Type.TypeName) if (!obj && v.Type.TypeName)
{ {
@@ -369,6 +372,7 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
ManagedSerialization::Deserialize(value, obj); ManagedSerialization::Deserialize(value, obj);
if (v.Type.Type == VariantType::Structure) if (v.Type.Type == VariantType::Structure)
v = MUtils::UnboxVariant(obj); v = MUtils::UnboxVariant(obj);
#endif
break; break;
} }
default: default:

View File

@@ -356,6 +356,7 @@ void ReadStream::ReadVariant(Variant* data)
// Json // Json
StringAnsi json; StringAnsi json;
ReadStringAnsi(&json, -71); ReadStringAnsi(&json, -71);
#if USE_MONO
MCore::AttachThread(); MCore::AttachThread();
MonoClass* klass = MUtils::GetClass(data->Type); MonoClass* klass = MUtils::GetClass(data->Type);
if (!klass) if (!klass)
@@ -376,6 +377,7 @@ void ReadStream::ReadVariant(Variant* data)
data->SetManagedObject(obj); data->SetManagedObject(obj);
else else
*data = MUtils::UnboxVariant(obj); *data = MUtils::UnboxVariant(obj);
#endif
} }
else else
{ {
@@ -706,6 +708,7 @@ void WriteStream::WriteVariant(const Variant& data)
case VariantType::ManagedObject: case VariantType::ManagedObject:
case VariantType::Structure: case VariantType::Structure:
{ {
#if USE_MONO
MonoObject* obj; MonoObject* obj;
if (data.Type.Type == VariantType::Structure) if (data.Type.Type == VariantType::Structure)
obj = MUtils::BoxVariant(data); obj = MUtils::BoxVariant(data);
@@ -721,6 +724,7 @@ void WriteStream::WriteVariant(const Variant& data)
WriteStringAnsi(StringAnsiView(json.GetString(), (int32)json.GetSize()), -71); WriteStringAnsi(StringAnsiView(json.GetString(), (int32)json.GetSize()), -71);
} }
else else
#endif
{ {
WriteByte(0); WriteByte(0);
} }

View File

@@ -183,7 +183,7 @@ int32 JobSystemThread::Run()
// Ensure to have C# thread attached to this thead (late init due to MCore being initialized after Job System) // 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 (attachMonoThread && !mono_domain_get())
{ {
const auto domain = MCore::Instance()->GetActiveDomain(); const auto domain = MCore::GetActiveDomain();
mono_thread_attach(domain->GetNative()); mono_thread_attach(domain->GetNative());
attachMonoThread = false; attachMonoThread = false;
} }

View File

@@ -5,8 +5,13 @@
#include "Engine/Scripting/ManagedCLR/MMethod.h" #include "Engine/Scripting/ManagedCLR/MMethod.h"
#include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Serialization/Serialization.h" #include "Engine/Serialization/Serialization.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
#if COMPILE_WITHOUT_CSHARP
#define UICANVAS_INVOKE(event)
#else
// Cached methods (FlaxEngine.CSharp.dll is loaded only once) // Cached methods (FlaxEngine.CSharp.dll is loaded only once)
MMethod* UICanvas_Serialize = nullptr; MMethod* UICanvas_Serialize = nullptr;
MMethod* UICanvas_SerializeDiff = nullptr; MMethod* UICanvas_SerializeDiff = nullptr;
@@ -24,7 +29,7 @@ MMethod* UICanvas_ParentChanged = nullptr;
auto instance = GetManagedInstance(); \ auto instance = GetManagedInstance(); \
if (instance) \ if (instance) \
{ \ { \
MonoObject* exception = nullptr; \ MObject* exception = nullptr; \
UICanvas_##event->Invoke(instance, nullptr, &exception); \ UICanvas_##event->Invoke(instance, nullptr, &exception); \
if (exception) \ if (exception) \
{ \ { \
@@ -32,10 +37,12 @@ MMethod* UICanvas_ParentChanged = nullptr;
ex.Log(LogType::Error, TEXT("UICanvas::" #event)); \ ex.Log(LogType::Error, TEXT("UICanvas::" #event)); \
} \ } \
} }
#endif
UICanvas::UICanvas(const SpawnParams& params) UICanvas::UICanvas(const SpawnParams& params)
: Actor(params) : Actor(params)
{ {
#if !COMPILE_WITHOUT_CSHARP
Platform::MemoryBarrier(); Platform::MemoryBarrier();
if (UICanvas_Serialize == nullptr) if (UICanvas_Serialize == nullptr)
{ {
@@ -52,6 +59,7 @@ UICanvas::UICanvas(const SpawnParams& params)
UICanvas_EndPlay = mclass->GetMethod("EndPlay"); UICanvas_EndPlay = mclass->GetMethod("EndPlay");
UICanvas_ParentChanged = mclass->GetMethod("ParentChanged"); UICanvas_ParentChanged = mclass->GetMethod("ParentChanged");
} }
#endif
} }
#if USE_EDITOR #if USE_EDITOR
@@ -71,10 +79,11 @@ void UICanvas::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE_GET_OTHER_OBJ(UICanvas); SERIALIZE_GET_OTHER_OBJ(UICanvas);
#if !COMPILE_WITHOUT_CSHARP
stream.JKEY("V"); stream.JKEY("V");
void* params[1]; void* params[1];
params[0] = other ? other->GetOrCreateManagedInstance() : nullptr; params[0] = other ? other->GetOrCreateManagedInstance() : nullptr;
MonoObject* exception = nullptr; MObject* exception = nullptr;
auto method = other ? UICanvas_SerializeDiff : UICanvas_Serialize; auto method = other ? UICanvas_SerializeDiff : UICanvas_Serialize;
auto invokeResultStr = (MonoString*)method->Invoke(GetOrCreateManagedInstance(), params, &exception); auto invokeResultStr = (MonoString*)method->Invoke(GetOrCreateManagedInstance(), params, &exception);
if (exception) if (exception)
@@ -93,6 +102,7 @@ void UICanvas::Serialize(SerializeStream& stream, const void* otherObj)
stream.RawValue(invokeResultChars); stream.RawValue(invokeResultChars);
mono_free(invokeResultChars); mono_free(invokeResultChars);
} }
#endif
} }
void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
@@ -100,6 +110,7 @@ void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi
// Base // Base
Actor::Deserialize(stream, modifier); Actor::Deserialize(stream, modifier);
#if !COMPILE_WITHOUT_CSHARP
// Handle C# object data serialization // Handle C# object data serialization
const auto dataMember = stream.FindMember("V"); const auto dataMember = stream.FindMember("V");
if (dataMember != stream.MemberEnd()) if (dataMember != stream.MemberEnd())
@@ -110,7 +121,7 @@ void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi
const auto str = buffer.GetString(); const auto str = buffer.GetString();
void* args[1]; void* args[1];
args[0] = mono_string_new(mono_domain_get(), str); args[0] = mono_string_new(mono_domain_get(), str);
MonoObject* exception = nullptr; MObject* exception = nullptr;
UICanvas_Deserialize->Invoke(GetOrCreateManagedInstance(), args, &exception); UICanvas_Deserialize->Invoke(GetOrCreateManagedInstance(), args, &exception);
if (exception) if (exception)
{ {
@@ -118,6 +129,7 @@ void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi
ex.Log(LogType::Error, TEXT("UICanvas::Deserialize")); ex.Log(LogType::Error, TEXT("UICanvas::Deserialize"));
} }
} }
#endif
if (IsDuringPlay()) if (IsDuringPlay())
{ {

View File

@@ -6,8 +6,13 @@
#include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/Scripting.h" #include "Engine/Scripting/Scripting.h"
#include "Engine/Serialization/Serialization.h" #include "Engine/Serialization/Serialization.h"
#if USE_MONO
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h> #include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
#endif
#if COMPILE_WITHOUT_CSHARP
#define UICONTROL_INVOKE(event)
#else
// Cached methods (FlaxEngine.CSharp.dll is loaded only once) // Cached methods (FlaxEngine.CSharp.dll is loaded only once)
MMethod* UIControl_Serialize = nullptr; MMethod* UIControl_Serialize = nullptr;
MMethod* UIControl_SerializeDiff = nullptr; MMethod* UIControl_SerializeDiff = nullptr;
@@ -22,7 +27,7 @@ MMethod* UIControl_EndPlay = nullptr;
#define UICONTROL_INVOKE(event) \ #define UICONTROL_INVOKE(event) \
if (HasManagedInstance()) \ if (HasManagedInstance()) \
{ \ { \
MonoObject* exception = nullptr; \ MObject* exception = nullptr; \
UIControl_##event->Invoke(GetManagedInstance(), nullptr, &exception); \ UIControl_##event->Invoke(GetManagedInstance(), nullptr, &exception); \
if (exception) \ if (exception) \
{ \ { \
@@ -30,10 +35,12 @@ MMethod* UIControl_EndPlay = nullptr;
ex.Log(LogType::Error, TEXT("UICanvas::" #event)); \ ex.Log(LogType::Error, TEXT("UICanvas::" #event)); \
} \ } \
} }
#endif
UIControl::UIControl(const SpawnParams& params) UIControl::UIControl(const SpawnParams& params)
: Actor(params) : Actor(params)
{ {
#if !COMPILE_WITHOUT_CSHARP
if (UIControl_Serialize == nullptr) if (UIControl_Serialize == nullptr)
{ {
MClass* mclass = GetClass(); MClass* mclass = GetClass();
@@ -47,6 +54,7 @@ UIControl::UIControl(const SpawnParams& params)
UIControl_BeginPlay = mclass->GetMethod("BeginPlay"); UIControl_BeginPlay = mclass->GetMethod("BeginPlay");
UIControl_EndPlay = mclass->GetMethod("EndPlay"); UIControl_EndPlay = mclass->GetMethod("EndPlay");
} }
#endif
} }
#if USE_EDITOR #if USE_EDITOR
@@ -66,11 +74,12 @@ void UIControl::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE_GET_OTHER_OBJ(UIControl); SERIALIZE_GET_OTHER_OBJ(UIControl);
#if !COMPILE_WITHOUT_CSHARP
void* params[2]; void* params[2];
MonoString* controlType = nullptr; MonoString* controlType = nullptr;
params[0] = &controlType; params[0] = &controlType;
params[1] = other ? other->GetOrCreateManagedInstance() : nullptr; params[1] = other ? other->GetOrCreateManagedInstance() : nullptr;
MonoObject* exception = nullptr; MObject* exception = nullptr;
const auto method = other ? UIControl_SerializeDiff : UIControl_Serialize; const auto method = other ? UIControl_SerializeDiff : UIControl_Serialize;
const auto invokeResultStr = (MonoString*)method->Invoke(GetOrCreateManagedInstance(), params, &exception); const auto invokeResultStr = (MonoString*)method->Invoke(GetOrCreateManagedInstance(), params, &exception);
if (exception) if (exception)
@@ -107,6 +116,7 @@ void UIControl::Serialize(SerializeStream& stream, const void* otherObj)
const auto invokeResultChars = mono_string_to_utf8(invokeResultStr); const auto invokeResultChars = mono_string_to_utf8(invokeResultStr);
stream.RawValue(invokeResultChars); stream.RawValue(invokeResultChars);
mono_free(invokeResultChars); mono_free(invokeResultChars);
#endif
} }
void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
@@ -114,6 +124,7 @@ void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
// Base // Base
Actor::Deserialize(stream, modifier); Actor::Deserialize(stream, modifier);
#if !COMPILE_WITHOUT_CSHARP
MonoReflectionType* typeObj = nullptr; MonoReflectionType* typeObj = nullptr;
const auto controlMember = stream.FindMember("Control"); const auto controlMember = stream.FindMember("Control");
if (controlMember != stream.MemberEnd()) if (controlMember != stream.MemberEnd())
@@ -140,7 +151,7 @@ void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
void* args[2]; void* args[2];
args[0] = mono_string_new(mono_domain_get(), str); args[0] = mono_string_new(mono_domain_get(), str);
args[1] = typeObj; args[1] = typeObj;
MonoObject* exception = nullptr; MObject* exception = nullptr;
UIControl_Deserialize->Invoke(GetOrCreateManagedInstance(), args, &exception); UIControl_Deserialize->Invoke(GetOrCreateManagedInstance(), args, &exception);
if (exception) if (exception)
{ {
@@ -148,6 +159,7 @@ void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
ex.Log(LogType::Error, TEXT("UIControl::Deserialize")); ex.Log(LogType::Error, TEXT("UIControl::Deserialize"));
} }
} }
#endif
} }
void UIControl::OnParentChanged() void UIControl::OnParentChanged()

View File

@@ -523,6 +523,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView); const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView);
if (!typeHandle) if (!typeHandle)
{ {
#if !COMPILE_WITHOUT_CSHARP
const auto mclass = Scripting::FindClass(typeNameAnsiView); const auto mclass = Scripting::FindClass(typeNameAnsiView);
if (mclass) if (mclass)
{ {
@@ -559,6 +560,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
} }
} }
else if (typeName.HasChars()) else if (typeName.HasChars())
#endif
{ {
OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName)); OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName));
} }
@@ -609,6 +611,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView); const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView);
if (!typeHandle) if (!typeHandle)
{ {
#if !COMPILE_WITHOUT_CSHARP
const auto mclass = Scripting::FindClass(typeNameAnsiView); const auto mclass = Scripting::FindClass(typeNameAnsiView);
if (mclass) if (mclass)
{ {
@@ -646,6 +649,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
} }
} }
else if (typeName.HasChars()) else if (typeName.HasChars())
#endif
{ {
OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName)); OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName));
} }

View File

@@ -27,9 +27,19 @@ namespace Flax.Build.Bindings
private static readonly HashSet<TypeInfo> CppVariantFromTypes = new HashSet<TypeInfo>(); private static readonly HashSet<TypeInfo> CppVariantFromTypes = new HashSet<TypeInfo>();
private static bool CppNonPodTypesConvertingGeneration = false; private static bool CppNonPodTypesConvertingGeneration = false;
public static readonly List<string> CppScriptObjectVirtualWrapperMethodsPostfixes = new List<string> public class ScriptingLangInfo
{ {
"_ManagedWrapper", // C# public bool Enabled;
public string VirtualWrapperMethodsPostfix;
}
public static readonly List<ScriptingLangInfo> ScriptingLangInfos = new List<ScriptingLangInfo>
{
new ScriptingLangInfo
{
Enabled = true,
VirtualWrapperMethodsPostfix = "_ManagedWrapper", // C#
},
}; };
public static event Action<BuildData, IGrouping<string, Module>, StringBuilder> GenerateCppBinaryModuleHeader; public static event Action<BuildData, IGrouping<string, Module>, StringBuilder> GenerateCppBinaryModuleHeader;
@@ -1003,6 +1013,8 @@ namespace Flax.Build.Bindings
private static void GenerateCppManagedWrapperFunction(BuildData buildData, StringBuilder contents, VirtualClassInfo classInfo, FunctionInfo functionInfo, int scriptVTableSize, int scriptVTableIndex) private static void GenerateCppManagedWrapperFunction(BuildData buildData, StringBuilder contents, VirtualClassInfo classInfo, FunctionInfo functionInfo, int scriptVTableSize, int scriptVTableIndex)
{ {
if (!EngineConfiguration.WithCSharp(buildData.TargetOptions))
return;
contents.AppendFormat(" {0} {1}_ManagedWrapper(", functionInfo.ReturnType, functionInfo.UniqueName); contents.AppendFormat(" {0} {1}_ManagedWrapper(", functionInfo.ReturnType, functionInfo.UniqueName);
var separator = false; var separator = false;
for (var i = 0; i < functionInfo.Parameters.Count; i++) for (var i = 0; i < functionInfo.Parameters.Count; i++)
@@ -1240,13 +1252,17 @@ namespace Flax.Build.Bindings
contents.AppendLine(" if (vtableIndex > 0 && vtableIndex < entriesCount)"); contents.AppendLine(" if (vtableIndex > 0 && vtableIndex < entriesCount)");
contents.AppendLine(" {"); contents.AppendLine(" {");
contents.AppendLine($" scriptVTableBase[{scriptVTableIndex} + 2] = vtable[vtableIndex];"); contents.AppendLine($" scriptVTableBase[{scriptVTableIndex} + 2] = vtable[vtableIndex];");
for (var i = 0; i < CppScriptObjectVirtualWrapperMethodsPostfixes.Count; i++) for (int i = 0, count = 0; i < ScriptingLangInfos.Count; i++)
{ {
contents.AppendLine(i == 0 ? " if (wrapperIndex == 0)" : $" else if (wrapperIndex == {i})"); var langInfo = ScriptingLangInfos[i];
if (!langInfo.Enabled)
continue;
contents.AppendLine(count == 0 ? " if (wrapperIndex == 0)" : $" else if (wrapperIndex == {count})");
contents.AppendLine(" {"); contents.AppendLine(" {");
contents.AppendLine($" auto thunkPtr = &{classInfo.NativeName}Internal::{functionInfo.UniqueName}{CppScriptObjectVirtualWrapperMethodsPostfixes[i]};"); contents.AppendLine($" auto thunkPtr = &{classInfo.NativeName}Internal::{functionInfo.UniqueName}{langInfo.VirtualWrapperMethodsPostfix};");
contents.AppendLine(" vtable[vtableIndex] = *(void**)&thunkPtr;"); contents.AppendLine(" vtable[vtableIndex] = *(void**)&thunkPtr;");
contents.AppendLine(" }"); contents.AppendLine(" }");
count++;
} }
contents.AppendLine(" }"); contents.AppendLine(" }");
contents.AppendLine(" else"); contents.AppendLine(" else");
@@ -1412,6 +1428,7 @@ namespace Flax.Build.Bindings
if (classInfo.Parent != null && !(classInfo.Parent is FileInfo)) if (classInfo.Parent != null && !(classInfo.Parent is FileInfo))
classTypeNameInternal = classInfo.Parent.FullNameNative + '_' + classTypeNameInternal; classTypeNameInternal = classInfo.Parent.FullNameNative + '_' + classTypeNameInternal;
var useScripting = classInfo.IsStatic || classInfo.IsScriptingObject; var useScripting = classInfo.IsStatic || classInfo.IsScriptingObject;
var useCSharp = EngineConfiguration.WithCSharp(buildData.TargetOptions);
var hasInterface = classInfo.Interfaces != null && classInfo.Interfaces.Any(x => x.Access == AccessLevel.Public); var hasInterface = classInfo.Interfaces != null && classInfo.Interfaces.Any(x => x.Access == AccessLevel.Public);
if (classInfo.IsAutoSerialization) if (classInfo.IsAutoSerialization)
@@ -1428,74 +1445,77 @@ namespace Flax.Build.Bindings
if (!useScripting) if (!useScripting)
continue; continue;
var paramsCount = eventInfo.Type.GenericArgs?.Count ?? 0; var paramsCount = eventInfo.Type.GenericArgs?.Count ?? 0;
// C# event invoking wrapper (calls C# event from C++ delegate)
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MEvent.h");
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
CppIncludeFiles.Add("Engine/Profiler/ProfilerCPU.h"); CppIncludeFiles.Add("Engine/Profiler/ProfilerCPU.h");
contents.Append(" ");
if (eventInfo.IsStatic)
contents.Append("static ");
contents.AppendFormat("void {0}_ManagedWrapper(", eventInfo.Name);
for (var i = 0; i < paramsCount; i++)
{
if (i != 0)
contents.Append(", ");
contents.Append(eventInfo.Type.GenericArgs[i]).Append(" arg" + i);
}
contents.Append(')').AppendLine();
contents.Append(" {").AppendLine();
contents.Append(" static MMethod* mmethod = nullptr;").AppendLine();
contents.Append(" if (!mmethod)").AppendLine();
contents.AppendFormat(" mmethod = {1}::TypeInitializer.GetType().ManagedClass->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
contents.Append(" CHECK(mmethod);").AppendLine();
contents.Append($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::On{eventInfo.Name}\");").AppendLine();
contents.Append(" MonoObject* exception = nullptr;").AppendLine();
if (paramsCount == 0)
contents.AppendLine(" void** params = nullptr;");
else
contents.AppendLine($" void* params[{paramsCount}];");
for (var i = 0; i < paramsCount; i++)
{
var paramType = eventInfo.Type.GenericArgs[i];
var paramName = "arg" + i;
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, paramType, paramName, classInfo, false);
contents.Append($" params[{i}] = {paramValue};").AppendLine();
}
if (eventInfo.IsStatic)
contents.AppendLine(" MonoObject* instance = nullptr;");
else
contents.AppendLine($" MonoObject* instance = (({classTypeNameNative}*)this)->GetManagedInstance();");
contents.Append(" mono_runtime_invoke(mmethod->GetNative(), instance, params, &exception);").AppendLine();
contents.Append(" if (exception)").AppendLine();
contents.Append(" DebugLog::LogException(exception);").AppendLine();
contents.Append(" }").AppendLine().AppendLine();
// C# event wrapper binding method (binds/unbinds C# wrapper to C++ delegate)
contents.AppendFormat(" static void {0}_ManagedBind(", eventInfo.Name);
if (!eventInfo.IsStatic)
contents.AppendFormat("{0}* obj, ", classTypeNameNative);
contents.Append("bool bind)").AppendLine();
contents.Append(" {").AppendLine();
contents.Append(" Function<void(");
for (var i = 0; i < paramsCount; i++)
{
if (i != 0)
contents.Append(", ");
contents.Append(eventInfo.Type.GenericArgs[i]);
}
contents.Append(")> f;").AppendLine();
if (eventInfo.IsStatic)
contents.AppendFormat(" f.Bind<{0}_ManagedWrapper>();", eventInfo.Name).AppendLine();
else
contents.AppendFormat(" f.Bind<{1}Internal, &{1}Internal::{0}_ManagedWrapper>(({1}Internal*)obj);", eventInfo.Name, classTypeNameInternal).AppendLine();
contents.Append(" if (bind)").AppendLine();
var bindPrefix = eventInfo.IsStatic ? classTypeNameNative + "::" : "obj->"; var bindPrefix = eventInfo.IsStatic ? classTypeNameNative + "::" : "obj->";
contents.AppendFormat(" {0}{1}.Bind(f);", bindPrefix, eventInfo.Name).AppendLine();
contents.Append(" else").AppendLine(); if (useCSharp)
contents.AppendFormat(" {0}{1}.Unbind(f);", bindPrefix, eventInfo.Name).AppendLine(); {
contents.Append(" }").AppendLine().AppendLine(); // C# event invoking wrapper (calls C# event from C++ delegate)
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MEvent.h");
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
contents.Append(" ");
if (eventInfo.IsStatic)
contents.Append("static ");
contents.AppendFormat("void {0}_ManagedWrapper(", eventInfo.Name);
for (var i = 0; i < paramsCount; i++)
{
if (i != 0)
contents.Append(", ");
contents.Append(eventInfo.Type.GenericArgs[i]).Append(" arg" + i);
}
contents.Append(')').AppendLine();
contents.Append(" {").AppendLine();
contents.Append(" static MMethod* mmethod = nullptr;").AppendLine();
contents.Append(" if (!mmethod)").AppendLine();
contents.AppendFormat(" mmethod = {1}::TypeInitializer.GetType().ManagedClass->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
contents.Append(" CHECK(mmethod);").AppendLine();
contents.Append($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::On{eventInfo.Name}\");").AppendLine();
contents.Append(" MonoObject* exception = nullptr;").AppendLine();
if (paramsCount == 0)
contents.AppendLine(" void** params = nullptr;");
else
contents.AppendLine($" void* params[{paramsCount}];");
for (var i = 0; i < paramsCount; i++)
{
var paramType = eventInfo.Type.GenericArgs[i];
var paramName = "arg" + i;
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, paramType, paramName, classInfo, false);
contents.Append($" params[{i}] = {paramValue};").AppendLine();
}
if (eventInfo.IsStatic)
contents.AppendLine(" MonoObject* instance = nullptr;");
else
contents.AppendLine($" MonoObject* instance = (({classTypeNameNative}*)this)->GetManagedInstance();");
contents.Append(" mono_runtime_invoke(mmethod->GetNative(), instance, params, &exception);").AppendLine();
contents.Append(" if (exception)").AppendLine();
contents.Append(" DebugLog::LogException(exception);").AppendLine();
contents.Append(" }").AppendLine().AppendLine();
// C# event wrapper binding method (binds/unbinds C# wrapper to C++ delegate)
contents.AppendFormat(" static void {0}_ManagedBind(", eventInfo.Name);
if (!eventInfo.IsStatic)
contents.AppendFormat("{0}* obj, ", classTypeNameNative);
contents.Append("bool bind)").AppendLine();
contents.Append(" {").AppendLine();
contents.Append(" Function<void(");
for (var i = 0; i < paramsCount; i++)
{
if (i != 0)
contents.Append(", ");
contents.Append(eventInfo.Type.GenericArgs[i]);
}
contents.Append(")> f;").AppendLine();
if (eventInfo.IsStatic)
contents.AppendFormat(" f.Bind<{0}_ManagedWrapper>();", eventInfo.Name).AppendLine();
else
contents.AppendFormat(" f.Bind<{1}Internal, &{1}Internal::{0}_ManagedWrapper>(({1}Internal*)obj);", eventInfo.Name, classTypeNameInternal).AppendLine();
contents.Append(" if (bind)").AppendLine();
contents.AppendFormat(" {0}{1}.Bind(f);", bindPrefix, eventInfo.Name).AppendLine();
contents.Append(" else").AppendLine();
contents.AppendFormat(" {0}{1}.Unbind(f);", bindPrefix, eventInfo.Name).AppendLine();
contents.Append(" }").AppendLine().AppendLine();
}
// Generic scripting event invoking wrapper (calls scripting code from C++ delegate) // Generic scripting event invoking wrapper (calls scripting code from C++ delegate)
CppIncludeFiles.Add("Engine/Scripting/Events.h"); CppIncludeFiles.Add("Engine/Scripting/Events.h");
@@ -1551,7 +1571,7 @@ namespace Flax.Build.Bindings
// Fields // Fields
foreach (var fieldInfo in classInfo.Fields) foreach (var fieldInfo in classInfo.Fields)
{ {
if (!useScripting) if (!useScripting || !useCSharp)
continue; continue;
if (fieldInfo.Getter != null) if (fieldInfo.Getter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Getter, "{0}"); GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Getter, "{0}");
@@ -1568,7 +1588,7 @@ namespace Flax.Build.Bindings
// Properties // Properties
foreach (var propertyInfo in classInfo.Properties) foreach (var propertyInfo in classInfo.Properties)
{ {
if (!useScripting) if (!useScripting || !useCSharp)
continue; continue;
if (propertyInfo.Getter != null) if (propertyInfo.Getter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, propertyInfo.Getter); GenerateCppWrapperFunction(buildData, contents, classInfo, propertyInfo.Getter);
@@ -1579,13 +1599,15 @@ namespace Flax.Build.Bindings
// Functions // Functions
foreach (var functionInfo in classInfo.Functions) foreach (var functionInfo in classInfo.Functions)
{ {
if (!useCSharp)
continue;
if (!useScripting) if (!useScripting)
throw new Exception($"Not supported function {functionInfo.Name} inside non-static and non-scripting class type {classInfo.Name}."); throw new Exception($"Not supported function {functionInfo.Name} inside non-static and non-scripting class type {classInfo.Name}.");
GenerateCppWrapperFunction(buildData, contents, classInfo, functionInfo); GenerateCppWrapperFunction(buildData, contents, classInfo, functionInfo);
} }
// Interface implementation // Interface implementation
if (hasInterface) if (hasInterface && useCSharp)
{ {
foreach (var interfaceInfo in classInfo.Interfaces) foreach (var interfaceInfo in classInfo.Interfaces)
{ {
@@ -1612,11 +1634,16 @@ namespace Flax.Build.Bindings
{ {
foreach (var eventInfo in classInfo.Events) foreach (var eventInfo in classInfo.Events)
{ {
contents.AppendLine($" ADD_INTERNAL_CALL(\"{classTypeNameManagedInternalCall}::Internal_{eventInfo.Name}_Bind\", &{eventInfo.Name}_ManagedBind);");
// Register scripting event binder // Register scripting event binder
contents.AppendLine($" ScriptingEvents::EventsTable[Pair<ScriptingTypeHandle, StringView>({classTypeNameNative}::TypeInitializer, StringView(TEXT(\"{eventInfo.Name}\"), {eventInfo.Name.Length}))] = (void(*)(ScriptingObject*, void*, bool)){classTypeNameInternal}Internal::{eventInfo.Name}_Bind;"); contents.AppendLine($" ScriptingEvents::EventsTable[Pair<ScriptingTypeHandle, StringView>({classTypeNameNative}::TypeInitializer, StringView(TEXT(\"{eventInfo.Name}\"), {eventInfo.Name.Length}))] = (void(*)(ScriptingObject*, void*, bool)){classTypeNameInternal}Internal::{eventInfo.Name}_Bind;");
} }
}
if (useScripting && useCSharp)
{
foreach (var eventInfo in classInfo.Events)
{
contents.AppendLine($" ADD_INTERNAL_CALL(\"{classTypeNameManagedInternalCall}::Internal_{eventInfo.Name}_Bind\", &{eventInfo.Name}_ManagedBind);");
}
foreach (var fieldInfo in classInfo.Fields) foreach (var fieldInfo in classInfo.Fields)
{ {
if (fieldInfo.Getter != null) if (fieldInfo.Getter != null)
@@ -1720,6 +1747,7 @@ namespace Flax.Build.Bindings
var structureTypeNameInternal = structureInfo.NativeName; var structureTypeNameInternal = structureInfo.NativeName;
if (structureInfo.Parent != null && !(structureInfo.Parent is FileInfo)) if (structureInfo.Parent != null && !(structureInfo.Parent is FileInfo))
structureTypeNameInternal = structureInfo.Parent.FullNameNative + '_' + structureTypeNameInternal; structureTypeNameInternal = structureInfo.Parent.FullNameNative + '_' + structureTypeNameInternal;
var useCSharp = EngineConfiguration.WithCSharp(buildData.TargetOptions);
if (structureInfo.IsAutoSerialization) if (structureInfo.IsAutoSerialization)
GenerateCppAutoSerialization(buildData, contents, moduleInfo, structureInfo, structureTypeNameNative); GenerateCppAutoSerialization(buildData, contents, moduleInfo, structureInfo, structureTypeNameNative);
@@ -1786,12 +1814,15 @@ namespace Flax.Build.Bindings
contents.AppendLine(" static void InitRuntime()"); contents.AppendLine(" static void InitRuntime()");
contents.AppendLine(" {"); contents.AppendLine(" {");
foreach (var fieldInfo in structureInfo.Fields) if (useCSharp)
{ {
if (fieldInfo.Getter != null) foreach (var fieldInfo in structureInfo.Fields)
contents.AppendLine($" ADD_INTERNAL_CALL(\"{structureTypeNameManagedInternalCall}::Internal_{fieldInfo.Getter.UniqueName}\", &{fieldInfo.Getter.UniqueName});"); {
if (fieldInfo.Setter != null) if (fieldInfo.Getter != null)
contents.AppendLine($" ADD_INTERNAL_CALL(\"{structureTypeNameManagedInternalCall}::Internal_{fieldInfo.Setter.UniqueName}\", &{fieldInfo.Setter.UniqueName});"); contents.AppendLine($" ADD_INTERNAL_CALL(\"{structureTypeNameManagedInternalCall}::Internal_{fieldInfo.Getter.UniqueName}\", &{fieldInfo.Getter.UniqueName});");
if (fieldInfo.Setter != null)
contents.AppendLine($" ADD_INTERNAL_CALL(\"{structureTypeNameManagedInternalCall}::Internal_{fieldInfo.Setter.UniqueName}\", &{fieldInfo.Setter.UniqueName});");
}
} }
contents.AppendLine(" }").AppendLine(); contents.AppendLine(" }").AppendLine();
@@ -1814,28 +1845,41 @@ namespace Flax.Build.Bindings
contents.AppendLine($" *({structureTypeNameNative}*)dst = *({structureTypeNameNative}*)src;"); contents.AppendLine($" *({structureTypeNameNative}*)dst = *({structureTypeNameNative}*)src;");
contents.AppendLine(" }").AppendLine(); contents.AppendLine(" }").AppendLine();
// Boxing structures from native data to managed object if (useCSharp)
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h"); {
if (!structureInfo.IsPod && !CppUsedNonPodTypes.Contains(structureInfo)) // Boxing structures from native data to managed object
CppUsedNonPodTypes.Add(structureInfo); CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
contents.AppendLine(" static MonoObject* Box(void* ptr)"); if (!structureInfo.IsPod && !CppUsedNonPodTypes.Contains(structureInfo))
contents.AppendLine(" {"); CppUsedNonPodTypes.Add(structureInfo);
contents.AppendLine($" MonoObject* managed = mono_object_new(mono_domain_get(), {structureTypeNameNative}::TypeInitializer.GetType().ManagedClass->GetNative());"); contents.AppendLine(" static MObject* Box(void* ptr)");
if (structureInfo.IsPod) contents.AppendLine(" {");
contents.AppendLine($" Platform::MemoryCopy(mono_object_unbox(managed), ptr, sizeof({structureTypeNameNative}));"); contents.AppendLine($" MonoObject* managed = mono_object_new(mono_domain_get(), {structureTypeNameNative}::TypeInitializer.GetType().ManagedClass->GetNative());");
else if (structureInfo.IsPod)
contents.AppendLine($" *({structureInfo.NativeName}Managed*)mono_object_unbox(managed) = ToManaged(*({structureTypeNameNative}*)ptr);"); contents.AppendLine($" Platform::MemoryCopy(mono_object_unbox(managed), ptr, sizeof({structureTypeNameNative}));");
contents.AppendLine(" return managed;"); else
contents.AppendLine(" }").AppendLine(); contents.AppendLine($" *({structureInfo.NativeName}Managed*)mono_object_unbox(managed) = ToManaged(*({structureTypeNameNative}*)ptr);");
contents.AppendLine(" return managed;");
contents.AppendLine(" }").AppendLine();
// Unboxing structures from managed object to native data // Unboxing structures from managed object to native data
contents.AppendLine(" static void Unbox(void* ptr, MonoObject* managed)"); contents.AppendLine(" static void Unbox(void* ptr, MObject* managed)");
contents.AppendLine(" {"); contents.AppendLine(" {");
if (structureInfo.IsPod) if (structureInfo.IsPod)
contents.AppendLine($" Platform::MemoryCopy(ptr, mono_object_unbox(managed), sizeof({structureTypeNameNative}));"); contents.AppendLine($" Platform::MemoryCopy(ptr, mono_object_unbox(managed), sizeof({structureTypeNameNative}));");
else
contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(*({structureInfo.NativeName}Managed*)mono_object_unbox(managed));");
contents.AppendLine(" }").AppendLine();
}
else else
contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(*({structureInfo.NativeName}Managed*)mono_object_unbox(managed));"); {
contents.AppendLine(" }").AppendLine(); contents.AppendLine(" static MObject* Box(void* ptr)");
contents.AppendLine(" {");
contents.AppendLine(" return nullptr;");
contents.AppendLine(" }").AppendLine();
contents.AppendLine(" static void Unbox(void* ptr, MObject* managed)");
contents.AppendLine(" {");
contents.AppendLine(" }").AppendLine();
}
// Getter for structure field // Getter for structure field
contents.AppendLine(" static void GetField(void* ptr, const String& name, Variant& value)"); contents.AppendLine(" static void GetField(void* ptr, const String& name, Variant& value)");
@@ -2060,6 +2104,9 @@ namespace Flax.Build.Bindings
CppVariantToTypes.Clear(); CppVariantToTypes.Clear();
CppVariantFromTypes.Clear(); CppVariantFromTypes.Clear();
// Disable C# scripting based on configuration
ScriptingLangInfos[0].Enabled = EngineConfiguration.WithCSharp(buildData.TargetOptions);
contents.AppendLine("// This code was auto-generated. Do not modify it."); contents.AppendLine("// This code was auto-generated. Do not modify it.");
contents.AppendLine(); contents.AppendLine();
contents.AppendLine("#include \"Engine/Core/Compiler.h\""); contents.AppendLine("#include \"Engine/Core/Compiler.h\"");
@@ -2174,8 +2221,11 @@ namespace Flax.Build.Bindings
// Non-POD types // Non-POD types
CppUsedNonPodTypesList.Clear(); CppUsedNonPodTypesList.Clear();
for (int k = 0; k < CppUsedNonPodTypes.Count; k++) if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
GenerateCppCppUsedNonPodTypes(buildData, CppUsedNonPodTypes[k]); {
for (int k = 0; k < CppUsedNonPodTypes.Count; k++)
GenerateCppCppUsedNonPodTypes(buildData, CppUsedNonPodTypes[k]);
}
foreach (var apiType in CppUsedNonPodTypesList) foreach (var apiType in CppUsedNonPodTypesList)
{ {
header.AppendLine(); header.AppendLine();

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Flax.Build.NativeCpp; using Flax.Build.NativeCpp;
@@ -34,8 +35,20 @@ namespace Flax.Build.Bindings
/// The generated C# file path that contains a API bindings wrapper code to setup the glue code. /// The generated C# file path that contains a API bindings wrapper code to setup the glue code.
/// </summary> /// </summary>
public string GeneratedCSharpFilePath; public string GeneratedCSharpFilePath;
/// <summary>
/// The custom data per-scripting language.
/// </summary>
public Dictionary<string, string> CustomScriptingData;
} }
public delegate void GenerateModuleBindingsDelegate(BuildData buildData, IGrouping<string, Module> binaryModule);
public delegate void GenerateBinaryModuleBindingsDelegate(BuildData buildData, ModuleInfo moduleInfo, ref BindingsResult bindings);
public static event GenerateModuleBindingsDelegate GenerateModuleBindings;
public static event GenerateBinaryModuleBindingsDelegate GenerateBinaryModuleBindings;
public static ModuleInfo ParseModule(BuildData buildData, Module module, BuildOptions moduleOptions = null) public static ModuleInfo ParseModule(BuildData buildData, Module module, BuildOptions moduleOptions = null)
{ {
if (buildData.ModulesInfo.TryGetValue(module, out var moduleInfo)) if (buildData.ModulesInfo.TryGetValue(module, out var moduleInfo))
@@ -513,7 +526,7 @@ namespace Flax.Build.Bindings
buildData.Modules.TryGetValue(moduleInfo.Module, out var moduleBuildInfo); buildData.Modules.TryGetValue(moduleInfo.Module, out var moduleBuildInfo);
// Ensure that generated files are included into build // Ensure that generated files are included into build
if (!moduleBuildInfo.SourceFiles.Contains(bindings.GeneratedCSharpFilePath)) if (EngineConfiguration.WithCSharp(buildData.TargetOptions) && !moduleBuildInfo.SourceFiles.Contains(bindings.GeneratedCSharpFilePath))
moduleBuildInfo.SourceFiles.Add(bindings.GeneratedCSharpFilePath); moduleBuildInfo.SourceFiles.Add(bindings.GeneratedCSharpFilePath);
} }
@@ -533,10 +546,12 @@ namespace Flax.Build.Bindings
Log.Verbose($"Generating API bindings for {module.Name} ({moduleInfo.Name})"); Log.Verbose($"Generating API bindings for {module.Name} ({moduleInfo.Name})");
using (new ProfileEventScope("Cpp")) using (new ProfileEventScope("Cpp"))
GenerateCpp(buildData, moduleInfo, ref bindings); GenerateCpp(buildData, moduleInfo, ref bindings);
using (new ProfileEventScope("CSharp")) if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
GenerateCSharp(buildData, moduleInfo, ref bindings); {
using (new ProfileEventScope("CSharp"))
// TODO: add support for extending this code and support generating bindings for other scripting languages GenerateCSharp(buildData, moduleInfo, ref bindings);
}
GenerateBinaryModuleBindings?.Invoke(buildData, moduleInfo, ref bindings);
} }
} }
@@ -552,9 +567,11 @@ namespace Flax.Build.Bindings
// Generate bindings for binary module // Generate bindings for binary module
Log.Verbose($"Generating binary module bindings for {binaryModule.Key}"); Log.Verbose($"Generating binary module bindings for {binaryModule.Key}");
GenerateCpp(buildData, binaryModule); GenerateCpp(buildData, binaryModule);
GenerateCSharp(buildData, binaryModule); if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
{
// TODO: add support for extending this code and support generating bindings for other scripting languages GenerateCSharp(buildData, binaryModule);
}
GenerateModuleBindings?.Invoke(buildData, binaryModule);
} }
} }
} }

View File

@@ -15,7 +15,7 @@ namespace Flax.Build
throw new NotImplementedException("TODO: building C# targets"); throw new NotImplementedException("TODO: building C# targets");
} }
private static void BuildTargetBindings(RulesAssembly rules, TaskGraph graph, BuildData buildData) private static void BuildTargetBindings(TaskGraph graph, BuildData buildData)
{ {
var workspaceRoot = buildData.TargetOptions.WorkingDirectory; var workspaceRoot = buildData.TargetOptions.WorkingDirectory;
var args = new List<string>(); var args = new List<string>();

View File

@@ -167,6 +167,7 @@ namespace Flax.Build
public static event Action<TaskGraph, BuildOptions> PreBuild; public static event Action<TaskGraph, BuildOptions> PreBuild;
public static event Action<TaskGraph, BuildOptions> PostBuild; public static event Action<TaskGraph, BuildOptions> PostBuild;
public static event Action<TaskGraph, BuildData> BuildBindings;
/// <summary> /// <summary>
/// Collects the modules required by the given target to build (includes dependencies). /// Collects the modules required by the given target to build (includes dependencies).
@@ -226,6 +227,20 @@ namespace Flax.Build
return buildData.Modules; return buildData.Modules;
} }
private static void OnBuildBindings(BuildData buildData, TaskGraph graph)
{
if (buildData.Target.IsPreBuilt)
return;
using (new ProfileEventScope("BuildBindings"))
{
if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
{
BuildTargetBindings(graph, buildData);
}
BuildBindings?.Invoke(graph, buildData);
}
}
private static void LinkNativeBinary(BuildData buildData, BuildOptions buildOptions, string outputPath) private static void LinkNativeBinary(BuildData buildData, BuildOptions buildOptions, string outputPath)
{ {
using (new ProfileEventScope("LinkNativeBinary")) using (new ProfileEventScope("LinkNativeBinary"))
@@ -794,13 +809,7 @@ namespace Flax.Build
} }
// Build scripting API bindings // Build scripting API bindings
using (new ProfileEventScope("BuildBindings")) OnBuildBindings(buildData, graph);
{
if (!buildData.Target.IsPreBuilt)
{
BuildTargetBindings(rules, graph, buildData);
}
}
// Link modules into a target // Link modules into a target
var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions); var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions);
@@ -835,7 +844,7 @@ namespace Flax.Build
var binaryModuleInfo = new BuildTargetBinaryModuleInfo var binaryModuleInfo = new BuildTargetBinaryModuleInfo
{ {
Name = binaryModule.Key, Name = binaryModule.Key,
ManagedPath = Path.Combine(outputPath, binaryModule.Key + ".CSharp.dll"), ManagedPath = EngineConfiguration.WithCSharp(targetBuildOptions) ? Path.Combine(outputPath, binaryModule.Key + ".CSharp.dll") : string.Empty,
}; };
switch (target.LinkType) switch (target.LinkType)
{ {
@@ -1069,11 +1078,7 @@ namespace Flax.Build
} }
// Build scripting API bindings // Build scripting API bindings
using (new ProfileEventScope("BuildBindings")) OnBuildBindings(buildData, graph);
{
if (!buildData.Target.IsPreBuilt)
BuildTargetBindings(rules, graph, buildData);
}
// Link modules into a target // Link modules into a target
var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions); var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions);
@@ -1099,7 +1104,7 @@ namespace Flax.Build
var binaryModuleInfo = new BuildTargetBinaryModuleInfo var binaryModuleInfo = new BuildTargetBinaryModuleInfo
{ {
Name = binaryModule.Key, Name = binaryModule.Key,
ManagedPath = Path.Combine(outputPath, binaryModule.Key + ".CSharp.dll"), ManagedPath = EngineConfiguration.WithCSharp(targetBuildOptions) ? Path.Combine(outputPath, binaryModule.Key + ".CSharp.dll") : string.Empty,
}; };
binaryModuleInfo.NativePathProcessed = string.Empty; binaryModuleInfo.NativePathProcessed = string.Empty;

View File

@@ -17,7 +17,11 @@ namespace Flax.Build.Plugins
base.Init(); base.Init();
BindingsGenerator.GenerateCppScriptWrapperFunction += OnGenerateCppScriptWrapperFunction; BindingsGenerator.GenerateCppScriptWrapperFunction += OnGenerateCppScriptWrapperFunction;
BindingsGenerator.CppScriptObjectVirtualWrapperMethodsPostfixes.Add("_VisualScriptWrapper"); BindingsGenerator.ScriptingLangInfos.Add(new BindingsGenerator.ScriptingLangInfo
{
Enabled = true,
VirtualWrapperMethodsPostfix = "_VisualScriptWrapper",
});
} }
private void OnGenerateCppScriptWrapperFunction(Builder.BuildData buildData, VirtualClassInfo classInfo, FunctionInfo functionInfo, int scriptVTableSize, int scriptVTableIndex, StringBuilder contents) private void OnGenerateCppScriptWrapperFunction(Builder.BuildData buildData, VirtualClassInfo classInfo, FunctionInfo functionInfo, int scriptVTableSize, int scriptVTableIndex, StringBuilder contents)

View File

@@ -67,6 +67,12 @@ namespace Flax.Build
options.CompileEnv.IncludePaths.Add(Path.Combine(Project.ProjectFolderPath, "Source")); options.CompileEnv.IncludePaths.Add(Path.Combine(Project.ProjectFolderPath, "Source"));
options.LinkEnv.LibraryPaths.Add(depsRoot); options.LinkEnv.LibraryPaths.Add(depsRoot);
// Ensure to propagate no-C# scripting define to the whole codebase
if (!EngineConfiguration.WithCSharp(options))
{
options.CompileEnv.PreprocessorDefinitions.Add("COMPILE_WITHOUT_CSHARP");
}
// Add include paths for referenced projects sources // Add include paths for referenced projects sources
foreach (var reference in Project.References) foreach (var reference in Project.References)
{ {

View File

@@ -212,4 +212,21 @@ namespace Flax.Build
/// </summary> /// </summary>
public static List<string> CustomDefines = new List<string>(); public static List<string> CustomDefines = new List<string>();
} }
/// <summary>
/// The engine configuration options.
/// </summary>
public static partial class EngineConfiguration
{
/// <summary>
/// True if managed C# scripting should be enabled, otherwise false. Engine without C# is partially supported and can be used when porting to a new platform before implementing C# runtime on it.
/// </summary>
[CommandLine("useCSharp", "0 to disable C# support in build")]
public static bool UseCSharp = true;
public static bool WithCSharp(NativeCpp.BuildOptions options)
{
return UseCSharp || options.Target.IsEditor;
}
}
} }

View File

@@ -38,6 +38,7 @@ namespace Flax.Build
{ {
// Setup // Setup
CommandLine.Configure(typeof(Configuration)); CommandLine.Configure(typeof(Configuration));
CommandLine.Configure(typeof(EngineConfiguration));
foreach (var option in CommandLine.GetOptions()) foreach (var option in CommandLine.GetOptions())
{ {
if (option.Name.Length > 1 && option.Name[0] == 'D') if (option.Name.Length > 1 && option.Name[0] == 'D')