mirror of
https://github.com/godotengine/godot.git
synced 2024-11-26 14:13:10 +00:00
Merge pull request #51739 from neikeq/fix-csharp-instance-bindings
Fix C# native instance bindings after recent re-write
This commit is contained in:
commit
2735f829c9
@ -1811,6 +1811,21 @@ void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingC
|
||||
return binding;
|
||||
}
|
||||
|
||||
bool Object::has_instance_binding(void *p_token) {
|
||||
bool found = false;
|
||||
_instance_binding_mutex.lock();
|
||||
for (uint32_t i = 0; i < _instance_binding_count; i++) {
|
||||
if (_instance_bindings[i].token == p_token) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_instance_binding_mutex.unlock();
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void Object::_construct_object(bool p_reference) {
|
||||
type_is_reference = p_reference;
|
||||
_instance_id = ObjectDB::add_instance(this);
|
||||
|
@ -809,6 +809,7 @@ public:
|
||||
void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
|
||||
// Used on creation by binding only.
|
||||
void set_instance_binding(void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
|
||||
bool has_instance_binding(void *p_token);
|
||||
|
||||
void clear_internal_resource_paths();
|
||||
|
||||
|
@ -82,6 +82,12 @@ static bool _create_project_solution_if_needed() {
|
||||
|
||||
CSharpLanguage *CSharpLanguage::singleton = nullptr;
|
||||
|
||||
GDNativeInstanceBindingCallbacks CSharpLanguage::_instance_binding_callbacks = {
|
||||
&_instance_binding_create_callback,
|
||||
&_instance_binding_free_callback,
|
||||
&_instance_binding_reference_callback
|
||||
};
|
||||
|
||||
String CSharpLanguage::get_name() const {
|
||||
return "C#";
|
||||
}
|
||||
@ -1444,46 +1450,46 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
|
||||
return true;
|
||||
}
|
||||
|
||||
void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
|
||||
MutexLock lock(language_bind_mutex);
|
||||
Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
|
||||
return script_bindings.insert(p_object, p_script_binding);
|
||||
}
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *match = script_bindings.find(p_object);
|
||||
void *CSharpLanguage::_instance_binding_create_callback(void *, void *p_instance) {
|
||||
CSharpLanguage *csharp_lang = CSharpLanguage::get_singleton();
|
||||
|
||||
MutexLock lock(csharp_lang->language_bind_mutex);
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance);
|
||||
if (match) {
|
||||
return (void *)match;
|
||||
}
|
||||
|
||||
CSharpScriptBinding script_binding;
|
||||
|
||||
if (!setup_csharp_script_binding(script_binding, p_object)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (void *)insert_script_binding(p_object, script_binding);
|
||||
return (void *)csharp_lang->insert_script_binding((Object *)p_instance, script_binding);
|
||||
}
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
|
||||
return script_bindings.insert(p_object, p_script_binding);
|
||||
}
|
||||
void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_binding) {
|
||||
CSharpLanguage *csharp_lang = CSharpLanguage::get_singleton();
|
||||
|
||||
void CSharpLanguage::free_instance_binding_data(void *p_data) {
|
||||
if (GDMono::get_singleton() == nullptr) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!script_bindings.is_empty());
|
||||
CRASH_COND(!csharp_lang->script_bindings.is_empty());
|
||||
#endif
|
||||
// Mono runtime finalized, all the gchandle bindings were already released
|
||||
return;
|
||||
}
|
||||
|
||||
if (finalizing) {
|
||||
if (csharp_lang->finalizing) {
|
||||
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
|
||||
}
|
||||
|
||||
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||
|
||||
{
|
||||
MutexLock lock(language_bind_mutex);
|
||||
MutexLock lock(csharp_lang->language_bind_mutex);
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
|
||||
Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_binding;
|
||||
|
||||
CSharpScriptBinding &script_binding = data->value();
|
||||
|
||||
@ -1497,62 +1503,21 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
|
||||
script_binding.gchandle.release();
|
||||
}
|
||||
|
||||
script_bindings.erase(data);
|
||||
csharp_lang->script_bindings.erase(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
|
||||
#if 0
|
||||
RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);
|
||||
GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) {
|
||||
CRASH_COND(!p_binding);
|
||||
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
|
||||
|
||||
RefCounted *rc_owner = Object::cast_to<RefCounted>(script_binding.owner);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!rc_owner);
|
||||
CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
|
||||
#endif
|
||||
|
||||
void *data = p_object->get_script_instance_binding(get_language_index());
|
||||
CRASH_COND(!data);
|
||||
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
MonoGCHandleData &gchandle = script_binding.gchandle;
|
||||
|
||||
if (!script_binding.inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||
|
||||
// The reference count was increased after the managed side was the only one referencing our owner.
|
||||
// This means the owner is being referenced again by the unmanaged side,
|
||||
// so the owner must hold the managed side alive again to avoid it from being GCed.
|
||||
|
||||
MonoObject *target = gchandle.get_target();
|
||||
if (!target) {
|
||||
return; // Called after the managed side was collected, so nothing to do here
|
||||
}
|
||||
|
||||
// Release the current weak handle and replace it with a strong handle.
|
||||
MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
|
||||
gchandle.release();
|
||||
gchandle = strong_gchandle;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
|
||||
#if 0
|
||||
RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!rc_owner);
|
||||
CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
|
||||
#endif
|
||||
|
||||
void *data = p_object->get_script_instance_binding(get_language_index());
|
||||
CRASH_COND(!data);
|
||||
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
MonoGCHandleData &gchandle = script_binding.gchandle;
|
||||
|
||||
int refcount = rc_owner->reference_get_count();
|
||||
@ -1561,28 +1526,87 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
|
||||
return refcount == 0;
|
||||
}
|
||||
|
||||
if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||
if (p_reference) {
|
||||
// Refcount incremented
|
||||
if (refcount > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||
|
||||
// If owner owner is no longer referenced by the unmanaged side,
|
||||
// the managed instance takes responsibility of deleting the owner when GCed.
|
||||
// The reference count was increased after the managed side was the only one referencing our owner.
|
||||
// This means the owner is being referenced again by the unmanaged side,
|
||||
// so the owner must hold the managed side alive again to avoid it from being GCed.
|
||||
|
||||
MonoObject *target = gchandle.get_target();
|
||||
if (!target) {
|
||||
return refcount == 0; // Called after the managed side was collected, so nothing to do here
|
||||
MonoObject *target = gchandle.get_target();
|
||||
if (!target) {
|
||||
return false; // Called after the managed side was collected, so nothing to do here
|
||||
}
|
||||
|
||||
// Release the current weak handle and replace it with a strong handle.
|
||||
MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
|
||||
gchandle.release();
|
||||
gchandle = strong_gchandle;
|
||||
}
|
||||
|
||||
// Release the current strong handle and replace it with a weak handle.
|
||||
MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
|
||||
gchandle.release();
|
||||
gchandle = weak_gchandle;
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// Refcount decremented
|
||||
if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||
|
||||
// If owner owner is no longer referenced by the unmanaged side,
|
||||
// the managed instance takes responsibility of deleting the owner when GCed.
|
||||
|
||||
MonoObject *target = gchandle.get_target();
|
||||
if (!target) {
|
||||
return refcount == 0; // Called after the managed side was collected, so nothing to do here
|
||||
}
|
||||
|
||||
// Release the current strong handle and replace it with a weak handle.
|
||||
MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
|
||||
gchandle.release();
|
||||
gchandle = weak_gchandle;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return refcount == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *CSharpLanguage::get_instance_binding(Object *p_object) {
|
||||
void *binding = p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks);
|
||||
|
||||
// Initially this was in `_instance_binding_create_callback`. However, after the new instance
|
||||
// binding re-write it was resulting in a deadlock in `_instance_binding_reference`, as
|
||||
// `setup_csharp_script_binding` may call `reference()`. It was moved here outside to fix that.
|
||||
|
||||
if (binding) {
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)binding)->value();
|
||||
|
||||
if (!script_binding.inited) {
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
|
||||
if (!script_binding.inited) { // Another thread may have set it up
|
||||
CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, p_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return refcount == 0;
|
||||
return binding;
|
||||
}
|
||||
|
||||
void *CSharpLanguage::get_existing_instance_binding(Object *p_object) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(p_object->has_instance_binding(p_object));
|
||||
#endif
|
||||
return false;
|
||||
return p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks);
|
||||
}
|
||||
|
||||
void CSharpLanguage::set_instance_binding(Object *p_object, void *p_binding) {
|
||||
p_object->set_instance_binding(get_singleton(), p_binding, &_instance_binding_callbacks);
|
||||
}
|
||||
|
||||
bool CSharpLanguage::has_instance_binding(Object *p_object) {
|
||||
return p_object->has_instance_binding(get_singleton());
|
||||
}
|
||||
|
||||
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
|
||||
@ -2260,28 +2284,15 @@ CSharpInstance::~CSharpInstance() {
|
||||
// Otherwise, the unsafe reference debug checks will incorrectly detect a bug.
|
||||
bool die = _unreference_owner_unsafe();
|
||||
CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die
|
||||
#if 0
|
||||
void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
|
||||
void *data = CSharpLanguage::get_instance_binding(owner);
|
||||
CRASH_COND(data == nullptr);
|
||||
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
|
||||
if (!script_binding.inited) {
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
|
||||
if (!script_binding.inited) { // Other thread may have set it up
|
||||
// Already had a binding that needs to be setup
|
||||
CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, owner);
|
||||
CRASH_COND(!script_binding.inited);
|
||||
}
|
||||
}
|
||||
CRASH_COND(!script_binding.inited);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
|
||||
CRASH_COND(rc_owner->reference_get_count() <= 1);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -3100,10 +3111,10 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
||||
// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
|
||||
ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner));
|
||||
}
|
||||
#if 0
|
||||
|
||||
// If the object had a script instance binding, dispose it before adding the CSharpInstance
|
||||
if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) {
|
||||
void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
if (CSharpLanguage::has_instance_binding(p_owner)) {
|
||||
void *data = CSharpLanguage::get_existing_instance_binding(p_owner);
|
||||
CRASH_COND(data == nullptr);
|
||||
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
@ -3122,7 +3133,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
||||
script_binding.inited = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this)));
|
||||
instance->base_ref_counted = p_is_ref_counted;
|
||||
instance->owner = p_owner;
|
||||
@ -3192,7 +3203,7 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
|
||||
CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
|
||||
if (!instance) {
|
||||
if (ref.is_null()) {
|
||||
memdelete(owner); //no owner, sorry
|
||||
memdelete(owner); // no owner, sorry
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
@ -401,7 +401,18 @@ class CSharpLanguage : public ScriptLanguage {
|
||||
static void _editor_init_callback();
|
||||
#endif
|
||||
|
||||
static void *_instance_binding_create_callback(void *p_token, void *p_instance);
|
||||
static void _instance_binding_free_callback(void *p_token, void *p_instance, void *p_binding);
|
||||
static GDNativeBool _instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference);
|
||||
|
||||
static GDNativeInstanceBindingCallbacks _instance_binding_callbacks;
|
||||
|
||||
public:
|
||||
static void *get_instance_binding(Object *p_object);
|
||||
static void *get_existing_instance_binding(Object *p_object);
|
||||
static void set_instance_binding(Object *p_object, void *p_binding);
|
||||
static bool has_instance_binding(Object *p_object);
|
||||
|
||||
StringNameCache string_names;
|
||||
|
||||
const Mutex &get_language_bind_mutex() { return language_bind_mutex; }
|
||||
@ -507,12 +518,6 @@ public:
|
||||
void thread_enter() override;
|
||||
void thread_exit() override;
|
||||
|
||||
// Don't use these. I'm watching you
|
||||
void *alloc_instance_binding_data(Object *p_object) override;
|
||||
void free_instance_binding_data(void *p_data) override;
|
||||
void refcount_incremented_instance_binding(Object *p_object) override;
|
||||
bool refcount_decremented_instance_binding(Object *p_object) override;
|
||||
|
||||
Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
|
||||
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
|
||||
|
||||
|
@ -64,8 +64,8 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
|
||||
|
||||
if (data) {
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
@ -76,7 +76,6 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
|
||||
@ -85,7 +84,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
|
||||
// This is only called with RefCounted derived classes
|
||||
CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
|
||||
#endif
|
||||
#if 0
|
||||
|
||||
RefCounted *rc = static_cast<RefCounted *>(p_ptr);
|
||||
|
||||
if (rc->get_script_instance()) {
|
||||
@ -113,7 +112,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
|
||||
if (rc->unreference()) {
|
||||
memdelete(rc);
|
||||
} else {
|
||||
void *data = rc->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
void *data = CSharpLanguage::get_existing_instance_binding(rc);
|
||||
|
||||
if (data) {
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
|
||||
@ -125,7 +124,6 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
|
||||
|
@ -45,7 +45,7 @@
|
||||
namespace GDMonoInternals {
|
||||
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||
// This method should not fail
|
||||
#if 0
|
||||
|
||||
CRASH_COND(!unmanaged);
|
||||
|
||||
// All mono objects created from the managed world (e.g.: 'new Player()')
|
||||
@ -89,12 +89,12 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||
}
|
||||
|
||||
// The object was just created, no script instance binding should have been attached
|
||||
CRASH_COND(unmanaged->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()));
|
||||
CRASH_COND(CSharpLanguage::has_instance_binding(unmanaged));
|
||||
|
||||
void *data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding);
|
||||
|
||||
// Should be thread safe because the object was just created and nothing else should be referencing it
|
||||
unmanaged->set_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index(), data);
|
||||
CSharpLanguage::set_instance_binding(unmanaged, data);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -108,7 +108,6 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
|
||||
|
||||
unmanaged->set_script_and_instance(script, csharp_instance);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unhandled_exception(MonoException *p_exc) {
|
||||
|
@ -54,7 +54,6 @@
|
||||
namespace GDMonoUtils {
|
||||
|
||||
MonoObject *unmanaged_get_managed(Object *unmanaged) {
|
||||
#if 0
|
||||
if (!unmanaged) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -69,22 +68,10 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
|
||||
|
||||
// If the owner does not have a CSharpInstance...
|
||||
|
||||
void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
void *data = CSharpLanguage::get_instance_binding(unmanaged);
|
||||
ERR_FAIL_NULL_V(data, nullptr);
|
||||
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
|
||||
|
||||
if (!script_binding.inited) {
|
||||
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
|
||||
|
||||
if (!script_binding.inited) { // Other thread may have set it up
|
||||
// Already had a binding that needs to be setup
|
||||
CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged);
|
||||
|
||||
ERR_FAIL_COND_V(!script_binding.inited, nullptr);
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V(!script_binding.inited, nullptr);
|
||||
|
||||
MonoGCHandleData &gchandle = script_binding.gchandle;
|
||||
|
||||
@ -121,8 +108,6 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
|
||||
}
|
||||
|
||||
return mono_object;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void set_main_thread(MonoThread *p_thread) {
|
||||
|
Loading…
Reference in New Issue
Block a user