base_object_glue.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*************************************************************************/
  2. /* base_object_glue.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 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. #ifdef MONO_GLUE_ENABLED
  31. #include "core/object/class_db.h"
  32. #include "core/object/reference.h"
  33. #include "core/string/string_name.h"
  34. #include "../csharp_script.h"
  35. #include "../mono_gd/gd_mono_cache.h"
  36. #include "../mono_gd/gd_mono_class.h"
  37. #include "../mono_gd/gd_mono_internals.h"
  38. #include "../mono_gd/gd_mono_marshal.h"
  39. #include "../mono_gd/gd_mono_utils.h"
  40. #include "../signal_awaiter_utils.h"
  41. #include "arguments_vector.h"
  42. Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
  43. Object *instance = memnew(Object);
  44. GDMonoInternals::tie_managed_to_unmanaged(p_obj, instance);
  45. return instance;
  46. }
  47. void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
  48. #ifdef DEBUG_ENABLED
  49. CRASH_COND(p_ptr == nullptr);
  50. #endif
  51. if (p_ptr->get_script_instance()) {
  52. CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
  53. if (cs_instance) {
  54. if (!cs_instance->is_destructing_script_instance()) {
  55. cs_instance->mono_object_disposed(p_obj);
  56. p_ptr->set_script_instance(nullptr);
  57. }
  58. return;
  59. }
  60. }
  61. void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
  62. if (data) {
  63. CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
  64. if (script_binding.inited) {
  65. MonoGCHandleData &gchandle = script_binding.gchandle;
  66. if (!gchandle.is_released()) {
  67. CSharpLanguage::release_script_gchandle(p_obj, gchandle);
  68. }
  69. }
  70. }
  71. }
  72. void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
  73. #ifdef DEBUG_ENABLED
  74. CRASH_COND(p_ptr == nullptr);
  75. // This is only called with Reference derived classes
  76. CRASH_COND(!Object::cast_to<Reference>(p_ptr));
  77. #endif
  78. Reference *ref = static_cast<Reference *>(p_ptr);
  79. if (ref->get_script_instance()) {
  80. CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance());
  81. if (cs_instance) {
  82. if (!cs_instance->is_destructing_script_instance()) {
  83. bool delete_owner;
  84. bool remove_script_instance;
  85. cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance);
  86. if (delete_owner) {
  87. memdelete(ref);
  88. } else if (remove_script_instance) {
  89. ref->set_script_instance(nullptr);
  90. }
  91. }
  92. return;
  93. }
  94. }
  95. // Unsafe refcount decrement. The managed instance also counts as a reference.
  96. // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
  97. CSharpLanguage::get_singleton()->pre_unsafe_unreference(ref);
  98. if (ref->unreference()) {
  99. memdelete(ref);
  100. } else {
  101. void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
  102. if (data) {
  103. CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
  104. if (script_binding.inited) {
  105. MonoGCHandleData &gchandle = script_binding.gchandle;
  106. if (!gchandle.is_released()) {
  107. CSharpLanguage::release_script_gchandle(p_obj, gchandle);
  108. }
  109. }
  110. }
  111. }
  112. }
  113. void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
  114. CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
  115. if (csharp_instance) {
  116. csharp_instance->connect_event_signals();
  117. }
  118. }
  119. MethodBind *godot_icall_Object_ClassDB_get_method(StringName *p_type, MonoString *p_method) {
  120. StringName type = p_type ? *p_type : StringName();
  121. StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
  122. return ClassDB::get_method(type, method);
  123. }
  124. MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
  125. if (!p_ptr) {
  126. return nullptr;
  127. }
  128. Ref<WeakRef> wref;
  129. Reference *ref = Object::cast_to<Reference>(p_ptr);
  130. if (ref) {
  131. REF r = ref;
  132. if (!r.is_valid()) {
  133. return nullptr;
  134. }
  135. wref.instance();
  136. wref->set_ref(r);
  137. } else {
  138. wref.instance();
  139. wref->set_obj(p_ptr);
  140. }
  141. return GDMonoUtils::unmanaged_get_managed(wref.ptr());
  142. }
  143. int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
  144. StringName signal = p_signal ? *p_signal : StringName();
  145. return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
  146. }
  147. MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
  148. List<PropertyInfo> property_list;
  149. p_ptr->get_property_list(&property_list);
  150. MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size());
  151. int i = 0;
  152. for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
  153. MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name);
  154. mono_array_setref(result, i, boxed);
  155. i++;
  156. }
  157. return result;
  158. }
  159. MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result) {
  160. String name = GDMonoMarshal::mono_string_to_godot(p_name);
  161. int argc = mono_array_length(p_args);
  162. ArgumentsVector<Variant> arg_store(argc);
  163. ArgumentsVector<const Variant *> args(argc);
  164. for (int i = 0; i < argc; i++) {
  165. MonoObject *elem = mono_array_get(p_args, MonoObject *, i);
  166. arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem));
  167. args.set(i, &arg_store.get(i));
  168. }
  169. Callable::CallError error;
  170. Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error);
  171. *r_result = GDMonoMarshal::variant_to_mono_object(result);
  172. return error.error == Callable::CallError::CALL_OK;
  173. }
  174. MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) {
  175. String name = GDMonoMarshal::mono_string_to_godot(p_name);
  176. bool valid;
  177. Variant value = p_ptr->get(StringName(name), &valid);
  178. if (valid) {
  179. *r_result = GDMonoMarshal::variant_to_mono_object(value);
  180. }
  181. return valid;
  182. }
  183. MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value) {
  184. String name = GDMonoMarshal::mono_string_to_godot(p_name);
  185. Variant value = GDMonoMarshal::mono_object_to_variant(p_value);
  186. bool valid;
  187. p_ptr->set(StringName(name), value, &valid);
  188. return valid;
  189. }
  190. MonoString *godot_icall_Object_ToString(Object *p_ptr) {
  191. #ifdef DEBUG_ENABLED
  192. // Cannot happen in C#; would get an ObjectDisposedException instead.
  193. CRASH_COND(p_ptr == nullptr);
  194. #endif
  195. // Can't call 'Object::to_string()' here, as that can end up calling 'ToString' again resulting in an endless circular loop.
  196. String result = "[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]";
  197. return GDMonoMarshal::mono_string_from_godot(result);
  198. }
  199. void godot_register_object_icalls() {
  200. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor);
  201. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed);
  202. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed);
  203. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals);
  204. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method);
  205. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString);
  206. GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref);
  207. GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
  208. GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", godot_icall_DynamicGodotObject_SetMemberList);
  209. GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", godot_icall_DynamicGodotObject_InvokeMember);
  210. GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember);
  211. GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember);
  212. }
  213. #endif // MONO_GLUE_ENABLED