diff --git a/godot-mono-decomp/GodotMonoDecomp/GodotModuleDecompiler.cs b/godot-mono-decomp/GodotMonoDecomp/GodotModuleDecompiler.cs index 4bd1e341..d23fb01c 100644 --- a/godot-mono-decomp/GodotMonoDecomp/GodotModuleDecompiler.cs +++ b/godot-mono-decomp/GodotMonoDecomp/GodotModuleDecompiler.cs @@ -547,7 +547,7 @@ private string GetPathForType(ITypeDefinition? typeDef){ .Where(p => p.GetAttributes().Any(a => a.AttributeType.Name == "ExportAttribute")).ToList(); var fields = typeDef.Fields.Where(p => p.GetAttributes().Any(a => a.AttributeType.Name.Contains("Export"))) .ToList(); - var signals = GodotStuff.GetSignalsInClass(typeDef); + var signals = GodotStuff.GetSignalDelegatesInClass(typeDef); var syntaxTree = decompiler.DecompileTypes([type]); var isTool = typeDef.GetAttributes().FirstOrDefault(a => a.AttributeType.Name == "ToolAttribute") != null; @@ -618,7 +618,7 @@ private string GetPathForType(ITypeDefinition? typeDef){ args = invokeMethod.Parameters.Select(p => p.Name).ToArray(); argTypes = invokeMethod.Parameters.Select(p => p.Type.Name).ToArray(); } - signalsInfo.Add(new MethodInfo(signal.Name, "void", args, argTypes, false, false, false)); + signalsInfo.Add(new MethodInfo(signal.Name.Substring(0, signal.Name.Length - GodotStuff.SIGNAL_DELEGATE_SUFFIX.Length), "void", args, argTypes, false, false, false)); } foreach (var method in typeDef.Methods) diff --git a/godot-mono-decomp/GodotMonoDecomp/GodotStuff.cs b/godot-mono-decomp/GodotMonoDecomp/GodotStuff.cs index 75a691c8..8107ed7f 100644 --- a/godot-mono-decomp/GodotMonoDecomp/GodotStuff.cs +++ b/godot-mono-decomp/GodotMonoDecomp/GodotStuff.cs @@ -229,6 +229,10 @@ public void Run(AstNode rootNode, TransformContext context) public static class GodotStuff { public const string BACKING_FIELD_PREFIX = "backing_"; + public const string EMIT_SIGNAL_METHOD_PREFIX = "EmitSignal"; + + // While signal delegates are user-defined, Godot source generators require them to have this suffix. + public const string SIGNAL_DELEGATE_SUFFIX = "EventHandler"; public static DotNetCoreDepInfo? GetGodotSharpPackageDep(DotNetCoreDepInfo? depInfo) { @@ -344,7 +348,7 @@ public static Dictionary> CreateFileMap(Metad bool useNestedDirectoriesForNamespaces, ISet? godotClassHandles = null) { - var fileMap = new Dictionary>(StringComparer.OrdinalIgnoreCase); + Dictionary> fileMap = new Dictionary>(StringComparer.OrdinalIgnoreCase); godotClassHandles ??= new HashSet(); var canonicalPaths = new HashSet(); var canonicalHandles = new HashSet(); @@ -988,23 +992,10 @@ public static bool IsGodotPartialClass(ITypeDefinition entity) public static bool IsSignalDelegate(IEntity entity) { - var attributes = entity.GetAttributes(); - - // check if any of the attributes are "Signal" - if (attributes.Any(a => a.AttributeType.FullName == "Godot.SignalAttribute")) - { - return true; - } - - if (attributes.Any(a => a.AttributeType.Name == "SignalAttribute")) - { - return true; - } - - return false; + return entity.GetAttributes().Any(a => a.AttributeType.FullName == "Godot.SignalAttribute"); } - public static IEnumerable GetSignalsInClass(ITypeDefinition entity) + public static IEnumerable GetSignalDelegatesInClass(ITypeDefinition entity) { return entity.NestedTypes.Where(IsSignalDelegate); } @@ -1014,7 +1005,7 @@ public static bool IsBackingSignalDelegateField(IEntity entity) if (entity is IField field) { return field.Name.StartsWith(BACKING_FIELD_PREFIX) && field.DeclaringTypeDefinition != null && - GetSignalsInClass(field.DeclaringTypeDefinition).Contains(field.Type.GetDefinition()); + GetSignalDelegatesInClass(field.DeclaringTypeDefinition).Contains(field.Type.GetDefinition()); } return false; @@ -1140,13 +1131,17 @@ public static bool IsBannedGodotTypeMember(IEntity entity) return true; } - // TODO: fix this to check if the method ends with a signal name // if the method name is EmitSignal and it's a protected or private void method, then it's an auto-generated signal emitter if ( - method is { IsVirtual: false, Accessibility: Accessibility.Internal or Accessibility.Protected or Accessibility.ProtectedOrInternal or Accessibility.ProtectedAndInternal or Accessibility.Private } && - method.Name.StartsWith("EmitSignal") && method.ReturnType.FullName == "System.Void") + method is { IsVirtual: false, Accessibility: not (Accessibility.Public or Accessibility.None) } && + method.Name.StartsWith(EMIT_SIGNAL_METHOD_PREFIX) && method.ReturnType.FullName == "System.Void" && method.DeclaringTypeDefinition != null) { - return true; + var strippedName = method.Name.Substring(EMIT_SIGNAL_METHOD_PREFIX.Length); + if (GetSignalDelegatesInClass(method.DeclaringTypeDefinition).Any(d => d.Name == strippedName + SIGNAL_DELEGATE_SUFFIX)) + { + return true; + } + return false; } // auto-generated getter methods for properties of parent classes @@ -1154,7 +1149,7 @@ public static bool IsBannedGodotTypeMember(IEntity entity) break; case IEvent @event: - if (@event.DeclaringTypeDefinition != null && GetSignalsInClass(@event.DeclaringTypeDefinition).Contains(@event.ReturnType.GetDefinition()) && + if (@event.DeclaringTypeDefinition != null && GetSignalDelegatesInClass(@event.DeclaringTypeDefinition).Contains(@event.ReturnType.GetDefinition()) && GetBackingSignalDelegateFieldNames(@event.DeclaringTypeDefinition) .Contains(BACKING_FIELD_PREFIX + @event.Name)) { diff --git a/utility/cli_helper.h b/utility/cli_helper.h index 1b043f40..107e77ed 100644 --- a/utility/cli_helper.h +++ b/utility/cli_helper.h @@ -2,6 +2,10 @@ #include "core/templates/hash_set.h" #include "core/variant/variant.h" +#if defined(WAYLAND_ENABLED) +#include "core/os/os.h" +#endif + #include "modules/gdsdecomp/utility/gdre_version.gen.h" namespace gdre { @@ -24,6 +28,41 @@ static void print_version() { print_line("Godot RE Tools " + String(GDRE_VERSION)); } +static void remove_flag(List *args, const String &flag, bool has_value = false) { + for (List::Element *E = args->front(); E; E = E->next()) { + auto arg_and_value = E->get().split("=", true, 1); + if (arg_and_value[0] == flag) { + // if the flag has a value, get the next element and remove it + if (has_value && arg_and_value.size() == 1 && E->next()) { + args->erase(E->next()); + } + args->erase(E); + break; + } + } +} + +static void insert_flag_at_front(List *args, const String &flag, const String &value = "") { + for (List::Element *E = args->front(); E; E = E->next()) { + if (E->get().begins_with("-")) { + auto inserted = args->insert_before(E, flag); + if (!value.is_empty()) { + args->insert_after(inserted, value); + } + break; + } + } +} + +static void add_wayland_args(List *args) { +#if defined(WAYLAND_ENABLED) + if (!OS::get_singleton()->get_environment("WAYLAND_DISPLAY").is_empty()) { + remove_flag(args, "--display-driver", true); + insert_flag_at_front(args, "--display-driver", "wayland"); + } +#endif +} + // returns true if we should quit the program immediately static bool modify_cli_args(List *args, List *user_args) { Vector engine_args; @@ -74,6 +113,7 @@ static bool modify_cli_args(List *args, List *user_args) { break; } } + add_wayland_args(args); return false; } } //namespace gdre