namespace Unity.VisualScripting
{
///
/// Sets the value of a field or property via reflection.
///
public sealed class SetMember : MemberUnit
{
public SetMember() : base() { }
public SetMember(Member member) : base(member) { }
///
/// Whether the target should be output to allow for chaining.
///
[Serialize]
[InspectableIf(nameof(supportsChaining))]
public bool chainable { get; set; }
[DoNotSerialize]
public bool supportsChaining => member.requiresTarget;
[DoNotSerialize]
[MemberFilter(Fields = true, Properties = true, ReadOnly = false)]
public Member setter
{
get => member;
set => member = value;
}
[DoNotSerialize]
[PortLabelHidden]
public ControlInput assign { get; private set; }
[DoNotSerialize]
[PortLabel("Value")]
[PortLabelHidden]
public ValueInput input { get; private set; }
[DoNotSerialize]
[PortLabel("Value")]
[PortLabelHidden]
public ValueOutput output { get; private set; }
///
/// The target object used when setting the value.
///
[DoNotSerialize]
[PortLabel("Target")]
[PortLabelHidden]
public ValueOutput targetOutput { get; private set; }
[DoNotSerialize]
[PortLabelHidden]
public ControlOutput assigned { get; private set; }
protected override void Definition()
{
base.Definition();
assign = ControlInput(nameof(assign), Assign);
assigned = ControlOutput(nameof(assigned));
Succession(assign, assigned);
if (supportsChaining && chainable)
{
targetOutput = ValueOutput(member.targetType, nameof(targetOutput));
Assignment(assign, targetOutput);
}
output = ValueOutput(member.type, nameof(output));
Assignment(assign, output);
if (member.requiresTarget)
{
Requirement(target, assign);
}
input = ValueInput(member.type, nameof(input));
Requirement(input, assign);
if (member.allowsNull)
{
input.AllowsNull();
}
input.SetDefaultValue(member.type.PseudoDefault());
}
protected override bool IsMemberValid(Member member)
{
return member.isAccessor && member.isSettable;
}
private object GetAndChainTarget(Flow flow)
{
if (member.requiresTarget)
{
var target = flow.GetValue(this.target, member.targetType);
if (supportsChaining && chainable)
{
flow.SetValue(targetOutput, target);
}
return target;
}
return null;
}
private ControlOutput Assign(Flow flow)
{
var target = GetAndChainTarget(flow);
var value = flow.GetConvertedValue(input);
flow.SetValue(output, member.Set(target, value));
return assigned;
}
#region Analytics
public override AnalyticsIdentifier GetAnalyticsIdentifier()
{
var aid = new AnalyticsIdentifier
{
Identifier = $"{member.targetType.FullName}.{member.name}(Set)",
Namespace = member.targetType.Namespace,
};
aid.Hashcode = aid.Identifier.GetHashCode();
return aid;
}
#endregion
}
}