File size: 3,775 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
namespace Unity.VisualScripting
{
    /// <summary>
    /// Sets the value of a field or property via reflection.
    /// </summary>
    public sealed class SetMember : MemberUnit
    {
        public SetMember() : base() { }

        public SetMember(Member member) : base(member) { }

        /// <summary>
        /// Whether the target should be output to allow for chaining.
        /// </summary>
        [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; }

        /// <summary>
        /// The target object used when setting the value.
        /// </summary>
        [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
    }
}