// Copyright (c) Wojciech Figat. All rights reserved.
#pragma once
#include "ScriptingType.h"
#include "Engine/Core/Object.h"
#include "Engine/Core/Delegate.h"
#include "ManagedCLR/MTypes.h"
#define SCRIPTING_OBJECT_CAST_WITH_CSHARP (USE_CSHARP)
///
/// Represents object from unmanaged memory that can use accessed via scripting.
///
API_CLASS(InBuild) class FLAXENGINE_API ScriptingObject : public Object
{
friend class Scripting;
friend class BinaryModule;
DECLARE_SCRIPTING_TYPE_NO_SPAWN(ScriptingObject);
public:
typedef ScriptingObjectSpawnParams SpawnParams;
protected:
MGCHandle _gcHandle;
ScriptingTypeHandle _type;
Guid _id;
public:
///
/// Initializes a new instance of the class.
///
/// The object initialization parameters.
explicit ScriptingObject(const SpawnParams& params);
///
/// Finalizes an instance of the class.
///
virtual ~ScriptingObject();
public:
// Spawns a new objects of the given type.
static ScriptingObject* NewObject(const ScriptingTypeHandle& typeHandle);
template
static T* NewObject()
{
return (T*)NewObject(T::TypeInitializer);
}
template
static T* NewObject(const ScriptingTypeHandle& typeHandle)
{
auto obj = NewObject(typeHandle);
if (obj && !obj->Is())
{
Delete(obj);
obj = nullptr;
}
return (T*)obj;
}
public:
///
/// Event fired when object gets deleted.
///
Delegate Deleted;
public:
///
/// Gets the managed instance object.
///
MObject* GetManagedInstance() const;
///
/// Gets the managed instance object or creates it if missing.
///
MObject* GetOrCreateManagedInstance() const;
///
/// Determines whether managed instance is alive.
///
FORCE_INLINE bool HasManagedInstance() const
{
return GetManagedInstance() != nullptr;
}
///
/// Gets the unique object ID.
///
FORCE_INLINE const Guid& GetID() const
{
return _id;
}
///
/// Gets the scripting type handle of this object.
///
FORCE_INLINE const ScriptingTypeHandle& GetTypeHandle() const
{
return _type;
}
///
/// Gets the scripting type of this object.
///
FORCE_INLINE const ScriptingType& GetType() const
{
return _type.GetType();
}
///
/// Gets the type class of this object.
///
MClass* GetClass() const;
public:
// Tries to cast native interface object to scripting object instance. Returns null if fails.
static ScriptingObject* FromInterface(void* interfaceObj, const ScriptingTypeHandle& interfaceType);
template
static ScriptingObject* FromInterface(T* interfaceObj)
{
return FromInterface(interfaceObj, T::TypeInitializer);
}
static void* ToInterface(ScriptingObject* obj, const ScriptingTypeHandle& interfaceType);
template
static T* ToInterface(ScriptingObject* obj)
{
return (T*)ToInterface(obj, T::TypeInitializer);
}
static ScriptingObject* ToNative(MObject* obj);
FORCE_INLINE static MObject* ToManaged(const ScriptingObject* obj)
{
return obj ? obj->GetOrCreateManagedInstance() : nullptr;
}
///
/// Checks if can cast one scripting object type into another type.
///
/// The object type for the cast.
/// The destination type to the cast.
/// True if can, otherwise false.
static bool CanCast(const ScriptingTypeHandle& from, const ScriptingTypeHandle& to);
///
/// Checks if can cast one scripting object type into another type.
///
/// The object class for the cast.
/// The destination class to the cast.
/// True if can, otherwise false.
static bool CanCast(const MClass* from, const MClass* to);
template
static T* Cast(ScriptingObject* obj)
{
#if SCRIPTING_OBJECT_CAST_WITH_CSHARP
return obj && CanCast(obj->GetClass(), T::GetStaticClass()) ? static_cast(obj) : nullptr;
#else
return obj && CanCast(obj->GetTypeHandle(), T::TypeInitializer) ? static_cast(obj) : nullptr;
#endif
}
bool Is(const ScriptingTypeHandle& type) const;
bool Is(const MClass* type) const
{
return CanCast(GetClass(), type);
}
template
bool Is() const
{
#if SCRIPTING_OBJECT_CAST_WITH_CSHARP
return CanCast(GetClass(), T::GetStaticClass());
#else
return CanCast(GetTypeHandle(), T::TypeInitializer);
#endif
}
public:
///
/// Changes the object id (both managed and unmanaged). Warning! Use with caution as object ID is what it identifies it and change might cause issues.
///
/// The new ID.
virtual void ChangeID(const Guid& newId);
public:
virtual void SetManagedInstance(MObject* instance);
virtual void OnManagedInstanceDeleted();
virtual void OnScriptingDispose();
virtual bool CreateManaged();
virtual void DestroyManaged();
public:
///
/// Determines whether this object is registered or not (can be found by the queries and used in a game).
///
FORCE_INLINE bool IsRegistered() const
{
return (Flags & ObjectFlags::IsRegistered) != ObjectFlags::None;
}
///
/// Registers the object (cannot be called when objects has been already registered).
///
void RegisterObject();
///
/// Unregisters the object (cannot be called when objects has not been already registered).
///
void UnregisterObject();
protected:
#if USE_CSHARP
///
/// Create a new managed object.
///
MObject* CreateManagedInternal();
#endif
public:
// [Object]
void OnDeleteObject() override;
String ToString() const override;
};
///
/// Managed object that uses weak GC handle to track the target object location in memory.
/// Can be destroyed by the GC.
/// Used by the objects that lifetime is controlled by the C# side.
///
API_CLASS(InBuild) class FLAXENGINE_API ManagedScriptingObject : public ScriptingObject
{
public:
///
/// Initializes a new instance of the class.
///
/// The object initialization parameters.
explicit ManagedScriptingObject(const SpawnParams& params);
public:
// [ScriptingObject]
void SetManagedInstance(MObject* instance) override;
void OnManagedInstanceDeleted() override;
void OnScriptingDispose() override;
bool CreateManaged() override;
};
///
/// Use ScriptingObject instead.
/// [Deprecated on 5.01.2022, expires on 5.01.2024]
///
API_CLASS(InBuild) class FLAXENGINE_API PersistentScriptingObject : public ScriptingObject
{
public:
PersistentScriptingObject(const SpawnParams& params);
};
extern FLAXENGINE_API class ScriptingObject* FindObject(const Guid& id, class MClass* type);