// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once #include "ScriptingType.h" #include "Engine/Core/Object.h" #include "Engine/Core/Delegate.h" #include "ManagedCLR/MTypes.h" /// /// 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: gchandle _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); 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); static MObject* ToManaged(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); #if USE_MONO static bool CanCast(const MClass* from, const MonoClass* to); #endif template static T* Cast(ScriptingObject* obj) { return obj && CanCast(obj->GetClass(), T::GetStaticClass()) ? (T*)obj : nullptr; } bool Is(const ScriptingTypeHandle& type) const; bool Is(const MClass* type) const { return CanCast(GetClass(), type); } #if USE_MONO bool Is(MonoClass* klass) const { return CanCast(GetClass(), klass); } #endif template bool Is() const { return CanCast(GetClass(), T::GetStaticClass()); } 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 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) != 0; } /// /// 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_MONO /// /// Create a new managed object. /// MonoObject* 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 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); };