// Collect the data required to set the link back up at runtime
 static void CollectResolveData(CrossSceneReferenceResolver resolver, UnityEngine.Object target, Type targetType, MemberInfo member, string GUID)
 {
     if (resolver != null)
     {
         CrossSceneReferenceSetupData data = new CrossSceneReferenceSetupData()
         {
             ClassHash = CodeGenerator.ClassHashFromType(targetType),
             RouteHash = member.Name.GetHashCode(),
             Target    = target,
             GUID      = GUID
         };
         resolver.AddResolverData(data);
     }
 }
        // Find or create a resolver in the target GameObject
        static CrossSceneReferenceResolver GetOrCreateResolver(UnityEngine.Object subject)
        {
            Behaviour behaviour = subject as Behaviour;

            if (!behaviour.TryGetComponent(typeof(CrossSceneReferenceResolver), out Component resolverRef))
            {
                resolverRef = behaviour.gameObject.AddComponent <CrossSceneReferenceResolver>();
            }

            CrossSceneReferenceResolver resolver = resolverRef as CrossSceneReferenceResolver;

            resolver.Prune();
            return(resolver);
        }
        private static void CollectClass(List <LinkResolver> temporaryResolvers, CodegenClass refClass)
        {
            // Search all open scenes for GameObject components matching 'refClass'
            foreach (MonoBehaviour refUsage in UnityEngine.Object.FindObjectsOfType(refClass.ClassType, true))
            {
                CrossSceneReferenceResolver resolver = GetOrCreateResolver(refUsage);
                foreach (CodegenClassMember member in refClass.Members)
                {
                    // Get the field's current value
                    UnityEngine.Object memberValue = member.InfoWrapper.GetValue(refUsage) as UnityEngine.Object;

                    if (memberValue == null)
                    {
                        CreateNullResolver(resolver, refUsage, member.InfoWrapper);
                    }
                    else
                    {
                        GameObject fieldValueGameObject = GetGameObject(memberValue, out SupportedObjectType type);
                        // We don't need to store anything for references within the same scene
                        if (fieldValueGameObject.scene == refUsage.gameObject.scene)
                        {
                            // Null out any existing resolver data pointing to this field
                            CreateNullResolver(resolver, refUsage, member.InfoWrapper);
                            continue;
                        }


                        // Set up a CrossSceneReferenceLocator and get the GUID which has been assigned to that object
                        string referencedGUID = GetCrossSceneReferenceGUID(memberValue);

                        // Store the data required so that the link can be restored at runtime
                        CollectResolveData(resolver, refUsage, refUsage.GetType(), member.InfoWrapper.MemberInfo, referencedGUID);

                        // More immediate way to restore the links once save is complete
                        temporaryResolvers.Add(new TemporaryLinkResolver()
                        {
                            Target = refUsage,
                            Route  = member.InfoWrapper,
                            Value  = memberValue
                        });

                        // Set to null during Scene save, otherwise Unity will complain about cross scene refs
                        member.InfoWrapper.SetValue(refUsage, null);
                    }
                }
            }
        }
 static void CreateNullResolver(CrossSceneReferenceResolver resolver, Behaviour refUsage, FieldOrPropertyInfo fieldInfoWrapper)
 {
     CollectResolveData(resolver, refUsage, refUsage.GetType(), fieldInfoWrapper?.MemberInfo, null);
 }
        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);
                }
            }
        }