diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs
new file mode 100644
index 000000000000..0c374169b9c5
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs
@@ -0,0 +1,10 @@
+namespace Godot.SourceGenerators.Sample
+{
+ public partial class AllReadOnly : GodotObject
+ {
+ public readonly string readonly_field = "foo";
+ public string readonly_auto_property { get; } = "foo";
+ public string readonly_property { get => "foo"; }
+ public string initonly_auto_property { get; init; }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs
new file mode 100644
index 000000000000..14a1802330b3
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Godot.SourceGenerators.Sample
+{
+ public partial class AllWriteOnly : GodotObject
+ {
+ bool writeonly_backing_field = false;
+ public bool writeonly_property { set => writeonly_backing_field = value; }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs
new file mode 100644
index 000000000000..f556bdc7e407
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs
@@ -0,0 +1,13 @@
+namespace Godot.SourceGenerators.Sample
+{
+ public partial class MixedReadonlyWriteOnly : GodotObject
+ {
+ public readonly string readonly_field = "foo";
+ public string readonly_auto_property { get; } = "foo";
+ public string readonly_property { get => "foo"; }
+ public string initonly_auto_property { get; init; }
+
+ bool writeonly_backing_field = false;
+ public bool writeonly_property { set => writeonly_backing_field = value; }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index b6ea4b8e88e3..5866db5144f9 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -303,11 +303,6 @@ namespace Godot.SourceGenerators
{
foreach (var property in properties)
{
- // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
- // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable.
- if (property.IsWriteOnly || property.IsReadOnly || property.SetMethod!.IsInitOnly)
- continue;
-
var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache);
if (marshalType == null)
@@ -325,10 +320,6 @@ namespace Godot.SourceGenerators
foreach (var field in fields)
{
// TODO: We should still restore read-only fields after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
- // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
- if (field.IsReadOnly)
- continue;
-
var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(field.Type, typeCache);
if (marshalType == null)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index 94d869671795..219ab7aa440c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -212,31 +212,37 @@ namespace Godot.SourceGenerators
}
// Generate GetGodotClassPropertyValue
+ bool allPropertiesAreWriteOnly = godotClassFields.Length == 0 && godotClassProperties.All(pi => pi.PropertySymbol.IsWriteOnly);
- source.Append(" /// \n");
- source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
- source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
- source.Append("out godot_variant value)\n {\n");
-
- isFirstEntry = true;
- foreach (var property in godotClassProperties)
+ if (!allPropertiesAreWriteOnly)
{
- GeneratePropertyGetter(property.PropertySymbol.Name,
- property.PropertySymbol.Type, property.Type, source, isFirstEntry);
- isFirstEntry = false;
+ source.Append(" /// \n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
+ source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
+ source.Append("out godot_variant value)\n {\n");
+
+ isFirstEntry = true;
+ foreach (var property in godotClassProperties)
+ {
+ if (property.PropertySymbol.IsWriteOnly)
+ continue;
+
+ GeneratePropertyGetter(property.PropertySymbol.Name,
+ property.PropertySymbol.Type, property.Type, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ foreach (var field in godotClassFields)
+ {
+ GeneratePropertyGetter(field.FieldSymbol.Name,
+ field.FieldSymbol.Type, field.Type, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n");
+
+ source.Append(" }\n");
}
-
- foreach (var field in godotClassFields)
- {
- GeneratePropertyGetter(field.FieldSymbol.Name,
- field.FieldSymbol.Type, field.Type, source, isFirstEntry);
- isFirstEntry = false;
- }
-
- source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n");
-
- source.Append(" }\n");
-
// Generate GetGodotPropertyList
const string dictionaryType = "global::System.Collections.Generic.List";
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index 231a7be021eb..9de99414b6b3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -119,8 +119,14 @@ namespace Godot.SourceGenerators
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
.Cast();
- var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
- var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
+ // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
+ // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable.
+ var godotClassProperties = propertySymbols.Where(property => !(property.IsReadOnly || property.IsWriteOnly || property.SetMethod!.IsInitOnly))
+ .WhereIsGodotCompatibleType(typeCache)
+ .ToArray();
+ var godotClassFields = fieldSymbols.Where(property => !property.IsReadOnly)
+ .WhereIsGodotCompatibleType(typeCache)
+ .ToArray();
var signalDelegateSymbols = members
.Where(s => s.Kind == SymbolKind.NamedType)