diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index 50196b84f04..bec39e9f50b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -218,6 +218,52 @@ INamedTypeSymbol symbol source.Append(" }\n"); } + // Generate the SignalEmit class + source.AppendLine($" public new class SignalEmit : {symbol.BaseType.FullQualifiedName()}.SignalEmit") + .AppendLine(" {"); + + source.AppendLine($" public SignalEmit({GodotClasses.Object} bound) : base(bound) {{ }}"); + + foreach (var signalDelegate in godotSignalDelegates) + { + string signalName = signalDelegate.Name; + var parameters = signalDelegate.InvokeMethodData.Method.Parameters; + string @params = ""; + string paramsCall = ""; + + if (parameters.Length > 0) + { + paramsCall += ", "; + + for (int i = 0; i < parameters.Length; i++) + { + @params += parameters[i].ToString() + + " " + + parameters[i].Name.ToString(); + + paramsCall += parameters[i].Name.ToString(); + + if (i != parameters.Length - 1) + { + @params += ", "; + paramsCall += ", "; + } + } + } + + source.AppendLine($" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedName()}\"/>"); + + source.Append($" public void {signalName}({@params})") + .AppendLine($" => bound.EmitSignal({symbol.NameWithTypeParameters()}.SignalName.{signalName}{paramsCall});"); + } + + source.AppendLine(" }"); + + // Generate the Emit property + source.AppendLine(" private SignalEmit _emit;") + .AppendLine(" /// <summary>A helper to quickly and safely emit signals.</summary>") + .AppendLine(" public new SignalEmit Emit => _emit ??= new(this);"); + source.Append("#pragma warning restore CS0109\n"); // Generate signal event diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index b90321b5869..e50d7f425c4 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1541,6 +1541,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.append(itype.name); output.append("\";\n"); + // Add Emit property + output << MEMBER_BEGIN "private SignalEmit _emit;\n" + << MEMBER_BEGIN "/// <summary>A helper to quickly and safely emit signals.</summary>\n" + << MEMBER_BEGIN "public new SignalEmit Emit => _emit \?\?= new(this);\n"; + if (itype.is_instantiable) { // Add native constructor static field @@ -1762,6 +1767,59 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } output << INDENT1 "}\n"; + //SignalEmit + if (!itype.is_singleton) { + if (is_inherit) { + output << MEMBER_BEGIN "public new class SignalEmit : " << obj_types[itype.base_name].proxy_name << ".SignalEmit\n" + << INDENT1 "{\n"; + // Generate ctor + output << INDENT2 "public SignalEmit(Godot.Object bound) : base(bound) { }\n"; + } else { + output << MEMBER_BEGIN "public class SignalEmit\n" + << INDENT1 "{\n"; + // Generate bound field and ctor + output << INDENT2 "protected Godot.Object bound;\n" + << INDENT2 "public SignalEmit(Godot.Object bound)\n" + << INDENT2 "{\n" + << INDENT3 "this.bound = bound;\n" + << INDENT2 "}\n"; + } + // Generate SignalEmit's methods + for (const SignalInterface &isignal : itype.signals_) { + String arg_sig; + String arg_call_sig; + + // Get arguments + const ArgumentInterface &first_arg = isignal.arguments.front()->get(); + for (const ArgumentInterface &iarg : isignal.arguments) { + const TypeInterface *arg_type = _get_type_or_null(iarg.type); + + // No need to Add ERR_FAIL_COND's because there already in _generate_cs_signal + + if (&iarg != &first_arg) { + arg_sig += ", "; + } + arg_call_sig += ", "; + + arg_sig += arg_type->cs_type; + arg_sig += " "; + arg_sig += iarg.name; + arg_call_sig += iarg.name; + } + + output << MEMBER_BEGIN INDENT1 "/// <summary>\n" + << INDENT2 "/// " + << "Raises the" + << "<see cref=\"" BINDINGS_NAMESPACE "." + itype.proxy_name + "." + isignal.proxy_name + "\"/>" + << " signal.\n" + << INDENT2 "/// </summary>\n"; + + output << INDENT2 "public void " << isignal.proxy_name << "(" << arg_sig << ")" + << " => bound.EmitSignal(\"" << isignal.name << "\"" << arg_call_sig << ");\n"; + } + output << INDENT1 "}\n"; + } + output.append(CLOSE_BLOCK /* class */); output.append("\n"