BsScriptHandleManager.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "BsScriptHandleManager.h"
  2. #include "BsScriptAssemblyManager.h"
  3. #include "BsMonoManager.h"
  4. #include "BsMonoAssembly.h"
  5. #include "BsMonoClass.h"
  6. #include "BsMonoField.h"
  7. #include "BsMonoMethod.h"
  8. #include "BsMonoUtil.h"
  9. #include "BsSelection.h"
  10. #include "BsSceneObject.h"
  11. #include "BsManagedComponent.h"
  12. #include "BsScriptObjectManager.h"
  13. using namespace std::placeholders;
  14. namespace BansheeEngine
  15. {
  16. ScriptHandleManager::ScriptHandleManager(ScriptAssemblyManager& scriptObjectManager)
  17. :mScriptObjectManager(scriptObjectManager)
  18. {
  19. mDomainLoadConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&ScriptHandleManager::loadAssemblyData, this));
  20. mDomainUnloadConn = MonoManager::instance().onDomainUnload.connect(std::bind(&ScriptHandleManager::clearAssemblyData, this));
  21. loadAssemblyData();
  22. }
  23. ScriptHandleManager::~ScriptHandleManager()
  24. {
  25. clearAssemblyData();
  26. mDomainUnloadConn.disconnect();
  27. mDomainLoadConn.disconnect();
  28. }
  29. void ScriptHandleManager::refreshHandles()
  30. {
  31. // Activate global handles
  32. for(auto& handle : mGlobalHandlesToCreate)
  33. {
  34. MonoObject* newHandleInstance = handle->createInstance();
  35. mActiveGlobalHandles.push_back(ActiveCustomHandleData());
  36. ActiveCustomHandleData& newHandleData = mActiveGlobalHandles.back();
  37. newHandleData.object = newHandleInstance;
  38. newHandleData.gcHandle = mono_gchandle_new(newHandleInstance, false);
  39. }
  40. mGlobalHandlesToCreate.clear();
  41. // Activate object-specific handles
  42. const Vector<HSceneObject>& selectedSOs = Selection::instance().getSceneObjects();
  43. HSceneObject newSelectedObject;
  44. if (selectedSOs.size() > 0)
  45. {
  46. // We only consider the first selected object for custom handles, multiple selection is not supported
  47. newSelectedObject = selectedSOs[0];
  48. }
  49. if (newSelectedObject != mActiveHandleData.selectedObject)
  50. {
  51. for (auto& handle : mActiveHandleData.handles)
  52. {
  53. callDestroy(handle.object);
  54. mono_gchandle_free(handle.gcHandle);
  55. }
  56. mActiveHandleData.selectedObject = newSelectedObject;
  57. mActiveHandleData.handles.clear();
  58. if (newSelectedObject)
  59. {
  60. const Vector<HComponent>& components = newSelectedObject->getComponents();
  61. for (auto& component : components)
  62. {
  63. if (!rtti_is_of_type<ManagedComponent>(component.getInternalPtr()))
  64. continue;
  65. HManagedComponent mc = static_object_cast<ManagedComponent>(component);
  66. const String& componentTypeName = mc->getManagedFullTypeName();
  67. auto iterFind = mHandles.find(componentTypeName);
  68. if (iterFind == mHandles.end())
  69. continue;
  70. CustomHandleData& handleData = iterFind->second;
  71. MonoObject* newHandleInstance = handleData.handleType->createInstance(false);
  72. void* params[1] = { mc->getManagedInstance() };
  73. handleData.ctor->invoke(newHandleInstance, params);
  74. mActiveHandleData.handles.push_back(ActiveCustomHandleData());
  75. ActiveCustomHandleData& newHandleData = mActiveHandleData.handles.back();
  76. newHandleData.object = newHandleInstance;
  77. newHandleData.gcHandle = mono_gchandle_new(newHandleInstance, false);
  78. }
  79. }
  80. }
  81. if (mDefaultHandleManager == nullptr)
  82. {
  83. mDefaultHandleManager = mDefaultHandleManagerClass->createInstance(true);
  84. mDefaultHandleManagerGCHandle = mono_gchandle_new(mDefaultHandleManager, false);
  85. }
  86. callPreInput(mDefaultHandleManager);
  87. for (auto& handle : mActiveGlobalHandles)
  88. callPreInput(handle.object);
  89. for (auto& handle : mActiveHandleData.handles)
  90. callPreInput(handle.object);
  91. }
  92. void ScriptHandleManager::triggerHandles()
  93. {
  94. callPostInput(mDefaultHandleManager);
  95. for (auto& handle : mActiveGlobalHandles)
  96. callPostInput(handle.object);
  97. for (auto& handle : mActiveHandleData.handles)
  98. callPostInput(handle.object);
  99. }
  100. void ScriptHandleManager::queueDrawCommands()
  101. {
  102. if (mDefaultHandleManager != nullptr)
  103. callDraw(mDefaultHandleManager);
  104. for (auto& handle : mActiveGlobalHandles)
  105. callDraw(handle.object);
  106. for (auto& handle : mActiveHandleData.handles)
  107. callDraw(handle.object);
  108. }
  109. void ScriptHandleManager::clearAssemblyData()
  110. {
  111. mGlobalHandlesToCreate.clear();
  112. for (auto& handle : mActiveGlobalHandles)
  113. {
  114. callDestroy(handle.object);
  115. mono_gchandle_free(handle.gcHandle);
  116. }
  117. mActiveGlobalHandles.clear();
  118. for (auto& handle : mActiveHandleData.handles)
  119. {
  120. callDestroy(handle.object);
  121. mono_gchandle_free(handle.gcHandle);
  122. }
  123. mActiveHandleData.selectedObject = HSceneObject();
  124. mActiveHandleData.handles.clear();
  125. if (mDefaultHandleManager != nullptr)
  126. {
  127. callDestroy(mDefaultHandleManager);
  128. mono_gchandle_free(mDefaultHandleManagerGCHandle);
  129. }
  130. mDefaultHandleManager = nullptr;
  131. mDefaultHandleManagerGCHandle = 0;
  132. }
  133. void ScriptHandleManager::loadAssemblyData()
  134. {
  135. MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);
  136. mCustomHandleAttribute = editorAssembly->getClass("BansheeEditor", "CustomHandle");
  137. if (mCustomHandleAttribute == nullptr)
  138. BS_EXCEPT(InvalidStateException, "Cannot find CustomHandle managed class.");
  139. mHandleBaseClass = editorAssembly->getClass("BansheeEditor", "Handle");
  140. if (mHandleBaseClass == nullptr)
  141. BS_EXCEPT(InvalidStateException, "Cannot find Handle managed class.");
  142. mDefaultHandleManagerClass = editorAssembly->getClass("BansheeEditor", "DefaultHandleManager");
  143. if (mDefaultHandleManagerClass == nullptr)
  144. BS_EXCEPT(InvalidStateException, "Cannot find DefaultHandleManager managed class.");
  145. mTypeField = mCustomHandleAttribute->getField("type");
  146. mPreInputMethod = mHandleBaseClass->getMethod("PreInput", 0);
  147. mPostInputMethod = mHandleBaseClass->getMethod("PostInput", 0);
  148. mDrawMethod = mHandleBaseClass->getMethod("Draw", 0);
  149. mDestroyThunk = (DestroyThunkDef)mHandleBaseClass->getMethod("Destroy", 0)->getThunk();
  150. Vector<String> scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies();
  151. for (auto& assemblyName : scriptAssemblyNames)
  152. {
  153. MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);
  154. // Find new custom handle types
  155. const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
  156. for (auto curClass : allClasses)
  157. {
  158. MonoClass* componentType = nullptr;
  159. MonoMethod* ctor = nullptr;
  160. if (isValidHandleType(curClass, componentType, ctor))
  161. {
  162. if (componentType != nullptr)
  163. {
  164. String fullComponentName = componentType->getFullName();
  165. CustomHandleData& newHandleData = mHandles[fullComponentName];
  166. newHandleData.componentType = componentType;
  167. newHandleData.handleType = curClass;
  168. newHandleData.ctor = ctor;
  169. }
  170. else // Global handle
  171. {
  172. mGlobalHandlesToCreate.push_back(curClass);
  173. }
  174. }
  175. }
  176. }
  177. }
  178. bool ScriptHandleManager::isValidHandleType(MonoClass* type, MonoClass*& componentType, MonoMethod*& ctor) const
  179. {
  180. componentType = nullptr;
  181. ctor = nullptr;
  182. if (!type->hasAttribute(mCustomHandleAttribute))
  183. return false;
  184. if (!type->isSubClassOf(mHandleBaseClass))
  185. return false;
  186. MonoObject* customHandleAttrib = type->getAttribute(mCustomHandleAttribute);
  187. MonoReflectionType* attribReflType = nullptr;
  188. mTypeField->getValue(customHandleAttrib, &attribReflType);
  189. // Handle shown only when specific component type is selected
  190. if (attribReflType != nullptr)
  191. {
  192. MonoType* attribType = mono_reflection_type_get_type(attribReflType);
  193. ::MonoClass* attribMonoClass = mono_class_from_mono_type(attribType);
  194. MonoClass* attribClass = MonoManager::instance().findClass(attribMonoClass);
  195. if (attribClass != nullptr)
  196. return false;
  197. MonoClass* componentClass = mScriptObjectManager.getComponentClass();
  198. if (!attribClass->isSubClassOf(componentClass))
  199. return false;
  200. MonoMethod* constructor = type->getMethod(".ctor", 1);
  201. if (constructor == nullptr)
  202. return false;
  203. MonoClass* paramType = constructor->getParameterType(0);
  204. if (paramType != attribClass)
  205. return false;
  206. componentType = paramType;
  207. ctor = constructor;
  208. }
  209. else // Handle shown always
  210. {
  211. // Do nothing
  212. }
  213. return true;
  214. }
  215. void ScriptHandleManager::callPreInput(MonoObject* instance)
  216. {
  217. mPreInputMethod->invokeVirtual(instance, nullptr);
  218. }
  219. void ScriptHandleManager::callPostInput(MonoObject* instance)
  220. {
  221. mPostInputMethod->invokeVirtual(instance, nullptr);
  222. }
  223. void ScriptHandleManager::callDraw(MonoObject* instance)
  224. {
  225. mDrawMethod->invokeVirtual(instance, nullptr);
  226. }
  227. void ScriptHandleManager::callDestroy(MonoObject* instance)
  228. {
  229. MonoUtil::invokeThunk(mDestroyThunk, instance);
  230. }
  231. }