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