private static void CalculateAssetBundleDependencies(ref BuildCommandSet.Command bundle, Dictionary <GUID, string> assetToBundleMap)
        {
            var allObjects   = new List <ObjectIdentifier>(bundle.assetBundleObjects);
            var dependencies = new HashSet <string>();

            for (var i = allObjects.Count - 1; i >= 0; --i)
            {
                // If we are dealing with Unity internal object types, do special handling
                if (allObjects[i].type == 0)
                {
                    if (!m_SpriteMap.ContainsKey(allObjects[i].guid))
                    {
                        // Remove built in unity objects that are not sprite atlas textures
                        // IE: shaders, primitives, etc
                        allObjects.RemoveAt(i);
                        continue;
                    }
                }

                // Check to see if the asset of this object is already explicityly in a bundle
                string dependency;
                if (!assetToBundleMap.TryGetValue(allObjects[i].guid, out dependency) || dependency == bundle.assetBundleName)
                {
                    continue;
                }

                dependencies.Add(dependency);
                allObjects.RemoveAt(i);
            }
            bundle.assetBundleObjects      = allObjects.ToArray();
            bundle.assetBundleDependencies = dependencies.ToArray();
        }
Exemple #2
0
        private bool ValidateCommand(BuildCommandSet.Command bundle)
        {
            if (bundle.explicitAssets.IsNullOrEmpty())
            {
                BuildLogger.LogWarning("Asset bundle '{0}' does not have any explicit assets defined.", bundle.assetBundleName);
            }
            else
            {
                foreach (var asset in bundle.explicitAssets)
                {
                    if (string.IsNullOrEmpty(asset.address))
                    {
                        BuildLogger.LogWarning("Asset bundle '{0}' has an asset '{1}' with an empty addressable name.", bundle.assetBundleName, asset.asset);
                    }

                    if (asset.includedObjects.IsNullOrEmpty() && asset.includedObjects.IsNullOrEmpty())
                    {
                        BuildLogger.LogWarning("Asset bundle '{0}' has an asset '{1}' with no objects to load.", bundle.assetBundleName, asset.asset);
                    }
                }
            }

            if (bundle.assetBundleObjects.IsNullOrEmpty())
            {
                BuildLogger.LogWarning("Asset bundle '{0}' does not have any serialized objects.", bundle.assetBundleName);
            }
            else
            {
                var localIDs = new HashSet <long>();
                foreach (var serializedInfo in bundle.assetBundleObjects)
                {
                    if (serializedInfo.serializationIndex == 1)
                    {
                        BuildLogger.LogError("Unable to continue resource writing. Asset bundle '{0}' has a serialized object with index of '1'. This is a reserved index and can not be used.",
                                             bundle.assetBundleName);
                        return(false);
                    }

                    if (!localIDs.Add(serializedInfo.serializationIndex))
                    {
                        BuildLogger.LogError("Unable to continue resource writing. Asset bundle '{0}' has multiple serialized objects with the same index '{1}'. Each serialized object must have a unique index.",
                                             bundle.assetBundleName, serializedInfo.serializationIndex);
                        return(false);
                    }
                }
            }

            return(true);
        }
        private Hash128 CalculateInputHash(BuildCommandSet.Command command, BuildSettings settings)
        {
            if (!UseCache)
            {
                return(new Hash128());
            }

            // NOTE: correct hash should be based off command, dependencies (internal name), settings, and asset hashes, (and usage tags, NYI)
            // NOTE: This hashing method assumes we use a deterministic method to generate all serializationIndex
            var dependencies = m_NameToDependencies[command.assetBundleName];
            var assetHashes  = new List <string>();

            foreach (var objectID in command.assetBundleObjects)
            {
                assetHashes.Add(m_AssetToHash[objectID.serializationObject.guid]);
            }

            return(HashingMethods.CalculateMD5Hash(Version, command, dependencies, assetHashes, settings));
        }
        public override BuildPipelineCodes Convert(BuildDependencyInformation buildInfo, out BuildCommandSet output)
        {
            StartProgressBar("Generating Build Commands", buildInfo.assetLoadInfo.Count);

            Hash128 hash = CalculateInputHash(buildInfo);

            if (UseCache && BuildCache.TryLoadCachedResults(hash, out output))
            {
                output = new BuildCommandSet();
                EndProgressBar();
                return(BuildPipelineCodes.SuccessCached);
            }

            var commands = new List <BuildCommandSet.Command>();

            foreach (var bundle in buildInfo.bundleToAssets)
            {
                var command            = new BuildCommandSet.Command();
                var explicitAssets     = new List <BuildCommandSet.AssetLoadInfo>();
                var assetBundleObjects = new List <BuildCommandSet.SerializationInfo>();
                var dependencies       = new HashSet <string>();

                foreach (var asset in bundle.Value)
                {
                    var assetInfo = buildInfo.assetLoadInfo[asset];
                    explicitAssets.Add(assetInfo);
                    if (!UpdateProgressBar(assetInfo.asset))
                    {
                        output = new BuildCommandSet();
                        EndProgressBar();
                        return(BuildPipelineCodes.Canceled);
                    }

                    dependencies.UnionWith(buildInfo.assetToBundles[asset]);

                    foreach (var includedObject in assetInfo.includedObjects)
                    {
                        if (!buildInfo.virtualAssets.Contains(asset) && buildInfo.objectToVirtualAsset.ContainsKey(includedObject))
                        {
                            continue;
                        }

                        assetBundleObjects.Add(new BuildCommandSet.SerializationInfo
                        {
                            serializationObject = includedObject,
                            serializationIndex  = SerializationIndexFromObjectIdentifier(includedObject)
                        });
                    }

                    foreach (var referencedObject in assetInfo.referencedObjects)
                    {
                        if (referencedObject.filePath == kUnityDefaultResourcePath)
                        {
                            continue;
                        }

                        if (buildInfo.objectToVirtualAsset.ContainsKey(referencedObject))
                        {
                            continue;
                        }

                        if (buildInfo.assetLoadInfo.ContainsKey(referencedObject.guid))
                        {
                            continue;
                        }

                        assetBundleObjects.Add(new BuildCommandSet.SerializationInfo
                        {
                            serializationObject = referencedObject,
                            serializationIndex  = SerializationIndexFromObjectIdentifier(referencedObject)
                        });
                    }

                    BuildUsageTagGlobal globalUsage;
                    if (buildInfo.sceneUsageTags.TryGetValue(asset, out globalUsage))
                    {
                        command.sceneBundle  = true;
                        command.globalUsage |= globalUsage;
                    }
                }

                dependencies.Remove(bundle.Key);
                assetBundleObjects.Sort(Compare);

                command.assetBundleName         = bundle.Key;
                command.explicitAssets          = explicitAssets.ToArray();
                command.assetBundleDependencies = dependencies.OrderBy(x => x).ToArray();
                command.assetBundleObjects      = assetBundleObjects.ToArray();
                commands.Add(command);
            }

            output          = new BuildCommandSet();
            output.commands = commands.ToArray();

            if (UseCache && !BuildCache.SaveCachedResults(hash, output))
            {
                BuildLogger.LogWarning("Unable to cache CommandSetProcessor results.");
            }

            if (!EndProgressBar())
            {
                return(BuildPipelineCodes.Canceled);
            }
            return(BuildPipelineCodes.Success);
        }
        public static BuildCommandSet GenerateBuildCommandSet(BuildInput input, BuildSettings settings)
        {
            // Rebuild sprite atlas cache for correct dependency calculation
            Packer.RebuildAtlasCacheIfNeeded(settings.target, true, Packer.Execution.Normal);

            // Need to specal case sprites as we only want to include the source texutre in certain situations
            m_SpriteMap.Clear();

            // Create commands array matching the size of the input
            var commandSet = new BuildCommandSet();

            commandSet.commands = new BuildCommandSet.Command[input.definitions.Length];
            for (var i = 0; i < input.definitions.Length; ++i)
            {
                var definition = input.definitions[i];

                // Populate each command from asset bundle definition
                var command = new BuildCommandSet.Command();
                command.assetBundleName = definition.assetBundleName;
                command.explicitAssets  = new BuildCommandSet.AssetLoadInfo[definition.explicitAssets.Length];

                // Fill out asset load info and references for each asset in the definition
                var allObjects = new HashSet <ObjectIdentifier>();
                for (var j = 0; j < definition.explicitAssets.Length; ++j)
                {
                    var explicitAsset = new BuildCommandSet.AssetLoadInfo();
                    explicitAsset.asset             = definition.explicitAssets[j];
                    explicitAsset.path              = AssetDatabase.GUIDToAssetPath(explicitAsset.asset.ToString());
                    explicitAsset.includedObjects   = AssetBundleBuildInterface.GetObjectIdentifiersInAsset(definition.explicitAssets[j]);
                    explicitAsset.referencedObjects = AssetBundleBuildInterface.GetPlayerDependenciesForObjects(explicitAsset.includedObjects);

                    // Is this asset a sprite?
                    var type = AssetDatabase.GetMainAssetTypeAtPath(explicitAsset.path);
                    if (type == typeof(Texture2D) && explicitAsset.referencedObjects.Length == 1)
                    {
                        // Source texture should always be the first included object, atlas should always be the first referenced object
                        m_SpriteMap[explicitAsset.referencedObjects[0].guid] = new StriteTextures(explicitAsset.includedObjects[0], explicitAsset.referencedObjects[0], command.assetBundleName);
                    }

                    command.explicitAssets[j] = explicitAsset;
                    allObjects.UnionWith(explicitAsset.includedObjects);
                    allObjects.UnionWith(explicitAsset.referencedObjects);
                }

                command.assetBundleObjects = allObjects.ToArray();
                commandSet.commands[i]     = command;
            }

            // TODO: Debug printing
            DebugPrintCommandSet(ref commandSet);

            // At this point, We have generated fully self contained asset bundles with 0 dependencies.
            // Default implementation is to reduce duplication of objects by declaring dependencies to other asset
            //    bundles if that other asset bundle has an explicit asset declared that contains the objects needed
            // We also remove any built in unity objects as they are built with the player (We may want to change this part in the future)
            CalculateAssetBundleBuildDependencies(ref commandSet);
            // Note: I may, or may not feel dirty doing mutable things to what otherwise should be immutable struct

            // TODO: Debug printing
            DebugPrintCommandSet(ref commandSet);

            return(commandSet);
        }