/// <summary>
        /// Whenever another scene is loaded, we have another shot at resolving more cross-scene references
        /// </summary>
        /// <param name="sceneSetup">The AmsMultiSceneSetup that was loaded</param>
        private void HandleNewSceneLoaded(AmsMultiSceneSetup sceneSetup)
        {
            var loadedScene = sceneSetup.gameObject.scene;

            if (!loadedScene.isLoaded)
            {
                Debug.LogErrorFormat(this, "{0} Received HandleNewSceneLoaded from scene {1} which isn't considered loaded.  The scene MUST be considered loaded by this point", GetType().Name, loadedScene.name);
            }

            // Restore any references to this newly loaded scene
            for (int i = 0; i < _crossSceneReferences.Count; ++i)
            {
                var xRef = _crossSceneReferences[i];

                if (!xRef.fromObject)
                {
                    AmsDebug.LogWarning(this, "xRef Index {0} had Null source (probably stale), Consider removing (via right-click on entry)", i);
                    continue;
                }

                if (!_referencesToResolve.Contains(xRef) && xRef.toScene.scene == loadedScene)
                {
                    _referencesToResolve.Add(xRef);
                }
            }

            if (_referencesToResolve.Count > 0)
            {
                AmsDebug.Log(this, "Scene {0} Loaded. {1} Cross-Scene References (in total) from Cross-Scene Manager in {2} are queued for resolve.", loadedScene.name, _referencesToResolve.Count, gameObject.scene.name);
                ConditionalResolveReferences(_referencesToResolve);
            }
        }
Пример #2
0
        /// <summary>
        /// Resolve a cross-scene reference if possible.
        /// </summary>
        /// <returns>The cross-scene referenced object if it's possible</returns>
        private Object  RuntimeResolve()
        {
            var scene = this.scene.scene;

            if (!scene.IsValid())
            {
                return(null);
            }

            // Try to find the Object with our custom method that checks only the subscene
            GameObject gameObject = GameObjectEx.FindBySceneAndPath(scene, fullPath);

            // If that fails, we can try using Unity's GameObject.Find in case the user has switched it on us, or
            // in the case that's it's in a DontDestroyOnLoad scene
            if (!gameObject)
            {
                gameObject = GameObject.Find(fullPath);

                // It's truly failed
                if (!gameObject)
                {
                    return(null);
                }
                else
                {
                    AmsDebug.LogWarning(gameObject, "UniqueObject '{0}' resolved unexpected to '{1}'{2}.  Did you move it manually?", this, gameObject.scene.name, gameObject.GetFullName());
                }
            }

            if (string.IsNullOrEmpty(componentName))
            {
                return(gameObject);
            }

            // This is the old method where we didn't store the component index (deprecated)
            if (version < 1)
            {
                Component oldStyleComponent = gameObject.GetComponent(componentName);
                if (componentIndex < 0 || oldStyleComponent)
                {
                    return(oldStyleComponent);
                }
            }

            // Get the component and index
            System.Type type = System.Type.GetType(componentName, false);
            if (type != null)
            {
                gameObject.GetComponents(type, _reusableComponentsList);
                if (componentIndex < _reusableComponentsList.Count)
                {
                    return(_reusableComponentsList[componentIndex]);
                }
            }

            return(null);
        }
        void Awake()
        {
            AmsDebug.Log(this, "{0}.Awake() Scene: {1}. IsLoaded: {2}. Path: {3}. Frame: {4}. Root Count: {5}", GetType().Name, gameObject.scene.name, gameObject.scene.isLoaded, gameObject.scene.path, Time.frameCount, gameObject.scene.rootCount);

            // Upgrade us (we upgraded the Cross-Scene Reference data)
            // This may freak out users on their first run since it will look like their cross-scene references are gone
            // In reality, they are just in the scene, ready to be re-created on save
            if (_version < CurrentSerializedVersion)
            {
                int numCrossSceneRefs = _crossSceneReferences.Count;
                ConditionalResolveReferences(_crossSceneReferences);

                if (numCrossSceneRefs != _crossSceneReferences.Count)
                {
                    AmsDebug.LogWarning(this, "{0} was upgraded. {1} cross-scene references will be re-created on next save.", name, numCrossSceneRefs - _crossSceneReferences.Count);
                }
                else
                {
                    AmsDebug.LogWarning(this, "{0} needs upgrading.  Please resave {1}", name, gameObject.scene.name);
                }

#if UNITY_EDITOR
                if (!Application.isPlaying)
                {
                    GameObject gameObject = this.gameObject;
                    EditorApplication.delayCall += () => { if (gameObject)
                                                           {
                                                               EditorSceneManager.MarkSceneDirty(gameObject.scene);
                                                           }
                    };
                }
#endif
            }

            // Make sure we keep track of all of the merged scenes
            AmsSceneReference thisScene = new AmsSceneReference(gameObject.scene);
            foreach (var prevScene in _mergedScenes)
            {
                _activeMergedScenes.Add(prevScene, thisScene);
            }

            // We need to queue our cross-scene references super early in case we get merged.
            _referencesToResolve.Clear();
            _referencesToResolve.AddRange(_crossSceneReferences);

            // We should be able to merge our cross-scene references to any other loaded scene here.
            ResolvePendingCrossSceneReferences();
        }
        void PerformPostBuildCleanup()
        {
            if (Application.isEditor && !Application.isPlaying && _realSceneRootsForPostBuild.Count > 0)
            {
                GameObject[] newSceneRoots = gameObject.scene.GetRootGameObjects();
                foreach (GameObject root in newSceneRoots)
                {
                    if (!_realSceneRootsForPostBuild.Contains(root))
                    {
                        AmsDebug.LogWarning(this, "Destroying '{0}/{1}' since we've determined it's a temporary for a cross-scene reference", gameObject.scene.name, root.name);
                        DestroyImmediate(root);
                    }
                }

                _realSceneRootsForPostBuild.Clear();
            }
        }
        private void ConditionalResolveReferences(List <RuntimeCrossSceneReference> references)
        {
            var fromScene = gameObject.scene;

            for (int i = references.Count - 1; i >= 0; --i)
            {
                var xRef = references[i];

                if (!xRef.fromObject)
                {
                    AmsDebug.LogWarning(this, "Missing Source Object for xRef at (possible index) {0}: {1}", i, xRef);
                    continue;
                }

                try
                {
                    // See if it's a reference to a merged scene... if so we need to redirect
                    var toScene = xRef.toScene;
                    if (!toScene.IsValid())
                    {
                        AmsSceneReference mergedSceneRedirect;
                        if (_activeMergedScenes.TryGetValue(toScene, out mergedSceneRedirect))
                        {
                            AmsDebug.Log(this, "Redirecting cross scene reference {0} from original target scene {1} to scene {2}", xRef, toScene.name, mergedSceneRedirect.name);
                            toScene      = mergedSceneRedirect;
                            xRef.toScene = mergedSceneRedirect;
                        }
                    }

                    // Debug information
                    AmsDebug.Log(this, "{0}.ConditionalResolveReferences() Scene: {1}. xRef: {2}. fromSceneLoaded: {3}. toSceneLoaded: {4}.", GetType().Name, fromScene.name, xRef, fromScene.isLoaded, toScene.isLoaded);

                    if (toScene.isLoaded)
                    {
                        // Remove it from our list (assuming it goes through)
                        references.RemoveAt(i);

                        AmsDebug.Log(this, "Restoring Cross-Scene Reference {0}", xRef);
                        AmsCrossSceneReferenceResolver.Resolve(xRef);

                        // Notify any listeners
                        if (CrossSceneReferenceRestored != null)
                        {
                            CrossSceneReferenceRestored(xRef);
                        }
                    }
                }
                catch (ResolveException ex)
                {
                    string message = ex.Message;

                    // Make it easier for us to find where the cross-scene reference is
                    Object context = xRef.fromObject;
                    if (!context)
                    {
                        context = this;
                    }

                    Debug.LogErrorFormat(context, "{0} in {1}: {2}", GetType().Name, gameObject.scene.name, message);
                }
                catch (System.Exception ex)
                {
                    Debug.LogException(ex, this);
                }
            }
        }