BsRuntimeScriptObjects.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. {
  14. }
  15. void RuntimeScriptObjects::refreshScriptObjects(const String& assemblyName)
  16. {
  17. clearScriptObjects(assemblyName);
  18. // Get necessary classes for detecting needed class & field information
  19. MonoAssembly* mscorlib = MonoManager::instance().getAssembly("mscorlib");
  20. if(mscorlib == nullptr)
  21. CM_EXCEPT(InvalidStateException, "mscorlib assembly is not loaded.");
  22. MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(BansheeEngineAssemblyName);
  23. if(bansheeEngineAssembly == nullptr)
  24. CM_EXCEPT(InvalidStateException, String(BansheeEngineAssemblyName) + " assembly is not loaded.");
  25. MonoClass* serializableAttribute = mscorlib->getClass("System", "SerializableAttribute");
  26. if(serializableAttribute == nullptr)
  27. CM_EXCEPT(InvalidStateException, "Cannot find SerializableAttribute managed class.");
  28. MonoClass* nonSerializedAttribute = mscorlib->getClass("System", "NonSerializedAttribute");
  29. if(nonSerializedAttribute == nullptr)
  30. CM_EXCEPT(InvalidStateException, "Cannot find NonSerializedAttribute managed class.");
  31. MonoClass* genericListClass = mscorlib->getClass("System", "List`1");
  32. if(genericListClass == nullptr)
  33. CM_EXCEPT(InvalidStateException, "Cannot find List<T> managed class.");
  34. MonoClass* componentClass = bansheeEngineAssembly->getClass("BansheeEngine", "Component");
  35. if(componentClass == nullptr)
  36. CM_EXCEPT(InvalidStateException, "Cannot find Component managed class.");
  37. MonoClass* sceneObjectClass = bansheeEngineAssembly->getClass("BansheeEngine", "SceneObject");
  38. if(sceneObjectClass == nullptr)
  39. CM_EXCEPT(InvalidStateException, "Cannot find SceneObject managed class.");
  40. MonoClass* textureClass = bansheeEngineAssembly->getClass("BansheeEngine", "Texture2D");
  41. if(textureClass == nullptr)
  42. CM_EXCEPT(InvalidStateException, "Cannot find Texture2D managed class.");
  43. MonoClass* spriteTextureClass = bansheeEngineAssembly->getClass("BansheeEngine", "SpriteTexture");
  44. if(spriteTextureClass == nullptr)
  45. CM_EXCEPT(InvalidStateException, "Cannot find SpriteTexture managed class.");
  46. MonoClass* serializeFieldAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializeField");
  47. if(serializeFieldAttribute == nullptr)
  48. CM_EXCEPT(InvalidStateException, "Cannot find SerializeField managed class.");
  49. MonoClass* hideInInspectorAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "HideInInspector");
  50. if(hideInInspectorAttribute == nullptr)
  51. CM_EXCEPT(InvalidStateException, "Cannot find HideInInspector managed class.");
  52. // Process all classes and fields
  53. CM::UINT32 mUniqueTypeId = 1;
  54. MonoAssembly* curAssembly = MonoManager::instance().getAssembly(assemblyName);
  55. if(curAssembly == nullptr)
  56. return;
  57. std::shared_ptr<ScriptSerializableAssemblyInfo> assemblyInfo = cm_shared_ptr<ScriptSerializableAssemblyInfo>();
  58. assemblyInfo->mName = assemblyName;
  59. mAssemblyInfos[assemblyName] = assemblyInfo;
  60. // Populate class data
  61. const Vector<MonoClass*>::type& allClasses = curAssembly->getAllClasses();
  62. for(auto& curClass : allClasses)
  63. {
  64. if((curClass->isSubClassOf(componentClass) || curClass->hasAttribute(serializableAttribute)) && curClass != componentClass)
  65. {
  66. std::shared_ptr<ScriptSerializableObjectInfo> objInfo = cm_shared_ptr<ScriptSerializableObjectInfo>();
  67. objInfo->mTypeId = mUniqueTypeId++;
  68. objInfo->mTypeName = curClass->getTypeName();
  69. objInfo->mNamespace = curClass->getNamespace();
  70. objInfo->mMonoClass = curClass;
  71. assemblyInfo->mTypeNameToId[objInfo->getFullTypeName()] = objInfo->mTypeId;
  72. assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
  73. }
  74. }
  75. // Populate field data
  76. for(auto& curClassInfo : assemblyInfo->mObjectInfos)
  77. {
  78. std::shared_ptr<ScriptSerializableObjectInfo> objInfo = curClassInfo.second;
  79. String fullTypeName = objInfo->mNamespace + "." + objInfo->mTypeName;
  80. assemblyInfo->mTypeNameToId[fullTypeName] = objInfo->mTypeId;
  81. assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
  82. CM::UINT32 mUniqueFieldId = 1;
  83. const CM::Vector<MonoField*>::type& fields = objInfo->mMonoClass->getAllFields();
  84. for(auto& field : fields)
  85. {
  86. if(field->isStatic())
  87. continue;
  88. MonoClass* fieldType = field->getType();
  89. MonoClass* fieldElementClass = fieldType;
  90. MonoType* monoType = mono_class_get_type(fieldType->_getInternalClass());
  91. int monoPrimitiveType = mono_type_get_type(monoType);
  92. std::shared_ptr<ScriptSerializableFieldInfo> fieldInfo = nullptr;
  93. bool isSupportedType = true;
  94. if(monoPrimitiveType == MONO_TYPE_ARRAY)
  95. {
  96. std::shared_ptr<ScriptSerializableFieldInfoArray> arrayFieldInfo = cm_shared_ptr<ScriptSerializableFieldInfoArray>();
  97. arrayFieldInfo->mArrayDimensions = (UINT32)mono_class_get_rank(fieldType->_getInternalClass());
  98. fieldInfo = arrayFieldInfo;
  99. ::MonoClass* elementClass = mono_class_get_element_class(fieldType->_getInternalClass());
  100. if(elementClass != nullptr)
  101. {
  102. monoType = mono_class_get_type(elementClass);
  103. monoPrimitiveType = mono_type_get_type(monoType);
  104. ::MonoClass* elementClass = mono_type_get_class(monoType);
  105. String elementNs = mono_class_get_namespace(elementClass);
  106. String elementTypeName = mono_class_get_name(elementClass);
  107. fieldElementClass = MonoManager::instance().findClass(elementNs, elementTypeName);
  108. }
  109. }
  110. else if(monoPrimitiveType == MONO_TYPE_CLASS)
  111. {
  112. // TODO - Check for List or Dictionary
  113. // If not List/Dictionary
  114. fieldInfo = cm_shared_ptr<ScriptSerializableFieldInfoPlain>();
  115. }
  116. else
  117. {
  118. fieldInfo = cm_shared_ptr<ScriptSerializableFieldInfoPlain>();
  119. }
  120. fieldInfo->mFieldId = mUniqueFieldId++;
  121. fieldInfo->mMonoField = field;
  122. fieldInfo->mName = field->getName();
  123. fieldInfo->mTypeNamespace = fieldType->getNamespace();
  124. fieldInfo->mTypeName = fieldType->getTypeName();
  125. // Determine field type
  126. switch(monoPrimitiveType) // TODO - If array I need to get underlying type
  127. {
  128. case MONO_TYPE_BOOLEAN:
  129. fieldInfo->mType = ScriptFieldType::Bool;
  130. break;
  131. case MONO_TYPE_CHAR:
  132. fieldInfo->mType = ScriptFieldType::Char;
  133. break;
  134. case MONO_TYPE_I1:
  135. fieldInfo->mType = ScriptFieldType::I8;
  136. break;
  137. case MONO_TYPE_U1:
  138. fieldInfo->mType = ScriptFieldType::U8;
  139. break;
  140. case MONO_TYPE_I2:
  141. fieldInfo->mType = ScriptFieldType::I16;
  142. break;
  143. case MONO_TYPE_U2:
  144. fieldInfo->mType = ScriptFieldType::U16;
  145. break;
  146. case MONO_TYPE_I4:
  147. fieldInfo->mType = ScriptFieldType::I32;
  148. break;
  149. case MONO_TYPE_U4:
  150. fieldInfo->mType = ScriptFieldType::U32;
  151. break;
  152. case MONO_TYPE_I8:
  153. fieldInfo->mType = ScriptFieldType::U64;
  154. break;
  155. case MONO_TYPE_U8:
  156. fieldInfo->mType = ScriptFieldType::U64;
  157. break;
  158. case MONO_TYPE_STRING:
  159. fieldInfo->mType = ScriptFieldType::String;
  160. break;
  161. case MONO_TYPE_R4:
  162. fieldInfo->mType = ScriptFieldType::Float;
  163. break;
  164. case MONO_TYPE_R8:
  165. fieldInfo->mType = ScriptFieldType::Double;
  166. break;
  167. case MONO_TYPE_CLASS:
  168. if(fieldElementClass->isSubClassOf(textureClass))
  169. fieldInfo->mType = ScriptFieldType::TextureRef;
  170. else if(fieldElementClass->isSubClassOf(spriteTextureClass))
  171. fieldInfo->mType = ScriptFieldType::SpriteTextureRef;
  172. else if(fieldElementClass->isSubClassOf(sceneObjectClass))
  173. fieldInfo->mType = ScriptFieldType::SceneObjectRef;
  174. else if(fieldElementClass->isSubClassOf(componentClass))
  175. fieldInfo->mType = ScriptFieldType::ComponentRef;
  176. else
  177. {
  178. if(hasSerializableObjectInfo(fieldElementClass->getNamespace(), fieldElementClass->getTypeName())) // TODO - Ensure this checks for array types
  179. fieldInfo->mType = ScriptFieldType::SerializableObjectRef;
  180. }
  181. break;
  182. case MONO_TYPE_VALUETYPE:
  183. if(hasSerializableObjectInfo(fieldElementClass->getNamespace(), fieldElementClass->getTypeName()))
  184. fieldInfo->mType = ScriptFieldType::SerializableObjectValue;
  185. break;
  186. }
  187. if(fieldInfo->mType != ScriptFieldType::Other)
  188. {
  189. MonoFieldVisibility visibility = field->getVisibility();
  190. if(visibility == MonoFieldVisibility::Public)
  191. {
  192. if(!field->hasAttribute(nonSerializedAttribute))
  193. fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
  194. if(!field->hasAttribute(hideInInspectorAttribute))
  195. fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Inspectable);
  196. }
  197. else
  198. {
  199. if(field->hasAttribute(serializeFieldAttribute))
  200. fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
  201. }
  202. }
  203. objInfo->mFieldNameToId[fieldInfo->mName] = fieldInfo->mFieldId;
  204. objInfo->mFields[fieldInfo->mFieldId] = fieldInfo;
  205. }
  206. }
  207. // Form parent/child connections
  208. for(auto& curClass : assemblyInfo->mObjectInfos)
  209. {
  210. MonoClass* base = curClass.second->mMonoClass->getBaseClass();
  211. while(base != nullptr)
  212. {
  213. std::shared_ptr<ScriptSerializableObjectInfo> baseObjInfo;
  214. if(getSerializableObjectInfo(base->getNamespace(), base->getTypeName(), baseObjInfo))
  215. {
  216. curClass.second->mBaseClass = baseObjInfo;
  217. baseObjInfo->mDerivedClasses.push_back(curClass.second);
  218. break;
  219. }
  220. base = base->getBaseClass();
  221. }
  222. }
  223. }
  224. void RuntimeScriptObjects::clearScriptObjects(const CM::String& assemblyName)
  225. {
  226. mAssemblyInfos.erase(assemblyName);
  227. }
  228. bool RuntimeScriptObjects::getSerializableObjectInfo(const CM::String& ns, const CM::String& typeName, std::shared_ptr<ScriptSerializableObjectInfo>& outInfo)
  229. {
  230. String fullName = ns + "." + typeName;
  231. for(auto& curAssembly : mAssemblyInfos)
  232. {
  233. auto iterFind = curAssembly.second->mTypeNameToId.find(fullName);
  234. if(iterFind != curAssembly.second->mTypeNameToId.end())
  235. {
  236. outInfo = curAssembly.second->mObjectInfos[iterFind->second];
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. bool RuntimeScriptObjects::hasSerializableObjectInfo(const CM::String& ns, const CM::String& typeName)
  243. {
  244. String fullName = ns + "." + typeName;
  245. for(auto& curAssembly : mAssemblyInfos)
  246. {
  247. auto iterFind = curAssembly.second->mTypeNameToId.find(fullName);
  248. if(iterFind != curAssembly.second->mTypeNameToId.end())
  249. return true;
  250. }
  251. return false;
  252. }
  253. }