You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-12 13:20:55 +00:00
C#: Lookup signals and methods in Get method
Allows to retrieve `Callable`s and `Signal`s using `Get` like it works in GDScript.
This commit is contained in:
@@ -272,6 +272,25 @@ namespace Godot.SourceGenerators
|
|||||||
source.Append(" }\n");
|
source.Append(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate HasGodotClassSignal
|
||||||
|
|
||||||
|
if (godotSignalDelegates.Count > 0)
|
||||||
|
{
|
||||||
|
source.Append(
|
||||||
|
" protected override bool HasGodotClassSignal(in godot_string_name signal)\n {\n");
|
||||||
|
|
||||||
|
bool isFirstEntry = true;
|
||||||
|
foreach (var signal in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
GenerateHasSignalEntry(signal.Name, source, isFirstEntry);
|
||||||
|
isFirstEntry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" return base.HasGodotClassSignal(signal);\n");
|
||||||
|
|
||||||
|
source.Append(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
source.Append("}\n"); // partial class
|
source.Append("}\n"); // partial class
|
||||||
|
|
||||||
if (isInnerClass)
|
if (isInnerClass)
|
||||||
@@ -397,6 +416,20 @@ namespace Godot.SourceGenerators
|
|||||||
PropertyHint.None, string.Empty, propUsage, exported: false);
|
PropertyHint.None, string.Empty, propUsage, exported: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void GenerateHasSignalEntry(
|
||||||
|
string signalName,
|
||||||
|
StringBuilder source,
|
||||||
|
bool isFirstEntry
|
||||||
|
)
|
||||||
|
{
|
||||||
|
source.Append(" ");
|
||||||
|
if (!isFirstEntry)
|
||||||
|
source.Append("else ");
|
||||||
|
source.Append("if (signal == SignalName.");
|
||||||
|
source.Append(signalName);
|
||||||
|
source.Append(") {\n return true;\n }\n");
|
||||||
|
}
|
||||||
|
|
||||||
private static void GenerateSignalEventInvoker(
|
private static void GenerateSignalEventInvoker(
|
||||||
GodotSignalDelegateData signal,
|
GodotSignalDelegateData signal,
|
||||||
StringBuilder source
|
StringBuilder source
|
||||||
|
|||||||
@@ -84,10 +84,12 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
|
|||||||
#define CS_PROPERTY_SINGLETON "Singleton"
|
#define CS_PROPERTY_SINGLETON "Singleton"
|
||||||
#define CS_METHOD_INVOKE_GODOT_CLASS_METHOD "InvokeGodotClassMethod"
|
#define CS_METHOD_INVOKE_GODOT_CLASS_METHOD "InvokeGodotClassMethod"
|
||||||
#define CS_METHOD_HAS_GODOT_CLASS_METHOD "HasGodotClassMethod"
|
#define CS_METHOD_HAS_GODOT_CLASS_METHOD "HasGodotClassMethod"
|
||||||
|
#define CS_METHOD_HAS_GODOT_CLASS_SIGNAL "HasGodotClassSignal"
|
||||||
|
|
||||||
#define CS_STATIC_FIELD_NATIVE_CTOR "NativeCtor"
|
#define CS_STATIC_FIELD_NATIVE_CTOR "NativeCtor"
|
||||||
#define CS_STATIC_FIELD_METHOD_BIND_PREFIX "MethodBind"
|
#define CS_STATIC_FIELD_METHOD_BIND_PREFIX "MethodBind"
|
||||||
#define CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX "MethodProxyName_"
|
#define CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX "MethodProxyName_"
|
||||||
|
#define CS_STATIC_FIELD_SIGNAL_PROXY_NAME_PREFIX "SignalProxyName_"
|
||||||
|
|
||||||
#define ICALL_PREFIX "godot_icall_"
|
#define ICALL_PREFIX "godot_icall_"
|
||||||
#define ICALL_CLASSDB_GET_METHOD "ClassDB_get_method"
|
#define ICALL_CLASSDB_GET_METHOD "ClassDB_get_method"
|
||||||
@@ -1608,6 +1610,16 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||||||
<< " = \"" << imethod.proxy_name << "\";\n";
|
<< " = \"" << imethod.proxy_name << "\";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate signal names cache fields
|
||||||
|
|
||||||
|
for (const SignalInterface &isignal : itype.signals_) {
|
||||||
|
output << MEMBER_BEGIN "// ReSharper disable once InconsistentNaming\n"
|
||||||
|
<< INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
|
||||||
|
<< INDENT1 "private static readonly StringName "
|
||||||
|
<< CS_STATIC_FIELD_SIGNAL_PROXY_NAME_PREFIX << isignal.name
|
||||||
|
<< " = \"" << isignal.proxy_name << "\";\n";
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Only generate HasGodotClassMethod and InvokeGodotClassMethod if there's any method
|
// TODO: Only generate HasGodotClassMethod and InvokeGodotClassMethod if there's any method
|
||||||
|
|
||||||
// Generate InvokeGodotClassMethod
|
// Generate InvokeGodotClassMethod
|
||||||
@@ -1721,6 +1733,34 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||||||
}
|
}
|
||||||
|
|
||||||
output << INDENT1 "}\n";
|
output << INDENT1 "}\n";
|
||||||
|
|
||||||
|
// Generate HasGodotClassSignal
|
||||||
|
|
||||||
|
output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
|
||||||
|
<< " bool " CS_METHOD_HAS_GODOT_CLASS_SIGNAL "(in godot_string_name signal)\n"
|
||||||
|
<< INDENT1 "{\n";
|
||||||
|
|
||||||
|
for (const SignalInterface &isignal : itype.signals_) {
|
||||||
|
// We check for native names (snake_case). If we detect one, we call HasGodotClassSignal
|
||||||
|
// again, but this time with the respective proxy name (PascalCase). It's the job of
|
||||||
|
// user derived classes to override the method and check for those. Our C# source
|
||||||
|
// generators take care of generating those override methods.
|
||||||
|
output << INDENT2 "if (signal == SignalName." << isignal.proxy_name
|
||||||
|
<< ")\n" INDENT2 "{\n"
|
||||||
|
<< INDENT3 "if (" CS_METHOD_HAS_GODOT_CLASS_SIGNAL "("
|
||||||
|
<< CS_STATIC_FIELD_SIGNAL_PROXY_NAME_PREFIX << isignal.name
|
||||||
|
<< ".NativeValue.DangerousSelfRef))\n" INDENT3 "{\n"
|
||||||
|
<< INDENT4 "return true;\n"
|
||||||
|
<< INDENT3 "}\n" INDENT2 "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_derived_type) {
|
||||||
|
output << INDENT2 "return base." CS_METHOD_HAS_GODOT_CLASS_SIGNAL "(signal);\n";
|
||||||
|
} else {
|
||||||
|
output << INDENT2 "return false;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
output << INDENT1 "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Generate StringName for all class members
|
//Generate StringName for all class members
|
||||||
|
|||||||
@@ -84,12 +84,29 @@ namespace Godot.Bridge
|
|||||||
if (godotObject == null)
|
if (godotObject == null)
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
// Properties
|
||||||
if (godotObject.GetGodotClassPropertyValue(CustomUnsafe.AsRef(name), out godot_variant outRetValue))
|
if (godotObject.GetGodotClassPropertyValue(CustomUnsafe.AsRef(name), out godot_variant outRetValue))
|
||||||
{
|
{
|
||||||
*outRet = outRetValue;
|
*outRet = outRetValue;
|
||||||
return godot_bool.True;
|
return godot_bool.True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signals
|
||||||
|
if (godotObject.HasGodotClassSignal(CustomUnsafe.AsRef(name)))
|
||||||
|
{
|
||||||
|
godot_signal signal = new godot_signal(*name, godotObject.GetInstanceId());
|
||||||
|
*outRet = VariantUtils.CreateFromSignalTakingOwnershipOfDisposableValue(signal);
|
||||||
|
return godot_bool.True;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
if (godotObject.HasGodotClassMethod(CustomUnsafe.AsRef(name)))
|
||||||
|
{
|
||||||
|
godot_callable method = new godot_callable(*name, godotObject.GetInstanceId());
|
||||||
|
*outRet = VariantUtils.CreateFromCallableTakingOwnershipOfDisposableValue(method);
|
||||||
|
return godot_bool.True;
|
||||||
|
}
|
||||||
|
|
||||||
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
|
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
|
||||||
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
|
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user