BsScriptObject.h 5.9 KB

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