BsScriptObject.h 6.1 KB

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