// Generate a GUID to identify target at runtime static string GetCrossSceneReferenceGUID(UnityEngine.Object target) { if (target == null) { return(null); } GameObject targetObject = GetGameObject(target, out SupportedObjectType type); if (type == SupportedObjectType.NULL) { return(null); } CrossSceneReferenceLocator loc = GetOrCreateLocator(targetObject); switch (type) { case SupportedObjectType.Transform: return(loc.TransformGUID); case SupportedObjectType.GameObject: return(loc.GameObjectGUID); case SupportedObjectType.MonoBehaviour: case SupportedObjectType.Component: Component comp = target as Component; for (int i = 0; i < loc.Passthroughs.Count; i++) { // If there is already a GUID for this object, return it if (loc.Passthroughs[i] == comp) { return(loc.ComponentGUIDS[i]); } } // Create a new GUID if needed string guid = GUID.Generate().ToString(); loc.ComponentGUIDS.Add(guid); loc.Passthroughs.Add(comp); Scene scene = comp.gameObject.scene; EditorSceneManager.MarkSceneDirty(scene); return(guid); default: throw new Exception($"Field of Type {target.GetType()} cannot be marked as a CrossSceneReference."); } }
// Find or create a locator on the given target static CrossSceneReferenceLocator GetOrCreateLocator(GameObject target) { CrossSceneReferenceLocator loc = target.GetComponent <CrossSceneReferenceLocator>(); if (loc == null) { loc = target.AddComponent <CrossSceneReferenceLocator>(); loc.GenerateGUIDs(); Scene scene = target.gameObject.scene; EditorSceneManager.MarkSceneDirty(scene); } if (string.IsNullOrEmpty(loc.TransformGUID)) { loc.GenerateGUIDs(); } loc.Prune(); return(loc); }
private static void CollectProxy(List <LinkResolver> temporaryResolvers, Type proxyType) //AnimTrackProxy { GameObject GetPassthroughGameObject(UnityEngine.Object obj) { if (obj is Component asComponent) { return(asComponent.gameObject); } else if (obj is GameObject asGO) { return(asGO); } throw new NotSupportedException($"Unsupported passthrough type {obj.GetType()}."); } var proxy = Activator.CreateInstance(proxyType) as CrossSceneReferenceProxy; // Search all open scenes for GameObject components matching the proxy's relevant component type foreach (Component relevantComponent in UnityEngine.Object.FindObjectsOfType(proxy.RelevantComponentType, true)) { // Generate a context for the proxy to effectively operate on targets & passthroughs. UnityEngine.Object context = proxy.AcquireContext(relevantComponent); // Iterate through all the proxy-type members contained within the relevant component instance. UnityEngine.Object[] proxyTargets = proxy.GetTargets(context); // However, if there are no valid targets, the context is useless. // No further logic is necessary for this iteration. Let's interrupt & dispose. if (proxyTargets == null || proxyTargets.Length == 0) { proxy.ReleaseContext(context); continue; } for (int i = 0; i < proxyTargets.Length; ++i) { var target = proxyTargets[i] as object; // Obtain the component at the other end of the proxy. UnityEngine.Object passthrough = proxy.GetPassthrough(ref target, context); if (passthrough == null) { continue; // No proxying to be done. Skip iteration. } // By now, we guarantee a GameObject component with a valid proxy endpoint. // Create a resolver to connect both proxy endpoints. CrossSceneReferenceResolver resolver = GetOrCreateResolver(relevantComponent); // Set up a CrossSceneReferenceLocator and get the GUID which has been assigned to the passthrough component. CrossSceneReferenceLocator loc = GetOrCreateLocator(GetPassthroughGameObject(passthrough)); int locGuidIdx = loc.Passthroughs.FindIndex(x => x == passthrough); if (locGuidIdx == -1) { // Only generate new GUID for unique entries. loc.ComponentGUIDS.Add(GUID.Generate().ToString()); loc.Passthroughs.Add(passthrough); locGuidIdx = loc.ComponentGUIDS.Count - 1; } // Mark relevant component's scene for saving to serialize the resolver on the Unity scene. Scene scene = relevantComponent.gameObject.scene; EditorSceneManager.MarkSceneDirty(scene); // Store the data required so that the link can be restored at runtime CrossSceneReferenceSetupData data = new CrossSceneReferenceSetupData() { ClassHash = CodeGenerator.ClassHashFromType(proxyType), RouteHash = proxy.GenerateRouteHash(passthrough, context), Target = target as UnityEngine.Object, GUID = loc.ComponentGUIDS[locGuidIdx], Context = context }; resolver.AddResolverData(data); // More immediate way to restore the links once save is complete temporaryResolvers.Add(new TemporaryProxyLinkResolver() // REVIEW: Consider not overloading Temp Link Resolver. Make specific classes for use case. { ProxyType = proxyType, Target = target, Value = passthrough, Context = context, Route = data.RouteHash }); // Set to null during Scene save, otherwise Unity will complain about cross scene refs proxy.Set(data.RouteHash, target, null, context); } } }