Add support for compiling and running engine without C# scripting

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

View File

@@ -3,6 +3,7 @@
#include "GameCooker.h"
#include "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);

View File

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

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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())
{

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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
};

View File

@@ -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

View File

@@ -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
};

View File

@@ -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)

View File

@@ -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"

View File

@@ -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:

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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))

View File

@@ -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)

View File

@@ -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:

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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.

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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();
};

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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();
};

View File

@@ -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

View File

@@ -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();
};

View File

@@ -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

View File

@@ -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();
};

View File

@@ -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

View File

@@ -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();
};

View File

@@ -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
};

View File

@@ -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

View File

@@ -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
};

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
};

View File

@@ -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
}

View File

@@ -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");
}
}

View File

@@ -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
}
};

View File

@@ -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();
}

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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);
}

View File

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

View File

@@ -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())
{

View File

@@ -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()

View File

@@ -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));
}

View File

@@ -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();

View File

@@ -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);
}
}
}

View File

@@ -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>();

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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;
}
}
}

View File

@@ -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')