Skip to content

Commit

Permalink
C#: Generate On{EventName} method to raise signal events
Browse files Browse the repository at this point in the history
  • Loading branch information
raulsntos committed Sep 23, 2024
1 parent da30673 commit 4b81107
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ partial class EventSignals
add => backing_MySignal += value;
remove => backing_MySignal -= value;
}
protected virtual void OnMySignal(string str, int num)
{
EmitSignal(SignalName.MySignal, str, num);
}
/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, NativeVariantPtrArgs args)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

// TODO:
// Determine a proper way to emit the signal.
// 'Emit(nameof(TheEvent))' creates a StringName every time and has the overhead of string marshaling.
// I haven't decided on the best option yet. Some possibilities:
// - Expose the generated StringName fields to the user, for use with 'Emit(...)'.
// - Generate a 'EmitSignalName' method for each event signal.

namespace Godot.SourceGenerators
{
[Generator]
Expand Down Expand Up @@ -288,6 +281,43 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType)
.Append(signalName)
.Append(" -= value;\n")
.Append("}\n");

// Generate On{EventName} method to raise the event

var invokeMethodSymbol = signalDelegate.InvokeMethodData.Method;
int paramCount = invokeMethodSymbol.Parameters.Length;

string raiseMethodModifiers = signalDelegate.DelegateSymbol.ContainingType.IsSealed ?
"private" :
"protected virtual";

source.Append($" {raiseMethodModifiers} void On{signalName}(");
for (int i = 0; i < paramCount; i++)
{
var paramSymbol = invokeMethodSymbol.Parameters[i];
source.Append($"{paramSymbol.Type.FullQualifiedNameIncludeGlobal()} {paramSymbol.Name}");
if (i < paramCount - 1)
{
source.Append(", ");
}
}
source.Append(")\n");
source.Append(" {\n");
source.Append($" EmitSignal(SignalName.{signalName}");
foreach (var paramSymbol in invokeMethodSymbol.Parameters)
{
// Enums must be converted to the underlying type before they can be implicitly converted to Variant
if (paramSymbol.Type.TypeKind == TypeKind.Enum)
{
var underlyingType = ((INamedTypeSymbol)paramSymbol.Type).EnumUnderlyingType;
source.Append($", ({underlyingType.FullQualifiedNameIncludeGlobal()}){paramSymbol.Name}");
continue;
}

source.Append($", {paramSymbol.Name}");
}
source.Append(");\n");
source.Append(" }\n");
}

// Generate RaiseGodotClassSignalCallbacks
Expand Down
40 changes: 40 additions & 0 deletions modules/mono/editor/bindings_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3104,6 +3104,46 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
}

p_output.append(CLOSE_BLOCK_L1);

// Generate On{EventName} method to raise the event.
if (!p_itype.is_singleton) {
p_output.append(MEMBER_BEGIN "protected virtual void ");
p_output << "On" << p_isignal.proxy_name;
if (is_parameterless) {
p_output.append("()\n" OPEN_BLOCK_L1 INDENT2);
p_output << "EmitSignal(SignalName." << p_isignal.proxy_name << ");\n";
p_output.append(CLOSE_BLOCK_L1);
} else {
p_output.append("(");

StringBuilder cs_emitsignal_params;

int idx = 0;
for (const ArgumentInterface &iarg : p_isignal.arguments) {
const TypeInterface *arg_type = _get_type_or_null(iarg.type);
ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found

if (idx != 0) {
p_output << ", ";
cs_emitsignal_params << ", ";
}

p_output << arg_type->cs_type << " " << iarg.name;

if (arg_type->is_enum) {
cs_emitsignal_params << "(long)";
}

cs_emitsignal_params << iarg.name;

idx++;
}

p_output.append(")\n" OPEN_BLOCK_L1 INDENT2);
p_output << "EmitSignal(SignalName." << p_isignal.proxy_name << ", " << cs_emitsignal_params << ");\n";
p_output.append(CLOSE_BLOCK_L1);
}
}
}

return OK;
Expand Down

0 comments on commit 4b81107

Please sign in to comment.