/// <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); } }
/// <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); } } }