A game about forced loneliness, made by TACStudios
1/*
2using System;
3using System.Collections.Generic;
4using System.Collections.ObjectModel;
5using System.Linq;
6using Unity.VisualScripting;
7using UnityEngine;
8using UnityObject = UnityEngine.Object;
9
10namespace Unity.VisualScripting
11{
12 [Inspector(typeof(MemberInvocation))]
13 public sealed class MemberInvocationInspector : InvocationInspector
14 {
15 public MemberInvocationInspector(Metadata metadata) : base(metadata) { }
16
17 public override void Initialize()
18 {
19 base.Initialize();
20
21 memberInspector = memberMetadata.Inspector<MemberManipulatorInspector>();
22 memberInspector.direction = (ActionDirection)directionMetadata.value;
23
24 referenceInspectors = new Dictionary<Metadata, Inspector>();
25 memberFilter = metadata.GetAttribute<MemberFilter>() ?? MemberFilter.Any;
26 memberTypeFilter = metadata.GetAttribute<TypeFilter>();
27 memberMetadata.valueChanged += previousMember => ReflectMember(false);
28 }
29
30 private MemberManipulatorInspector memberInspector;
31
32 private Dictionary<Metadata, Inspector> referenceInspectors;
33
34 private IFuzzyOptionTree GetMemberOptions()
35 {
36 return new MemberOptionTree(typeSet, memberFilter, memberTypeFilter, (ActionDirection)directionMetadata.value);
37 }
38
39 #region Metadata
40
41 private Metadata memberMetadata => metadata[nameof(MemberInvocation.member)];
42
43 private Metadata directionMetadata => metadata[nameof(MemberInvocation.direction)];
44
45 private Metadata targetMetadata => metadata[nameof(MemberInvocation.target)];
46
47 #endregion
48
49 #region Settings
50
51 private ReadOnlyCollection<Type> _typeSet;
52
53 private MemberFilter _memberFilter;
54
55 private TypeFilter _memberTypeFilter;
56
57 public override Type expectedType
58 {
59 get
60 {
61 return base.expectedType;
62 }
63 set
64 {
65 base.expectedType = value;
66 memberTypeFilter = value != null ? new TypeFilter(TypesMatching.Any, value) : null;
67 }
68 }
69
70 public ReadOnlyCollection<Type> typeSet
71 {
72 get
73 {
74 return _typeSet;
75 }
76 set
77 {
78 _typeSet = value;
79 memberInspector.typeSet = value;
80 }
81 }
82
83 public MemberFilter memberFilter
84 {
85 get
86 {
87 return _memberFilter;
88 }
89 set
90 {
91 _memberFilter = value;
92 memberInspector.memberFilter = value;
93 }
94 }
95
96 public TypeFilter memberTypeFilter
97 {
98 get
99 {
100 return _memberTypeFilter;
101 }
102 set
103 {
104 _memberTypeFilter = value;
105 memberInspector.memberTypeFilter = value;
106 }
107 }
108
109 #endregion
110
111 #region Reflection
112
113 private bool reflectionSucceeded;
114
115 private void ReflectMember(bool reset)
116 {
117 memberMetadata.DisposeChildren();
118
119 var member = (Member)memberMetadata.value;
120
121 // Clear the metadata tree and optionally the arguments
122
123 if (reset)
124 {
125 targetMetadata.value = null;
126 argumentsMetadata.Clear();
127 }
128
129 referenceInspectors.Clear();
130
131 // Attempt to reflect the member
132
133 reflectionSucceeded = false;
134
135 if (member != null)
136 {
137 try
138 {
139 member.EnsureReflected();
140 reflectionSucceeded = true;
141 }
142 catch { }
143 }
144
145 if (!reflectionSucceeded)
146 {
147 return;
148 }
149
150 // Create the metadata tree and optionally assign default arguments
151
152 if (reset)
153 {
154 IExpression target;
155
156 if (member.requiresTarget)
157 {
158 if (ComponentHolderProtocol.IsComponentHolderType(member.targetType) && metadata.UnityObjectAncestor() != null)
159 {
160 target = new Self();
161 }
162 else
163 {
164 target = null;
165 }
166 }
167 else
168 {
169 target = null;
170 }
171
172 targetMetadata.value = target;
173 }
174
175 targetMetadata.Inspector<IExpressionInspector>().expectedType = member.targetType;
176
177 if (member.isInvocable)
178 {
179 var argumentIndex = 0;
180
181 foreach (var parameterInfo in member.methodBase.GetParametersWithoutThis())
182 {
183 if (reset || argumentIndex >= argumentsMetadata.Count)
184 {
185 argumentsMetadata.Add(parameterInfo.DefaultInspectableExpression());
186 }
187
188 var argumentMetadata = argumentsMetadata[argumentIndex];
189
190 PrepareParameterLabel(argumentMetadata, parameterInfo.HumanName(), member.methodBase.ParameterSummary(parameterInfo));
191
192 if (parameterInfo.ParameterType.IsByRef)
193 {
194 var argument = argumentsMetadata[argumentIndex].value as Literal;
195
196 if (argument == null || argument.type != typeof(IVariableReference))
197 {
198 argumentsMetadata[argumentIndex].value = new Literal(typeof(IVariableReference), null);
199 }
200
201 var referenceInspector = new IVariableReferenceInspector(argumentMetadata[nameof(ILiteral.value)]);
202 referenceInspector.Initialize();
203 referenceInspector.direction = ActionDirection.Set;
204 referenceInspectors.Add(argumentMetadata, referenceInspector);
205 PrepareParameterLabel(argumentMetadata[nameof(ILiteral.value)], parameterInfo.HumanName(), member.methodBase.ParameterSummary(parameterInfo));
206 }
207 else
208 {
209 PrepareParameterInspector(argumentMetadata, parameterInfo.ParameterType);
210 }
211
212 argumentIndex++;
213 }
214 }
215 else if (member.isSettable && (ActionDirection)directionMetadata.value != ActionDirection.Get)
216 {
217 if (reset || argumentsMetadata.Count == 0)
218 {
219 argumentsMetadata.Add(member.type.ToInspectableExpression());
220 }
221
222 var argumentMetadata = argumentsMetadata[0];
223
224 PrepareParameterLabel(argumentMetadata, member.info.HumanName(), member.info.Summary());
225 PrepareParameterInspector(argumentMetadata, member.type);
226 }
227
228 SetHeightDirty();
229 }
230
231 public static bool WillFail(bool reflectionSucceeded, MemberInvocation invocation, UnityObject owner)
232 {
233 if (!reflectionSucceeded)
234 {
235 return true;
236 }
237
238 // We can only analyze if the member isn't null and
239 // if we can infer the value of the target expression in edit mode
240 var canAnalyze = invocation.member != null && (invocation.target is ILiteral || invocation.target is Self);
241
242 if (!canAnalyze)
243 {
244 return false;
245 }
246
247 object target;
248
249 if (invocation.target is ILiteral)
250 {
251 target = ((ILiteral)invocation.target).value;
252 }
253 else if (invocation.target is Self)
254 {
255 target = owner;
256 }
257 else
258 {
259 throw new NotSupportedException();
260 }
261
262 if (target == null)
263 {
264 return true;
265 }
266
267 var targetType = target.GetType();
268
269 if (ComponentHolderProtocol.IsComponentHolderType(invocation.member.targetType))
270 {
271 if (!ComponentHolderProtocol.IsComponentHolderType(targetType))
272 {
273 return true;
274 }
275
276 // Don't fail true if the owner isn't a component holder
277 // (e.g. it might be a graph asset)
278 if (!owner.IsComponentHolder())
279 {
280 return false;
281 }
282
283 return invocation.member.targetType != typeof(GameObject) && !((UnityObject)target).GetComponents<Component>().Any(c => invocation.member.targetType.IsInstanceOfType(c));
284 }
285 else
286 {
287 return !invocation.member.targetType.IsAssignableFrom(targetType);
288 }
289 }
290
291 private bool willFail => WillFail(reflectionSucceeded, (MemberInvocation)metadata.value, metadata.UnityObjectAncestor());
292
293 #endregion
294
295 #region Rendering
296
297 protected override IEnumerable<GUIContent> compactLabels => base.compactLabels.Concat(targetMetadata.label.Yield());
298
299 protected override float GetHeight(float width, GUIContent label)
300 {
301 var height = 0f;
302
303 height += GetMemberHeight(width);
304
305 using (LudiqGUIUtility.labelWidth.Override(GetCompactLabelsWidth(width)))
306 {
307 if (reflectionSucceeded)
308 {
309 height += Styles.spaceBetweenParameters;
310
311 if (((Member)memberMetadata.value).requiresTarget)
312 {
313 height += GetTargetHeight(width);
314
315 if (parameters.Count > 0)
316 {
317 height += Styles.spaceBetweenParameters;
318 }
319 }
320
321 height += GetParametersHeight(width);
322 }
323 }
324
325 height = HeightWithLabel(metadata, width, height, label);
326
327 return height;
328 }
329
330 private float GetMemberHeight(float width)
331 {
332 return InspectorGUI.GetHeight(memberMetadata, width, GUIContent.none, this);
333 }
334
335 private float GetTargetHeight(float width)
336 {
337 return InspectorGUI.GetHeight(targetMetadata, width, targetMetadata.label, this);
338 }
339
340 protected override float GetParameterHeight(Metadata parameter, float width)
341 {
342 if (referenceInspectors.ContainsKey(parameter))
343 {
344 return referenceInspectors[parameter].GetHeight(width, GUIContent.none, this);
345 }
346 else
347 {
348 return InspectorGUI.GetHeight(parameter, width, GUIContent.none, this);
349 }
350 }
351
352 protected override void OnGUI(Rect position, GUIContent label)
353 {
354 var memberPosition = position.VerticalSection(ref y, GetMemberHeight(position.width));
355
356 memberPosition = PrefixLabel(metadata, memberPosition, label);
357
358 OnMemberGUI(memberPosition);
359
360 position = ReclaimImplementationSelector(position);
361
362 if (reflectionSucceeded)
363 {
364 using (LudiqGUIUtility.labelWidth.Override(GetCompactLabelsWidth(position.width)))
365 {
366 y += Styles.spaceBetweenParameters;
367
368 if (((Member)memberMetadata.value).requiresTarget)
369 {
370 var targetPosition = position.VerticalSection(ref y, GetTargetHeight(position.width));
371
372 OnTargetGUI(targetPosition);
373
374 if (parameters.Count > 0)
375 {
376 y += Styles.spaceBetweenParameters;
377 }
378 }
379
380 OnParametersGUI(position);
381 }
382 }
383 }
384
385 private void OnMemberGUI(Rect memberPosition)
386 {
387 BeginBlock(memberMetadata, memberPosition, GUIContent.none);
388
389 memberMetadata.Inspector<MemberManipulatorInspector>().willFail = willFail;
390
391 InspectorGUI.Field(memberMetadata, memberPosition, GUIContent.none);
392
393 if (EndBlock(memberMetadata))
394 {
395 ReflectMember(true);
396 }
397 }
398
399 private void OnTargetGUI(Rect targetPosition)
400 {
401 InspectorGUI.Field(targetMetadata, targetPosition);
402 }
403
404 protected override void OnParameterGUI(Rect parameterPosition, Metadata parameter)
405 {
406 if (referenceInspectors.ContainsKey(parameter))
407 {
408 referenceInspectors[parameter].Field(parameterPosition);
409 }
410 else
411 {
412 base.OnParameterGUI(parameterPosition, parameter);
413 }
414 }
415
416 #endregion
417 }
418}
419*/