BsScriptObject.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. ScriptObjectBackup() {}
  19. explicit ScriptObjectBackup(const Any& data)
  20. :data(data)
  21. { }
  22. Any data;
  23. };
  24. /** Contains backup data in the form of a raw memory buffer. */
  25. struct RawBackupData
  26. {
  27. UINT8* data = nullptr;
  28. UINT32 size = 0;
  29. };
  30. /**
  31. * Base class for all script interop objects. Interop objects form a connection between C++ and CLR classes and methods.
  32. */
  33. class BS_SCR_BE_EXPORT ScriptObjectBase
  34. {
  35. public:
  36. ScriptObjectBase(MonoObject* instance);
  37. virtual ~ScriptObjectBase();
  38. /**
  39. * Should the interop object persist through assembly reload. If false then the interop object will be destroyed on
  40. * reload.
  41. */
  42. virtual bool isPersistent() const { return false; }
  43. /**
  44. * Clears any managed instance references from the interop object, and releases any GC handles. Called during
  45. * assembly refresh just before the script domain is unloaded.
  46. */
  47. virtual void _clearManagedInstance() { }
  48. /** Allows persistent objects to restore their managed instances after assembly reload. */
  49. virtual void _restoreManagedInstance() { }
  50. /** Called when the managed instance gets finalized by the CLR. */
  51. virtual void _onManagedInstanceDeleted(bool assemblyRefresh);
  52. /** Called before assembly reload starts to give the object a chance to back up its data. */
  53. virtual ScriptObjectBackup beginRefresh();
  54. /**
  55. * Called after assembly reload starts to give the object a chance to restore the data backed up by the previous
  56. * beginRefresh() call.
  57. */
  58. virtual void endRefresh(const ScriptObjectBackup& data);
  59. };
  60. /** Base class for all persistent interop objects. Persistent objects persist through assembly reload. */
  61. class BS_SCR_BE_EXPORT PersistentScriptObjectBase : public ScriptObjectBase
  62. {
  63. public:
  64. PersistentScriptObjectBase(MonoObject* instance);
  65. virtual ~PersistentScriptObjectBase();
  66. /** @copydoc ScriptObjectBase::isPersistent */
  67. bool isPersistent() const override { return true; }
  68. };
  69. template <class Type, class Base>
  70. class ScriptObject;
  71. /** Helper class to initialize all script interop objects as soon as the library is loaded. */
  72. template <class Type, class Base>
  73. struct InitScriptObjectOnStart
  74. {
  75. public:
  76. InitScriptObjectOnStart()
  77. {
  78. ScriptObject<Type, Base>::_initMetaData();
  79. }
  80. void makeSureIAmInstantiated() { }
  81. };
  82. /** Template version of ScriptObjectBase populates the object meta-data on library load. */
  83. template <class Type, class Base = ScriptObjectBase>
  84. class ScriptObject : public Base
  85. {
  86. public:
  87. ScriptObject(MonoObject* instance)
  88. :Base(instance)
  89. {
  90. initOnStart.makeSureIAmInstantiated();
  91. Type* param = (Type*)(Base*)this; // Needed due to multiple inheritance. Safe since Type must point to an class derived from this one.
  92. if(metaData.thisPtrField != nullptr)
  93. metaData.thisPtrField->set(instance, &param);
  94. }
  95. virtual ~ScriptObject()
  96. { }
  97. /** Allows persistent objects to restore their managed instances after assembly reload. */
  98. void _restoreManagedInstance()
  99. {
  100. MonoObject* instance = _createManagedInstance(true);
  101. Type* param = (Type*)(Base*)this; // Needed due to multiple inheritance. Safe since Type must point to an class derived from this one.
  102. if (metaData.thisPtrField != nullptr && instance != nullptr)
  103. metaData.thisPtrField->set(instance, &param);
  104. }
  105. /** Creates a new managed instance of the type wrapped by this interop object. */
  106. virtual MonoObject* _createManagedInstance(bool construct)
  107. {
  108. return metaData.scriptClass->createInstance(construct);
  109. }
  110. /**
  111. * Converts a managed instance into a specific interop object. Caller must ensure the managed instance is of the
  112. * proper type.
  113. */
  114. static Type* toNative(MonoObject* managedInstance)
  115. {
  116. Type* nativeInstance = nullptr;
  117. if (metaData.thisPtrField != nullptr && managedInstance != nullptr)
  118. metaData.thisPtrField->get(managedInstance, &nativeInstance);
  119. return nativeInstance;
  120. }
  121. /** Returns the meta-data containing class and method information for the managed type. */
  122. static const ScriptMeta* getMetaData() { return &metaData; }
  123. /**
  124. * Initializes the meta-data containing class and method information for the managed type. Called on library load
  125. * and on assembly reload.
  126. */
  127. static void _initMetaData()
  128. {
  129. // Need to delay init of actual metaData since it's also a static, and we can't guarantee the order
  130. // (if it gets initialized after this, it will just overwrite the data)
  131. ScriptMeta localMetaData = ScriptMeta(Type::getAssemblyName(), Type::getNamespace(), Type::getTypeName(),
  132. &Type::initRuntimeData);
  133. MonoManager::registerScriptType(&metaData, localMetaData);
  134. }
  135. protected:
  136. static ScriptMeta metaData;
  137. private:
  138. static InitScriptObjectOnStart<Type, Base> initOnStart;
  139. };
  140. template <typename Type, typename Base>
  141. InitScriptObjectOnStart<Type, Base> ScriptObject<Type, Base>::initOnStart;
  142. template <typename Type, typename Base>
  143. ScriptMeta ScriptObject<Type, Base>::metaData;
  144. /** Helper macro to use with script interop objects that form a link between C++ and CLR. */
  145. #define SCRIPT_OBJ(assembly, namespace, name) \
  146. static String getAssemblyName() { return assembly; } \
  147. static String getNamespace() { return namespace; } \
  148. static String getTypeName() { return name; } \
  149. static void initRuntimeData();
  150. /** @} */
  151. }