base_object_glue.cpp 9.8 KB

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