| 1145 | } |
| 1146 | |
| 1147 | bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object) { |
| 1148 | #ifdef DEBUG_ENABLED |
| 1149 | // I don't trust you |
| 1150 | if (p_object->get_script_instance()) { |
| 1151 | CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance()); |
| 1152 | CRASH_COND(csharp_instance != nullptr && !csharp_instance->is_destructing_script_instance()); |
| 1153 | } |
| 1154 | #endif // DEBUG_ENABLED |
| 1155 | |
| 1156 | StringName type_name = p_object->get_class_name(); |
| 1157 | |
| 1158 | const ClassDB::ClassInfo *classinfo = ClassDB::classes.getptr(type_name); |
| 1159 | |
| 1160 | // This skipping of GDExtension classes, as well as whatever classes are in this list of ignored types, is a |
| 1161 | // workaround to allow GDExtension classes to be used from C# so long as they're only used through base classes that |
| 1162 | // are registered from the engine. This will likely need to be removed whenever proper support for GDExtension |
| 1163 | // classes is added to C#. See #75955 for more details. |
| 1164 | while (classinfo && (!classinfo->exposed || classinfo->gdextension || ignored_types.has(classinfo->name))) { |
| 1165 | classinfo = classinfo->inherits_ptr; |
| 1166 | } |
| 1167 | |
| 1168 | ERR_FAIL_NULL_V(classinfo, false); |
| 1169 | type_name = classinfo->name; |
| 1170 | |
| 1171 | bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), type_name); |
| 1172 | ERR_FAIL_COND_V_MSG(!parent_is_object_class, false, |
| 1173 | "Type inherits from native type '" + type_name + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'."); |
| 1174 | |
| 1175 | #ifdef DEBUG_ENABLED |
| 1176 | CRASH_COND(!r_script_binding.gchandle.is_released()); |
| 1177 | #endif // DEBUG_ENABLED |
| 1178 | |
| 1179 | GCHandleIntPtr strong_gchandle = |
| 1180 | GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding( |
| 1181 | &type_name, p_object); |
| 1182 | |
| 1183 | ERR_FAIL_NULL_V(strong_gchandle.value, false); |
| 1184 | |
| 1185 | r_script_binding.inited = true; |
| 1186 | r_script_binding.type_name = type_name; |
| 1187 | r_script_binding.gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE); |
| 1188 | r_script_binding.owner = p_object; |
| 1189 | |
| 1190 | // Tie managed to unmanaged |
| 1191 | RefCounted *rc = Object::cast_to<RefCounted>(p_object); |
| 1192 | |
| 1193 | if (rc) { |
| 1194 | // Unsafe refcount increment. The managed instance also counts as a reference. |
| 1195 | // This way if the unmanaged world has no references to our owner |
| 1196 | // but the managed instance is alive, the refcount will be 1 instead of 0. |
| 1197 | // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) |
| 1198 | |
| 1199 | rc->reference(); |
| 1200 | CSharpLanguage::get_singleton()->post_unsafe_reference(rc); |
| 1201 | } |
| 1202 | |
| 1203 | return true; |
| 1204 | } |
no test coverage detected