From b1356a3590ad1a4ed7bc4f85e1ffe7e9776855c3 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Tue, 4 Sep 2018 05:40:41 +0200 Subject: [PATCH 1/5] Cleanup of c# api files and bindings generator - We no longer generate RID and NodePath C# classes. Both will be maintained manually. - We no longer generate C# declarations and runtime registration of internal calls for the following classes: RID, NodePath, String, GD, SignalAwaiter and Godot.Object (partial base). - We no longer auto-generate the base members of Godot.Object. They will be maintained manually as a partial class. This makes it easier to maintain these C# classes and their internal calls, as well as the bindings generator which no longer generates C# classes that don't derive from Godot Object, and it no longer generates the Godot.Object base members (which where unreadable in the bindings generator code). - Added missing 'RID(Object from)' constructor to the RID C# class. - Replaced MONO_GLUE_DISABLED constant macro with MONO_GLUE_ENABLED. - Add sources in module/mono/glue even if glue is disabled, but surround glue files with ifdef MONO_GLUE_ENABLED. --- modules/mono/SCsub | 5 +- modules/mono/csharp_script.cpp | 2 +- modules/mono/editor/bindings_generator.cpp | 431 ++++-------------- modules/mono/editor/bindings_generator.h | 5 - modules/mono/glue/base_object_glue.cpp | 96 ++++ modules/mono/glue/base_object_glue.h | 57 +++ modules/mono/glue/collections_glue.cpp | 5 + modules/mono/glue/collections_glue.h | 4 + modules/mono/glue/cs_files/Array.cs | 78 ++-- modules/mono/glue/cs_files/Dictionary.cs | 85 ++-- .../cs_files/Extensions/ObjectExtensions.cs | 6 +- modules/mono/glue/cs_files/GD.cs | 78 +++- modules/mono/glue/cs_files/NodePath.cs | 147 ++++++ modules/mono/glue/cs_files/Object.base.cs | 81 ++++ modules/mono/glue/cs_files/RID.cs | 76 +++ modules/mono/glue/cs_files/SignalAwaiter.cs | 9 +- .../mono/glue/cs_files/StringExtensions.cs | 31 +- modules/mono/glue/gd_glue.cpp | 202 ++++++++ modules/mono/glue/gd_glue.h | 74 +++ modules/mono/glue/glue_header.h | 308 ++----------- ...builtin_types_glue.h => nodepath_glue.cpp} | 51 ++- modules/mono/glue/nodepath_glue.h | 68 +++ modules/mono/glue/rid_glue.cpp | 61 +++ modules/mono/glue/rid_glue.h | 53 +++ modules/mono/glue/string_glue.cpp | 79 ++++ modules/mono/glue/string_glue.h | 56 +++ modules/mono/mono_gd/gd_mono.cpp | 16 +- 27 files changed, 1410 insertions(+), 754 deletions(-) create mode 100644 modules/mono/glue/base_object_glue.cpp create mode 100644 modules/mono/glue/base_object_glue.h create mode 100644 modules/mono/glue/cs_files/NodePath.cs create mode 100644 modules/mono/glue/cs_files/Object.base.cs create mode 100644 modules/mono/glue/cs_files/RID.cs create mode 100644 modules/mono/glue/gd_glue.cpp create mode 100644 modules/mono/glue/gd_glue.h rename modules/mono/glue/{builtin_types_glue.h => nodepath_glue.cpp} (61%) create mode 100644 modules/mono/glue/nodepath_glue.h create mode 100644 modules/mono/glue/rid_glue.cpp create mode 100644 modules/mono/glue/rid_glue.h create mode 100644 modules/mono/glue/string_glue.cpp create mode 100644 modules/mono/glue/string_glue.h diff --git a/modules/mono/SCsub b/modules/mono/SCsub index f3cf4c9c5d4..4c6c4a03009 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -57,6 +57,7 @@ def make_cs_files_header(src, dst): 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') @@ -72,9 +73,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']) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index d2a861dbe8a..0efdf0ee1db 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -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 diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index cc954348f4c..327079d6023 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -48,7 +48,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 +68,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 +96,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 +191,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::Element *E = p_itype.methods.front(); E; E = E->next()) { @@ -248,13 +201,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 +216,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::Element *match = method_icalls.find(im_icall); + List::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::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::Element *added = builtin_method_icalls.push_back(im_icall); + List::Element *added = method_icalls.push_back(im_icall); method_icalls_map.insert(&E->get(), &added->get()); } } @@ -483,20 +422,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 compressed_files; @@ -537,29 +462,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::Element *E = core_custom_icalls.front(); E; E = E->next()) ADD_INTERNAL_CALL(E->get()); for (const List::Element *E = method_icalls.front(); E; E = E->next()) ADD_INTERNAL_CALL(E->get()); - for (const List::Element *E = builtin_method_icalls.front(); E; E = E->next()) - ADD_INTERNAL_CALL(E->get()); #undef ADD_INTERNAL_CALL @@ -658,8 +580,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::Element *E = editor_custom_icalls.front(); E; E = E->next()) ADD_INTERNAL_CALL(E->get()); for (const List::Element *E = method_icalls.front(); E; E = E->next()) @@ -693,18 +613,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 &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 output; @@ -733,28 +669,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 +783,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::Element *E = itype.properties.front(); E; E = E->next()) { @@ -865,43 +794,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 +808,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 +839,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::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::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::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::Element *E = itype.methods.front(); E; E = E->next()) { const MethodInterface &imethod = E->get(); @@ -1030,7 +859,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 +1007,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 default_args_doc; @@ -1257,9 +1084,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 +1199,31 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { List 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::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 &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::Element *E = itype.methods.front(); E; E = E->next()) { const MethodInterface &imethod = E->get(); @@ -1409,7 +1248,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 +1265,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"); @@ -1441,8 +1280,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { 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 +1344,11 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { output.push_back("#endif\n"); } - for (const List::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) @@ -1591,9 +1429,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::Element *match = method_icalls_map.find(&p_imethod); ERR_FAIL_NULL_V(match, ERR_BUG); @@ -1628,7 +1463,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 +1513,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 +1521,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 +1587,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 +1721,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 +2102,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 +2118,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 +2232,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 method_list; - v.get_method_list(&method_list); - method_list.sort(); - - for (List::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 +2329,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::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 &p_cmdline_args) { diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 735e7ce7cc8..c3123d1d525 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -456,10 +456,7 @@ class BindingsGenerator { List global_enums; List global_constants; - Map extra_members; - List method_icalls; - List builtin_method_icalls; Map method_icalls_map; List 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(); diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp new file mode 100644 index 00000000000..8ee2fae475e --- /dev/null +++ b/modules/mono/glue/base_object_glue.cpp @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* 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 "../mono_gd/gd_mono_internals.h" +#include "../mono_gd/gd_mono_utils.h" +#include "../signal_awaiter_utils.h" + +Object *godot_icall_Object_Ctor(MonoObject *obj) { + Object *instance = memnew(Object); + GDMonoInternals::tie_managed_to_unmanaged(obj, instance); + return instance; +} + +void godot_icall_Object_Dtor(MonoObject *obj, Object *ptr) { +#ifdef DEBUG_ENABLED + CRASH_COND(ptr == NULL); +#endif + _GodotSharp::get_singleton()->queue_dispose(obj, ptr); +} + +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 wref; + Reference *ref = Object::cast_to(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(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_Dtor", (void *)godot_icall_Object_Dtor); + 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 diff --git a/modules/mono/glue/base_object_glue.h b/modules/mono/glue/base_object_glue.h new file mode 100644 index 00000000000..08cc380429b --- /dev/null +++ b/modules/mono/glue/base_object_glue.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* 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 *obj); + +void godot_icall_Object_Dtor(MonoObject *obj, Object *ptr); + +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 diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index bb218b49b70..d9dba1c60d7 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -30,9 +30,12 @@ #include "collections_glue.h" +#ifdef MONO_GLUE_ENABLED + #include #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 diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h index eb5ecfb7251..fa8e4c28aa7 100644 --- a/modules/mono/glue/collections_glue.h +++ b/modules/mono/glue/collections_glue.h @@ -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 diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs index 2f0185b1e3c..8e337dd9b18 100644 --- a/modules/mono/glue/cs_files/Array.cs +++ b/modules/mono/glue/cs_files/Array.cs @@ -30,45 +30,6 @@ namespace Godot.Collections public class Array : IList, ICollection, IEnumerable, 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; @@ -200,6 +161,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 : IList, ICollection, IEnumerable diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs index 64cb9f935da..57a476cb23f 100644 --- a/modules/mono/glue/cs_files/Dictionary.cs +++ b/modules/mono/glue/cs_files/Dictionary.cs @@ -34,48 +34,6 @@ namespace Godot.Collections IEnumerable>, 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; @@ -240,8 +198,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 : IDictionary, diff --git a/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs b/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs index 5c9e6609f46..9ef09597500 100644 --- a/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs +++ b/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs @@ -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); } } diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs index 0a5d703f274..264be235883 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/cs_files/GD.cs @@ -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); } } diff --git a/modules/mono/glue/cs_files/NodePath.cs b/modules/mono/glue/cs_files/NodePath.cs new file mode 100644 index 00000000000..2c89bec87fe --- /dev/null +++ b/modules/mono/glue/cs_files/NodePath.cs @@ -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); + } +} diff --git a/modules/mono/glue/cs_files/Object.base.cs b/modules/mono/glue/cs_files/Object.base.cs new file mode 100644 index 00000000000..5d62d0b335d --- /dev/null +++ b/modules/mono/glue/cs_files/Object.base.cs @@ -0,0 +1,81 @@ +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_Object_Dtor(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_Dtor(object obj, IntPtr ptr); + + // Used by the generated API + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Object_ClassDB_get_method(string type, string method); + } +} diff --git a/modules/mono/glue/cs_files/RID.cs b/modules/mono/glue/cs_files/RID.cs new file mode 100644 index 00000000000..b862b8cac05 --- /dev/null +++ b/modules/mono/glue/cs_files/RID.cs @@ -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); + } +} diff --git a/modules/mono/glue/cs_files/SignalAwaiter.cs b/modules/mono/glue/cs_files/SignalAwaiter.cs index c06f6b05c97..9483b6ffb43 100644 --- a/modules/mono/glue/cs_files/SignalAwaiter.cs +++ b/modules/mono/glue/cs_files/SignalAwaiter.cs @@ -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 diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs index cda573f6c56..21c9be98c19 100644 --- a/modules/mono/glue/cs_files/StringExtensions.cs +++ b/modules/mono/glue/cs_files/StringExtensions.cs @@ -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 // 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); + // // Return the MD5 hash of the string as a string. // 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); + // // Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. // @@ -752,17 +759,23 @@ namespace Godot // 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); + // // Perform a search for a substring, but start from the end of the string instead of the beginning. Also search case-insensitive. // 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); + // // Return the right side of the string from a given position. // @@ -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); + // // Return the SHA-256 hash of the string as a string. // 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); + // // Return the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar. // diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp new file mode 100644 index 00000000000..051f42b9668 --- /dev/null +++ b/modules/mono/glue/gd_glue.cpp @@ -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 diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h new file mode 100644 index 00000000000..6f846f221d5 --- /dev/null +++ b/modules/mono/glue/gd_glue.h @@ -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 diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 6a6f3062b4d..69c5c6dcdb2 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.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(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 ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer(); - // TODO Check possible Array/Vector 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 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 wref; - Reference *ref = Object::cast_to(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(wref.ptr())); -} - -void godot_register_header_icalls() { - godot_register_builtin_type_icalls(); - godot_register_collections_icalls(); -} +#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/builtin_types_glue.h b/modules/mono/glue/nodepath_glue.cpp similarity index 61% rename from modules/mono/glue/builtin_types_glue.h rename to modules/mono/glue/nodepath_glue.cpp index ef9f152682e..4b7648a4f9f 100644 --- a/modules/mono/glue/builtin_types_glue.h +++ b/modules/mono/glue/nodepath_glue.cpp @@ -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 +#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 diff --git a/modules/mono/glue/nodepath_glue.h b/modules/mono/glue/nodepath_glue.h new file mode 100644 index 00000000000..92579399a65 --- /dev/null +++ b/modules/mono/glue/nodepath_glue.h @@ -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 diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp new file mode 100644 index 00000000000..5d66b8aa6f0 --- /dev/null +++ b/modules/mono/glue/rid_glue.cpp @@ -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(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 diff --git a/modules/mono/glue/rid_glue.h b/modules/mono/glue/rid_glue.h new file mode 100644 index 00000000000..c725a9b5de6 --- /dev/null +++ b/modules/mono/glue/rid_glue.h @@ -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 diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp new file mode 100644 index 00000000000..e1a2f1affd1 --- /dev/null +++ b/modules/mono/glue/string_glue.cpp @@ -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 ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer(); + // TODO Check possible Array/Vector 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 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 diff --git a/modules/mono/glue/string_glue.h b/modules/mono/glue/string_glue.h new file mode 100644 index 00000000000..8b1553e28b4 --- /dev/null +++ b/modules/mono/glue/string_glue.h @@ -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 diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index fadac941e97..a21727fd611 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -232,7 +232,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 +275,7 @@ void GDMono::initialize() { print_verbose("Mono: INITIALIZED"); } -#ifndef MONO_GLUE_DISABLED +#ifdef MONO_GLUE_ENABLED namespace GodotSharpBindings { uint64_t get_core_api_hash(); @@ -290,7 +290,7 @@ void register_generated_icalls(); #endif void GDMono::_register_internal_calls() { -#ifndef MONO_GLUE_DISABLED +#ifdef MONO_GLUE_ENABLED GodotSharpBindings::register_generated_icalls(); #endif @@ -304,7 +304,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 +313,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,7 +431,7 @@ 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 || @@ -457,7 +457,7 @@ 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 || @@ -684,7 +684,7 @@ Error GDMono::reload_scripts_domain() { return err; } -#ifndef MONO_GLUE_DISABLED +#ifdef MONO_GLUE_ENABLED if (!_load_api_assemblies()) { return ERR_CANT_OPEN; } From 691d4e38352ba3d1dc81ea66e2944f0947c4c4fb Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Tue, 4 Sep 2018 22:13:47 +0200 Subject: [PATCH 2/5] Allow special characters in C# glue files Fixes #21139 - Surround the generated file modules/mono/glue/cs_compressed.gen.h with ifdef TOOLS_ENABLED --- modules/mono/SCsub | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 4c6c4a03009..c3b1e722b8c 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -11,17 +11,20 @@ def make_cs_files_header(src, 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))): @@ -53,7 +58,8 @@ def make_cs_files_header(src, dst): '\t\tdata = p_data;\n' '\t}\n' '\n\tCompressedFile() {}\n' '};\n' '\nvoid get_compressed_files(Map& 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') env_mono.add_source_files(env.modules_sources, '*.cpp') @@ -63,7 +69,7 @@ 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 + # 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') vars = Variables() From 61426464ea28f82f0c340572caafeb6aaaad4c91 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Thu, 6 Sep 2018 19:38:24 +0200 Subject: [PATCH 3/5] Add some mono root hint dirs for OSX Fixes #13355 --- modules/mono/editor/godotsharp_builds.cpp | 21 ++++++++++++-------- modules/mono/mono_gd/gd_mono.cpp | 24 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 2faab1718dc..35959f3b020 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -30,6 +30,7 @@ #include "godotsharp_builds.h" +#include "core/vector.h" #include "main/main.h" #include "../godotsharp_dirs.h" @@ -50,6 +51,16 @@ void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString * GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code); } +static Vector _get_msbuild_hint_dirs() { + Vector 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 +72,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 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)) { diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index a21727fd611..f1dbb5c5146 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -177,6 +177,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 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 From e558e1ec09aa27852426bbd24dfa21e9b60cfbfc Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Wed, 12 Sep 2018 02:41:54 +0200 Subject: [PATCH 4/5] Fix/workaround for issue #21667 When a Reference managed instance is garbage collected and its finalizer is called, it could happen that the native instance is referenced once again before the finalizer can unreference and memdelete it. The workaround is to create a new managed instance when this happens (at least for now). --- modules/mono/csharp_script.cpp | 344 +++++++++++++++++----- modules/mono/csharp_script.h | 32 +- modules/mono/editor/mono_bottom_panel.cpp | 6 +- modules/mono/glue/base_object_glue.cpp | 70 ++++- modules/mono/glue/base_object_glue.h | 6 +- modules/mono/glue/cs_files/Array.cs | 5 - modules/mono/glue/cs_files/Dictionary.cs | 5 - modules/mono/glue/cs_files/Object.base.cs | 11 +- modules/mono/mono_gc_handle.cpp | 20 +- modules/mono/mono_gc_handle.h | 7 +- modules/mono/mono_gd/gd_mono.cpp | 130 ++++---- modules/mono/mono_gd/gd_mono.h | 22 +- modules/mono/mono_gd/gd_mono_utils.cpp | 46 ++- modules/mono/mono_gd/gd_mono_utils.h | 2 + modules/mono/signal_awaiter_utils.cpp | 2 +- 15 files changed, 512 insertions(+), 196 deletions(-) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 0efdf0ee1db..a7899257b5f 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -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 CSharpLanguage::stack_trace_get_info(MonoObjec void CSharpLanguage::frame() { - const Ref &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle; + if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) { + const Ref &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 &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 &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(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 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 >::Element *data = (Map >::Element *)p_data; + Map::Element *data = (Map::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 &gchandle = ((Map >::Element *)data)->get(); + Ref &gchandle = ((Map::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 &gchandle = ((Map >::Element *)data)->get(); + Ref &gchandle = ((Map::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(owner)->init_ref(); + bool success = Object::cast_to(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(owner)->unreference()) { + bool die = static_cast(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(); + 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(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(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