public void WhenReferencesContainPreviousSceneAssetDependencies_FilterReferencesForAsset_PrunesPreviousAssetDependencies([Values] bool containsPreviousSceneAsset) { var assetInBundle = new GUID("00000000000000000000000000000001"); var referenceNotInBundle = new GUID("00000000000000000000000000000000"); List <ObjectIdentifier> objects = CreateObjectIdentifierList("path", referenceNotInBundle); IDependencyData dep = GetDependencyData(objects, assetInBundle); var references = new List <ObjectIdentifier>(objects); var previousSceneReferences = new HashSet <GUID>(); if (containsPreviousSceneAsset) { previousSceneReferences.Add(assetInBundle); } GenerateBundlePacking.FilterReferencesForAsset(dep, assetInBundle, references, new HashSet <ObjectIdentifier>(), previousSceneReferences); if (containsPreviousSceneAsset) { Assert.AreEqual(0, references.Count); } else { Assert.AreEqual(1, references.Count); } }
internal static void CreateResourceLocationData( AddressableAssetGroup assetGroup, string bundleName, string bundleInternalId, string bundleProvider, string assetProvider, List <GUID> assetsInBundle, HashSet <string> bundleDependencies, List <ContentCatalogDataEntry> locations, HashSet <Type> providerTypes, IDependencyData dependencyData) { locations.Add(new ContentCatalogDataEntry(typeof(IAssetBundleResource), bundleInternalId, bundleProvider, new object[] { bundleName })); var assets = new List <AddressableAssetEntry>(); assetGroup.GatherAllAssets(assets, true, true, false); var guidToEntry = new Dictionary <string, AddressableAssetEntry>(); foreach (var a in assets) { guidToEntry.Add(a.guid, a); } foreach (var a in assetsInBundle) { AddressableAssetEntry entry; if (!guidToEntry.TryGetValue(a.ToString(), out entry)) { continue; } entry.CreateCatalogEntriesInternal(locations, true, assetProvider, bundleDependencies, null, dependencyData.AssetInfo); } }
/// <inheritdoc /> public ReturnCode PostWriting(IBuildParameters parameters, IDependencyData dependencyData, IWriteData writeData, IBuildResults results) { if (PostWritingCallback != null) { return(PostWritingCallback(parameters, dependencyData, writeData, results)); } return(ReturnCode.Success); }
/// <inheritdoc /> public ReturnCode PostDependency(IBuildParameters buildParameters, IDependencyData dependencyData) { if (PostDependencyCallback != null) { return(PostDependencyCallback(buildParameters, dependencyData)); } return(ReturnCode.Success); }
/// <inheritdoc /> public ReturnCode PostPacking(IBuildParameters buildParameters, IDependencyData dependencyData, IWriteData writeData) { if (PostPackingCallback != null) { return(PostPackingCallback(buildParameters, dependencyData, writeData)); } return(ReturnCode.Success); }
public void DefaultBuildTasks_GenerateBundleMaps() { IDependencyData dep = GetDependencyData(); IBundleWriteData writeData = new BundleWriteData(); ReturnCode exitCode = RunTask <GenerateBundleMaps>(dep, writeData); Assert.AreEqual(ReturnCode.Success, exitCode); }
public void DefaultBuildTasks_GenerateBundlePacking() { IBundleBuildContent buildContent = GetBundleContent(); IDependencyData dep = GetDependencyData(); IBundleWriteData writeData = new BundleWriteData(); IDeterministicIdentifiers deterministicId = new PrefabPackedIdentifiers(); ReturnCode exitCode = RunTask <GenerateBundlePacking>(buildContent, dep, writeData, deterministicId); Assert.AreEqual(ReturnCode.Success, exitCode); }
public void WhenReferencesContainsAssetsInBundles_FilterReferencesForAsset_PrunesAssetsInBundles() { var assetInBundle = new GUID("00000000000000000000000000000000"); List <ObjectIdentifier> objects = CreateObjectIdentifierList("path", assetInBundle); IDependencyData dep = GetDependencyData(objects, assetInBundle); var references = new List <ObjectIdentifier>(objects); GenerateBundlePacking.FilterReferencesForAsset(dep, assetInBundle, references); Assert.AreEqual(0, references.Count); }
public void WhenReferencesAreUnique_FilterReferencesForAsset_ReturnsReferences() { var assetInBundle = new GUID("00000000000000000000000000000000"); List <ObjectIdentifier> objects = CreateObjectIdentifierList("path", assetInBundle, assetInBundle); IDependencyData dep = GetDependencyData(objects, assetInBundle); var references = new List <ObjectIdentifier>(objects); List <GUID> results = GenerateBundlePacking.FilterReferencesForAsset(dep, assetInBundle, references); Assert.AreEqual(1, results.Count); Assert.AreEqual(assetInBundle, results[0]); }
public void WhenReferencesContainsRefsIncludedByCircularAssetsWithLowerGuid_FilterReferencesForAsset_PrunesRefsIncludedByCircularAssetsWithLowerGuid() { var assetNotInBundle = new GUID("00000000000000000000000000000001"); var referenceInBundle = new GUID("00000000000000000000000000000000"); List <ObjectIdentifier> objects = CreateObjectIdentifierList("path", assetNotInBundle); // circular reference to asset whose references we want to filter IDependencyData dep = GetDependencyData(objects, referenceInBundle); List <ObjectIdentifier> references = CreateObjectIdentifierList("path", referenceInBundle, assetNotInBundle); GenerateBundlePacking.FilterReferencesForAsset(dep, assetNotInBundle, references); Assert.AreEqual(0, references.Count); }
public void WhenReferencesContainsRefsIncludedByNonCircularAssets_FilterReferencesForAsset_PrunesRefsIncludedByNonCircularAssets() { var assetNotInBundle = new GUID("00000000000000000000000000000000"); var referenceInBundle = new GUID("00000000000000000000000000000001"); var referenceNotInBundle = new GUID("00000000000000000000000000000002"); List <ObjectIdentifier> objects = CreateObjectIdentifierList("path", referenceNotInBundle); IDependencyData dep = GetDependencyData(objects, referenceInBundle); List <ObjectIdentifier> references = CreateObjectIdentifierList("path", referenceInBundle, referenceNotInBundle); GenerateBundlePacking.FilterReferencesForAsset(dep, assetNotInBundle, references); Assert.AreEqual(0, references.Count); }
internal static List <GUID> FilterReferencesForAsset(IDependencyData dependencyData, GUID asset, List <ObjectIdentifier> references, HashSet <ObjectIdentifier> previousSceneObjects = null) { var referencedAssets = new HashSet <AssetLoadInfo>(); var referencesPruned = new List <ObjectIdentifier>(references.Count); // Remove Default Resources and Includes for Assets assigned to Bundles foreach (ObjectIdentifier reference in references) { if (reference.filePath.Equals(CommonStrings.UnityDefaultResourcePath, StringComparison.OrdinalIgnoreCase)) { continue; } if (dependencyData.AssetInfo.TryGetValue(reference.guid, out AssetLoadInfo referenceInfo)) { referencedAssets.Add(referenceInfo); continue; } referencesPruned.Add(reference); } references.Clear(); references.AddRange(referencesPruned); var referencedAssetsGuids = new List <GUID>(referencedAssets.Count); // Remove References also included by non-circular Referenced Assets // Remove References also included by circular Referenced Assets if Asset's GUID is higher than Referenced Asset's GUID foreach (AssetLoadInfo referencedAsset in referencedAssets) { var refObjectIdLookup = new HashSet <ObjectIdentifier>(referencedAsset.referencedObjects); bool circularRef = refObjectIdLookup.Select(x => x.guid).Contains(asset); if (!circularRef || (circularRef && asset > referencedAsset.asset || asset == referencedAsset.asset)) { references.RemoveAll(refObjectIdLookup.Contains); } referencedAssetsGuids.Add(referencedAsset.asset); } // Special path for scenes, they can use data from previous sharedAssets in the same bundle if (!previousSceneObjects.IsNullOrEmpty()) { references.RemoveAll(previousSceneObjects.Contains); } return(referencedAssetsGuids); }
public void DefaultBuildTasks_PostDependencyCallback() { bool dependencyCallbackCalled = false; IBuildParameters buildParameters = GetBuildParameters(); IDependencyData dep = GetDependencyData(); BuildCallbacks callback = new BuildCallbacks(); callback.PostDependencyCallback = (parameters, data) => { dependencyCallbackCalled = true; return(ReturnCode.Success); }; ReturnCode exitCode = RunTask <PostDependencyCallback>(buildParameters, dep, callback); Assert.AreEqual(ReturnCode.Success, exitCode); Assert.IsTrue(dependencyCallbackCalled); }
public void DefaultBuildTasks_PostPackingCallback() { bool packingCallbackCalled = false; IBuildParameters buildParams = GetBuildParameters(); IDependencyData dep = GetDependencyData(); IBundleWriteData writeData = new BundleWriteData(); BuildCallbacks callback = new BuildCallbacks(); callback.PostPackingCallback = (parameters, data, arg3) => { packingCallbackCalled = true; return(ReturnCode.Success); }; ReturnCode exitCode = RunTask <PostPackingCallback>(buildParams, dep, writeData, callback); Assert.AreEqual(ReturnCode.Success, exitCode); Assert.IsTrue(packingCallbackCalled); }
/// <summary> /// This callback is what remove the unwanted AssetBundle writing operation from being processed with the WriteSerializedFiles /// and ArchiveAndCompressBundles taskes /// </summary> /// <param name="buildParams"></param> /// <param name="dependencyData"></param> /// <param name="writeData"></param> /// <returns></returns> private static ReturnCode PostPackingCallback(IBuildParameters buildParams, IDependencyData dependencyData, IWriteData writeData) { if (includedBundles != null && includedBundles.Count > 0) { for (int i = writeData.WriteOperations.Count - 1; i >= 0; --i) { // get the AssetBundle name that the writeOperation is for AssetBundleWriteOperation op = writeData.WriteOperations[i] as AssetBundleWriteOperation; string bundleName = null; if (op != null) { bundleName = op.Info.bundleName; } else { // scene bundles are also different if (writeData.WriteOperations[i] is SceneBundleWriteOperation s_op) { bundleName = s_op.Info.bundleName; } else { Debug.LogError("Unexpected write operation"); return(ReturnCode.Error); } } // if we do not want to build that bundle, remove the write operation from the list if (includedBundles.Contains(bundleName) == false) { writeData.WriteOperations.RemoveAt(i); } } } return(ReturnCode.Success); }
private static ReturnCode PostPackingForSelectiveBuild(IBuildParameters buildParams, IDependencyData dependencyData, IWriteData writeData) { var includedBundles = AssetbundleBuildSettings.EditorInstance.BundleSettings .Where(setting => setting.IncludedInPlayer) .Select(setting => setting.BundleName) .ToList(); //quick exit if (includedBundles == null || includedBundles.Count == 0) { return(ReturnCode.Success); } for (int i = writeData.WriteOperations.Count - 1; i >= 0; --i) { string bundleName; //derive bundle name from operation if (writeData.WriteOperations[i] is AssetBundleWriteOperation bundleOp) { bundleName = bundleOp.Info.bundleName; } else if (writeData.WriteOperations[i] is SceneBundleWriteOperation sceneBundleOp) { bundleName = sceneBundleOp.Info.bundleName; } else if (writeData.WriteOperations[i] is SceneDataWriteOperation sceneDataOp) { //this is the simplest way to derive bundle name from SceneDataWriteOperation var bundleWriteData = writeData as IBundleWriteData; bundleName = bundleWriteData.FileToBundle[sceneDataOp.Command.internalName]; } else { Debug.LogError("Unexpected write operation"); return(ReturnCode.Error); } // if we do not want to build that bundle, remove the write operation from the list if (includedBundles.Contains(bundleName) == false) { writeData.WriteOperations.RemoveAt(i); } } return(ReturnCode.Success); }
private ReturnCode PostWriting(IBuildParameters buildParameters, IDependencyData dependencyData, IWriteData writeData, IBuildResults results) { var parameters = buildParameters as BundleBuildParameters; return(ReturnCode.Success); }
internal static ReturnCode RunInternal(IAddressableAssetsBuildContext aaBuildContext, IBundleWriteData writeData, IDependencyData dependencyData) { var aaContext = aaBuildContext as AddressableAssetsBuildContext; if (aaContext == null) { return(ReturnCode.Error); } AddressableAssetSettings aaSettings = aaContext.Settings; List <ContentCatalogDataEntry> locations = aaContext.locations; Dictionary <string, string> bundleToAssetGroup = aaContext.bundleToAssetGroup; var bundleToAssets = new Dictionary <string, List <GUID> >(); var dependencySetForBundle = new Dictionary <string, HashSet <string> >(); foreach (KeyValuePair <GUID, List <string> > k in writeData.AssetToFiles) { List <GUID> assetList; string bundle = writeData.FileToBundle[k.Value[0]]; if (!bundleToAssets.TryGetValue(bundle, out assetList)) { bundleToAssets.Add(bundle, assetList = new List <GUID>()); } HashSet <string> bundleDeps; if (!dependencySetForBundle.TryGetValue(bundle, out bundleDeps)) { dependencySetForBundle.Add(bundle, bundleDeps = new HashSet <string>()); } for (int i = 0; i < k.Value.Count; i++) { bundleDeps.Add(writeData.FileToBundle[k.Value[i]]); } foreach (string file in k.Value) { string fileBundle = writeData.FileToBundle[file]; if (!bundleToAssets.ContainsKey(fileBundle)) { bundleToAssets.Add(fileBundle, new List <GUID>()); } } assetList.Add(k.Key); } var assetGroupToBundle = (aaContext.assetGroupToBundles = new Dictionary <AddressableAssetGroup, List <string> >()); foreach (KeyValuePair <string, List <GUID> > kvp in bundleToAssets) { AddressableAssetGroup assetGroup = aaSettings.DefaultGroup; string groupGuid; if (bundleToAssetGroup.TryGetValue(kvp.Key, out groupGuid)) { assetGroup = aaSettings.FindGroup(g => g != null && g.Guid == groupGuid); } List <string> bundles; if (!assetGroupToBundle.TryGetValue(assetGroup, out bundles)) { assetGroupToBundle.Add(assetGroup, bundles = new List <string>()); } bundles.Add(kvp.Key); HashSet <string> bundleDeps = null; dependencySetForBundle.TryGetValue(kvp.Key, out bundleDeps); CreateResourceLocationData(assetGroup, kvp.Key, GetLoadPath(assetGroup, kvp.Key), GetBundleProviderName(assetGroup), GetAssetProviderName(assetGroup), kvp.Value, bundleDeps, locations, aaContext.providerTypes, dependencyData); } return(ReturnCode.Success); }
private static ReturnCode PostPackingForSelectiveBuild(IBuildParameters buildParams, IDependencyData dependencyData, IWriteData writeData) { var customBuildParams = buildParams as CustomBuildParameters; List <string> includedBundles; if (customBuildParams.CurrentBuildType == BuildType.Local) { includedBundles = customBuildParams.CurrentSettings.BundleSettings .Where(setting => setting.IncludedInPlayer) .Select(setting => setting.BundleName) .ToList(); } //if not local build, we include everything else { includedBundles = customBuildParams.CurrentSettings.BundleSettings .Select(setting => setting.BundleName) .ToList(); } //quick exit if (includedBundles == null || includedBundles.Count == 0) { Debug.Log("Nothing to build"); return(ReturnCode.Success); } var bundleHashDic = new Dictionary <string, HashSet <GUID> >(); for (int i = writeData.WriteOperations.Count - 1; i >= 0; --i) { string bundleName; HashSet <GUID> guidHashSet; switch (writeData.WriteOperations[i]) { case SceneBundleWriteOperation sceneOperation: bundleName = sceneOperation.Info.bundleName; if (!bundleHashDic.TryGetValue(bundleName, out guidHashSet)) { guidHashSet = new HashSet <GUID>(); bundleHashDic.Add(bundleName, guidHashSet); } foreach (var bundleSceneInfo in sceneOperation.Info.bundleScenes) { guidHashSet.Add(bundleSceneInfo.asset); } foreach (var asset in sceneOperation.PreloadInfo.preloadObjects) { if (asset.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(asset.guid); } break; case SceneDataWriteOperation sceneDataOperation: var bundleWriteData = writeData as IBundleWriteData; bundleName = bundleWriteData.FileToBundle[sceneDataOperation.Command.internalName]; if (!bundleHashDic.TryGetValue(bundleName, out guidHashSet)) { guidHashSet = new HashSet <GUID>(); bundleHashDic.Add(bundleName, guidHashSet); } foreach (var identifier in sceneDataOperation.PreloadInfo.preloadObjects) { if (identifier.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(identifier.guid); } break; case AssetBundleWriteOperation assetBundleOperation: bundleName = assetBundleOperation.Info.bundleName; if (!bundleHashDic.TryGetValue(bundleName, out guidHashSet)) { guidHashSet = new HashSet <GUID>(); bundleHashDic.Add(bundleName, guidHashSet); } foreach (var bs in assetBundleOperation.Info.bundleAssets) { foreach (var asset in bs.includedObjects) { if (asset.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(asset.guid); } foreach (var asset in bs.referencedObjects) { if (asset.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(asset.guid); } } break; default: Debug.LogError("Unexpected write operation"); return(ReturnCode.Error); } // if we do not want to build that bundle, remove the write operation from the list if (!includedBundles.Contains(bundleName) || customBuildParams.CurrentBuildType == BuildType.Dry) { writeData.WriteOperations.RemoveAt(i); } } //log deps file WriteDuplicateLogFile(Application.dataPath + "/../", bundleHashDic); return(ReturnCode.Success); }
/// <summary> /// Save the content update information for a set of AddressableAssetEntry objects. /// </summary> /// <param name="locations">The ContentCatalogDataEntry locations that were built into the Content Catalog.</param> /// <param name="path">File to write content stat info to. If file already exists, it will be deleted before the new file is created.</param> /// <param name="entries">The entries to save.</param> /// <param name="dependencyData">The raw dependency information generated from the build.</param> /// <param name="playerVersion">The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion.</param> /// <param name="remoteCatalogPath">The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur.</param> /// <returns>True if the file is saved, false otherwise.</returns> public static bool SaveContentState(List <ContentCatalogDataEntry> locations, string path, List <AddressableAssetEntry> entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath) { return(SaveContentState(locations, path, entries, dependencyData, playerVersion, remoteCatalogPath, null)); }
/// <summary> /// Save the content update information for a set of AddressableAssetEntry objects. /// </summary> /// <param name="locations">The ContentCatalogDataEntry locations that were built into the Content Catalog.</param> /// <param name="path">File to write content stat info to. If file already exists, it will be deleted before the new file is created.</param> /// <param name="entries">The entries to save.</param> /// <param name="dependencyData">The raw dependency information generated from the build.</param> /// <param name="playerVersion">The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion.</param> /// <param name="remoteCatalogPath">The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur.</param> /// <returns>True if the file is saved, false otherwise.</returns> public static bool SaveContentState(List <ContentCatalogDataEntry> locations, string path, List <AddressableAssetEntry> entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath) { try { IList <CachedAssetState> cachedInfos = new List <CachedAssetState>(); foreach (var assetData in dependencyData.AssetInfo) { AddressableAssetEntry addressableAssetEntry = entries.FirstOrDefault((e) => e.guid == assetData.Key.ToString()); ContentCatalogDataEntry catalogAssetEntry = locations.FirstOrDefault((e) => { if (e.Keys.Count <= 1) { return(false); } return((e.Keys[1] as string) == assetData.Key.ToString()); }); CachedAssetState cachedAssetState; if (addressableAssetEntry != null && catalogAssetEntry != null && GetCachedAssetStateForData(assetData.Key, addressableAssetEntry.BundleFileId, addressableAssetEntry.parentGroup.Guid, catalogAssetEntry.Data, assetData.Value.referencedObjects.Select(x => x.guid), out cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } foreach (var sceneData in dependencyData.SceneInfo) { AddressableAssetEntry addressableSceneEntry = entries.FirstOrDefault((e) => e.guid == sceneData.Key.ToString()); ContentCatalogDataEntry catalogSceneEntry = locations.FirstOrDefault((e) => { if (e.Keys.Count <= 1) { return(false); } return((e.Keys[1] as string) == sceneData.Key.ToString()); }); CachedAssetState cachedAssetState; if (addressableSceneEntry != null && catalogSceneEntry != null && GetCachedAssetStateForData(sceneData.Key, addressableSceneEntry.BundleFileId, addressableSceneEntry.parentGroup.Guid, catalogSceneEntry.Data, sceneData.Value.referencedObjects.Select(x => x.guid), out cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } var cacheData = new AddressablesContentState { cachedInfos = cachedInfos.ToArray(), playerVersion = playerVersion, editorVersion = Application.unityVersion, remoteCatalogLoadPath = remoteCatalogPath }; var formatter = new BinaryFormatter(); if (File.Exists(path)) { File.Delete(path); } var dir = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write); formatter.Serialize(stream, cacheData); stream.Flush(); stream.Close(); stream.Dispose(); return(true); } catch (Exception e) { Debug.LogException(e); return(false); } }
internal static List <GUID> FilterReferencesForAsset(IDependencyData dependencyData, GUID asset, List <ObjectIdentifier> references, HashSet <ObjectIdentifier> previousSceneObjects = null, HashSet <GUID> previousSceneReferences = null, Dictionary <GUID, HashSet <ObjectIdentifier> > assetObjectIdentifierHashSets = null) { var referencedAssets = new HashSet <AssetLoadInfo>(); var referencedAssetsGuids = new List <GUID>(referencedAssets.Count); var referencesPruned = new List <ObjectIdentifier>(references.Count); // Remove Default Resources and Includes for Assets assigned to Bundles foreach (ObjectIdentifier reference in references) { if (reference.filePath.Equals(CommonStrings.UnityDefaultResourcePath, StringComparison.OrdinalIgnoreCase)) { continue; } if (dependencyData.AssetInfo.TryGetValue(reference.guid, out AssetLoadInfo referenceInfo)) { if (referencedAssets.Add(referenceInfo)) { referencedAssetsGuids.Add(referenceInfo.asset); } continue; } referencesPruned.Add(reference); } references.Clear(); references.AddRange(referencesPruned); // Remove References also included by non-circular Referenced Assets // Remove References also included by circular Referenced Assets if Asset's GUID is higher than Referenced Asset's GUID foreach (AssetLoadInfo referencedAsset in referencedAssets) { if ((asset > referencedAsset.asset) || (asset == referencedAsset.asset)) { references.RemoveAll(GetRefObjectIdLookup(referencedAsset, assetObjectIdentifierHashSets).Contains); } else { bool exists = false; foreach (ObjectIdentifier referencedObject in referencedAsset.referencedObjects) { if (referencedObject.guid == asset) { exists = true; break; } } if (!exists) { references.RemoveAll(GetRefObjectIdLookup(referencedAsset, assetObjectIdentifierHashSets).Contains); } } } // Special path for scenes, they can reference the same assets previously references if (!previousSceneReferences.IsNullOrEmpty()) { foreach (GUID reference in previousSceneReferences) { if (!dependencyData.AssetInfo.TryGetValue(reference, out AssetLoadInfo referencedAsset)) { continue; } var refObjectIdLookup = GetRefObjectIdLookup(referencedAsset, assetObjectIdentifierHashSets); // NOTE: It's impossible for an asset to depend on a scene, thus no need for circular reference checks // So just remove and add a dependency on the asset if there is a need to depend upon it. if (references.RemoveAll(refObjectIdLookup.Contains) > 0) { referencedAssetsGuids.Add(referencedAsset.asset); } } } // Special path for scenes, they can use data from previous sharedAssets in the same bundle if (!previousSceneObjects.IsNullOrEmpty()) { references.RemoveAll(previousSceneObjects.Contains); } return(referencedAssetsGuids); }
static IList <CachedAssetState> GetCachedAssetStates(List <ContentCatalogDataEntry> locations, List <AddressableAssetEntry> entries, IDependencyData dependencyData) { Dictionary <string, AddressableAssetEntry> guidToEntries = new Dictionary <string, AddressableAssetEntry>(); Dictionary <string, ContentCatalogDataEntry> key1ToCCEntries = new Dictionary <string, ContentCatalogDataEntry>(); foreach (AddressableAssetEntry entry in entries) { if (!guidToEntries.ContainsKey(entry.guid)) { guidToEntries[entry.guid] = entry; } } foreach (ContentCatalogDataEntry ccEntry in locations) { if (ccEntry != null && ccEntry.Keys != null && ccEntry.Keys.Count > 1 && (ccEntry.Keys[1] as string) != null && !key1ToCCEntries.ContainsKey(ccEntry.Keys[1] as string)) { key1ToCCEntries[ccEntry.Keys[1] as string] = ccEntry; } } IList <CachedAssetState> cachedInfos = new List <CachedAssetState>(); foreach (var assetData in dependencyData.AssetInfo) { guidToEntries.TryGetValue(assetData.Key.ToString(), out AddressableAssetEntry addressableAssetEntry); key1ToCCEntries.TryGetValue(assetData.Key.ToString(), out ContentCatalogDataEntry catalogAssetEntry); if (addressableAssetEntry != null && catalogAssetEntry != null && GetCachedAssetStateForData(assetData.Key, addressableAssetEntry.BundleFileId, addressableAssetEntry.parentGroup.Guid, catalogAssetEntry.Data, assetData.Value.referencedObjects.Select(x => x.guid), out CachedAssetState cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } foreach (var sceneData in dependencyData.SceneInfo) { guidToEntries.TryGetValue(sceneData.Key.ToString(), out AddressableAssetEntry addressableSceneEntry); key1ToCCEntries.TryGetValue(sceneData.Key.ToString(), out ContentCatalogDataEntry catalogSceneEntry); if (addressableSceneEntry != null && catalogSceneEntry != null && GetCachedAssetStateForData(sceneData.Key, addressableSceneEntry.BundleFileId, addressableSceneEntry.parentGroup.Guid, catalogSceneEntry.Data, sceneData.Value.referencedObjects.Select(x => x.guid), out CachedAssetState cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } return(cachedInfos); }
/// <summary> /// Save the content update information for a set of AddressableAssetEntry objects. /// </summary> /// <param name="path">File to write content stat info to. If file already exists, it will be deleted before the new file is created.</param> /// <param name="entries">The entries to save.</param> /// <param name="dependencyData">The raw dependency information generated from the build.</param> /// <param name="playerVersion">The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion.</param> /// <param name="remoteCatalogPath">The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur.</param> /// <returns>True if the file is saved, false otherwise.</returns> public static bool SaveContentState(string path, List <AddressableAssetEntry> entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath) { try { IList <CachedAssetState> cachedInfos = new List <CachedAssetState>(); foreach (var assetData in dependencyData.AssetInfo) { CachedAssetState cachedAssetState; if (GetCachedAssetStateForData(assetData.Key, assetData.Value.referencedObjects.Select(x => x.guid), out cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } foreach (var sceneData in dependencyData.SceneInfo) { CachedAssetState cachedAssetState; if (GetCachedAssetStateForData(sceneData.Key, sceneData.Value.referencedObjects.Select(x => x.guid), out cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } var cacheData = new AddressablesContentState { cachedInfos = cachedInfos.ToArray(), playerVersion = playerVersion, editorVersion = Application.unityVersion, remoteCatalogLoadPath = remoteCatalogPath }; var formatter = new BinaryFormatter(); if (File.Exists(path)) { File.Delete(path); } var dir = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write); formatter.Serialize(stream, cacheData); stream.Flush(); stream.Close(); stream.Dispose(); return(true); } catch (Exception e) { Debug.LogException(e); return(false); } }
/// <summary> /// Save the content update information for a set of AddressableAssetEntry objects. /// </summary> /// <param name="locations">The ContentCatalogDataEntry locations that were built into the Content Catalog.</param> /// <param name="path">File to write content stat info to. If file already exists, it will be deleted before the new file is created.</param> /// <param name="entries">The entries to save.</param> /// <param name="dependencyData">The raw dependency information generated from the build.</param> /// <param name="playerVersion">The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion.</param> /// <param name="remoteCatalogPath">The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur.</param> /// <param name="carryOverCacheState">Cached state that needs to carry over from the previous build. This mainly affects Content Update.</param> /// <returns>True if the file is saved, false otherwise.</returns> public static bool SaveContentState(List <ContentCatalogDataEntry> locations, string path, List <AddressableAssetEntry> entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath, List <CachedAssetState> carryOverCacheState) { try { Dictionary <string, AddressableAssetEntry> guidToEntries = new Dictionary <string, AddressableAssetEntry>(); Dictionary <string, ContentCatalogDataEntry> key1ToCCEntries = new Dictionary <string, ContentCatalogDataEntry>(); foreach (AddressableAssetEntry entry in entries) { if (!guidToEntries.ContainsKey(entry.guid)) { guidToEntries[entry.guid] = entry; } } foreach (ContentCatalogDataEntry ccEntry in locations) { if (ccEntry != null && ccEntry.Keys != null && ccEntry.Keys.Count > 1 && (ccEntry.Keys[1] as string) != null && !key1ToCCEntries.ContainsKey(ccEntry.Keys[1] as string)) { key1ToCCEntries[ccEntry.Keys[1] as string] = ccEntry; } } IList <CachedAssetState> cachedInfos = new List <CachedAssetState>(); foreach (var assetData in dependencyData.AssetInfo) { guidToEntries.TryGetValue(assetData.Key.ToString(), out AddressableAssetEntry addressableAssetEntry); key1ToCCEntries.TryGetValue(assetData.Key.ToString(), out ContentCatalogDataEntry catalogAssetEntry); if (addressableAssetEntry != null && catalogAssetEntry != null && GetCachedAssetStateForData(assetData.Key, addressableAssetEntry.BundleFileId, addressableAssetEntry.parentGroup.Guid, catalogAssetEntry.Data, assetData.Value.referencedObjects.Select(x => x.guid), out CachedAssetState cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } foreach (var sceneData in dependencyData.SceneInfo) { guidToEntries.TryGetValue(sceneData.Key.ToString(), out AddressableAssetEntry addressableSceneEntry); key1ToCCEntries.TryGetValue(sceneData.Key.ToString(), out ContentCatalogDataEntry catalogSceneEntry); if (addressableSceneEntry != null && catalogSceneEntry != null && GetCachedAssetStateForData(sceneData.Key, addressableSceneEntry.BundleFileId, addressableSceneEntry.parentGroup.Guid, catalogSceneEntry.Data, sceneData.Value.referencedObjects.Select(x => x.guid), out CachedAssetState cachedAssetState)) { cachedInfos.Add(cachedAssetState); } } if (carryOverCacheState != null) { foreach (var cs in carryOverCacheState) { cachedInfos.Add(cs); } } var cacheData = new AddressablesContentState { cachedInfos = cachedInfos.ToArray(), playerVersion = playerVersion, editorVersion = Application.unityVersion, remoteCatalogLoadPath = remoteCatalogPath }; var formatter = new BinaryFormatter(); if (File.Exists(path)) { File.Delete(path); } var dir = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write); formatter.Serialize(stream, cacheData); stream.Flush(); stream.Close(); stream.Dispose(); return(true); } catch (Exception e) { Debug.LogException(e); return(false); } }
/// <summary> /// Save the content update information for a set of AddressableAssetEntry objects. /// </summary> /// <param name="locations">The ContentCatalogDataEntry locations that were built into the Content Catalog.</param> /// <param name="path">File to write content stat info to. If file already exists, it will be deleted before the new file is created.</param> /// <param name="entries">The entries to save.</param> /// <param name="dependencyData">The raw dependency information generated from the build.</param> /// <param name="playerVersion">The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion.</param> /// <param name="remoteCatalogPath">The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur.</param> /// <param name="carryOverCacheState">Cached state that needs to carry over from the previous build. This mainly affects Content Update.</param> /// <returns>True if the file is saved, false otherwise.</returns> public static bool SaveContentState(List <ContentCatalogDataEntry> locations, string path, List <AddressableAssetEntry> entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath, List <CachedAssetState> carryOverCacheState) { try { var cachedInfos = GetCachedAssetStates(locations, entries, dependencyData); var cachedBundleInfos = new List <CachedBundleState>(); foreach (ContentCatalogDataEntry ccEntry in locations) { if (typeof(IAssetBundleResource).IsAssignableFrom(ccEntry.ResourceType)) { cachedBundleInfos.Add(new CachedBundleState() { bundleFileId = ccEntry.InternalId, data = ccEntry.Data }); } } if (carryOverCacheState != null) { foreach (var cs in carryOverCacheState) { cachedInfos.Add(cs); } } var cacheData = new AddressablesContentState { cachedInfos = cachedInfos.ToArray(), playerVersion = playerVersion, editorVersion = Application.unityVersion, remoteCatalogLoadPath = remoteCatalogPath, cachedBundles = cachedBundleInfos.ToArray() }; var formatter = new BinaryFormatter(); if (File.Exists(path)) { File.Delete(path); } var dir = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write); formatter.Serialize(stream, cacheData); stream.Flush(); stream.Close(); stream.Dispose(); return(true); } catch (UnauthorizedAccessException uae) { if (!AddressableAssetUtility.IsVCAssetOpenForEdit(path)) { Debug.LogErrorFormat("Cannot access the file {0}. It may be locked by version control.", path); } else { Debug.LogException(uae); } return(false); } catch (Exception e) { Debug.LogException(e); return(false); } }
private static ReturnCode PostPackingForSelectiveBuild(IBuildParameters buildParams, IDependencyData dependencyData, IWriteData writeData) { List <string> includedBundles; if (s_CurrentBuildType == BuildType.Local) { includedBundles = s_CurrentBuildingSettings.BundleSettings .Where(setting => setting.IncludedInPlayer) .Select(setting => setting.BundleName) .ToList(); } //if not local build, we include everything else { includedBundles = s_CurrentBuildingSettings.BundleSettings .Select(setting => setting.BundleName) .ToList(); } //quick exit if (includedBundles == null || includedBundles.Count == 0) { Debug.Log("Nothing to build"); return(ReturnCode.Success); } var sb = new System.Text.StringBuilder(); sb.AppendLine($"Build Time : {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); sb.AppendLine(); var bundleHashDic = new Dictionary <string, HashSet <GUID> >(); for (int i = writeData.WriteOperations.Count - 1; i >= 0; --i) { string bundleName; HashSet <GUID> guidHashSet; switch (writeData.WriteOperations[i]) { case SceneBundleWriteOperation sceneOperation: bundleName = sceneOperation.Info.bundleName; if (!bundleHashDic.TryGetValue(bundleName, out guidHashSet)) { guidHashSet = new HashSet <GUID>(); bundleHashDic.Add(bundleName, guidHashSet); } foreach (var bundleSceneInfo in sceneOperation.Info.bundleScenes) { guidHashSet.Add(bundleSceneInfo.asset); } foreach (var asset in sceneOperation.PreloadInfo.preloadObjects) { if (asset.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(asset.guid); } break; case SceneDataWriteOperation sceneDataOperation: var bundleWriteData = writeData as IBundleWriteData; bundleName = bundleWriteData.FileToBundle[sceneDataOperation.Command.internalName]; if (!bundleHashDic.TryGetValue(bundleName, out guidHashSet)) { guidHashSet = new HashSet <GUID>(); bundleHashDic.Add(bundleName, guidHashSet); } foreach (var identifier in sceneDataOperation.PreloadInfo.preloadObjects) { if (identifier.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(identifier.guid); } break; case AssetBundleWriteOperation assetBundleOperation: bundleName = assetBundleOperation.Info.bundleName; if (!bundleHashDic.TryGetValue(bundleName, out guidHashSet)) { guidHashSet = new HashSet <GUID>(); bundleHashDic.Add(bundleName, guidHashSet); } foreach (var bs in assetBundleOperation.Info.bundleAssets) { foreach (var asset in bs.includedObjects) { if (asset.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(asset.guid); } foreach (var asset in bs.referencedObjects) { if (asset.fileType == UnityEditor.Build.Content.FileType.NonAssetType) { continue; } guidHashSet.Add(asset.guid); } } break; default: Debug.LogError("Unexpected write operation"); return(ReturnCode.Error); } // if we do not want to build that bundle, remove the write operation from the list if (!includedBundles.Contains(bundleName) || s_CurrentBuildType == BuildType.Dry) { writeData.WriteOperations.RemoveAt(i); } } foreach (var kv in bundleHashDic) { sb.AppendLine($"----File Path : {kv.Key}----"); foreach (var guid in kv.Value) { sb.AppendLine($"{(GetCompressedFileSize(guid.ToString()) * 0.000001f).ToString("0.00000").PadLeft(10)} mb - {AssetDatabase.GUIDToAssetPath(guid.ToString())}"); } sb.AppendLine(); } var path = Application.dataPath + "/../"; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } File.WriteAllText(Path.Combine(path, LogDependencyName), sb.ToString()); return(ReturnCode.Success); }
private static ReturnCode PostPackingForSelectiveBuild(IBuildParameters buildParams, IDependencyData dependencyData, IWriteData writeData) { var customBuildParams = buildParams as CustomBuildParameters; var depsDic = customBuildParams.DependencyDic; List <string> includedBundles; if (customBuildParams.CurrentBuildType == BuildType.Local) { //deps includes every local dependencies recursively includedBundles = customBuildParams.CurrentSettings.BundleSettings .Where(setting => setting.IncludedInPlayer) .Select(setting => setting.BundleName) .SelectMany(bundleName => Utility.CollectBundleDependencies(depsDic, bundleName, true)) .Distinct() .ToList(); } //if not local build, we include everything else { includedBundles = depsDic.Keys.ToList(); } //quick exit if (includedBundles == null || includedBundles.Count == 0) { Debug.Log("Nothing to build"); writeData.WriteOperations.Clear(); return(ReturnCode.Success); } for (int i = writeData.WriteOperations.Count - 1; i >= 0; --i) { string bundleName; switch (writeData.WriteOperations[i]) { case SceneBundleWriteOperation sceneOperation: bundleName = sceneOperation.Info.bundleName; break; case SceneDataWriteOperation sceneDataOperation: var bundleWriteData = writeData as IBundleWriteData; bundleName = bundleWriteData.FileToBundle[sceneDataOperation.Command.internalName]; break; case AssetBundleWriteOperation assetBundleOperation: bundleName = assetBundleOperation.Info.bundleName; break; default: Debug.LogError("Unexpected write operation"); return(ReturnCode.Error); } // if we do not want to build that bundle, remove the write operation from the list if (!includedBundles.Contains(bundleName)) { writeData.WriteOperations.RemoveAt(i); } } return(ReturnCode.Success); }
private static ProviderDefinition GetProvider(IDependencyData from, Dictionary <Type, DependencyDefinition> dependencies) { var dependencyType = from.Type; var providerType = from.Provider; if (providerType == null) { return(new ProviderDefinition() { Strategy = ProviderType.Implementation, Type = providerType }); } else if (dependencyType.IsAssignableFrom(providerType)) { return(new ProviderDefinition() { Strategy = ProviderType.Implementation, Type = providerType }); } else { var factoryMethods = providerType.GetMethods() .Where(item => dependencyType.IsAssignableFrom(item.ReturnType)); if (factoryMethods.Count() == 1) { var factoryMethod = factoryMethods.Single(); var provider = new ProviderDefinition() { Strategy = ProviderType.Factory, Type = providerType, Method = factoryMethod, Dependencies = new List <DependencyDefinition>() }; if (!dependencies.ContainsKey(providerType)) { dependencies.Add( providerType, new DependencyDefinition() { Declaration = null, Lifestyle = Lifestyles.Transient, Type = providerType, Provider = new ProviderDefinition() { Strategy = ProviderType.Implementation, Type = providerType } }); } return(provider); } else { throw new Exception(); } } }