using System; using System.Collections.Generic; using System.Linq; using UnityEditor.Build.Content; using UnityEditor.Build.Pipeline.Interfaces; using UnityEditor.Build.Player; namespace UnityEditor.Build.Pipeline.Utilities { [Serializable] struct ObjectTypes { public ObjectIdentifier ObjectID; public Type[] Types; public ObjectTypes(ObjectIdentifier objectID, Type[] types) { ObjectID = objectID; Types = types; } } static class ExtensionMethods { public static bool IsNullOrEmpty(this ICollection collection) { return collection == null || collection.Count == 0; } public static void GetOrAdd(this IDictionary dictionary, TKey key, out TValue value) where TValue : new() { if (dictionary.TryGetValue(key, out value)) return; value = new TValue(); dictionary.Add(key, value); } public static void Swap(this IList list, int first, int second) { T temp = list[second]; list[second] = list[first]; list[first] = temp; } public static void GatherSerializedObjectCacheEntries(this WriteCommand command, HashSet cacheEntries) { if (command.serializeObjects != null) { var objectIds = command.serializeObjects.Select(x => x.serializationObject); var types = BuildCacheUtility.GetSortedUniqueTypesForObjects(objectIds); cacheEntries.UnionWith(types.Select(BuildCacheUtility.GetCacheEntry)); cacheEntries.UnionWith(objectIds.Select(BuildCacheUtility.GetCacheEntry)); } } public static void ExtractCommonCacheData(IBuildCache cache, IEnumerable includedObjects, IEnumerable referencedObjects, HashSet uniqueTypes, List objectTypes, HashSet dependencies) { if (includedObjects != null) { foreach (var objectId in includedObjects) { var types = BuildCacheUtility.GetSortedUniqueTypesForObject(objectId); objectTypes.Add(new ObjectTypes(objectId, types)); uniqueTypes.UnionWith(types); } } if (referencedObjects != null) { foreach (var objectId in referencedObjects) { var types = BuildCacheUtility.GetSortedUniqueTypesForObject(objectId); objectTypes.Add(new ObjectTypes(objectId, types)); uniqueTypes.UnionWith(types); dependencies.Add(cache.GetCacheEntry(objectId)); } } dependencies.UnionWith(uniqueTypes.Select(cache.GetCacheEntry)); } #if NONRECURSIVE_DEPENDENCY_DATA public static ObjectIdentifier[] FilterReferencedObjectIDs(GUID asset, ObjectIdentifier[] references, BuildTarget target, TypeDB typeDB, HashSet dependencies) { // Expectation: references is populated with DependencyType.ValidReferences only for the given asset var collectedImmediateReferences = new HashSet(); var encounteredDependencies = new HashSet(); while (references.Length > 0) { // Track which roots we encounter to do dependency pruning encounteredDependencies.UnionWith(references.Where(x => x.guid != asset && dependencies.Contains(x.guid))); // We only want to recursively grab references for objects being pulled in and won't go to another bundle ObjectIdentifier[] immediateReferencesNotInOtherBundles = references.Where(x => !dependencies.Contains(x.guid) && !collectedImmediateReferences.Contains(x)).ToArray(); collectedImmediateReferences.UnionWith(immediateReferencesNotInOtherBundles); // Grab next set of valid references and loop references = ContentBuildInterface.GetPlayerDependenciesForObjects(immediateReferencesNotInOtherBundles, target, typeDB, DependencyType.ValidReferences); } // We need to ensure that we have a reference to a visible representation so our runtime dependency appending process // can find something that can be appended, otherwise the necessary data will fail to load correctly in all cases. (EX: prefab A has reference to component on prefab B) foreach (var dependency in encounteredDependencies) { // For each dependency, add just the main representation as a reference var representations = ContentBuildInterface.GetPlayerAssetRepresentations(dependency.guid, target); collectedImmediateReferences.Add(representations.First()); } collectedImmediateReferences.UnionWith(encounteredDependencies); return collectedImmediateReferences.ToArray(); } #endif } }