Refactor native core objects to simplify usage for newcomers

This commit is contained in:
2022-01-08 15:06:23 +01:00
parent e144a6f69d
commit 192af7ec14
47 changed files with 204 additions and 249 deletions
+1 -1
View File
@@ -197,7 +197,7 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
// Converter for Scripting Objects (collection of values).
template<typename T>
struct MConverter<T, typename TEnableIf<TIsBaseOf<class PersistentScriptingObject, T>::Value>::Type>
struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Value>::Type>
{
MonoObject* Box(const T& data, MonoClass* klass)
{
+1 -1
View File
@@ -134,7 +134,7 @@ private:
public:
// [PersistentScriptingObject]
// [ScriptingObject]
String ToString() const override;
void OnDeleteObject() override;
+75 -89
View File
@@ -40,20 +40,32 @@ ScriptingObject::ScriptingObject(const SpawnParams& params)
ScriptingObject::~ScriptingObject()
{
// Ensure that GC handle is empty
ASSERT(_gcHandle == 0);
// Ensure that object has been already unregistered
if (IsRegistered())
UnregisterObject();
Deleted(this);
// Get rid of managed object
ScriptingObject::DestroyManaged();
ASSERT(_gcHandle == 0);
// Handle custom scripting objects removing
if (Flags & ObjectFlags::IsCustomScriptingType)
{
_type.Module->OnObjectDeleted(this);
}
// Ensure that object has been already unregistered
if (IsRegistered())
UnregisterObject();
}
ScriptingObject* ScriptingObject::NewObject(const ScriptingTypeHandle& typeHandle)
{
if (!typeHandle)
return nullptr;
auto& type = typeHandle.GetType();
if (type.Type != ScriptingTypes::Script)
return nullptr;
const ScriptingObjectSpawnParams params(Guid::New(), typeHandle);
return type.Script.Spawn(params);
}
MObject* ScriptingObject::GetManagedInstance() const
@@ -82,17 +94,6 @@ MClass* ScriptingObject::GetClass() const
return _type ? _type.GetType().ManagedClass : nullptr;
}
ScriptingObject* ScriptingObject::NewObject(const ScriptingTypeHandle& typeHandle)
{
if (!typeHandle)
return nullptr;
auto& type = typeHandle.GetType();
if (type.Type != ScriptingTypes::Script)
return nullptr;
const ScriptingObjectSpawnParams params(Guid::New(), typeHandle);
return type.Script.Spawn(params);
}
ScriptingObject* ScriptingObject::FromInterface(void* interfaceObj, const ScriptingTypeHandle& interfaceType)
{
if (!interfaceObj || !interfaceType)
@@ -220,18 +221,49 @@ void ScriptingObject::OnManagedInstanceDeleted()
// Unregister object
if (IsRegistered())
UnregisterObject();
// Self destruct
DeleteObject();
}
void ScriptingObject::OnScriptingDispose()
{
// Delete C# object
if (IsRegistered())
UnregisterObject();
DestroyManaged();
}
// Delete C++ object
DeleteObject();
bool ScriptingObject::CreateManaged()
{
#if USE_MONO
MonoObject* managedInstance = CreateManagedInternal();
if (!managedInstance)
return true;
// Prevent form object GC destruction
auto handle = mono_gchandle_new(managedInstance, false);
auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0);
if (*(uint32*)&oldHandle != 0)
{
// Other thread already created the object before
if (const auto monoClass = GetClass())
{
// Reset managed to unmanaged pointer
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
if (monoUnmanagedPtrField)
{
void* param = nullptr;
monoUnmanagedPtrField->SetValue(managedInstance, &param);
}
}
mono_gchandle_free(handle);
return true;
}
#endif
// Ensure to be registered
if (!IsRegistered())
RegisterObject();
return false;
}
#if USE_MONO
@@ -379,7 +411,7 @@ void ScriptingObject::OnDeleteObject()
UnregisterObject();
// Base
RemovableObject::OnDeleteObject();
Object::OnDeleteObject();
}
String ScriptingObject::ToString() const
@@ -392,6 +424,24 @@ ManagedScriptingObject::ManagedScriptingObject(const SpawnParams& params)
{
}
void ManagedScriptingObject::OnManagedInstanceDeleted()
{
// Base
ScriptingObject::OnManagedInstanceDeleted();
// Self destruct
DeleteObject();
}
void ManagedScriptingObject::OnScriptingDispose()
{
// Base
ScriptingObject::OnScriptingDispose();
// Self destruct
DeleteObject();
}
bool ManagedScriptingObject::CreateManaged()
{
#if USE_MONO
@@ -432,70 +482,6 @@ PersistentScriptingObject::PersistentScriptingObject(const SpawnParams& params)
{
}
PersistentScriptingObject::~PersistentScriptingObject()
{
PersistentScriptingObject::DestroyManaged();
}
void PersistentScriptingObject::OnManagedInstanceDeleted()
{
// Cleanup
if (_gcHandle)
{
#if USE_MONO
mono_gchandle_free(_gcHandle);
#endif
_gcHandle = 0;
}
// But do not delete itself
}
void PersistentScriptingObject::OnScriptingDispose()
{
// Delete C# object
if (IsRegistered())
UnregisterObject();
DestroyManaged();
// Don't delete C++ object
}
bool PersistentScriptingObject::CreateManaged()
{
#if USE_MONO
MonoObject* managedInstance = CreateManagedInternal();
if (!managedInstance)
return true;
// Prevent form object GC destruction
auto handle = mono_gchandle_new(managedInstance, false);
auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0);
if (*(uint32*)&oldHandle != 0)
{
// Other thread already created the object before
if (const auto monoClass = GetClass())
{
// Reset managed to unmanaged pointer
const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr);
if (monoUnmanagedPtrField)
{
void* param = nullptr;
monoUnmanagedPtrField->SetValue(managedInstance, &param);
}
}
mono_gchandle_free(handle);
return true;
}
#endif
// Ensure to be registered
if (!IsRegistered())
RegisterObject();
return false;
}
class ScriptingObjectInternal
{
public:
@@ -767,7 +753,7 @@ public:
static ScriptingObject* Spawn(const ScriptingObjectSpawnParams& params)
{
return New<PersistentScriptingObject>(params);
return New<ScriptingObject>(params);
}
};
+29 -42
View File
@@ -8,9 +8,9 @@
#include "ManagedCLR/MTypes.h"
/// <summary>
/// Represents object from unmanaged memory that can use accessed via C# scripting.
/// Represents object from unmanaged memory that can use accessed via scripting.
/// </summary>
API_CLASS(InBuild) class FLAXENGINE_API ScriptingObject : public RemovableObject
API_CLASS(InBuild) class FLAXENGINE_API ScriptingObject : public Object
{
friend class Scripting;
friend class BinaryModule;
@@ -40,14 +40,23 @@ public:
public:
/// <summary>
/// Spawns a new objects of the given type.
/// </summary>
// Spawns a new objects of the given type.
static ScriptingObject* NewObject(const ScriptingTypeHandle& typeHandle);
template<typename T>
static T* Spawn()
static T* NewObject()
{
const SpawnParams params(Guid::New(), T::TypeInitializer);
return T::New(params);
return (T*)NewObject(T::TypeInitializer);
}
template<typename T>
static T* NewObject(const ScriptingTypeHandle& typeHandle)
{
auto obj = NewObject(typeHandle);
if (obj && !obj->Is<T>())
{
Delete(obj);
obj = nullptr;
}
return (T*)obj;
}
public:
@@ -108,13 +117,6 @@ public:
public:
static ScriptingObject* NewObject(const ScriptingTypeHandle& typeHandle);
template<typename T>
static T* NewObject()
{
return (T*)NewObject(T::TypeInitializer);
}
// Tries to cast native interface object to scripting object instance. Returns null if fails.
static ScriptingObject* FromInterface(void* interfaceObj, const ScriptingTypeHandle& interfaceType);
static void* ToInterface(ScriptingObject* obj, const ScriptingTypeHandle& interfaceType);
@@ -189,7 +191,7 @@ public:
virtual void OnManagedInstanceDeleted();
virtual void OnScriptingDispose();
virtual bool CreateManaged() = 0;
virtual bool CreateManaged();
virtual void DestroyManaged();
public:
@@ -223,7 +225,7 @@ protected:
public:
// [RemovableObject]
// [Object]
void OnDeleteObject() override;
String ToString() const override;
};
@@ -246,32 +248,17 @@ public:
public:
// [ScriptingObject]
bool CreateManaged() override;
};
/// <summary>
/// Managed object that uses pinned GC handle to prevent collecting and moving.
/// Used by the objects that lifetime is controlled by the C++ side.
/// </summary>
API_CLASS(InBuild) class FLAXENGINE_API PersistentScriptingObject : public ScriptingObject
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="PersistentScriptingObject"/> class.
/// </summary>
/// <param name="params">The object initialization parameters.</param>
explicit PersistentScriptingObject(const SpawnParams& params);
/// <summary>
/// Finalizes an instance of the <see cref="PersistentScriptingObject"/> class.
/// </summary>
~PersistentScriptingObject();
public:
// [ManagedScriptingObject]
void OnManagedInstanceDeleted() override;
void OnScriptingDispose() override;
bool CreateManaged() override;
};
/// <summary>
/// Use ScriptingObject instead.
/// [Deprecated on 5.01.2022, expires on 5.01.2024]
/// </summary>
API_CLASS(InBuild) class FLAXENGINE_API PersistentScriptingObject : public ScriptingObject
{
public:
PersistentScriptingObject(const SpawnParams& params);
};