BsRuntimeScriptObjects.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. #include "BsRuntimeScriptObjects.h"
  2. #include "BsScriptResourceManager.h"
  3. #include "BsScriptGameObjectManager.h"
  4. #include "BsMonoManager.h"
  5. #include "BsMonoAssembly.h"
  6. #include "BsMonoClass.h"
  7. #include "BsMonoField.h"
  8. #include "BsMonoUtil.h"
  9. using namespace CamelotFramework;
  10. namespace BansheeEngine
  11. {
  12. RuntimeScriptObjects::RuntimeScriptObjects()
  13. :mBaseTypesInitialized(false), mSerializableAttribute(nullptr), mNonSerializedAttribute(nullptr),
  14. mComponentClass(nullptr), mSceneObjectClass(nullptr), mTextureClass(nullptr), mSpriteTextureClass(nullptr),
  15. mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr), mSystemArrayClass(nullptr)
  16. {
  17. }
  18. RuntimeScriptObjects::~RuntimeScriptObjects()
  19. {
  20. }
  21. void RuntimeScriptObjects::refreshScriptObjects(const String& assemblyName)
  22. {
  23. clearScriptObjects(assemblyName);
  24. if(!mBaseTypesInitialized)
  25. initializeBaseTypes();
  26. // Process all classes and fields
  27. CM::UINT32 mUniqueTypeId = 1;
  28. MonoAssembly* curAssembly = MonoManager::instance().getAssembly(assemblyName);
  29. if(curAssembly == nullptr)
  30. return;
  31. std::shared_ptr<ScriptSerializableAssemblyInfo> assemblyInfo = cm_shared_ptr<ScriptSerializableAssemblyInfo>();
  32. assemblyInfo->mName = assemblyName;
  33. mAssemblyInfos[assemblyName] = assemblyInfo;
  34. // Populate class data
  35. const Vector<MonoClass*>::type& allClasses = curAssembly->getAllClasses();
  36. for(auto& curClass : allClasses)
  37. {
  38. if((curClass->isSubClassOf(mComponentClass) || curClass->hasAttribute(mSerializableAttribute)) && curClass != mComponentClass)
  39. {
  40. std::shared_ptr<ScriptSerializableObjectInfo> objInfo = cm_shared_ptr<ScriptSerializableObjectInfo>();
  41. objInfo->mTypeId = mUniqueTypeId++;
  42. objInfo->mTypeName = curClass->getTypeName();
  43. objInfo->mNamespace = curClass->getNamespace();
  44. objInfo->mMonoClass = curClass;
  45. assemblyInfo->mTypeNameToId[objInfo->getFullTypeName()] = objInfo->mTypeId;
  46. assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
  47. }
  48. }
  49. // Populate field data
  50. for(auto& curClassInfo : assemblyInfo->mObjectInfos)
  51. {
  52. std::shared_ptr<ScriptSerializableObjectInfo> objInfo = curClassInfo.second;
  53. String fullTypeName = objInfo->mNamespace + "." + objInfo->mTypeName;
  54. assemblyInfo->mTypeNameToId[fullTypeName] = objInfo->mTypeId;
  55. assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
  56. CM::UINT32 mUniqueFieldId = 1;
  57. const CM::Vector<MonoField*>::type& fields = objInfo->mMonoClass->getAllFields();
  58. for(auto& field : fields)
  59. {
  60. if(field->isStatic())
  61. continue;
  62. std::shared_ptr<ScriptSerializableFieldInfo> fieldInfo = cm_shared_ptr<ScriptSerializableFieldInfo>();
  63. fieldInfo->mFieldId = mUniqueFieldId++;
  64. fieldInfo->mName = field->getName();
  65. fieldInfo->mMonoField = field;
  66. fieldInfo->mTypeInfo = determineType(field->getType());
  67. if(fieldInfo->mTypeInfo != nullptr)
  68. {
  69. MonoFieldVisibility visibility = field->getVisibility();
  70. if(visibility == MonoFieldVisibility::Public)
  71. {
  72. if(!field->hasAttribute(mNonSerializedAttribute))
  73. fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
  74. if(!field->hasAttribute(mHideInInspectorAttribute))
  75. fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Inspectable);
  76. }
  77. else
  78. {
  79. if(field->hasAttribute(mSerializeFieldAttribute))
  80. fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
  81. }
  82. }
  83. objInfo->mFieldNameToId[fieldInfo->mName] = fieldInfo->mFieldId;
  84. objInfo->mFields[fieldInfo->mFieldId] = fieldInfo;
  85. }
  86. }
  87. // Form parent/child connections
  88. for(auto& curClass : assemblyInfo->mObjectInfos)
  89. {
  90. MonoClass* base = curClass.second->mMonoClass->getBaseClass();
  91. while(base != nullptr)
  92. {
  93. std::shared_ptr<ScriptSerializableObjectInfo> baseObjInfo;
  94. if(getSerializableObjectInfo(base->getNamespace(), base->getTypeName(), baseObjInfo))
  95. {
  96. curClass.second->mBaseClass = baseObjInfo;
  97. baseObjInfo->mDerivedClasses.push_back(curClass.second);
  98. break;
  99. }
  100. base = base->getBaseClass();
  101. }
  102. }
  103. }
  104. ScriptSerializableTypeInfoPtr RuntimeScriptObjects::determineType(MonoClass* monoClass)
  105. {
  106. if(!mBaseTypesInitialized)
  107. CM_EXCEPT(InvalidStateException, "Calling determineType without previously initializing base types.");
  108. MonoType* monoType = mono_class_get_type(monoClass->_getInternalClass());
  109. int monoPrimitiveType = mono_type_get_type(monoType);
  110. // Determine field type
  111. switch(monoPrimitiveType)
  112. {
  113. case MONO_TYPE_BOOLEAN:
  114. {
  115. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  116. typeInfo->mType = ScriptPrimitiveType::Bool;
  117. return typeInfo;
  118. }
  119. case MONO_TYPE_CHAR:
  120. {
  121. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  122. typeInfo->mType = ScriptPrimitiveType::Char;
  123. return typeInfo;
  124. }
  125. case MONO_TYPE_I1:
  126. {
  127. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  128. typeInfo->mType = ScriptPrimitiveType::I8;
  129. return typeInfo;
  130. }
  131. case MONO_TYPE_U1:
  132. {
  133. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  134. typeInfo->mType = ScriptPrimitiveType::U8;
  135. return typeInfo;
  136. }
  137. case MONO_TYPE_I2:
  138. {
  139. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  140. typeInfo->mType = ScriptPrimitiveType::I16;
  141. return typeInfo;
  142. }
  143. case MONO_TYPE_U2:
  144. {
  145. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  146. typeInfo->mType = ScriptPrimitiveType::U16;
  147. return typeInfo;
  148. }
  149. case MONO_TYPE_I4:
  150. {
  151. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  152. typeInfo->mType = ScriptPrimitiveType::I32;
  153. return typeInfo;
  154. }
  155. case MONO_TYPE_U4:
  156. {
  157. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  158. typeInfo->mType = ScriptPrimitiveType::U32;
  159. return typeInfo;
  160. }
  161. case MONO_TYPE_I8:
  162. {
  163. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  164. typeInfo->mType = ScriptPrimitiveType::I64;
  165. return typeInfo;
  166. }
  167. case MONO_TYPE_U8:
  168. {
  169. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  170. typeInfo->mType = ScriptPrimitiveType::U64;
  171. return typeInfo;
  172. }
  173. case MONO_TYPE_STRING:
  174. {
  175. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  176. typeInfo->mType = ScriptPrimitiveType::String;
  177. return typeInfo;
  178. }
  179. case MONO_TYPE_R4:
  180. {
  181. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  182. typeInfo->mType = ScriptPrimitiveType::Float;
  183. return typeInfo;
  184. }
  185. case MONO_TYPE_R8:
  186. {
  187. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  188. typeInfo->mType = ScriptPrimitiveType::Double;
  189. return typeInfo;
  190. }
  191. case MONO_TYPE_CLASS:
  192. if(monoClass->isSubClassOf(mTextureClass))
  193. {
  194. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  195. typeInfo->mType = ScriptPrimitiveType::TextureRef;
  196. return typeInfo;
  197. }
  198. else if(monoClass->isSubClassOf(mSpriteTextureClass))
  199. {
  200. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  201. typeInfo->mType = ScriptPrimitiveType::SpriteTextureRef;
  202. return typeInfo;
  203. }
  204. else if(monoClass->isSubClassOf(mSceneObjectClass))
  205. {
  206. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  207. typeInfo->mType = ScriptPrimitiveType::SceneObjectRef;
  208. return typeInfo;
  209. }
  210. else if(monoClass->isSubClassOf(mComponentClass))
  211. {
  212. std::shared_ptr<ScriptSerializableTypeInfoPrimitive> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoPrimitive>();
  213. typeInfo->mType = ScriptPrimitiveType::ComponentRef;
  214. return typeInfo;
  215. }
  216. else
  217. {
  218. if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
  219. {
  220. std::shared_ptr<ScriptSerializableTypeInfoObject> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoObject>();
  221. typeInfo->mTypeNamespace = monoClass->getNamespace();
  222. typeInfo->mTypeName = monoClass->getTypeName();
  223. return typeInfo;
  224. }
  225. else
  226. {
  227. // TODO - Later check for List or Dictionary here
  228. }
  229. }
  230. break;
  231. case MONO_TYPE_VALUETYPE:
  232. if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
  233. {
  234. std::shared_ptr<ScriptSerializableTypeInfoObject> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoObject>();
  235. typeInfo->mTypeNamespace = monoClass->getNamespace();
  236. typeInfo->mTypeName = monoClass->getTypeName();
  237. return typeInfo;
  238. }
  239. break;
  240. case MONO_TYPE_ARRAY:
  241. {
  242. std::shared_ptr<ScriptSerializableTypeInfoArray> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoArray>();
  243. ::MonoClass* elementClass = mono_class_get_element_class(monoClass->_getInternalClass());
  244. if(elementClass != nullptr)
  245. {
  246. monoType = mono_class_get_type(elementClass);
  247. monoPrimitiveType = mono_type_get_type(monoType);
  248. ::MonoClass* elementClass = mono_type_get_class(monoType);
  249. String elementNs = mono_class_get_namespace(elementClass);
  250. String elementTypeName = mono_class_get_name(elementClass);
  251. MonoClass* monoElementClass = MonoManager::instance().findClass(elementNs, elementTypeName);
  252. if(monoElementClass != nullptr)
  253. typeInfo->mElementType = determineType(monoElementClass);
  254. }
  255. typeInfo->mRank = (UINT32)mono_class_get_rank(monoClass->_getInternalClass());
  256. return typeInfo;
  257. }
  258. }
  259. return nullptr;
  260. }
  261. void RuntimeScriptObjects::clearScriptObjects(const CM::String& assemblyName)
  262. {
  263. mAssemblyInfos.erase(assemblyName);
  264. mBaseTypesInitialized = false;
  265. mSystemArrayClass = nullptr;
  266. mSerializableAttribute = nullptr;
  267. mNonSerializedAttribute = nullptr;
  268. mComponentClass = nullptr;
  269. mSceneObjectClass = nullptr;
  270. mTextureClass = nullptr;
  271. mSpriteTextureClass = nullptr;
  272. mSerializeFieldAttribute = nullptr;
  273. mHideInInspectorAttribute = nullptr;
  274. }
  275. void RuntimeScriptObjects::initializeBaseTypes()
  276. {
  277. // Get necessary classes for detecting needed class & field information
  278. MonoAssembly* mscorlib = MonoManager::instance().getAssembly("mscorlib");
  279. if(mscorlib == nullptr)
  280. CM_EXCEPT(InvalidStateException, "mscorlib assembly is not loaded.");
  281. MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(BansheeEngineAssemblyName);
  282. if(bansheeEngineAssembly == nullptr)
  283. CM_EXCEPT(InvalidStateException, String(BansheeEngineAssemblyName) + " assembly is not loaded.");
  284. mSystemArrayClass = mscorlib->getClass("System", "Array");
  285. if(mSystemArrayClass == nullptr)
  286. CM_EXCEPT(InvalidStateException, "Cannot find System.Array managed class.");
  287. mSerializableAttribute = mscorlib->getClass("System", "SerializableAttribute");
  288. if(mSerializableAttribute == nullptr)
  289. CM_EXCEPT(InvalidStateException, "Cannot find SerializableAttribute managed class.");
  290. mNonSerializedAttribute = mscorlib->getClass("System", "NonSerializedAttribute");
  291. if(mNonSerializedAttribute == nullptr)
  292. CM_EXCEPT(InvalidStateException, "Cannot find NonSerializedAttribute managed class.");
  293. mComponentClass = bansheeEngineAssembly->getClass("BansheeEngine", "Component");
  294. if(mComponentClass == nullptr)
  295. CM_EXCEPT(InvalidStateException, "Cannot find Component managed class.");
  296. mSceneObjectClass = bansheeEngineAssembly->getClass("BansheeEngine", "SceneObject");
  297. if(mSceneObjectClass == nullptr)
  298. CM_EXCEPT(InvalidStateException, "Cannot find SceneObject managed class.");
  299. mTextureClass = bansheeEngineAssembly->getClass("BansheeEngine", "Texture2D");
  300. if(mTextureClass == nullptr)
  301. CM_EXCEPT(InvalidStateException, "Cannot find Texture2D managed class.");
  302. mSpriteTextureClass = bansheeEngineAssembly->getClass("BansheeEngine", "SpriteTexture");
  303. if(mSpriteTextureClass == nullptr)
  304. CM_EXCEPT(InvalidStateException, "Cannot find SpriteTexture managed class.");
  305. mSerializeFieldAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializeField");
  306. if(mSerializeFieldAttribute == nullptr)
  307. CM_EXCEPT(InvalidStateException, "Cannot find SerializeField managed class.");
  308. mHideInInspectorAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "HideInInspector");
  309. if(mHideInInspectorAttribute == nullptr)
  310. CM_EXCEPT(InvalidStateException, "Cannot find HideInInspector managed class.");
  311. mBaseTypesInitialized = true;
  312. }
  313. bool RuntimeScriptObjects::getSerializableObjectInfo(const CM::String& ns, const CM::String& typeName, std::shared_ptr<ScriptSerializableObjectInfo>& outInfo)
  314. {
  315. String fullName = ns + "." + typeName;
  316. for(auto& curAssembly : mAssemblyInfos)
  317. {
  318. auto iterFind = curAssembly.second->mTypeNameToId.find(fullName);
  319. if(iterFind != curAssembly.second->mTypeNameToId.end())
  320. {
  321. outInfo = curAssembly.second->mObjectInfos[iterFind->second];
  322. return true;
  323. }
  324. }
  325. return false;
  326. }
  327. bool RuntimeScriptObjects::hasSerializableObjectInfo(const CM::String& ns, const CM::String& typeName)
  328. {
  329. String fullName = ns + "." + typeName;
  330. for(auto& curAssembly : mAssemblyInfos)
  331. {
  332. auto iterFind = curAssembly.second->mTypeNameToId.find(fullName);
  333. if(iterFind != curAssembly.second->mTypeNameToId.end())
  334. return true;
  335. }
  336. return false;
  337. }
  338. bool RuntimeScriptObjects::isArray(MonoObject* object)
  339. {
  340. if(!mBaseTypesInitialized)
  341. CM_EXCEPT(InvalidStateException, "Calling isArray without previously initializing base types.");
  342. ::MonoClass* monoClass = mono_object_get_class(object);
  343. return mono_class_is_subclass_of(monoClass, mSystemArrayClass->_getInternalClass(), false) != 0;
  344. }
  345. }