Merge pull request #21990 from neikeq/howwouldyounamethisbranch
C#/Mono fixes and enhancements
This commit is contained in:
commit
cc71012266
36 changed files with 1982 additions and 971 deletions
|
@ -7,21 +7,24 @@ env_mono = env_modules.Clone()
|
|||
|
||||
# TODO move functions to their own modules
|
||||
|
||||
def make_cs_files_header(src, dst):
|
||||
def make_cs_files_header(src, dst, version_dst):
|
||||
from compat import byte_to_str
|
||||
|
||||
with open(dst, 'w') as header:
|
||||
header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n')
|
||||
header.write('#ifndef _CS_FILES_DATA_H\n')
|
||||
header.write('#define _CS_FILES_DATA_H\n\n')
|
||||
header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
|
||||
header.write('#ifndef CS_COMPRESSED_H\n')
|
||||
header.write('#define CS_COMPRESSED_H\n\n')
|
||||
header.write('#ifdef TOOLS_ENABLED\n\n')
|
||||
header.write('#include "map.h"\n')
|
||||
header.write('#include "ustring.h"\n')
|
||||
inserted_files = ''
|
||||
import os
|
||||
latest_mtime = 0
|
||||
cs_file_count = 0
|
||||
for root, _, files in os.walk(src):
|
||||
files = [f for f in files if f.endswith('.cs')]
|
||||
for file in files:
|
||||
cs_file_count += 1
|
||||
filepath = os.path.join(root, file)
|
||||
filepath_src_rel = os.path.relpath(filepath, src)
|
||||
mtime = os.path.getmtime(filepath)
|
||||
|
@ -31,8 +34,10 @@ def make_cs_files_header(src, dst):
|
|||
decomp_size = len(buf)
|
||||
import zlib
|
||||
buf = zlib.compress(buf)
|
||||
name = os.path.splitext(os.path.normpath(filepath_src_rel))[0].strip(os.sep).replace(os.sep, '_').replace('.', '_dotto_')
|
||||
header.write('\nstatic const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
|
||||
name = str(cs_file_count)
|
||||
header.write('\n')
|
||||
header.write('// ' + filepath_src_rel + '\n')
|
||||
header.write('static const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
|
||||
header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n')
|
||||
header.write('static const unsigned char _cs_' + name + '_compressed[] = { ')
|
||||
for i, buf_idx in enumerate(range(len(buf))):
|
||||
|
@ -44,8 +49,6 @@ def make_cs_files_header(src, dst):
|
|||
'_cs_' + name + '_uncompressed_size, ' \
|
||||
'_cs_' + name + '_compressed));\n'
|
||||
header.write(' };\n')
|
||||
glue_version = int(latest_mtime) # The latest modified time will do for now
|
||||
header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
|
||||
header.write('\nstruct CompressedFile\n' '{\n'
|
||||
'\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
|
||||
'\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
|
||||
|
@ -53,17 +56,28 @@ def make_cs_files_header(src, dst):
|
|||
'\t\tdata = p_data;\n' '\t}\n' '\n\tCompressedFile() {}\n' '};\n'
|
||||
'\nvoid get_compressed_files(Map<String, CompressedFile>& r_files)\n' '{\n' + inserted_files + '}\n'
|
||||
)
|
||||
header.write('#endif // _CS_FILES_DATA_H')
|
||||
header.write('\n#endif // TOOLS_ENABLED\n')
|
||||
header.write('\n#endif // CS_COMPRESSED_H\n')
|
||||
|
||||
glue_version = int(latest_mtime) # The latest modified time will do for now
|
||||
|
||||
with open(version_dst, 'w') as version_header:
|
||||
version_header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
|
||||
version_header.write('#ifndef CS_GLUE_VERSION_H\n')
|
||||
version_header.write('#define CS_GLUE_VERSION_H\n\n')
|
||||
version_header.write('#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
|
||||
version_header.write('\n#endif // CS_GLUE_VERSION_H\n')
|
||||
|
||||
|
||||
env_mono.add_source_files(env.modules_sources, '*.cpp')
|
||||
env_mono.add_source_files(env.modules_sources, 'glue/*.cpp')
|
||||
env_mono.add_source_files(env.modules_sources, 'mono_gd/*.cpp')
|
||||
env_mono.add_source_files(env.modules_sources, 'utils/*.cpp')
|
||||
|
||||
if env['tools']:
|
||||
env_mono.add_source_files(env.modules_sources, 'editor/*.cpp')
|
||||
# NOTE: It is safe to generate this file here, since this is still execute serially
|
||||
make_cs_files_header('glue/cs_files', 'glue/cs_compressed.gen.h')
|
||||
# NOTE: It is safe to generate this file here, since this is still executed serially
|
||||
make_cs_files_header('glue/cs_files', 'glue/cs_compressed.gen.h', 'glue/cs_glue_version.gen.h')
|
||||
|
||||
vars = Variables()
|
||||
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
|
||||
|
@ -72,9 +86,7 @@ vars.Update(env_mono)
|
|||
|
||||
# Glue sources
|
||||
if env_mono['mono_glue']:
|
||||
env_mono.add_source_files(env.modules_sources, 'glue/*.cpp')
|
||||
else:
|
||||
env_mono.Append(CPPDEFINES=['MONO_GLUE_DISABLED'])
|
||||
env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
|
||||
|
||||
if ARGUMENTS.get('yolo_copy', False):
|
||||
env_mono.Append(CPPDEFINES=['YOLO_COPY'])
|
||||
|
|
|
@ -107,7 +107,7 @@ void CSharpLanguage::init() {
|
|||
gdmono = memnew(GDMono);
|
||||
gdmono->initialize();
|
||||
|
||||
#ifdef MONO_GLUE_DISABLED
|
||||
#ifndef MONO_GLUE_ENABLED
|
||||
WARN_PRINT("This binary is built with `mono_glue=no` and cannot be used for scripting");
|
||||
#endif
|
||||
|
||||
|
@ -138,7 +138,7 @@ void CSharpLanguage::finish() {
|
|||
#endif
|
||||
|
||||
// Release gchandle bindings before finalizing mono runtime
|
||||
gchandle_bindings.clear();
|
||||
script_bindings.clear();
|
||||
|
||||
if (gdmono) {
|
||||
memdelete(gdmono);
|
||||
|
@ -551,22 +551,22 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
|
|||
|
||||
void CSharpLanguage::frame() {
|
||||
|
||||
const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle;
|
||||
if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) {
|
||||
const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle;
|
||||
|
||||
if (task_scheduler_handle.is_valid()) {
|
||||
MonoObject *task_scheduler = task_scheduler_handle->get_target();
|
||||
if (task_scheduler_handle.is_valid()) {
|
||||
MonoObject *task_scheduler = task_scheduler_handle->get_target();
|
||||
|
||||
if (task_scheduler) {
|
||||
GDMonoUtils::GodotTaskScheduler_Activate thunk = CACHED_METHOD_THUNK(GodotTaskScheduler, Activate);
|
||||
if (task_scheduler) {
|
||||
GDMonoUtils::GodotTaskScheduler_Activate thunk = CACHED_METHOD_THUNK(GodotTaskScheduler, Activate);
|
||||
|
||||
ERR_FAIL_NULL(thunk);
|
||||
MonoException *exc = NULL;
|
||||
thunk(task_scheduler, (MonoObject **)&exc);
|
||||
|
||||
MonoException *exc = NULL;
|
||||
thunk(task_scheduler, (MonoObject **)&exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
_UNREACHABLE_();
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
_UNREACHABLE_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -892,6 +892,48 @@ void CSharpLanguage::set_language_index(int p_idx) {
|
|||
lang_idx = p_idx;
|
||||
}
|
||||
|
||||
void CSharpLanguage::release_script_gchandle(Ref<MonoGCHandle> &p_gchandle) {
|
||||
|
||||
if (!p_gchandle->is_released()) { // Do not locking unnecessarily
|
||||
#ifndef NO_THREADS
|
||||
get_singleton()->script_gchandle_release_lock->lock();
|
||||
#endif
|
||||
|
||||
p_gchandle->release();
|
||||
|
||||
#ifndef NO_THREADS
|
||||
get_singleton()->script_gchandle_release_lock->unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CSharpLanguage::release_script_gchandle(MonoObject *p_pinned_expected_obj, Ref<MonoGCHandle> &p_gchandle) {
|
||||
|
||||
uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(p_pinned_expected_obj); // we might lock after this, so pin it
|
||||
|
||||
if (!p_gchandle->is_released()) { // Do not locking unnecessarily
|
||||
#ifndef NO_THREADS
|
||||
get_singleton()->script_gchandle_release_lock->lock();
|
||||
#endif
|
||||
|
||||
MonoObject *target = p_gchandle->get_target();
|
||||
|
||||
// We release the gchandle if it points to the MonoObject* we expect (otherwise it was
|
||||
// already released and could have been replaced) or if we can't get its target MonoObject*
|
||||
// (which doesn't necessarily mean it was released, and we want it released in order to
|
||||
// avoid locking other threads unnecessarily).
|
||||
if (target == p_pinned_expected_obj || target == NULL) {
|
||||
p_gchandle->release();
|
||||
}
|
||||
|
||||
#ifndef NO_THREADS
|
||||
get_singleton()->script_gchandle_release_lock->unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
MonoGCHandle::free_handle(pinned_gchandle);
|
||||
}
|
||||
|
||||
CSharpLanguage::CSharpLanguage() {
|
||||
|
||||
ERR_FAIL_COND(singleton);
|
||||
|
@ -904,9 +946,11 @@ CSharpLanguage::CSharpLanguage() {
|
|||
#ifdef NO_THREADS
|
||||
lock = NULL;
|
||||
gchandle_bind_lock = NULL;
|
||||
script_gchandle_release_lock = NULL;
|
||||
#else
|
||||
lock = Mutex::create();
|
||||
script_bind_lock = Mutex::create();
|
||||
script_gchandle_release_lock = Mutex::create();
|
||||
#endif
|
||||
|
||||
lang_idx = -1;
|
||||
|
@ -926,6 +970,11 @@ CSharpLanguage::~CSharpLanguage() {
|
|||
script_bind_lock = NULL;
|
||||
}
|
||||
|
||||
if (script_gchandle_release_lock) {
|
||||
memdelete(script_gchandle_release_lock);
|
||||
script_gchandle_release_lock = NULL;
|
||||
}
|
||||
|
||||
singleton = NULL;
|
||||
}
|
||||
|
||||
|
@ -954,6 +1003,22 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
|
|||
|
||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||
|
||||
CSharpScriptBinding script_binding;
|
||||
|
||||
script_binding.type_name = type_name;
|
||||
script_binding.wrapper_class = type_class; // cache
|
||||
script_binding.gchandle = MonoGCHandle::create_strong(mono_object);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script_bind_lock->lock();
|
||||
#endif
|
||||
|
||||
void *data = (void *)script_bindings.insert(p_object, script_binding);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script_bind_lock->unlock();
|
||||
#endif
|
||||
|
||||
// Tie managed to unmanaged
|
||||
Reference *ref = Object::cast_to<Reference>(p_object);
|
||||
|
||||
|
@ -961,23 +1026,11 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
|
|||
// 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: _GodotSharp::_dispose_object(Object *p_object)
|
||||
// See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
|
||||
|
||||
ref->reference();
|
||||
}
|
||||
|
||||
Ref<MonoGCHandle> gchandle = MonoGCHandle::create_strong(mono_object);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script_bind_lock->lock();
|
||||
#endif
|
||||
|
||||
void *data = (void *)gchandle_bindings.insert(p_object, gchandle);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script_bind_lock->unlock();
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -985,7 +1038,7 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
|
|||
|
||||
if (GDMono::get_singleton() == NULL) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!gchandle_bindings.empty());
|
||||
CRASH_COND(!script_bindings.empty());
|
||||
#endif
|
||||
// Mono runtime finalized, all the gchandle bindings were already released
|
||||
return;
|
||||
|
@ -998,15 +1051,15 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
|
|||
script_bind_lock->lock();
|
||||
#endif
|
||||
|
||||
Map<Object *, Ref<MonoGCHandle> >::Element *data = (Map<Object *, Ref<MonoGCHandle> >::Element *)p_data;
|
||||
Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
|
||||
|
||||
// Set the native instance field to IntPtr.Zero, if not yet garbage collected
|
||||
MonoObject *mono_object = data->value()->get_target();
|
||||
MonoObject *mono_object = data->value().gchandle->get_target();
|
||||
if (mono_object) {
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
|
||||
}
|
||||
|
||||
gchandle_bindings.erase(data);
|
||||
script_bindings.erase(data);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
script_bind_lock->unlock();
|
||||
|
@ -1024,7 +1077,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
|
|||
void *data = p_object->get_script_instance_binding(get_language_index());
|
||||
if (!data)
|
||||
return;
|
||||
Ref<MonoGCHandle> &gchandle = ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->get();
|
||||
Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
|
||||
|
||||
if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
||||
// The reference count was increased after the managed side was the only one referencing our owner.
|
||||
|
@ -1036,7 +1089,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
|
|||
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.
|
||||
uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(target);
|
||||
uint32_t strong_gchandle = MonoGCHandle::new_strong_handle(target);
|
||||
gchandle->release();
|
||||
gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE);
|
||||
}
|
||||
|
@ -1055,7 +1108,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
|
|||
void *data = p_object->get_script_instance_binding(get_language_index());
|
||||
if (!data)
|
||||
return refcount == 0;
|
||||
Ref<MonoGCHandle> &gchandle = ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->get();
|
||||
Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
|
||||
|
||||
if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
|
||||
// If owner owner is no longer referenced by the unmanaged side,
|
||||
|
@ -1066,7 +1119,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
|
|||
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.
|
||||
uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(target);
|
||||
uint32_t weak_gchandle = MonoGCHandle::new_weak_handle(target);
|
||||
gchandle->release();
|
||||
gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE);
|
||||
|
||||
|
@ -1096,9 +1149,8 @@ CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpS
|
|||
}
|
||||
|
||||
MonoObject *CSharpInstance::get_mono_object() const {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(gchandle.is_null());
|
||||
#endif
|
||||
|
||||
ERR_FAIL_COND_V(gchandle.is_null(), NULL);
|
||||
return gchandle->get_target();
|
||||
}
|
||||
|
||||
|
@ -1326,10 +1378,12 @@ void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const
|
|||
call_multilevel(p_method, p_args, p_argcount);
|
||||
}
|
||||
|
||||
void CSharpInstance::_reference_owner_unsafe() {
|
||||
bool CSharpInstance::_reference_owner_unsafe() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!base_ref);
|
||||
CRASH_COND(owner == NULL);
|
||||
CRASH_COND(unsafe_referenced); // already referenced
|
||||
#endif
|
||||
|
||||
// Unsafe refcount increment. The managed instance also counts as a reference.
|
||||
|
@ -1338,36 +1392,107 @@ void CSharpInstance::_reference_owner_unsafe() {
|
|||
// See: _unreference_owner_unsafe()
|
||||
|
||||
// May not me referenced yet, so we must use init_ref() instead of reference()
|
||||
Object::cast_to<Reference>(owner)->init_ref();
|
||||
bool success = Object::cast_to<Reference>(owner)->init_ref();
|
||||
unsafe_referenced = success;
|
||||
return success;
|
||||
}
|
||||
|
||||
void CSharpInstance::_unreference_owner_unsafe() {
|
||||
bool CSharpInstance::_unreference_owner_unsafe() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!base_ref);
|
||||
CRASH_COND(owner == NULL);
|
||||
#endif
|
||||
|
||||
if (!unsafe_referenced)
|
||||
return false; // Already unreferenced
|
||||
|
||||
// Called from CSharpInstance::mono_object_disposed() or ~CSharpInstance()
|
||||
|
||||
// Unsafe refcount decrement. The managed instance also counts as a reference.
|
||||
// See: _reference_owner_unsafe()
|
||||
|
||||
if (Object::cast_to<Reference>(owner)->unreference()) {
|
||||
bool die = static_cast<Reference *>(owner)->unreference();
|
||||
|
||||
if (die) {
|
||||
memdelete(owner);
|
||||
owner = NULL;
|
||||
}
|
||||
|
||||
return die;
|
||||
}
|
||||
|
||||
void CSharpInstance::mono_object_disposed() {
|
||||
MonoObject *CSharpInstance::_internal_new_managed() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!gchandle.is_valid());
|
||||
#endif
|
||||
|
||||
CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
|
||||
|
||||
ERR_FAIL_NULL_V(owner, NULL);
|
||||
ERR_FAIL_COND_V(script.is_null(), NULL);
|
||||
|
||||
if (base_ref)
|
||||
_unreference_owner_unsafe();
|
||||
_reference_owner_unsafe();
|
||||
|
||||
MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script->script_class->get_mono_ptr());
|
||||
|
||||
if (!mono_object) {
|
||||
script = Ref<CSharpScript>();
|
||||
owner->set_script_instance(NULL);
|
||||
ERR_EXPLAIN("Failed to allocate memory for the object");
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner);
|
||||
|
||||
// Construct
|
||||
GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
||||
ctor->invoke_raw(mono_object, NULL);
|
||||
|
||||
// Tie managed to unmanaged
|
||||
gchandle = MonoGCHandle::create_strong(mono_object);
|
||||
|
||||
return mono_object;
|
||||
}
|
||||
|
||||
bool CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(base_ref == true);
|
||||
CRASH_COND(gchandle.is_null());
|
||||
#endif
|
||||
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
|
||||
}
|
||||
|
||||
bool CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(base_ref == false);
|
||||
CRASH_COND(gchandle.is_null());
|
||||
#endif
|
||||
if (_unreference_owner_unsafe()) {
|
||||
r_owner_deleted = true;
|
||||
} else {
|
||||
r_owner_deleted = false;
|
||||
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
|
||||
if (p_is_finalizer) {
|
||||
// If the native instance is still alive, then it was
|
||||
// referenced from another thread before the finalizer could
|
||||
// unreference it and delete it, so we want to keep it.
|
||||
// GC.ReRegisterForFinalize(this) is not safe because the objects
|
||||
// referenced by this could have already been collected.
|
||||
// Instead we will create a new managed instance here.
|
||||
_internal_new_managed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSharpInstance::refcount_incremented() {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!base_ref);
|
||||
CRASH_COND(owner == NULL);
|
||||
#endif
|
||||
|
||||
Reference *ref_owner = Object::cast_to<Reference>(owner);
|
||||
|
@ -1378,7 +1503,7 @@ void CSharpInstance::refcount_incremented() {
|
|||
// so the owner must hold the managed side alive again to avoid it from being GCed.
|
||||
|
||||
// Release the current weak handle and replace it with a strong handle.
|
||||
uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(gchandle->get_target());
|
||||
uint32_t strong_gchandle = MonoGCHandle::new_strong_handle(gchandle->get_target());
|
||||
gchandle->release();
|
||||
gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE);
|
||||
}
|
||||
|
@ -1388,6 +1513,7 @@ bool CSharpInstance::refcount_decremented() {
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!base_ref);
|
||||
CRASH_COND(owner == NULL);
|
||||
#endif
|
||||
|
||||
Reference *ref_owner = Object::cast_to<Reference>(owner);
|
||||
|
@ -1399,7 +1525,7 @@ bool CSharpInstance::refcount_decremented() {
|
|||
// the managed instance takes responsibility of deleting the owner when GCed.
|
||||
|
||||
// Release the current strong handle and replace it with a weak handle.
|
||||
uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(gchandle->get_target());
|
||||
uint32_t weak_gchandle = MonoGCHandle::new_weak_handle(gchandle->get_target());
|
||||
gchandle->release();
|
||||
gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE);
|
||||
|
||||
|
@ -1470,25 +1596,64 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab
|
|||
|
||||
void CSharpInstance::notification(int p_notification) {
|
||||
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
|
||||
if (p_notification == Object::NOTIFICATION_PREDELETE) {
|
||||
if (mono_object != NULL) { // otherwise it was collected, and the finalizer already called NOTIFICATION_PREDELETE
|
||||
call_notification_no_check(mono_object, p_notification);
|
||||
// Set the native instance field to IntPtr.Zero
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
|
||||
// When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose().
|
||||
// It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
|
||||
// to be sent at least once, which happens right before the call to the destructor.
|
||||
|
||||
if (base_ref) {
|
||||
// It's not safe to proceed if the owner derives Reference and the refcount reached 0.
|
||||
// At this point, Dispose() was already called (manually or from the finalizer) so
|
||||
// that's not a problem. The refcount wouldn't have reached 0 otherwise, since the
|
||||
// managed side references it and Dispose() needs to be called to release it.
|
||||
// However, this means C# Reference scripts can't receive NOTIFICATION_PREDELETE, but
|
||||
// this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784
|
||||
return;
|
||||
}
|
||||
|
||||
_call_notification(p_notification);
|
||||
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
ERR_FAIL_NULL(mono_object);
|
||||
|
||||
GDMonoUtils::GodotObject_Dispose thunk = CACHED_METHOD_THUNK(GodotObject, Dispose);
|
||||
|
||||
MonoException *exc = NULL;
|
||||
thunk(mono_object, (MonoObject **)&exc);
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::set_pending_exception(exc);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
call_notification_no_check(mono_object, p_notification);
|
||||
_call_notification(p_notification);
|
||||
}
|
||||
|
||||
void CSharpInstance::call_notification_no_check(MonoObject *p_mono_object, int p_notification) {
|
||||
Variant value = p_notification;
|
||||
const Variant *args[1] = { &value };
|
||||
void CSharpInstance::_call_notification(int p_notification) {
|
||||
|
||||
_call_multilevel(p_mono_object, CACHED_STRING_NAME(_notification), args, 1);
|
||||
MonoObject *mono_object = get_mono_object();
|
||||
ERR_FAIL_NULL(mono_object);
|
||||
|
||||
// Custom version of _call_multilevel, optimized for _notification
|
||||
|
||||
uint32_t arg = p_notification;
|
||||
void *args[1] = { &arg };
|
||||
StringName method_name = CACHED_STRING_NAME(_notification);
|
||||
|
||||
GDMonoClass *top = script->script_class;
|
||||
|
||||
while (top && top != script->native) {
|
||||
GDMonoMethod *method = top->get_method(method_name, 1);
|
||||
|
||||
if (method) {
|
||||
method->invoke_raw(mono_object, args);
|
||||
return;
|
||||
}
|
||||
|
||||
top = top->get_parent_class();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Script> CSharpInstance::get_script() const {
|
||||
|
@ -1501,11 +1666,11 @@ ScriptLanguage *CSharpInstance::get_language() {
|
|||
return CSharpLanguage::get_singleton();
|
||||
}
|
||||
|
||||
CSharpInstance::CSharpInstance() {
|
||||
|
||||
owner = NULL;
|
||||
base_ref = false;
|
||||
ref_dying = false;
|
||||
CSharpInstance::CSharpInstance() :
|
||||
owner(NULL),
|
||||
base_ref(false),
|
||||
ref_dying(false),
|
||||
unsafe_referenced(false) {
|
||||
}
|
||||
|
||||
CSharpInstance::~CSharpInstance() {
|
||||
|
@ -1514,10 +1679,7 @@ CSharpInstance::~CSharpInstance() {
|
|||
gchandle->release(); // Make sure it's released
|
||||
}
|
||||
|
||||
if (base_ref && !ref_dying) { // it may be called from the owner's destructor
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(!owner); // dunno, just in case
|
||||
#endif
|
||||
if (base_ref && !ref_dying && owner) { // it may be called from the owner's destructor
|
||||
_unreference_owner_unsafe();
|
||||
}
|
||||
|
||||
|
@ -1586,29 +1748,30 @@ bool CSharpScript::_update_exports() {
|
|||
exported_members_cache.clear();
|
||||
exported_members_defval_cache.clear();
|
||||
|
||||
// We are creating a temporary new instance of the class here to get the default value
|
||||
// TODO Workaround. Should be replaced with IL opcodes analysis
|
||||
// Here we create a temporary managed instance of the class to get the initial values
|
||||
|
||||
MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_mono_ptr());
|
||||
|
||||
if (tmp_object) {
|
||||
CACHED_FIELD(GodotObject, ptr)->set_value_raw(tmp_object, tmp_object); // FIXME WTF is this workaround
|
||||
|
||||
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
||||
MonoException *exc = NULL;
|
||||
ctor->invoke(tmp_object, NULL, &exc);
|
||||
|
||||
if (exc) {
|
||||
ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
tmp_object = NULL;
|
||||
ERR_FAIL_V(false);
|
||||
}
|
||||
} else {
|
||||
if (!tmp_object) {
|
||||
ERR_PRINT("Failed to create temporary MonoObject");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed)
|
||||
|
||||
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
||||
MonoException *ctor_exc = NULL;
|
||||
ctor->invoke(tmp_object, NULL, &ctor_exc);
|
||||
|
||||
if (ctor_exc) {
|
||||
MonoGCHandle::free_handle(tmp_pinned_gchandle);
|
||||
tmp_object = NULL;
|
||||
|
||||
ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
|
||||
GDMonoUtils::debug_print_unhandled_exception(ctor_exc);
|
||||
return false;
|
||||
}
|
||||
|
||||
GDMonoClass *top = script_class;
|
||||
|
||||
while (top && top != native) {
|
||||
|
@ -1666,6 +1829,21 @@ bool CSharpScript::_update_exports() {
|
|||
|
||||
top = top->get_parent_class();
|
||||
}
|
||||
|
||||
// Dispose the temporary managed instance
|
||||
|
||||
GDMonoUtils::GodotObject_Dispose thunk = CACHED_METHOD_THUNK(GodotObject, Dispose);
|
||||
|
||||
MonoException *exc = NULL;
|
||||
thunk(tmp_object, (MonoObject **)&exc);
|
||||
|
||||
if (exc) {
|
||||
ERR_PRINT("Exception thrown from method Dispose() of temporary MonoObject:");
|
||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
||||
}
|
||||
|
||||
MonoGCHandle::free_handle(tmp_pinned_gchandle);
|
||||
tmp_object = NULL;
|
||||
}
|
||||
|
||||
if (placeholders.size()) {
|
||||
|
@ -2012,6 +2190,8 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
|||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(mono_object); // we might lock after this, so pin it
|
||||
|
||||
#ifndef NO_THREADS
|
||||
CSharpLanguage::singleton->lock->lock();
|
||||
#endif
|
||||
|
@ -2033,6 +2213,8 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
|
|||
|
||||
/* STEP 3, PARTY */
|
||||
|
||||
MonoGCHandle::free_handle(pinned_gchandle);
|
||||
|
||||
//@TODO make thread safe
|
||||
return instance;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ class CSharpLanguage;
|
|||
#ifdef NO_SAFE_CAST
|
||||
template <typename TScriptInstance, typename TScriptLanguage>
|
||||
TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
|
||||
if (!p_inst)
|
||||
return NULL;
|
||||
return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : NULL;
|
||||
}
|
||||
#else
|
||||
|
@ -177,14 +179,19 @@ class CSharpInstance : public ScriptInstance {
|
|||
|
||||
friend class CSharpScript;
|
||||
friend class CSharpLanguage;
|
||||
|
||||
Object *owner;
|
||||
Ref<CSharpScript> script;
|
||||
Ref<MonoGCHandle> gchandle;
|
||||
bool base_ref;
|
||||
bool ref_dying;
|
||||
bool unsafe_referenced;
|
||||
|
||||
void _reference_owner_unsafe();
|
||||
void _unreference_owner_unsafe();
|
||||
Ref<CSharpScript> script;
|
||||
Ref<MonoGCHandle> gchandle;
|
||||
|
||||
bool _reference_owner_unsafe();
|
||||
bool _unreference_owner_unsafe();
|
||||
|
||||
MonoObject *_internal_new_managed();
|
||||
|
||||
// Do not use unless you know what you are doing
|
||||
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
|
||||
|
@ -208,7 +215,8 @@ public:
|
|||
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
|
||||
|
||||
void mono_object_disposed();
|
||||
bool mono_object_disposed(MonoObject *p_obj);
|
||||
bool mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted);
|
||||
|
||||
virtual void refcount_incremented();
|
||||
virtual bool refcount_decremented();
|
||||
|
@ -217,7 +225,7 @@ public:
|
|||
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
|
||||
|
||||
virtual void notification(int p_notification);
|
||||
void call_notification_no_check(MonoObject *p_mono_object, int p_notification);
|
||||
void _call_notification(int p_notification);
|
||||
|
||||
virtual Ref<Script> get_script() const;
|
||||
|
||||
|
@ -227,6 +235,12 @@ public:
|
|||
~CSharpInstance();
|
||||
};
|
||||
|
||||
struct CSharpScriptBinding {
|
||||
StringName type_name;
|
||||
GDMonoClass *wrapper_class;
|
||||
Ref<MonoGCHandle> gchandle;
|
||||
};
|
||||
|
||||
class CSharpLanguage : public ScriptLanguage {
|
||||
|
||||
friend class CSharpScript;
|
||||
|
@ -241,10 +255,11 @@ class CSharpLanguage : public ScriptLanguage {
|
|||
|
||||
Mutex *lock;
|
||||
Mutex *script_bind_lock;
|
||||
Mutex *script_gchandle_release_lock;
|
||||
|
||||
Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
|
||||
|
||||
Map<Object *, Ref<MonoGCHandle> > gchandle_bindings;
|
||||
Map<Object *, CSharpScriptBinding> script_bindings;
|
||||
|
||||
struct StringNameCache {
|
||||
|
||||
|
@ -270,6 +285,9 @@ public:
|
|||
|
||||
_FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; }
|
||||
|
||||
static void release_script_gchandle(Ref<MonoGCHandle> &p_gchandle);
|
||||
static void release_script_gchandle(MonoObject *p_pinned_expected_obj, Ref<MonoGCHandle> &p_gchandle);
|
||||
|
||||
bool debug_break(const String &p_error, bool p_allow_continue = true);
|
||||
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "ucaps.h"
|
||||
|
||||
#include "../glue/cs_compressed.gen.h"
|
||||
#include "../glue/cs_glue_version.gen.h"
|
||||
#include "../godotsharp_defs.h"
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
#include "../utils/path_utils.h"
|
||||
|
@ -48,7 +49,7 @@
|
|||
#include "csharp_project.h"
|
||||
#include "net_solution.h"
|
||||
|
||||
#define CS_INDENT " "
|
||||
#define CS_INDENT " " // 4 whitespaces
|
||||
|
||||
#define INDENT1 CS_INDENT
|
||||
#define INDENT2 INDENT1 INDENT1
|
||||
|
@ -68,23 +69,18 @@
|
|||
#define CLOSE_BLOCK_L3 INDENT3 CLOSE_BLOCK
|
||||
#define CLOSE_BLOCK_L4 INDENT4 CLOSE_BLOCK
|
||||
|
||||
#define LOCAL_RET "ret"
|
||||
|
||||
#define CS_FIELD_MEMORYOWN "memoryOwn"
|
||||
#define CS_PARAM_METHODBIND "method"
|
||||
#define CS_PARAM_INSTANCE "ptr"
|
||||
#define CS_SMETHOD_GETINSTANCE "GetPtr"
|
||||
#define CS_FIELD_SINGLETON "instance"
|
||||
#define CS_PROP_SINGLETON "Instance"
|
||||
#define CS_CLASS_SIGNALAWAITER "SignalAwaiter"
|
||||
#define CS_METHOD_CALL "Call"
|
||||
|
||||
#define GLUE_HEADER_FILE "glue_header.h"
|
||||
#define ICALL_PREFIX "godot_icall_"
|
||||
#define SINGLETON_ICALL_SUFFIX "_get_singleton"
|
||||
#define ICALL_GET_METHODBIND ICALL_PREFIX "ClassDB_get_method"
|
||||
#define ICALL_CONNECT_SIGNAL_AWAITER ICALL_PREFIX "Object_connect_signal_awaiter"
|
||||
#define ICALL_OBJECT_DTOR ICALL_PREFIX "Object_Dtor"
|
||||
#define ICALL_GET_METHODBIND ICALL_PREFIX "Object_ClassDB_get_method"
|
||||
|
||||
#define C_LOCAL_RET "ret"
|
||||
#define C_LOCAL_PTRCALL_ARGS "call_args"
|
||||
#define C_MACRO_OBJECT_CONSTRUCT "GODOTSHARP_INSTANCE_OBJECT"
|
||||
|
||||
|
@ -101,7 +97,7 @@
|
|||
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
|
||||
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
|
||||
|
||||
#define BINDINGS_GENERATOR_VERSION UINT32_C(2)
|
||||
#define BINDINGS_GENERATOR_VERSION UINT32_C(3)
|
||||
|
||||
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
|
||||
|
||||
|
@ -196,48 +192,6 @@ String BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
|
|||
return front->get().name.substr(0, candidate_len);
|
||||
}
|
||||
|
||||
void BindingsGenerator::_generate_header_icalls() {
|
||||
|
||||
core_custom_icalls.clear();
|
||||
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_GET_METHODBIND, "IntPtr", "string type, string method"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_OBJECT_DTOR, "void", "object obj, IntPtr ptr"));
|
||||
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_CONNECT_SIGNAL_AWAITER, "Error",
|
||||
"IntPtr source, string signal, IntPtr target, " CS_CLASS_SIGNALAWAITER " awaiter"));
|
||||
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "NodePath_Ctor", "IntPtr", "string path"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "NodePath_Dtor", "void", "IntPtr ptr"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "NodePath_operator_String", "string", "IntPtr ptr"));
|
||||
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "RID_Ctor", "IntPtr", "IntPtr from"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "RID_Dtor", "void", "IntPtr ptr"));
|
||||
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_md5_buffer", "byte[]", "string str"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_md5_text", "string", "string str"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_rfind", "int", "string str, string what, int from"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_rfindn", "int", "string str, string what, int from"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_sha256_buffer", "byte[]", "string str"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_sha256_text", "string", "string str"));
|
||||
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_bytes2var", "object", "byte[] bytes"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_convert", "object", "object what, int type"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_hash", "int", "object var"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_instance_from_id", "Object", "int instance_id"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_print", "void", "object[] what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_printerr", "void", "object[] what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_printraw", "void", "object[] what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_prints", "void", "object[] what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_printt", "void", "object[] what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_seed", "void", "int seed"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_str", "string", "object[] what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_str2var", "object", "string str"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_type_exists", "bool", "string type"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_var2bytes", "byte[]", "object what"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_var2str", "string", "object var"));
|
||||
core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_weakref", "WeakRef", "IntPtr obj"));
|
||||
}
|
||||
|
||||
void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
|
||||
|
||||
for (const List<MethodInterface>::Element *E = p_itype.methods.front(); E; E = E->next()) {
|
||||
|
@ -248,13 +202,8 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
|
|||
|
||||
const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type);
|
||||
|
||||
String im_sig;
|
||||
String im_unique_sig;
|
||||
|
||||
if (p_itype.is_object_type) {
|
||||
im_sig += "IntPtr " CS_PARAM_METHODBIND ", ";
|
||||
im_unique_sig += imethod.return_type.cname.operator String() + ",IntPtr,IntPtr";
|
||||
}
|
||||
String im_sig = "IntPtr " CS_PARAM_METHODBIND ", ";
|
||||
String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr,IntPtr";
|
||||
|
||||
im_sig += "IntPtr " CS_PARAM_INSTANCE;
|
||||
|
||||
|
@ -268,37 +217,28 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
|
|||
im_sig += " arg";
|
||||
im_sig += itos(i + 1);
|
||||
|
||||
if (p_itype.is_object_type) {
|
||||
im_unique_sig += ",";
|
||||
im_unique_sig += get_unique_sig(*arg_type);
|
||||
}
|
||||
im_unique_sig += ",";
|
||||
im_unique_sig += get_unique_sig(*arg_type);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// godot_icall_{argc}_{icallcount}
|
||||
String icall_method = ICALL_PREFIX;
|
||||
|
||||
if (p_itype.is_object_type) {
|
||||
icall_method += itos(imethod.arguments.size()) + "_" + itos(method_icalls.size()); // godot_icall_{argc}_{icallcount}
|
||||
} else {
|
||||
icall_method += p_itype.name + "_" + imethod.name; // godot_icall_{Type}_{method}
|
||||
}
|
||||
icall_method += itos(imethod.arguments.size());
|
||||
icall_method += "_";
|
||||
icall_method += itos(method_icalls.size());
|
||||
|
||||
InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, return_type->im_type_out, im_sig, im_unique_sig);
|
||||
|
||||
if (p_itype.is_object_type) {
|
||||
List<InternalCall>::Element *match = method_icalls.find(im_icall);
|
||||
List<InternalCall>::Element *match = method_icalls.find(im_icall);
|
||||
|
||||
if (match) {
|
||||
if (p_itype.api_type != ClassDB::API_EDITOR)
|
||||
match->get().editor_only = false;
|
||||
method_icalls_map.insert(&E->get(), &match->get());
|
||||
} else {
|
||||
List<InternalCall>::Element *added = method_icalls.push_back(im_icall);
|
||||
method_icalls_map.insert(&E->get(), &added->get());
|
||||
}
|
||||
if (match) {
|
||||
if (p_itype.api_type != ClassDB::API_EDITOR)
|
||||
match->get().editor_only = false;
|
||||
method_icalls_map.insert(&E->get(), &match->get());
|
||||
} else {
|
||||
List<InternalCall>::Element *added = builtin_method_icalls.push_back(im_icall);
|
||||
List<InternalCall>::Element *added = method_icalls.push_back(im_icall);
|
||||
method_icalls_map.insert(&E->get(), &added->get());
|
||||
}
|
||||
}
|
||||
|
@ -483,20 +423,6 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
|
|||
compile_items.push_back(output_file);
|
||||
}
|
||||
|
||||
#define GENERATE_BUILTIN_TYPE(m_name) \
|
||||
{ \
|
||||
String output_file = path_join(core_dir, #m_name ".cs"); \
|
||||
Error err = _generate_cs_type(builtin_types[#m_name], output_file); \
|
||||
if (err != OK) \
|
||||
return err; \
|
||||
compile_items.push_back(output_file); \
|
||||
}
|
||||
|
||||
GENERATE_BUILTIN_TYPE(NodePath);
|
||||
GENERATE_BUILTIN_TYPE(RID);
|
||||
|
||||
#undef GENERATE_BUILTIN_TYPE
|
||||
|
||||
// Generate sources from compressed files
|
||||
|
||||
Map<String, CompressedFile> compressed_files;
|
||||
|
@ -537,29 +463,26 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
|
|||
cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
||||
cs_icalls_content.push_back(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
|
||||
|
||||
cs_icalls_content.push_back(INDENT2 "internal static ulong godot_api_hash = ");
|
||||
cs_icalls_content.push_back(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
|
||||
cs_icalls_content.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
|
||||
cs_icalls_content.push_back(INDENT2 "internal static uint bindings_version = ");
|
||||
cs_icalls_content.push_back(MEMBER_BEGIN "internal static uint bindings_version = ");
|
||||
cs_icalls_content.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
|
||||
cs_icalls_content.push_back(INDENT2 "internal static uint cs_glue_version = ");
|
||||
cs_icalls_content.push_back(MEMBER_BEGIN "internal static uint cs_glue_version = ");
|
||||
cs_icalls_content.push_back(String::num_uint64(CS_GLUE_VERSION) + ";\n");
|
||||
cs_icalls_content.push_back("\n");
|
||||
|
||||
#define ADD_INTERNAL_CALL(m_icall) \
|
||||
if (!m_icall.editor_only) { \
|
||||
cs_icalls_content.push_back(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
|
||||
cs_icalls_content.push_back(INDENT2 "internal extern static "); \
|
||||
cs_icalls_content.push_back(m_icall.im_type_out + " "); \
|
||||
cs_icalls_content.push_back(m_icall.name + "("); \
|
||||
cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
|
||||
#define ADD_INTERNAL_CALL(m_icall) \
|
||||
if (!m_icall.editor_only) { \
|
||||
cs_icalls_content.push_back(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
|
||||
cs_icalls_content.push_back(INDENT2 "internal extern static "); \
|
||||
cs_icalls_content.push_back(m_icall.im_type_out + " "); \
|
||||
cs_icalls_content.push_back(m_icall.name + "("); \
|
||||
cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
|
||||
}
|
||||
|
||||
for (const List<InternalCall>::Element *E = core_custom_icalls.front(); E; E = E->next())
|
||||
ADD_INTERNAL_CALL(E->get());
|
||||
for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next())
|
||||
ADD_INTERNAL_CALL(E->get());
|
||||
for (const List<InternalCall>::Element *E = builtin_method_icalls.front(); E; E = E->next())
|
||||
ADD_INTERNAL_CALL(E->get());
|
||||
|
||||
#undef ADD_INTERNAL_CALL
|
||||
|
||||
|
@ -658,8 +581,6 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
|
|||
cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
|
||||
}
|
||||
|
||||
// No need to add builtin_method_icalls. Builtin types are core only
|
||||
|
||||
for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
|
||||
ADD_INTERNAL_CALL(E->get());
|
||||
for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next())
|
||||
|
@ -693,18 +614,34 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
|
|||
return OK;
|
||||
}
|
||||
|
||||
// TODO: there are constants that hide inherited members. must explicitly use `new` to avoid warnings
|
||||
// e.g.: warning CS0108: 'SpriteBase3D.FLAG_MAX' hides inherited member 'GeometryInstance.FLAG_MAX'. Use the new keyword if hiding was intended.
|
||||
// FIXME: There are some members that hide other inherited members.
|
||||
// - In the case of both members being the same kind, the new one must be declared
|
||||
// explicitly as `new` to avoid the warning (and we must print a message about it).
|
||||
// - In the case of both members being of a different kind, then the new one must
|
||||
// be renamed to avoid the name collision (and we must print a warning about it).
|
||||
// - Csc warning e.g.:
|
||||
// ObjectType/LineEdit.cs(140,38): warning CS0108: 'LineEdit.FocusMode' hides inherited member 'Control.FocusMode'. Use the new keyword if hiding was intended.
|
||||
Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const String &p_output_file) {
|
||||
|
||||
CRASH_COND(!itype.is_object_type);
|
||||
|
||||
bool is_derived_type = itype.base_name != StringName();
|
||||
|
||||
if (!is_derived_type) {
|
||||
// Some Godot.Object assertions
|
||||
CRASH_COND(itype.cname != name_cache.type_Object);
|
||||
CRASH_COND(!itype.is_instantiable);
|
||||
CRASH_COND(itype.api_type != ClassDB::API_CORE);
|
||||
CRASH_COND(itype.is_reference);
|
||||
CRASH_COND(itype.is_singleton);
|
||||
}
|
||||
|
||||
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
|
||||
|
||||
if (verbose_output)
|
||||
OS::get_singleton()->print(String("Generating " + itype.proxy_name + ".cs...\n").utf8());
|
||||
|
||||
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
|
||||
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
|
||||
|
||||
List<String> output;
|
||||
|
||||
|
@ -733,28 +670,24 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
}
|
||||
|
||||
output.push_back(INDENT1 "public ");
|
||||
if (itype.is_object_type) {
|
||||
if (itype.is_singleton) {
|
||||
output.push_back("static partial class ");
|
||||
} else {
|
||||
output.push_back(itype.is_instantiable ? "partial class " : "abstract partial class ");
|
||||
}
|
||||
if (itype.is_singleton) {
|
||||
output.push_back("static partial class ");
|
||||
} else {
|
||||
output.push_back("partial class ");
|
||||
output.push_back(itype.is_instantiable ? "partial class " : "abstract partial class ");
|
||||
}
|
||||
output.push_back(itype.proxy_name);
|
||||
|
||||
if (itype.is_singleton) {
|
||||
output.push_back("\n");
|
||||
} else if (!is_derived_type || !itype.is_object_type /* assuming only object types inherit */) {
|
||||
output.push_back(" : IDisposable\n");
|
||||
} else if (obj_types.has(itype.base_name)) {
|
||||
output.push_back(" : ");
|
||||
output.push_back(obj_types[itype.base_name].proxy_name);
|
||||
output.push_back("\n");
|
||||
} else {
|
||||
ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class " + itype.name);
|
||||
return ERR_INVALID_DATA;
|
||||
} else if (is_derived_type) {
|
||||
if (obj_types.has(itype.base_name)) {
|
||||
output.push_back(" : ");
|
||||
output.push_back(obj_types[itype.base_name].proxy_name);
|
||||
output.push_back("\n");
|
||||
} else {
|
||||
ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class " + itype.name);
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(INDENT1 "{");
|
||||
|
@ -851,9 +784,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
output.push_back(INDENT2 CLOSE_BLOCK);
|
||||
}
|
||||
|
||||
if (itype.enums.size())
|
||||
output.push_back("\n");
|
||||
|
||||
// Add properties
|
||||
|
||||
for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) {
|
||||
|
@ -865,43 +795,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
ERR_FAIL_V(prop_err);
|
||||
}
|
||||
}
|
||||
|
||||
if (class_doc->properties.size())
|
||||
output.push_back("\n");
|
||||
}
|
||||
|
||||
if (!itype.is_object_type) {
|
||||
output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"" + itype.name + "\";\n");
|
||||
output.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
|
||||
output.push_back(MEMBER_BEGIN "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
|
||||
|
||||
output.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(");
|
||||
output.push_back(itype.proxy_name);
|
||||
output.push_back(" instance)\n" OPEN_BLOCK_L2 "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
|
||||
|
||||
// Add Destructor
|
||||
output.push_back(MEMBER_BEGIN "~");
|
||||
output.push_back(itype.proxy_name);
|
||||
output.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
|
||||
|
||||
// Add the Dispose from IDisposable
|
||||
output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
|
||||
|
||||
// Add the virtual Dispose
|
||||
output.push_back(MEMBER_BEGIN "protected virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
|
||||
"if (disposed) return;\n" INDENT3
|
||||
"if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "NativeCalls.godot_icall_");
|
||||
output.push_back(itype.proxy_name);
|
||||
output.push_back("_Dtor(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L3 INDENT3
|
||||
"GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
|
||||
|
||||
output.push_back(MEMBER_BEGIN "internal ");
|
||||
output.push_back(itype.proxy_name);
|
||||
output.push_back("(IntPtr " BINDINGS_PTR_FIELD ")\n" OPEN_BLOCK_L2 "this." BINDINGS_PTR_FIELD " = " BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
|
||||
|
||||
output.push_back(MEMBER_BEGIN "public IntPtr NativeInstance\n" OPEN_BLOCK_L2
|
||||
"get { return " BINDINGS_PTR_FIELD "; }\n" CLOSE_BLOCK_L2);
|
||||
} else if (itype.is_singleton) {
|
||||
if (itype.is_singleton) {
|
||||
// Add the type name and the singleton pointer as static fields
|
||||
|
||||
output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
|
||||
|
@ -913,21 +809,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
output.push_back("." ICALL_PREFIX);
|
||||
output.push_back(itype.name);
|
||||
output.push_back(SINGLETON_ICALL_SUFFIX "();\n");
|
||||
} else {
|
||||
} else if (is_derived_type) {
|
||||
// Add member fields
|
||||
|
||||
output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
|
||||
output.push_back(itype.name);
|
||||
output.push_back("\";\n");
|
||||
|
||||
// Only the base class stores the pointer to the native object
|
||||
// This pointer is expected to be and must be of type Object*
|
||||
if (!is_derived_type) {
|
||||
output.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
|
||||
output.push_back(INDENT2 "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
|
||||
output.push_back(INDENT2 "internal bool " CS_FIELD_MEMORYOWN ";\n");
|
||||
}
|
||||
|
||||
// Add default constructor
|
||||
if (itype.is_instantiable) {
|
||||
output.push_back(MEMBER_BEGIN "public ");
|
||||
|
@ -952,67 +840,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
// Add.. em.. trick constructor. Sort of.
|
||||
output.push_back(MEMBER_BEGIN "internal ");
|
||||
output.push_back(itype.proxy_name);
|
||||
if (is_derived_type) {
|
||||
output.push_back("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
|
||||
} else {
|
||||
output.push_back("(bool " CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L2
|
||||
"this." CS_FIELD_MEMORYOWN " = " CS_FIELD_MEMORYOWN ";\n" CLOSE_BLOCK_L2);
|
||||
}
|
||||
|
||||
// Add methods
|
||||
|
||||
if (!is_derived_type) {
|
||||
output.push_back(MEMBER_BEGIN "public IntPtr NativeInstance\n" OPEN_BLOCK_L2
|
||||
"get { return " BINDINGS_PTR_FIELD "; }\n" CLOSE_BLOCK_L2);
|
||||
|
||||
output.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(Object instance)\n" OPEN_BLOCK_L2
|
||||
"return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
|
||||
}
|
||||
|
||||
if (!is_derived_type) {
|
||||
// Add destructor
|
||||
output.push_back(MEMBER_BEGIN "~");
|
||||
output.push_back(itype.proxy_name);
|
||||
output.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
|
||||
|
||||
// Add the Dispose from IDisposable
|
||||
output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
|
||||
|
||||
// Add the virtual Dispose
|
||||
output.push_back(MEMBER_BEGIN "protected virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
|
||||
"if (disposed) return;\n" INDENT3
|
||||
"if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
|
||||
"if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
|
||||
" = false;\n" INDENT5 BINDINGS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
|
||||
"(this, " BINDINGS_PTR_FIELD ");\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
|
||||
"this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" INDENT3
|
||||
"GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
|
||||
|
||||
Map<StringName, TypeInterface>::Element *array_itype = builtin_types.find(name_cache.type_Array);
|
||||
|
||||
if (!array_itype) {
|
||||
ERR_PRINT("BUG: Array type interface not found!");
|
||||
return ERR_BUG;
|
||||
}
|
||||
|
||||
OrderedHashMap<StringName, TypeInterface>::Element object_itype = obj_types.find("Object");
|
||||
|
||||
if (!object_itype) {
|
||||
ERR_PRINT("BUG: Object type interface not found!");
|
||||
return ERR_BUG;
|
||||
}
|
||||
|
||||
output.push_back(MEMBER_BEGIN "public " CS_CLASS_SIGNALAWAITER " ToSignal(");
|
||||
output.push_back(object_itype.get().cs_type);
|
||||
output.push_back(" source, string signal)\n" OPEN_BLOCK_L2
|
||||
"return new " CS_CLASS_SIGNALAWAITER "(source, signal, this);\n" CLOSE_BLOCK_L2);
|
||||
}
|
||||
output.push_back("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
|
||||
}
|
||||
|
||||
Map<StringName, String>::Element *extra_member = extra_members.find(itype.cname);
|
||||
if (extra_member)
|
||||
output.push_back(extra_member->get());
|
||||
|
||||
int method_bind_count = 0;
|
||||
for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
|
||||
const MethodInterface &imethod = E->get();
|
||||
|
@ -1030,7 +860,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
custom_icalls.push_back(singleton_icall);
|
||||
}
|
||||
|
||||
if (itype.is_instantiable) {
|
||||
if (is_derived_type && itype.is_instantiable) {
|
||||
InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
|
||||
|
||||
if (!find_icall_by_name(ctor_icall.name, custom_icalls))
|
||||
|
@ -1178,9 +1008,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
|||
String arguments_sig;
|
||||
String cs_in_statements;
|
||||
|
||||
String icall_params;
|
||||
if (p_itype.is_object_type)
|
||||
icall_params += method_bind_field + ", ";
|
||||
String icall_params = method_bind_field + ", ";
|
||||
icall_params += sformat(p_itype.cs_in, "this");
|
||||
|
||||
List<String> default_args_doc;
|
||||
|
@ -1257,9 +1085,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
|||
|
||||
// Generate method
|
||||
{
|
||||
if (p_itype.is_object_type && !p_imethod.is_virtual && !p_imethod.requires_object_call) {
|
||||
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
|
||||
p_output.push_back(MEMBER_BEGIN "private static IntPtr ");
|
||||
p_output.push_back(method_bind_field + " = " BINDINGS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
|
||||
p_output.push_back(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
|
||||
p_output.push_back(p_imethod.name);
|
||||
p_output.push_back("\");\n");
|
||||
}
|
||||
|
@ -1372,19 +1200,31 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
|||
|
||||
List<String> output;
|
||||
|
||||
output.push_back("#include \"" GLUE_HEADER_FILE "\"\n"
|
||||
"\n");
|
||||
output.push_back("/* THIS FILE IS GENERATED DO NOT EDIT */\n");
|
||||
output.push_back("#include \"" GLUE_HEADER_FILE "\"\n");
|
||||
output.push_back("\n#ifdef MONO_GLUE_ENABLED\n");
|
||||
|
||||
generated_icall_funcs.clear();
|
||||
|
||||
for (OrderedHashMap<StringName, TypeInterface>::Element type_elem = obj_types.front(); type_elem; type_elem = type_elem.next()) {
|
||||
const TypeInterface &itype = type_elem.get();
|
||||
|
||||
bool is_derived_type = itype.base_name != StringName();
|
||||
|
||||
if (!is_derived_type) {
|
||||
// Some Object assertions
|
||||
CRASH_COND(itype.cname != name_cache.type_Object);
|
||||
CRASH_COND(!itype.is_instantiable);
|
||||
CRASH_COND(itype.api_type != ClassDB::API_CORE);
|
||||
CRASH_COND(itype.is_reference);
|
||||
CRASH_COND(itype.is_singleton);
|
||||
}
|
||||
|
||||
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
|
||||
|
||||
OS::get_singleton()->print(String("Generating " + itype.name + "...\n").utf8());
|
||||
|
||||
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
|
||||
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
|
||||
|
||||
for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
|
||||
const MethodInterface &imethod = E->get();
|
||||
|
@ -1409,7 +1249,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
|||
output.push_back("\");\n" CLOSE_BLOCK "\n");
|
||||
}
|
||||
|
||||
if (itype.is_instantiable) {
|
||||
if (is_derived_type && itype.is_instantiable) {
|
||||
InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
|
||||
|
||||
if (!find_icall_by_name(ctor_icall.name, custom_icalls))
|
||||
|
@ -1426,7 +1266,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
|||
}
|
||||
}
|
||||
|
||||
output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK);
|
||||
output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK "\n");
|
||||
|
||||
output.push_back("uint64_t get_core_api_hash() { return ");
|
||||
output.push_back(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
|
||||
|
@ -1438,11 +1278,9 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
|||
|
||||
output.push_back("uint32_t get_bindings_version() { return ");
|
||||
output.push_back(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
|
||||
output.push_back("uint32_t get_cs_glue_version() { return ");
|
||||
output.push_back(String::num_uint64(CS_GLUE_VERSION) + "; }\n");
|
||||
|
||||
output.push_back("void register_generated_icalls() " OPEN_BLOCK);
|
||||
output.push_back("\tgodot_register_header_icalls();");
|
||||
output.push_back("\nvoid register_generated_icalls() " OPEN_BLOCK);
|
||||
output.push_back("\tgodot_register_glue_header_icalls();\n");
|
||||
|
||||
#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
|
||||
{ \
|
||||
|
@ -1505,12 +1343,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
|||
output.push_back("#endif\n");
|
||||
}
|
||||
|
||||
for (const List<InternalCall>::Element *E = builtin_method_icalls.front(); E; E = E->next())
|
||||
ADD_INTERNAL_CALL_REGISTRATION(E->get());
|
||||
|
||||
#undef ADD_INTERNAL_CALL_REGISTRATION
|
||||
|
||||
output.push_back(CLOSE_BLOCK "}\n");
|
||||
output.push_back(CLOSE_BLOCK "\n} // namespace GodotSharpBindings\n");
|
||||
|
||||
output.push_back("\n#endif // MONO_GLUE_ENABLED\n");
|
||||
|
||||
Error save_err = _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), output);
|
||||
if (save_err != OK)
|
||||
|
@ -1525,10 +1362,6 @@ uint32_t BindingsGenerator::get_version() {
|
|||
return BINDINGS_GENERATOR_VERSION;
|
||||
}
|
||||
|
||||
uint32_t BindingsGenerator::get_cs_glue_version() {
|
||||
return CS_GLUE_VERSION;
|
||||
}
|
||||
|
||||
Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) {
|
||||
|
||||
FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
|
||||
|
@ -1591,9 +1424,6 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
|
|||
i++;
|
||||
}
|
||||
|
||||
if (!p_itype.is_object_type)
|
||||
return OK; // no auto-generated icall functions for builtin types
|
||||
|
||||
const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
|
||||
ERR_FAIL_NULL_V(match, ERR_BUG);
|
||||
|
||||
|
@ -1628,7 +1458,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
|
|||
}
|
||||
|
||||
p_output.push_back("\t" + ptrcall_return_type);
|
||||
p_output.push_back(" " LOCAL_RET);
|
||||
p_output.push_back(" " C_LOCAL_RET);
|
||||
p_output.push_back(initialization + ";\n");
|
||||
p_output.push_back("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE);
|
||||
p_output.push_back(fail_ret);
|
||||
|
@ -1678,7 +1508,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
|
|||
p_output.push_back("\tVariant::CallError vcall_error;\n\t");
|
||||
|
||||
if (!ret_void)
|
||||
p_output.push_back(LOCAL_RET " = ");
|
||||
p_output.push_back(C_LOCAL_RET " = ");
|
||||
|
||||
p_output.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
|
||||
p_output.push_back(p_imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
|
||||
|
@ -1686,14 +1516,14 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
|
|||
} else {
|
||||
p_output.push_back("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
|
||||
p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
|
||||
p_output.push_back(!ret_void ? "&" LOCAL_RET ");\n" : "NULL);\n");
|
||||
p_output.push_back(!ret_void ? "&" C_LOCAL_RET ");\n" : "NULL);\n");
|
||||
}
|
||||
|
||||
if (!ret_void) {
|
||||
if (return_type->c_out.empty())
|
||||
p_output.push_back("\treturn " LOCAL_RET ";\n");
|
||||
p_output.push_back("\treturn " C_LOCAL_RET ";\n");
|
||||
else
|
||||
p_output.push_back(sformat(return_type->c_out, return_type->c_type_out, LOCAL_RET, return_type->name));
|
||||
p_output.push_back(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name));
|
||||
}
|
||||
|
||||
p_output.push_back(CLOSE_BLOCK "\n");
|
||||
|
@ -1752,9 +1582,6 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
|
|||
return &placeholder_types.insert(placeholder.cname, placeholder)->get();
|
||||
}
|
||||
|
||||
static void _create_constant_interface_from(const StringName &p_constant, const DocData::ClassDoc &p_classdoc) {
|
||||
}
|
||||
|
||||
void BindingsGenerator::_populate_object_type_interfaces() {
|
||||
|
||||
obj_types.clear();
|
||||
|
@ -1889,9 +1716,6 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||
if (virtual_method_list.find(method_info)) {
|
||||
// A virtual method without the virtual flag. This is a special case.
|
||||
|
||||
// This type of method can only be found in Object derived types.
|
||||
ERR_FAIL_COND(!itype.is_object_type);
|
||||
|
||||
// There is no method bind, so let's fallback to Godot's object.Call(string, params)
|
||||
imethod.requires_object_call = true;
|
||||
|
||||
|
@ -2273,13 +2097,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
|||
itype.cs_out = "return new %1(%0);";
|
||||
itype.im_type_in = "IntPtr";
|
||||
itype.im_type_out = "IntPtr";
|
||||
_populate_builtin_type(itype, Variant::NODE_PATH);
|
||||
extra_members.insert(itype.cname, MEMBER_BEGIN "public NodePath() : this(string.Empty) {}\n" MEMBER_BEGIN "public NodePath(string path)\n" OPEN_BLOCK_L2
|
||||
"this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2
|
||||
MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2
|
||||
MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2
|
||||
"return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2
|
||||
MEMBER_BEGIN "public override string ToString()\n" OPEN_BLOCK_L2 "return (string)this;\n" CLOSE_BLOCK_L2);
|
||||
builtin_types.insert(itype.cname, itype);
|
||||
|
||||
// RID
|
||||
|
@ -2296,9 +2113,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
|||
itype.cs_out = "return new %1(%0);";
|
||||
itype.im_type_in = "IntPtr";
|
||||
itype.im_type_out = "IntPtr";
|
||||
_populate_builtin_type(itype, Variant::_RID);
|
||||
extra_members.insert(itype.cname, MEMBER_BEGIN "internal RID()\n" OPEN_BLOCK_L2
|
||||
"this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L2);
|
||||
builtin_types.insert(itype.cname, itype);
|
||||
|
||||
// Variant
|
||||
|
@ -2413,60 +2227,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
|||
builtin_types.insert(itype.cname, itype);
|
||||
}
|
||||
|
||||
void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype) {
|
||||
|
||||
Variant::CallError cerror;
|
||||
Variant v = Variant::construct(vtype, NULL, 0, cerror);
|
||||
|
||||
List<MethodInfo> method_list;
|
||||
v.get_method_list(&method_list);
|
||||
method_list.sort();
|
||||
|
||||
for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
|
||||
MethodInfo &mi = E->get();
|
||||
MethodInterface imethod;
|
||||
|
||||
imethod.name = mi.name;
|
||||
imethod.cname = imethod.name;
|
||||
imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(mi.name));
|
||||
|
||||
for (int i = 0; i < mi.arguments.size(); i++) {
|
||||
ArgumentInterface iarg;
|
||||
PropertyInfo pi = mi.arguments[i];
|
||||
|
||||
iarg.name = pi.name;
|
||||
|
||||
if (pi.type == Variant::NIL)
|
||||
iarg.type.cname = name_cache.type_Variant;
|
||||
else
|
||||
iarg.type.cname = Variant::get_type_name(pi.type);
|
||||
|
||||
if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0)
|
||||
_default_argument_from_variant(Variant::construct(pi.type, NULL, 0, cerror), iarg);
|
||||
|
||||
imethod.add_argument(iarg);
|
||||
}
|
||||
|
||||
if (mi.return_val.type == Variant::NIL) {
|
||||
if (mi.return_val.name != "")
|
||||
imethod.return_type.cname = name_cache.type_Variant;
|
||||
} else {
|
||||
imethod.return_type.cname = Variant::get_type_name(mi.return_val.type);
|
||||
}
|
||||
|
||||
if (r_itype.class_doc) {
|
||||
for (int i = 0; i < r_itype.class_doc->methods.size(); i++) {
|
||||
if (r_itype.class_doc->methods[i].name == imethod.name) {
|
||||
imethod.method_doc = &r_itype.class_doc->methods[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r_itype.methods.push_back(imethod);
|
||||
}
|
||||
}
|
||||
|
||||
void BindingsGenerator::_populate_global_constants() {
|
||||
|
||||
int global_constants_count = GlobalConstants::get_global_constant_count();
|
||||
|
@ -2564,15 +2324,13 @@ void BindingsGenerator::initialize() {
|
|||
|
||||
_populate_global_constants();
|
||||
|
||||
// Populate internal calls (after populating type interfaces and global constants)
|
||||
// Generate internal calls (after populating type interfaces and global constants)
|
||||
|
||||
_generate_header_icalls();
|
||||
core_custom_icalls.clear();
|
||||
editor_custom_icalls.clear();
|
||||
|
||||
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next())
|
||||
_generate_method_icalls(E.get());
|
||||
|
||||
_generate_method_icalls(builtin_types["NodePath"]);
|
||||
_generate_method_icalls(builtin_types["RID"]);
|
||||
}
|
||||
|
||||
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
|
||||
|
|
|
@ -456,10 +456,7 @@ class BindingsGenerator {
|
|||
List<EnumInterface> global_enums;
|
||||
List<ConstantInterface> global_constants;
|
||||
|
||||
Map<StringName, String> extra_members;
|
||||
|
||||
List<InternalCall> method_icalls;
|
||||
List<InternalCall> builtin_method_icalls;
|
||||
Map<const MethodInterface *, const InternalCall *> method_icalls_map;
|
||||
|
||||
List<const InternalCall *> generated_icall_funcs;
|
||||
|
@ -518,14 +515,12 @@ class BindingsGenerator {
|
|||
|
||||
String _determine_enum_prefix(const EnumInterface &p_ienum);
|
||||
|
||||
void _generate_header_icalls();
|
||||
void _generate_method_icalls(const TypeInterface &p_itype);
|
||||
|
||||
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
|
||||
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
|
||||
|
||||
void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg);
|
||||
void _populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype);
|
||||
|
||||
void _populate_object_type_interfaces();
|
||||
void _populate_builtin_type_interfaces();
|
||||
|
@ -557,7 +552,6 @@ public:
|
|||
Error generate_glue(const String &p_output_dir);
|
||||
|
||||
static uint32_t get_version();
|
||||
static uint32_t get_cs_glue_version();
|
||||
|
||||
void initialize();
|
||||
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
|
||||
#include "godotsharp_builds.h"
|
||||
|
||||
#include "core/vector.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#include "../glue/cs_glue_version.gen.h"
|
||||
#include "../godotsharp_dirs.h"
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
@ -50,6 +52,16 @@ void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *
|
|||
GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code);
|
||||
}
|
||||
|
||||
static Vector<const char *> _get_msbuild_hint_dirs() {
|
||||
Vector<const char *> ret;
|
||||
#ifdef OSX_ENABLED
|
||||
ret.push_back("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
|
||||
ret.push_back("/usr/local/var/homebrew/linked/mono/bin/");
|
||||
#endif
|
||||
ret.push_back("/opt/novell/mono/bin/");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UNIX_ENABLED
|
||||
String _find_build_engine_on_unix(const String &p_name) {
|
||||
String ret = path_which(p_name);
|
||||
|
@ -61,15 +73,9 @@ String _find_build_engine_on_unix(const String &p_name) {
|
|||
if (ret_fallback.length())
|
||||
return ret_fallback;
|
||||
|
||||
const char *locations[] = {
|
||||
#ifdef OSX_ENABLED
|
||||
"/Library/Frameworks/Mono.framework/Versions/Current/bin/",
|
||||
"/usr/local/var/homebrew/linked/mono/bin/",
|
||||
#endif
|
||||
"/opt/novell/mono/bin/"
|
||||
};
|
||||
static Vector<const char *> locations = _get_msbuild_hint_dirs();
|
||||
|
||||
for (int i = 0; i < sizeof(locations) / sizeof(const char *); i++) {
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
String hint_path = locations[i] + p_name;
|
||||
|
||||
if (FileAccess::exists(hint_path)) {
|
||||
|
@ -263,7 +269,7 @@ String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
|
|||
GDMono::get_singleton()->get_api_editor_hash();
|
||||
return String::num_uint64(api_hash) +
|
||||
"_" + String::num_uint64(BindingsGenerator::get_version()) +
|
||||
"_" + String::num_uint64(BindingsGenerator::get_cs_glue_version());
|
||||
"_" + String::num_uint64(CS_GLUE_VERSION);
|
||||
}
|
||||
|
||||
bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
|
||||
|
|
|
@ -53,9 +53,9 @@ void MonoBottomPanel::_update_build_tabs_list() {
|
|||
|
||||
build_tabs_list->add_item(item_name, tab->get_icon_texture());
|
||||
|
||||
String item_tooltip = String("Solution: ") + tab->build_info.solution;
|
||||
item_tooltip += String("\nConfiguration: ") + tab->build_info.configuration;
|
||||
item_tooltip += String("\nStatus: ");
|
||||
String item_tooltip = "Solution: " + tab->build_info.solution;
|
||||
item_tooltip += "\nConfiguration: " + tab->build_info.configuration;
|
||||
item_tooltip += "\nStatus: ";
|
||||
|
||||
if (tab->build_exited) {
|
||||
item_tooltip += tab->build_result == MonoBuildTab::RESULT_SUCCESS ? "Succeeded" : "Errored";
|
||||
|
|
154
modules/mono/glue/base_object_glue.cpp
Normal file
154
modules/mono/glue/base_object_glue.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*************************************************************************/
|
||||
/* base_object_glue.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "base_object_glue.h"
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/reference.h"
|
||||
#include "core/string_db.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../mono_gd/gd_mono_internals.h"
|
||||
#include "../mono_gd/gd_mono_utils.h"
|
||||
#include "../signal_awaiter_utils.h"
|
||||
|
||||
Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
|
||||
Object *instance = memnew(Object);
|
||||
GDMonoInternals::tie_managed_to_unmanaged(p_obj, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(p_ptr == NULL);
|
||||
#endif
|
||||
|
||||
if (p_ptr->get_script_instance()) {
|
||||
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
|
||||
if (cs_instance) {
|
||||
cs_instance->mono_object_disposed(p_obj);
|
||||
p_ptr->set_script_instance(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
if (data) {
|
||||
Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
|
||||
if (gchandle.is_valid()) {
|
||||
CSharpLanguage::release_script_gchandle(p_obj, gchandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(p_ptr == NULL);
|
||||
// This is only called with Reference derived classes
|
||||
CRASH_COND(!Object::cast_to<Reference>(p_ptr));
|
||||
#endif
|
||||
|
||||
Reference *ref = static_cast<Reference *>(p_ptr);
|
||||
|
||||
if (ref->get_script_instance()) {
|
||||
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance());
|
||||
if (cs_instance) {
|
||||
bool r_owner_deleted;
|
||||
cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, r_owner_deleted);
|
||||
if (!r_owner_deleted && !p_is_finalizer) {
|
||||
// If the native instance is still alive and Dispose() was called
|
||||
// (instead of the finalizer), then we remove the script instance.
|
||||
ref->set_script_instance(NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe refcount decrement. The managed instance also counts as a reference.
|
||||
// See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
|
||||
if (ref->unreference()) {
|
||||
memdelete(ref);
|
||||
} else {
|
||||
void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
if (data) {
|
||||
Ref<MonoGCHandle> &gchandle = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get().gchandle;
|
||||
if (gchandle.is_valid()) {
|
||||
CSharpLanguage::release_script_gchandle(p_obj, gchandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method) {
|
||||
StringName type(GDMonoMarshal::mono_string_to_godot(p_type));
|
||||
StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
|
||||
return ClassDB::get_method(type, method);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Object_weakref(Object *p_obj) {
|
||||
if (!p_obj)
|
||||
return NULL;
|
||||
|
||||
Ref<WeakRef> wref;
|
||||
Reference *ref = Object::cast_to<Reference>(p_obj);
|
||||
|
||||
if (ref) {
|
||||
REF r = ref;
|
||||
if (!r.is_valid())
|
||||
return NULL;
|
||||
|
||||
wref.instance();
|
||||
wref->set_ref(r);
|
||||
} else {
|
||||
wref.instance();
|
||||
wref->set_obj(p_obj);
|
||||
}
|
||||
|
||||
return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr()));
|
||||
}
|
||||
|
||||
Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) {
|
||||
String signal = GDMonoMarshal::mono_string_to_godot(p_signal);
|
||||
return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
|
||||
}
|
||||
|
||||
void godot_register_object_icalls() {
|
||||
mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor);
|
||||
mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed);
|
||||
mono_add_internal_call("Godot.Object::godot_icall_Reference_Disposed", (void *)godot_icall_Reference_Disposed);
|
||||
mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method);
|
||||
mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref);
|
||||
mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect);
|
||||
}
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
59
modules/mono/glue/base_object_glue.h
Normal file
59
modules/mono/glue/base_object_glue.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*************************************************************************/
|
||||
/* base_object_glue.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef BASE_OBJECT_GLUE_H
|
||||
#define BASE_OBJECT_GLUE_H
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/class_db.h"
|
||||
#include "core/object.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
||||
Object *godot_icall_Object_Ctor(MonoObject *p_obj);
|
||||
|
||||
void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr);
|
||||
|
||||
void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer);
|
||||
|
||||
MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method);
|
||||
|
||||
MonoObject *godot_icall_Object_weakref(Object *p_obj);
|
||||
|
||||
Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter);
|
||||
|
||||
// Register internal calls
|
||||
|
||||
void godot_register_object_icalls();
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
#endif // BASE_OBJECT_GLUE_H
|
|
@ -30,9 +30,12 @@
|
|||
|
||||
#include "collections_glue.h"
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include <mono/metadata/exception.h>
|
||||
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
#include "../mono_gd/gd_mono_utils.h"
|
||||
|
||||
Array *godot_icall_Array_Ctor() {
|
||||
return memnew(Array);
|
||||
|
@ -238,3 +241,5 @@ void godot_register_collections_icalls() {
|
|||
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove);
|
||||
mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue);
|
||||
}
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#ifndef COLLECTIONS_GLUE_H
|
||||
#define COLLECTIONS_GLUE_H
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/array.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
@ -97,4 +99,6 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb
|
|||
|
||||
void godot_register_collections_icalls();
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
#endif // COLLECTIONS_GLUE_H
|
||||
|
|
|
@ -30,45 +30,6 @@ namespace Godot.Collections
|
|||
|
||||
public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Array_Ctor();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Array_Count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
|
||||
|
||||
ArraySafeHandle safeHandle;
|
||||
bool disposed = false;
|
||||
|
||||
|
@ -93,11 +54,6 @@ namespace Godot.Collections
|
|||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
@ -200,6 +156,45 @@ namespace Godot.Collections
|
|||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Array_Ctor();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Array_Count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Add(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
|
||||
}
|
||||
|
||||
public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
|
||||
|
|
|
@ -34,48 +34,6 @@ namespace Godot.Collections
|
|||
IEnumerable<KeyValuePair<object, object>>,
|
||||
IDisposable
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Dictionary_Ctor();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
|
||||
|
||||
DictionarySafeHandle safeHandle;
|
||||
bool disposed = false;
|
||||
|
||||
|
@ -100,11 +58,6 @@ namespace Godot.Collections
|
|||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
@ -240,8 +193,49 @@ namespace Godot.Collections
|
|||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Dictionary_Ctor();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
|
||||
}
|
||||
|
||||
public class Dictionary<TKey, TValue> :
|
||||
IDictionary<TKey, TValue>,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
|
@ -11,7 +12,10 @@ namespace Godot
|
|||
|
||||
public static WeakRef WeakRef(Object obj)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj));
|
||||
return godot_icall_Object_weakref(Object.GetPtr(obj));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static WeakRef godot_icall_Object_weakref(IntPtr obj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
#if REAL_T_IS_DOUBLE
|
||||
using real_t = System.Double;
|
||||
#else
|
||||
using real_t = System.Single;
|
||||
#endif
|
||||
|
||||
// TODO: Add comments describing what this class does. It is not obvious.
|
||||
// TODO: Add comments describing what this class does. It is not obvious.
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
|
@ -13,12 +14,12 @@ namespace Godot
|
|||
{
|
||||
public static object Bytes2Var(byte[] bytes)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_bytes2var(bytes);
|
||||
return godot_icall_GD_bytes2var(bytes);
|
||||
}
|
||||
|
||||
public static object Convert(object what, int type)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_convert(what, type);
|
||||
return godot_icall_GD_convert(what, type);
|
||||
}
|
||||
|
||||
public static real_t Db2Linear(real_t db)
|
||||
|
@ -46,12 +47,12 @@ namespace Godot
|
|||
|
||||
public static int Hash(object var)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_hash(var);
|
||||
return godot_icall_GD_hash(var);
|
||||
}
|
||||
|
||||
public static Object InstanceFromId(int instanceId)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_instance_from_id(instanceId);
|
||||
return godot_icall_GD_instance_from_id(instanceId);
|
||||
}
|
||||
|
||||
public static real_t Linear2Db(real_t linear)
|
||||
|
@ -71,7 +72,7 @@ namespace Godot
|
|||
|
||||
public static void Print(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_print(what);
|
||||
godot_icall_GD_print(what);
|
||||
}
|
||||
|
||||
public static void PrintStack()
|
||||
|
@ -81,22 +82,22 @@ namespace Godot
|
|||
|
||||
public static void PrintErr(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_printerr(what);
|
||||
godot_icall_GD_printerr(what);
|
||||
}
|
||||
|
||||
public static void PrintRaw(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_printraw(what);
|
||||
godot_icall_GD_printraw(what);
|
||||
}
|
||||
|
||||
public static void PrintS(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_prints(what);
|
||||
godot_icall_GD_prints(what);
|
||||
}
|
||||
|
||||
public static void PrintT(params object[] what)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_printt(what);
|
||||
godot_icall_GD_printt(what);
|
||||
}
|
||||
|
||||
public static int[] Range(int length)
|
||||
|
@ -165,32 +166,77 @@ namespace Godot
|
|||
|
||||
public static void Seed(int seed)
|
||||
{
|
||||
NativeCalls.godot_icall_Godot_seed(seed);
|
||||
godot_icall_GD_seed(seed);
|
||||
}
|
||||
|
||||
public static string Str(params object[] what)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_str(what);
|
||||
return godot_icall_GD_str(what);
|
||||
}
|
||||
|
||||
public static object Str2Var(string str)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_str2var(str);
|
||||
return godot_icall_GD_str2var(str);
|
||||
}
|
||||
|
||||
public static bool TypeExists(string type)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_type_exists(type);
|
||||
return godot_icall_GD_type_exists(type);
|
||||
}
|
||||
|
||||
public static byte[] Var2Bytes(object var)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_var2bytes(var);
|
||||
return godot_icall_GD_var2bytes(var);
|
||||
}
|
||||
|
||||
public static string Var2Str(object var)
|
||||
{
|
||||
return NativeCalls.godot_icall_Godot_var2str(var);
|
||||
return godot_icall_GD_var2str(var);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_GD_bytes2var(byte[] bytes);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_GD_convert(object what, int type);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_GD_hash(object var);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static Object godot_icall_GD_instance_from_id(int instance_id);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_GD_print(object[] what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_GD_printerr(object[] what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_GD_printraw(object[] what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_GD_prints(object[] what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_GD_printt(object[] what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_GD_seed(int seed);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_GD_str(object[] what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static object godot_icall_GD_str2var(string str);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_GD_type_exists(string type);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static byte[] godot_icall_GD_var2bytes(object what);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_GD_var2str(object var);
|
||||
}
|
||||
}
|
||||
|
|
147
modules/mono/glue/cs_files/NodePath.cs
Normal file
147
modules/mono/glue/cs_files/NodePath.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public partial class NodePath : IDisposable
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
internal IntPtr ptr;
|
||||
|
||||
internal static IntPtr GetPtr(NodePath instance)
|
||||
{
|
||||
return instance == null ? IntPtr.Zero : instance.ptr;
|
||||
}
|
||||
|
||||
~NodePath()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
godot_icall_NodePath_Dtor(ptr);
|
||||
ptr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
internal NodePath(IntPtr ptr)
|
||||
{
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public IntPtr NativeInstance
|
||||
{
|
||||
get { return ptr; }
|
||||
}
|
||||
|
||||
public NodePath() : this(string.Empty) {}
|
||||
|
||||
public NodePath(string path)
|
||||
{
|
||||
this.ptr = godot_icall_NodePath_Ctor(path);
|
||||
}
|
||||
|
||||
public static implicit operator NodePath(string from)
|
||||
{
|
||||
return new NodePath(from);
|
||||
}
|
||||
|
||||
public static implicit operator string(NodePath from)
|
||||
{
|
||||
return godot_icall_NodePath_operator_String(NodePath.GetPtr(from));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return (string)this;
|
||||
}
|
||||
|
||||
public NodePath GetAsPropertyPath()
|
||||
{
|
||||
return new NodePath(godot_icall_NodePath_get_as_property_path(NodePath.GetPtr(this)));
|
||||
}
|
||||
|
||||
public string GetConcatenatedSubnames()
|
||||
{
|
||||
return godot_icall_NodePath_get_concatenated_subnames(NodePath.GetPtr(this));
|
||||
}
|
||||
|
||||
public string GetName(int idx)
|
||||
{
|
||||
return godot_icall_NodePath_get_name(NodePath.GetPtr(this), idx);
|
||||
}
|
||||
|
||||
public int GetNameCount()
|
||||
{
|
||||
return godot_icall_NodePath_get_name_count(NodePath.GetPtr(this));
|
||||
}
|
||||
|
||||
public string GetSubname(int idx)
|
||||
{
|
||||
return godot_icall_NodePath_get_subname(NodePath.GetPtr(this), idx);
|
||||
}
|
||||
|
||||
public int GetSubnameCount()
|
||||
{
|
||||
return godot_icall_NodePath_get_subname_count(NodePath.GetPtr(this));
|
||||
}
|
||||
|
||||
public bool IsAbsolute()
|
||||
{
|
||||
return godot_icall_NodePath_is_absolute(NodePath.GetPtr(this));
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return godot_icall_NodePath_is_empty(NodePath.GetPtr(this));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_NodePath_Ctor(string path);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_NodePath_Dtor(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_NodePath_operator_String(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_NodePath_get_name_count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_NodePath_get_subname_count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_NodePath_is_absolute(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static bool godot_icall_NodePath_is_empty(IntPtr ptr);
|
||||
}
|
||||
}
|
88
modules/mono/glue/cs_files/Object.base.cs
Normal file
88
modules/mono/glue/cs_files/Object.base.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public partial class Object : IDisposable
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
private const string nativeName = "Object";
|
||||
|
||||
internal IntPtr ptr;
|
||||
internal bool memoryOwn;
|
||||
|
||||
public Object() : this(false)
|
||||
{
|
||||
if (ptr == IntPtr.Zero)
|
||||
ptr = godot_icall_Object_Ctor(this);
|
||||
}
|
||||
|
||||
internal Object(bool memoryOwn)
|
||||
{
|
||||
this.memoryOwn = memoryOwn;
|
||||
}
|
||||
|
||||
public IntPtr NativeInstance
|
||||
{
|
||||
get { return ptr; }
|
||||
}
|
||||
|
||||
internal static IntPtr GetPtr(Object instance)
|
||||
{
|
||||
return instance == null ? IntPtr.Zero : instance.ptr;
|
||||
}
|
||||
|
||||
~Object()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
if (memoryOwn)
|
||||
{
|
||||
memoryOwn = false;
|
||||
godot_icall_Reference_Disposed(this, ptr, !disposing);
|
||||
}
|
||||
else
|
||||
{
|
||||
godot_icall_Object_Disposed(this, ptr);
|
||||
}
|
||||
|
||||
this.ptr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public SignalAwaiter ToSignal(Object source, string signal)
|
||||
{
|
||||
return new SignalAwaiter(source, signal, this);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Object_Ctor(Object obj);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
|
||||
|
||||
// Used by the generated API
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_Object_ClassDB_get_method(string type, string method);
|
||||
}
|
||||
}
|
76
modules/mono/glue/cs_files/RID.cs
Normal file
76
modules/mono/glue/cs_files/RID.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public partial class RID : IDisposable
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
internal IntPtr ptr;
|
||||
|
||||
internal static IntPtr GetPtr(RID instance)
|
||||
{
|
||||
return instance == null ? IntPtr.Zero : instance.ptr;
|
||||
}
|
||||
|
||||
~RID()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
godot_icall_RID_Dtor(ptr);
|
||||
ptr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
internal RID(IntPtr ptr)
|
||||
{
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
public IntPtr NativeInstance
|
||||
{
|
||||
get { return ptr; }
|
||||
}
|
||||
|
||||
internal RID()
|
||||
{
|
||||
this.ptr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public RID(Object from)
|
||||
{
|
||||
this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from));
|
||||
}
|
||||
|
||||
public int GetId()
|
||||
{
|
||||
return godot_icall_RID_get_id(RID.GetPtr(this));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static IntPtr godot_icall_RID_Ctor(IntPtr from);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_RID_Dtor(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_RID_get_id(IntPtr ptr);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
|
@ -10,12 +11,12 @@ namespace Godot
|
|||
|
||||
public SignalAwaiter(Object source, string signal, Object target)
|
||||
{
|
||||
NativeCalls.godot_icall_Object_connect_signal_awaiter(
|
||||
Object.GetPtr(source),
|
||||
signal, Object.GetPtr(target), this
|
||||
);
|
||||
godot_icall_SignalAwaiter_connect(Object.GetPtr(source), signal, Object.GetPtr(target), this);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static Error godot_icall_SignalAwaiter_connect(IntPtr source, string signal, IntPtr target, SignalAwaiter awaiter);
|
||||
|
||||
public bool IsCompleted
|
||||
{
|
||||
get
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
@ -609,17 +610,23 @@ namespace Godot
|
|||
// </summary>
|
||||
public static byte[] MD5Buffer(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_md5_buffer(instance);
|
||||
return godot_icall_String_md5_buffer(instance);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static byte[] godot_icall_String_md5_buffer(string str);
|
||||
|
||||
// <summary>
|
||||
// Return the MD5 hash of the string as a string.
|
||||
// </summary>
|
||||
public static string MD5Text(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_md5_text(instance);
|
||||
return godot_icall_String_md5_text(instance);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_String_md5_text(string str);
|
||||
|
||||
// <summary>
|
||||
// Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
|
||||
// </summary>
|
||||
|
@ -752,17 +759,23 @@ namespace Godot
|
|||
// </summary>
|
||||
public static int RFind(this string instance, string what, int from = -1)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_rfind(instance, what, from);
|
||||
return godot_icall_String_rfind(instance, what, from);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_String_rfind(string str, string what, int from);
|
||||
|
||||
// <summary>
|
||||
// Perform a search for a substring, but start from the end of the string instead of the beginning. Also search case-insensitive.
|
||||
// </summary>
|
||||
public static int RFindN(this string instance, string what, int from = -1)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_rfindn(instance, what, from);
|
||||
return godot_icall_String_rfindn(instance, what, from);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_String_rfindn(string str, string what, int from);
|
||||
|
||||
// <summary>
|
||||
// Return the right side of the string from a given position.
|
||||
// </summary>
|
||||
|
@ -779,17 +792,23 @@ namespace Godot
|
|||
|
||||
public static byte[] SHA256Buffer(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_sha256_buffer(instance);
|
||||
return godot_icall_String_sha256_buffer(instance);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static byte[] godot_icall_String_sha256_buffer(string str);
|
||||
|
||||
// <summary>
|
||||
// Return the SHA-256 hash of the string as a string.
|
||||
// </summary>
|
||||
public static string SHA256Text(this string instance)
|
||||
{
|
||||
return NativeCalls.godot_icall_String_sha256_text(instance);
|
||||
return godot_icall_String_sha256_text(instance);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static string godot_icall_String_sha256_text(string str);
|
||||
|
||||
// <summary>
|
||||
// Return the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar.
|
||||
// </summary>
|
||||
|
|
202
modules/mono/glue/gd_glue.cpp
Normal file
202
modules/mono/glue/gd_glue.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*************************************************************************/
|
||||
/* gd_glue.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "gd_glue.h"
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/array.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/ustring.h"
|
||||
#include "core/variant.h"
|
||||
#include "core/variant_parser.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_utils.h"
|
||||
|
||||
MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes) {
|
||||
Variant ret;
|
||||
PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
|
||||
PoolByteArray::Read r = varr.read();
|
||||
Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
|
||||
if (err != OK) {
|
||||
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
|
||||
}
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_GD_convert(MonoObject *p_what, int p_type) {
|
||||
Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
|
||||
const Variant *args[1] = { &what };
|
||||
Variant::CallError ce;
|
||||
Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Variant::CallError::CALL_OK, NULL);
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
int godot_icall_GD_hash(MonoObject *p_var) {
|
||||
return GDMonoMarshal::mono_object_to_variant(p_var).hash();
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_GD_instance_from_id(int p_instance_id) {
|
||||
return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id));
|
||||
}
|
||||
|
||||
void godot_icall_GD_print(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_GD_printerr(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
OS::get_singleton()->printerr("%s\n", str.utf8().get_data());
|
||||
}
|
||||
|
||||
void godot_icall_GD_printraw(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
OS::get_singleton()->print("%s", str.utf8().get_data());
|
||||
}
|
||||
|
||||
void godot_icall_GD_prints(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
if (i)
|
||||
str += " ";
|
||||
str += what[i].operator String();
|
||||
}
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_GD_printt(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
if (i)
|
||||
str += "\t";
|
||||
str += what[i].operator String();
|
||||
}
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_GD_seed(int p_seed) {
|
||||
Math::seed(p_seed);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_GD_str(MonoArray *p_what) {
|
||||
String str;
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
String os = what[i].operator String();
|
||||
|
||||
if (i == 0)
|
||||
str = os;
|
||||
else
|
||||
str += os;
|
||||
}
|
||||
|
||||
return GDMonoMarshal::mono_string_from_godot(str);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
|
||||
Variant ret;
|
||||
|
||||
VariantParser::StreamString ss;
|
||||
ss.s = GDMonoMarshal::mono_string_to_godot(p_str);
|
||||
|
||||
String errs;
|
||||
int line;
|
||||
Error err = VariantParser::parse(&ss, ret, errs, line);
|
||||
if (err != OK) {
|
||||
String err_str = "Parse error at line " + itos(line) + ": " + errs;
|
||||
ERR_PRINTS(err_str);
|
||||
ret = err_str;
|
||||
}
|
||||
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
bool godot_icall_GD_type_exists(MonoString *p_type) {
|
||||
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) {
|
||||
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
|
||||
|
||||
PoolByteArray barr;
|
||||
int len;
|
||||
Error err = encode_variant(var, NULL, len);
|
||||
ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
|
||||
ERR_FAIL_COND_V(err != OK, NULL);
|
||||
|
||||
barr.resize(len);
|
||||
{
|
||||
PoolByteArray::Write w = barr.write();
|
||||
encode_variant(var, w.ptr(), len);
|
||||
}
|
||||
|
||||
return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_GD_var2str(MonoObject *p_var) {
|
||||
String vars;
|
||||
VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars);
|
||||
return GDMonoMarshal::mono_string_from_godot(vars);
|
||||
}
|
||||
|
||||
void godot_register_gd_icalls() {
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_bytes2var", (void *)godot_icall_GD_bytes2var);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_prints", (void *)godot_icall_GD_prints);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_printt", (void *)godot_icall_GD_printt);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_seed", (void *)godot_icall_GD_seed);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_str", (void *)godot_icall_GD_str);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_str2var", (void *)godot_icall_GD_str2var);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_type_exists", (void *)godot_icall_GD_type_exists);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_var2bytes", (void *)godot_icall_GD_var2bytes);
|
||||
mono_add_internal_call("Godot.GD::godot_icall_GD_var2str", (void *)godot_icall_GD_var2str);
|
||||
}
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
74
modules/mono/glue/gd_glue.h
Normal file
74
modules/mono/glue/gd_glue.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*************************************************************************/
|
||||
/* gd_glue.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GD_GLUE_H
|
||||
#define GD_GLUE_H
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
||||
MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes);
|
||||
|
||||
MonoObject *godot_icall_GD_convert(MonoObject *p_what, int p_type);
|
||||
|
||||
int godot_icall_GD_hash(MonoObject *p_var);
|
||||
|
||||
MonoObject *godot_icall_GD_instance_from_id(int p_instance_id);
|
||||
|
||||
void godot_icall_GD_print(MonoArray *p_what);
|
||||
|
||||
void godot_icall_GD_printerr(MonoArray *p_what);
|
||||
|
||||
void godot_icall_GD_printraw(MonoArray *p_what);
|
||||
|
||||
void godot_icall_GD_prints(MonoArray *p_what);
|
||||
|
||||
void godot_icall_GD_printt(MonoArray *p_what);
|
||||
|
||||
void godot_icall_GD_seed(int p_seed);
|
||||
|
||||
MonoString *godot_icall_GD_str(MonoArray *p_what);
|
||||
|
||||
MonoObject *godot_icall_GD_str2var(MonoString *p_str);
|
||||
|
||||
bool godot_icall_GD_type_exists(MonoString *p_type);
|
||||
|
||||
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var);
|
||||
|
||||
MonoString *godot_icall_GD_var2str(MonoObject *p_var);
|
||||
|
||||
// Register internal calls
|
||||
|
||||
void godot_register_gd_icalls();
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
#endif // GD_GLUE_H
|
|
@ -28,27 +28,44 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "builtin_types_glue.h"
|
||||
#include "collections_glue.h"
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "base_object_glue.h"
|
||||
#include "collections_glue.h"
|
||||
#include "gd_glue.h"
|
||||
#include "nodepath_glue.h"
|
||||
#include "rid_glue.h"
|
||||
#include "string_glue.h"
|
||||
|
||||
/**
|
||||
* Registers internal calls that were not generated. This function is called
|
||||
* from the generated GodotSharpBindings::register_generated_icalls() function.
|
||||
*/
|
||||
void godot_register_glue_header_icalls() {
|
||||
godot_register_collections_icalls();
|
||||
godot_register_gd_icalls();
|
||||
godot_register_nodepath_icalls();
|
||||
godot_register_object_icalls();
|
||||
godot_register_rid_icalls();
|
||||
godot_register_string_icalls();
|
||||
}
|
||||
|
||||
// Used by the generated glue
|
||||
|
||||
#include "core/array.h"
|
||||
#include "core/class_db.h"
|
||||
#include "core/dictionary.h"
|
||||
#include "core/engine.h"
|
||||
#include "core/method_bind.h"
|
||||
#include "core/node_path.h"
|
||||
#include "core/object.h"
|
||||
#include "core/reference.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../mono_gd/gd_mono_class.h"
|
||||
#include "../mono_gd/gd_mono_internals.h"
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
#include "../signal_awaiter_utils.h"
|
||||
|
||||
#include "bind/core_bind.h"
|
||||
#include "class_db.h"
|
||||
#include "engine.h"
|
||||
#include "io/marshalls.h"
|
||||
#include "object.h"
|
||||
#include "os/os.h"
|
||||
#include "reference.h"
|
||||
#include "variant_parser.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/editor_node.h"
|
||||
#endif
|
||||
#include "../mono_gd/gd_mono_utils.h"
|
||||
|
||||
#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \
|
||||
static ClassDB::ClassInfo *ci = NULL; \
|
||||
|
@ -57,257 +74,4 @@
|
|||
} \
|
||||
Object *m_instance = ci->creation_func();
|
||||
|
||||
void godot_icall_Object_Dtor(MonoObject *obj, Object *ptr) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(ptr == NULL);
|
||||
#endif
|
||||
_GodotSharp::get_singleton()->queue_dispose(obj, ptr);
|
||||
}
|
||||
|
||||
// -- ClassDB --
|
||||
|
||||
MethodBind *godot_icall_ClassDB_get_method(MonoString *p_type, MonoString *p_method) {
|
||||
StringName type(GDMonoMarshal::mono_string_to_godot(p_type));
|
||||
StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
|
||||
return ClassDB::get_method(type, method);
|
||||
}
|
||||
|
||||
// -- SignalAwaiter --
|
||||
|
||||
Error godot_icall_Object_connect_signal_awaiter(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) {
|
||||
String signal = GDMonoMarshal::mono_string_to_godot(p_signal);
|
||||
return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
|
||||
}
|
||||
|
||||
// -- NodePath --
|
||||
|
||||
NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
|
||||
return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path)));
|
||||
}
|
||||
|
||||
void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
|
||||
ERR_FAIL_NULL(p_ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(p_ptr);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
|
||||
return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
|
||||
}
|
||||
|
||||
// -- RID --
|
||||
|
||||
RID *godot_icall_RID_Ctor(Object *p_from) {
|
||||
Resource *res_from = Object::cast_to<Resource>(p_from);
|
||||
|
||||
if (res_from)
|
||||
return memnew(RID(res_from->get_rid()));
|
||||
|
||||
return memnew(RID);
|
||||
}
|
||||
|
||||
void godot_icall_RID_Dtor(RID *p_ptr) {
|
||||
ERR_FAIL_NULL(p_ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(p_ptr);
|
||||
}
|
||||
|
||||
// -- String --
|
||||
|
||||
MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
|
||||
Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
|
||||
// TODO Check possible Array/Vector<uint8_t> problem?
|
||||
return GDMonoMarshal::Array_to_mono_array(Variant(ret));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_String_md5_text(MonoString *p_str) {
|
||||
String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text();
|
||||
return GDMonoMarshal::mono_string_from_godot(ret);
|
||||
}
|
||||
|
||||
int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from) {
|
||||
String what = GDMonoMarshal::mono_string_to_godot(p_what);
|
||||
return GDMonoMarshal::mono_string_to_godot(p_str).rfind(what, p_from);
|
||||
}
|
||||
|
||||
int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from) {
|
||||
String what = GDMonoMarshal::mono_string_to_godot(p_what);
|
||||
return GDMonoMarshal::mono_string_to_godot(p_str).rfindn(what, p_from);
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str) {
|
||||
Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_buffer();
|
||||
return GDMonoMarshal::Array_to_mono_array(Variant(ret));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
|
||||
String ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_text();
|
||||
return GDMonoMarshal::mono_string_from_godot(ret);
|
||||
}
|
||||
|
||||
// -- Global Scope --
|
||||
|
||||
MonoObject *godot_icall_Godot_bytes2var(MonoArray *p_bytes) {
|
||||
Variant ret;
|
||||
PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
|
||||
PoolByteArray::Read r = varr.read();
|
||||
Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
|
||||
if (err != OK) {
|
||||
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
|
||||
}
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_convert(MonoObject *p_what, int p_type) {
|
||||
Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
|
||||
const Variant *args[1] = { &what };
|
||||
Variant::CallError ce;
|
||||
Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Variant::CallError::CALL_OK, NULL);
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
int godot_icall_Godot_hash(MonoObject *p_var) {
|
||||
return GDMonoMarshal::mono_object_to_variant(p_var).hash();
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_instance_from_id(int p_instance_id) {
|
||||
return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id));
|
||||
}
|
||||
|
||||
void godot_icall_Godot_print(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_Godot_printerr(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
OS::get_singleton()->printerr("%s\n", str.utf8().get_data());
|
||||
}
|
||||
|
||||
void godot_icall_Godot_printraw(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++)
|
||||
str += what[i].operator String();
|
||||
OS::get_singleton()->print("%s", str.utf8().get_data());
|
||||
}
|
||||
|
||||
void godot_icall_Godot_prints(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
if (i)
|
||||
str += " ";
|
||||
str += what[i].operator String();
|
||||
}
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_Godot_printt(MonoArray *p_what) {
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
String str;
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
if (i)
|
||||
str += "\t";
|
||||
str += what[i].operator String();
|
||||
}
|
||||
print_line(str);
|
||||
}
|
||||
|
||||
void godot_icall_Godot_seed(int p_seed) {
|
||||
Math::seed(p_seed);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Godot_str(MonoArray *p_what) {
|
||||
String str;
|
||||
Array what = GDMonoMarshal::mono_array_to_Array(p_what);
|
||||
|
||||
for (int i = 0; i < what.size(); i++) {
|
||||
String os = what[i].operator String();
|
||||
|
||||
if (i == 0)
|
||||
str = os;
|
||||
else
|
||||
str += os;
|
||||
}
|
||||
|
||||
return GDMonoMarshal::mono_string_from_godot(str);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_str2var(MonoString *p_str) {
|
||||
Variant ret;
|
||||
|
||||
VariantParser::StreamString ss;
|
||||
ss.s = GDMonoMarshal::mono_string_to_godot(p_str);
|
||||
|
||||
String errs;
|
||||
int line;
|
||||
Error err = VariantParser::parse(&ss, ret, errs, line);
|
||||
if (err != OK) {
|
||||
String err_str = "Parse error at line " + itos(line) + ": " + errs;
|
||||
ERR_PRINTS(err_str);
|
||||
ret = err_str;
|
||||
}
|
||||
|
||||
return GDMonoMarshal::variant_to_mono_object(ret);
|
||||
}
|
||||
|
||||
bool godot_icall_Godot_type_exists(MonoString *p_type) {
|
||||
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_Godot_var2bytes(MonoObject *p_var) {
|
||||
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
|
||||
|
||||
PoolByteArray barr;
|
||||
int len;
|
||||
Error err = encode_variant(var, NULL, len);
|
||||
ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
|
||||
ERR_FAIL_COND_V(err != OK, NULL);
|
||||
|
||||
barr.resize(len);
|
||||
{
|
||||
PoolByteArray::Write w = barr.write();
|
||||
encode_variant(var, w.ptr(), len);
|
||||
}
|
||||
|
||||
return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_Godot_var2str(MonoObject *p_var) {
|
||||
String vars;
|
||||
VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars);
|
||||
return GDMonoMarshal::mono_string_from_godot(vars);
|
||||
}
|
||||
|
||||
MonoObject *godot_icall_Godot_weakref(Object *p_obj) {
|
||||
if (!p_obj)
|
||||
return NULL;
|
||||
|
||||
Ref<WeakRef> wref;
|
||||
Reference *ref = Object::cast_to<Reference>(p_obj);
|
||||
|
||||
if (ref) {
|
||||
REF r = ref;
|
||||
if (!r.is_valid())
|
||||
return NULL;
|
||||
|
||||
wref.instance();
|
||||
wref->set_ref(r);
|
||||
} else {
|
||||
wref.instance();
|
||||
wref->set_obj(p_obj);
|
||||
}
|
||||
|
||||
return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr()));
|
||||
}
|
||||
|
||||
void godot_register_header_icalls() {
|
||||
godot_register_builtin_type_icalls();
|
||||
godot_register_collections_icalls();
|
||||
}
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*************************************************************************/
|
||||
/* builtin_types_glue.h */
|
||||
/* nodepath_glue.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,15 +28,24 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef BUILTIN_TYPES_GLUE_H
|
||||
#define BUILTIN_TYPES_GLUE_H
|
||||
#include "nodepath_glue.h"
|
||||
|
||||
#include "core/node_path.h"
|
||||
#include "core/rid.h"
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include <mono/metadata/object.h>
|
||||
#include "core/ustring.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
|
||||
return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path)));
|
||||
}
|
||||
|
||||
void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
|
||||
ERR_FAIL_NULL(p_ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(p_ptr);
|
||||
}
|
||||
|
||||
MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
|
||||
return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
|
||||
}
|
||||
|
||||
MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr) {
|
||||
return (MonoBoolean)p_ptr->is_absolute();
|
||||
|
@ -70,20 +79,18 @@ MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
|
|||
return (MonoBoolean)p_ptr->is_empty();
|
||||
}
|
||||
|
||||
uint32_t godot_icall_RID_get_id(RID *p_ptr) {
|
||||
return p_ptr->get_id();
|
||||
void godot_register_nodepath_icalls() {
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", (void *)godot_icall_NodePath_Ctor);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", (void *)godot_icall_NodePath_Dtor);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", (void *)godot_icall_NodePath_operator_String);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute);
|
||||
mono_add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty);
|
||||
}
|
||||
|
||||
void godot_register_builtin_type_icalls() {
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_as_property_path", (void *)godot_icall_NodePath_get_as_property_path);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_concatenated_subnames", (void *)godot_icall_NodePath_get_concatenated_subnames);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_name", (void *)godot_icall_NodePath_get_name);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_name_count", (void *)godot_icall_NodePath_get_name_count);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_subname", (void *)godot_icall_NodePath_get_subname);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_get_subname_count", (void *)godot_icall_NodePath_get_subname_count);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_is_absolute", (void *)godot_icall_NodePath_is_absolute);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_NodePath_is_empty", (void *)godot_icall_NodePath_is_empty);
|
||||
mono_add_internal_call("Godot.NativeCalls::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id);
|
||||
}
|
||||
|
||||
#endif // BUILTIN_TYPES_GLUE_H
|
||||
#endif // MONO_GLUE_ENABLED
|
68
modules/mono/glue/nodepath_glue.h
Normal file
68
modules/mono/glue/nodepath_glue.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*************************************************************************/
|
||||
/* nodepath_glue.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef NODEPATH_GLUE_H
|
||||
#define NODEPATH_GLUE_H
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/node_path.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
||||
NodePath *godot_icall_NodePath_Ctor(MonoString *p_path);
|
||||
|
||||
void godot_icall_NodePath_Dtor(NodePath *p_ptr);
|
||||
|
||||
MonoString *godot_icall_NodePath_operator_String(NodePath *p_np);
|
||||
|
||||
MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr);
|
||||
|
||||
uint32_t godot_icall_NodePath_get_name_count(NodePath *p_ptr);
|
||||
|
||||
MonoString *godot_icall_NodePath_get_name(NodePath *p_ptr, uint32_t p_idx);
|
||||
|
||||
uint32_t godot_icall_NodePath_get_subname_count(NodePath *p_ptr);
|
||||
|
||||
MonoString *godot_icall_NodePath_get_subname(NodePath *p_ptr, uint32_t p_idx);
|
||||
|
||||
MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr);
|
||||
|
||||
NodePath *godot_icall_NodePath_get_as_property_path(NodePath *p_ptr);
|
||||
|
||||
MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr);
|
||||
|
||||
// Register internal calls
|
||||
|
||||
void godot_register_nodepath_icalls();
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
#endif // NODEPATH_GLUE_H
|
61
modules/mono/glue/rid_glue.cpp
Normal file
61
modules/mono/glue/rid_glue.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*************************************************************************/
|
||||
/* rid_glue.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "rid_glue.h"
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/resource.h"
|
||||
|
||||
RID *godot_icall_RID_Ctor(Object *p_from) {
|
||||
Resource *res_from = Object::cast_to<Resource>(p_from);
|
||||
|
||||
if (res_from)
|
||||
return memnew(RID(res_from->get_rid()));
|
||||
|
||||
return memnew(RID);
|
||||
}
|
||||
|
||||
void godot_icall_RID_Dtor(RID *p_ptr) {
|
||||
ERR_FAIL_NULL(p_ptr);
|
||||
_GodotSharp::get_singleton()->queue_dispose(p_ptr);
|
||||
}
|
||||
|
||||
uint32_t godot_icall_RID_get_id(RID *p_ptr) {
|
||||
return p_ptr->get_id();
|
||||
}
|
||||
|
||||
void godot_register_rid_icalls() {
|
||||
mono_add_internal_call("Godot.RID::godot_icall_RID_Ctor", (void *)godot_icall_RID_Ctor);
|
||||
mono_add_internal_call("Godot.RID::godot_icall_RID_Dtor", (void *)godot_icall_RID_Dtor);
|
||||
mono_add_internal_call("Godot.RID::godot_icall_RID_get_id", (void *)godot_icall_RID_get_id);
|
||||
}
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
53
modules/mono/glue/rid_glue.h
Normal file
53
modules/mono/glue/rid_glue.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*************************************************************************/
|
||||
/* rid_glue.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef RID_GLUE_H
|
||||
#define RID_GLUE_H
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/object.h"
|
||||
#include "core/rid.h"
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
||||
RID *godot_icall_RID_Ctor(Object *p_from);
|
||||
|
||||
void godot_icall_RID_Dtor(RID *p_ptr);
|
||||
|
||||
uint32_t godot_icall_RID_get_id(RID *p_ptr);
|
||||
|
||||
// Register internal calls
|
||||
|
||||
void godot_register_rid_icalls();
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
#endif // RID_GLUE_H
|
79
modules/mono/glue/string_glue.cpp
Normal file
79
modules/mono/glue/string_glue.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*************************************************************************/
|
||||
/* string_glue.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "string_glue.h"
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "core/ustring.h"
|
||||
#include "core/variant.h"
|
||||
#include "core/vector.h"
|
||||
|
||||
MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
|
||||
Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
|
||||
// TODO Check possible Array/Vector<uint8_t> problem?
|
||||
return GDMonoMarshal::Array_to_mono_array(Variant(ret));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_String_md5_text(MonoString *p_str) {
|
||||
String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text();
|
||||
return GDMonoMarshal::mono_string_from_godot(ret);
|
||||
}
|
||||
|
||||
int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from) {
|
||||
String what = GDMonoMarshal::mono_string_to_godot(p_what);
|
||||
return GDMonoMarshal::mono_string_to_godot(p_str).rfind(what, p_from);
|
||||
}
|
||||
|
||||
int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from) {
|
||||
String what = GDMonoMarshal::mono_string_to_godot(p_what);
|
||||
return GDMonoMarshal::mono_string_to_godot(p_str).rfindn(what, p_from);
|
||||
}
|
||||
|
||||
MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str) {
|
||||
Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_buffer();
|
||||
return GDMonoMarshal::Array_to_mono_array(Variant(ret));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
|
||||
String ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_text();
|
||||
return GDMonoMarshal::mono_string_from_godot(ret);
|
||||
}
|
||||
|
||||
void godot_register_string_icalls() {
|
||||
mono_add_internal_call("Godot.String::godot_icall_String_md5_buffer", (void *)godot_icall_String_md5_buffer);
|
||||
mono_add_internal_call("Godot.String::godot_icall_String_md5_text", (void *)godot_icall_String_md5_text);
|
||||
mono_add_internal_call("Godot.String::godot_icall_String_rfind", (void *)godot_icall_String_rfind);
|
||||
mono_add_internal_call("Godot.String::godot_icall_String_rfindn", (void *)godot_icall_String_rfindn);
|
||||
mono_add_internal_call("Godot.String::godot_icall_String_sha256_buffer", (void *)godot_icall_String_sha256_buffer);
|
||||
mono_add_internal_call("Godot.String::godot_icall_String_sha256_text", (void *)godot_icall_String_sha256_text);
|
||||
}
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
56
modules/mono/glue/string_glue.h
Normal file
56
modules/mono/glue/string_glue.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*************************************************************************/
|
||||
/* string_glue.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef STRING_GLUE_H
|
||||
#define STRING_GLUE_H
|
||||
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
|
||||
#include "../mono_gd/gd_mono_marshal.h"
|
||||
|
||||
MonoArray *godot_icall_String_md5_buffer(MonoString *p_str);
|
||||
|
||||
MonoString *godot_icall_String_md5_text(MonoString *p_str);
|
||||
|
||||
int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from);
|
||||
|
||||
int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from);
|
||||
|
||||
MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str);
|
||||
|
||||
MonoString *godot_icall_String_sha256_text(MonoString *p_str);
|
||||
|
||||
// Register internal calls
|
||||
|
||||
void godot_register_string_icalls();
|
||||
|
||||
#endif // MONO_GLUE_ENABLED
|
||||
|
||||
#endif // STRING_GLUE_H
|
|
@ -32,24 +32,34 @@
|
|||
|
||||
#include "mono_gd/gd_mono.h"
|
||||
|
||||
uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
|
||||
uint32_t MonoGCHandle::new_strong_handle(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new(p_object, /* pinned: */ false);
|
||||
}
|
||||
|
||||
uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
|
||||
uint32_t MonoGCHandle::new_strong_handle_pinned(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new(p_object, /* pinned: */ true);
|
||||
}
|
||||
|
||||
uint32_t MonoGCHandle::new_weak_handle(MonoObject *p_object) {
|
||||
|
||||
return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false);
|
||||
}
|
||||
|
||||
void MonoGCHandle::free_handle(uint32_t p_gchandle) {
|
||||
|
||||
mono_gchandle_free(p_gchandle);
|
||||
}
|
||||
|
||||
Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
|
||||
|
||||
return memnew(MonoGCHandle(make_strong_handle(p_object), STRONG_HANDLE));
|
||||
return memnew(MonoGCHandle(new_strong_handle(p_object), STRONG_HANDLE));
|
||||
}
|
||||
|
||||
Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
|
||||
|
||||
return memnew(MonoGCHandle(make_weak_handle(p_object), WEAK_HANDLE));
|
||||
return memnew(MonoGCHandle(new_weak_handle(p_object), WEAK_HANDLE));
|
||||
}
|
||||
|
||||
void MonoGCHandle::release() {
|
||||
|
@ -59,7 +69,7 @@ void MonoGCHandle::release() {
|
|||
#endif
|
||||
|
||||
if (!released && GDMono::get_singleton()->is_runtime_initialized()) {
|
||||
mono_gchandle_free(handle);
|
||||
free_handle(handle);
|
||||
released = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,12 +49,15 @@ public:
|
|||
WEAK_HANDLE
|
||||
};
|
||||
|
||||
static uint32_t make_strong_handle(MonoObject *p_object);
|
||||
static uint32_t make_weak_handle(MonoObject *p_object);
|
||||
static uint32_t new_strong_handle(MonoObject *p_object);
|
||||
static uint32_t new_strong_handle_pinned(MonoObject *p_object);
|
||||
static uint32_t new_weak_handle(MonoObject *p_object);
|
||||
static void free_handle(uint32_t p_gchandle);
|
||||
|
||||
static Ref<MonoGCHandle> create_strong(MonoObject *p_object);
|
||||
static Ref<MonoGCHandle> create_weak(MonoObject *p_object);
|
||||
|
||||
_FORCE_INLINE_ bool is_released() { return released; }
|
||||
_FORCE_INLINE_ bool is_weak() { return weak; }
|
||||
|
||||
_FORCE_INLINE_ MonoObject *get_target() const { return released ? NULL : mono_gchandle_get_target(handle); }
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "project_settings.h"
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../glue/cs_glue_version.gen.h"
|
||||
#include "../godotsharp_dirs.h"
|
||||
#include "../utils/path_utils.h"
|
||||
#include "gd_mono_class.h"
|
||||
|
@ -177,6 +178,30 @@ void GDMono::initialize() {
|
|||
|
||||
mono_set_dirs(assembly_dir.length() ? assembly_dir.get_data() : NULL,
|
||||
config_dir.length() ? config_dir.get_data() : NULL);
|
||||
#elif OSX_ENABLED
|
||||
mono_set_dirs(NULL, NULL);
|
||||
|
||||
{
|
||||
const char *assembly_rootdir = mono_assembly_getrootdir();
|
||||
const char *config_dir = mono_get_config_dir();
|
||||
|
||||
if (!assembly_rootdir || !config_dir || !DirAccess::exists(assembly_rootdir) || !DirAccess::exists(config_dir)) {
|
||||
Vector<const char *> locations;
|
||||
locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/");
|
||||
locations.push_back("/usr/local/var/homebrew/linked/mono/");
|
||||
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
String hint_assembly_rootdir = path_join(locations[i], "lib");
|
||||
String hint_mscorlib_path = path_join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
|
||||
String hint_config_dir = path_join(locations[i], "etc");
|
||||
|
||||
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
|
||||
mono_set_dirs(hint_assembly_rootdir.utf8().get_data(), hint_config_dir.utf8().get_data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
mono_set_dirs(NULL, NULL);
|
||||
#endif
|
||||
|
@ -232,7 +257,7 @@ void GDMono::initialize() {
|
|||
_register_internal_calls();
|
||||
|
||||
// The following assemblies are not required at initialization
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
if (_load_api_assemblies()) {
|
||||
if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) {
|
||||
// Everything is fine with the api assemblies, load the project assembly
|
||||
|
@ -275,7 +300,7 @@ void GDMono::initialize() {
|
|||
print_verbose("Mono: INITIALIZED");
|
||||
}
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
namespace GodotSharpBindings {
|
||||
|
||||
uint64_t get_core_api_hash();
|
||||
|
@ -283,14 +308,13 @@ uint64_t get_core_api_hash();
|
|||
uint64_t get_editor_api_hash();
|
||||
#endif // TOOLS_ENABLED
|
||||
uint32_t get_bindings_version();
|
||||
uint32_t get_cs_glue_version();
|
||||
|
||||
void register_generated_icalls();
|
||||
} // namespace GodotSharpBindings
|
||||
#endif
|
||||
|
||||
void GDMono::_register_internal_calls() {
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
GodotSharpBindings::register_generated_icalls();
|
||||
#endif
|
||||
|
||||
|
@ -304,7 +328,7 @@ void GDMono::_initialize_and_check_api_hashes() {
|
|||
|
||||
api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
if (api_core_hash != GodotSharpBindings::get_core_api_hash()) {
|
||||
ERR_PRINT("Mono: Core API hash mismatch!");
|
||||
}
|
||||
|
@ -313,7 +337,7 @@ void GDMono::_initialize_and_check_api_hashes() {
|
|||
#ifdef TOOLS_ENABLED
|
||||
api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
if (api_editor_hash != GodotSharpBindings::get_editor_api_hash()) {
|
||||
ERR_PRINT("Mono: Editor API hash mismatch!");
|
||||
}
|
||||
|
@ -431,11 +455,11 @@ bool GDMono::_load_core_api_assembly() {
|
|||
bool success = load_assembly(API_ASSEMBLY_NAME, &core_api_assembly);
|
||||
|
||||
if (success) {
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE);
|
||||
core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash ||
|
||||
GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
|
||||
GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
|
||||
CS_GLUE_VERSION != api_assembly_ver.cs_glue_version;
|
||||
#endif
|
||||
GDMonoUtils::update_godot_api_cache();
|
||||
}
|
||||
|
@ -457,11 +481,11 @@ bool GDMono::_load_editor_api_assembly() {
|
|||
bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
|
||||
|
||||
if (success) {
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR);
|
||||
editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
|
||||
GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
|
||||
GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
|
||||
CS_GLUE_VERSION != api_assembly_ver.cs_glue_version;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -615,9 +639,7 @@ Error GDMono::_unload_scripts_domain() {
|
|||
|
||||
mono_gc_collect(mono_gc_max_generation());
|
||||
|
||||
finalizing_scripts_domain = true;
|
||||
mono_domain_finalize(scripts_domain, 2000);
|
||||
finalizing_scripts_domain = false;
|
||||
|
||||
mono_gc_collect(mono_gc_max_generation());
|
||||
|
||||
|
@ -684,7 +706,7 @@ Error GDMono::reload_scripts_domain() {
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifndef MONO_GLUE_DISABLED
|
||||
#ifdef MONO_GLUE_ENABLED
|
||||
if (!_load_api_assemblies()) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
@ -698,13 +720,15 @@ Error GDMono::reload_scripts_domain() {
|
|||
// so we invalidate the version in the metadata and unload the script domain.
|
||||
|
||||
if (core_api_assembly_out_of_sync) {
|
||||
ERR_PRINT("The loaded Core API assembly is out of sync");
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
|
||||
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
|
||||
ERR_PRINT("Core API assembly is in sync, but the cache update failed");
|
||||
ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed");
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true);
|
||||
}
|
||||
|
||||
if (editor_api_assembly_out_of_sync) {
|
||||
ERR_PRINT("The loaded Editor API assembly is out of sync");
|
||||
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
|
||||
}
|
||||
|
||||
|
@ -813,7 +837,6 @@ GDMono::GDMono() {
|
|||
gdmono_log = memnew(GDMonoLog);
|
||||
|
||||
runtime_initialized = false;
|
||||
finalizing_scripts_domain = false;
|
||||
|
||||
root_domain = NULL;
|
||||
scripts_domain = NULL;
|
||||
|
@ -842,7 +865,7 @@ GDMono::GDMono() {
|
|||
|
||||
GDMono::~GDMono() {
|
||||
|
||||
if (runtime_initialized) {
|
||||
if (is_runtime_initialized()) {
|
||||
|
||||
if (scripts_domain) {
|
||||
|
||||
|
@ -867,8 +890,9 @@ GDMono::~GDMono() {
|
|||
|
||||
print_verbose("Mono: Runtime cleanup...");
|
||||
|
||||
runtime_initialized = false;
|
||||
mono_jit_cleanup(root_domain);
|
||||
|
||||
runtime_initialized = false;
|
||||
}
|
||||
|
||||
if (gdmono_log)
|
||||
|
@ -879,33 +903,12 @@ GDMono::~GDMono() {
|
|||
|
||||
_GodotSharp *_GodotSharp::singleton = NULL;
|
||||
|
||||
void _GodotSharp::_dispose_object(Object *p_object) {
|
||||
|
||||
if (p_object->get_script_instance()) {
|
||||
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
|
||||
if (cs_instance) {
|
||||
cs_instance->mono_object_disposed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe refcount decrement. The managed instance also counts as a reference.
|
||||
// See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
|
||||
if (Object::cast_to<Reference>(p_object)->unreference()) {
|
||||
memdelete(p_object);
|
||||
}
|
||||
}
|
||||
|
||||
void _GodotSharp::_dispose_callback() {
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->lock();
|
||||
#endif
|
||||
|
||||
for (List<Object *>::Element *E = obj_delete_queue.front(); E; E = E->next()) {
|
||||
_dispose_object(E->get());
|
||||
}
|
||||
|
||||
for (List<NodePath *>::Element *E = np_delete_queue.front(); E; E = E->next()) {
|
||||
memdelete(E->get());
|
||||
}
|
||||
|
@ -914,7 +917,6 @@ void _GodotSharp::_dispose_callback() {
|
|||
memdelete(E->get());
|
||||
}
|
||||
|
||||
obj_delete_queue.clear();
|
||||
np_delete_queue.clear();
|
||||
rid_delete_queue.clear();
|
||||
queue_empty = true;
|
||||
|
@ -934,52 +936,69 @@ void _GodotSharp::detach_thread() {
|
|||
GDMonoUtils::detach_current_thread();
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_finalizing_domain() {
|
||||
int32_t _GodotSharp::get_domain_id() {
|
||||
|
||||
return GDMono::get_singleton()->is_finalizing_scripts_domain();
|
||||
MonoDomain *domain = mono_domain_get();
|
||||
CRASH_COND(!domain); // User must check if runtime is initialized before calling this method
|
||||
return mono_domain_get_id(domain);
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_domain_loaded() {
|
||||
int32_t _GodotSharp::get_scripts_domain_id() {
|
||||
|
||||
return GDMono::get_singleton()->get_scripts_domain() != NULL;
|
||||
MonoDomain *domain = SCRIPTS_DOMAIN;
|
||||
CRASH_COND(!domain); // User must check if scripts domain is loaded before calling this method
|
||||
return mono_domain_get_id(domain);
|
||||
}
|
||||
|
||||
#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
|
||||
m_queue.push_back(m_inst); \
|
||||
if (queue_empty) { \
|
||||
queue_empty = false; \
|
||||
if (!is_finalizing_domain()) { /* call_deferred may not be safe here */ \
|
||||
call_deferred("_dispose_callback"); \
|
||||
} \
|
||||
bool _GodotSharp::is_scripts_domain_loaded() {
|
||||
|
||||
return GDMono::get_singleton()->is_runtime_initialized() && SCRIPTS_DOMAIN != NULL;
|
||||
}
|
||||
|
||||
bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
|
||||
|
||||
return is_domain_finalizing_for_unload(p_domain_id);
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_domain_finalizing_for_unload() {
|
||||
|
||||
return is_domain_finalizing_for_unload(mono_domain_get());
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
|
||||
|
||||
return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id));
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
|
||||
|
||||
if (!p_domain)
|
||||
return true;
|
||||
return mono_domain_is_unloading(p_domain);
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_runtime_shutting_down() {
|
||||
|
||||
return mono_runtime_is_shutting_down();
|
||||
}
|
||||
|
||||
bool _GodotSharp::is_runtime_initialized() {
|
||||
|
||||
return GDMono::get_singleton()->is_runtime_initialized();
|
||||
}
|
||||
|
||||
#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
|
||||
m_queue.push_back(m_inst); \
|
||||
if (queue_empty) { \
|
||||
queue_empty = false; \
|
||||
if (!is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) { /* call_deferred may not be safe here */ \
|
||||
call_deferred("_dispose_callback"); \
|
||||
} \
|
||||
}
|
||||
|
||||
void _GodotSharp::queue_dispose(MonoObject *p_mono_object, Object *p_object) {
|
||||
|
||||
if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
|
||||
_dispose_object(p_object);
|
||||
} else {
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->lock();
|
||||
#endif
|
||||
|
||||
// This is our last chance to invoke notification predelete (this is being called from the finalizer)
|
||||
// We must use the MonoObject* passed by the finalizer, because the weak GC handle target returns NULL at this point
|
||||
CSharpInstance *si = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
|
||||
if (si) {
|
||||
si->call_notification_no_check(p_mono_object, Object::NOTIFICATION_PREDELETE);
|
||||
}
|
||||
|
||||
ENQUEUE_FOR_DISPOSAL(obj_delete_queue, p_object);
|
||||
|
||||
#ifndef NO_THREADS
|
||||
queue_mutex->unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _GodotSharp::queue_dispose(NodePath *p_node_path) {
|
||||
|
||||
if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
|
||||
if (GDMonoUtils::is_main_thread() && !is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) {
|
||||
memdelete(p_node_path);
|
||||
} else {
|
||||
#ifndef NO_THREADS
|
||||
|
@ -996,7 +1015,7 @@ void _GodotSharp::queue_dispose(NodePath *p_node_path) {
|
|||
|
||||
void _GodotSharp::queue_dispose(RID *p_rid) {
|
||||
|
||||
if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
|
||||
if (GDMonoUtils::is_main_thread() && !is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) {
|
||||
memdelete(p_rid);
|
||||
} else {
|
||||
#ifndef NO_THREADS
|
||||
|
@ -1016,8 +1035,13 @@ void _GodotSharp::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
|
||||
ClassDB::bind_method(D_METHOD("detach_thread"), &_GodotSharp::detach_thread);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_finalizing_domain"), &_GodotSharp::is_finalizing_domain);
|
||||
ClassDB::bind_method(D_METHOD("is_domain_loaded"), &_GodotSharp::is_domain_loaded);
|
||||
ClassDB::bind_method(D_METHOD("get_domain_id"), &_GodotSharp::get_domain_id);
|
||||
ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &_GodotSharp::get_scripts_domain_id);
|
||||
ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &_GodotSharp::is_scripts_domain_loaded);
|
||||
ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &_GodotSharp::_is_domain_finalizing_for_unload);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &_GodotSharp::is_runtime_shutting_down);
|
||||
ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &_GodotSharp::is_runtime_initialized);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_dispose_callback"), &_GodotSharp::_dispose_callback);
|
||||
}
|
||||
|
|
|
@ -170,8 +170,7 @@ public:
|
|||
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
|
||||
GDMonoAssembly **get_loaded_assembly(const String &p_name);
|
||||
|
||||
_FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized; }
|
||||
_FORCE_INLINE_ bool is_finalizing_scripts_domain() const { return finalizing_scripts_domain; }
|
||||
_FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; }
|
||||
|
||||
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
@ -236,11 +235,10 @@ class _GodotSharp : public Object {
|
|||
|
||||
friend class GDMono;
|
||||
|
||||
void _dispose_object(Object *p_object);
|
||||
|
||||
void _dispose_callback();
|
||||
|
||||
List<Object *> obj_delete_queue;
|
||||
bool _is_domain_finalizing_for_unload(int32_t p_domain_id);
|
||||
|
||||
List<NodePath *> np_delete_queue;
|
||||
List<RID *> rid_delete_queue;
|
||||
|
||||
|
@ -260,10 +258,18 @@ public:
|
|||
void attach_thread();
|
||||
void detach_thread();
|
||||
|
||||
bool is_finalizing_domain();
|
||||
bool is_domain_loaded();
|
||||
int32_t get_domain_id();
|
||||
int32_t get_scripts_domain_id();
|
||||
|
||||
bool is_scripts_domain_loaded();
|
||||
|
||||
bool is_domain_finalizing_for_unload();
|
||||
bool is_domain_finalizing_for_unload(int32_t p_domain_id);
|
||||
bool is_domain_finalizing_for_unload(MonoDomain *p_domain);
|
||||
|
||||
bool is_runtime_shutting_down();
|
||||
bool is_runtime_initialized();
|
||||
|
||||
void queue_dispose(MonoObject *p_mono_object, Object *p_object);
|
||||
void queue_dispose(NodePath *p_node_path);
|
||||
void queue_dispose(RID *p_rid);
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ void MonoCache::clear_members() {
|
|||
field_Image_ptr = NULL;
|
||||
field_RID_ptr = NULL;
|
||||
|
||||
methodthunk_GodotObject_Dispose = NULL;
|
||||
methodthunk_Array_GetPtr = NULL;
|
||||
methodthunk_Dictionary_GetPtr = NULL;
|
||||
methodthunk_MarshalUtils_IsArrayGenericType = NULL;
|
||||
|
@ -235,6 +236,7 @@ void update_godot_api_cache() {
|
|||
CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
|
||||
CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
|
||||
|
||||
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0));
|
||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1));
|
||||
|
@ -247,7 +249,7 @@ void update_godot_api_cache() {
|
|||
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4));
|
||||
#endif
|
||||
|
||||
// TODO Move to CSharpLanguage::init()
|
||||
// TODO Move to CSharpLanguage::init() and do handle disposal
|
||||
MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
|
||||
GDMonoUtils::runtime_object_init(task_scheduler);
|
||||
mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
|
||||
|
@ -270,11 +272,48 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
|
|||
}
|
||||
}
|
||||
|
||||
// Only called if the owner does not have a CSharpInstance
|
||||
// If the owner does not have a CSharpInstance...
|
||||
|
||||
void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
|
||||
|
||||
if (data) {
|
||||
return ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->value()->get_target();
|
||||
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
|
||||
|
||||
Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
|
||||
ERR_FAIL_COND_V(gchandle.is_null(), NULL);
|
||||
|
||||
MonoObject *target = gchandle->get_target();
|
||||
|
||||
if (target)
|
||||
return target;
|
||||
|
||||
CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
|
||||
|
||||
// Create a new one
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
CRASH_COND(script_binding.type_name == StringName());
|
||||
CRASH_COND(script_binding.wrapper_class == NULL);
|
||||
#endif
|
||||
|
||||
MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
|
||||
ERR_FAIL_NULL_V(mono_object, NULL);
|
||||
|
||||
gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE);
|
||||
|
||||
// Tie managed to unmanaged
|
||||
Reference *ref = Object::cast_to<Reference>(unmanaged);
|
||||
|
||||
if (ref) {
|
||||
// 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_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
|
||||
|
||||
ref->reference();
|
||||
}
|
||||
|
||||
return mono_object;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,6 +343,7 @@ MonoThread *get_current_thread() {
|
|||
|
||||
void runtime_object_init(MonoObject *p_this_obj) {
|
||||
GD_MONO_BEGIN_RUNTIME_INVOKE;
|
||||
// FIXME: Do not use mono_runtime_object_init, it aborts if an exception is thrown
|
||||
mono_runtime_object_init(p_this_obj);
|
||||
GD_MONO_END_RUNTIME_INVOKE;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
namespace GDMonoUtils {
|
||||
|
||||
typedef void (*GodotObject_Dispose)(MonoObject *, MonoObject **);
|
||||
typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **);
|
||||
typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **);
|
||||
typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **);
|
||||
|
@ -141,6 +142,7 @@ struct MonoCache {
|
|||
GDMonoField *field_Image_ptr;
|
||||
GDMonoField *field_RID_ptr;
|
||||
|
||||
GodotObject_Dispose methodthunk_GodotObject_Dispose;
|
||||
Array_GetPtr methodthunk_Array_GetPtr;
|
||||
Dictionary_GetPtr methodthunk_Dictionary_GetPtr;
|
||||
IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType;
|
||||
|
|
|
@ -119,7 +119,7 @@ void SignalAwaiterHandle::_bind_methods() {
|
|||
}
|
||||
|
||||
SignalAwaiterHandle::SignalAwaiterHandle(MonoObject *p_managed) :
|
||||
MonoGCHandle(MonoGCHandle::make_strong_handle(p_managed), STRONG_HANDLE) {
|
||||
MonoGCHandle(MonoGCHandle::new_strong_handle(p_managed), STRONG_HANDLE) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
conn_target_id = 0;
|
||||
|
|
Loading…
Reference in a new issue