summaryrefslogtreecommitdiff
path: root/modules/mono/glue/placeholder_glue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/glue/placeholder_glue.cpp')
-rw-r--r--modules/mono/glue/placeholder_glue.cpp161
1 files changed, 153 insertions, 8 deletions
diff --git a/modules/mono/glue/placeholder_glue.cpp b/modules/mono/glue/placeholder_glue.cpp
index edac231bb4..0dd904373e 100644
--- a/modules/mono/glue/placeholder_glue.cpp
+++ b/modules/mono/glue/placeholder_glue.cpp
@@ -33,24 +33,169 @@
#include "core/object/object.h"
+#include "../csharp_script.h"
+#include "../mono_gd/gd_mono_cache.h"
#include "../mono_gd/gd_mono_internals.h"
#include "../mono_gd/gd_mono_utils.h"
-MonoObject *godot_icall_InteropUtils_unmanaged_get_managed(Object *unmanaged) {
- return GDMonoUtils::unmanaged_get_managed(unmanaged);
+GCHandleIntPtr unmanaged_get_script_instance_managed(Object *p_unmanaged, bool *r_has_cs_script_instance) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+ CRASH_COND(!r_has_cs_script_instance);
+#endif
+
+ if (p_unmanaged->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
+
+ if (cs_instance) {
+ *r_has_cs_script_instance = true;
+ return cs_instance->get_gchandle_intptr();
+ }
+ }
+
+ *r_has_cs_script_instance = false;
+ return GCHandleIntPtr();
}
-void godot_icall_InteropUtils_tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
- GDMonoInternals::tie_managed_to_unmanaged(managed, unmanaged);
+GCHandleIntPtr unmanaged_get_instance_binding_managed(Object *p_unmanaged) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+
+ return script_binding.gchandle.get_intptr();
+}
+
+GCHandleIntPtr unmanaged_instance_binding_create_managed(Object *p_unmanaged, GCHandleIntPtr p_old_gchandle) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+
+ // TODO: Possible data race?
+ CRASH_COND(gchandle.get_intptr().value != p_old_gchandle.value);
+
+ CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
+ script_binding.inited = false;
+
+ // Create a new one
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(script_binding.type_name == StringName());
+#endif
+
+ bool parent_is_object_class = ClassDB::is_parent_class(p_unmanaged->get_class_name(), script_binding.type_name);
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, GCHandleIntPtr(),
+ "Type inherits from native type '" + script_binding.type_name + "', so it can't be instantiated in object of type: '" + p_unmanaged->get_class() + "'.");
+
+ MonoException *exc = nullptr;
+ GCHandleIntPtr strong_gchandle =
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding
+ .invoke(&script_binding.type_name, p_unmanaged, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return GCHandleIntPtr();
+ }
+
+ ERR_FAIL_NULL_V(strong_gchandle.value, GCHandleIntPtr());
+
+ gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
+ script_binding.inited = true;
+
+ // Tie managed to unmanaged
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
+
+ if (rc) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
+ rc->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
+ }
+
+ return gchandle.get_intptr();
+}
+
+void godot_icall_InteropUtils_tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
+ CSharpLanguage::tie_native_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_native_name, p_ref_counted);
+}
+
+void godot_icall_InteropUtils_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
+ CSharpLanguage::tie_user_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_script, p_ref_counted);
+}
+
+void godot_icall_InteropUtils_tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
+ CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(p_gchandle_intptr, p_unmanaged);
+}
+
+CSharpScript *godot_icall_InteropUtils_internal_new_csharp_script() {
+ CSharpScript *script = memnew(CSharpScript);
+ CRASH_COND(!script);
+ return script;
+}
+
+void godotsharp_array_filter_godot_objects_by_native(StringName *p_native_name, const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ if (ClassDB::is_parent_class(((Object *)(*p_input)[i])->get_class(), *p_native_name)) {
+ r_output->push_back(p_input[i]);
+ }
+ }
+}
+
+void godotsharp_array_filter_godot_objects_by_non_native(const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ CSharpInstance *si = CAST_CSHARP_INSTANCE(((Object *)(*p_input)[i])->get_script_instance());
+
+ if (si != nullptr) {
+ r_output->push_back(p_input[i]);
+ }
+ }
}
void godot_register_placeholder_icalls() {
GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_unmanaged_get_managed",
- godot_icall_InteropUtils_unmanaged_get_managed);
+ "Godot.NativeInterop.InteropUtils::unmanaged_get_script_instance_managed",
+ unmanaged_get_script_instance_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::unmanaged_get_instance_binding_managed",
+ unmanaged_get_instance_binding_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::unmanaged_instance_binding_create_managed",
+ unmanaged_instance_binding_create_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_native_managed_to_unmanaged",
+ godot_icall_InteropUtils_tie_native_managed_to_unmanaged);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_user_managed_to_unmanaged",
+ godot_icall_InteropUtils_tie_user_managed_to_unmanaged);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged_with_pre_setup",
+ godot_icall_InteropUtils_tie_managed_to_unmanaged_with_pre_setup);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_new_csharp_script",
+ godot_icall_InteropUtils_internal_new_csharp_script);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.SceneTree::godotsharp_array_filter_godot_objects_by_native",
+ godotsharp_array_filter_godot_objects_by_native);
GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged",
- godot_icall_InteropUtils_tie_managed_to_unmanaged);
+ "Godot.NativeInterop.SceneTree::godotsharp_array_filter_godot_objects_by_non_native",
+ godotsharp_array_filter_godot_objects_by_non_native);
}
#endif // GLUE_HEADER_H