BsScriptObject.h 5.9 KB

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