gd_mono_utils.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*************************************************************************/
  2. /* gd_mono_utils.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "gd_mono_utils.h"
  31. #include "os/dir_access.h"
  32. #include "project_settings.h"
  33. #include "reference.h"
  34. #include "../csharp_script.h"
  35. #include "gd_mono.h"
  36. #include "gd_mono_class.h"
  37. #include "gd_mono_marshal.h"
  38. namespace GDMonoUtils {
  39. MonoCache mono_cache;
  40. #define CACHE_AND_CHECK(m_var, m_val) \
  41. { \
  42. m_var = m_val; \
  43. if (!m_var) ERR_PRINT("Mono Cache: Member " #m_var " is null. This is really bad!"); \
  44. }
  45. #define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val)
  46. #define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val)
  47. #define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val)
  48. #define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
  49. #define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
  50. void MonoCache::clear_members() {
  51. class_MonoObject = NULL;
  52. class_bool = NULL;
  53. class_int8_t = NULL;
  54. class_int16_t = NULL;
  55. class_int32_t = NULL;
  56. class_int64_t = NULL;
  57. class_uint8_t = NULL;
  58. class_uint16_t = NULL;
  59. class_uint32_t = NULL;
  60. class_uint64_t = NULL;
  61. class_float = NULL;
  62. class_double = NULL;
  63. class_String = NULL;
  64. class_IntPtr = NULL;
  65. rawclass_Dictionary = NULL;
  66. class_Vector2 = NULL;
  67. class_Rect2 = NULL;
  68. class_Transform2D = NULL;
  69. class_Vector3 = NULL;
  70. class_Basis = NULL;
  71. class_Quat = NULL;
  72. class_Transform = NULL;
  73. class_Rect3 = NULL;
  74. class_Color = NULL;
  75. class_Plane = NULL;
  76. class_NodePath = NULL;
  77. class_RID = NULL;
  78. class_GodotObject = NULL;
  79. class_GodotReference = NULL;
  80. class_Node = NULL;
  81. class_Control = NULL;
  82. class_Spatial = NULL;
  83. class_WeakRef = NULL;
  84. class_MarshalUtils = NULL;
  85. class_ExportAttribute = NULL;
  86. field_ExportAttribute_hint = NULL;
  87. field_ExportAttribute_hint_string = NULL;
  88. class_ToolAttribute = NULL;
  89. class_RemoteAttribute = NULL;
  90. class_SyncAttribute = NULL;
  91. class_MasterAttribute = NULL;
  92. class_SlaveAttribute = NULL;
  93. class_GodotMethodAttribute = NULL;
  94. field_GodotMethodAttribute_methodName = NULL;
  95. field_GodotObject_ptr = NULL;
  96. field_NodePath_ptr = NULL;
  97. field_Image_ptr = NULL;
  98. field_RID_ptr = NULL;
  99. methodthunk_MarshalUtils_DictionaryToArrays = NULL;
  100. methodthunk_MarshalUtils_ArraysToDictionary = NULL;
  101. methodthunk_SignalAwaiter_SignalCallback = NULL;
  102. methodthunk_SignalAwaiter_FailureCallback = NULL;
  103. methodthunk_GodotTaskScheduler_Activate = NULL;
  104. task_scheduler_handle = Ref<MonoGCHandle>();
  105. }
  106. #define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
  107. void update_corlib_cache() {
  108. CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
  109. CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
  110. CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
  111. CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
  112. CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
  113. CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
  114. CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
  115. CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
  116. CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
  117. CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
  118. CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
  119. CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
  120. CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
  121. CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
  122. }
  123. void update_godot_api_cache() {
  124. CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
  125. CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
  126. CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
  127. CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
  128. CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
  129. CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat));
  130. CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform));
  131. CACHE_CLASS_AND_CHECK(Rect3, GODOT_API_CLASS(Rect3));
  132. CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
  133. CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
  134. CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
  135. CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(NodePath));
  136. CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
  137. CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference));
  138. CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
  139. CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
  140. CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
  141. CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
  142. CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
  143. // Attributes
  144. CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
  145. CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
  146. CACHE_FIELD_AND_CHECK(ExportAttribute, hint_string, CACHED_CLASS(ExportAttribute)->get_field("hint_string"));
  147. CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
  148. CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
  149. CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
  150. CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
  151. CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute));
  152. CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
  153. CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
  154. CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
  155. CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
  156. CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
  157. CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk());
  158. CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk());
  159. CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk());
  160. CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk());
  161. CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
  162. {
  163. /*
  164. * TODO Right now we only support Dictionary<object, object>.
  165. * It would be great if we could support other key/value types
  166. * without forcing the user to copy the entries.
  167. */
  168. GDMonoMethod *method_get_dict_type = CACHED_CLASS(MarshalUtils)->get_method("GetDictionaryType", 0);
  169. ERR_FAIL_NULL(method_get_dict_type);
  170. MonoReflectionType *dict_refl_type = (MonoReflectionType *)method_get_dict_type->invoke(NULL);
  171. ERR_FAIL_NULL(dict_refl_type);
  172. MonoType *dict_type = mono_reflection_type_get_type(dict_refl_type);
  173. ERR_FAIL_NULL(dict_type);
  174. CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type));
  175. }
  176. MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_raw());
  177. mono_runtime_object_init(task_scheduler);
  178. mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
  179. }
  180. void clear_cache() {
  181. mono_cache.cleanup();
  182. mono_cache.clear_members();
  183. }
  184. MonoObject *unmanaged_get_managed(Object *unmanaged) {
  185. if (unmanaged) {
  186. if (unmanaged->get_script_instance()) {
  187. CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
  188. if (cs_instance) {
  189. return cs_instance->get_mono_object();
  190. }
  191. }
  192. // Only called if the owner does not have a CSharpInstance
  193. void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
  194. if (data) {
  195. return ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->value()->get_target();
  196. }
  197. }
  198. return NULL;
  199. }
  200. void set_main_thread(MonoThread *p_thread) {
  201. mono_thread_set_main(p_thread);
  202. }
  203. void attach_current_thread() {
  204. ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
  205. MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN);
  206. ERR_FAIL_NULL(mono_thread);
  207. }
  208. void detach_current_thread() {
  209. ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
  210. MonoThread *mono_thread = mono_thread_current();
  211. ERR_FAIL_NULL(mono_thread);
  212. mono_thread_detach(mono_thread);
  213. }
  214. MonoThread *get_current_thread() {
  215. return mono_thread_current();
  216. }
  217. GDMonoClass *get_object_class(MonoObject *p_object) {
  218. return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
  219. }
  220. GDMonoClass *type_get_proxy_class(const StringName &p_type) {
  221. String class_name = p_type;
  222. if (class_name[0] == '_')
  223. class_name = class_name.substr(1, class_name.length());
  224. GDMonoClass *klass = GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
  225. #ifdef TOOLS_ENABLED
  226. if (!klass) {
  227. return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
  228. }
  229. #endif
  230. return klass;
  231. }
  232. GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
  233. GDMonoClass *klass = p_class;
  234. do {
  235. const GDMonoAssembly *assembly = klass->get_assembly();
  236. if (assembly == GDMono::get_singleton()->get_api_assembly())
  237. return klass;
  238. #ifdef TOOLS_ENABLED
  239. if (assembly == GDMono::get_singleton()->get_editor_api_assembly())
  240. return klass;
  241. #endif
  242. } while ((klass = klass->get_parent_class()) != NULL);
  243. return NULL;
  244. }
  245. MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
  246. String object_type = p_object->get_class_name();
  247. if (object_type[0] == '_')
  248. object_type = object_type.substr(1, object_type.length());
  249. if (!ClassDB::is_parent_class(object_type, p_native)) {
  250. ERR_EXPLAIN("Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'");
  251. ERR_FAIL_V(NULL);
  252. }
  253. MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_raw());
  254. ERR_FAIL_NULL_V(mono_object, NULL);
  255. CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
  256. // Construct
  257. mono_runtime_object_init(mono_object);
  258. return mono_object;
  259. }
  260. MonoObject *create_managed_from(const NodePath &p_from) {
  261. MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(NodePath));
  262. ERR_FAIL_NULL_V(mono_object, NULL);
  263. // Construct
  264. mono_runtime_object_init(mono_object);
  265. CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
  266. return mono_object;
  267. }
  268. MonoObject *create_managed_from(const RID &p_from) {
  269. MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(RID));
  270. ERR_FAIL_NULL_V(mono_object, NULL);
  271. // Construct
  272. mono_runtime_object_init(mono_object);
  273. CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
  274. return mono_object;
  275. }
  276. MonoDomain *create_domain(const String &p_friendly_name) {
  277. MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
  278. if (domain) {
  279. // Workaround to avoid this exception:
  280. // System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system.
  281. // ---> System.ArgumentException: The 'ExeConfigFilename' argument cannot be null.
  282. mono_domain_set_config(domain, ".", "");
  283. }
  284. return domain;
  285. }
  286. String get_exception_name_and_message(MonoObject *p_ex) {
  287. String res;
  288. MonoClass *klass = mono_object_get_class(p_ex);
  289. MonoType *type = mono_class_get_type(klass);
  290. char *full_name = mono_type_full_name(type);
  291. res += full_name;
  292. mono_free(full_name);
  293. res += ": ";
  294. MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
  295. MonoString *msg = (MonoString *)mono_property_get_value(prop, p_ex, NULL, NULL);
  296. res += GDMonoMarshal::mono_string_to_godot(msg);
  297. return res;
  298. }
  299. }