diff options
author | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2020-03-14 19:20:17 +0100 |
---|---|---|
committer | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2020-03-17 16:30:04 +0100 |
commit | 6a85cdf640d735b1ca8216b4c6e16fb949f4d183 (patch) | |
tree | afc06540f53d6d2f7ede36fc8383330dee149262 /modules/mono/editor | |
parent | 0159787864e7ecce60a4d3142f5c82e024710f89 (diff) |
Fix C# bindings after recent breaking changes
Implementation for new Variant types Callable, Signal, StringName.
Added support for PackedInt64Array and PackedFloat64Array.
Add generation of signal members as events, as well as support for
user created signals as events.
NOTE: As of now, raising such events will not emit the signal. As such,
one must use `EmitSignal` instead of raising the event directly.
Removed old ThreadLocal fallback class. It's safe to use thread_local now since
it's supported on all minimum versions of compilers we support.
Diffstat (limited to 'modules/mono/editor')
6 files changed, 363 insertions, 56 deletions
diff --git a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs index 2971236482..e4c8759802 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs @@ -280,7 +280,7 @@ namespace GodotTools Text = "Build Project".TTR(), FocusMode = FocusModeEnum.None }; - buildProjectBtn.Connect("pressed", this, nameof(BuildProjectPressed)); + buildProjectBtn.PressedSignal += BuildProjectPressed; toolBarHBox.AddChild(buildProjectBtn); toolBarHBox.AddSpacer(begin: false); @@ -293,7 +293,7 @@ namespace GodotTools Visible = false, FocusMode = FocusModeEnum.None }; - warningsBtn.Connect("toggled", this, nameof(_WarningsToggled)); + warningsBtn.Toggled += _WarningsToggled; toolBarHBox.AddChild(warningsBtn); errorsBtn = new ToolButton @@ -304,7 +304,7 @@ namespace GodotTools Visible = false, FocusMode = FocusModeEnum.None }; - errorsBtn.Connect("toggled", this, nameof(_ErrorsToggled)); + errorsBtn.Toggled += _ErrorsToggled; toolBarHBox.AddChild(errorsBtn); toolBarHBox.AddSpacer(begin: false); @@ -315,7 +315,7 @@ namespace GodotTools FocusMode = FocusModeEnum.None, Visible = false }; - viewLogBtn.Connect("pressed", this, nameof(_ViewLogPressed)); + viewLogBtn.PressedSignal += _ViewLogPressed; toolBarHBox.AddChild(viewLogBtn); var hsc = new HSplitContainer @@ -326,8 +326,8 @@ namespace GodotTools panelBuildsTab.AddChild(hsc); buildTabsList = new ItemList { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill }; - buildTabsList.Connect("item_selected", this, nameof(_BuildTabsItemSelected)); - buildTabsList.Connect("nothing_selected", this, nameof(_BuildTabsNothingSelected)); + buildTabsList.ItemSelected += _BuildTabsItemSelected; + buildTabsList.NothingSelected += _BuildTabsNothingSelected; hsc.AddChild(buildTabsList); buildTabs = new TabContainer diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs b/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs index f75fe239e3..b2459b69ad 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs @@ -251,7 +251,7 @@ namespace GodotTools base._Ready(); issuesList = new ItemList { SizeFlagsVertical = (int)SizeFlags.ExpandFill }; - issuesList.Connect("item_activated", this, nameof(_IssueActivated)); + issuesList.ItemActivated += _IssueActivated; AddChild(issuesList); } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 796522b2f2..e4e391765e 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -121,16 +121,9 @@ namespace GodotTools aboutDialog.PopupCenteredMinsize(); } - private void _ToggleAboutDialogOnStart(bool enabled) + private void _MenuOptionPressed(int id) { - bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start"); - if (showOnStart != enabled) - editorSettings.SetSetting("mono/editor/show_info_on_start", enabled); - } - - private void _MenuOptionPressed(MenuOptions id) - { - switch (id) + switch ((MenuOptions)id) { case MenuOptions.CreateSln: CreateProjectSolution(); @@ -210,7 +203,7 @@ namespace GodotTools string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath); RiderPathManager.OpenFile(GodotSharpDirs.ProjectSlnPath, scriptPath, line); return Error.Ok; - } + } case ExternalEditorId.MonoDevelop: { string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath); @@ -395,7 +388,12 @@ namespace GodotTools // CheckBox in main container aboutDialogCheckBox = new CheckBox { Text = "Show this warning when starting the editor" }; - aboutDialogCheckBox.Connect("toggled", this, nameof(_ToggleAboutDialogOnStart)); + aboutDialogCheckBox.Toggled += enabled => + { + bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start"); + if (showOnStart != enabled) + editorSettings.SetSetting("mono/editor/show_info_on_start", enabled); + }; aboutVBox.AddChild(aboutDialogCheckBox); } @@ -424,7 +422,7 @@ namespace GodotTools menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln); } - menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed)); + menuPopup.IdPressed += _MenuOptionPressed; var buildButton = new ToolButton { @@ -432,7 +430,7 @@ namespace GodotTools HintTooltip = "Build solution", FocusMode = Control.FocusModeEnum.None }; - buildButton.Connect("pressed", this, nameof(_BuildSolutionPressed)); + buildButton.PressedSignal += _BuildSolutionPressed; AddControlToContainer(CustomControlContainer.Toolbar, buildButton); // External editor settings diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs index 0ed567afd1..1d19fab706 100644 --- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs +++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs @@ -40,7 +40,7 @@ namespace GodotTools OneShot = false, WaitTime = (float)EditorDef("mono/assembly_watch_interval_sec", 0.5) }; - watchTimer.Connect("timeout", this, nameof(TimerTimeout)); + watchTimer.Timeout += TimerTimeout; AddChild(watchTimer); watchTimer.Start(); } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 5355cb4e45..c8430234d6 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -76,7 +76,7 @@ #define GLUE_HEADER_FILE "glue_header.h" #define ICALL_PREFIX "godot_icall_" #define SINGLETON_ICALL_SUFFIX "_get_singleton" -#define ICALL_GET_METHODBIND ICALL_PREFIX "Object_ClassDB_get_method" +#define ICALL_GET_METHODBIND "__ClassDB_get_method" #define C_LOCAL_RET "ret" #define C_LOCAL_VARARG_RET "vararg_ret" @@ -95,6 +95,10 @@ #define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot" #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 C_METHOD_MANAGED_TO_CALLABLE C_NS_MONOMARSHAL "::managed_to_callable" +#define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL "::callable_to_managed" +#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable" +#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info" #define BINDINGS_GENERATOR_VERSION UINT32_C(11) @@ -504,23 +508,23 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(tag); xml_output.append("</c>"); } else if (tag == "PackedByteArray") { - xml_output.append("<see cref=\"byte\"/>"); + xml_output.append("<see cref=\"T:byte[]\"/>"); } else if (tag == "PackedInt32Array") { - xml_output.append("<see cref=\"int\"/>"); + xml_output.append("<see cref=\"T:int[]\"/>"); + } else if (tag == "PackedInt64Array") { + xml_output.append("<see cref=\"T:long[]\"/>"); } else if (tag == "PackedFloat32Array") { -#ifdef REAL_T_IS_DOUBLE - xml_output.append("<see cref=\"double\"/>"); -#else - xml_output.append("<see cref=\"float\"/>"); -#endif + xml_output.append("<see cref=\"T:float[]\"/>"); + } else if (tag == "PackedFloat64Array") { + xml_output.append("<see cref=\"T:double[]\"/>"); } else if (tag == "PackedStringArray") { - xml_output.append("<see cref=\"string\"/>"); + xml_output.append("<see cref=\"T:string[]\"/>"); } else if (tag == "PackedVector2Array") { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>"); + xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector2[]\"/>"); } else if (tag == "PackedVector3Array") { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>"); + xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector3[]\"/>"); } else if (tag == "PackedColorArray") { - xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>"); + xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Color[]\"/>"); } else { const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag)); @@ -932,7 +936,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { "using System.Runtime.CompilerServices;\n" "\n"); cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); - cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK); + cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 "{"); cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = "); cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n"); @@ -944,7 +948,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { #define ADD_INTERNAL_CALL(m_icall) \ if (!m_icall.editor_only) { \ cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \ - cs_icalls_content.append(INDENT2 "internal extern static "); \ + cs_icalls_content.append(INDENT2 "internal static extern "); \ cs_icalls_content.append(m_icall.im_type_out + " "); \ cs_icalls_content.append(m_icall.name + "("); \ cs_icalls_content.append(m_icall.im_sig + ");\n"); \ @@ -1046,7 +1050,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { #define ADD_INTERNAL_CALL(m_icall) \ if (m_icall.editor_only) { \ cs_icalls_content.append(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \ - cs_icalls_content.append(INDENT2 "internal extern static "); \ + cs_icalls_content.append(INDENT2 "internal static extern "); \ cs_icalls_content.append(m_icall.im_type_out + " "); \ cs_icalls_content.append(m_icall.name + "("); \ cs_icalls_content.append(m_icall.im_sig + ");\n"); \ @@ -1312,7 +1316,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.append(itype.proxy_name); output.append(").Name);\n" INDENT4 "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n"); - output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \""); + output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \""); output.append(itype.name); output.append("\";\n"); @@ -1324,7 +1328,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } else if (is_derived_type) { // Add member fields - output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \""); + output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \""); output.append(itype.name); output.append("\";\n"); @@ -1363,6 +1367,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str "Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'."); } + for (const List<SignalInterface>::Element *E = itype.signals_.front(); E; E = E->next()) { + const SignalInterface &isignal = E->get(); + Error method_err = _generate_cs_signal(itype, isignal, output); + ERR_FAIL_COND_V_MSG(method_err != OK, method_err, + "Failed to generate signal '" + isignal.name + "' for class '" + itype.name + "'."); + } + if (itype.is_singleton) { InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr"); @@ -1424,7 +1435,16 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte } if (getter && setter) { - ERR_FAIL_COND_V(getter->return_type.cname != setter->arguments.back()->get().type.cname, ERR_BUG); + const ArgumentInterface &setter_first_arg = setter->arguments.back()->get(); + if (getter->return_type.cname != setter_first_arg.type.cname) { + // Special case for Node::set_name + bool whitelisted = getter->return_type.cname == name_cache.type_StringName && + setter_first_arg.type.cname == name_cache.type_String; + + ERR_FAIL_COND_V_MSG(!whitelisted, ERR_BUG, + "Return type from getter doesn't match first argument of setter for property: '" + + p_itype.name + "." + String(p_iprop.cname) + "'."); + } } const TypeReference &proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type; @@ -1525,7 +1545,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type); - String method_bind_field = "method_bind_" + itos(p_method_bind_count); + String method_bind_field = "__method_bind_" + itos(p_method_bind_count); String arguments_sig; String cs_in_statements; @@ -1612,7 +1632,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf { if (!p_imethod.is_virtual && !p_imethod.requires_object_call) { p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr "); - p_output.append(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \""); + p_output.append(method_bind_field); + p_output.append(" = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \""); p_output.append(p_imethod.name); p_output.append("\");\n"); } @@ -1726,6 +1747,106 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf return OK; } +Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output) { + String arguments_sig; + + // Retrieve information from the arguments + for (const List<ArgumentInterface>::Element *F = p_isignal.arguments.front(); F; F = F->next()) { + const ArgumentInterface &iarg = F->get(); + const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); + + // Add the current arguments to the signature + + if (F != p_isignal.arguments.front()) + arguments_sig += ", "; + + arguments_sig += arg_type->cs_type; + arguments_sig += " "; + arguments_sig += iarg.name; + } + + // Generate signal + { + if (p_isignal.method_doc && p_isignal.method_doc->description.size()) { + String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype); + Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); + + if (summary_lines.size()) { + p_output.append(MEMBER_BEGIN "/// <summary>\n"); + + for (int i = 0; i < summary_lines.size(); i++) { + p_output.append(INDENT2 "/// "); + p_output.append(summary_lines[i]); + p_output.append("\n"); + } + + p_output.append(INDENT2 "/// </summary>"); + } + } + + if (p_isignal.is_deprecated) { + if (p_isignal.deprecation_message.empty()) + WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'."); + + p_output.append(MEMBER_BEGIN "[Obsolete(\""); + p_output.append(p_isignal.deprecation_message); + p_output.append("\")]"); + } + + String delegate_name = p_isignal.proxy_name; + delegate_name += "Handler"; // Delegate name is [SignalName]Handler + + // Generate delegate + p_output.append(MEMBER_BEGIN "public delegate void "); + p_output.append(delegate_name); + p_output.append("("); + p_output.append(arguments_sig); + p_output.append(");\n"); + + // TODO: + // Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded? + // If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here. + + // Cached signal name (StringName) + p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static StringName __signal_name_"); + p_output.append(p_isignal.name); + p_output.append(" = \""); + p_output.append(p_isignal.name); + p_output.append("\";\n"); + + // Generate event + p_output.append(MEMBER_BEGIN "[Signal]" MEMBER_BEGIN "public "); + + if (p_itype.is_singleton) + p_output.append("static "); + + p_output.append("event "); + p_output.append(delegate_name); + p_output.append(" "); + p_output.append(p_isignal.proxy_name); + p_output.append("\n" OPEN_BLOCK_L2); + + if (p_itype.is_singleton) + p_output.append("add => Singleton.Connect(__signal_name_"); + else + p_output.append("add => Connect(__signal_name_"); + + p_output.append(p_isignal.name); + p_output.append(", new Callable(value));\n"); + + if (p_itype.is_singleton) + p_output.append(INDENT3 "remove => Singleton.Disconnect(__signal_name_"); + else + p_output.append(INDENT3 "remove => Disconnect(__signal_name_"); + + p_output.append(p_isignal.name); + p_output.append(", new Callable(value));\n"); + p_output.append(CLOSE_BLOCK_L2); + } + + return OK; +} + Error BindingsGenerator::generate_glue(const String &p_output_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); @@ -2479,13 +2600,92 @@ bool BindingsGenerator::_populate_object_type_interfaces() { } } + // Populate signals + + const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map; + const StringName *k = NULL; + + while ((k = signal_map.next(k))) { + SignalInterface isignal; + + const MethodInfo &method_info = signal_map.get(*k); + + isignal.name = method_info.name; + isignal.cname = method_info.name; + + int argc = method_info.arguments.size(); + + for (int i = 0; i < argc; i++) { + PropertyInfo arginfo = method_info.arguments[i]; + + String orig_arg_name = arginfo.name; + + ArgumentInterface iarg; + iarg.name = orig_arg_name; + + if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + iarg.type.cname = arginfo.class_name; + iarg.type.is_enum = true; + } else if (arginfo.class_name != StringName()) { + iarg.type.cname = arginfo.class_name; + } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { + iarg.type.cname = arginfo.hint_string; + } else if (arginfo.type == Variant::NIL) { + iarg.type.cname = name_cache.type_Variant; + } else { + if (arginfo.type == Variant::INT) { + iarg.type.cname = _get_int_type_name_from_meta(GodotTypeInfo::METADATA_NONE); + } else if (arginfo.type == Variant::FLOAT) { + iarg.type.cname = _get_float_type_name_from_meta(GodotTypeInfo::METADATA_NONE); + } else { + iarg.type.cname = Variant::get_type_name(arginfo.type); + } + } + + iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name)); + + isignal.add_argument(iarg); + } + + isignal.proxy_name = escape_csharp_keyword(snake_to_pascal_case(isignal.name)); + + // Prevent the signal and its enclosing type from sharing the same name + if (isignal.proxy_name == itype.proxy_name) { + _log("Name of signal '%s' is ambiguous with the name of its enclosing class '%s'. Renaming signal to '%s_'\n", + isignal.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), isignal.proxy_name.utf8().get_data()); + + isignal.proxy_name += "_"; + } + + if (itype.find_property_by_proxy_name(isignal.proxy_name) || itype.find_method_by_proxy_name(isignal.proxy_name)) { + // ClassDB allows signal names that conflict with method or property names. + // While registering a signal with a conflicting name is considered wrong, + // it may still happen and it may take some time until someone fixes the name. + // We can't allow the bindings to be in a broken state while we wait for a fix; + // that's why we must handle this possibility by renaming the signal. + isignal.proxy_name += "Signal"; + } + + if (itype.class_doc) { + for (int i = 0; i < itype.class_doc->signals.size(); i++) { + const DocData::MethodDoc &signal_doc = itype.class_doc->signals[i]; + if (signal_doc.name == isignal.name) { + isignal.method_doc = &signal_doc; + break; + } + } + } + + itype.signals_.push_back(isignal); + } + // Populate enums and constants List<String> constants; ClassDB::get_integer_constant_list(type_cname, &constants, true); const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map; - const StringName *k = NULL; + k = NULL; while ((k = enum_map.next(k))) { StringName enum_proxy_cname = *k; @@ -2587,8 +2787,15 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar #endif break; case Variant::STRING: + case Variant::STRING_NAME: case Variant::NODE_PATH: - r_iarg.default_argument = "\"" + r_iarg.default_argument + "\""; + if (r_iarg.type.cname == name_cache.type_StringName || r_iarg.type.cname == name_cache.type_NodePath) { + r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\""; + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; + } else { + CRASH_COND(r_iarg.type.cname != name_cache.type_String); + r_iarg.default_argument = "\"" + r_iarg.default_argument + "\""; + } break; case Variant::TRANSFORM: if (p_val.operator Transform() == Transform()) @@ -2630,8 +2837,8 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar case Variant::ARRAY: case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: - case Variant::PACKED_FLOAT32_ARRAY: case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: case Variant::PACKED_FLOAT64_ARRAY: case Variant::PACKED_STRING_ARRAY: case Variant::PACKED_VECTOR2_ARRAY: @@ -2646,8 +2853,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar r_iarg.default_argument = Variant::get_type_name(p_val.get_type()) + ".Identity"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; break; - default: { - } + case Variant::CALLABLE: + case Variant::SIGNAL: + CRASH_NOW_MSG("Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value."); + break; + default: + CRASH_NOW_MSG("Unexpected Variant type: " + itos(p_val.get_type())); + break; } if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "null") @@ -2672,7 +2884,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = "GDMonoMarshal::M_" #m_type; \ itype.cs_in = "ref %s"; \ /* in cs_out, im_type_out (%3) includes the 'out ' part */ \ - itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; \ + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; \ itype.im_type_out = "out " + itype.cs_type; \ itype.ret_as_byref_arg = true; \ builtin_types.insert(itype.cname, itype); \ @@ -2749,7 +2961,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = "out " + itype.name; itype.cs_in = "ref %0"; /* in cs_out, im_type_out (%3) includes the 'out ' part */ - itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; itype.ret_as_byref_arg = true; builtin_types.insert(itype.cname, itype); @@ -2766,7 +2978,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = "out " + itype.name; itype.cs_in = "ref %0"; /* in cs_out, im_type_out (%3) includes the 'out ' part */ - itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; itype.ret_as_byref_arg = true; builtin_types.insert(itype.cname, itype); } @@ -2792,7 +3004,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = "out " + itype.proxy_name; itype.cs_in = "ref %0"; /* in cs_out, im_type_out (%3) includes the 'out ' part */ - itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; itype.ret_as_byref_arg = true; builtin_types.insert(itype.cname, itype); @@ -2814,7 +3026,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = "out " + itype.proxy_name; itype.cs_in = "ref %0"; /* in cs_out, im_type_out (%3) includes the 'out ' part */ - itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; itype.ret_as_byref_arg = true; builtin_types.insert(itype.cname, itype); } @@ -2835,6 +3047,24 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = itype.proxy_name; builtin_types.insert(itype.cname, itype); + // StringName + itype = TypeInterface(); + itype.name = "StringName"; + itype.cname = itype.name; + itype.proxy_name = "StringName"; + itype.c_in = "\t%0 %1_in = %1 ? *%1 : StringName();\n"; + itype.c_out = "\treturn memnew(StringName(%1));\n"; + itype.c_arg_in = "&%s_in"; + itype.c_type = itype.name; + itype.c_type_in = itype.c_type + "*"; + itype.c_type_out = itype.c_type + "*"; + itype.cs_type = itype.proxy_name; + itype.cs_in = "StringName." CS_SMETHOD_GETINSTANCE "(%0)"; + itype.cs_out = "return new %2(%0(%1));"; + itype.im_type_in = "IntPtr"; + itype.im_type_out = "IntPtr"; + builtin_types.insert(itype.cname, itype); + // NodePath itype = TypeInterface(); itype.name = "NodePath"; @@ -2883,6 +3113,40 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.im_type_out = itype.proxy_name; builtin_types.insert(itype.cname, itype); + // Callable + itype = TypeInterface::create_value_type(String("Callable")); + itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(*%1);\n"; + itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_CALLABLE "(%1);\n"; + itype.c_arg_in = "&%s_in"; + itype.c_type_in = "GDMonoMarshal::M_Callable*"; + itype.c_type_out = "GDMonoMarshal::M_Callable"; + itype.cs_in = "ref %s"; + /* in cs_out, im_type_out (%3) includes the 'out ' part */ + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; + itype.im_type_out = "out " + itype.cs_type; + itype.ret_as_byref_arg = true; + builtin_types.insert(itype.cname, itype); + + // Signal + itype = TypeInterface(); + itype.name = "Signal"; + itype.cname = itype.name; + itype.proxy_name = "SignalInfo"; + itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(*%1);\n"; + itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_SIGNAL "(%1);\n"; + itype.c_arg_in = "&%s_in"; + itype.c_type = itype.name; + itype.c_type_in = "GDMonoMarshal::M_SignalInfo*"; + itype.c_type_out = "GDMonoMarshal::M_SignalInfo"; + itype.cs_in = "ref %s"; + /* in cs_out, im_type_out (%3) includes the 'out ' part */ + itype.cs_out = "%0(%1, %3 argRet); return argRet;"; + itype.cs_type = itype.proxy_name; + itype.im_type_in = "ref " + itype.cs_type; + itype.im_type_out = "out " + itype.cs_type; + itype.ret_as_byref_arg = true; + builtin_types.insert(itype.cname, itype); + // VarArg (fictitious type to represent variable arguments) itype = TypeInterface(); itype.name = "VarArg"; @@ -2917,13 +3181,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t) INSERT_ARRAY(PackedInt32Array, int); + INSERT_ARRAY(PackedInt64Array, long); INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, byte); -#ifdef REAL_T_IS_DOUBLE - INSERT_ARRAY(PackedFloat32Array, double); -#else INSERT_ARRAY(PackedFloat32Array, float); -#endif + INSERT_ARRAY(PackedFloat64Array, double); INSERT_ARRAY(PackedStringArray, string); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 0998d9f76a..b133923c25 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -107,9 +107,15 @@ class BindingsGenerator { TypeReference type; String name; - String default_argument; DefaultParamMode def_param_mode; + /** + * Determines the expression for the parameter default value. + * Formatting elements: + * %0 or %s: [cs_type] of the argument type + */ + String default_argument; + ArgumentInterface() { def_param_mode = CONSTANT; } @@ -175,6 +181,32 @@ class BindingsGenerator { } }; + struct SignalInterface { + String name; + StringName cname; + + /** + * Name of the C# method + */ + String proxy_name; + + List<ArgumentInterface> arguments; + + const DocData::MethodDoc *method_doc; + + bool is_deprecated; + String deprecation_message; + + void add_argument(const ArgumentInterface &argument) { + arguments.push_back(argument); + } + + SignalInterface() { + method_doc = NULL; + is_deprecated = false; + } + }; + struct TypeInterface { /** * Identifier name for this type. @@ -336,6 +368,7 @@ class BindingsGenerator { List<EnumInterface> enums; List<PropertyInterface> properties; List<MethodInterface> methods; + List<SignalInterface> signals_; const MethodInterface *find_method_by_name(const StringName &p_cname) const { for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) { @@ -364,6 +397,15 @@ class BindingsGenerator { return NULL; } + const MethodInterface *find_method_by_proxy_name(const String &p_proxy_name) const { + for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().proxy_name == p_proxy_name) + return &E->get(); + } + + return NULL; + } + private: static void _init_value_type(TypeInterface &itype) { itype.proxy_name = itype.name; @@ -524,6 +566,8 @@ class BindingsGenerator { StringName type_Reference; StringName type_RID; StringName type_String; + StringName type_StringName; + StringName type_NodePath; StringName type_at_GlobalScope; StringName enum_Error; @@ -548,6 +592,8 @@ class BindingsGenerator { type_Reference = StaticCString::create("Reference"); type_RID = StaticCString::create("RID"); type_String = StaticCString::create("String"); + type_StringName = StaticCString::create("StringName"); + type_NodePath = StaticCString::create("NodePath"); type_at_GlobalScope = StaticCString::create("@GlobalScope"); enum_Error = StaticCString::create("Error"); @@ -623,6 +669,7 @@ class BindingsGenerator { Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output); Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output); + Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output); void _generate_global_constants(StringBuilder &p_output); |