A game about forced loneliness, made by TACStudios
1namespace Unity.VisualScripting
2{
3 /// <summary>
4 /// Sets the value of a field or property via reflection.
5 /// </summary>
6 public sealed class SetMember : MemberUnit
7 {
8 public SetMember() : base() { }
9
10 public SetMember(Member member) : base(member) { }
11
12 /// <summary>
13 /// Whether the target should be output to allow for chaining.
14 /// </summary>
15 [Serialize]
16 [InspectableIf(nameof(supportsChaining))]
17 public bool chainable { get; set; }
18
19 [DoNotSerialize]
20 public bool supportsChaining => member.requiresTarget;
21
22 [DoNotSerialize]
23 [MemberFilter(Fields = true, Properties = true, ReadOnly = false)]
24 public Member setter
25 {
26 get => member;
27 set => member = value;
28 }
29
30 [DoNotSerialize]
31 [PortLabelHidden]
32 public ControlInput assign { get; private set; }
33
34 [DoNotSerialize]
35 [PortLabel("Value")]
36 [PortLabelHidden]
37 public ValueInput input { get; private set; }
38
39 [DoNotSerialize]
40 [PortLabel("Value")]
41 [PortLabelHidden]
42 public ValueOutput output { get; private set; }
43
44 /// <summary>
45 /// The target object used when setting the value.
46 /// </summary>
47 [DoNotSerialize]
48 [PortLabel("Target")]
49 [PortLabelHidden]
50 public ValueOutput targetOutput { get; private set; }
51
52 [DoNotSerialize]
53 [PortLabelHidden]
54 public ControlOutput assigned { get; private set; }
55
56 protected override void Definition()
57 {
58 base.Definition();
59
60 assign = ControlInput(nameof(assign), Assign);
61 assigned = ControlOutput(nameof(assigned));
62 Succession(assign, assigned);
63
64 if (supportsChaining && chainable)
65 {
66 targetOutput = ValueOutput(member.targetType, nameof(targetOutput));
67 Assignment(assign, targetOutput);
68 }
69
70 output = ValueOutput(member.type, nameof(output));
71 Assignment(assign, output);
72
73 if (member.requiresTarget)
74 {
75 Requirement(target, assign);
76 }
77
78 input = ValueInput(member.type, nameof(input));
79 Requirement(input, assign);
80
81 if (member.allowsNull)
82 {
83 input.AllowsNull();
84 }
85
86 input.SetDefaultValue(member.type.PseudoDefault());
87 }
88
89 protected override bool IsMemberValid(Member member)
90 {
91 return member.isAccessor && member.isSettable;
92 }
93
94 private object GetAndChainTarget(Flow flow)
95 {
96 if (member.requiresTarget)
97 {
98 var target = flow.GetValue(this.target, member.targetType);
99
100 if (supportsChaining && chainable)
101 {
102 flow.SetValue(targetOutput, target);
103 }
104
105 return target;
106 }
107
108 return null;
109 }
110
111 private ControlOutput Assign(Flow flow)
112 {
113 var target = GetAndChainTarget(flow);
114
115 var value = flow.GetConvertedValue(input);
116
117 flow.SetValue(output, member.Set(target, value));
118
119 return assigned;
120 }
121
122 #region Analytics
123
124 public override AnalyticsIdentifier GetAnalyticsIdentifier()
125 {
126 var aid = new AnalyticsIdentifier
127 {
128 Identifier = $"{member.targetType.FullName}.{member.name}(Set)",
129 Namespace = member.targetType.Namespace,
130 };
131 aid.Hashcode = aid.Identifier.GetHashCode();
132 return aid;
133 }
134
135 #endregion
136 }
137}