Skip to content

Commit fa8a07d

Browse files
committed
C#: Generate On{EventName} method to raise signal events
1 parent 77ac23a commit fa8a07d

3 files changed

Lines changed: 81 additions & 7 deletions

File tree

modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ partial class EventSignals
3232
add => backing_MySignal += value;
3333
remove => backing_MySignal -= value;
3434
}
35+
protected void OnMySignal(string str, int num)
36+
{
37+
EmitSignal(SignalName.MySignal, str, num);
38+
}
3539
/// <inheritdoc/>
3640
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
3741
protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, NativeVariantPtrArgs args)

modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@
55
using Microsoft.CodeAnalysis.CSharp.Syntax;
66
using Microsoft.CodeAnalysis.Text;
77

8-
// TODO:
9-
// Determine a proper way to emit the signal.
10-
// 'Emit(nameof(TheEvent))' creates a StringName every time and has the overhead of string marshaling.
11-
// I haven't decided on the best option yet. Some possibilities:
12-
// - Expose the generated StringName fields to the user, for use with 'Emit(...)'.
13-
// - Generate a 'EmitSignalName' method for each event signal.
14-
158
namespace Godot.SourceGenerators
169
{
1710
[Generator]
@@ -288,6 +281,43 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType)
288281
.Append(signalName)
289282
.Append(" -= value;\n")
290283
.Append("}\n");
284+
285+
// Generate On{EventName} method to raise the event
286+
287+
var invokeMethodSymbol = signalDelegate.InvokeMethodData.Method;
288+
int paramCount = invokeMethodSymbol.Parameters.Length;
289+
290+
string raiseMethodModifiers = signalDelegate.DelegateSymbol.ContainingType.IsSealed ?
291+
"private" :
292+
"protected";
293+
294+
source.Append($" {raiseMethodModifiers} void On{signalName}(");
295+
for (int i = 0; i < paramCount; i++)
296+
{
297+
var paramSymbol = invokeMethodSymbol.Parameters[i];
298+
source.Append($"{paramSymbol.Type.FullQualifiedNameIncludeGlobal()} {paramSymbol.Name}");
299+
if (i < paramCount - 1)
300+
{
301+
source.Append(", ");
302+
}
303+
}
304+
source.Append(")\n");
305+
source.Append(" {\n");
306+
source.Append($" EmitSignal(SignalName.{signalName}");
307+
foreach (var paramSymbol in invokeMethodSymbol.Parameters)
308+
{
309+
// Enums must be converted to the underlying type before they can be implicitly converted to Variant
310+
if (paramSymbol.Type.TypeKind == TypeKind.Enum)
311+
{
312+
var underlyingType = ((INamedTypeSymbol)paramSymbol.Type).EnumUnderlyingType;
313+
source.Append($", ({underlyingType.FullQualifiedNameIncludeGlobal()}){paramSymbol.Name}");
314+
continue;
315+
}
316+
317+
source.Append($", {paramSymbol.Name}");
318+
}
319+
source.Append(");\n");
320+
source.Append(" }\n");
291321
}
292322

293323
// Generate RaiseGodotClassSignalCallbacks

modules/mono/editor/bindings_generator.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,6 +3104,46 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
31043104
}
31053105

31063106
p_output.append(CLOSE_BLOCK_L1);
3107+
3108+
// Generate On{EventName} method to raise the event.
3109+
if (!p_itype.is_singleton) {
3110+
p_output.append(MEMBER_BEGIN "protected void ");
3111+
p_output << "On" << p_isignal.proxy_name;
3112+
if (is_parameterless) {
3113+
p_output.append("()\n" OPEN_BLOCK_L1 INDENT2);
3114+
p_output << "EmitSignal(SignalName." << p_isignal.proxy_name << ");\n";
3115+
p_output.append(CLOSE_BLOCK_L1);
3116+
} else {
3117+
p_output.append("(");
3118+
3119+
StringBuilder cs_emitsignal_params;
3120+
3121+
int idx = 0;
3122+
for (const ArgumentInterface &iarg : p_isignal.arguments) {
3123+
const TypeInterface *arg_type = _get_type_or_null(iarg.type);
3124+
ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found.");
3125+
3126+
if (idx != 0) {
3127+
p_output << ", ";
3128+
cs_emitsignal_params << ", ";
3129+
}
3130+
3131+
p_output << arg_type->cs_type << " " << iarg.name;
3132+
3133+
if (arg_type->is_enum) {
3134+
cs_emitsignal_params << "(long)";
3135+
}
3136+
3137+
cs_emitsignal_params << iarg.name;
3138+
3139+
idx++;
3140+
}
3141+
3142+
p_output.append(")\n" OPEN_BLOCK_L1 INDENT2);
3143+
p_output << "EmitSignal(SignalName." << p_isignal.proxy_name << ", " << cs_emitsignal_params << ");\n";
3144+
p_output.append(CLOSE_BLOCK_L1);
3145+
}
3146+
}
31073147
}
31083148

31093149
return OK;

0 commit comments

Comments
 (0)