BsScriptObject.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsScriptEnginePrerequisites.h"
  5. #include "BsScriptMeta.h"
  6. #include "Error/BsException.h"
  7. #include "BsMonoManager.h"
  8. #include "BsMonoField.h"
  9. #include "BsMonoClass.h"
  10. namespace bs
  11. {
  12. /** @addtogroup SBansheeEngine
  13. * @{
  14. */
  15. /** Contains backed up interop object data. */
  16. struct ScriptObjectBackup
  17. {
  18. Any data;
  19. };
  20. /**
  21. * Base class for all script interop objects. Interop objects form a connection between C++ and CLR classes and methods.
  22. */
  23. class BS_SCR_BE_EXPORT ScriptObjectBase
  24. {
  25. public:
  26. ScriptObjectBase(MonoObject* instance);
  27. virtual ~ScriptObjectBase();
  28. /** Gets the managed object this interop object represents. */
  29. MonoObject* getManagedInstance() const { return mManagedInstance; }
  30. /**
  31. * Should the interop object persist through assembly reload. If false then the interop object will be destroyed on
  32. * reload.
  33. */
  34. virtual bool isPersistent() const { return false; }
  35. /**
  36. * Clears any managed instance references from the interop object. Normally called right after the assemblies are
  37. * unloaded.
  38. */
  39. virtual void _clearManagedInstance() { }
  40. /** Allows persistent objects to restore their managed instances after assembly reload. */
  41. virtual void _restoreManagedInstance() { }
  42. /** Called when the managed instance gets finalized by the CLR. */
  43. virtual void _onManagedInstanceDeleted();
  44. /** Called before assembly reload starts to give the object a chance to back up its data. */
  45. virtual ScriptObjectBackup beginRefresh();
  46. /**
  47. * Called after assembly reload starts to give the object a chance to restore the data backed up by the previous
  48. * beginRefresh() call.
  49. */
  50. virtual void endRefresh(const ScriptObjectBackup& data);
  51. protected:
  52. MonoObject* mManagedInstance;
  53. };
  54. /** Base class for all persistent interop objects. Persistent objects persist through assembly reload. */
  55. class BS_SCR_BE_EXPORT PersistentScriptObjectBase : public ScriptObjectBase
  56. {
  57. public:
  58. PersistentScriptObjectBase(MonoObject* instance);
  59. virtual ~PersistentScriptObjectBase();
  60. /** @copydoc ScriptObjectBase::isPersistent */
  61. virtual bool isPersistent() const override { return true; }
  62. };
  63. template <class Type, class Base>
  64. class ScriptObject;
  65. /** Helper class to initialize all script interop objects as soon as the library is loaded. */
  66. template <class Type, class Base>
  67. struct InitScriptObjectOnStart
  68. {
  69. public:
  70. InitScriptObjectOnStart()
  71. {
  72. ScriptObject<Type, Base>::_initMetaData();
  73. }
  74. void makeSureIAmInstantiated() { }
  75. };
  76. /** Template version of ScriptObjectBase populates the object meta-data on library load. */
  77. template <class Type, class Base = ScriptObjectBase>
  78. class ScriptObject : public Base
  79. {
  80. public:
  81. ScriptObject(MonoObject* instance)
  82. :Base(instance)
  83. {
  84. initOnStart.makeSureIAmInstantiated();
  85. Type* param = (Type*)(Base*)this; // Needed due to multiple inheritance. Safe since Type must point to an class derived from this one.
  86. if(metaData.thisPtrField != nullptr)
  87. metaData.thisPtrField->set(instance, &param);
  88. }
  89. virtual ~ScriptObject()
  90. { }
  91. /**
  92. * Clears any managed instance references from the interop object. Normally called right after the assemblies are
  93. * unloaded.
  94. */
  95. void _clearManagedInstance()
  96. {
  97. if (metaData.thisPtrField != nullptr && this->mManagedInstance != nullptr)
  98. metaData.thisPtrField->set(this->mManagedInstance, nullptr);
  99. this->mManagedInstance = nullptr;
  100. }
  101. /** Allows persistent objects to restore their managed instances after assembly reload. */
  102. void _restoreManagedInstance()
  103. {
  104. this->mManagedInstance = _createManagedInstance(true);
  105. Type* param = (Type*)(Base*)this; // Needed due to multiple inheritance. Safe since Type must point to an class derived from this one.
  106. if (metaData.thisPtrField != nullptr && this->mManagedInstance != nullptr)
  107. metaData.thisPtrField->set(this->mManagedInstance, &param);
  108. }
  109. /** Creates a new managed instance of the type wrapped by this interop object. */
  110. virtual MonoObject* _createManagedInstance(bool construct)
  111. {
  112. return metaData.scriptClass->createInstance(construct);
  113. }
  114. /**
  115. * Converts a managed instance into a specific interop object. Caller must ensure the managed instance is of the
  116. * proper type.
  117. */
  118. static Type* toNative(MonoObject* managedInstance)
  119. {
  120. Type* nativeInstance = nullptr;
  121. if (metaData.thisPtrField != nullptr && managedInstance != nullptr)
  122. metaData.thisPtrField->get(managedInstance, &nativeInstance);
  123. return nativeInstance;
  124. }
  125. /** Returns the meta-data containing class and method information for the managed type. */
  126. static const ScriptMeta* getMetaData() { return &metaData; }
  127. /**
  128. * Initializes the meta-data containing class and method information for the managed type. Called on library load
  129. * and on assembly reload.
  130. */
  131. static void _initMetaData()
  132. {
  133. assert(metaData.name.empty());
  134. metaData = ScriptMeta(Type::getAssemblyName(), Type::getNamespace(), Type::getTypeName(), &Type::initRuntimeData);
  135. MonoManager::registerScriptType(&metaData);
  136. }
  137. protected:
  138. static ScriptMeta metaData;
  139. private:
  140. static InitScriptObjectOnStart<Type, Base> initOnStart;
  141. };
  142. template <typename Type, typename Base>
  143. InitScriptObjectOnStart<Type, Base> ScriptObject<Type, Base>::initOnStart;
  144. template <typename Type, typename Base>
  145. ScriptMeta ScriptObject<Type, Base>::metaData;
  146. /** Helper macro to use with script interop objects that form a link between C++ and CLR. */
  147. #define SCRIPT_OBJ(assembly, namespace, name) \
  148. static String getAssemblyName() { return assembly; } \
  149. static String getNamespace() { return namespace; } \
  150. static String getTypeName() { return name; } \
  151. static void initRuntimeData();
  152. /** @} */
  153. }