using System; using System.Reflection; using UnityEngine; namespace Unity.VisualScripting { public sealed class MemberMetadata : Metadata { public enum Mode { Field, Property } public MemberMetadata(string name, BindingFlags bindingFlags, Metadata parent) : base(name, parent) { this.name = name; this.bindingFlags = bindingFlags; Reflect(true); } public string name { get; private set; } public BindingFlags bindingFlags { get; private set; } public MemberInfo member { get; private set; } public FieldInfo field { get; private set; } public PropertyInfo property { get; private set; } public Mode mode { get; private set; } protected override object rawValue { get { switch (mode) { case Mode.Field: return field.GetValueOptimized(parent.value); case Mode.Property: return property.GetValueOptimized(parent.value); default: throw new UnexpectedEnumValueException(mode); } } set { switch (mode) { case Mode.Field: field.SetValueOptimized(parent.value, value); break; case Mode.Property: property.SetValueOptimized(parent.value, value); break; default: throw new UnexpectedEnumValueException(mode); } } } protected override void OnParentValueTypeChange(Type previousType) { Reflect(false); } private void Reflect(bool throwOnFail) { field = parent.valueType.GetFieldUnambiguous(name, bindingFlags); if (field != null) { mode = Mode.Field; member = field; definedType = field.FieldType; field.Prewarm(); } else { property = parent.valueType.GetPropertyUnambiguous(name, bindingFlags); if (property != null) { mode = Mode.Property; member = property; definedType = property.PropertyType; property.Prewarm(); } } if (member == null) { if (throwOnFail) { throw new MissingMemberException($"Failed to find reflected member '{name}' on '{parent.valueType.CSharpName()}':\n{this}"); } else { Unlink(); return; } } // The text is created from class properties found by reflection. // So to mitigate the risk of breaking something that is looking for a 'macro' property, // instead of renaming the 'macro' property into 'graph asset' we are just changing the text. var text = member.HumanName(); if (text == "Macro") text = "Graph"; label = new GUIContent(text, member.Summary()); } public override Attribute[] GetCustomAttributes(bool inherit = true) { return Attribute.GetCustomAttributes(member, inherit); } public const BindingFlags DefaultBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; } }