/// <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="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> /// <param name="removeUnloadableObjects">If set to <c>true</c>, assets will be cloned with <see cref="AssetClonerFlags.RemoveUnloadableObjects"/>.</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, bool removeUnloadableObjects) { 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(flags: removeUnloadableObjects ? AssetClonerFlags.RemoveUnloadableObjects : AssetClonerFlags.None)).ToList(); } // idRemap should contain only assets that have either 1) their id remapped or 2) their location remapped var idRemap = new Dictionary <AssetId, Tuple <AssetId, UFile> >(); var itemRemap = new Dictionary <AssetItem, Tuple <AssetId, UFile> >(); foreach (var item in items) { if (outputItems.Contains(item)) { continue; } outputItems.Add(item); bool changed = false; AssetId newId; if (assetResolver.RegisterId(item.Id, out newId)) { changed = true; } // Note: we ignore name collisions if asset is not referenceable var referenceable = item.Asset.GetType().GetCustomAttribute <AssetDescriptionAttribute>()?.Referenceable ?? true; UFile newLocation = null; if (referenceable && assetResolver.RegisterLocation(item.Location, out newLocation)) { changed = true; } var tuple = new Tuple <AssetId, UFile>(newId != AssetId.Empty ? newId : 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 <AssetId, 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; } // Fix base parts if there are any remap for them as well // This has to be done before the default resolver below because this fix requires to rewrite the base part completely, since the base part asset is immutable var assetComposite = item.Asset as IAssetComposite; if (assetComposite != null) { foreach (var basePart in assetComposite.CollectParts()) { if (basePart.Base != null && idRemap.TryGetValue(basePart.Base.BasePartAsset.Id, out remap) && IsNewReference(remap, basePart.Base.BasePartAsset)) { var newAssetReference = new AssetReference(remap.Item1, remap.Item2); basePart.UpdateBase(new BasePart(newAssetReference, basePart.Base.BasePartId, basePart.Base.InstanceId)); 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; } } } // Process roots (until references in package are handled in general) if (package != null) { UpdateRootAssets(package.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); } }