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*/