Replies: 3 comments
-
I'm also missing:
|
Beta Was this translation helpful? Give feedback.
-
I am currently working on a mock-up model of this. Right now I have the following attributes:
Please note that I have yet to properly implement Categories, Groups, and Subgroups, and almost all HintTypes Table of Contents
General OverviewThis new mock-up requires changing how Godot bridges between native and C#, and how Godot internally stores properties. The primary motivation of this was due to rewriting the same Tool over and over again when the editor has all the information that it needs to not load the script in the editor. Source Generator ChangesThe source generator for generating Example using Godot;
public partial class Foo : Node
{
[Export]
private int bar;
public void Baz()
{ }
} Example.Names.generated.cs using Godot;
partial class Foo
{
new public abstract class MethodNameStrings : Node.MethodNameStrings
{
public const string Baz = "Baz";
}
new public abstract class MethodName : Node.MethodName
{
public static readonly StringName Baz = MethodNameStrings.Baz;
}
new public abstract class PropertyNameStrings : Node.PropertyNameStrings
{
public const string bar = "bar";
}
new public abstract class PropertyName : Node.PropertyName
{
public static readonly StringName bar = PropertyNameStrings.bar;
}
new public abstract class SignalNameStrings : Node.SignalNameStrings
{
}
new public abstract class SignalName : Node.SignalName
{
}
} Bridge ChangesBridge/PropertyInfo.cs (Modified)using System.Collections.Generic;
namespace Godot.Bridge
{
public readonly struct PropertyInfo
{
public TypeInfo Type { get; init; }
public StringName Name { get; init; }
public StringName? DisplayNameOverride { get; init; }
public List<PropertyHideConditionInfo>? HideConditions { get; init; }
public PropertyRangeHintInfo? Range { get; init; }
public PropertyUsageFlags Usage { get; init; }
public bool Exported { get; init; }
public PropertyInfo(TypeInfo type, StringName name, PropertyUsageFlags usage, bool exported, PropertyRangeHintInfo? range = null, List<PropertyHideConditionInfo>? hideConditions = null)
: this(type, name, null, usage, exported, range, hideConditions)
{
}
public PropertyInfo(TypeInfo type, StringName name, StringName? displayNameOverride, PropertyUsageFlags usage, bool exported, PropertyRangeHintInfo? range = null, List<PropertyHideConditionInfo>? hideConditions = null)
{
this.Type = type;
this.Name = name;
this.DisplayNameOverride = displayNameOverride;
this.Usage = usage;
this.Exported = exported;
this.Range = range;
this.HideConditions = hideConditions;
}
}
} Bridge/TypeInfo.cs (New)Encapsulates type information. namespace Godot.Bridge
{
public readonly struct TypeInfo
{
public Variant.Type Type { get; init; }
public string? TypeString { get; init; }
public StringName? ClassName { get; init; }
public TypeInfo(Variant.Type type) : this(type, null, null)
{ }
public TypeInfo(Variant.Type type, string? typeString) : this(type, typeString, null)
{ }
public TypeInfo(Variant.Type type, string? typeString, StringName? className)
{
this.Type = type;
this.TypeString = typeString;
this.ClassName = className;
}
}
} Bridge/PropertyRangeHintInfo.cs (New)Stores the information for limiting a property to a range of values. namespace Godot.Bridge
{
public readonly struct PropertyRangeHintInfo
{
public Variant? MinValue { get; init; }
public Variant? MaxValue { get; init; }
public Variant? StepValue { get; init; }
public bool HideSlider { get; init; }
public bool AllowLess { get; init; }
public bool AllowGreater { get; init; }
public string? Suffix { get; init; }
public bool RadiansAsDegrees { get; init; }
public PropertyRangeHintInfo(Variant? minValue, Variant? maxValue, Variant? stepValue = null, bool hideSlider = false, bool allowLess = false, bool allowGreater = false, string? suffix = null, bool radiansAsDegrees = false)
{
this.MinValue = minValue;
this.MaxValue = maxValue;
this.StepValue = stepValue;
this.HideSlider = hideSlider;
this.AllowLess = allowLess;
this.AllowGreater = allowGreater;
this.Suffix = suffix;
this.RadiansAsDegrees = radiansAsDegrees;
}
}
} Bridge/PropertyHideConditionInfo.cs (New)Stores the condition to hide a property. namespace Godot.Bridge
{
public readonly struct PropertyHideConditionInfo
{
public StringName[] Properties { get; init; }
public string HintString { get; init; }
public Variant Value { get; init; }
public PropertyHideConditionInfo(Variant value, string hintString, params StringName[] properties)
{
this.Value = value;
this.Properties = properties;
this.HintString = hintString;
}
}
} Bridge/MethodInfo.cs (Modified)using System.Collections.Generic;
namespace Godot.Bridge
{
public readonly struct MethodInfo
{
public StringName Name { get; init; }
public TypeInfo ReturnVal { get; init; }
public MethodFlags Flags { get; init; }
public int Id { get; init; }
public List<ArgumentInfo>? Arguments { get; init; }
public MethodInfo(StringName name, TypeInfo returnVal, MethodFlags flags, List<ArgumentInfo>? arguments)
{
this.Id = 0;
this.Name = name;
this.ReturnVal = returnVal;
this.Flags = flags;
this.Arguments = arguments;
}
}
} Bridge/ArgumentInfo.cs (New)Stores all method-argument related information. namespace Godot.Bridge
{
public readonly struct ArgumentInfo
{
public StringName Name { get; init; }
public TypeInfo Type { get; init; }
public Variant DefaultValue { get; init; }
public ArgumentInfo(StringName name, TypeInfo type, Variant defaultValue)
{
this.Name = name;
this.Type = type;
this.DefaultValue = defaultValue;
}
}
} Attribute SpecificationsProperty AttributesPropertyAttribute.csusing System;
namespace Godot
{
public abstract class PropertyAttribute : Attribute
{
}
} HideIfAttribute.csusing System;
namespace Godot
{
/// <summary>
/// Hides the property in the Editor if any of the
/// specified properties are the specified value.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public sealed class HideIfAttribute : PropertyAttribute
{
public Variant Value { get; }
public StringName[] Properties { get; }
private HideIfAttribute(Variant value, string[] properties)
{
this.Value = value;
this.Properties = new StringName[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
this.Properties[i] = properties[i];
}
}
// right now we only support bool, but we could expand this
// in the future. Especially with the HintString support.
public HideIfAttribute(bool value, params string[] properties)
: this((Variant)value, properties)
{ }
}
} ExportRangeRestrictionAttribute.csnamespace Godot
{
public abstract class ExportRangeRestrictionAttribute : PropertyAttribute
{
public string? Suffix { get; init; }
public bool RadiansAsDegrees { get; init; }
}
} ExportMinAttribute.csusing System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class ExportMinAttribute : ExportRangeRestrictionAttribute
{
public Variant MinValue { get; }
public ExportMinAttribute(Variant minValue)
{
this.MinValue = minValue;
}
public ExportMinAttribute(byte minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(sbyte minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(short minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(ushort minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(int minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(uint minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(long minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(ulong minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(float minValue)
: this((Variant)minValue)
{ }
public ExportMinAttribute(double minValue)
: this((Variant)minValue)
{ }
}
} ExportMaxAttribute.csusing System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class ExportMaxAttribute : ExportRangeRestrictionAttribute
{
public Variant MaxValue { get; }
public ExportMaxAttribute(Variant maxValue)
{
this.MaxValue = maxValue;
}
public ExportMaxAttribute(byte maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(sbyte maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(short maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(ushort maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(int maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(uint maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(long maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(ulong maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(float maxValue)
: this((Variant)maxValue)
{ }
public ExportMaxAttribute(double maxValue)
: this((Variant)maxValue)
{ }
}
} ExportRangeAttribute.csusing System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class ExportRangeAttribute : ExportRangeRestrictionAttribute
{
public Variant MinValue { get; }
public Variant MaxValue { get; }
public Variant? StepValue { get; }
public bool HideSlider { get; init; }
public bool AllowGreater { get; init; }
public bool AllowLess { get; init; }
public ExportRangeAttribute(Variant minValue, Variant maxValue, Variant? stepValue = null)
{
this.MinValue = minValue;
this.MaxValue = maxValue;
this.StepValue = stepValue;
}
public ExportRangeAttribute(byte minValue, byte maxValue, byte? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(sbyte minValue, sbyte maxValue, sbyte? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(short minValue, short maxValue, short? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(ushort minValue, ushort maxValue, ushort? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(int minValue, int maxValue, int? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(uint minValue, uint maxValue, uint? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(long minValue, long maxValue, long? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(ulong minValue, ulong maxValue, ulong? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(float minValue, float maxValue, float? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
public ExportRangeAttribute(double minValue, double maxValue, double? stepValue = null)
: this((Variant)minValue, (Variant)maxValue, stepValue.HasValue ? (Variant?)stepValue.Value : null)
{ }
}
} Class AttributesClassAttribute.csusing System;
namespace Godot
{
/// <summary>
/// The base class for all class-related attributes.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public abstract class ClassAttribute : Attribute
{
}
} LoadInEditorAttribute.csusing System;
namespace Godot
{
/// <summary>
/// Loads instances of the Godot Object in the Editor.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class LoadInEditorAttribute : ClassAttribute
{
}
} DynamicPropertiesAttribute.csusing System;
namespace Godot
{
/// <summary>
/// Loads instances of the Godot Object in the Editor for
/// uses of Dynamic Properties using
/// <see cref="GodotObject._Get(StringName)">_Get</see>,
/// <see cref="GodotObject._Set(StringName, Variant)">_Set</see>,
/// <see cref="GodotObject._PropertyCanRevert(StringName)">_PropertyCanRevert</see>,
/// and
/// <see cref="GodotObject._PropertyGetRevert(StringName)">_PropertyGetRevert</see>.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class DynamicPropertiesAttribute : LoadInEditorAttribute
{
}
} ToolAttribute.csusing System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Class)]
public sealed class ToolAttribute : LoadInEditorAttribute
{
}
} Generic AttributesGodotIgnoreAttribute.csusing System;
namespace Godot
{
/// <summary>
/// Marks a property or a method of a Godot Object as
/// ignored.
/// </summary>
/// <remarks>
/// <para>
/// Ignored properties are not serialized, wont be
/// displayed in the Editor, and cannot be accessed from
/// <see cref="GodotObject.Get(StringName)">Get</see>
/// or
/// <see cref="GodotObject.Set(StringName, Variant)">Set</see>.
/// </para>
/// <para>
/// Ignored methods are not accessible to signals, and
/// cannot be called from
/// <see cref="GodotObject.Call(StringName, Variant[])">Call</see>,
/// <see cref="GodotObject.CallDeferred(StringName, Variant[])">CallDeferred</see>,
/// or
/// <see cref="GodotObject.Callv(StringName, Variant[])">Callv</see>.
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]
public sealed class GodotIgnoreAttribute : Attribute
{
}
} GodotMemberNameAttribute.csusing System;
namespace Godot
{
/// <summary>
/// Changes the name of the annotated property or method of
/// a Godot Object internally used in Godot.
/// </summary>
/// <remarks>
/// <para>
/// For a property, the name specified will need to be used
/// instead of the name of the property in
/// <see cref="GodotObject.Get(StringName)">Get</see>,
/// <see cref="GodotObject.Set(StringName, Variant)">Set</see>,
/// <see cref="GodotObject.PropertyCanRevert(StringName)">PropertyCanRevert</see>,
/// and
/// <see cref="GodotObject.PropertyGetRevert(StringName)">PropertyGetRevert</see>.
/// The new name will be accessible in the
/// <c>PropertyNameStrings</c> and <c>PropertyName</c>
/// generated classes.
/// </para>
/// <para>
/// For a method, the name specified will need to be used
/// instead of the name of the method in
/// <see cref="GodotObject.Call(StringName, Variant[])">Call</see>,
/// <see cref="GodotObject.CallDeferred(StringName, Variant[])">CallDeferred</see>,
/// and
/// <see cref="GodotObject.Callv(StringName, Variant[])">Callv</see>.
/// The new name will be accessible in the
/// <c>MethodNameStrings</c> and <c>MethodName</c>
/// generated classes.
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]
public class GodotMemberNameAttribute : Attribute
{
public string Name { get; }
public GodotMemberNameAttribute(string name)
{
this.Name = name;
}
}
} ExamplesHideIfAttribute ExamplesExample 1The following example displays a using Godot;
using System;
[GlobalClass]
public sealed partial class HideIfExample1 : Resource
{
[Export]
private bool requires_key;
[Export]
[HideIf(false, PropertyNameStrings.requires_key)]
private Resource[] valid_keys = Array.Empty<Resource>();
} Name Source Generator Output using Godot;
partial class HideIfExample1
{
new public abstract class MethodNameStrings : Resource.MethodNameStrings
{
}
new public abstract class MethodName : Resource.MethodName
{
}
new public abstract class PropertyNameStrings : Resource.PropertyNameStrings
{
public const string requires_key = "requires_key";
public const string valid_keys = "valid_keys";
}
new public abstract class PropertyName : Resource.PropertyName
{
public static readonly StringName requires_key = PropertyNameStrings.requires_key;
public static readonly StringName valid_keys = PropertyNameStrings.valid_keys;
}
new public abstract class SignalNameStrings : Resource.SignalNameStrings
{
}
new public abstract class SignalName : Resource.SignalName
{
}
} Native Interop Source Generator Output using Godot.NativeInterop;
using Godot.Bridge;
using Godot;
using System.Collections.Generic;
partial class HideIfExample1
{
protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
if (name == HideIfExample1.PropertyName.requires_key)
{
value = VariantUtils.CreateFrom<bool>(this.requires_key);
return true;
}
else if (name == HideIfExample1.PropertyName.valid_keys)
{
GodotObject[] v = this.valid_keys;
value = VariantUtils.CreateFromSystemArrayOfGodotObject(this.valid_keys);
return true;
}
else
{
return base.GetGodotClassPropertyValue(in name, out value);
}
}
protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
if (name == HideIfExample1.PropertyName.requires_key)
{
this.requires_key = VariantUtils.ConvertTo<bool>(in value);
return true;
}
else if (name == HideIfExample1.PropertyName.valid_keys)
{
this.valid_keys = VariantUtils.ConvertToSystemArrayOfGodotObject<Resource>(in value)!;
return true;
}
else
{
return base.SetGodotClassPropertyValue(in name, in value);
}
}
protected override void SaveGodotObjectData(GodotSerializationInfo info)
{
base.SaveGodotObjectData(info);
info.AddProperty(HideIfExample1.PropertyName.requires_key, Variant.From<bool>(this.requires_key));
info.AddProperty(HideIfExample1.PropertyName.valid_keys, Variant.From<GodotObject[]>(this.valid_keys));
}
protected override void RestoreGodotObjectData(GodotSerializationInfo info)
{
base.RestoreGodotObjectData(info);
if (info.TryGetProperty(HideIfExample1.PropertyName.requires_key, out Variant value__requires_key))
{
this.requires_key = value__requires_key.As<bool>();
}
if (info.TryGetProperty(HideIfExample1.PropertyName.valid_keys, out Variant value__valid_keys))
{
this.valid_keys = value__requires_key.AsGodotObjectArray<Resource>()!;
}
}
internal static Dictionary<StringName, Variant> GetGodotPropertyDefaultValues()
{
Dictionary<StringName, Variant> values = new(2);
bool defaultvalue__requires_key = false;
Resource[] defaultvalue__valid_keys = System.Array.Empty<Resource>();
values.Add(HideIfExample1.PropertyName.requires_key, Variant.From<bool>(defaultvalue__requires_key));
values.Add(HideIfExample1.PropertyName.valid_keys, Variant.From<GodotObject[]>(defaultvalue__valid_keys));
return values;
}
internal static List<PropertyInfo> GetGodotPropertyList()
{
return new List<PropertyInfo>()
{
new PropertyInfo(new TypeInfo(Variant.Type.Bool), HideIfExample1.PropertyName.requires_key, PropertyUsageFlags.Storage | PropertyUsageFlags.Editor | PropertyUsageFlags.ScriptVariable, true),
new PropertyInfo(new TypeInfo(Variant.Type.Array, "24:Resource"), HideIfExample1.PropertyName.valid_keys, PropertyUsageFlags.Storage | PropertyUsageFlags.Editor | PropertyUsageFlags.ScriptVariable, true, hideConditions: new List<PropertyHideConditionInfo>()
{
new PropertyHideConditionInfo(false, "", HideIfExample1.PropertyName.requires_key)
})
};
}
} ExportMinAttribute ExamplesExample 1The following example clamps a time value to be at least 0, and adds a "secs" suffix: using Godot;
[GlobalClass]
public partial class ExportRangeMinExample1 : Node
{
[Export]
[ExportMin(0, Suffix = "secs")]
private float m_time;
} Name Source Generator Output using Godot;
partial class ExportRangeMinExample1
{
new public abstract class MethodNameStrings : Node.MethodNameStrings
{
}
new public abstract class MethodName : Node.MethodName
{
}
new public abstract class PropertyNameStrings : Node.PropertyNameStrings
{
public const string m_time = "m_time";
}
new public abstract class PropertyName : Node.PropertyName
{
public static readonly StringName m_time = PropertyNameStrings.m_time;
}
new public abstract class SignalNameStrings : Node.SignalNameStrings
{
}
new public abstract class SignalName : Resource.SignalName
{
}
} Native Interop Source Generator Output using Godot;
using Godot.Bridge;
using Godot.NativeInterop;
using System.Collections.Generic;
partial class ExportRangeMinExample1
{
protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
if (name == ExportRangeMinExample1.PropertyName.m_time)
{
value = VariantUtils.CreateFrom<float>(this.m_time);
return true;
}
else
{
return base.GetGodotClassPropertyValue(in name, out value);
}
}
protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
if (name == ExportRangeMinExample1.PropertyName.m_time)
{
// note: look how setting the value is clamped
// here!
this.m_time = System.Math.Max(VariantUtils.ConvertTo<float>(in value), 0);
return true;
}
else
{
return base.SetGodotClassPropertyValue(in name, in value);
}
}
protected override void SaveGodotObjectData(GodotSerializationInfo info)
{
base.SaveGodotObjectData(info);
info.AddProperty(ExportRangeMinExample1.PropertyName.m_time, Variant.From<float>(this.m_time));
}
protected override void RestoreGodotObjectData(GodotSerializationInfo info)
{
base.RestoreGodotObjectData(info);
if (info.TryGetProperty(ExportRangeMinExample1.PropertyName.m_time, out Variant value__m_time))
{
// note: look how setting the value is not
// clamped here!
this.m_time = value__m_time.As<float>();
}
}
internal static Dictionary<StringName, Variant> GetGodotPropertyDefaultValues()
{
Dictionary<StringName, Variant> values = new(1);
float defaultvalue__m_time = 0f;
values.Add(ExportRangeMinExample1.PropertyName.m_time, Variant.From<float>(defaultvalue__m_time));
return values;
}
internal static List<PropertyInfo> GetGodotPropertyList()
{
return new List<PropertyInfo>()
{
new PropertyInfo(new TypeInfo(Variant.Type.Float), ExportRangeMinExample1.PropertyName.m_time, PropertyUsageFlags.Storage | PropertyUsageFlags.Editor | PropertyUsageFlags.ScriptVariable, true, range: new PropertyRangeHintInfo(
Variant.From<float>(0), null, suffix: "Secs"
))
};
}
} GodotIgnoreAttribute ExamplesExample 1The following example is the same example used in Example 1 of using Godot;
[GlobalClass]
public partial class GodotIgnorePropertyExample1 : Node
{
[GodotIgnore]
// [Export] Uncomment for error: (id): Cannot exported an ignored member
private float m_timeSecs;
[Export]
public float Time
{
get => this.m_timeSecs;
set
{
if (float.IsNaN(value)) return;
this.m_timeSecs = Mathf.Max(value, 0);
}
}
} Name Source Generator Output using Godot;
partial class GodotIgnorePropertyExample1
{
new public abstract class MethodNameStrings : Node.MethodNameStrings
{
}
new public abstract class MethodName : Node.MethodName
{
}
new public abstract class PropertyNameStrings : Node.PropertyNameStrings
{
// note: how m_timeSecs is completely missing
// because it was ignored.
public const string Time = "Time";
}
new public abstract class PropertyName : Node.PropertyName
{
public static readonly StringName Time = PropertyNameStrings.Time;
}
new public abstract class SignalNameStrings : Node.SignalNameStrings
{
}
new public abstract class SignalName : Resource.SignalName
{
}
} Native Interop Source Generator Output using Godot;
using Godot.Bridge;
using Godot.NativeInterop;
using System.Collections.Generic;
partial class GodotIgnorePropertyExample1
{
protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
if (name == GodotIgnorePropertyExample1.PropertyName.Time)
{
value = VariantUtils.CreateFrom<float>(this.Time);
return true;
}
else
{
return base.GetGodotClassPropertyValue(in name, out value);
}
}
protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
if (name == GodotIgnorePropertyExample1.PropertyName.Time)
{
this.Time = VariantUtils.ConvertTo<float>(in value);
return true;
}
else
{
return base.SetGodotClassPropertyValue(in name, in value);
}
}
protected override void SaveGodotObjectData(GodotSerializationInfo info)
{
base.SaveGodotObjectData(info);
info.AddProperty(GodotIgnorePropertyExample1.PropertyName.Time, Variant.From<float>(this.Time));
}
protected override void RestoreGodotObjectData(GodotSerializationInfo info)
{
base.RestoreGodotObjectData(info);
if (info.TryGetProperty(GodotIgnorePropertyExample1.PropertyName.Time, out Variant value__Time))
{
this.Time = value__Time.As<float>();
}
}
internal static Dictionary<StringName, Variant> GetGodotPropertyDefaultValues()
{
Dictionary<StringName, Variant> values = new(1);
float defaultvalue__Time = 0f;
values.Add(GodotIgnorePropertyExample1.PropertyName.Time, Variant.From<float>(defaultvalue__Time));
return values;
}
internal static List<PropertyInfo> GetGodotPropertyList()
{
return new List<PropertyInfo>()
{
new PropertyInfo(new TypeInfo(Variant.Type.Float), GodotIgnorePropertyExample1.PropertyName.Time, PropertyUsageFlags.Storage | PropertyUsageFlags.Editor | PropertyUsageFlags.ScriptVariable, true)
};
}
} GodotMemberNameAttribute ExamplesExample 1The following example renames a public property to godot's preferred snake_case specification using Godot;
[GlobalClass]
public sealed partial class GodotMemberNameExample1 : Resource
{
private float m_timeSecs;
// note: clamping via the Mathf.Max
// isn't run at all due the script not
// being loaded in the Editor.
//
// However at run time, the value is properly
// clamped as it gets assigned when the resource
// gets loaded.
[Export]
[GodotMemberName("time")]
public float Time
{
get => this.m_timeSecs;
set
{
if (float.IsNaN(value)) return;
this.m_timeSecs = Mathf.Max(value, 0);
}
}
} Name Source Generator Output using Godot;
partial class GodotMemberNameExample1
{
new public abstract class MethodNameStrings : Resource.MethodNameStrings
{
}
new public abstract class MethodName : Resource.MethodName
{
}
new public abstract class PropertyNameStrings : Resource.PropertyNameStrings
{
public const string m_timeSecs = "m_timeSecs";
// note: how the value of this is not the same as
// the name of it. This is due to
// GodotMemberNameAttribute. The value of this
// property will be the Name value of the
// GodotMemberNameAttribute.
public const string Time = "time";
}
new public abstract class PropertyName : Resource.PropertyName
{
public static readonly StringName m_timeSecs = PropertyNameStrings.m_timeSecs;
public static readonly StringName Time = PropertyNameStrings.Time;
}
new public abstract class SignalNameStrings : Resource.SignalNameStrings
{
}
new public abstract class SignalName : Resource.SignalName
{
}
} Native Interop Source Generator Output using Godot;
using Godot.Bridge;
using Godot.NativeInterop;
using System.Collections.Generic;
partial class GodotMemberNameExample1
{
protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
{
if (name == GodotMemberNameExample1.PropertyName.m_timeSecs)
{
value = VariantUtils.CreateFrom<float>(this.m_timeSecs);
return true;
}
else if (name == GodotMemberNameExample1.PropertyName.Time)
{
value = VariantUtils.CreateFrom<float>(this.Time);
return true;
}
else
{
return base.GetGodotClassPropertyValue(in name, out value);
}
}
protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
{
if (name == GodotMemberNameExample1.PropertyName.m_timeSecs)
{
this.m_timeSecs = VariantUtils.ConvertTo<float>(in value);
return true;
}
else if (name == GodotMemberNameExample1.PropertyName.Time)
{
this.Time = VariantUtils.ConvertTo<float>(in value);
return true;
}
else
{
return base.SetGodotClassPropertyValue(in name, in value);
}
}
protected override void SaveGodotObjectData(GodotSerializationInfo info)
{
base.SaveGodotObjectData(info);
info.AddProperty(GodotMemberNameExample1.PropertyName.m_timeSecs, Variant.From<float>(this.m_timeSecs));
info.AddProperty(GodotMemberNameExample1.PropertyName.Time, Variant.From<float>(this.Time));
}
protected override void RestoreGodotObjectData(GodotSerializationInfo info)
{
base.RestoreGodotObjectData(info);
if (info.TryGetProperty(GodotMemberNameExample1.PropertyName.m_timeSecs, out Variant value__m_timeSecs))
{
this.m_timeSecs = value__m_timeSecs.As<float>();
}
if (info.TryGetProperty(GodotMemberNameExample1.PropertyName.Time, out Variant value__Time))
{
this.Time = value__Time.As<float>();
}
}
internal static Dictionary<StringName, Variant> GetGodotPropertyDefaultValues()
{
Dictionary<StringName, Variant> values = new(2);
float defaultvalue__m_timeSecs = 0f;
float defaultvalue__Time = 0f;
values.Add(GodotMemberNameExample1.PropertyName.m_timeSecs, Variant.From<float>(defaultvalue__m_timeSecs));
values.Add(GodotMemberNameExample1.PropertyName.Time, Variant.From<float>(defaultvalue__Time));
return values;
}
internal static List<PropertyInfo> GetGodotPropertyList()
{
return new List<PropertyInfo>()
{
new PropertyInfo(new TypeInfo(Variant.Type.Float), GodotMemberNameExample1.PropertyName.m_timeSecs, PropertyUsageFlags.ScriptVariable, false),
new PropertyInfo(new TypeInfo(Variant.Type.Float), GodotMemberNameExample1.PropertyName.Time, PropertyUsageFlags.Storage | PropertyUsageFlags.Editor | PropertyUsageFlags.ScriptVariable, true)
};
}
} |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Coming from Unity, there are a lot of missing (and imo key) GUI visualizations that I feel could help improve the editor experience. These are some improvements I could think of off the top of my head.
List of GUI-related attributes that can be implemented to improve the editor:
RangeAttribute
- Although (somewhat) specified onExportAttribute
, keeping it separate makes it more clearer for meTextAreaAttribute
- Makes a string field appear as a massive text area with a scroll bar.DefaultValueAttribute
- Default value when adding the script or when resetting it to default value via context menuDescriptionAttribute
- I know that there's already an attribute for this onExportAttribute
, but this would make it clearerDisplayNameAttribute
- Changes the name displayed in the editorShowInEditorAttribute
- Behaves likeExportAttribute
, but isn't serialized at all, rather is shown as read-only in the editor (useful for debugging)SerializeObjectAttribute
- For specifying a class/object as serializable. It would be nice as I would like to create tiny utility classes/structs that shouldn't be a separate game resource. Understandable if not possible, although would be niceSpaceAttribute
- Allows putting space between exported fields.Additional improvements:
List<T>
(should be serialized as T[])Current Specification
Beta Was this translation helpful? Give feedback.
All reactions