public static void Run(AssetItem assetItem, ILogger log, AssetAnalysisParameters parameters) { if (assetItem == null) { throw new ArgumentNullException("assetItem"); } if (log == null) { throw new ArgumentNullException("log"); } if (parameters == null) { throw new ArgumentNullException("parameters"); } if (assetItem.Package == null) { throw new InvalidOperationException("AssetItem must belong to an existing package"); } var package = assetItem.Package; // Check that there is no duplicate in assets if (package.Session != null) { var packages = package.FindDependencies(); foreach (var otherPackage in packages) { var existingAsset = otherPackage.Assets.Find(assetItem.Id); if (existingAsset != null) { log.Error("Assets [{0}] with id [{1}] from Package [{2}] is already loaded from package [{3}]", existingAsset.FullPath, existingAsset.Id, package.FullPath, existingAsset.Package.FullPath); } else { existingAsset = otherPackage.Assets.Find(assetItem.Location); if (existingAsset != null) { log.Error("Assets [{0}] with location [{1}] from Package [{2}] is already loaded from package [{3}]", existingAsset.FullPath, existingAsset.Location, package.FullPath, existingAsset.Package.FullPath); } } } } var assetReferences = AssetReferenceAnalysis.Visit(assetItem.Asset); if (package.Session != null && parameters.IsProcessingAssetReferences) { UpdateAssetReferences(assetItem, assetReferences, log, parameters); } // Update paths for asset items if (parameters.IsProcessingUPaths) { // Find where this asset item was previously stored (in a different package for example) CommonAnalysis.UpdatePaths(assetItem, assetReferences.Where(link => link.Reference is UPath), parameters); } }
/// <summary> /// Processes the UPaths on package (but not on assets, use <see cref="ProcessAssets"/> for this) /// </summary> public void ProcessPackageUPaths() { if (package.FullPath == null) { return; } var packageReferenceLinks = AssetReferenceAnalysis.Visit(package); CommonAnalysis.UpdatePaths(package, packageReferenceLinks.Where(link => link.Reference is UPath), Parameters); }
/// <summary> /// Cleans the specified input items. /// </summary> /// <param name="inputItems">The input items.</param> /// <param name="outputItems">The output items.</param> /// <param name="assetResolver">The asset resolver.</param> /// <param name="cloneInput">if set to <c>true</c> [clone input].</param> /// <exception cref="System.ArgumentNullException"> /// inputItems /// or /// outputItems /// or /// assetResolver /// </exception> /// <exception cref="System.ArgumentException">List cannot contain null items;inputItems</exception> public static void Clean(ICollection <AssetItem> inputItems, ICollection <AssetItem> outputItems, AssetResolver assetResolver, bool cloneInput) { if (inputItems == null) { throw new ArgumentNullException("inputItems"); } if (outputItems == null) { throw new ArgumentNullException("outputItems"); } if (assetResolver == null) { throw new ArgumentNullException("assetResolver"); } // Check that all items are non-null if (inputItems.Any(item => item == null)) { throw new ArgumentException("List cannot contain null items", "inputItems"); } var items = inputItems; if (cloneInput) { items = inputItems.Select(item => item.Clone()).ToList(); } // Check if locations are conflicting var locationConflicts = new Dictionary <AssetItem, UFile>(); foreach (var item in items) { UFile newLocation; if (assetResolver.RegisterLocation(item.Location, out newLocation)) { locationConflicts[item] = newLocation; } } // Check if ids are conflicting var idConflicts = new Dictionary <AssetItem, Guid>(); foreach (var item in items) { Guid newGuid; if (assetResolver.RegisterId(item.Id, out newGuid)) { idConflicts[item] = newGuid; } } // Calculate final guid => guid remapping // Because several asset items can have the same id, we are only using the first one for remapping var idRemap = new Dictionary <Guid, Tuple <Guid, UFile> >(); var locationRemap = new Dictionary <UFile, UFile>(); foreach (var item in items) { if (outputItems.Contains(item)) { continue; } outputItems.Add(item); Guid newGuid; if (!idConflicts.TryGetValue(item, out newGuid)) { newGuid = item.Id; } UFile newLocation; if (locationConflicts.TryGetValue(item, out newLocation) && !locationRemap.ContainsKey(item.Location)) { locationRemap.Add(item.Location, newLocation); } if (!idRemap.ContainsKey(item.Id)) { idRemap.Add(item.Id, new Tuple <Guid, UFile>(newGuid, newLocation ?? item.Location)); } } // Process assets foreach (var item in outputItems) { // Replace Id Guid newGuid; if (idConflicts.TryGetValue(item, out newGuid)) { item.Asset.Id = newGuid; item.IsDirty = true; } // Replace location if (locationConflicts.ContainsKey(item)) { item.Location = locationConflicts[item]; item.IsDirty = true; } // The loop is a one or two-step. // - If there is no link to update, and the asset has not been cloned, we can exist immediately // - If there is links to update, and the asset has not been cloned, we need to clone it and re-enter the loop // to perform the update of the clone asset var links = AssetReferenceAnalysis.Visit(item.Asset).Where(link => link.Reference is IContentReference).ToList(); foreach (var assetLink in links) { var assetReference = (IContentReference)assetLink.Reference; var newId = assetReference.Id; var newLocation = assetReference.Location; bool requireUpdate = false; Tuple <Guid, UFile> newRemap; if (idRemap.TryGetValue(newId, out newRemap) && (newId != newRemap.Item1 || newLocation != newRemap.Item2)) { newId = newRemap.Item1; newLocation = newRemap.Item2; requireUpdate = true; } UFile remapLocation; if (!requireUpdate && locationRemap.TryGetValue(newLocation, out remapLocation)) { newLocation = remapLocation; requireUpdate = true; } if (requireUpdate) { assetLink.UpdateReference(newId, newLocation); item.IsDirty = true; } } } }
/// <summary> /// Cleans the specified input items. /// </summary> /// <param name="package">The package to process (optional).</param> /// <param name="inputItems">The input items.</param> /// <param name="outputItems">The output items.</param> /// <param name="assetResolver">The asset resolver.</param> /// <param name="cloneInput">if set to <c>true</c> [clone input].</param> /// <exception cref="System.ArgumentNullException"> /// inputItems /// or /// outputItems /// or /// assetResolver /// </exception> /// <exception cref="System.ArgumentException">List cannot contain null items;inputItems</exception> public static void Clean(Package package, ICollection <AssetItem> inputItems, ICollection <AssetItem> outputItems, AssetResolver assetResolver, bool cloneInput) { if (inputItems == null) { throw new ArgumentNullException(nameof(inputItems)); } if (outputItems == null) { throw new ArgumentNullException(nameof(outputItems)); } if (assetResolver == null) { throw new ArgumentNullException(nameof(assetResolver)); } // Check that all items are non-null if (inputItems.Any(item => item == null)) { throw new ArgumentException("List cannot contain null items", nameof(inputItems)); } var items = inputItems; if (cloneInput) { items = inputItems.Select(item => item.Clone()).ToList(); } // idRemap should contain only assets that have either 1) their id remapped or 2) their location remapped var idRemap = new Dictionary <Guid, Tuple <Guid, UFile> >(); var itemRemap = new Dictionary <AssetItem, Tuple <Guid, UFile> >(); foreach (var item in items) { if (outputItems.Contains(item)) { continue; } outputItems.Add(item); bool changed = false; Guid newGuid; if (assetResolver.RegisterId(item.Id, out newGuid)) { changed = true; } UFile newLocation; if (assetResolver.RegisterLocation(item.Location, out newLocation)) { changed = true; } var tuple = new Tuple <Guid, UFile>(newGuid != Guid.Empty ? newGuid : item.Id, newLocation ?? item.Location); if (changed) { if (!itemRemap.ContainsKey(item)) { itemRemap.Add(item, tuple); } } if (!idRemap.ContainsKey(item.Id)) { idRemap.Add(item.Id, tuple); } } // Process assets foreach (var item in outputItems) { Tuple <Guid, UFile> remap; if (itemRemap.TryGetValue(item, out remap) && (remap.Item1 != item.Asset.Id || remap.Item2 != item.Location)) { item.Asset.Id = remap.Item1; item.Location = remap.Item2; item.IsDirty = true; } // The loop is a one or two-step. // - If there is no link to update, and the asset has not been cloned, we can exist immediately // - If there is links to update, and the asset has not been cloned, we need to clone it and re-enter the loop // to perform the update of the clone asset var links = AssetReferenceAnalysis.Visit(item.Asset).Where(link => link.Reference is IReference).ToList(); foreach (var assetLink in links) { var assetReference = (IReference)assetLink.Reference; var newId = assetReference.Id; if (idRemap.TryGetValue(newId, out remap) && IsNewReference(remap, assetReference)) { assetLink.UpdateReference(remap.Item1, remap.Item2); item.IsDirty = true; } } // Fix base if there are any if (item.Asset.Base != null && idRemap.TryGetValue(item.Asset.Base.Id, out remap) && IsNewReference(remap, item.Asset.Base)) { item.Asset.Base.Asset.Id = remap.Item1; item.Asset.Base = new AssetBase(remap.Item2, item.Asset.Base.Asset); item.IsDirty = true; } // Fix base parts if there are any remap for them as well if (item.Asset.BaseParts != null) { for (int i = 0; i < item.Asset.BaseParts.Count; i++) { var basePart = item.Asset.BaseParts[i]; if (idRemap.TryGetValue(basePart.Id, out remap) && IsNewReference(remap, basePart)) { basePart.Asset.Id = remap.Item1; item.Asset.BaseParts[i] = new AssetBase(remap.Item2, basePart.Asset); item.IsDirty = true; } } } } // Process roots (until references in package are handled in general) if (package != null) { UpdateRootAssets(package.RootAssets, idRemap); // We check dependencies to be consistent with other places, but nothing should be changed in there // (except if we were to instantiate multiple packages referencing each other at once?) foreach (var dependency in package.LocalDependencies) { if (dependency.RootAssets != null) { UpdateRootAssets(dependency.RootAssets, idRemap); } } foreach (var dependency in package.Meta.Dependencies) { if (dependency.RootAssets != null) { UpdateRootAssets(dependency.RootAssets, idRemap); } } } }
public static void Run(AssetItem assetItem, ILogger log, AssetAnalysisParameters parameters) { if (assetItem == null) { throw new ArgumentNullException(nameof(assetItem)); } if (log == null) { throw new ArgumentNullException(nameof(log)); } if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (assetItem.Package == null) { throw new InvalidOperationException("AssetItem must belong to an existing package"); } var package = assetItem.Package; // Check that there is no duplicate in assets if (package.Session != null) { var packages = package.FindDependencies(); foreach (var otherPackage in packages) { var existingAsset = otherPackage.Assets.Find(assetItem.Id); if (existingAsset != null) { log.Error($"Assets [{existingAsset.FullPath}] with id [{existingAsset.Id}] from Package [{package.FullPath}] is already loaded from package [{existingAsset.Package.FullPath}]"); } else { existingAsset = otherPackage.Assets.Find(assetItem.Location); if (existingAsset != null) { log.Error($"Assets [{existingAsset.FullPath}] with location [{existingAsset.Location}] from Package [{package.FullPath}] is already loaded from package [{existingAsset.Package.FullPath}]"); } } } } var assetReferences = AssetReferenceAnalysis.Visit(assetItem.Asset); if (package.Session != null && parameters.IsProcessingAssetReferences) { UpdateAssetReferences(assetItem, assetReferences, log, parameters); } // Update paths for asset items if (parameters.IsProcessingUPaths) { // Find where this asset item was previously stored (in a different package for example) CommonAnalysis.UpdatePaths(assetItem, assetReferences.Where(link => link.Reference is UPath), parameters); // Source hashes are not processed by analysis, we need to manually indicate them to update SourceHashesHelper.UpdateUPaths(assetItem.Asset, assetItem.FullPath.GetParent(), parameters.ConvertUPathTo); } }