Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C#: Cleaner signal emission #69142

Closed
wants to merge 11 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 58 additions & 0 deletions modules/mono/editor/bindings_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"
Expand Down