private IValueReference <TValue> GetActiveScene(IStackFrame frame)
        {
            try
            {
                var sceneManagerType = myValueServices.GetReifiedType(frame,
                                                                      "UnityEngine.SceneManagement.SceneManager, UnityEngine.CoreModule")
                                       ?? myValueServices.GetReifiedType(frame,
                                                                         "UnityEngine.SceneManagement.SceneManager, UnityEngine");
                if (sceneManagerType == null)
                {
                    myLogger.Warn("Unable to get typeof(SceneManager). Not a Unity project?");
                    return(null);
                }

                var getActiveSceneMethod = sceneManagerType.MetadataType.GetMethods()
                                           .FirstOrDefault(m => m.IsStatic && m.Parameters.Length == 0 && m.Name == "GetActiveScene");
                if (getActiveSceneMethod == null)
                {
                    myLogger.Warn("Unable to find SceneManager.GetActiveScene");
                    return(null);
                }

                var activeScene = sceneManagerType.CallStaticMethod(frame, mySession.EvaluationOptions, getActiveSceneMethod);
                if (activeScene == null)
                {
                    myLogger.Warn("Unexpected response: SceneManager.GetActiveScene() == null");
                    return(null);
                }

                // Don't show type presentation. We know it's a scene, the clue's in the name
                return(new SimpleValueReference <TValue>(activeScene, sceneManagerType.MetadataType,
                                                         "Active scene", ValueOriginKind.Property,
                                                         ValueFlags.None | ValueFlags.IsReadOnly | ValueFlags.IsDefaultTypePresentation, frame,
                                                         myValueServices.RoleFactory));
            }
            catch (Exception e)
            {
                myLogger.LogException(e);
                return(null);
            }
        }
Ejemplo n.º 2
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)));
        }
            private IEnumerable <IValueEntity> GetChildrenImpl(IPresentationOptions 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);

                    yield return(new NamedReferenceDecorator <TValue>(componentReference, componentName,
                                                                      ValueOriginKind.Property, ValueFlags.None | ValueFlags.IsReadOnly,
                                                                      componentType.MetadataType, myValueServices.RoleFactory, isNameFromValue)
                                 .ToValue(myValueServices));
                }
            }