예제 #1
0
        /// <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;
                    }
                }
            }
        }
예제 #2
0
        /// <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);
                    }
                }
            }
        }
예제 #3
0
        /// <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;
                }

                UFile newLocation;
                if (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;
                }

                // 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 parts if there are any remap for them as well
                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;
                        }
                    }
                }
            }

            // 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);
                }
            }
        }
예제 #4
0
        /// <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;
                    }
                }
            }
        }