Add support for compiling and running engine without C# scripting
(configurable via `EngineConfiguration.UseCSharp` in Flax.Build)
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "GameCooker.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MTypes.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
@@ -450,7 +451,7 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
}
|
||||
|
||||
MCore::AttachThread();
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
auto list = (MonoArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -486,7 +487,7 @@ bool GameCookerImpl::Build()
|
||||
Steps.Add(New<PostProcessStep>());
|
||||
}
|
||||
|
||||
MCore::Instance()->AttachThread();
|
||||
MCore::AttachThread();
|
||||
|
||||
// Build Started
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
|
||||
@@ -11,5 +11,7 @@ class CustomEditorsUtil
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
static MonoReflectionType* GetCustomEditor(MonoReflectionType* refType);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ void OnVisualScriptingDebugFlow()
|
||||
flowInfo.ScriptInstance = stack->Instance ? stack->Instance->GetOrCreateManagedInstance() : nullptr;
|
||||
flowInfo.NodeId = stack->Node->ID;
|
||||
flowInfo.BoxId = stack->Box->ID;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
void* params[1];
|
||||
params[0] = &flowInfo;
|
||||
Internal_OnVisualScriptingDebugFlow->Invoke(nullptr, params, &exception);
|
||||
@@ -191,7 +191,7 @@ void ManagedEditor::Init()
|
||||
{
|
||||
LOG(Fatal, "Failed to create editor instance.");
|
||||
}
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
bool isHeadless = CommandLine::Options.Headless.IsTrue();
|
||||
bool skipCompile = CommandLine::Options.SkipCompile.IsTrue();
|
||||
bool newProject = CommandLine::Options.NewProject.IsTrue();
|
||||
@@ -259,7 +259,7 @@ void ManagedEditor::Update()
|
||||
}
|
||||
|
||||
// Call update
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
UpdateMethod->Invoke(instance, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -291,7 +291,7 @@ void ManagedEditor::Exit()
|
||||
{
|
||||
LOG(Fatal, "Invalid Editor assembly!");
|
||||
}
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
exitMethod->Invoke(instance, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
|
||||
@@ -456,7 +456,7 @@ void ScriptsBuilderImpl::CallCompileEvent(EventData& data)
|
||||
LOG(Fatal, "Invalid Editor assembly!");
|
||||
}
|
||||
}
|
||||
/*MonoObject* exception = nullptr;
|
||||
/*MObject* exception = nullptr;
|
||||
void* args[1];
|
||||
args[0] = &data.Type;
|
||||
Internal_OnEvent->Invoke(nullptr, args, &exception);
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
struct InternalInitData
|
||||
@@ -80,15 +83,20 @@ namespace AnimGraphInternal
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void AnimGraphExecutor::initRuntime()
|
||||
{
|
||||
#if USE_MONO
|
||||
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_HasConnection", &AnimGraphInternal::HasConnection);
|
||||
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetInputValue", &AnimGraphInternal::GetInputValue);
|
||||
ADD_INTERNAL_CALL("FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData", &AnimGraphInternal::GetOutputImpulseData);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value& value)
|
||||
{
|
||||
#if USE_MONO
|
||||
auto& context = Context.Get();
|
||||
if (context.ValueCache.TryGet(boxBase, value))
|
||||
return;
|
||||
@@ -124,7 +132,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
|
||||
// Evaluate node
|
||||
void* params[1];
|
||||
params[0] = &internalContext;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
MonoObject* result = data.Evaluate->Invoke(obj, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -136,6 +144,7 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
|
||||
// Extract result
|
||||
value = MUtils::UnboxVariant(result);
|
||||
context.ValueCache.Add(boxBase, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AnimGraph::IsReady() const
|
||||
@@ -156,13 +165,16 @@ void AnimGraph::ClearCustomNode(Node* node)
|
||||
data.Evaluate = nullptr;
|
||||
if (data.Handle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(data.Handle);
|
||||
#endif
|
||||
data.Handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimGraph::InitCustomNode(Node* node)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Fetch the node logic controller type
|
||||
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();
|
||||
void* params[1];
|
||||
params[0] = &initData;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
load->Invoke(obj, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -227,7 +239,7 @@ bool AnimGraph::InitCustomNode(Node* node)
|
||||
auto& data = node->Data.Custom;
|
||||
data.Evaluate = evaluate;
|
||||
data.Handle = handleGC;
|
||||
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,7 @@ void SceneAnimationPlayer::MapTrack(const StringView& from, const Guid& to)
|
||||
|
||||
void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Restore all tracks
|
||||
for (int32 j = 0; j < anim->Tracks.Count(); j++)
|
||||
{
|
||||
@@ -293,7 +294,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
||||
|| state.RestoreStateIndex == -1
|
||||
|| (state.Field == nullptr && state.Property == nullptr))
|
||||
break;
|
||||
MonoObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject;
|
||||
MObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject;
|
||||
if (!instance)
|
||||
break;
|
||||
|
||||
@@ -318,7 +319,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
||||
{
|
||||
if (state.Property)
|
||||
{
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
state.ManagedObject = state.Property->GetValue(instance, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -341,7 +342,7 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
||||
// Set the value
|
||||
if (state.Property)
|
||||
{
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
state.Property->SetValue(instance, value, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -353,16 +354,17 @@ void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
||||
{
|
||||
state.Field->SetValue(instance, value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case SceneAnimation::Track::Types::KeyframesProperty:
|
||||
@@ -511,17 +513,18 @@ bool SceneAnimationPlayer::TickPropertyTrack(int32 trackIndex, int32 stateIndexO
|
||||
case SceneAnimation::Track::Types::ObjectProperty:
|
||||
{
|
||||
// Cache the sub-object pointer for the sub-tracks
|
||||
state.ManagedObject = *(MonoObject**)target;
|
||||
state.ManagedObject = *(MObject**)target;
|
||||
return false;
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int32 stateIndexOffset, CallStack& callStack)
|
||||
{
|
||||
#if USE_MONO
|
||||
const float fps = anim->FramesPerSecond;
|
||||
#if !BUILD_RELEASE || USE_EDITOR
|
||||
callStack.Add(anim);
|
||||
@@ -827,7 +830,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
break;
|
||||
|
||||
// Skip if parent object is missing
|
||||
MonoObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject;
|
||||
MObject* instance = _tracks[stateIndexOffset + parentTrack.TrackStateIndex].ManagedObject;
|
||||
if (!instance)
|
||||
break;
|
||||
|
||||
@@ -860,7 +863,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
{
|
||||
if (state.Property)
|
||||
{
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
auto boxed = state.Property->GetValue(instance, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -876,7 +879,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
}
|
||||
else
|
||||
{
|
||||
*(MonoObject**)value = boxed;
|
||||
*(MObject**)value = boxed;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -900,7 +903,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
}
|
||||
case SceneAnimation::Track::Types::ObjectReferenceProperty:
|
||||
{
|
||||
auto obj = Scripting::FindObject(*(MonoObject**)value);
|
||||
auto obj = Scripting::FindObject(*(MObject**)value);
|
||||
auto id = obj ? obj->GetID() : Guid::Empty;
|
||||
_restoreData.Add((byte*)&id, sizeof(Guid));
|
||||
break;
|
||||
@@ -922,7 +925,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
value = (void*)*(intptr*)value;
|
||||
if (state.Property)
|
||||
{
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
state.Property->SetValue(instance, value, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -995,7 +998,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
|
||||
// Invoke the method
|
||||
Variant result;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
mono_runtime_invoke((MonoMethod*)state.Method, instance, paramsData, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -1064,6 +1067,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SceneAnimationPlayer::Tick()
|
||||
|
||||
@@ -43,7 +43,7 @@ private:
|
||||
struct TrackInstance
|
||||
{
|
||||
ScriptingObjectReference<ScriptingObject> Object;
|
||||
MonoObject* ManagedObject = nullptr;
|
||||
MObject* ManagedObject = nullptr;
|
||||
MProperty* Property = nullptr;
|
||||
MField* Field = nullptr;
|
||||
void* Method = nullptr;
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Threading/MainThreadTask.h"
|
||||
#include "Engine/Threading/ConcurrentTaskQueue.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
|
||||
#endif
|
||||
|
||||
AssetReferenceBase::~AssetReferenceBase()
|
||||
{
|
||||
@@ -202,7 +204,9 @@ void Asset::OnManagedInstanceDeleted()
|
||||
// Cleanup
|
||||
if (_gcHandle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(_gcHandle);
|
||||
#endif
|
||||
_gcHandle = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets managed instance object (or null if no asset set).
|
||||
/// </summary>
|
||||
FORCE_INLINE MonoObject* GetManagedInstance() const
|
||||
FORCE_INLINE MObject* GetManagedInstance() const
|
||||
{
|
||||
return _asset ? _asset->GetOrCreateManagedInstance() : nullptr;
|
||||
}
|
||||
|
||||
@@ -310,10 +310,17 @@ void VisualScriptExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
|
||||
const StringAsANSI<100> typeNameAnsi(typeName.Get(), typeName.Length());
|
||||
if (StringUtils::Compare(typeNameAnsi.Get(), obj.Type.GetTypeName()) != 0)
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* klass = Scripting::FindClassNative(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
|
||||
MonoClass* objKlass = MUtils::GetClass(obj);
|
||||
if (!klass || !objKlass || mono_class_is_subclass_of(objKlass, klass, false) == 0)
|
||||
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
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Fallback to C#-only types
|
||||
const auto mclass = Scripting::FindClass(StringAnsiView(typeNameAnsi.Get(), typeName.Length()));
|
||||
if (mclass)
|
||||
@@ -461,6 +469,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value&
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (typeName.HasChars())
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets managed instance object (or null if no asset set).
|
||||
/// </summary>
|
||||
FORCE_INLINE MonoObject* GetManagedInstance() const
|
||||
FORCE_INLINE MObject* GetManagedInstance() const
|
||||
{
|
||||
return _asset ? _asset->GetOrCreateManagedInstance() : nullptr;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ VariantType::VariantType(Types type, _MonoClass* klass)
|
||||
{
|
||||
Type = type;
|
||||
TypeName = nullptr;
|
||||
#if USE_MONO
|
||||
if (klass)
|
||||
{
|
||||
MString typeName;
|
||||
@@ -72,6 +73,7 @@ VariantType::VariantType(Types type, _MonoClass* klass)
|
||||
TypeName = static_cast<char*>(Allocator::Allocate(length));
|
||||
Platform::MemoryCopy(TypeName, typeName.Get(), length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VariantType::VariantType(const VariantType& other)
|
||||
@@ -517,12 +519,24 @@ Variant::Variant(Asset* v)
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
Variant::Variant(_MonoObject* v)
|
||||
: Type(VariantType::ManagedObject, v ? mono_object_get_class(v) : nullptr)
|
||||
{
|
||||
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)
|
||||
: Type(VariantType::String)
|
||||
{
|
||||
@@ -788,8 +802,8 @@ Variant::~Variant()
|
||||
case VariantType::Dictionary:
|
||||
Delete(AsDictionary);
|
||||
break;
|
||||
#if USE_MONO
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
if (AsUint)
|
||||
mono_gchandle_free(AsUint);
|
||||
break;
|
||||
@@ -912,7 +926,9 @@ Variant& Variant::operator=(const Variant& other)
|
||||
AsDictionary = New<Dictionary<Variant, Variant>>(*other.AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
AsUint = other.AsUint ? mono_gchandle_new(mono_gchandle_get_target(other.AsUint), true) : 0;
|
||||
#endif
|
||||
break;
|
||||
case VariantType::Null:
|
||||
case VariantType::Void:
|
||||
@@ -1015,9 +1031,6 @@ bool Variant::operator==(const Variant& other) const
|
||||
return false;
|
||||
}
|
||||
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:
|
||||
if (AsBlob.Data == nullptr && other.AsBlob.Data == nullptr)
|
||||
return true;
|
||||
@@ -1026,6 +1039,11 @@ bool Variant::operator==(const Variant& other) const
|
||||
if (other.AsBlob.Data == nullptr)
|
||||
return false;
|
||||
return AsBlob.Length == other.AsBlob.Length && StringUtils::Compare(static_cast<const char*>(AsBlob.Data), static_cast<const char*>(other.AsBlob.Data), AsBlob.Length - 1) == 0;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
// TODO: invoke C# Equality logic?
|
||||
return AsUint == other.AsUint || mono_gchandle_get_target(AsUint) == mono_gchandle_get_target(other.AsUint);
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1115,7 +1133,9 @@ Variant::operator bool() const
|
||||
case VariantType::Asset:
|
||||
return AsAsset != nullptr;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
return AsUint != 0 && mono_gchandle_get_target(AsUint) != nullptr;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1461,7 +1481,9 @@ Variant::operator void*() const
|
||||
case VariantType::Blob:
|
||||
return AsBlob.Data;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
return AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1504,7 +1526,11 @@ Variant::operator ScriptingObject*() const
|
||||
|
||||
Variant::operator _MonoObject*() const
|
||||
{
|
||||
#if USE_MONO
|
||||
return Type.Type == VariantType::ManagedObject && AsUint ? mono_gchandle_get_target(AsUint) : nullptr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
Variant::operator Asset*() const
|
||||
@@ -2011,8 +2037,10 @@ void Variant::SetType(const VariantType& type)
|
||||
Delete(AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
if (AsUint)
|
||||
mono_gchandle_free(AsUint);
|
||||
#endif
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
@@ -2105,8 +2133,10 @@ void Variant::SetType(VariantType&& type)
|
||||
Delete(AsDictionary);
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
#if USE_MONO
|
||||
if (AsUint)
|
||||
mono_gchandle_free(AsUint);
|
||||
#endif
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
@@ -2245,6 +2275,7 @@ void Variant::SetObject(ScriptingObject* object)
|
||||
|
||||
void Variant::SetManagedObject(_MonoObject* object)
|
||||
{
|
||||
#if USE_MONO
|
||||
if (object)
|
||||
{
|
||||
if (Type.Type != VariantType::ManagedObject)
|
||||
@@ -2257,6 +2288,7 @@ void Variant::SetManagedObject(_MonoObject* object)
|
||||
SetType(VariantType(VariantType::ManagedObject));
|
||||
AsUint = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Variant::SetAsset(Asset* asset)
|
||||
@@ -2338,10 +2370,12 @@ String Variant::ToString() const
|
||||
return (*(Ray*)AsBlob.Data).ToString();
|
||||
case VariantType::Matrix:
|
||||
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:
|
||||
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:
|
||||
return String::Empty;
|
||||
}
|
||||
@@ -3110,6 +3144,7 @@ void Variant::AllocStructure()
|
||||
AsBlob.Data = Allocator::Allocate(AsBlob.Length);
|
||||
*((int16*)AsBlob.Data) = 0;
|
||||
}
|
||||
#if USE_MONO
|
||||
else if (const auto mclass = Scripting::FindClass(typeName))
|
||||
{
|
||||
// Fallback to C#-only types
|
||||
@@ -3134,6 +3169,7 @@ void Variant::AllocStructure()
|
||||
AsBlob.Length = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
if (typeName.Length() != 0)
|
||||
@@ -3213,10 +3249,12 @@ uint32 GetHash(const Variant& key)
|
||||
return GetHash(*(Color*)key.AsData);
|
||||
case VariantType::Guid:
|
||||
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:
|
||||
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:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/exception.h>
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
@@ -61,8 +64,11 @@ bool CacheMethods()
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void DebugLog::Log(LogType type, const StringView& message)
|
||||
{
|
||||
#if USE_MONO
|
||||
if (CacheMethods())
|
||||
return;
|
||||
|
||||
@@ -77,34 +83,41 @@ void DebugLog::Log(LogType type, const StringView& message)
|
||||
params.AddParam(stackTrace, scriptsDomain->GetNative());
|
||||
#endif
|
||||
MainThreadManagedInvokeAction::Invoke(Internal_SendLog, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugLog::LogException(MonoObject* exceptionObject)
|
||||
void DebugLog::LogException(MObject* exceptionObject)
|
||||
{
|
||||
#if USE_MONO
|
||||
if (exceptionObject == nullptr || CacheMethods())
|
||||
return;
|
||||
|
||||
MainThreadManagedInvokeAction::ParamsBuilder params;
|
||||
params.AddParam(exceptionObject);
|
||||
MainThreadManagedInvokeAction::Invoke(Internal_SendLogException, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
String DebugLog::GetStackTrace()
|
||||
{
|
||||
String result;
|
||||
#if USE_MONO
|
||||
if (!CacheMethods())
|
||||
{
|
||||
auto stackTraceObj = Internal_GetStackTrace->Invoke(nullptr, nullptr, nullptr);
|
||||
MUtils::ToString((MonoString*)stackTraceObj, result);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
void DebugLog::ThrowException(const char* msg)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Throw exception to the C# world
|
||||
auto ex = mono_exception_from_name_msg(mono_get_corlib(), "System", "Exception", msg);
|
||||
mono_raise_exception(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugLog::ThrowNullReference()
|
||||
@@ -112,35 +125,45 @@ void DebugLog::ThrowNullReference()
|
||||
//LOG(Warning, "Invalid null reference.");
|
||||
//LOG_STR(Warning, DebugLog::GetStackTrace());
|
||||
|
||||
#if USE_MONO
|
||||
// Throw exception to the C# world
|
||||
auto ex = mono_get_exception_null_reference();
|
||||
mono_raise_exception(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugLog::ThrowArgument(const char* arg, const char* msg)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Throw exception to the C# world
|
||||
auto ex = mono_get_exception_argument(arg, msg);
|
||||
mono_raise_exception(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugLog::ThrowArgumentNull(const char* arg)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Throw exception to the C# world
|
||||
auto ex = mono_get_exception_argument_null(arg);
|
||||
mono_raise_exception(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugLog::ThrowArgumentOutOfRange(const char* arg)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Throw exception to the C# world
|
||||
auto ex = mono_get_exception_argument_out_of_range(arg);
|
||||
mono_raise_exception(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugLog::ThrowNotSupported(const char* msg)
|
||||
{
|
||||
#if USE_MONO
|
||||
// Throw exception to the C# world
|
||||
auto ex = mono_get_exception_not_supported(msg);
|
||||
mono_raise_exception(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
/// Logs a formatted exception message to the Flax Console.
|
||||
/// </summary>
|
||||
/// <param name="exceptionObject">Runtime Exception.</param>
|
||||
static void LogException(MonoObject* exceptionObject);
|
||||
static void LogException(MObject* exceptionObject);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ void EngineImpl::InitMainWindow()
|
||||
return;
|
||||
}
|
||||
|
||||
#if !USE_EDITOR
|
||||
#if !USE_EDITOR && !COMPILE_WITHOUT_CSHARP
|
||||
// Inform the managed runtime about the window (game can link GUI to it)
|
||||
auto scriptingClass = Scripting::GetStaticClass();
|
||||
ASSERT(scriptingClass);
|
||||
@@ -613,7 +613,7 @@ void EngineImpl::InitMainWindow()
|
||||
ASSERT(setWindowMethod);
|
||||
void* params[1];
|
||||
params[0] = Engine::MainWindow->GetOrCreateManagedInstance();
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
setWindowMethod->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -106,6 +108,8 @@ namespace
|
||||
return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vertices, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, triangles);
|
||||
}
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
|
||||
template<typename IndexType>
|
||||
bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
||||
{
|
||||
@@ -132,6 +136,8 @@ namespace
|
||||
|
||||
return mesh->UpdateTriangles(triangleCount, ib);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Mesh::HasVertexColors() const
|
||||
@@ -591,6 +597,8 @@ ScriptingObject* Mesh::GetParentModel()
|
||||
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)
|
||||
{
|
||||
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());
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -404,9 +404,11 @@ private:
|
||||
|
||||
// Internal bindings
|
||||
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
|
||||
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if USE_MONO
|
||||
#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)
|
||||
{
|
||||
@@ -316,6 +318,8 @@ ScriptingObject* SkinnedMesh::GetParentModel()
|
||||
return _model;
|
||||
}
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
|
||||
template<typename IndexType>
|
||||
bool UpdateMesh(SkinnedMesh* mesh, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj)
|
||||
{
|
||||
@@ -561,3 +565,5 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
|
||||
ConvertMeshData(mesh, type, resultObj, data.Get());
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -258,7 +258,9 @@ private:
|
||||
|
||||
// Internal bindings
|
||||
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
|
||||
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -20,13 +20,17 @@
|
||||
#include "Engine/Scripting/Script.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Renderer/Lightmaps.h"
|
||||
#else
|
||||
#include "Engine/Engine/Screen.h"
|
||||
#endif
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
// TODO: use API for events and remove this manual wrapper code
|
||||
class RenderContextInternal
|
||||
{
|
||||
@@ -53,6 +57,8 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Array<RenderTask*> RenderTask::Tasks;
|
||||
CriticalSection RenderTask::TasksLocker;
|
||||
int32 RenderTask::TasksDoneLastFrame;
|
||||
@@ -174,7 +180,7 @@ void ManagedPostProcessEffect::FetchInfo()
|
||||
args[0] = Target->GetOrCreateManagedInstance();
|
||||
args[1] = &_location;
|
||||
args[2] = &_useSingleTarget;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
FetchInfoManaged->Invoke(nullptr, args, &exception);
|
||||
if (exception)
|
||||
DebugLog::LogException(exception);
|
||||
@@ -187,6 +193,7 @@ bool ManagedPostProcessEffect::IsLoaded() const
|
||||
|
||||
void ManagedPostProcessEffect::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output)
|
||||
{
|
||||
#if USE_MONO
|
||||
const auto context = GPUDevice::Instance->GetMainContext();
|
||||
auto inputObj = ScriptingObject::ToManaged(input);
|
||||
auto outputObj = ScriptingObject::ToManaged(output);
|
||||
@@ -203,10 +210,11 @@ void ManagedPostProcessEffect::Render(RenderContext& renderContext, GPUTexture*
|
||||
params[1] = &tmp;
|
||||
params[2] = inputObj;
|
||||
params[3] = outputObj;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
renderMethod->InvokeVirtual(Target->GetOrCreateManagedInstance(), params, &exception);
|
||||
if (exception)
|
||||
DebugLog::LogException(exception);
|
||||
#endif
|
||||
}
|
||||
|
||||
SceneRenderTask::SceneRenderTask(const SpawnParams& params)
|
||||
@@ -340,6 +348,8 @@ void SceneRenderTask::OnBegin(GPUContext* context)
|
||||
}
|
||||
|
||||
// Get custom and global PostFx
|
||||
CustomPostFx.Clear();
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// TODO: move postFx in SceneRenderTask from C# to C++
|
||||
static MMethod* GetPostFxManaged = GetStaticClass()->GetMethod("GetPostFx", 1);
|
||||
if (GetPostFxManaged)
|
||||
@@ -347,7 +357,8 @@ void SceneRenderTask::OnBegin(GPUContext* context)
|
||||
int32 count = 0;
|
||||
void* params[1];
|
||||
params[0] = &count;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
#if USE_MONO
|
||||
const auto objects = (MonoArray*)GetPostFxManaged->Invoke(GetOrCreateManagedInstance(), params, &exception);
|
||||
if (exception)
|
||||
DebugLog::LogException(exception);
|
||||
@@ -359,9 +370,9 @@ void SceneRenderTask::OnBegin(GPUContext* context)
|
||||
if (postFx.Target)
|
||||
postFx.FetchInfo();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
CustomPostFx.Clear();
|
||||
#endif
|
||||
|
||||
// Setup render buffers for the output rendering resolution
|
||||
if (Output)
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Animations/CurveSerialization.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
|
||||
#endif
|
||||
|
||||
Spline::Spline(const SpawnParams& params)
|
||||
: Actor(params)
|
||||
@@ -437,6 +439,8 @@ void Spline::UpdateSpline()
|
||||
SplineUpdated();
|
||||
}
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
|
||||
void Spline::GetKeyframes(MonoArray* data)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
|
||||
@@ -368,8 +368,10 @@ protected:
|
||||
private:
|
||||
|
||||
// Internal bindings
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
API_FUNCTION(NoProxy) void GetKeyframes(MonoArray* data);
|
||||
API_FUNCTION(NoProxy) void SetKeyframes(MonoArray* data);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ void SceneObject::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
stream.Guid(_parent->GetID());
|
||||
}
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Handle C# objects data serialization
|
||||
if (Flags & ObjectFlags::IsManagedType)
|
||||
{
|
||||
@@ -130,6 +131,7 @@ void SceneObject::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
ManagedSerialization::Serialize(stream, GetOrCreateManagedInstance());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Handle custom scripting objects data serialization
|
||||
if (Flags & ObjectFlags::IsCustomScriptingType)
|
||||
@@ -146,6 +148,7 @@ void SceneObject::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
// _prefabID is deserialized by Actor/Script impl
|
||||
DESERIALIZE_MEMBER(PrefabObjectID, _prefabObjectID);
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Handle C# objects data serialization
|
||||
if (Flags & ObjectFlags::IsManagedType)
|
||||
{
|
||||
@@ -155,6 +158,7 @@ void SceneObject::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
|
||||
ManagedSerialization::Deserialize(v->value, GetOrCreateManagedInstance());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Handle custom scripting objects data serialization
|
||||
if (Flags & ObjectFlags::IsCustomScriptingType)
|
||||
|
||||
@@ -47,8 +47,6 @@ CultureInfo::CultureInfo(int32 lcid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "Missing CultureInfo implementation."
|
||||
#endif
|
||||
if (!_data)
|
||||
{
|
||||
@@ -89,8 +87,6 @@ CultureInfo::CultureInfo(const StringAnsiView& name)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "Missing CultureInfo implementation."
|
||||
#endif
|
||||
if (!_data)
|
||||
{
|
||||
@@ -132,8 +128,6 @@ bool CultureInfo::IsRightToLeft() const
|
||||
const auto data = static_cast<CultureInfoEntry*>(_data);
|
||||
if (data)
|
||||
return data->text_info.is_right_to_left ? true : false;
|
||||
#else
|
||||
#error "Missing CultureInfo implementation."
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,11 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
#endif
|
||||
|
||||
#if USE_MONO
|
||||
// Helper macros for calling C# events
|
||||
#define BEGIN_INVOKE_EVENT(name, paramsCount) \
|
||||
auto managedInstance = GetManagedInstance(); \
|
||||
@@ -42,7 +45,7 @@
|
||||
params[0] = param0; \
|
||||
params[1] = param1; \
|
||||
params[2] = param2; \
|
||||
MonoObject* exception = nullptr; \
|
||||
MObject* exception = nullptr; \
|
||||
_method_##name->Invoke(managedInstance, params, &exception); \
|
||||
END_INVOKE_EVENT(name)
|
||||
#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++) \
|
||||
*(MonoString**)mono_array_addr_with_size(outputDataMono, sizeof(MonoString*), i) = MUtils::ToString(outputData[i]); \
|
||||
params[2] = outputDataMono; \
|
||||
MonoObject* exception = nullptr; \
|
||||
MObject* exception = nullptr; \
|
||||
auto resultObj = _method_##name->Invoke(GetManagedInstance(), params, &exception); \
|
||||
if (resultObj) \
|
||||
result = (DragDropEffect)MUtils::Unbox<int32>(resultObj); \
|
||||
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)
|
||||
: PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer))
|
||||
|
||||
@@ -21,8 +21,12 @@ Delegate<ScriptingObject*, Span<Variant>, ScriptingTypeHandle, StringView> Scrip
|
||||
|
||||
ManagedBinaryModule* GetBinaryModuleCorlib()
|
||||
{
|
||||
#if COMPILE_WITHOUT_CSHARP
|
||||
return nullptr;
|
||||
#else
|
||||
static ManagedBinaryModule assembly("corlib", MAssemblyOptions(false)); // Don't precache all corlib classes
|
||||
return &assembly;
|
||||
#endif
|
||||
}
|
||||
|
||||
ScriptingTypeHandle::ScriptingTypeHandle(const ScriptingTypeInitializer& initializer)
|
||||
@@ -698,6 +702,8 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
return object;
|
||||
}
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
|
||||
namespace
|
||||
{
|
||||
MMethod* FindMethod(MClass* mclass, const MMethod* referenceMethod)
|
||||
@@ -719,6 +725,8 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature)
|
||||
{
|
||||
if (!mclass)
|
||||
@@ -726,6 +734,7 @@ MMethod* ManagedBinaryModule::FindMethod(MClass* mclass, const ScriptingTypeMeth
|
||||
const auto& methods = mclass->GetMethods();
|
||||
for (MMethod* method : methods)
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoMethodSignature* sig = mono_method_signature(method->GetNative());
|
||||
if (method->IsStatic() != signature.IsStatic ||
|
||||
method->GetName() != signature.Name ||
|
||||
@@ -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)))
|
||||
return method;
|
||||
#endif
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
ManagedBinaryModule* ManagedBinaryModule::FindModule(MonoClass* klass)
|
||||
{
|
||||
// TODO: consider caching lookup table MonoImage* -> ManagedBinaryModule*
|
||||
@@ -782,6 +794,8 @@ ScriptingTypeHandle ManagedBinaryModule::FindType(MonoClass* klass)
|
||||
return ScriptingTypeHandle();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ManagedBinaryModule::OnLoading(MAssembly* assembly)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
@@ -793,6 +807,7 @@ void ManagedBinaryModule::OnLoading(MAssembly* assembly)
|
||||
|
||||
void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
PROFILE_CPU();
|
||||
ASSERT(ClassToTypeIndex.IsEmpty());
|
||||
|
||||
@@ -849,10 +864,12 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
InitType(mclass);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ManagedBinaryModule::InitType(MClass* mclass)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Skip if already initialized
|
||||
const MString& typeName = mclass->GetFullName();
|
||||
if (TypeNameToTypeIndex.ContainsKey(typeName))
|
||||
@@ -992,6 +1009,7 @@ void ManagedBinaryModule::InitType(MClass* mclass)
|
||||
// Move to the next entry (table is null terminated)
|
||||
scriptVTable++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
|
||||
@@ -1020,7 +1038,9 @@ void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
|
||||
type.Script.ScriptVTable = nullptr;
|
||||
}
|
||||
}
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
ClassToTypeIndex.Clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
const StringAnsi& ManagedBinaryModule::GetName() const
|
||||
@@ -1030,7 +1050,11 @@ const StringAnsi& ManagedBinaryModule::GetName() const
|
||||
|
||||
bool ManagedBinaryModule::IsLoaded() const
|
||||
{
|
||||
#if COMPILE_WITHOUT_CSHARP
|
||||
return true;
|
||||
#else
|
||||
return Assembly->IsLoaded();
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#if USE_MONO
|
||||
const auto mMethod = (MMethod*)method;
|
||||
MonoMethodSignature* signature = mono_method_signature(mMethod->GetNative());
|
||||
void* signatureParams = nullptr;
|
||||
@@ -1101,7 +1126,7 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
|
||||
}
|
||||
|
||||
// Invoke the method
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
MonoObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MonoObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -1164,10 +1189,14 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSignature& signature)
|
||||
{
|
||||
#if USE_MONO
|
||||
const auto mMethod = (MMethod*)method;
|
||||
signature.Name = mMethod->GetName();
|
||||
signature.IsStatic = mMethod->IsStatic();
|
||||
@@ -1183,6 +1212,7 @@ void ManagedBinaryModule::GetMethodSignature(void* method, ScriptingTypeMethodSi
|
||||
param.Type = MoveTemp(MUtils::UnboxVariantType(((MonoType**)signatureParams)[paramIdx]));
|
||||
param.IsOut = mono_signature_param_is_out(sig, paramIdx) != 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#if USE_MONO
|
||||
const auto mField = (MField*)field;
|
||||
fieldSignature.Name = mField->GetName();
|
||||
fieldSignature.ValueType = MoveTemp(MUtils::UnboxVariantType(mField->GetType().GetNative()));
|
||||
fieldSignature.IsStatic = mField->IsStatic();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Variant& result)
|
||||
{
|
||||
#if USE_MONO
|
||||
const auto mField = (MField*)field;
|
||||
|
||||
// Get instance object
|
||||
@@ -1225,10 +1258,14 @@ bool ManagedBinaryModule::GetFieldValue(void* field, const Variant& instance, Va
|
||||
MonoObject* resultObject = mField->GetValueBoxed(instanceObject);
|
||||
result = MUtils::UnboxVariant(resultObject);
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value)
|
||||
{
|
||||
#if USE_MONO
|
||||
const auto mField = (MField*)field;
|
||||
|
||||
// Get instance object
|
||||
@@ -1253,6 +1290,9 @@ bool ManagedBinaryModule::SetFieldValue(void* field, const Variant& instance, Va
|
||||
bool failed = false;
|
||||
mField->SetValue(instanceObject, MUtils::VariantToManagedArgPtr(value, mField->GetType(), failed));
|
||||
return failed;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ManagedBinaryModule::Destroy(bool isReloading)
|
||||
|
||||
@@ -290,15 +290,19 @@ public:
|
||||
/// </summary>
|
||||
MAssembly* Assembly;
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
/// <summary>
|
||||
/// The scripting types cache that maps the managed class to the scripting type index. Build after assembly is loaded and scripting types get the managed classes information.
|
||||
/// </summary>
|
||||
Dictionary<MonoClass*, int32, HeapAllocation> ClassToTypeIndex;
|
||||
#endif
|
||||
|
||||
static ScriptingObject* ManagedObjectSpawn(const ScriptingObjectSpawnParams& params);
|
||||
static MMethod* FindMethod(MClass* mclass, const ScriptingTypeMethodSignature& signature);
|
||||
#if USE_MONO
|
||||
static ManagedBinaryModule* FindModule(MonoClass* klass);
|
||||
static ScriptingTypeHandle FindType(MonoClass* klass);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
#include "Engine/Core/Log.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);
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
namespace UtilsInternal
|
||||
{
|
||||
MonoObject* ExtractArrayFromList(MonoObject* obj)
|
||||
@@ -70,9 +72,12 @@ namespace FlaxLogWriterInternal
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void registerFlaxEngineInternalCalls()
|
||||
{
|
||||
AnimGraphExecutor::initRuntime();
|
||||
#if USE_MONO
|
||||
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &Platform::MemoryCopy);
|
||||
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &Platform::MemoryClear);
|
||||
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_LogException", &DebugLogHandlerInternal::LogException);
|
||||
ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MField.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/appdomain.h>
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
|
||||
@@ -15,7 +16,7 @@
|
||||
struct ManagedBitArray
|
||||
{
|
||||
template<typename AllocationType = HeapAllocation>
|
||||
static MonoObject* ToManaged(const BitArray<AllocationType>& data)
|
||||
static MObject* ToManaged(const BitArray<AllocationType>& data)
|
||||
{
|
||||
#if 0
|
||||
// TODO: use actual System.Collections.BitArray for BitArray interop
|
||||
@@ -53,3 +54,5 @@ struct ManagedBitArray
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
struct FLAXENGINE_API ManagedDictionary
|
||||
@@ -93,7 +94,7 @@ struct FLAXENGINE_API ManagedDictionary
|
||||
void* params[2];
|
||||
params[0] = genericType;
|
||||
params[1] = genericArgs;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
auto dictionaryType = makeGenericMethod->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -127,7 +128,7 @@ struct FLAXENGINE_API ManagedDictionary
|
||||
params[0] = Instance;
|
||||
params[1] = key;
|
||||
params[2] = value;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
mono_runtime_invoke(addDictionaryItemMethod->GetNative(), Instance, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -159,3 +160,5 @@ struct FLAXENGINE_API ManagedDictionary
|
||||
return mono_runtime_invoke(getItemMethod, Instance, params, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
#include "MException.h"
|
||||
#include "ManagedCLR/MUtils.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
|
||||
#endif
|
||||
|
||||
MException::MException(MonoObject* exception)
|
||||
MException::MException(MObject* exception)
|
||||
: InnerException(nullptr)
|
||||
{
|
||||
#if USE_MONO
|
||||
ASSERT(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);
|
||||
if (innerException)
|
||||
InnerException = New<MException>(innerException);
|
||||
#endif
|
||||
}
|
||||
|
||||
MException::~MException()
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MException"/> class.
|
||||
/// </summary>
|
||||
@@ -38,12 +39,13 @@ public:
|
||||
: MException((MonoObject*)exception)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception object.</param>
|
||||
explicit MException(MonoObject* exception);
|
||||
explicit MException(MObject* exception);
|
||||
|
||||
/// <summary>
|
||||
/// Disposes a instance of the <see cref="MException"/> class.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "Engine/Scripting/ScriptingCalls.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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
void* paramsData[8];
|
||||
params.GetParams(paramsData);
|
||||
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
method->Invoke(instance, paramsData, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -82,14 +82,13 @@ bool MainThreadManagedInvokeAction::Run()
|
||||
void* paramsData[8];
|
||||
_params.GetParams(paramsData);
|
||||
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
if (_method)
|
||||
{
|
||||
_method->Invoke(_instance, paramsData, &exception);
|
||||
}
|
||||
else
|
||||
else if (_methodThunk)
|
||||
{
|
||||
ASSERT(_methodThunk);
|
||||
switch (_params.Count)
|
||||
{
|
||||
case 0:
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
AddParam(val);
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
FORCE_INLINE void AddParam(const String& value)
|
||||
{
|
||||
MonoString* val = MUtils::ToString(value);
|
||||
@@ -94,6 +95,7 @@ public:
|
||||
MonoString* val = MUtils::ToString(value, domain);
|
||||
AddParam(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
void GetParams(void* params[8])
|
||||
{
|
||||
@@ -109,7 +111,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
MonoObject* _instance;
|
||||
MObject* _instance;
|
||||
MMethod* _method;
|
||||
void* _methodThunk;
|
||||
LogType _exceptionLevel;
|
||||
@@ -117,7 +119,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
MainThreadManagedInvokeAction(MonoObject* instance, MMethod* method, LogType exceptionLevel)
|
||||
MainThreadManagedInvokeAction(MObject* instance, MMethod* method, LogType exceptionLevel)
|
||||
: _instance(instance)
|
||||
, _method(method)
|
||||
, _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)
|
||||
, _method(method)
|
||||
, _methodThunk(nullptr)
|
||||
@@ -153,7 +155,7 @@ public:
|
||||
/// <param name="instance">The managed instance object.</param>
|
||||
/// <param name="exceptionLevel">The exception logging error level.</param>
|
||||
/// <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>
|
||||
/// 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="exceptionLevel">The exception logging error level.</param>
|
||||
/// <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>
|
||||
/// 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="instance">The managed instance object.</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:
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MAssembly.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MClass.h"
|
||||
#include "MDomain.h"
|
||||
#include "MUtils.h"
|
||||
@@ -19,14 +16,14 @@
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.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/assembly.h>
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/tokentype.h>
|
||||
#endif
|
||||
|
||||
MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options)
|
||||
: _monoAssembly(nullptr)
|
||||
, _monoImage(nullptr)
|
||||
, _domain(domain)
|
||||
: _domain(domain)
|
||||
, _isLoaded(false)
|
||||
, _isLoading(false)
|
||||
, _isDependency(false)
|
||||
@@ -83,6 +80,8 @@ bool MAssembly::Load(const String& assemblyPath)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
bool MAssembly::Load(MonoImage* monoImage)
|
||||
{
|
||||
if (IsLoaded())
|
||||
@@ -116,6 +115,8 @@ bool MAssembly::Load(MonoImage* monoImage)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void MAssembly::Unload(bool isReloading)
|
||||
{
|
||||
if (!IsLoaded())
|
||||
@@ -125,6 +126,7 @@ void MAssembly::Unload(bool isReloading)
|
||||
Unloading(this);
|
||||
|
||||
// Close runtime
|
||||
#if USE_MONO
|
||||
if (_monoImage)
|
||||
{
|
||||
if (isReloading)
|
||||
@@ -143,6 +145,7 @@ void MAssembly::Unload(bool isReloading)
|
||||
_monoAssembly = nullptr;
|
||||
_monoImage = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Cleanup
|
||||
_debugData.Resize(0);
|
||||
@@ -190,6 +193,8 @@ MClass* MAssembly::GetClass(const StringAnsiView& fullname) const
|
||||
return result;
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
MClass* MAssembly::GetClass(MonoClass* monoClass) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
||||
{
|
||||
if (_hasCachedClasses || !IsLoaded())
|
||||
return _classes;
|
||||
PROFILE_CPU();
|
||||
const auto startTime = DateTime::NowUTC();
|
||||
|
||||
#if USE_MONO
|
||||
#if TRACY_ENABLE
|
||||
const StringAnsiView monoImageName(mono_image_get_name(_monoImage));
|
||||
ZoneText(*monoImageName, monoImageName.Length());
|
||||
@@ -239,9 +249,6 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
||||
if (_hasCachedClasses)
|
||||
return _classes;
|
||||
ASSERT(_classes.IsEmpty());
|
||||
|
||||
const auto startTime = DateTime::NowUTC();
|
||||
|
||||
const int32 numRows = mono_image_get_table_rows(_monoImage, MONO_TABLE_TYPEDEF);
|
||||
_classes.EnsureCapacity(numRows * 4);
|
||||
for (int32 i = 1; i < numRows; i++) // Skip <Module> class
|
||||
@@ -256,6 +263,7 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
||||
auto mclass = New<MClass>(this, klass, fullname);
|
||||
_classes.Add(fullname, mclass);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto endTime = DateTime::NowUTC();
|
||||
LOG(Info, "Caching classes for assembly {0} took {1}ms", String(_name), (int32)(endTime - startTime).GetTotalMilliseconds());
|
||||
@@ -271,6 +279,7 @@ const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
||||
|
||||
bool MAssembly::LoadDefault(const String& assemblyPath)
|
||||
{
|
||||
#if USE_MONO
|
||||
// With this method of loading we need to make sure, we won't try to load assembly again if its loaded somewhere.
|
||||
auto assembly = mono_domain_assembly_open(_domain->GetNative(), assemblyPath.ToStringAnsi().Get());
|
||||
if (!assembly)
|
||||
@@ -283,17 +292,18 @@ bool MAssembly::LoadDefault(const String& assemblyPath)
|
||||
mono_assembly_close(assembly);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Register in domain
|
||||
_domain->_assemblies[_name] = this;
|
||||
|
||||
// Set state
|
||||
_monoAssembly = assembly;
|
||||
_monoImage = assemblyImage;
|
||||
#endif
|
||||
|
||||
// Set state
|
||||
_isDependency = false;
|
||||
_hasCachedClasses = false;
|
||||
_isFileLocked = true;
|
||||
_assemblyPath = assemblyPath;
|
||||
|
||||
// Register in domain
|
||||
_domain->_assemblies[_name] = this;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -307,6 +317,7 @@ bool MAssembly::LoadWithImage(const String& assemblyPath)
|
||||
Array<byte> data;
|
||||
File::ReadAllBytes(assemblyPath, data);
|
||||
|
||||
#if USE_MONO
|
||||
// Init Mono image
|
||||
MonoImageOpenStatus status;
|
||||
const auto name = assemblyPath.ToStringAnsi();
|
||||
@@ -359,10 +370,11 @@ bool MAssembly::LoadWithImage(const String& assemblyPath)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set state
|
||||
_monoAssembly = assembly;
|
||||
_monoImage = assemblyImage;
|
||||
#endif
|
||||
|
||||
// Set state
|
||||
_isDependency = false;
|
||||
_hasCachedClasses = false;
|
||||
_isFileLocked = false;
|
||||
@@ -379,7 +391,7 @@ void MAssembly::OnLoading()
|
||||
|
||||
// Pick a domain
|
||||
if (_domain == nullptr)
|
||||
_domain = MCore::Instance()->GetActiveDomain();
|
||||
_domain = MCore::GetActiveDomain();
|
||||
}
|
||||
|
||||
void MAssembly::OnLoaded(const DateTime& startTime)
|
||||
@@ -405,5 +417,3 @@ void MAssembly::OnLoadFailed()
|
||||
|
||||
LoadFailed(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,7 +16,6 @@
|
||||
class FLAXENGINE_API MAssembly
|
||||
{
|
||||
friend MDomain;
|
||||
|
||||
public:
|
||||
|
||||
typedef Dictionary<MString, MClass*> ClassesDictionary;
|
||||
@@ -24,8 +23,8 @@ public:
|
||||
private:
|
||||
|
||||
#if USE_MONO
|
||||
MonoAssembly* _monoAssembly;
|
||||
MonoImage* _monoImage;
|
||||
MonoAssembly* _monoAssembly = nullptr;
|
||||
MonoImage* _monoImage = nullptr;
|
||||
#endif
|
||||
MDomain* _domain;
|
||||
|
||||
@@ -98,7 +97,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if assembly is during loading state.
|
||||
/// </summary>
|
||||
/// <returns>True if is loading, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsLoading() const
|
||||
{
|
||||
return _isLoading != 0;
|
||||
@@ -107,7 +105,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if assembly has been loaded.
|
||||
/// </summary>
|
||||
/// <returns>True if is loaded, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsLoaded() const
|
||||
{
|
||||
return _isLoaded != 0;
|
||||
@@ -116,7 +113,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the assembly name.
|
||||
/// </summary>
|
||||
/// <returns>The assembly name.</returns>
|
||||
FORCE_INLINE const MString& GetName() const
|
||||
{
|
||||
return _name;
|
||||
@@ -125,7 +121,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the assembly name as string.
|
||||
/// </summary>
|
||||
/// <returns>The assembly name.</returns>
|
||||
String ToString() const;
|
||||
|
||||
/// <summary>
|
||||
@@ -134,7 +129,6 @@ public:
|
||||
/// <remarks>
|
||||
/// If assembly was made from scratch (empty), path will return null.
|
||||
/// </remarks>
|
||||
/// <returns>The assembly path.</returns>
|
||||
FORCE_INLINE const String& GetAssemblyPath() const
|
||||
{
|
||||
return _assemblyPath;
|
||||
@@ -143,20 +137,15 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the parent domain.
|
||||
/// </summary>
|
||||
/// <returns>The domain object.</returns>
|
||||
FORCE_INLINE MDomain* GetDomain() const
|
||||
{
|
||||
return _domain;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mono assembly.
|
||||
/// </summary>
|
||||
/// <returns>The Mono assembly.</returns>
|
||||
FORCE_INLINE MonoAssembly* GetMonoAssembly() const
|
||||
{
|
||||
return _monoAssembly;
|
||||
@@ -165,25 +154,22 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the Mono image.
|
||||
/// </summary>
|
||||
/// <returns>The Mono image.</returns>
|
||||
FORCE_INLINE MonoImage* GetMonoImage() const
|
||||
{
|
||||
return _monoImage;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the options that assembly was created with.
|
||||
/// </summary>
|
||||
/// <returns>The options.</returns>
|
||||
FORCE_INLINE const MAssemblyOptions& GetOptions() const
|
||||
{
|
||||
return _options;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Loads assembly for domain.
|
||||
/// </summary>
|
||||
@@ -192,14 +178,12 @@ public:
|
||||
bool Load(const String& assemblyPath);
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Loads assembly for domain.
|
||||
/// </summary>
|
||||
/// <param name="monoImage">The assembly image.</param>
|
||||
/// <returns>True if cannot load, otherwise false.</returns>
|
||||
bool Load(MonoImage* monoImage);
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -218,7 +202,6 @@ public:
|
||||
MClass* GetClass(const StringAnsiView& typeName) const;
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Converts an internal mono representation of a class into engine class.
|
||||
/// </summary>
|
||||
@@ -231,7 +214,6 @@ public:
|
||||
/// </summary>
|
||||
/// <returns>The native assembly object.</returns>
|
||||
MonoReflectionAssembly* GetNative() const;
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -242,8 +224,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Loads the assembly for domain.
|
||||
/// </summary>
|
||||
@@ -256,8 +236,6 @@ private:
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool LoadWithImage(const String& assemblyPath);
|
||||
|
||||
#endif
|
||||
|
||||
void OnLoading();
|
||||
void OnLoaded(const struct DateTime& startTime);
|
||||
void OnLoadFailed();
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MClass.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MType.h"
|
||||
#include "MTypes.h"
|
||||
#include "MField.h"
|
||||
@@ -11,16 +8,16 @@
|
||||
#include "MMethod.h"
|
||||
#include "MEvent.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/attrdefs.h>
|
||||
|
||||
#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)
|
||||
: _monoClass(monoClass)
|
||||
, _attrInfo(nullptr)
|
||||
, _assembly(parentAssembly)
|
||||
: _assembly(parentAssembly)
|
||||
, _fullname(fullname)
|
||||
, _visibility(MVisibility::Private)
|
||||
, _hasCachedProperties(false)
|
||||
@@ -33,9 +30,10 @@ MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MStr
|
||||
, _isAbstract(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)
|
||||
{
|
||||
@@ -67,12 +65,14 @@ MClass::MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MStr
|
||||
_isAbstract = !_isStatic && (flags & MONO_TYPE_ATTR_ABSTRACT) == MONO_TYPE_ATTR_ABSTRACT;
|
||||
_isInterface = (flags & MONO_TYPE_ATTR_CLASS_SEMANTIC_MASK) == MONO_TYPE_ATTR_INTERFACE;
|
||||
}
|
||||
#endif
|
||||
|
||||
MClass::~MClass()
|
||||
{
|
||||
#if USE_MONO
|
||||
if (_attrInfo)
|
||||
mono_custom_attrs_free((MonoCustomAttrInfo*)_attrInfo);
|
||||
|
||||
#endif
|
||||
_fields.ClearDelete();
|
||||
_properties.ClearDelete();
|
||||
_methods.ClearDelete();
|
||||
@@ -80,11 +80,6 @@ MClass::~MClass()
|
||||
_events.ClearDelete();
|
||||
}
|
||||
|
||||
MonoClass* MClass::GetNative() const
|
||||
{
|
||||
return _monoClass;
|
||||
}
|
||||
|
||||
bool MClass::IsGeneric() const
|
||||
{
|
||||
return _fullname.FindLast('`') != -1;
|
||||
@@ -92,45 +87,63 @@ bool MClass::IsGeneric() const
|
||||
|
||||
MType MClass::GetType() const
|
||||
{
|
||||
#if USE_MONO
|
||||
return MType(mono_class_get_type(_monoClass));
|
||||
#else
|
||||
return MType();
|
||||
#endif
|
||||
}
|
||||
|
||||
MClass* MClass::GetBaseClass() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* monoBase = mono_class_get_parent(_monoClass);
|
||||
if (monoBase == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return Scripting::FindClass(monoBase);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MClass::IsSubClassOf(const MClass* klass) const
|
||||
{
|
||||
#if USE_MONO
|
||||
return klass && mono_class_is_subclass_of(_monoClass, klass->GetNative(), false) != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
bool MClass::IsSubClassOf(MonoClass* monoClass) const
|
||||
{
|
||||
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)
|
||||
return false;
|
||||
|
||||
#if USE_MONO
|
||||
MonoClass* monoClass = mono_object_get_class(object);
|
||||
return mono_class_is_subclass_of(monoClass, _monoClass, false) != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32 MClass::GetInstanceSize() const
|
||||
{
|
||||
#if USE_MONO
|
||||
uint32 dummy = 0;
|
||||
|
||||
if (mono_class_is_valuetype(_monoClass))
|
||||
return mono_class_value_size(_monoClass, &dummy);
|
||||
|
||||
return mono_class_instance_size(_monoClass);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
MMethod* MClass::FindMethod(const char* name, int32 numParams, bool checkBaseClasses)
|
||||
@@ -154,6 +167,7 @@ MMethod* MClass::GetMethod(const char* name, int32 numParams)
|
||||
return _methods[i];
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
// Find Mono method
|
||||
MonoMethod* monoMethod = mono_class_get_method_from_name(_monoClass, name, numParams);
|
||||
if (monoMethod == nullptr)
|
||||
@@ -162,8 +176,10 @@ MMethod* MClass::GetMethod(const char* name, int32 numParams)
|
||||
// Create method
|
||||
auto method = New<MMethod>(monoMethod, name, this);
|
||||
_methods.Add(method);
|
||||
|
||||
return method;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MMethod*>& MClass::GetMethods()
|
||||
@@ -171,6 +187,7 @@ const Array<MMethod*>& MClass::GetMethods()
|
||||
if (_hasCachedMethods)
|
||||
return _methods;
|
||||
|
||||
#if USE_MONO
|
||||
void* iter = nullptr;
|
||||
MonoMethod* curClassMethod;
|
||||
while ((curClassMethod = mono_class_get_methods(_monoClass, &iter)))
|
||||
@@ -193,6 +210,7 @@ const Array<MMethod*>& MClass::GetMethods()
|
||||
_methods.Add(method);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_hasCachedMethods = true;
|
||||
return _methods;
|
||||
@@ -207,6 +225,7 @@ MField* MClass::GetField(const char* name)
|
||||
return _fields[i];
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
// Find mono field
|
||||
MonoClassField* field = mono_class_get_field_from_name(_monoClass, name);
|
||||
if (field == nullptr)
|
||||
@@ -216,6 +235,9 @@ MField* MClass::GetField(const char* name)
|
||||
auto mfield = New<MField>(field, name, this);
|
||||
_fields.Add(mfield);
|
||||
return mfield;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MField*>& MClass::GetFields()
|
||||
@@ -223,6 +245,7 @@ const Array<MField*>& MClass::GetFields()
|
||||
if (_hasCachedFields)
|
||||
return _fields;
|
||||
|
||||
#if USE_MONO
|
||||
void* iter = nullptr;
|
||||
MonoClassField* curClassField;
|
||||
while ((curClassField = mono_class_get_fields(_monoClass, &iter)))
|
||||
@@ -230,6 +253,7 @@ const Array<MField*>& MClass::GetFields()
|
||||
const char* fieldName = mono_field_get_name(curClassField);
|
||||
GetField(fieldName);
|
||||
}
|
||||
#endif
|
||||
|
||||
_hasCachedFields = true;
|
||||
return _fields;
|
||||
@@ -246,34 +270,33 @@ MEvent* MClass::GetEvent(const char* name)
|
||||
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()
|
||||
{
|
||||
if (_hasCachedEvents)
|
||||
return _events;
|
||||
|
||||
#if USE_MONO
|
||||
void* iter = nullptr;
|
||||
MonoEvent* curEvent;
|
||||
while ((curEvent = mono_class_get_events(_monoClass, &iter)))
|
||||
{
|
||||
const char* fieldName = mono_event_get_name(curEvent);
|
||||
AddEvent(fieldName, curEvent);
|
||||
const char* name = mono_event_get_name(curEvent);
|
||||
bool missing = true;
|
||||
for (int32 i = 0; i < _events.Count(); i++)
|
||||
{
|
||||
if (_events[i]->GetName() == name)
|
||||
{
|
||||
missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
auto result = New<MEvent>(curEvent, name, this);
|
||||
_events.Add(result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_hasCachedEvents = true;
|
||||
return _events;
|
||||
@@ -288,6 +311,7 @@ MProperty* MClass::GetProperty(const char* name)
|
||||
return _properties[i];
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
// Find mono property
|
||||
MonoProperty* monoProperty = mono_class_get_property_from_name(_monoClass, name);
|
||||
if (monoProperty == nullptr)
|
||||
@@ -298,6 +322,9 @@ MProperty* MClass::GetProperty(const char* name)
|
||||
_properties.Add(mproperty);
|
||||
|
||||
return mproperty;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MProperty*>& MClass::GetProperties()
|
||||
@@ -305,6 +332,7 @@ const Array<MProperty*>& MClass::GetProperties()
|
||||
if (_hasCachedProperties)
|
||||
return _properties;
|
||||
|
||||
#if USE_MONO
|
||||
void* iter = nullptr;
|
||||
MonoProperty* curClassProperty;
|
||||
while ((curClassProperty = mono_class_get_properties(_monoClass, &iter)))
|
||||
@@ -312,52 +340,74 @@ const Array<MProperty*>& MClass::GetProperties()
|
||||
const char* propertyName = mono_property_get_name(curClassProperty);
|
||||
GetProperty(propertyName);
|
||||
}
|
||||
#endif
|
||||
|
||||
_hasCachedProperties = true;
|
||||
return _properties;
|
||||
}
|
||||
|
||||
MonoObject* MClass::CreateInstance() const
|
||||
MObject* MClass::CreateInstance() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoObject* obj = mono_object_new(mono_domain_get(), _monoClass);
|
||||
if (!mono_class_is_valuetype(_monoClass))
|
||||
mono_runtime_object_init(obj);
|
||||
return obj;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
const auto constructor = GetMethod(".ctor", numParams);
|
||||
ASSERT(constructor);
|
||||
constructor->Invoke(obj, params, nullptr);
|
||||
return obj;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MClass::HasAttribute(MClass* monoClass)
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
|
||||
return attrInfo != nullptr && mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MClass::HasAttribute()
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
|
||||
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();
|
||||
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)
|
||||
return _attributes;
|
||||
|
||||
_hasCachedAttributes = true;
|
||||
#if USE_MONO
|
||||
MonoCustomAttrInfo* attrInfo = GET_CUSTOM_ATTR();
|
||||
if (attrInfo == nullptr)
|
||||
return _attributes;
|
||||
@@ -366,9 +416,8 @@ const Array<MonoObject*>& MClass::GetAttributes()
|
||||
const auto length = (uint32)mono_array_length(monoAttributesArray);
|
||||
_attributes.Resize(length);
|
||||
for (uint32 i = 0; i < length; i++)
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,7 +14,7 @@ private:
|
||||
|
||||
#if USE_MONO
|
||||
MonoClass* _monoClass;
|
||||
void* _attrInfo;
|
||||
void* _attrInfo = nullptr;
|
||||
#endif
|
||||
const MAssembly* _assembly;
|
||||
|
||||
@@ -23,7 +23,7 @@ private:
|
||||
Array<MMethod*> _methods;
|
||||
Array<MField*> _fields;
|
||||
Array<MProperty*> _properties;
|
||||
Array<MonoObject*> _attributes;
|
||||
Array<MObject*> _attributes;
|
||||
Array<MEvent*> _events;
|
||||
|
||||
MVisibility _visibility;
|
||||
@@ -40,6 +40,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MClass"/> class.
|
||||
/// </summary>
|
||||
@@ -47,6 +48,7 @@ public:
|
||||
/// <param name="monoClass">The Mono class.</param>
|
||||
/// <param name="fullname">The fullname.</param>
|
||||
MClass(const MAssembly* parentAssembly, MonoClass* monoClass, const MString& fullname);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="MClass"/> class.
|
||||
@@ -72,12 +74,13 @@ public:
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mono class handle.
|
||||
/// </summary>
|
||||
MonoClass* GetNative() const;
|
||||
|
||||
FORCE_INLINE MonoClass* GetNative() const
|
||||
{
|
||||
return _monoClass;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -142,19 +145,21 @@ public:
|
||||
/// <returns>True if this class is a sub class of the specified class.</returns>
|
||||
bool IsSubClassOf(const MClass* klass) const;
|
||||
|
||||
#if USE_MONO
|
||||
/// <summary>
|
||||
/// Checks if this class is a sub class of the specified class (including any derived types).
|
||||
/// </summary>
|
||||
/// <param name="monoClass">The Mono class.</param>
|
||||
/// <returns>True if this class is a sub class of the specified class.</returns>
|
||||
bool IsSubClassOf(MonoClass* monoClass) const;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Checks is the provided object instance of this class' type.
|
||||
/// </summary>
|
||||
/// <param name="object">The object to check.</param>
|
||||
/// <returns>True if object is an instance the this class.</returns>
|
||||
bool IsInstanceOfType(MonoObject* object) const;
|
||||
bool IsInstanceOfType(MObject* object) const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of an instance of this class, in bytes.
|
||||
@@ -217,14 +222,6 @@ public:
|
||||
/// <returns>The event object.</returns>
|
||||
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>
|
||||
/// Returns all events belonging to this class.
|
||||
/// </summary>
|
||||
@@ -257,7 +254,7 @@ public:
|
||||
/// Creates a new instance of this class and constructs it.
|
||||
/// </summary>
|
||||
/// <returns>The created managed object.</returns>
|
||||
MonoObject* CreateInstance() const;
|
||||
MObject* CreateInstance() const;
|
||||
|
||||
/// <summary>
|
||||
/// 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="numParams">The number of parameters the constructor accepts.</param>
|
||||
/// <returns>The created managed object.</returns>
|
||||
MonoObject* CreateInstance(void** params, uint32 numParams);
|
||||
MObject* CreateInstance(void** params, uint32 numParams);
|
||||
|
||||
public:
|
||||
|
||||
@@ -287,11 +284,11 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="monoClass">The attribute class to take.</param>
|
||||
/// <returns>The attribute object.</returns>
|
||||
MonoObject* GetAttribute(MClass* monoClass);
|
||||
MObject* GetAttribute(MClass* monoClass);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of all attributes connected with given class. Returns null if the class doesn't have any attributes.
|
||||
/// </summary>
|
||||
/// <returns>The array of attribute objects.</returns>
|
||||
const Array<MonoObject*>& GetAttributes();
|
||||
const Array<MObject*>& GetAttributes();
|
||||
};
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MCore.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MDomain.h"
|
||||
#include "MClass.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
@@ -16,6 +13,7 @@
|
||||
#include "Engine/Platform/Thread.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#if USE_MONO
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#endif
|
||||
@@ -33,15 +31,24 @@
|
||||
#if !USE_MONO_DYNAMIC_LIB
|
||||
#include <ThirdParty/mono-2.0/mono/utils/mono-dl-fallback.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
void* MonoAotModuleHandle = nullptr;
|
||||
#endif
|
||||
|
||||
MCore::MCore()
|
||||
: _rootDomain(nullptr)
|
||||
, _activeDomain(nullptr)
|
||||
MDomain* MRootDomain = nullptr;
|
||||
MDomain* MActiveDomain = nullptr;
|
||||
Array<MDomain*, InlinedAllocation<4>> MDomains;
|
||||
|
||||
MDomain* MCore::GetRootDomain()
|
||||
{
|
||||
return MRootDomain;
|
||||
}
|
||||
|
||||
MDomain* MCore::GetActiveDomain()
|
||||
{
|
||||
return MActiveDomain;
|
||||
}
|
||||
|
||||
MDomain* MCore::CreateDomain(const MString& domainName)
|
||||
@@ -51,50 +58,56 @@ MDomain* MCore::CreateDomain(const MString& domainName)
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
for (int32 i = 0; i < _domains.Count(); i++)
|
||||
for (int32 i = 0; i < MDomains.Count(); i++)
|
||||
{
|
||||
if (_domains[i]->GetName() == domainName)
|
||||
return _domains[i];
|
||||
if (MDomains[i]->GetName() == domainName)
|
||||
return MDomains[i];
|
||||
}
|
||||
|
||||
|
||||
auto domain = New<MDomain>(domainName);
|
||||
#if USE_MONO
|
||||
const auto monoDomain = mono_domain_create_appdomain((char*)domainName.Get(), nullptr);
|
||||
#if MONO_DEBUG_ENABLE
|
||||
mono_debug_domain_create(monoDomain);
|
||||
#endif
|
||||
ASSERT(monoDomain);
|
||||
auto domain = New<MDomain>(domainName, monoDomain);
|
||||
_domains.Add(domain);
|
||||
domain->_monoDomain = monoDomain;
|
||||
#endif
|
||||
MDomains.Add(domain);
|
||||
return domain;
|
||||
}
|
||||
|
||||
void MCore::UnloadDomain(const MString& domainName)
|
||||
{
|
||||
int32 i = 0;
|
||||
for (; i < _domains.Count(); i++)
|
||||
for (; i < MDomains.Count(); i++)
|
||||
{
|
||||
if (_domains[i]->GetName() == domainName)
|
||||
if (MDomains[i]->GetName() == domainName)
|
||||
break;
|
||||
}
|
||||
if (i == _domains.Count())
|
||||
if (i == MDomains.Count())
|
||||
return;
|
||||
|
||||
auto domain = _domains[i];
|
||||
auto domain = MDomains[i];
|
||||
#if USE_MONO
|
||||
#if MONO_DEBUG_ENABLE
|
||||
//mono_debug_domain_unload(domain->GetNative());
|
||||
#endif
|
||||
//mono_domain_finalize(_monoScriptsDomain, 2000);
|
||||
|
||||
MonoObject* exception = nullptr;
|
||||
//mono_domain_finalize(domain->GetNative(), 2000);
|
||||
MObject* exception = nullptr;
|
||||
mono_domain_try_unload(domain->GetNative(), &exception);
|
||||
if (exception)
|
||||
{
|
||||
MException ex(exception);
|
||||
ex.Log(LogType::Fatal, TEXT("Scripting::Release"));
|
||||
}
|
||||
#endif
|
||||
Delete(domain);
|
||||
_domains.RemoveAtKeepOrder(i);
|
||||
MDomains.RemoveAtKeepOrder(i);
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#if 0
|
||||
|
||||
void* MonoMalloc(size_t size)
|
||||
@@ -254,7 +267,7 @@ void OnLogCallback(const char* logDomain, const char* logLevel, const char* mess
|
||||
|
||||
if (currentDomain.IsEmpty())
|
||||
{
|
||||
auto domain = MCore::Instance()->GetActiveDomain();
|
||||
auto domain = MCore::GetActiveDomain();
|
||||
if (domain != nullptr)
|
||||
{
|
||||
currentDomain = domain->GetName().Get();
|
||||
@@ -443,7 +456,7 @@ bool MCore::LoadEngine()
|
||||
#endif
|
||||
|
||||
// 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_printerr_handler(OnPrintErrorCallback);
|
||||
}
|
||||
@@ -505,7 +518,7 @@ bool MCore::LoadEngine()
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init Mono
|
||||
// Init Mono
|
||||
#if PLATFORM_ANDROID
|
||||
const char* monoVersion = "mobile";
|
||||
#else
|
||||
@@ -513,8 +526,9 @@ bool MCore::LoadEngine()
|
||||
#endif
|
||||
auto monoRootDomain = mono_jit_init_version("Flax", monoVersion);
|
||||
ASSERT(monoRootDomain);
|
||||
_rootDomain = New<MDomain>("Root", monoRootDomain);
|
||||
_domains.Add(_rootDomain);
|
||||
MRootDomain = New<MDomain>("Root");
|
||||
MRootDomain->_monoDomain = monoRootDomain;
|
||||
MDomains.Add(MRootDomain);
|
||||
|
||||
auto exePath = Platform::GetExecutableFilePath();
|
||||
auto configDir = StringUtils::GetDirectoryName(exePath).ToStringAnsi();
|
||||
@@ -553,29 +567,29 @@ void MCore::UnloadEngine()
|
||||
Thread::ThreadExiting.Unbind<OnThreadExiting>();
|
||||
|
||||
// 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);
|
||||
}
|
||||
_domains.Clear();
|
||||
MDomains.Clear();
|
||||
|
||||
if (_rootDomain)
|
||||
if (MRootDomain)
|
||||
{
|
||||
#if PLATFORM_WINDOWS && USE_EDITOR
|
||||
// TODO: reduce issues with hot-reloading C# DLLs because sometimes it crashes on exit
|
||||
__try
|
||||
#endif
|
||||
{
|
||||
mono_jit_cleanup(_rootDomain->GetNative());
|
||||
mono_jit_cleanup(MRootDomain->GetNative());
|
||||
}
|
||||
#if PLATFORM_WINDOWS && USE_EDITOR
|
||||
__except (MonoHackSehExceptionHandler(nullptr))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
Delete(_rootDomain);
|
||||
_rootDomain = nullptr;
|
||||
Delete(MRootDomain);
|
||||
MRootDomain = nullptr;
|
||||
}
|
||||
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
@@ -591,39 +605,65 @@ void MCore::UnloadEngine()
|
||||
#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()
|
||||
{
|
||||
#if USE_MONO
|
||||
if (!IsInMainThread() && !mono_domain_get())
|
||||
{
|
||||
const auto domain = Instance()->GetActiveDomain();
|
||||
const auto domain = GetActiveDomain();
|
||||
ASSERT(domain);
|
||||
mono_thread_attach(domain->GetNative());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::ExitThread()
|
||||
{
|
||||
#if USE_MONO
|
||||
if (!IsInMainThread() && mono_domain_get())
|
||||
{
|
||||
LOG(Info, "Thread 0x{0:x} exits the managed runtime", Platform::GetCurrentThreadID());
|
||||
mono_thread_exit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::GC::Collect()
|
||||
{
|
||||
#if USE_MONO
|
||||
PROFILE_CPU();
|
||||
mono_gc_collect(mono_gc_max_generation());
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::GC::Collect(int32 generation)
|
||||
{
|
||||
#if USE_MONO
|
||||
PROFILE_CPU();
|
||||
mono_gc_collect(generation);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::GC::WaitForPendingFinalizers()
|
||||
{
|
||||
#if USE_MONO
|
||||
PROFILE_CPU();
|
||||
if (mono_gc_pending_finalizers())
|
||||
{
|
||||
@@ -633,9 +673,10 @@ void MCore::GC::WaitForPendingFinalizers()
|
||||
Platform::Sleep(1);
|
||||
} 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
|
||||
#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")
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -2,63 +2,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Singleton.h"
|
||||
#include "MTypes.h"
|
||||
|
||||
/// <summary>
|
||||
/// Main handler for CLR Engine.
|
||||
/// </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:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MCore"/> class.
|
||||
/// Gets the root domain.
|
||||
/// </summary>
|
||||
MCore();
|
||||
static MDomain* GetRootDomain();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the currently active domain.
|
||||
/// </summary>
|
||||
static MDomain* GetActiveDomain();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an new empty domain.
|
||||
/// </summary>
|
||||
/// <param name="domainName">The domain name to create.</param>
|
||||
/// <returns>The domain object.</returns>
|
||||
MDomain* CreateDomain(const MString& domainName);
|
||||
static MDomain* CreateDomain(const MString& domainName);
|
||||
|
||||
/// <summary>
|
||||
/// Unloads the domain.
|
||||
/// </summary>
|
||||
/// <param name="domainName">The domain name to remove.</param>
|
||||
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;
|
||||
}
|
||||
static void UnloadDomain(const MString& domainName);
|
||||
|
||||
public:
|
||||
|
||||
@@ -66,12 +40,12 @@ public:
|
||||
/// Initialize CLR Engine
|
||||
/// </summary>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool LoadEngine();
|
||||
static bool LoadEngine();
|
||||
|
||||
/// <summary>
|
||||
/// Unload CLR Engine
|
||||
/// </summary>
|
||||
void UnloadEngine();
|
||||
static void UnloadEngine();
|
||||
|
||||
/// <summary>
|
||||
/// Attaches CLR runtime to the current thread. Use it to allow invoking managed runtime from native threads.
|
||||
|
||||
@@ -1,38 +1,31 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MDomain.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MCore.h"
|
||||
#include "MAssembly.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Debug/Exceptions/ArgumentException.h"
|
||||
#include "Engine/Debug/Exceptions/Exceptions.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/threads.h>
|
||||
#endif
|
||||
|
||||
MDomain::MDomain(const MString& domainName, MonoDomain* monoDomain)
|
||||
: _monoDomain(monoDomain)
|
||||
, _domainName(domainName)
|
||||
, _coreInstance(MCore::Instance())
|
||||
{
|
||||
}
|
||||
extern MDomain* MActiveDomain;
|
||||
|
||||
MonoDomain* MDomain::GetNative() const
|
||||
MDomain::MDomain(const MString& domainName)
|
||||
: _domainName(domainName)
|
||||
{
|
||||
return _monoDomain;
|
||||
}
|
||||
|
||||
bool MDomain::SetCurrentDomain(bool force)
|
||||
{
|
||||
ASSERT(_monoDomain);
|
||||
const auto monoBool = mono_domain_set(_monoDomain, force) != 0;
|
||||
if (monoBool)
|
||||
{
|
||||
_coreInstance->_activeDomain = this;
|
||||
}
|
||||
return monoBool;
|
||||
#if USE_MONO
|
||||
if (mono_domain_set(_monoDomain, force) == 0)
|
||||
return false;
|
||||
#endif
|
||||
MActiveDomain = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
MAssembly* MDomain::CreateEmptyAssembly(const MString& assemblyName, const MAssemblyOptions options)
|
||||
@@ -72,10 +65,12 @@ MAssembly* MDomain::GetAssembly(const MString& assemblyName) const
|
||||
|
||||
void MDomain::Dispatch() const
|
||||
{
|
||||
#if USE_MONO
|
||||
if (!IsInMainThread())
|
||||
{
|
||||
mono_thread_attach(_monoDomain);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MClass* MDomain::FindClass(const StringAnsiView& fullname) const
|
||||
@@ -90,5 +85,3 @@ MClass* MDomain::FindClass(const StringAnsiView& fullname) const
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,7 +17,6 @@ class FLAXENGINE_API MDomain
|
||||
{
|
||||
friend MCore;
|
||||
friend MAssembly;
|
||||
|
||||
public:
|
||||
|
||||
typedef Dictionary<MString, MAssembly*> AssembliesDictionary;
|
||||
@@ -27,38 +26,43 @@ private:
|
||||
#if USE_MONO
|
||||
MonoDomain* _monoDomain;
|
||||
#endif
|
||||
|
||||
MString _domainName;
|
||||
AssembliesDictionary _assemblies;
|
||||
MCore* _coreInstance;
|
||||
|
||||
public:
|
||||
|
||||
MDomain(const MString& domainName);
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
MDomain(const MString& domainName, MonoDomain* monoDomain);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets native domain class
|
||||
/// Gets native domain class.
|
||||
/// </summary>
|
||||
/// <returns>The native domain.</returns>
|
||||
MonoDomain* GetNative() const;
|
||||
|
||||
FORCE_INLINE MonoDomain* GetNative() const
|
||||
{
|
||||
return _monoDomain;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets current domain name
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
FORCE_INLINE const MString& GetName() const
|
||||
{
|
||||
return _domainName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current domain assemblies.
|
||||
/// </summary>
|
||||
FORCE_INLINE const AssembliesDictionary& GetAssemblies() const
|
||||
{
|
||||
return _assemblies;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Create assembly container from current domain
|
||||
/// </summary>
|
||||
@@ -73,15 +77,6 @@ public:
|
||||
/// <param name="assemblyName">Assembly name</param>
|
||||
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>
|
||||
/// Gets current domain assembly.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MEvent.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MType.h"
|
||||
#include "MClass.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
|
||||
|
||||
MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass)
|
||||
@@ -24,13 +22,14 @@ MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass)
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MType MEvent::GetType()
|
||||
{
|
||||
if (GetAddMethod() != nullptr)
|
||||
return GetAddMethod()->GetReturnType();
|
||||
if (GetRemoveMethod() != nullptr)
|
||||
return GetRemoveMethod()->GetReturnType();
|
||||
CRASH;
|
||||
return MType();
|
||||
}
|
||||
|
||||
@@ -40,12 +39,14 @@ MMethod* MEvent::GetAddMethod()
|
||||
return nullptr;
|
||||
if (_addMethod == nullptr)
|
||||
{
|
||||
#if USE_MONO
|
||||
auto addMonoMethod = mono_event_get_add_method(_monoEvent);
|
||||
if (addMonoMethod != nullptr)
|
||||
{
|
||||
_hasAddMonoMethod = true;
|
||||
return _addMethod = New<MMethod>(addMonoMethod, _parentClass);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return _addMethod;
|
||||
}
|
||||
@@ -56,19 +57,21 @@ MMethod* MEvent::GetRemoveMethod()
|
||||
return nullptr;
|
||||
if (_removeMethod == nullptr)
|
||||
{
|
||||
#if USE_MONO
|
||||
auto removeMonoMethod = mono_event_get_remove_method(_monoEvent);
|
||||
if (removeMonoMethod)
|
||||
{
|
||||
_hasRemoveMonoMethod = true;
|
||||
return _removeMethod = New<MMethod>(removeMonoMethod, _parentClass);
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
return _removeMethod;
|
||||
}
|
||||
|
||||
bool MEvent::HasAttribute(MClass* monoClass) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -77,10 +80,14 @@ bool MEvent::HasAttribute(MClass* monoClass) const
|
||||
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return hasAttr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MEvent::HasAttribute() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -93,10 +100,14 @@ bool MEvent::HasAttribute() const
|
||||
}
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
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);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -105,14 +116,18 @@ MonoObject* MEvent::GetAttribute(MClass* monoClass) const
|
||||
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return foundAttr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MonoObject*>& MEvent::GetAttributes()
|
||||
const Array<MObject*>& MEvent::GetAttributes()
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
|
||||
_hasCachedAttributes = true;
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_event_get_parent(_monoEvent);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_event(parentClass, _monoEvent);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -122,9 +137,8 @@ const Array<MonoObject*>& MEvent::GetAttributes()
|
||||
const auto length = (uint32)mono_array_length(monoAttributesArray);
|
||||
_attributes.Resize(length);
|
||||
for (uint32 i = 0; i < length; i++)
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -23,12 +23,12 @@ protected:
|
||||
|
||||
MString _name;
|
||||
|
||||
Array<MonoObject*> _attributes;
|
||||
|
||||
int32 _hasCachedAttributes : 1;
|
||||
int32 _hasAddMonoMethod : 1;
|
||||
int32 _hasRemoveMonoMethod : 1;
|
||||
|
||||
Array<MObject*> _attributes;
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the event name.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
FORCE_INLINE const MString& GetName() const
|
||||
{
|
||||
return _name;
|
||||
@@ -49,7 +48,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns the parent class that this method is contained with.
|
||||
/// </summary>
|
||||
/// <returns>The parent class.</returns>
|
||||
FORCE_INLINE MClass* GetParentClass() const
|
||||
{
|
||||
return _parentClass;
|
||||
@@ -58,25 +56,21 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the event type class.
|
||||
/// </summary>
|
||||
/// <returns>The type class.</returns>
|
||||
MType GetType();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event add method.
|
||||
/// </summary>
|
||||
/// <returns>The method object.</returns>
|
||||
MMethod* GetAddMethod();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event remove method.
|
||||
/// </summary>
|
||||
/// <returns>The method object.</returns>
|
||||
MMethod* GetRemoveMethod();
|
||||
|
||||
/// <summary>
|
||||
/// Gets event visibility in the class.
|
||||
/// </summary>
|
||||
/// <returns>The event visibility.</returns>
|
||||
FORCE_INLINE MVisibility GetVisibility()
|
||||
{
|
||||
return GetAddMethod()->GetVisibility();
|
||||
@@ -85,23 +79,19 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if event is static.
|
||||
/// </summary>
|
||||
/// <returns>True if is static, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsStatic()
|
||||
{
|
||||
return GetAddMethod()->IsStatic();
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mono event handle.
|
||||
/// </summary>
|
||||
/// <returns>The Mono event.</returns>
|
||||
FORCE_INLINE MonoEvent* GetNative() const
|
||||
{
|
||||
return _monoEvent;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -124,11 +114,11 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="monoClass">The attribute class to take.</param>
|
||||
/// <returns>The attribute object.</returns>
|
||||
MonoObject* GetAttribute(MClass* monoClass) const;
|
||||
MObject* GetAttribute(MClass* monoClass) const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of all attributes connected with given event. Returns null if the event doesn't have any attributes.
|
||||
/// </summary>
|
||||
/// <returns>The array of attribute objects.</returns>
|
||||
const Array<MonoObject*>& GetAttributes();
|
||||
const Array<MObject*>& GetAttributes();
|
||||
};
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MField.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MType.h"
|
||||
#include "MClass.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MType MField::GetType() const
|
||||
{
|
||||
#if USE_MONO
|
||||
return MType(_monoType);
|
||||
#else
|
||||
return MType();
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 MField::GetOffset() const
|
||||
{
|
||||
#if USE_MONO
|
||||
return mono_field_get_offset(_monoField) - sizeof(MonoObject);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MField::GetValue(MonoObject* instance, void* result) const
|
||||
void MField::GetValue(MObject* instance, void* result) const
|
||||
{
|
||||
#if USE_MONO
|
||||
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);
|
||||
#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);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MField::HasAttribute(MClass* monoClass) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_field_get_parent(_monoField);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -83,10 +100,14 @@ bool MField::HasAttribute(MClass* monoClass) const
|
||||
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return hasAttr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MField::HasAttribute() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_field_get_parent(_monoField);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -98,11 +119,13 @@ bool MField::HasAttribute() const
|
||||
return true;
|
||||
}
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
MonoObject* MField::GetAttribute(MClass* monoClass) const
|
||||
MObject* MField::GetAttribute(MClass* monoClass) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_field_get_parent(_monoField);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -111,14 +134,18 @@ MonoObject* MField::GetAttribute(MClass* monoClass) const
|
||||
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return foundAttr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MonoObject*>& MField::GetAttributes()
|
||||
const Array<MObject*>& MField::GetAttributes()
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
|
||||
_hasCachedAttributes = true;
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_field_get_parent(_monoField);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_field(parentClass, _monoField);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -130,7 +157,6 @@ const Array<MonoObject*>& MField::GetAttributes()
|
||||
for (uint32 i = 0; i < length; i++)
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,15 +20,15 @@ protected:
|
||||
#endif
|
||||
|
||||
MClass* _parentClass;
|
||||
|
||||
MString _name;
|
||||
MVisibility _visibility;
|
||||
|
||||
Array<MonoObject*> _attributes;
|
||||
MVisibility _visibility;
|
||||
|
||||
int32 _hasCachedAttributes : 1;
|
||||
int32 _isStatic : 1;
|
||||
|
||||
Array<MObject*> _attributes;
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets field name.
|
||||
/// </summary>
|
||||
/// <returns>The field name.</returns>
|
||||
FORCE_INLINE const MString& GetName() const
|
||||
{
|
||||
return _name;
|
||||
@@ -49,7 +48,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns the parent class that this method is contained with.
|
||||
/// </summary>
|
||||
/// <returns>The parent class.</returns>
|
||||
FORCE_INLINE MClass* GetParentClass() const
|
||||
{
|
||||
return _parentClass;
|
||||
@@ -58,19 +56,16 @@ public:
|
||||
/// <summary>
|
||||
/// Gets field type class.
|
||||
/// </summary>
|
||||
/// <returns>The field type.</returns>
|
||||
MType GetType() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the field offset (in bytes) from the start of the parent object.
|
||||
/// </summary>
|
||||
/// <returns>The field offset in bytes.</returns>
|
||||
int32 GetOffset() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets field visibility in the class.
|
||||
/// </summary>
|
||||
/// <returns>The field visibility.</returns>
|
||||
FORCE_INLINE MVisibility GetVisibility() const
|
||||
{
|
||||
return _visibility;
|
||||
@@ -79,23 +74,19 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if field is static.
|
||||
/// </summary>
|
||||
/// <returns>True if is static, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsStatic() const
|
||||
{
|
||||
return _isStatic != 0;
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets mono field handle.
|
||||
/// </summary>
|
||||
/// <returns>The Mono field object.</returns>
|
||||
FORCE_INLINE MonoClassField* GetNative() const
|
||||
{
|
||||
return _monoField;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="instance">The object of given type to get value from.</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>
|
||||
/// 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>
|
||||
/// <param name="instance">The object of given type to get value from.</param>
|
||||
/// <returns>The boxed value object.</returns>
|
||||
MonoObject* GetValueBoxed(MonoObject* instance) const;
|
||||
MObject* GetValueBoxed(MObject* instance) const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value for the field on the specified object instance. If field is static object instance can be null.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="instance">The object of given type to set value to.</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:
|
||||
|
||||
@@ -147,11 +138,11 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="monoClass">The attribute class to take.</param>
|
||||
/// <returns>The attribute object.</returns>
|
||||
MonoObject* GetAttribute(MClass* monoClass) const;
|
||||
MObject* GetAttribute(MClass* monoClass) const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of all attributes connected with given field. Returns null if the field doesn't have any attributes.
|
||||
/// </summary>
|
||||
/// <returns>The array of attribute objects.</returns>
|
||||
const Array<MonoObject*>& GetAttributes();
|
||||
const Array<MObject*>& GetAttributes();
|
||||
};
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MMethod.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "MType.h"
|
||||
#include "MClass.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/attrdefs.h>
|
||||
|
||||
@@ -68,17 +66,27 @@ MMethod::MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass)
|
||||
#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);
|
||||
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);
|
||||
MonoMethod* virtualMethod = mono_object_get_virtual_method(instance, _monoMethod);
|
||||
return mono_runtime_invoke(virtualMethod, instance, params, exception);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !USE_MONO_AOT
|
||||
@@ -87,7 +95,9 @@ void* MMethod::GetThunk()
|
||||
{
|
||||
if (!_cachedThunk)
|
||||
{
|
||||
#if USE_MONO
|
||||
_cachedThunk = mono_method_get_unmanaged_thunk(_monoMethod);
|
||||
#endif
|
||||
}
|
||||
return _cachedThunk;
|
||||
}
|
||||
@@ -96,35 +106,52 @@ void* MMethod::GetThunk()
|
||||
|
||||
MType MMethod::GetReturnType() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
|
||||
MonoType* returnType = mono_signature_get_return_type(sig);
|
||||
return MType(returnType);
|
||||
#else
|
||||
return MType();
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 MMethod::GetParametersCount() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
|
||||
return mono_signature_get_param_count(sig);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
MType MMethod::GetParameterType(int32 paramIdx) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
|
||||
ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig));
|
||||
void* it = nullptr;
|
||||
mono_signature_get_params(sig, &it);
|
||||
return MType(((MonoType**)it)[paramIdx]);
|
||||
#else
|
||||
return MType();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MMethod::GetParameterIsOut(int32 paramIdx) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoMethodSignature* sig = mono_method_signature(_monoMethod);
|
||||
ASSERT_LOW_LAYER(paramIdx >= 0 && paramIdx < (int32)mono_signature_get_param_count(sig));
|
||||
return mono_signature_param_is_out(sig, paramIdx) != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MMethod::HasAttribute(MClass* monoClass) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
|
||||
if (attrInfo == nullptr)
|
||||
return false;
|
||||
@@ -132,10 +159,14 @@ bool MMethod::HasAttribute(MClass* monoClass) const
|
||||
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return hasAttr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MMethod::HasAttribute() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
|
||||
if (attrInfo == nullptr)
|
||||
return false;
|
||||
@@ -146,11 +177,13 @@ bool MMethod::HasAttribute() const
|
||||
return true;
|
||||
}
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
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);
|
||||
if (attrInfo == nullptr)
|
||||
return nullptr;
|
||||
@@ -158,14 +191,18 @@ MonoObject* MMethod::GetAttribute(MClass* monoClass) const
|
||||
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return foundAttr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MonoObject*>& MMethod::GetAttributes()
|
||||
const Array<MObject*>& MMethod::GetAttributes()
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
|
||||
_hasCachedAttributes = true;
|
||||
#if USE_MONO
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method(_monoMethod);
|
||||
if (attrInfo == nullptr)
|
||||
return _attributes;
|
||||
@@ -176,7 +213,6 @@ const Array<MonoObject*>& MMethod::GetAttributes()
|
||||
for (uint32 i = 0; i < length; i++)
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -29,11 +29,11 @@ protected:
|
||||
void* _cachedThunk = nullptr;
|
||||
#endif
|
||||
|
||||
Array<MonoObject*> _attributes;
|
||||
|
||||
int32 _hasCachedAttributes : 1;
|
||||
int32 _isStatic : 1;
|
||||
|
||||
Array<MObject*> _attributes;
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
@@ -48,8 +48,6 @@ public:
|
||||
SourceLocationData ProfilerData;
|
||||
#endif
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <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.
|
||||
/// </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="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
|
||||
/// 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>
|
||||
/// <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>
|
||||
/// 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">
|
||||
/// 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
|
||||
/// values and for reference types they should be pointers to MonoObject.
|
||||
/// 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>
|
||||
/// <returns>A boxed return value, or null if method has no return value.</returns>
|
||||
MonoObject* InvokeVirtual(MonoObject* instance, void** params, MonoObject** exception) const;
|
||||
|
||||
#endif
|
||||
MObject* InvokeVirtual(MObject* instance, void** params, MObject** exception) const;
|
||||
|
||||
#if !USE_MONO_AOT
|
||||
|
||||
/// <summary>
|
||||
/// Gets a thunk for this method. A thunk is a C++ like function pointer that you can use for calling the method.
|
||||
/// </summary>
|
||||
@@ -93,7 +88,6 @@ public:
|
||||
/// </remarks>
|
||||
/// <returns>The method thunk pointer.</returns>
|
||||
void* GetThunk();
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -153,7 +147,6 @@ public:
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mono method handle.
|
||||
/// </summary>
|
||||
@@ -161,7 +154,6 @@ public:
|
||||
{
|
||||
return _monoMethod;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -184,11 +176,11 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="monoClass">The attribute Class to take.</param>
|
||||
/// <returns>The attribute object.</returns>
|
||||
MonoObject* GetAttribute(MClass* monoClass) const;
|
||||
MObject* GetAttribute(MClass* monoClass) const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of all attributes connected with given method. Returns null if the method doesn't have any attributes.
|
||||
/// </summary>
|
||||
/// <returns>The array of attribute objects.</returns>
|
||||
const Array<MonoObject*>& GetAttributes();
|
||||
const Array<MObject*>& GetAttributes();
|
||||
};
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "MProperty.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "MMethod.h"
|
||||
#include "MClass.h"
|
||||
#include "MType.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
|
||||
|
||||
MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass)
|
||||
@@ -29,6 +27,8 @@ MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* paren
|
||||
GetSetMethod();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MProperty::~MProperty()
|
||||
{
|
||||
if (_getMethod)
|
||||
@@ -48,18 +48,17 @@ MMethod* MProperty::GetGetMethod()
|
||||
{
|
||||
if (!_hasGetMethod)
|
||||
return nullptr;
|
||||
|
||||
if (_getMethod == nullptr)
|
||||
{
|
||||
#if USE_MONO
|
||||
auto method = mono_property_get_get_method(_monoProperty);
|
||||
if (method != nullptr)
|
||||
{
|
||||
_hasGetMethod = true;
|
||||
return _getMethod = New<MMethod>(method, _parentClass);
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
return _getMethod;
|
||||
}
|
||||
|
||||
@@ -67,18 +66,17 @@ MMethod* MProperty::GetSetMethod()
|
||||
{
|
||||
if (!_hasSetMethod)
|
||||
return nullptr;
|
||||
|
||||
if (_setMethod == nullptr)
|
||||
{
|
||||
#if USE_MONO
|
||||
auto method = mono_property_get_set_method(_monoProperty);
|
||||
if (method != nullptr)
|
||||
{
|
||||
_hasSetMethod = true;
|
||||
return _setMethod = New<MMethod>(method, _parentClass);
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
return _setMethod;
|
||||
}
|
||||
|
||||
@@ -112,20 +110,27 @@ bool MProperty::IsStatic()
|
||||
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);
|
||||
#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];
|
||||
params[0] = value;
|
||||
mono_property_set_value(_monoProperty, instance, params, exception);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MProperty::HasAttribute(MClass* monoClass) const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -134,10 +139,14 @@ bool MProperty::HasAttribute(MClass* monoClass) const
|
||||
const bool hasAttr = mono_custom_attrs_has_attr(attrInfo, monoClass->GetNative()) != 0;
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return hasAttr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MProperty::HasAttribute() const
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -150,10 +159,14 @@ bool MProperty::HasAttribute() const
|
||||
}
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
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);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -162,14 +175,18 @@ MonoObject* MProperty::GetAttribute(MClass* monoClass) const
|
||||
MonoObject* foundAttr = mono_custom_attrs_get_attr(attrInfo, monoClass->GetNative());
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
return foundAttr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const Array<MonoObject*>& MProperty::GetAttributes()
|
||||
const Array<MObject*>& MProperty::GetAttributes()
|
||||
{
|
||||
if (_hasCachedAttributes)
|
||||
return _attributes;
|
||||
|
||||
_hasCachedAttributes = true;
|
||||
#if USE_MONO
|
||||
MonoClass* parentClass = mono_property_get_parent(_monoProperty);
|
||||
MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_property(parentClass, _monoProperty);
|
||||
if (attrInfo == nullptr)
|
||||
@@ -179,9 +196,8 @@ const Array<MonoObject*>& MProperty::GetAttributes()
|
||||
const auto length = (uint32)mono_array_length(monoAttributesArray);
|
||||
_attributes.Resize(length);
|
||||
for (uint32 i = 0; i < length; i++)
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i);
|
||||
_attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i);
|
||||
mono_custom_attrs_free(attrInfo);
|
||||
#endif
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -25,12 +25,12 @@ protected:
|
||||
|
||||
MString _name;
|
||||
|
||||
Array<MonoObject*> _attributes;
|
||||
|
||||
int32 _hasCachedAttributes : 1;
|
||||
int32 _hasSetMethod : 1;
|
||||
int32 _hasGetMethod : 1;
|
||||
|
||||
Array<MObject*> _attributes;
|
||||
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
@@ -47,7 +47,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the property name.
|
||||
/// </summary>
|
||||
/// <returns>The property name.</returns>
|
||||
FORCE_INLINE const MString& GetName() const
|
||||
{
|
||||
return _name;
|
||||
@@ -56,7 +55,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns the parent class that this method is contained with.
|
||||
/// </summary>
|
||||
/// <returns>The parent class.</returns>
|
||||
FORCE_INLINE MClass* GetParentClass() const
|
||||
{
|
||||
return _parentClass;
|
||||
@@ -65,31 +63,26 @@ public:
|
||||
/// <summary>
|
||||
/// Gets property type class.
|
||||
/// </summary>
|
||||
/// <returns>The property type.</returns>
|
||||
MType GetType();
|
||||
|
||||
/// <summary>
|
||||
/// Gets property get method.
|
||||
/// </summary>
|
||||
/// <returns>The getter method.</returns>
|
||||
MMethod* GetGetMethod();
|
||||
|
||||
/// <summary>
|
||||
/// Gets property set method.
|
||||
/// </summary>
|
||||
/// <returns>The setter method.</returns>
|
||||
MMethod* GetSetMethod();
|
||||
|
||||
/// <summary>
|
||||
/// Gets property visibility in the class.
|
||||
/// </summary>
|
||||
/// <returns>The property visibility.</returns>
|
||||
MVisibility GetVisibility();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if property is static.
|
||||
/// </summary>
|
||||
/// <returns>True if is static, otherwise false.</returns>
|
||||
bool IsStatic();
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="instance">The object of given type to get value from.</param>
|
||||
/// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
|
||||
/// <returns>The returned boxed value object.</returns>
|
||||
MonoObject* GetValue(MonoObject* instance, MonoObject** exception);
|
||||
MObject* GetValue(MObject* instance, MObject** exception);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value for the property on the specified object instance. If property is static object instance can be null.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="instance">Object of given type to set value to.</param>
|
||||
/// <param name="exception">An optional pointer to the exception value to store exception object reference.</param>
|
||||
/// <param name="value">The value to set of undefined type.</param>
|
||||
void SetValue(MonoObject* instance, void* value, MonoObject** exception);
|
||||
void SetValue(MObject* instance, void* value, MObject** exception);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@@ -136,11 +130,11 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="monoClass">The attribute class to take.</param>
|
||||
/// <returns>The attribute object.</returns>
|
||||
MonoObject* GetAttribute(MClass* monoClass) const;
|
||||
MObject* GetAttribute(MClass* monoClass) const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of all attributes connected with given property. Returns null if the property doesn't have any attributes.
|
||||
/// </summary>
|
||||
/// <returns>The array of attribute objects.</returns>
|
||||
const Array<MonoObject*>& GetAttributes();
|
||||
const Array<MObject*>& GetAttributes();
|
||||
};
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Class for converting mono classes and methods into usable form without instancing a class.
|
||||
@@ -13,6 +15,7 @@ class MStaticConverter
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
static MonoClass* GetMonoClassFromObject(MonoObject* monoObject)
|
||||
{
|
||||
ASSERT(monoObject);
|
||||
@@ -63,4 +66,5 @@ public:
|
||||
}
|
||||
return array;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
#include "MType.h"
|
||||
#include "MUtils.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
|
||||
|
||||
String MType::ToString() const
|
||||
@@ -42,4 +40,11 @@ bool MType::IsByRef() const
|
||||
return mono_type_is_byref(_monoType) != 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
String MType::ToString() const
|
||||
{
|
||||
return String::Empty;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
#include "MTypes.h"
|
||||
|
||||
/// <summary>
|
||||
/// Contains information about managed type
|
||||
/// Contains information about managed type.
|
||||
/// </summary>
|
||||
class MType
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
MonoType* _monoType;
|
||||
|
||||
/// <summary>
|
||||
@@ -31,7 +30,6 @@ public:
|
||||
: _monoType(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -46,11 +44,9 @@ public:
|
||||
String ToString() const;
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
/// <summary>
|
||||
/// Gets mono type handle
|
||||
/// </summary>
|
||||
/// <returns>Mono type</returns>
|
||||
MonoType* GetNative() const
|
||||
{
|
||||
return _monoType;
|
||||
@@ -78,6 +74,5 @@ public:
|
||||
{
|
||||
return _monoType != nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -2,63 +2,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Types.h"
|
||||
#include "Engine/Core/Types/String.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>
|
||||
/// 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>
|
||||
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
|
||||
{
|
||||
Private,
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
struct _MonoType
|
||||
{
|
||||
union
|
||||
@@ -846,3 +848,5 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
|
||||
failed = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "Engine/Core/Types/Variant.h"
|
||||
#include "Engine/Core/Collections/Array.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/appdomain.h>
|
||||
|
||||
@@ -498,3 +501,5 @@ namespace MUtils
|
||||
|
||||
extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ManagedSerialization.h"
|
||||
#if USE_MONO
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Serialization/Json.h"
|
||||
#include "Engine/Serialization/JsonWriter.h"
|
||||
@@ -26,7 +27,7 @@ void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, Mon
|
||||
params[1] = &isManagedOnly;
|
||||
|
||||
// Call serialization tool
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
// TODO: use method thunk
|
||||
auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_Serialize->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
@@ -64,7 +65,7 @@ void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream,
|
||||
params[2] = &isManagedOnly;
|
||||
|
||||
// Call serialization tool
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
// TODO: use method thunk
|
||||
auto invokeResultStr = (MonoString*)StdTypesContainer::Instance()->Json_SerializeDiff->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
@@ -115,7 +116,7 @@ void ManagedSerialization::Deserialize(const StringAnsiView& data, MonoObject* o
|
||||
args[2] = (void*)&len;
|
||||
|
||||
// Call serialization tool
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
// TODO: use method thunk
|
||||
StdTypesContainer::Instance()->Json_Deserialize->Invoke(nullptr, args, &exception);
|
||||
if (exception)
|
||||
@@ -124,3 +125,5 @@ void ManagedSerialization::Deserialize(const StringAnsiView& data, MonoObject* o
|
||||
ex.Log(LogType::Error, TEXT("ManagedSerialization::Deserialize"));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,7 @@ class FLAXENGINE_API ManagedSerialization
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
/// <summary>
|
||||
/// Serializes managed object to JSON.
|
||||
/// </summary>
|
||||
@@ -40,4 +41,5 @@ public:
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <param name="object">The object to deserialize.</param>
|
||||
static void Deserialize(const StringAnsiView& data, MonoObject* object);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -44,13 +44,14 @@ PluginManagerService PluginManagerServiceInstance;
|
||||
|
||||
void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
if (Internal_LoadPlugin == nullptr)
|
||||
{
|
||||
Internal_LoadPlugin = PluginManager::GetStaticClass()->GetMethod("Internal_LoadPlugin", 2);
|
||||
ASSERT(Internal_LoadPlugin);
|
||||
}
|
||||
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
void* params[2];
|
||||
params[0] = MUtils::GetType(klass->GetNative());
|
||||
params[1] = &isEditor;
|
||||
@@ -59,6 +60,7 @@ void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor)
|
||||
{
|
||||
DebugLog::LogException(exception);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
|
||||
@@ -113,10 +115,11 @@ void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
|
||||
|
||||
void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Cleanup plugins from this assembly
|
||||
const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose", 1);
|
||||
ASSERT(disposeMethod);
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
void* params[1];
|
||||
params[0] = assembly->GetNative();
|
||||
disposeMethod->Invoke(nullptr, params, &exception);
|
||||
@@ -124,6 +127,7 @@ void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly)
|
||||
{
|
||||
DebugLog::LogException(exception);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module)
|
||||
@@ -169,13 +173,15 @@ void PluginManagerService::Dispose()
|
||||
|
||||
PROFILE_CPU_NAMED("Dispose Plugins");
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Cleanup all plugins
|
||||
const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose");
|
||||
ASSERT(disposeMethod);
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
disposeMethod->Invoke(nullptr, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
DebugLog::LogException(exception);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -13,7 +13,11 @@ public class Scripting : EngineModule
|
||||
{
|
||||
base.Setup(options);
|
||||
|
||||
options.PublicDependencies.Add("mono");
|
||||
if (EngineConfiguration.WithCSharp(options))
|
||||
{
|
||||
options.PublicDependencies.Add("mono");
|
||||
}
|
||||
|
||||
options.PrivateDependencies.Add("Utilities");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
#endif
|
||||
#include "Engine/Core/Types/Pair.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
|
||||
#endif
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
namespace ProfilerInternal
|
||||
{
|
||||
@@ -99,9 +103,12 @@ namespace ProfilerInternal
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class ScriptingInternal
|
||||
{
|
||||
public:
|
||||
#if USE_MONO
|
||||
static bool HasGameModulesLoaded()
|
||||
{
|
||||
return Scripting::HasGameModulesLoaded();
|
||||
@@ -117,9 +124,11 @@ public:
|
||||
ASSERT(IsInMainThread());
|
||||
ObjectsRemovalService::Flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void InitRuntime()
|
||||
{
|
||||
#if USE_MONO
|
||||
// Scripting API
|
||||
ADD_INTERNAL_CALL("FlaxEngine.Scripting::HasGameModulesLoaded", &HasGameModulesLoaded);
|
||||
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::BeginEventGPU", &ProfilerInternal::BeginEventGPU);
|
||||
ADD_INTERNAL_CALL("FlaxEngine.Profiler::EndEventGPU", &ProfilerInternal::EndEventGPU);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Graphics/RenderTask.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/object.h>
|
||||
#endif
|
||||
|
||||
extern void registerFlaxEngineInternalCalls();
|
||||
|
||||
@@ -55,8 +57,8 @@ public:
|
||||
|
||||
namespace
|
||||
{
|
||||
MDomain* _monoRootDomain = nullptr;
|
||||
MDomain* _monoScriptsDomain = nullptr;
|
||||
MDomain* _rootDomain = nullptr;
|
||||
MDomain* _scriptsDomain = nullptr;
|
||||
CriticalSection _objectsLocker;
|
||||
#define USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING 0
|
||||
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
|
||||
@@ -134,24 +136,24 @@ bool ScriptingService::Init()
|
||||
engineAssembly->Unloading.Bind(onEngineUnloading);
|
||||
|
||||
// Initialize managed runtime
|
||||
if (MCore::Instance()->LoadEngine())
|
||||
if (MCore::LoadEngine())
|
||||
{
|
||||
LOG(Fatal, "Mono initialization failed.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cache root domain
|
||||
_monoRootDomain = MCore::Instance()->GetRootDomain();
|
||||
_rootDomain = MCore::GetRootDomain();
|
||||
|
||||
#if USE_SINGLE_DOMAIN
|
||||
#if USE_SCRIPTING_SINGLE_DOMAIN
|
||||
// Use single root domain
|
||||
auto domain = _monoRootDomain;
|
||||
auto domain = _rootDomain;
|
||||
#else
|
||||
// Create Mono domain for scripts
|
||||
auto domain = MCore::Instance()->CreateDomain(TEXT("Scripts Domain"));
|
||||
// Create Mono domain for scripts
|
||||
auto domain = MCore::CreateDomain("Scripts Domain");
|
||||
#endif
|
||||
domain->SetCurrentDomain(true);
|
||||
_monoScriptsDomain = domain;
|
||||
_scriptsDomain = domain;
|
||||
|
||||
// Add internal calls
|
||||
registerFlaxEngineInternalCalls();
|
||||
@@ -169,6 +171,9 @@ bool ScriptingService::Init()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if COMPILE_WITHOUT_CSHARP
|
||||
#define INVOKE_EVENT(name)
|
||||
#else
|
||||
#define INVOKE_EVENT(name) \
|
||||
if (!_isEngineAssemblyLoaded) return; \
|
||||
if (_method_##name == nullptr) \
|
||||
@@ -186,9 +191,10 @@ bool ScriptingService::Init()
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
MonoObject* exception = nullptr; \
|
||||
MObject* exception = nullptr; \
|
||||
_method_##name->Invoke(nullptr, nullptr, &exception); \
|
||||
DebugLog::LogException(exception)
|
||||
#endif
|
||||
|
||||
void ScriptingService::Update()
|
||||
{
|
||||
@@ -227,12 +233,12 @@ void ScriptingService::BeforeExit()
|
||||
|
||||
MDomain* Scripting::GetRootDomain()
|
||||
{
|
||||
return _monoRootDomain;
|
||||
return _rootDomain;
|
||||
}
|
||||
|
||||
MDomain* Scripting::GetScriptsDomain()
|
||||
{
|
||||
return _monoScriptsDomain;
|
||||
return _scriptsDomain;
|
||||
}
|
||||
|
||||
void Scripting::ProcessBuildInfoPath(String& path, const String& projectFolderPath)
|
||||
@@ -276,10 +282,9 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
|
||||
|
||||
// Load all references
|
||||
auto referencesMember = document.FindMember("References");
|
||||
if (referencesMember != document.MemberEnd())
|
||||
if (referencesMember != document.MemberEnd() && referencesMember->value.IsArray())
|
||||
{
|
||||
auto& referencesArray = referencesMember->value;
|
||||
ASSERT(referencesArray.IsArray());
|
||||
for (rapidjson::SizeType i = 0; i < referencesArray.Size(); i++)
|
||||
{
|
||||
auto& reference = referencesArray[i];
|
||||
@@ -308,10 +313,9 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
|
||||
|
||||
// Load all binary modules
|
||||
auto binaryModulesMember = document.FindMember("BinaryModules");
|
||||
if (binaryModulesMember != document.MemberEnd())
|
||||
if (binaryModulesMember != document.MemberEnd() && binaryModulesMember->value.IsArray())
|
||||
{
|
||||
auto& binaryModulesArray = binaryModulesMember->value;
|
||||
ASSERT(binaryModulesArray.IsArray());
|
||||
for (rapidjson::SizeType i = 0; i < binaryModulesArray.Size(); i++)
|
||||
{
|
||||
auto& binaryModule = binaryModulesArray[i];
|
||||
@@ -396,6 +400,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
|
||||
}
|
||||
}
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// C#
|
||||
if (managedPath.HasChars() && !((ManagedBinaryModule*)module)->Assembly->IsLoaded())
|
||||
{
|
||||
@@ -405,6 +410,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
||||
ASSERT(IsInMainThread());
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Load C# core assembly
|
||||
if (GetBinaryModuleCorlib()->Assembly->Load(mono_get_corlib()))
|
||||
{
|
||||
LOG(Error, "Failed to load corlib C# assembly.");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Load FlaxEngine
|
||||
const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
|
||||
@@ -539,7 +547,7 @@ void Scripting::Release()
|
||||
ObjectsRemovalService::Flush();
|
||||
|
||||
// Switch domain
|
||||
auto rootDomain = MCore::Instance()->GetRootDomain();
|
||||
auto rootDomain = MCore::GetRootDomain();
|
||||
if (rootDomain)
|
||||
{
|
||||
if (!rootDomain->SetCurrentDomain(false))
|
||||
@@ -548,8 +556,8 @@ void Scripting::Release()
|
||||
}
|
||||
}
|
||||
|
||||
#if !USE_SINGLE_DOMAIN
|
||||
MCore::Instance()->UnloadDomain("Scripts Domain");
|
||||
#if !USE_SCRIPTING_SINGLE_DOMAIN
|
||||
MCore::UnloadDomain("Scripts Domain");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -647,25 +655,6 @@ void Scripting::Reload(bool canTriggerSceneReload)
|
||||
|
||||
#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)
|
||||
{
|
||||
if (fullname.IsEmpty())
|
||||
@@ -685,6 +674,27 @@ MClass* Scripting::FindClass(const StringAnsiView& fullname)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
MClass* Scripting::FindClass(MonoClass* monoClass)
|
||||
{
|
||||
if (monoClass == nullptr)
|
||||
return nullptr;
|
||||
PROFILE_CPU();
|
||||
auto& modules = BinaryModule::GetModules();
|
||||
for (auto module : modules)
|
||||
{
|
||||
auto managedModule = dynamic_cast<ManagedBinaryModule*>(module);
|
||||
if (managedModule && managedModule->Assembly->IsLoaded())
|
||||
{
|
||||
MClass* result = managedModule->Assembly->GetClass(monoClass);
|
||||
if (result != nullptr)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MonoClass* Scripting::FindClassNative(const StringAnsiView& fullname)
|
||||
{
|
||||
if (fullname.IsEmpty())
|
||||
@@ -704,6 +714,8 @@ MonoClass* Scripting::FindClassNative(const StringAnsiView& fullname)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname)
|
||||
{
|
||||
if (fullname.IsEmpty())
|
||||
@@ -816,7 +828,7 @@ ScriptingObject* Scripting::TryFindObject(Guid id, MClass* type)
|
||||
return result;
|
||||
}
|
||||
|
||||
ScriptingObject* Scripting::FindObject(const MonoObject* managedInstance)
|
||||
ScriptingObject* Scripting::FindObject(const MObject* managedInstance)
|
||||
{
|
||||
if (managedInstance == nullptr)
|
||||
return nullptr;
|
||||
@@ -938,13 +950,14 @@ bool initFlaxEngine()
|
||||
if (StdTypesContainer::Instance()->Gather())
|
||||
return true;
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Init C# class library
|
||||
{
|
||||
auto scriptingClass = Scripting::GetStaticClass();
|
||||
ASSERT(scriptingClass);
|
||||
const auto initMethod = scriptingClass->GetMethod("Init");
|
||||
ASSERT(initMethod);
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
initMethod->Invoke(nullptr, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -952,10 +965,11 @@ bool initFlaxEngine()
|
||||
ex.Log(LogType::Fatal, TEXT("FlaxEngine.Scripting.Init"));
|
||||
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;
|
||||
}
|
||||
@@ -989,5 +1003,5 @@ void ScriptingService::Dispose()
|
||||
{
|
||||
Scripting::Release();
|
||||
|
||||
MCore::Instance()->UnloadEngine();
|
||||
MCore::UnloadEngine();
|
||||
}
|
||||
|
||||
@@ -47,12 +47,12 @@ public:
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets mono root domain
|
||||
/// Gets the root domain.
|
||||
/// </summary>
|
||||
static MDomain* GetRootDomain();
|
||||
|
||||
/// <summary>
|
||||
/// Gets scripts domain
|
||||
/// Gets the scripts domain (it can be the root domain if not using separate domain for scripting).
|
||||
/// </summary>
|
||||
static MDomain* GetScriptsDomain();
|
||||
|
||||
@@ -70,17 +70,23 @@ public:
|
||||
static void Release();
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
/// Reloads scripts.
|
||||
/// </summary>
|
||||
/// <param name="canTriggerSceneReload">True if allow to scene scripts reload callback, otherwise it won't be possible.</param>
|
||||
static void Reload(bool canTriggerSceneReload = true);
|
||||
|
||||
#endif
|
||||
|
||||
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>
|
||||
/// Finds the class from the given Mono class object within whole assembly.
|
||||
/// </summary>
|
||||
@@ -88,19 +94,13 @@ public:
|
||||
/// <returns>The MClass object or null if missing.</returns>
|
||||
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>
|
||||
/// Finds the native class with given fully qualified name within whole assembly.
|
||||
/// </summary>
|
||||
/// <param name="fullname">The full name of the type eg: System.Int64.</param>
|
||||
/// <returns>The MClass object or null if missing.</returns>
|
||||
static MonoClass* FindClassNative(const StringAnsiView& fullname);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Finds the scripting type of the given fullname by searching loaded scripting assemblies.
|
||||
@@ -161,7 +161,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="managedInstance">The managed instance pointer.</param>
|
||||
/// <returns>The found object or null if missing.</returns>
|
||||
static ScriptingObject* FindObject(const MonoObject* managedInstance);
|
||||
static ScriptingObject* FindObject(const MObject* managedInstance);
|
||||
|
||||
/// <summary>
|
||||
/// Event called by the internal call on a finalizer thread when the managed objects gets deleted by the GC.
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
#include "Engine/Scripting/ManagedCLR/MTypes.h"
|
||||
|
||||
typedef void (*Thunk_Void_0)(MonoObject** exception);
|
||||
typedef void (*Thunk_Void_1)(void* param_1, MonoObject** exception);
|
||||
typedef void (*Thunk_Void_2)(void* param_1, void* param_2, MonoObject** exception);
|
||||
typedef void (*Thunk_Void_3)(void* param_1, void* param_2, void* param_3, MonoObject** exception);
|
||||
typedef void (*Thunk_Void_4)(void* param_1, void* param_2, void* param_3, void* param_4, MonoObject** exception);
|
||||
typedef void (*Thunk_Void_0)(MObject** exception);
|
||||
typedef void (*Thunk_Void_1)(void* param_1, MObject** 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, MObject** 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 MonoObject* (*Thunk_Object_1)(void* param_1, MonoObject** exception);
|
||||
typedef MonoObject* (*Thunk_Object_2)(void* param_1, void* param_2, MonoObject** exception);
|
||||
typedef MonoObject* (*Thunk_Object_3)(void* param_1, void* param_2, void* param_3, MonoObject** exception);
|
||||
typedef MonoObject* (*Thunk_Object_4)(void* param_1, void* param_2, void* param_3, void* param_4, MonoObject** exception);
|
||||
typedef MObject* (*Thunk_Object_0)(MObject** exception);
|
||||
typedef MObject* (*Thunk_Object_1)(void* param_1, MObject** exception);
|
||||
typedef MObject* (*Thunk_Object_2)(void* param_1, void* param_2, MObject** exception);
|
||||
typedef MObject* (*Thunk_Object_3)(void* param_1, void* param_2, void* param_3, MObject** exception);
|
||||
typedef MObject* (*Thunk_Object_4)(void* param_1, void* param_2, void* param_3, void* param_4, MObject** exception);
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
#include "ManagedCLR/MCore.h"
|
||||
#endif
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#if USE_MONO
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
#endif
|
||||
|
||||
#define ScriptingObject_unmanagedPtr "__unmanagedPtr"
|
||||
#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;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
MonoObject* ScriptingObject::GetOrCreateManagedInstance() const
|
||||
MObject* ScriptingObject::GetOrCreateManagedInstance() const
|
||||
{
|
||||
MonoObject* managedInstance = GetManagedInstance();
|
||||
MObject* managedInstance = GetManagedInstance();
|
||||
if (!managedInstance)
|
||||
{
|
||||
const_cast<ScriptingObject*>(this)->CreateManaged();
|
||||
@@ -144,9 +150,10 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
|
||||
return result;
|
||||
}
|
||||
|
||||
ScriptingObject* ScriptingObject::ToNative(MonoObject* obj)
|
||||
ScriptingObject* ScriptingObject::ToNative(MObject* obj)
|
||||
{
|
||||
ScriptingObject* ptr = nullptr;
|
||||
#if USE_MONO
|
||||
if (obj)
|
||||
{
|
||||
// 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);
|
||||
mono_field_get_value(obj, ptrField, &ptr);
|
||||
}
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -191,7 +199,9 @@ void ScriptingObject::OnManagedInstanceDeleted()
|
||||
// Release the handle
|
||||
if (_gcHandle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(_gcHandle);
|
||||
#endif
|
||||
_gcHandle = 0;
|
||||
}
|
||||
|
||||
@@ -212,6 +222,8 @@ void ScriptingObject::OnScriptingDispose()
|
||||
DeleteObject();
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
MonoObject* ScriptingObject::CreateManagedInternal()
|
||||
{
|
||||
#if BUILD_DEBUG
|
||||
@@ -254,8 +266,11 @@ MonoObject* ScriptingObject::CreateManagedInternal()
|
||||
return managedInstance;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ScriptingObject::DestroyManaged()
|
||||
{
|
||||
#if USE_MONO
|
||||
// Get managed instance
|
||||
const auto managedInstance = GetManagedInstance();
|
||||
|
||||
@@ -279,6 +294,9 @@ void ScriptingObject::DestroyManaged()
|
||||
mono_gchandle_free(_gcHandle);
|
||||
_gcHandle = 0;
|
||||
}
|
||||
#else
|
||||
_gcHandle = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ScriptingObject::RegisterObject()
|
||||
@@ -319,6 +337,8 @@ bool ScriptingObject::CanCast(MClass* from, MClass* to)
|
||||
return from->IsSubClassOf(to);
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
|
||||
bool ScriptingObject::CanCast(MClass* from, MonoClass* to)
|
||||
{
|
||||
if (!from && !to)
|
||||
@@ -333,6 +353,8 @@ bool ScriptingObject::CanCast(MClass* from, MonoClass* to)
|
||||
return from->IsSubClassOf(to);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ScriptingObject::OnDeleteObject()
|
||||
{
|
||||
// Cleanup managed object
|
||||
@@ -358,6 +380,7 @@ ManagedScriptingObject::ManagedScriptingObject(const SpawnParams& params)
|
||||
|
||||
void ManagedScriptingObject::CreateManaged()
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoObject* managedInstance = CreateManagedInternal();
|
||||
if (managedInstance)
|
||||
{
|
||||
@@ -368,6 +391,11 @@ void ManagedScriptingObject::CreateManaged()
|
||||
if (!IsRegistered())
|
||||
RegisterObject();
|
||||
}
|
||||
#else
|
||||
// Ensure to be registered
|
||||
if (!IsRegistered())
|
||||
RegisterObject();
|
||||
#endif
|
||||
}
|
||||
|
||||
PersistentScriptingObject::PersistentScriptingObject(const SpawnParams& params)
|
||||
@@ -385,7 +413,9 @@ void PersistentScriptingObject::OnManagedInstanceDeleted()
|
||||
// Cleanup
|
||||
if (_gcHandle)
|
||||
{
|
||||
#if USE_MONO
|
||||
mono_gchandle_free(_gcHandle);
|
||||
#endif
|
||||
_gcHandle = 0;
|
||||
}
|
||||
|
||||
@@ -404,6 +434,7 @@ void PersistentScriptingObject::OnScriptingDispose()
|
||||
|
||||
void PersistentScriptingObject::CreateManaged()
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoObject* managedInstance = CreateManagedInternal();
|
||||
if (managedInstance)
|
||||
{
|
||||
@@ -414,11 +445,18 @@ void PersistentScriptingObject::CreateManaged()
|
||||
if (!IsRegistered())
|
||||
RegisterObject();
|
||||
}
|
||||
#else
|
||||
// Ensure to be registered
|
||||
if (!IsRegistered())
|
||||
RegisterObject();
|
||||
#endif
|
||||
}
|
||||
|
||||
class ScriptingObjectInternal
|
||||
{
|
||||
public:
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
|
||||
static MonoObject* Create1(MonoReflectionType* type)
|
||||
{
|
||||
@@ -676,6 +714,14 @@ public:
|
||||
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_GetUnmanagedInterface", &GetUnmanagedInterface);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void InitRuntime()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static ScriptingObject* Spawn(const ScriptingObjectSpawnParams& params)
|
||||
{
|
||||
return New<PersistentScriptingObject>(params);
|
||||
|
||||
@@ -62,12 +62,12 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the managed instance object.
|
||||
/// </summary>
|
||||
MonoObject* GetManagedInstance() const;
|
||||
MObject* GetManagedInstance() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the managed instance object or creates it if missing.
|
||||
/// </summary>
|
||||
MonoObject* GetOrCreateManagedInstance() const;
|
||||
MObject* GetOrCreateManagedInstance() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether managed instance is alive.
|
||||
@@ -117,9 +117,9 @@ public:
|
||||
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;
|
||||
}
|
||||
@@ -139,7 +139,9 @@ public:
|
||||
/// <param name="to">The destination class to the cast.</param>
|
||||
/// <returns>True if can, otherwise false.</returns>
|
||||
static bool CanCast(MClass* from, MClass* to);
|
||||
#if USE_MONO
|
||||
static bool CanCast(MClass* from, MonoClass* to);
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
static T* Cast(ScriptingObject* obj)
|
||||
@@ -154,10 +156,12 @@ public:
|
||||
return CanCast(GetClass(), type);
|
||||
}
|
||||
|
||||
#if USE_MONO
|
||||
bool Is(MonoClass* klass) const
|
||||
{
|
||||
return CanCast(GetClass(), klass);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
bool Is() const
|
||||
@@ -186,7 +190,6 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this object is registered or not (can be found by the queries and used in a game).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this instance is registered; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsRegistered() const
|
||||
{
|
||||
return (Flags & ObjectFlags::IsRegistered) != 0;
|
||||
@@ -204,10 +207,12 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
#if USE_MONO
|
||||
/// <summary>
|
||||
/// Create a new managed object.
|
||||
/// </summary>
|
||||
MonoObject* CreateManagedInternal();
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets managed instance object (or null if no object linked).
|
||||
/// </summary>
|
||||
FORCE_INLINE MonoObject* GetManagedInstance() const
|
||||
FORCE_INLINE MObject* GetManagedInstance() const
|
||||
{
|
||||
return _object ? _object->GetOrCreateManagedInstance() : nullptr;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the managed instance object or creates it if missing or null if not assigned.
|
||||
/// </summary>
|
||||
FORCE_INLINE MonoObject* GetOrCreateManagedInstance() const
|
||||
FORCE_INLINE MObject* GetOrCreateManagedInstance() const
|
||||
{
|
||||
return _object ? _object->GetOrCreateManagedInstance() : nullptr;
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ class NativeBinaryModule;
|
||||
struct ScriptingTypeHandle;
|
||||
struct ScriptingTypeInitializer;
|
||||
struct ScriptingObjectSpawnParams;
|
||||
typedef struct _MonoClass MonoClass;
|
||||
typedef struct _MonoObject MonoObject;
|
||||
typedef struct _MonoType MonoType;
|
||||
|
||||
/// <summary>
|
||||
/// 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 (*Dtor)(void* ptr);
|
||||
typedef void (*Copy)(void* dst, void* src);
|
||||
typedef MonoObject* (*Box)(void* ptr);
|
||||
typedef void (*Unbox)(void* ptr, MonoObject* managed);
|
||||
typedef MObject* (*Box)(void* ptr);
|
||||
typedef void (*Unbox)(void* ptr, MObject* managed);
|
||||
typedef void (*GetField)(void* ptr, const String& name, Variant& value);
|
||||
typedef void (*SetField)(void* ptr, const String& name, const Variant& value);
|
||||
typedef void* (*GetInterfaceWrapper)(ScriptingObject* obj);
|
||||
|
||||
@@ -281,7 +281,7 @@ public:
|
||||
/// Gets managed instance object (or null if no object linked).
|
||||
/// </summary>
|
||||
/// <returns>The managed object instance.</returns>
|
||||
MonoObject* GetManagedInstance() const
|
||||
MObject* GetManagedInstance() const
|
||||
{
|
||||
auto object = Get();
|
||||
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.
|
||||
/// </summary>
|
||||
/// <returns>The Mono managed object.</returns>
|
||||
MonoObject* GetOrCreateManagedInstance() const
|
||||
MObject* GetOrCreateManagedInstance() const
|
||||
{
|
||||
auto object = Get();
|
||||
return object ? object->GetOrCreateManagedInstance() : nullptr;
|
||||
|
||||
@@ -47,6 +47,7 @@ void StdTypesContainer::Clear()
|
||||
|
||||
bool StdTypesContainer::Gather()
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
#define GET_CLASS(assembly, type, typeName) \
|
||||
type = ((ManagedBinaryModule*)CONCAT_MACROS(GetBinaryModule, assembly)())->Assembly->GetClass(typeName); \
|
||||
if (type == nullptr) \
|
||||
@@ -93,5 +94,6 @@ bool StdTypesContainer::Gather()
|
||||
|
||||
#undef GET_CLASS
|
||||
#undef GET_METHOD
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,69 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// Forward declarations
|
||||
class Scripting;
|
||||
struct ScriptingType;
|
||||
class BinaryModule;
|
||||
class ScriptingObject;
|
||||
class MCore;
|
||||
class MDomain;
|
||||
class MException;
|
||||
class MAssembly;
|
||||
class MClass;
|
||||
class MField;
|
||||
class MMethod;
|
||||
class MProperty;
|
||||
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
|
||||
|
||||
@@ -208,12 +208,14 @@ void Serialization::Serialize(ISerializable::SerializeStream& stream, const Vari
|
||||
case VariantType::ManagedObject:
|
||||
case VariantType::Structure:
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoObject* obj;
|
||||
if (v.Type.Type == VariantType::Structure)
|
||||
obj = MUtils::BoxVariant(v);
|
||||
else
|
||||
obj = (MonoObject*)v;
|
||||
ManagedSerialization::Serialize(stream, obj);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -346,6 +348,7 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
|
||||
case VariantType::ManagedObject:
|
||||
case VariantType::Structure:
|
||||
{
|
||||
#if USE_MONO
|
||||
auto obj = (MonoObject*)v;
|
||||
if (!obj && v.Type.TypeName)
|
||||
{
|
||||
@@ -369,6 +372,7 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
|
||||
ManagedSerialization::Deserialize(value, obj);
|
||||
if (v.Type.Type == VariantType::Structure)
|
||||
v = MUtils::UnboxVariant(obj);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -356,6 +356,7 @@ void ReadStream::ReadVariant(Variant* data)
|
||||
// Json
|
||||
StringAnsi json;
|
||||
ReadStringAnsi(&json, -71);
|
||||
#if USE_MONO
|
||||
MCore::AttachThread();
|
||||
MonoClass* klass = MUtils::GetClass(data->Type);
|
||||
if (!klass)
|
||||
@@ -376,6 +377,7 @@ void ReadStream::ReadVariant(Variant* data)
|
||||
data->SetManagedObject(obj);
|
||||
else
|
||||
*data = MUtils::UnboxVariant(obj);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -706,6 +708,7 @@ void WriteStream::WriteVariant(const Variant& data)
|
||||
case VariantType::ManagedObject:
|
||||
case VariantType::Structure:
|
||||
{
|
||||
#if USE_MONO
|
||||
MonoObject* obj;
|
||||
if (data.Type.Type == VariantType::Structure)
|
||||
obj = MUtils::BoxVariant(data);
|
||||
@@ -721,6 +724,7 @@ void WriteStream::WriteVariant(const Variant& data)
|
||||
WriteStringAnsi(StringAnsiView(json.GetString(), (int32)json.GetSize()), -71);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
WriteByte(0);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
if (attachMonoThread && !mono_domain_get())
|
||||
{
|
||||
const auto domain = MCore::Instance()->GetActiveDomain();
|
||||
const auto domain = MCore::GetActiveDomain();
|
||||
mono_thread_attach(domain->GetNative());
|
||||
attachMonoThread = false;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,13 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#if USE_MONO
|
||||
#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)
|
||||
MMethod* UICanvas_Serialize = nullptr;
|
||||
MMethod* UICanvas_SerializeDiff = nullptr;
|
||||
@@ -24,7 +29,7 @@ MMethod* UICanvas_ParentChanged = nullptr;
|
||||
auto instance = GetManagedInstance(); \
|
||||
if (instance) \
|
||||
{ \
|
||||
MonoObject* exception = nullptr; \
|
||||
MObject* exception = nullptr; \
|
||||
UICanvas_##event->Invoke(instance, nullptr, &exception); \
|
||||
if (exception) \
|
||||
{ \
|
||||
@@ -32,10 +37,12 @@ MMethod* UICanvas_ParentChanged = nullptr;
|
||||
ex.Log(LogType::Error, TEXT("UICanvas::" #event)); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
UICanvas::UICanvas(const SpawnParams& params)
|
||||
: Actor(params)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
Platform::MemoryBarrier();
|
||||
if (UICanvas_Serialize == nullptr)
|
||||
{
|
||||
@@ -52,6 +59,7 @@ UICanvas::UICanvas(const SpawnParams& params)
|
||||
UICanvas_EndPlay = mclass->GetMethod("EndPlay");
|
||||
UICanvas_ParentChanged = mclass->GetMethod("ParentChanged");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -71,10 +79,11 @@ void UICanvas::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
|
||||
SERIALIZE_GET_OTHER_OBJ(UICanvas);
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
stream.JKEY("V");
|
||||
void* params[1];
|
||||
params[0] = other ? other->GetOrCreateManagedInstance() : nullptr;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
auto method = other ? UICanvas_SerializeDiff : UICanvas_Serialize;
|
||||
auto invokeResultStr = (MonoString*)method->Invoke(GetOrCreateManagedInstance(), params, &exception);
|
||||
if (exception)
|
||||
@@ -93,6 +102,7 @@ void UICanvas::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
stream.RawValue(invokeResultChars);
|
||||
mono_free(invokeResultChars);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
@@ -100,6 +110,7 @@ void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi
|
||||
// Base
|
||||
Actor::Deserialize(stream, modifier);
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Handle C# object data serialization
|
||||
const auto dataMember = stream.FindMember("V");
|
||||
if (dataMember != stream.MemberEnd())
|
||||
@@ -110,7 +121,7 @@ void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi
|
||||
const auto str = buffer.GetString();
|
||||
void* args[1];
|
||||
args[0] = mono_string_new(mono_domain_get(), str);
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
UICanvas_Deserialize->Invoke(GetOrCreateManagedInstance(), args, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -118,6 +129,7 @@ void UICanvas::Deserialize(DeserializeStream& stream, ISerializeModifier* modifi
|
||||
ex.Log(LogType::Error, TEXT("UICanvas::Deserialize"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsDuringPlay())
|
||||
{
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#if USE_MONO
|
||||
#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)
|
||||
MMethod* UIControl_Serialize = nullptr;
|
||||
MMethod* UIControl_SerializeDiff = nullptr;
|
||||
@@ -22,7 +27,7 @@ MMethod* UIControl_EndPlay = nullptr;
|
||||
#define UICONTROL_INVOKE(event) \
|
||||
if (HasManagedInstance()) \
|
||||
{ \
|
||||
MonoObject* exception = nullptr; \
|
||||
MObject* exception = nullptr; \
|
||||
UIControl_##event->Invoke(GetManagedInstance(), nullptr, &exception); \
|
||||
if (exception) \
|
||||
{ \
|
||||
@@ -30,10 +35,12 @@ MMethod* UIControl_EndPlay = nullptr;
|
||||
ex.Log(LogType::Error, TEXT("UICanvas::" #event)); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
UIControl::UIControl(const SpawnParams& params)
|
||||
: Actor(params)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
if (UIControl_Serialize == nullptr)
|
||||
{
|
||||
MClass* mclass = GetClass();
|
||||
@@ -47,6 +54,7 @@ UIControl::UIControl(const SpawnParams& params)
|
||||
UIControl_BeginPlay = mclass->GetMethod("BeginPlay");
|
||||
UIControl_EndPlay = mclass->GetMethod("EndPlay");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -66,11 +74,12 @@ void UIControl::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
|
||||
SERIALIZE_GET_OTHER_OBJ(UIControl);
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
void* params[2];
|
||||
MonoString* controlType = nullptr;
|
||||
params[0] = &controlType;
|
||||
params[1] = other ? other->GetOrCreateManagedInstance() : nullptr;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
const auto method = other ? UIControl_SerializeDiff : UIControl_Serialize;
|
||||
const auto invokeResultStr = (MonoString*)method->Invoke(GetOrCreateManagedInstance(), params, &exception);
|
||||
if (exception)
|
||||
@@ -107,6 +116,7 @@ void UIControl::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
const auto invokeResultChars = mono_string_to_utf8(invokeResultStr);
|
||||
stream.RawValue(invokeResultChars);
|
||||
mono_free(invokeResultChars);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
@@ -114,6 +124,7 @@ void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
|
||||
// Base
|
||||
Actor::Deserialize(stream, modifier);
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
MonoReflectionType* typeObj = nullptr;
|
||||
const auto controlMember = stream.FindMember("Control");
|
||||
if (controlMember != stream.MemberEnd())
|
||||
@@ -140,7 +151,7 @@ void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
|
||||
void* args[2];
|
||||
args[0] = mono_string_new(mono_domain_get(), str);
|
||||
args[1] = typeObj;
|
||||
MonoObject* exception = nullptr;
|
||||
MObject* exception = nullptr;
|
||||
UIControl_Deserialize->Invoke(GetOrCreateManagedInstance(), args, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -148,6 +159,7 @@ void UIControl::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
|
||||
ex.Log(LogType::Error, TEXT("UIControl::Deserialize"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UIControl::OnParentChanged()
|
||||
|
||||
@@ -523,6 +523,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
|
||||
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeNameAnsiView);
|
||||
if (!typeHandle)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
const auto mclass = Scripting::FindClass(typeNameAnsiView);
|
||||
if (mclass)
|
||||
{
|
||||
@@ -559,6 +560,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
|
||||
}
|
||||
}
|
||||
else if (typeName.HasChars())
|
||||
#endif
|
||||
{
|
||||
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);
|
||||
if (!typeHandle)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
const auto mclass = Scripting::FindClass(typeNameAnsiView);
|
||||
if (mclass)
|
||||
{
|
||||
@@ -646,6 +649,7 @@ void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
|
||||
}
|
||||
}
|
||||
else if (typeName.HasChars())
|
||||
#endif
|
||||
{
|
||||
OnError(node, box, String::Format(TEXT("Missing type '{0}'"), typeName));
|
||||
}
|
||||
|
||||
@@ -27,9 +27,19 @@ namespace Flax.Build.Bindings
|
||||
private static readonly HashSet<TypeInfo> CppVariantFromTypes = new HashSet<TypeInfo>();
|
||||
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;
|
||||
@@ -1003,6 +1013,8 @@ namespace Flax.Build.Bindings
|
||||
|
||||
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);
|
||||
var separator = false;
|
||||
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(" {");
|
||||
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($" 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(" }");
|
||||
count++;
|
||||
}
|
||||
contents.AppendLine(" }");
|
||||
contents.AppendLine(" else");
|
||||
@@ -1412,6 +1428,7 @@ namespace Flax.Build.Bindings
|
||||
if (classInfo.Parent != null && !(classInfo.Parent is FileInfo))
|
||||
classTypeNameInternal = classInfo.Parent.FullNameNative + '_' + classTypeNameInternal;
|
||||
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);
|
||||
|
||||
if (classInfo.IsAutoSerialization)
|
||||
@@ -1428,74 +1445,77 @@ namespace Flax.Build.Bindings
|
||||
if (!useScripting)
|
||||
continue;
|
||||
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");
|
||||
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->";
|
||||
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();
|
||||
|
||||
if (useCSharp)
|
||||
{
|
||||
// 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)
|
||||
CppIncludeFiles.Add("Engine/Scripting/Events.h");
|
||||
@@ -1551,7 +1571,7 @@ namespace Flax.Build.Bindings
|
||||
// Fields
|
||||
foreach (var fieldInfo in classInfo.Fields)
|
||||
{
|
||||
if (!useScripting)
|
||||
if (!useScripting || !useCSharp)
|
||||
continue;
|
||||
if (fieldInfo.Getter != null)
|
||||
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Getter, "{0}");
|
||||
@@ -1568,7 +1588,7 @@ namespace Flax.Build.Bindings
|
||||
// Properties
|
||||
foreach (var propertyInfo in classInfo.Properties)
|
||||
{
|
||||
if (!useScripting)
|
||||
if (!useScripting || !useCSharp)
|
||||
continue;
|
||||
if (propertyInfo.Getter != null)
|
||||
GenerateCppWrapperFunction(buildData, contents, classInfo, propertyInfo.Getter);
|
||||
@@ -1579,13 +1599,15 @@ namespace Flax.Build.Bindings
|
||||
// Functions
|
||||
foreach (var functionInfo in classInfo.Functions)
|
||||
{
|
||||
if (!useCSharp)
|
||||
continue;
|
||||
if (!useScripting)
|
||||
throw new Exception($"Not supported function {functionInfo.Name} inside non-static and non-scripting class type {classInfo.Name}.");
|
||||
GenerateCppWrapperFunction(buildData, contents, classInfo, functionInfo);
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
if (hasInterface)
|
||||
if (hasInterface && useCSharp)
|
||||
{
|
||||
foreach (var interfaceInfo in classInfo.Interfaces)
|
||||
{
|
||||
@@ -1612,11 +1634,16 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
foreach (var eventInfo in classInfo.Events)
|
||||
{
|
||||
contents.AppendLine($" ADD_INTERNAL_CALL(\"{classTypeNameManagedInternalCall}::Internal_{eventInfo.Name}_Bind\", &{eventInfo.Name}_ManagedBind);");
|
||||
|
||||
// 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;");
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (fieldInfo.Getter != null)
|
||||
@@ -1720,6 +1747,7 @@ namespace Flax.Build.Bindings
|
||||
var structureTypeNameInternal = structureInfo.NativeName;
|
||||
if (structureInfo.Parent != null && !(structureInfo.Parent is FileInfo))
|
||||
structureTypeNameInternal = structureInfo.Parent.FullNameNative + '_' + structureTypeNameInternal;
|
||||
var useCSharp = EngineConfiguration.WithCSharp(buildData.TargetOptions);
|
||||
|
||||
if (structureInfo.IsAutoSerialization)
|
||||
GenerateCppAutoSerialization(buildData, contents, moduleInfo, structureInfo, structureTypeNameNative);
|
||||
@@ -1786,12 +1814,15 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine(" static void InitRuntime()");
|
||||
contents.AppendLine(" {");
|
||||
|
||||
foreach (var fieldInfo in structureInfo.Fields)
|
||||
if (useCSharp)
|
||||
{
|
||||
if (fieldInfo.Getter != null)
|
||||
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});");
|
||||
foreach (var fieldInfo in structureInfo.Fields)
|
||||
{
|
||||
if (fieldInfo.Getter != null)
|
||||
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();
|
||||
@@ -1814,28 +1845,41 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine($" *({structureTypeNameNative}*)dst = *({structureTypeNameNative}*)src;");
|
||||
contents.AppendLine(" }").AppendLine();
|
||||
|
||||
// Boxing structures from native data to managed object
|
||||
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
|
||||
if (!structureInfo.IsPod && !CppUsedNonPodTypes.Contains(structureInfo))
|
||||
CppUsedNonPodTypes.Add(structureInfo);
|
||||
contents.AppendLine(" static MonoObject* Box(void* ptr)");
|
||||
contents.AppendLine(" {");
|
||||
contents.AppendLine($" MonoObject* managed = mono_object_new(mono_domain_get(), {structureTypeNameNative}::TypeInitializer.GetType().ManagedClass->GetNative());");
|
||||
if (structureInfo.IsPod)
|
||||
contents.AppendLine($" Platform::MemoryCopy(mono_object_unbox(managed), ptr, sizeof({structureTypeNameNative}));");
|
||||
else
|
||||
contents.AppendLine($" *({structureInfo.NativeName}Managed*)mono_object_unbox(managed) = ToManaged(*({structureTypeNameNative}*)ptr);");
|
||||
contents.AppendLine(" return managed;");
|
||||
contents.AppendLine(" }").AppendLine();
|
||||
if (useCSharp)
|
||||
{
|
||||
// Boxing structures from native data to managed object
|
||||
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
|
||||
if (!structureInfo.IsPod && !CppUsedNonPodTypes.Contains(structureInfo))
|
||||
CppUsedNonPodTypes.Add(structureInfo);
|
||||
contents.AppendLine(" static MObject* Box(void* ptr)");
|
||||
contents.AppendLine(" {");
|
||||
contents.AppendLine($" MonoObject* managed = mono_object_new(mono_domain_get(), {structureTypeNameNative}::TypeInitializer.GetType().ManagedClass->GetNative());");
|
||||
if (structureInfo.IsPod)
|
||||
contents.AppendLine($" Platform::MemoryCopy(mono_object_unbox(managed), ptr, sizeof({structureTypeNameNative}));");
|
||||
else
|
||||
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
|
||||
contents.AppendLine(" static void Unbox(void* ptr, MonoObject* managed)");
|
||||
contents.AppendLine(" {");
|
||||
if (structureInfo.IsPod)
|
||||
contents.AppendLine($" Platform::MemoryCopy(ptr, mono_object_unbox(managed), sizeof({structureTypeNameNative}));");
|
||||
// Unboxing structures from managed object to native data
|
||||
contents.AppendLine(" static void Unbox(void* ptr, MObject* managed)");
|
||||
contents.AppendLine(" {");
|
||||
if (structureInfo.IsPod)
|
||||
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
|
||||
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
|
||||
contents.AppendLine(" static void GetField(void* ptr, const String& name, Variant& value)");
|
||||
@@ -2060,6 +2104,9 @@ namespace Flax.Build.Bindings
|
||||
CppVariantToTypes.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();
|
||||
contents.AppendLine("#include \"Engine/Core/Compiler.h\"");
|
||||
@@ -2174,8 +2221,11 @@ namespace Flax.Build.Bindings
|
||||
|
||||
// Non-POD types
|
||||
CppUsedNonPodTypesList.Clear();
|
||||
for (int k = 0; k < CppUsedNonPodTypes.Count; k++)
|
||||
GenerateCppCppUsedNonPodTypes(buildData, CppUsedNonPodTypes[k]);
|
||||
if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
|
||||
{
|
||||
for (int k = 0; k < CppUsedNonPodTypes.Count; k++)
|
||||
GenerateCppCppUsedNonPodTypes(buildData, CppUsedNonPodTypes[k]);
|
||||
}
|
||||
foreach (var apiType in CppUsedNonPodTypesList)
|
||||
{
|
||||
header.AppendLine();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
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.
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
if (buildData.ModulesInfo.TryGetValue(module, out var moduleInfo))
|
||||
@@ -513,7 +526,7 @@ namespace Flax.Build.Bindings
|
||||
buildData.Modules.TryGetValue(moduleInfo.Module, out var moduleBuildInfo);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -533,10 +546,12 @@ namespace Flax.Build.Bindings
|
||||
Log.Verbose($"Generating API bindings for {module.Name} ({moduleInfo.Name})");
|
||||
using (new ProfileEventScope("Cpp"))
|
||||
GenerateCpp(buildData, moduleInfo, ref bindings);
|
||||
using (new ProfileEventScope("CSharp"))
|
||||
GenerateCSharp(buildData, moduleInfo, ref bindings);
|
||||
|
||||
// TODO: add support for extending this code and support generating bindings for other scripting languages
|
||||
if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
|
||||
{
|
||||
using (new ProfileEventScope("CSharp"))
|
||||
GenerateCSharp(buildData, moduleInfo, ref bindings);
|
||||
}
|
||||
GenerateBinaryModuleBindings?.Invoke(buildData, moduleInfo, ref bindings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,9 +567,11 @@ namespace Flax.Build.Bindings
|
||||
// Generate bindings for binary module
|
||||
Log.Verbose($"Generating binary module bindings for {binaryModule.Key}");
|
||||
GenerateCpp(buildData, binaryModule);
|
||||
GenerateCSharp(buildData, binaryModule);
|
||||
|
||||
// TODO: add support for extending this code and support generating bindings for other scripting languages
|
||||
if (EngineConfiguration.WithCSharp(buildData.TargetOptions))
|
||||
{
|
||||
GenerateCSharp(buildData, binaryModule);
|
||||
}
|
||||
GenerateModuleBindings?.Invoke(buildData, binaryModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Flax.Build
|
||||
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 args = new List<string>();
|
||||
|
||||
@@ -167,6 +167,7 @@ namespace Flax.Build
|
||||
|
||||
public static event Action<TaskGraph, BuildOptions> PreBuild;
|
||||
public static event Action<TaskGraph, BuildOptions> PostBuild;
|
||||
public static event Action<TaskGraph, BuildData> BuildBindings;
|
||||
|
||||
/// <summary>
|
||||
/// Collects the modules required by the given target to build (includes dependencies).
|
||||
@@ -226,6 +227,20 @@ namespace Flax.Build
|
||||
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)
|
||||
{
|
||||
using (new ProfileEventScope("LinkNativeBinary"))
|
||||
@@ -794,13 +809,7 @@ namespace Flax.Build
|
||||
}
|
||||
|
||||
// Build scripting API bindings
|
||||
using (new ProfileEventScope("BuildBindings"))
|
||||
{
|
||||
if (!buildData.Target.IsPreBuilt)
|
||||
{
|
||||
BuildTargetBindings(rules, graph, buildData);
|
||||
}
|
||||
}
|
||||
OnBuildBindings(buildData, graph);
|
||||
|
||||
// Link modules into a target
|
||||
var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions);
|
||||
@@ -835,7 +844,7 @@ namespace Flax.Build
|
||||
var binaryModuleInfo = new BuildTargetBinaryModuleInfo
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -1069,11 +1078,7 @@ namespace Flax.Build
|
||||
}
|
||||
|
||||
// Build scripting API bindings
|
||||
using (new ProfileEventScope("BuildBindings"))
|
||||
{
|
||||
if (!buildData.Target.IsPreBuilt)
|
||||
BuildTargetBindings(rules, graph, buildData);
|
||||
}
|
||||
OnBuildBindings(buildData, graph);
|
||||
|
||||
// Link modules into a target
|
||||
var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions);
|
||||
@@ -1099,7 +1104,7 @@ namespace Flax.Build
|
||||
var binaryModuleInfo = new BuildTargetBinaryModuleInfo
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -17,7 +17,11 @@ namespace Flax.Build.Plugins
|
||||
base.Init();
|
||||
|
||||
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)
|
||||
|
||||
@@ -67,6 +67,12 @@ namespace Flax.Build
|
||||
options.CompileEnv.IncludePaths.Add(Path.Combine(Project.ProjectFolderPath, "Source"));
|
||||
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
|
||||
foreach (var reference in Project.References)
|
||||
{
|
||||
|
||||
@@ -212,4 +212,21 @@ namespace Flax.Build
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Flax.Build
|
||||
{
|
||||
// Setup
|
||||
CommandLine.Configure(typeof(Configuration));
|
||||
CommandLine.Configure(typeof(EngineConfiguration));
|
||||
foreach (var option in CommandLine.GetOptions())
|
||||
{
|
||||
if (option.Name.Length > 1 && option.Name[0] == 'D')
|
||||
|
||||
Reference in New Issue
Block a user