Refactor native core objects to simplify usage for newcomers
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
// [PersistentScriptingObject]
|
||||
// [ScriptingObject]
|
||||
String ToString() const override;
|
||||
void OnDeleteObject() override;
|
||||
|
||||
|
||||
@@ -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, ¶m);
|
||||
}
|
||||
}
|
||||
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, ¶m);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user