public void WhenAssetImplicitlyPulledIntoBundle_ImplicitEntryAndReferencesCreated()
    {
        AddressableAssetGroup group = CreateGroup("Group1");
        string prefabGUID           = CreateAddressablePrefab("p1", group);
        string aGUID = CreateAsset("p2");

        MakePefabReference(prefabGUID, aGUID);

        BuildLayout layout = BuildAndExtractLayout();

        BuildLayout.DataFromOtherAsset oa = layout.Groups[0].Bundles[0].Files[0].OtherAssets.First(x => x.AssetPath.Contains("p2.prefab"));
        Assert.AreEqual(aGUID, oa.AssetGuid);
    }
 public void WhenReferencedObjectIdentifiedWithFilename_ObjectRepresentedInDataFromOtherAssets()
 {
     using (new SpritePackerScope(SpritePackerMode.BuildTimeOnlyAtlas))
     {
         BuildCache.PurgeCache(false);
         AddressableAssetGroup group = CreateGroup("Group1");
         string textureGUID          = CreateSpriteTexture("spritetexture", 256, false);
         MakeAddressable(group, CreateSpriteAtlas("atlas", textureGUID));
         BuildLayout layout = BuildAndExtractLayout();
         BuildLayout.DataFromOtherAsset otherAssets = layout.Groups[0].Bundles[0].Files[0].Assets[0].InternalReferencedOtherAssets[0];
         Assert.IsTrue(otherAssets.AssetPath.StartsWith("library/atlascache", StringComparison.OrdinalIgnoreCase));
         CollectionAssert.Contains(otherAssets.ReferencingAssets, layout.Groups[0].Bundles[0].Files[0].Assets[0]);
     }
 }
        private BuildLayout CreateBuildLayout()
        {
            LayoutLookupTables lookup = new LayoutLookupTables();

            foreach (string bundleName in m_WriteData.FileToBundle.Values.Distinct())
            {
                BuildLayout.Bundle bundle = new BuildLayout.Bundle();
                bundle.Name = bundleName;
                string path = m_Parameters.GetOutputFilePathForIdentifier(bundle.Name);
                UnityEngine.BuildCompression compression = m_Parameters.GetCompressionForIdentifier(bundle.Name);
                bundle.FileSize    = (ulong)new FileInfo(path).Length;
                bundle.Compression = compression.compression.ToString();
                lookup.Bundles.Add(bundle.Name, bundle);
            }

            // create files
            foreach (KeyValuePair <string, string> fileBundle in m_WriteData.FileToBundle)
            {
                BuildLayout.Bundle bundle = lookup.Bundles[fileBundle.Value];
                BuildLayout.File   f      = new BuildLayout.File();
                f.Name = fileBundle.Key;

                WriteResult result = m_Results.WriteResults[f.Name];
                foreach (ResourceFile rf in result.resourceFiles)
                {
                    var sf = new BuildLayout.SubFile();
                    sf.IsSerializedFile = rf.serializedFile;
                    sf.Name             = rf.fileAlias;
                    sf.Size             = (ulong)new FileInfo(rf.fileName).Length;
                    f.SubFiles.Add(sf);
                }

                bundle.Files.Add(f);
                lookup.Files.Add(f.Name, f);
            }

            // create assets
            foreach (KeyValuePair <GUID, List <string> > assetFile in m_WriteData.AssetToFiles)
            {
                BuildLayout.File          file = lookup.Files[assetFile.Value[0]];
                BuildLayout.ExplicitAsset a    = new BuildLayout.ExplicitAsset();
                a.Guid      = assetFile.Key.ToString();
                a.AssetPath = AssetDatabase.GUIDToAssetPath(a.Guid);
                file.Assets.Add(a);
                lookup.GuidToExplicitAsset.Add(a.Guid, a);
            }

            Dictionary <string, List <BuildLayout.DataFromOtherAsset> > guidToPulledInBuckets = new Dictionary <string, List <BuildLayout.DataFromOtherAsset> >();

            foreach (BuildLayout.File file in lookup.Files.Values)
            {
                Dictionary <string, AssetBucket> buckets = new Dictionary <string, AssetBucket>();
                WriteResult writeResult = m_Results.WriteResults[file.Name];
                List <ObjectSerializedInfo> sceneObjects = new List <ObjectSerializedInfo>();

                foreach (ObjectSerializedInfo info in writeResult.serializedObjects)
                {
                    string sourceGuid = string.Empty;
                    if (info.serializedObject.guid.Empty())
                    {
                        if (info.serializedObject.filePath.Equals("temp:/assetbundle", StringComparison.OrdinalIgnoreCase))
                        {
                            file.BundleObjectInfo      = new BuildLayout.AssetBundleObjectInfo();
                            file.BundleObjectInfo.Size = info.header.size;
                            continue;
                        }
                        else if (info.serializedObject.filePath.StartsWith("temp:/preloaddata", StringComparison.OrdinalIgnoreCase))
                        {
                            file.PreloadInfoSize = (int)info.header.size;
                            continue;
                        }
                        else if (info.serializedObject.filePath.StartsWith("temp:/", StringComparison.OrdinalIgnoreCase))
                        {
                            sceneObjects.Add(info);
                            continue;
                        }
                        else if (!string.IsNullOrEmpty(info.serializedObject.filePath))
                        {
                            AssetBucket pathBucket = GetOrCreate(buckets, info.serializedObject.filePath.ToString());
                            pathBucket.isFilePathBucket = true;
                            pathBucket.objs.Add(info);
                            continue;
                        }
                    }

                    AssetBucket bucket = GetOrCreate(buckets, info.serializedObject.guid.ToString());
                    bucket.objs.Add(info);
                }

                if (sceneObjects.Count > 0)
                {
                    BuildLayout.ExplicitAsset sceneAsset = file.Assets.First(x => x.AssetPath.EndsWith(".unity"));
                    AssetBucket bucket = GetOrCreate(buckets, sceneAsset.Guid);
                    bucket.objs.AddRange(sceneObjects);
                }

                // Update buckets with a reference to their explicit asset
                file.Assets.ForEach(eAsset =>
                {
                    if (!buckets.TryGetValue(eAsset.Guid, out AssetBucket b))
                    {
                        b = GetOrCreate(buckets, eAsset.Guid); // some assets might not pull in any objects
                    }
                    b.ExplictAsset = eAsset;
                });

                // Create entries for buckets that are implicitly pulled in
                Dictionary <string, BuildLayout.DataFromOtherAsset> guidToOtherData = new Dictionary <string, BuildLayout.DataFromOtherAsset>();
                foreach (AssetBucket bucket in buckets.Values.Where(x => x.ExplictAsset == null))
                {
                    string assetPath = bucket.isFilePathBucket ? bucket.guid : AssetDatabase.GUIDToAssetPath(bucket.guid);
                    if (assetPath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || assetPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
                    {
                        file.MonoScriptCount++;
                        file.MonoScriptSize += bucket.CalcObjectSize();
                        continue;
                    }
                    var otherData = new BuildLayout.DataFromOtherAsset();
                    otherData.AssetPath      = assetPath;
                    otherData.AssetGuid      = bucket.guid;
                    otherData.SerializedSize = bucket.CalcObjectSize();
                    otherData.StreamedSize   = bucket.CalcStreamedSize();
                    otherData.ObjectCount    = bucket.objs.Count;
                    file.OtherAssets.Add(otherData);
                    guidToOtherData[otherData.AssetGuid] = otherData;

                    if (!guidToPulledInBuckets.TryGetValue(otherData.AssetGuid, out List <BuildLayout.DataFromOtherAsset> bucketList))
                    {
                        bucketList = guidToPulledInBuckets[otherData.AssetGuid] = new List <BuildLayout.DataFromOtherAsset>();
                    }
                    bucketList.Add(otherData);
                }

                // Add references
                foreach (BuildLayout.ExplicitAsset asset in file.Assets)
                {
                    AssetBucket bucket = buckets[asset.Guid];
                    asset.SerializedSize = bucket.CalcObjectSize();
                    asset.StreamedSize   = bucket.CalcStreamedSize();

                    IEnumerable <ObjectIdentifier> refs = null;
                    if (m_DependencyData.AssetInfo.TryGetValue(new GUID(asset.Guid), out AssetLoadInfo info))
                    {
                        refs = info.referencedObjects;
                    }
                    else
                    {
                        refs = m_DependencyData.SceneInfo[new GUID(asset.Guid)].referencedObjects;
                    }
                    foreach (string refGUID in refs.Select(x => x.guid.Empty() ? x.filePath : x.guid.ToString()).Distinct())
                    {
                        if (guidToOtherData.TryGetValue(refGUID, out BuildLayout.DataFromOtherAsset dfoa))
                        {
                            dfoa.ReferencingAssets.Add(asset);
                            asset.InternalReferencedOtherAssets.Add(dfoa);
                        }
                        else if (buckets.TryGetValue(refGUID, out AssetBucket refBucket))
                        {
                            asset.InternalReferencedExplicitAssets.Add(refBucket.ExplictAsset);
                        }
                        else if (lookup.GuidToExplicitAsset.TryGetValue(refGUID, out BuildLayout.ExplicitAsset refAsset))
                        {
                            asset.ExternallyReferencedAssets.Add(refAsset);
                        }
                    }
                }
            }

            BuildLayout layout = new BuildLayout();

            // This is the addressables section. Everything above could technically be moved to SBP.
            {
                AddressableAssetsBuildContext aaContext = (AddressableAssetsBuildContext)m_AaBuildContext;
                // Map from GUID to AddrssableAssetEntry
                Dictionary <string, AddressableAssetEntry> guidToEntry = aaContext.assetEntries.ToDictionary(x => x.guid, x => x);

                // create groups
                foreach (AddressableAssetGroup group in aaContext.Settings.groups)
                {
                    var grp = new BuildLayout.Group();
                    grp.Name = group.Name;
                    grp.Guid = group.Guid;

                    foreach (AddressableAssetGroupSchema schema in group.Schemas)
                    {
                        var sd = new BuildLayout.SchemaData();
                        sd.Guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(schema));
                        sd.Type = schema.GetType().Name.ToString();

                        BundledAssetGroupSchema bSchema = schema as BundledAssetGroupSchema;
                        if (bSchema != null)
                        {
                            sd.KvpDetails.Add(new Tuple <string, string>("PackingMode", bSchema.BundleMode.ToString()));
                            sd.KvpDetails.Add(new Tuple <string, string>("Compression", bSchema.Compression.ToString()));
                        }
                        grp.Schemas.Add(sd);
                    }

                    lookup.GroupLookup.Add(group.Guid, grp);
                    layout.Groups.Add(grp);
                }

                // go through all the bundles and put them in groups
                foreach (BuildLayout.Bundle b in lookup.Bundles.Values)
                {
                    if (aaContext.bundleToImmediateBundleDependencies.TryGetValue(b.Name, out List <string> deps))
                    {
                        b.Dependencies = deps.Select(x => lookup.Bundles[x]).Where(x => b != x).ToList();
                    }
                    if (aaContext.bundleToExpandedBundleDependencies.TryGetValue(b.Name, out List <string> deps2))
                    {
                        b.ExpandedDependencies = deps2.Select(x => lookup.Bundles[x]).Where(x => b != x).ToList();
                    }

                    if (aaContext.bundleToAssetGroup.TryGetValue(b.Name, out string grpName))
                    {
                        lookup.GroupLookup[grpName].Bundles.Add(b);
                    }
                    else
                    {
                        layout.BuiltInBundles.Add(b);
                    }
                }

                // Apply the addressable name to the asset
                foreach (BuildLayout.ExplicitAsset a in BuildLayoutHelpers.EnumerateAssets(layout))
                {
                    if (guidToEntry.TryGetValue(a.Guid, out AddressableAssetEntry entry))
                    {
                        a.AddressableName = entry.address;
                    }
                }

                // The addressables build script can rename the bundles
                foreach (BuildLayout.Bundle b in BuildLayoutHelpers.EnumerateBundles(layout))
                {
                    if (m_BundleNameRemap.TryGetValue(b.Name, out string newName))
                    {
                        b.Name = newName;
                    }
                }
            }

            return(layout);
        }