private IEnumerable <IValueEntity> GetChildrenImpl(IPresentationOptions options, CancellationToken token)
            {
                // GameObject[] Scene.GetRootObjects()
                var gameObjectArray = new SimpleValueReference <TValue>(
                    mySceneValueRole.CallInstanceMethod(myGetRootObjectsMethod),
                    mySceneValueRole.ValueReference.OriginatingFrame, myValueServices.RoleFactory)
                                      .GetExactPrimaryRoleSafe <TValue, IArrayValueRole <TValue> >(options);

                if (gameObjectArray == null)
                {
                    myLogger.Warn("Unable to retrieve GameObject array, or unexpectedly returned null");
                    yield break;
                }

                if (options.ClusterArrays)
                {
                    var absoluteElementCount = ArrayIndexUtil.GetAbsoluteElementCount(gameObjectArray.Dimensions);
                    foreach (var valueEntity in GetChunkedChildren(gameObjectArray, 0, absoluteElementCount, options, token))
                    {
                        yield return(valueEntity);
                    }
                }
                else
                {
                    var enumerator = (IChildReferencesEnumerator <TValue>)gameObjectArray;
                    foreach (var childReference in enumerator.GetChildReferences())
                    {
                        yield return(GetElementValue(childReference, options));
                    }
                }
            }
Beispiel #2
0
            private bool TryInvokeGetIterator(IObjectValueRole <TValue> serializedObjectRole,
                                              IValueFetchOptions options,
                                              out IObjectValueRole <TValue> returnedSerializedPropertyRole)
            {
                returnedSerializedPropertyRole = null;

                var method = MetadataTypeLiteEx.LookupInstanceMethodSafe(serializedObjectRole.ReifiedType.MetadataType,
                                                                         MethodSelectors.SerializedObject_GetIterator, false);

                if (method == null)
                {
                    myLogger.Warn("Cannot find GetIterator method on SerializedObject");
                    return(false);
                }

                returnedSerializedPropertyRole = new SimpleValueReference <TValue>(
                    serializedObjectRole.CallInstanceMethod(method),
                    serializedObjectRole.ValueReference.OriginatingFrame, myValueServices.RoleFactory)
                                                 .AsObjectSafe(options);
                if (returnedSerializedPropertyRole == null)
                {
                    myLogger.Warn("Unable to invoke GetIterator");
                    return(false);
                }

                return(true);
            }
Beispiel #3
0
            public override IEnumerable <IValueEntity> GetChildren(IPresentationOptions options,
                                                                   CancellationToken token = new CancellationToken())
            {
                var gameObjectsArray = new SimpleValueReference <TValue>(
                    myValueRole.CallInstanceMethod(myGetRootObjectMethod),
                    myValueRole.ValueReference.OriginatingFrame, myValueServices.RoleFactory)
                                       .GetExactPrimaryRoleSafe <TValue, IArrayValueRole <TValue> >(options);

                if (gameObjectsArray == null)
                {
                    yield break;
                }

                var childReferencesEnumerator = (IChildReferencesEnumerator <TValue>)gameObjectsArray;

                foreach (var childReference in childReferencesEnumerator.GetChildReferences())
                {
                    var childRole = childReference.AsObjectSafe(options);
                    if (childRole == null)
                    {
                        continue;
                    }

                    var name = childRole.GetInstancePropertyReference("name", true)?.AsStringSafe(options)
                               ?.GetString() ?? "Game Object";
                    yield return(new NamedReferenceDecorator <TValue>(childRole.ValueReference, name,
                                                                      ValueOriginKind.Property, childRole.ReifiedType.MetadataType, myValueServices.RoleFactory)
                                 .ToValue(myValueServices));
                }
            }
Beispiel #4
0
            protected override IValue GetElementValueAt(IObjectValueRole <TValue> collection, int index, IValueFetchOptions options)
            {
                try
                {
                    var frame               = myGameObjectRole.ValueReference.OriginatingFrame;
                    var indexValue          = myValueServices.ValueFactory.CreatePrimitive(frame, options, index);
                    var childTransformValue = collection.CallInstanceMethod(myGetChildMethod, indexValue);
                    var childTransform      = new SimpleValueReference <TValue>(childTransformValue,
                                                                                frame, myValueServices.RoleFactory).AsObjectSafe(options);
                    var gameObject = childTransform?.GetInstancePropertyReference("gameObject", true)
                                     ?.AsObjectSafe(options);
                    if (gameObject == null)
                    {
                        return(new ErrorValue("Game Object", "Unable to find child gameObject, or value is null"));
                    }

                    var name = gameObject.GetInstancePropertyReference("name", true)?.AsStringSafe(options)
                               ?.GetString() ?? "Game Object";

                    // Tell the value presenter to not show the name field, we're already showing it as the key. Also don't
                    // show the type - a GameObject's child can only be a GameObject
                    return(new CalculatedValueReferenceDecorator <TValue>(gameObject.ValueReference,
                                                                          myValueServices.RoleFactory, name, false, false).ToValue(myValueServices));
                }
                catch (Exception e)
                {
                    // We must always return a value, as we're effectively showing the contents of an array here. We're
                    // possibly also being evaluated lazily, thanks to chunked arrays, so can't rely on the caller
                    // catching exceptions.
                    myLogger.LogExceptionSilently(e);
                    return(myValueServices.ValueRenderers.GetValueStubForException(e, "Game Object",
                                                                                   collection.ValueReference.OriginatingFrame) as IValue
                           ?? new ErrorValue("Game Object", "Unable to retrieve child game object"));
                }
            }
Beispiel #5
0
            private string GetComponentName(IValueReference <TValue> componentValue,
                                            [CanBeNull] IReifiedType <TValue> objectNamesType,
                                            [CanBeNull] IMetadataMethodLite getInspectorTitleMethod,
                                            IStackFrame frame,
                                            IValueFetchOptions options, IValueServicesFacade <TValue> services)
            {
                if (objectNamesType != null && getInspectorTitleMethod != null)
                {
                    try
                    {
                        var inspectorTitle = objectNamesType.CallStaticMethod(frame, options, getInspectorTitleMethod,
                                                                              componentValue.GetValue(options));
                        var stringValueRole =
                            new SimpleValueReference <TValue>(inspectorTitle, frame, services.RoleFactory)
                            .AsStringSafe(options);
                        if (stringValueRole != null)
                        {
                            return(stringValueRole.GetString());
                        }
                    }
                    catch (Exception e)
                    {
                        myLogger.Error(e, "Unable to fetch object names for {0}", componentValue);
                    }
                }

                return(componentValue.GetPrimaryRole(options).ReifiedType.MetadataType.ShortName);
            }
            private bool TryCopySerializedProperty(IObjectValueRole <TValue> serializedPropertyRole,
                                                   IValueFetchOptions options,
                                                   out IObjectValueRole <TValue> copiedSerializedPropertyRole)
            {
                copiedSerializedPropertyRole = null;

                // Get a copy of the property, so we can call Next(true) without updating the current instance
                var copyMethod = MetadataTypeLiteEx.LookupInstanceMethodSafe(
                    mySerializedPropertyRole.ReifiedType.MetadataType,
                    MethodSelectors.SerializedProperty_Copy, false);

                if (copyMethod == null)
                {
                    myLogger.Warn("Cannot find Copy method on SerializedProperty");
                    return(false);
                }

                // CallInstanceMethod always returns not null (VoidValue if it fails)
                copiedSerializedPropertyRole = new SimpleValueReference <TValue>(
                    serializedPropertyRole.CallInstanceMethod(copyMethod),
                    mySerializedPropertyRole.ValueReference.OriginatingFrame, myValueServices.RoleFactory)
                                               .AsObjectSafe(options);
                if (copiedSerializedPropertyRole == null)
                {
                    myLogger.Warn("Unable to Copy serializedProperty");
                    return(false);
                }

                return(true);
            }
            protected override IValue GetElementValueAt(IObjectValueRole <TValue> collection, int index, IValueFetchOptions options)
            {
                var name = $"[{index}]";

                try
                {
                    var frame      = mySerializedPropertyRole.ValueReference.OriginatingFrame;
                    var indexValue = myValueServices.ValueFactory.CreatePrimitive(frame, options, index);
                    var childSerializedPropertyValue = collection.CallInstanceMethod(myGetElementMethod, indexValue);
                    var valueReference = new SimpleValueReference <TValue>(childSerializedPropertyValue,
                                                                           mySerializedPropertyRole.ReifiedType.MetadataType, name, ValueOriginKind.ArrayElement,
                                                                           ValueFlags.None | ValueFlags.IsReadOnly, frame, myValueServices.RoleFactory);

                    // Tell the value presenter to hide the name, because it's always "data" (DefaultName is the key name)
                    // Also hide the type presentation - they can only ever be SerializedProperty instances
                    return(new CalculatedValueReferenceDecorator <TValue>(valueReference, myValueServices.RoleFactory,
                                                                          valueReference.DefaultName, false, false).ToValue(myValueServices));
                }
                catch (Exception e)
                {
                    // We must always return a value, as we're effectively showing the contents of an array here. We're
                    // possibly also being evaluated lazily, thanks to chunked arrays, so can't rely on the caller
                    // catching exceptions.
                    myLogger.LogExceptionSilently(e);
                    return(myValueServices.ValueRenderers.GetValueStubForException(e, name,
                                                                                   collection.ValueReference.OriginatingFrame) as IValue
                           ?? new ErrorValue(name, "Unable to retrieve child serialized property"));
                }
            }
Beispiel #8
0
            public override IEnumerable <IValueEntity> GetChildren(IPresentationOptions options,
                                                                   CancellationToken token = new CancellationToken())
            {
                var frame         = myGameObjectRole.ValueReference.OriginatingFrame;
                var componentType =
                    myValueServices.TypeUniverse.GetReifiedType(frame, "UnityEngine.Component, UnityEngine.CoreModule")
                    ?? myValueServices.TypeUniverse.GetReifiedType(frame, "UnityEngine.Component, UnityEngine");

                if (componentType == null)
                {
                    yield break;
                }

                var getComponentsMethod = myGameObjectRole.ReifiedType.MetadataType.GetMethods()
                                          .FirstOrDefault(ourGetComponentsSelector);

                if (getComponentsMethod == null)
                {
                    yield break;
                }

                // Component[] GameObject.GetComponents(typeof(Component))
                var typeObject      = (IValueReference <TValue>)componentType.GetTypeObject(frame);
                var componentsArray =
                    myGameObjectRole.CallInstanceMethod(getComponentsMethod, typeObject.GetValue(options));
                var componentArray =
                    new SimpleValueReference <TValue>(componentsArray, frame, myValueServices.RoleFactory)
                    .GetExactPrimaryRoleSafe <TValue, IArrayValueRole <TValue> >(options);

                if (componentArray == null)
                {
                    yield break;
                }

                // string UnityEditor.ObjectNames.GetInspectorTitle(UnityEngine.Object)
                // Returns the name of the component, formatted the same as in the Inspector. Values are also cached per
                // type. This obviously won't be available for standalone players, where we'll display the short type
                // name instead.
                // TODO: Support extra fallback names
                // Unity doesn't use the short name, but will look at the type and use GameObject.name,
                // MonoBehaviour.GetScriptClassName and so on.
                var objectNamesType = (IReifiedType <TValue>)
                                          (myValueServices.TypeUniverse.GetReifiedType(frame, "UnityEditor.ObjectNames, UnityEditor")
                                          ?? myValueServices.TypeUniverse.GetReifiedType(frame, "UnityEditor.ObjectNames, UnityEditor.CoreModule"));
                var getInspectorTitleMethod = objectNamesType?.MetadataType.GetMethods()
                                              .FirstOrDefault(ourGetInspectorTitleSelector);

                var childReferencesEnumerator = (IChildReferencesEnumerator <TValue>)componentArray;

                foreach (var componentReference in childReferencesEnumerator.GetChildReferences())
                {
                    var componentName = GetComponentName(componentReference, objectNamesType, getInspectorTitleMethod,
                                                         frame, options, myValueServices);
                    yield return(new NamedReferenceDecorator <TValue>(componentReference, componentName,
                                                                      ValueOriginKind.ArrayElement, componentType.MetadataType, myValueServices.RoleFactory)
                                 .ToValue(myValueServices));
                }
            }
            protected override IValue GetElementValueAt(IObjectValueRole <TValue> collection, int index, IValueFetchOptions options)
            {
                var frame      = mySerializedPropertyRole.ValueReference.OriginatingFrame;
                var indexValue = myValueServices.ValueFactory.CreatePrimitive(frame, options, index);
                var childSerializedPropertyValue = collection.CallInstanceMethod(myGetElementMethod, indexValue);
                var valueReference = new SimpleValueReference <TValue>(childSerializedPropertyValue,
                                                                       mySerializedPropertyRole.ReifiedType.MetadataType, $"[{index}]", ValueOriginKind.ArrayElement,
                                                                       ValueFlags.None | ValueFlags.IsReadOnly, frame, myValueServices.RoleFactory);

                // Tell the value presenter to hide the name, because it's always "data" (DefaultName is the key name)
                // Also hide the type presentation - they can only ever be SerializedProperty instances
                return(new CalculatedValueReferenceDecorator <TValue>(valueReference, myValueServices.RoleFactory,
                                                                      valueReference.DefaultName, false, false).ToValue(myValueServices));
            }
            protected override IValue GetElementValueAt(IObjectValueRole <TValue> collection, int index, IValueFetchOptions options)
            {
                var frame               = myGameObjectRole.ValueReference.OriginatingFrame;
                var indexValue          = myValueServices.ValueFactory.CreatePrimitive(frame, options, index);
                var childTransformValue = collection.CallInstanceMethod(myGetChildMethod, indexValue);
                var childTransform      = new SimpleValueReference <TValue>(childTransformValue,
                                                                            frame, myValueServices.RoleFactory).AsObjectSafe(options);
                var gameObject = childTransform?.GetInstancePropertyReference("gameObject", true)
                                 ?.AsObjectSafe(options);
                var name = gameObject?.GetInstancePropertyReference("name", true)?.AsStringSafe(options)
                           ?.GetString() ?? "Game Object";

                return(new NamedReferenceDecorator <TValue>(gameObject.ValueReference, name,
                                                            ValueOriginKind.Property,
                                                            ValueFlags.None | ValueFlags.IsReadOnly,
                                                            myGameObjectRole.ReifiedType.MetadataType, myValueServices.RoleFactory, true)
                       .ToValue(myValueServices));
            }
Beispiel #11
0
            public override IEnumerable <IValueEntity> GetChildren(IPresentationOptions options,
                                                                   CancellationToken token = new CancellationToken())
            {
                var transformObject = myTransformReference.AsObjectSafe(options);
                var childCountRole  = transformObject?.GetInstancePropertyReference("childCount", true)
                                      ?.AsPrimitiveSafe(options);

                if (childCountRole == null)
                {
                    yield break;
                }

                if (!(childCountRole.GetPrimitive() is int childCount))
                {
                    yield break;
                }

                var transformType =
                    transformObject.ReifiedType.MetadataType.FindTypeThroughHierarchy("UnityEngine.Transform");
                var getChildMethod = transformType?.GetMethods().FirstOrDefault(ourGetChildSelector);

                if (getChildMethod == null)
                {
                    yield break;
                }

                for (int i = 0; i < childCount; i++)
                {
                    var frame          = myTransformReference.OriginatingFrame;
                    var index          = myServices.ValueFactory.CreatePrimitive(frame, options, i);
                    var childTransform = new SimpleValueReference <TValue>(
                        transformObject.CallInstanceMethod(getChildMethod, index), frame, myServices.RoleFactory)
                                         .AsObjectSafe(options);
                    if (childTransform == null)
                    {
                        continue;
                    }

                    var name = childTransform.GetInstancePropertyReference("name", true)?.AsStringSafe(options)
                               ?.GetString() ?? "Game Object";
                    yield return(new NamedReferenceDecorator <TValue>(childTransform.ValueReference, name,
                                                                      ValueOriginKind.Property, transformType, myServices.RoleFactory).ToValue(myServices));
                }
            }
 public static string GetThrownExceptionMessage <TValue>(EvaluatorExceptionThrownException <TValue> exception,
                                                         IStackFrame frame,
                                                         IValueServicesFacade <TValue> valueServices,
                                                         IValueFetchOptions valueFetchOptions,
                                                         ILogger logger)
     where TValue : class
 {
     try
     {
         var reference = new SimpleValueReference <TValue>(exception.Exception, frame, valueServices.RoleFactory);
         return(reference.AsObjectSafe(valueFetchOptions)
                ?.GetInstancePropertyReference("Message", true)
                ?.AsStringSafe(valueFetchOptions)?.GetString());
     }
     catch (Exception e)
     {
         // Argh! Exception thrown while trying to get information about a thrown exception!
         logger.LogExceptionSilently(e);
         return(null);
     }
 }
Beispiel #13
0
            protected override IValue GetElementValueAt(IObjectValueRole <TValue> collection, int index, IValueFetchOptions options)
            {
                var frame               = myGameObjectRole.ValueReference.OriginatingFrame;
                var indexValue          = myValueServices.ValueFactory.CreatePrimitive(frame, options, index);
                var childTransformValue = collection.CallInstanceMethod(myGetChildMethod, indexValue);
                var childTransform      = new SimpleValueReference <TValue>(childTransformValue,
                                                                            frame, myValueServices.RoleFactory).AsObjectSafe(options);
                var gameObject = childTransform?.GetInstancePropertyReference("gameObject", true)
                                 ?.AsObjectSafe(options);

                if (gameObject == null)
                {
                    return(new ErrorValue("Game Object", "Unable to retrieve child game object"));
                }

                var name = gameObject.GetInstancePropertyReference("name", true)?.AsStringSafe(options)
                           ?.GetString() ?? "Game Object";

                // Tell the value presenter to not show the name field, we're already showing it as the key. Also don't
                // show the type - a GameObject's child can only be a GameObject
                return(new CalculatedValueReferenceDecorator <TValue>(gameObject.ValueReference,
                                                                      myValueServices.RoleFactory, name, false, false).ToValue(myValueServices));
            }
            private bool TryInvokeNext(IObjectValueRole <TValue> serializedPropertyRole,
                                       IMetadataMethodLite nextMethod,
                                       TValue boolArg,
                                       IValueFetchOptions options,
                                       out bool returnValue)
            {
                returnValue = false;

                var returnValueRole = new SimpleValueReference <TValue>(
                    serializedPropertyRole.CallInstanceMethod(nextMethod, boolArg),
                    mySerializedPropertyRole.ValueReference.OriginatingFrame,
                    myValueServices.RoleFactory)
                                      .AsPrimitiveSafe(options);

                if (returnValueRole == null)
                {
                    myLogger.Warn("Unable to call Next on serializedProperty");
                    return(false);
                }

                returnValue = returnValueRole.GetPrimitive <bool>();
                return(true);
            }
Beispiel #15
0
            private string GetComponentName(IValueReference <TValue> componentValue,
                                            [CanBeNull] IReifiedType <TValue> objectNamesType,
                                            [CanBeNull] IMetadataMethodLite getInspectorTitleMethod,
                                            IStackFrame frame,
                                            IValueFetchOptions options,
                                            IValueServicesFacade <TValue> services,
                                            out bool isNameFromValue)
            {
                if (objectNamesType != null && getInspectorTitleMethod != null)
                {
                    try
                    {
                        var inspectorTitle = objectNamesType.CallStaticMethod(frame, options, getInspectorTitleMethod,
                                                                              componentValue.GetValue(options));
                        var stringValueRole =
                            new SimpleValueReference <TValue>(inspectorTitle, frame, services.RoleFactory)
                            .AsStringSafe(options);
                        if (stringValueRole != null)
                        {
                            isNameFromValue = true;
                            return(stringValueRole.GetString());
                        }
                    }
                    catch (EvaluatorAbortedException e)
                    {
                        myLogger.LogExceptionSilently(e);
                    }
                    catch (Exception e)
                    {
                        myLogger.Warn(e, ExceptionOrigin.Algorithmic,
                                      $"Unable to fetch object names for {componentValue}");
                    }
                }

                isNameFromValue = false;
                return(componentValue.GetPrimaryRole(options).ReifiedType.MetadataType.ShortName);
            }
Beispiel #16
0
        public static IValueEntity GetScenePathValue <TValue>([CanBeNull] IObjectValueRole <TValue> gameObjectRole,
                                                              IPresentationOptions options,
                                                              IValueServicesFacade <TValue> valueServices,
                                                              ILogger logger)
            where TValue : class
        {
            if (gameObjectRole == null)
            {
                return(null);
            }
            return(logger.CatchEvaluatorException <TValue, IValueEntity>(() =>
            {
                // Only available in the editor. Not available for players, where we'll display nothing.
                // TODO: Hand roll this for players. Simply follow transform.parent
                // However, this will obviously be more expensive to calculate
                var frame = gameObjectRole.ValueReference.OriginatingFrame;
                var animationUtilityType =
                    valueServices.GetReifiedType(frame, "UnityEditor.AnimationUtility, UnityEditor")
                    ?? valueServices.GetReifiedType(frame, "UnityEditor.AnimationUtility, UnityEditor.CoreModule");
                var method = animationUtilityType?.MetadataType.GetMethods()
                             .FirstOrDefault(ourCalculateTransformPathSelector);
                if (method == null)
                {
                    logger.Trace(
                        "Unable to get metadata for AnimationUtility.CalculateTransformPath method. Is this a player?");
                    return null;
                }

                var targetTransformReference = gameObjectRole.GetInstancePropertyReference("transform");
                var targetTransformRole = targetTransformReference?.AsObjectSafe(options);
                // Search in bases - transform might be a RectTransform or a Transform, and root is defined on Transform
                var rootTransformReference = targetTransformRole?.GetInstancePropertyReference("root", true);
                var rootTransformRole = rootTransformReference?.AsObjectSafe(options);

                if (targetTransformRole == null || rootTransformRole == null)
                {
                    logger.Warn("Unable to evaluate gameObject.transform and/or gameObject.transform.root or values are null.");
                    return null;
                }

                var rootTransformName = rootTransformRole.GetInstancePropertyReference("name", true)
                                        ?.AsStringSafe(options)?.GetString() ?? "";

                var pathValue = animationUtilityType.CallStaticMethod(frame, options, method,
                                                                      targetTransformReference.GetValue(options), rootTransformReference.GetValue(options));
                var path = new SimpleValueReference <TValue>(pathValue, frame, valueServices.RoleFactory)
                           .AsStringSafe(options)?.GetString();
                if (path == null)
                {
                    // We expect empty string at least
                    logger.Warn("Unexpected null returned from AnimationUtility.CalculateTransformPath");
                    return null;
                }

                var fullPath = path.IsNullOrEmpty() ? rootTransformName : rootTransformName + "/" + path;
                var fullPathValue = valueServices.ValueFactory.CreateString(frame, options, fullPath);

                // Don't show type presentation. This is informational, rather than an actual property
                var simpleReference = new SimpleValueReference <TValue>(fullPathValue, null, "Scene path",
                                                                        ValueOriginKind.Property,
                                                                        ValueFlags.None | ValueFlags.IsReadOnly | ValueFlags.IsDefaultTypePresentation, frame,
                                                                        valueServices.RoleFactory);

                // Wrap the simple reference - the default StringValuePresenter will display the simple reference as a
                // string property, with syntax colouring, quotes and type name. Our TextValuePresenter will handle the
                // TextValueReference and use the flags we've set
                return new TextValueReference <TValue>(simpleReference, valueServices.RoleFactory).ToValue(
                    valueServices);
            },
                                                                         exception => logger.LogThrownUnityException(exception, gameObjectRole.ValueReference.OriginatingFrame,
                                                                                                                     valueServices, options)));
        }
Beispiel #17
0
            private IEnumerable <IValueEntity> GetChildrenImpl(IValueFetchOptions options)
            {
                var frame         = myGameObjectRole.ValueReference.OriginatingFrame;
                var componentType =
                    myValueServices.GetReifiedType(frame, "UnityEngine.Component, UnityEngine.CoreModule")
                    ?? myValueServices.GetReifiedType(frame, "UnityEngine.Component, UnityEngine");

                if (componentType == null)
                {
                    myLogger.Warn("Unable to find UnityEngine.Component");
                    yield break;
                }

                var getComponentsMethod = myGameObjectRole.ReifiedType.MetadataType.GetMethods()
                                          .FirstOrDefault(ourGetComponentsSelector);

                if (getComponentsMethod == null)
                {
                    myLogger.Warn("Unable to find UnityEngine.GameObject.GetComponents method");
                    yield break;
                }

                // Call Component[] GameObject.GetComponents(typeof(Component))
                var typeObject      = (IValueReference <TValue>)componentType.GetTypeObject(frame);
                var componentsArray =
                    myGameObjectRole.CallInstanceMethod(getComponentsMethod, typeObject.GetValue(options));
                var componentArray =
                    new SimpleValueReference <TValue>(componentsArray, frame, myValueServices.RoleFactory)
                    .GetExactPrimaryRoleSafe <TValue, IArrayValueRole <TValue> >(options);

                if (componentArray == null)
                {
                    myLogger.Warn("Cannot get return value of GameObject.GetComponents or method returned null");
                    yield break;
                }

                // string UnityEditor.ObjectNames.GetInspectorTitle(UnityEngine.Object)
                // Returns the name of the component, formatted the same as in the Inspector. Values are also cached per
                // type. This obviously won't be available for standalone players, where we'll display the short type
                // name instead.
                // TODO: Support extra fallback names
                // Unity doesn't use the short name, but will look at the type and use GameObject.name,
                // MonoBehaviour.GetScriptClassName and so on.
                var objectNamesType = myValueServices.GetReifiedType(frame, "UnityEditor.ObjectNames, UnityEditor")
                                      ?? myValueServices.GetReifiedType(frame,
                                                                        "UnityEditor.ObjectNames, UnityEditor.CoreModule");
                var getInspectorTitleMethod = objectNamesType?.MetadataType.GetMethods()
                                              .FirstOrDefault(ourGetInspectorTitleSelector);

                var childReferencesEnumerator = (IChildReferencesEnumerator <TValue>)componentArray;

                foreach (var componentReference in childReferencesEnumerator.GetChildReferences())
                {
                    var componentName = GetComponentName(componentReference, objectNamesType,
                                                         getInspectorTitleMethod, frame, options, myValueServices, out var isNameFromValue);

                    // Tell the value presenter to hide the name field, if we're using it for the key. Also hide the
                    // default type presentation - we know it's a Component, it's under a group called "Components"
                    yield return(new CalculatedValueReferenceDecorator <TValue>(componentReference,
                                                                                myValueServices.RoleFactory, componentName, !isNameFromValue, false).ToValue(myValueServices));
                }
            }